在C ++中,为什么要求在合并之前必须对列表进行排序

时间:2014-05-15 14:58:48

标签: c++ list linked-list

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

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

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

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

我感到困惑,因为如果需要对列表进行排序,为什么C ++不会通过在合并函数中调用sort函数来强制执行它?

另一件事,我可以先合并未排序的列表,然后我可以对合并列表进行排序,是不是这样呢?

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

3 个答案:

答案 0 :(得分:16)

  

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

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

  

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

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

  

另一件事,我可以先合并未排序的列表,然后我可以对合并列表进行排序,不是这样吗?

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

你可以通过附加两个列表然后对结果进行排序来实现同样的目的;但如果列表已经排序,那么效率会很低。

答案 1 :(得分:2)

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

你可能指的是

的要求
  

§23.3.5.5list操作

     

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)。如果您已经有排序列表,这是不受欢迎的。

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

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

答案 2 :(得分:0)

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

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

合并已排序的列表:

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 ++标准提供了多种算法,每种算法都具有该特定任务的最佳复杂性。