【问题标题】:In C++, why there is a requirement that lists must be sorted before merging在 C++ 中,为什么要求列表必须在合并之前进行排序
【发布时间】:2014-07-04 02:52:53
【问题描述】:

在 C++ 中,列表数据结构有一个合并功能,它基本上删除源列表中的所有对象并放入目标列表。

// source list will be empty after this operation
destinationList.merge(sourceList);

根据教程/示例,列表必须在合并操作之前进行排序。

destinationList.sort();
sourceList.sort();
destinationList.merge(sourceList);

我很困惑,因为如果有排序列表的要求,为什么 C++ 不通过在合并函数中调用排序函数来强制它?

另外,我可以先合并未排序的列表,然后我可以排序合并的列表,这不一样吗?

destinationList.merge(sourceList);
destinationList.sort();

【问题讨论】:

  • 如果顺序不重要,可以使用dst.insert(dst.end(), src.begin(), src.end()); src.clear();
  • 如果merge应该先排序,算法的复杂度是不一样的。
  • 某些列表可能已经排序,因此在合并之前无需调用 sort。如果 STL 在合并之前调用排序,那么它将执行不必要的排序。基本上,代码执行它在锡上所说的:排序排序和合并合并。由您决定是否输入智能,即在合并之前进行排序。
  • 我会指出list::sort 在比较方面可能只是 O(n*log(n)),但在迭代方面它是低效的(在内存中来回移动)到一个随机访问容器,例如vectordeque。我将您推荐给How can I efficiently select a standard library container in C++11,作为如何选择最合适容器的快速指南。

标签: c++ list linked-list


【解决方案1】:

为什么要求列表在合并前必须排序?

merge 的目的是合并两个排序列表以创建一个新的排序列表,而无需执行另一个排序的开销。合并可以在线性时间内完成,而排序是O(n*log(n))

为什么 c++ 不通过在合并函数中调用排序函数来强制执行它?

因为,如果列表已经排序,那将是非常低效的。

另外,我可以先合并未排序的列表,然后我可以排序合并的列表,这不一样吗?

没有。合并算法要求对输入进行排序,并从中生成排序列表。它通过比较输入列表的第一个元素,取较低的元素,并将其附加到输出列表来工作。

您可以通过附加两个列表然后对结果进行排序来实现相同的目的;但是,如果列表已经排序,那将是低效的。

【讨论】:

  • 我怎么可以合并两个无序列表list<int>l1 {5,4,3,2,1}list<int>l2 {10,9,8,7,6}?我的意思是它在哪里说明了订购的方式或含义?优势?后代?
  • @CătălinaSîrbu 是您所期望的合并结果吗?顺序由通过模板传递的比较器决定,默认为std::less,这使用元素上的operator<()进行比较。
【解决方案2】:

C++ 设计的驱动原则之一是“不要为不使用的东西付费”。

你可能指的是需求

§23.3.5.5 list 操作

void merge(list& x);

void merge(list&& x);

template void merge(list& x, Compare comp);

template void merge(list&& x, Compare comp);

22要求:comp 应定义严格的弱排序(25.4),列表和参数列表都应按照此排序。

在实际实现中发生的情况是,合并操作不只是采用两个列表并将元素从一个复制到另一个,它只是利用某种链表(如结构)的底层表示,并从一个重新链接元素列表到另一个。它将通过遍历两个列表并获取下一个更大的元素来做到这一点。由于两个列表都已经排序,它可以通过始终查看两个列表的第一个元素来做到这一点。线性时间的操作O(n)

您是否总是将它们连接起来(在恒定时间内通过类似拼接的操作可能进行的操作)然后对它们进行排序,复杂性会提高到 O(n log n)。如果您已经有排序列表,这是不希望的。

如果您不这样做,那么将它们拼接在一起,然后进行排序是您想要做的事情。

单独提供所有这些功能(拼接、合并、排序),用户可以根据他对列表是否已经排序的了解来选择最有效的方法来组合他的列表。

【讨论】:

    【解决方案3】:

    假设您在这里的意思是“合并”而不是“合并”,则略有不同。

    不要求列表在组合在一起之前进行排序。 根据您的要求,有 3 种不同的稍微不同的方式来组合列表

    合并排序列表:

    list1.merge( list2 ) // Complexity linear. Assumes list1 & list2 are sorted
    

    将一个列表的所有元素移动到另一个列表中:

    list1.splice( std::end( list1 ), list2 ) //Complexity: constant
    

    将一个列表的一些元素复制到另一个列表中:

    list1.insert( it1, it2 )// Complexity: linear, it1 & it2 are iterators pointing into list2
    

    因此,事实上 C++ 标准提供了多种算法,每种算法都具有针对特定任务的最佳复杂度。

    【讨论】:

      猜你喜欢
      • 2021-10-01
      • 2023-03-23
      • 1970-01-01
      • 2018-06-13
      • 1970-01-01
      • 2013-09-21
      • 2011-07-10
      • 2020-08-13
      • 1970-01-01
      相关资源
      最近更新 更多