快速排序

  上次的快排理解的不深刻,这次梳理一下它的核心:

  (1)选择一个标志值(通常为数组第一个元素)

  (2)从后向前进行一次遍历,找到一个小于标志值的数,i++,与标志值互换

  (3)从前向后进行一次遍历,找到一个大于标志值的数,j--,与标志值互换

  (4)重复(2)(3)步骤,直到左边数全部小于标志值,右边数全部大于标志值

  (5)将左右两侧的小于大于部分再次调用该方法,继续进行快排。

  上代码方便观看:

public void quickSort (int firstSub, int lastSub) {
    int i = firstSub;
    int j = lastSub;
    int key = numArr[i];
        
    while(i < j) {
        while(i < j && numArr[j] >= key)
        j--;
            
        if(i < j){
            numArr[i] = numArr[i] + numArr[j];
            numArr[j] = numArr[i] - numArr[j];
            numArr[i] = numArr[i] - numArr[j];
            i++;
        }
            
        while(i < j && numArr[i] <= key)
        i++;
            
        if(i < j){
            numArr[j] = numArr[i] + numArr[j];
            numArr[i] = numArr[j] - numArr[i];
            numArr[j] = numArr[j] - numArr[i];
            j--;
        }
    }
    if(i > firstSub)quickSort(firstSub , i - 1);
    if(j < lastSub)quickSort(i + 1, lastSub);
}

 

  举个例走一遍它的算法流程:

  比如有一个无序数组:8  12  5  9  2  33  45  4  10  6  (看起来尽可能杂乱无章嗷)

 

  1、第一步,我们选择数组首个元素作为标志数,意思是通过这个数来将整个数组分成两部分,通过一系列比较移动后,得到一个左侧全部小于这个数,右侧全部大于这个标志数的数组。

 

  2、第二步、我们需要两个下标(前下标i,后下标j),因为快排方法是通过右到左一次找小于标志数的值换位,再从左向右找到一个大于该标志数的值换位,所以要有连两个下标来记录找到的符合要求的元素值的下标。同时,也要靠这两个下标来进行判断是否已经完成了一个整个数组的查询,比如方法中,我们始终判断后下标大于前下标,如果不大于,说明后下表找到是前下标已经找过的元素了。所以我们通过比较前下标与后下标来判断什么时候执行完毕跳出来。

接下来就是循环判断了,只要后下标大于前下标,就会一直进行循环。

 

  3、首先从右向左找小于标志数的元素值,找到后,后下标值与 前下标i(存储的是标志数的下标) 进行换位操作。

  前: 8  12  5  9  2  33  45  4  10  6

  后: 6  12  5  9  2  33  45  4  10  8

  直接找到了 6 < 8 ,换位。

 

  4、接着从左向右寻找大于标志数的元素值,找到后,前下标i 与 后下标j(标志数的下标位置) 进行换位操作。

  前: 6  12  5  9  2  33  45  4  10  8

  后: 6  8    5  9  2  33  45  4  10  12

  12 > 8,换位。

 

  5、然后这是一个循环过程,接着找,重复 3 和 4 ,类似这样:

  6  4  5  9  2  33  45  8  10  12   (右向左找小)

  6  4  5  8  2  33  45  9  10  12   (左向右找大)

  6  4  5  2  8  33  45  9  10  12   (右向左找小)

 

  6、好啦,到这一步完后,再次判断后就会跳出循环,因为每次都会 i++ 或 j--,i < j 会跳出。

可以很明显的看出,8 为标志数,左侧都小于8,右侧都大于8,大家可以自己在纸上试试这个变换过程哦,不是很复杂~

接着,我们再次调用快排方法,这回只会传入前部分的前下标后下标,和后部分的前下标后下标。

 

  7、又会对两个部分进行 3 和 4 的操作,像这样:

  前部分:

  6  4  5  2   (6标志数)

  2  4  5  6   (右向左找小)

  2  4  5  6   (左向右找大,然而没有,搞定跳出)

  后部分:

  33  45  9  10  12   (33标志数)

  12  45  9  10  33   (右向左找小)

  12  33  9  10  45   (左向右找大)

  12  10  9  33  45   (右向左找小)

 

  8、这个例子举得不好。。。后半部分执行到这还得进行一次快排:

  12  10  9   (12标志数)

  10  9  12   (右向左找小)

  10  9  12   (左向右找大,都大,跳出,左侧部分再进行一次快排)

 

  相信大家看到这都理解快排的原理了吧,但是它还有不稳定,大神们也对它进行了诸多的改进,比如对标志数进行随机选择等等。希望对学算法的各位有所帮助吧!

posted @ 2017-03-30 13:02  名字不好起啊  阅读(252)  评论(0编辑  收藏  举报