我在哪里可以获得 C++ STL 中 __merge_without_buffer() 中使用的算法的体面的高级描述?我正在尝试用 D 编程语言重新实现此代码,并进行一些增强。我似乎无法通过阅读 STL 源代码来理解它在算法级别上所做的事情,因为有太多低级细节掩盖了它。此外,我不想只是盲目地翻译代码,因为那样的话,如果它不起作用,我将不知道为什么,并且我将无法添加我的增强功能。

最佳答案

__merge_without_buffer() 正在执行 就地合并 ,作为就地归并排序的合并步骤。它将假设已经排序的两个数据范围 [first, middle)[middle, last) 作为输入。 len1len2 参数等于两个输入范围的长度,分别是 (middle - first)(last - middle)

首先,它选择一个枢轴元素。然后,将数据重新排列为 A1 B1 A2 B2 的顺序,其中 A1[first, middle) 中小于枢轴的元素集合, A2[first, middle) 中大于或等于枢轴的元素集合, B1[middle, last) 小于枢轴,而 B2[middle, last) 中大于或等于枢轴的元素集合。请注意,数据最初的顺序是 A1 A2 B1 B2 ,所以我们要做的就是将 A2 B1 变成 B1 A2 。这是通过调用 std::rotate() 来实现的。

现在我们已经将小于主元的元素( A1B1 )与大于或等于主元的元素( A2B2 )分开了,所以现在我们可以递归地合并两个子范围 A1 A2B1 B2

我们如何选择支点?在我正在查看的实现中,它从较大的子范围中选择中值元素(即,如果 [first, middle) 的元素多于 [middle, last) ,则它选择 [first, middle) 的中值;否则,它选择 [middle, last) 的中值)。由于子范围已经排序,选择中位数是微不足道的。这种pivot选择确保在递归合并两个子范围时,每个子问题不超过当前问题大小的3/4,因为在最坏的情况下,至少有1/4的元素大于或小于pivot .

这个的运行时间是多少? std::rotate() 调用需要 O(N) 时间,我们对自己进行了两次递归调用。这相当于 O(N log N) 的运行时间。但是,请注意,这只是归并排序的一个步骤:请记住,在归并排序中,您首先对两半进行递归排序,然后进行合并。因此,现在归并排序运行时间的递推关系为:
T(N) = 2T(N/2) + O(N log N)
将其插入 Master theorem ,您现在可以在 O(N log2 N) 时间内运行合并排序!

作为一个有趣的最后一点,请考虑基于比较的排序算法的以下三个特性:

  • 就地
  • 稳定
  • 在 O(N log N) 时间内运行

  • 您通常一次只能获得其中的 2 个 - 快速排序获得 (1) 和 (3),归并排序获得 (2) 和 (3),就地归并排序获得 (1) 和 (2)。非基于比较的排序(例如计数排序)可以实现所有 3 种排序,但这些排序只能对某些数据类型进行排序。可能存在一种基于比较的排序,它可以实现所有 3 个,但如果有,我不知道它的存在,而且几乎可以肯定它要复杂得多。

    关于c++ - STL __merge_without_buffer 算法?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/438012/

    10-11 01:42