Java 快速排序算法问题

2018-12-18 06:42:32 +08:00
 wenb1

菜鸡如我又来问问题了,我懂快速排序的思路,但是没看懂这个方法 private static int partition(Comparable[] a, int lo, int hi)两个 while 循环是怎么配合 exch(a, i, j),less()执行的,while(true)里代码的执行顺序是什么样的。希望大神们能指教下,多谢了!

源码 link: https://algs4.cs.princeton.edu/23quicksort/Quick.java.html

public class Quick {

// This class should not be instantiated.
private Quick() { }

/**
 * Rearranges the array in ascending order, using the natural order.
 * @param a the array to be sorted
 */
public static void sort(Comparable[] a) {
    StdRandom.shuffle(a);
    sort(a, 0, a.length - 1);
    assert isSorted(a);
}

// quicksort the subarray from a[lo] to a[hi]
private static void sort(Comparable[] a, int lo, int hi) { 
    if (hi <= lo) return;
    int j = partition(a, lo, hi);
    sort(a, lo, j-1);
    sort(a, j+1, hi);
    assert isSorted(a, lo, hi);
}

// partition the subarray a[lo..hi] so that a[lo..j-1] <= a[j] <= a[j+1..hi]
// and return the index j.
private static int partition(Comparable[] a, int lo, int hi) {
    int i = lo;
    int j = hi + 1;
    Comparable v = a[lo];
    while (true) { 

        // find item on lo to swap
        while (less(a[++i], v)) {
            if (i == hi) break;
        }

        // find item on hi to swap
        while (less(v, a[--j])) {
            if (j == lo) break;      // redundant since a[lo] acts as sentinel
        }

        // check if pointers cross
        if (i >= j) break;

        exch(a, i, j);
    }

    // put partitioning item v at a[j]
    exch(a, lo, j);

    // now, a[lo .. j-1] <= a[j] <= a[j+1 .. hi]
    return j;
}

private static boolean less(Comparable v, Comparable w) {
    if (v == w) return false;   // optimization when reference equals
    return v.compareTo(w) < 0;
}
    
// exchange a[i] and a[j]
private static void exch(Object[] a, int i, int j) {
    Object swap = a[i];
    a[i] = a[j];
    a[j] = swap;
}
2958 次点击
所在节点    Java
10 条回复
ywcjxf1515
2018-12-18 08:14:10 +08:00
三个 break 都表示跳出循环,这时变一下基准数位置,就切分完毕,变成比基准数小,基准数,比基准数大三部分。第一个 break,到右边界,跳出循环,表示其他所有数都比基准数小。第二个 break,到左边界,跳出循环,表示所有其他所有数都比基准数大。while(true)内部的的第二个 while 之下的 if 的条件能成立,表示剩下所有数是前面部分比基准数大,后面部分比基准数小,同样是变一下基准数位置就切分完毕。exch(a,i,j)是放在 break 之后,有隐含条件是 if(i<j),为了交换左边的一个和右边的一个数,最终是为了达到左边比基准数小,右边比基准数大。
wenb1
2018-12-18 08:31:06 +08:00
@ywcjxf1515 感谢回答,你说的这些我都明白的,可能我问的不太清楚,我想问两个 while 在什么条件会停下来得到 i 和
j 并完成一次交换? while 是在得到 less 的结果为 true 的时候停下来吗,然后得到了 i 的值,同理取得 j 的值,再进行交换?
luosuosile
2018-12-18 08:43:09 +08:00
大红本算法第四版,理由有图,说的很清楚。数据结构和算法的好书
wenb1
2018-12-18 09:01:11 +08:00
@luosuosile 多谢提醒,我没仔细看那个图,看了一下明白了。。。
ywcjxf1515
2018-12-18 09:13:15 +08:00
@wenb1 你问的 while 的应该是 while(true)内部的两个 while 吧?在得到 less 的结果为 true 时,并不会停下来,内部不是还有一个 if,停下来要么是 if 的 break 执行了,要么是 less 的结果是 false,这时 i 才不变,等着被交换。j 同理。切分的目标是左边的所有比基准数小,右边的所有比基准数大,排定基准数。为了减少交换,从左边起比基准数小,就自加序号看下一个数,直到不比基准数大(也就是 false)。
wenb1
2018-12-18 09:15:43 +08:00
@ywcjxf1515 明白了,感谢回答!
dezhou9
2018-12-18 10:41:00 +08:00
这个函数命名很差 less exch 都不是完整的话啊
quinoa42
2018-12-18 10:41:48 +08:00
觉得难理解可以看 clrs 快排那章,思路清晰也很好懂
wenb1
2018-12-18 11:17:18 +08:00
@dezhou9 不会吧,这本书还是比较权威的教科书
wenb1
2018-12-18 11:17:40 +08:00
@quinoa42 我已经明白了,谢谢啦

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/518456

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX