【问题标题】:Is this how median-of-three quicksort works?这是三个中位数快速排序的工作原理吗?
【发布时间】:2019-08-07 19:38:47
【问题描述】:

我知道以前有人问过这个问题。我已经阅读了它们,但我仍然不确定我所解释的是否正确。

假设我们有一个 [51,20,26,16,19,38,10,37,49] 数组。

首先,我们必须选择中位数作为枢轴(第一个、最后一个和中间)。

[51,19,49]

因此,49 是支点,我们将它移到后面。

接下来,分区子数组[51,20,26,16,19,38,10,37]49。

由于 51 是大于 49 的 first 元素,而 37 是小于 49 的 first 元素,我们交换它们。

[37,20,26,16,19,38,10,51]
  ^                    ^     

重复相同的步骤。

由于 51 是第一个大于 49 但其索引大于 37 的元素,因此我们将枢轴换成 51。现在我们的数组如下所示:

[37,20,26,16,19,38,10,49,51]

现在 49 和 51 已排序。

然后,我们再次从[37,20,26,16,19,38,10] 中选择枢轴:[37,16,10]。

向后交换枢轴: [37,20,26,10,19,38,16] 寻找大于 16 的元素:37

寻找小于 16 的元素:10

交换

[10,20,26,37,19,38,16]

寻找大于 16 的元素:20

寻找小于 16 的元素:10

由于索引为 20 > 索引为 10,我将用 20 交换枢轴

[10,16,26,37,19,38,20]

从这里开始,我将重复从找到中位数到分区的步骤。但是,我真的不确定这是否是正确的方法。抱歉,如果这是一篇冗长的文章,我试图尽可能具体地说明我的思考过程。谁能告诉我我的做法是否正确?

【问题讨论】:

  • "因为 51 是第一个大于 49 的元素,而 37 是第一个小于 49 的元素,我们交换它们。" -- 你不知道是不是这样,你只知道一个比枢轴大,另一个比枢轴小。此外,您接下来要做的是将它们放在两个单独的数组中,以便枢轴用作中间的元素。这两个序列存储在一个数组中是一个优化细节。顺便说一句:从您的描述中不清楚,但是您在分区中间没有切换枢轴。
  • 这是否意味着在我第一次以[37,20,26,16,19,38,10,49,51] 结尾的分区之后,我应该再次从[37,19,51] 中选择中位数。因此,我的新中位数是 37,我从那里开始工作?

标签: algorithm data-structures quicksort


【解决方案1】:

三的中位数和分区方案 Lomuto 或 Hoare 存在差异。对于 Hoare 分区方案,三个的中位数通常排序为 first、middle、last:

[51,20,26,16,19,38,10,37,49] => [19,20,26,16,49,38,10,37,51]

Hoare 从左右扫描。左边没有值 >= 49,所以左边的扫描在到达 49 时停止。右边的扫描在 37 停止,因为这是第一个值

[19,20,26,16,37,38,10,49,51]

左扫描继续​​,直到再次达到 49。右扫描在 10 处停止。由于右索引现在

[19,20,26,16,37,38,10]   [49,51]

请注意,Hoare 仅保证左侧部分元素是 = 枢轴。 Elements == pivot 和 pivot 本身可能会出现在左侧和/或右侧的任何位置。


Lomuto 方案通常只从左侧扫描,通常枢轴在右侧。 3 的中位数仍然可以交换类似于我上面显示的内容,除了它会导致第一个

[51,20,26,16,19,38,10,37,49] => [19,20,26,16,51,38,10,37] [49]

Lomuto 然后从左边开始扫描,使用两个索引,一个每次更新,另一个索引为每个元素

[19,20,26,16,38,10,37,51] [49]

然后枢轴与第一个元素>=枢轴交换,结果是:

[20,26,16,19,38,10,37] [49] [51]

对于Lomuto方案,3的中位数可以在不交换的情况下确定,然后3的中位数交换到最后一个位置,这与问题相同。

[51,20,26,16,19,38,10,37,49] => [51,20,26,16,19,38,10,37] [49]

第一个分区步骤将导致:

[51,20,26,16,19,38,10,37] [49] => [20,26,16,19,38,10,37] [49] [51]

【讨论】:

  • 感谢您的解释!!但是,这是否意味着我做错了我没有按升序对 3 个元素(第一个、中间、最后一个)进行排序?一旦我找到了中位数[49],我就把它换到后面:[51,20,26,16,19,38,10,37,49]
  • @Kirbbbb - 我丢失了编辑。我更新了我的答案以显示仅将 3 的中位数与最后一个交换的第三种选择,这与您在问题中所做的相匹配。没有对与错。如果数据已经排序或反向排序,则中值 3 确实消除了最坏情况下的时间复杂度。 Hoare 分区方案在典型情况下速度更快,尤其是在存在重复值的情况下,这会导致 Lomuto 花费更多时间而 Hoare 花费更少时间。
  • @Kirbbbb - 我忘了提,Hoare 方案需要枢轴位于中间,或者至少不是第一个或最后一个元素,因为它依靠元素 == 枢轴来停止从左侧扫描和正确的。 Lomuto 方案需要枢轴是最后一个或第一个。
  • 非常感谢您的解释。我现在看起来更清楚了。在我四处阅读之前,但对为什么它们周围有这么多不同的“版本”感到困惑。但现在我知道我所做的是 Lomuto 中位数 3 方案。
猜你喜欢
  • 2014-06-08
  • 2018-11-27
  • 1970-01-01
  • 2014-08-23
  • 1970-01-01
  • 2020-03-23
  • 2014-12-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多