在c++中,列表数据结构有一个merge函数,基本上就是把源列表中的所有对象都移到目标列表中。
// source list will be empty after this operation
destinationList.merge(sourceList);
根据教程/示例,在合并操作之前必须对列表进行排序。
destinationList.sort();
sourceList.sort();
destinationList.merge(sourceList);
我很困惑,因为如果有排序列表的要求,为什么c++不通过在合并函数中调用排序函数来强制执行它?
还有一件事,我可以先对未排序的列表进行归并,然后再对已排序的列表进行排序,这不是一样吗?
destinationList.merge(sourceList);
destinationList.sort();
为什么要求列表在合并之前必须排序?
merge
的目的是合并两个排序列表以创建一个新的排序列表,而不需要执行另一个排序的开销。归并可以在线性时间内完成,而排序是O(n*log(n))
。
为什么c++不通过在merge函数中调用sort函数来强制执行?
因为,如果列表已经排序了,那将是非常低效的。
还有一件事,我可以先对未排序的列表进行归并,然后再对已排序的列表进行排序,这不是一样的吗?
。合并算法要求对输入进行排序,并从中产生一个排序列表。它的工作原理是比较输入列表的第一个元素,取较低的元素,并将其附加到输出列表中。
你可以通过添加两个列表然后对结果排序来实现同样的事情;但是,如果列表已经排序,那么这样做的效率会很低。
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 require:
comp
必须定义一个严格的弱排序(25.4),并且列表和实参列表都必须按照这个顺序排序。
在实际实现中发生的是,合并操作不只是取两个列表并将元素从一个复制到另一个,它只是利用某种链表结构的底层表示,并将元素从一个列表链接到另一个列表。它将遍历两个列表并取下一个更大的元素。因为这两个列表都已经排序过了,所以它可以通过总是查看两个列表的第一个元素来做到这一点。线性时间O(n)的运算。
如果你总是将它们连接起来(这是在常数时间内通过拼接操作实现的一种操作)然后对它们排序,那么复杂度将上升到O(n log n)。如果您已经有排序列表,则不希望这样做。
如果你没有,那么把它们拼接在一起,然后排序是你想要做的事情。
分别提供了所有这些功能(拼接、合并、排序),用户可以根据他对列表是否已经排序的了解,选择最有效的方式来组合列表。
如果你在这里指的是"合并"而不是"合并",那就略有不同了。
在组合在一起之前,不要求对列表进行排序。根据你的需求,有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++标准提供了多种算法,每种算法都具有针对特定任务的最佳复杂度。