快速排序 3 方式 - 为啥当元素大于枢轴时循环索引不增加?

Posted

技术标签:

【中文标题】快速排序 3 方式 - 为啥当元素大于枢轴时循环索引不增加?【英文标题】:Quick sort 3 way - why loop index is not incremented when element is greater than pivot?快速排序 3 方式 - 为什么当元素大于枢轴时循环索引不增加? 【发布时间】:2016-12-02 01:30:07 【问题描述】:

我一直在寻找与 3 路快速排序相关的许多问题,但找不到答案/解释(像这个和类似的 - Quicksort with 3-way partition)。

以下是 Robert Sedgewick 和 Kevin Wayne 的《算法》一书中的 3 向快速排序代码。

private static void sort(Comparable[] a, int lo, int hi)  
    if (hi <= lo) return;
    int lt = lo, gt = hi;
    Comparable v = a[lo];
    int i = lo;
    while (i <= gt) 
        int cmp = a[i].compareTo(v);
        if      (cmp < 0) exch(a, lt++, i++);
        else if (cmp > 0) exch(a, i, gt--);
        else              i++;
    

    sort(a, lo, lt-1);
    sort(a, gt+1, hi);

分区后,主元左边的元素应该小于主元,右边的元素应该大于主元。等于枢轴的元素应该在中间。我已经尝试逐步详细地编写上述代码,但无法理解为什么当元素大于枢轴时 i 不递增。当元素小于枢轴时,它会增加:

else if (cmp > 0) exch(a, **i, gt--**);

如果有人能解释这种分区方案,那就太好了。

【问题讨论】:

【参考方案1】:

因为您应该再次检查 a[i] 元素(以前的 a[gt]) - 目前尚不清楚 - 该元素是小还是大

*  *  *  *  *  *  *  *
      ^     ^     ^
      lt    i     gt

看一些中间情况:i 不小于 lt 且不大于 gt。

留给 i 的元素已被检查为不大于枢轴。

如果我们将 a[i] 与 a[lt] 交换,我们知道 a[i] 很小并且必须继续递增 i。

如果我们将 a[i] 与 a[gt] 交换,我们不会得到 a[i] 的新值,必须再次检查它

附:请注意,链接问题是关于具有两个枢轴值的 3 路分区,而 Sedgewick 算法适用于具有一个枢轴的“荷兰国旗”分区,并且对等于枢轴的值进行特殊处理

【讨论】:

谢谢,但要完全理解这一点(很抱歉无法理解):为什么它在小于大小写的情况下增加? exch(a, lt++, i++); "如果我们将 a[i] 与 a[lt] 交换,我们知道 a[i] 很小并且必须继续,递增 i。" - 好的,a[i] 小于枢轴,必须继续。 “如果我们将 a[i] 与 a[gt] 交换,我们不会得到 a[i] 的新值,并且必须再次检查它” - 不是 a[i] 即较旧的 a[gt] > 枢轴,即为什么要交换它? 好的,a[i] > 枢轴而不是 a[gt],它只是被交换以在最后移动更大的元素,但我们不知道交换它的元素。对吗? 是的,绝对的 有一个有用的“循环不变量”概念——在每个算法循环运行之前和之后彻底检查数据状态,并观察一些需要的状态(部分排序等)是否仍然保持(并且变得更好) .虽然有时选择这些不变量并不容易。似乎在这种具体情况下,您只是错过了数据流的特殊性-未知元素替换了处理过的元素。

以上是关于快速排序 3 方式 - 为啥当元素大于枢轴时循环索引不增加?的主要内容,如果未能解决你的问题,请参考以下文章

快速排序从入门到精通

快速排序:选择枢轴

如何使快速排序递归?

数据结构与算法之三 深入学习排序

使用第一个元素作为枢轴进行快速排序[关闭]

您如何在中间位置实现枢轴快速排序,这种变化称为啥? [关闭]