详解快速排序

摘自百度百科:

       快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。 

一趟快速排序的算法是:

1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];(第一个位置空闲出来,需要赋值)
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]互换; 不需要互换,因为下一次操作会覆盖A[j]。 将A[j]值赋给A[i], 这时第j个位置空闲出来,需要赋值)
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换; (不需要互换,因为下一次操作会覆盖A[i]。将A[i]值赋给A[j], 这时第i个位置空闲出来,需要赋值)
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。(这时第i个位置是空闲的,如果继续循环则执行第3步骤给它赋值;如果跳出循环则赋值为key )

       说通俗一点, 快排的思想就是将大问题分解成小问题,解决完所有小问题后大问题也就解决了,即“分而治之”的算法思想。以上的5个步骤理解理解为填空题, 从第一个位置开始填空, 每当循环赋值后位置便空闲出来等待赋值,循环的从后向前或从前向后遍历 然后再递归排序前半部分和后半部分。

       对照例子说明快排的一趟排序(A[0]~A[9]表示数组元素,红色表示空闲位置,绿色表示刚刚被替换):

下标0123456789
数值60115485573980704582
初始状态:key是60,i=0,j=9


执行算法第3步骤,即从数组j位置向前搜索,第一个满足条件的是下标8、数值45。

下标0123456789
数值45115485573980704582
i=0, j=8, key=60 ,  这时A[0]和A[8]都是45, 数组里少了个值60! 别急,这是A[8]可以理解为无效值,要想办法给它赋值。


执行算法第4个步骤, 从从数组i位置想后搜索,找到下标3、数组85, 将A[3]赋值给A[8]。A[3]变为无效位置,等待赋值。

下标0123456789
数值45115485573980708582
i=3, j=8, key=60,  这时A[3]和A[8]都是85。


执行算法第3步骤,从j即第8个位置向前遍历, 下标5、值39符合要求(即小于key值60)

下标0123456789
数值45115439573980708582
i=3,j=5,key=60, 这时A[3]和A[5]都是39, 下标5位置空闲出来,等待赋值。


执行算法第4步骤, 从下标i即第3个位置向后遍历,因为i<j条件限制, i自动都第5个位置时跳出循环。

下标0123456789
数值45115439576080708582
i=5, j=5, key=60, 这时比key小的都在左边, 比key大的都在右边。

     

        然后再递归排序key位置的左边和右边就行了。

完整Java代码:

    private int partition(int[] array, int begin, int end) {
        int i = begin;   //从前向后遍历
        int j = end;     //从后向前遍历
        int buf = array[begin];   //缓存数据, 可以理解成begin位置空出来了,等待赋值。

        while (i < j) {  //循环填充空闲出来的唯一位置
            while (i<j && array[j] >= buf) {  //从后向前找到第一个小于buf变量的位置
                j--;
            }
            array[i] = array[j];  //将第j位置的值赋给第i个位置。这时第j个位置可以理解为空出来了,等待赋值。
            while (i<j && array[i] <= buf) {
                i++;
            }
            array[j] = array[i];  //给空出来的第j位置赋值, 这时i位置空闲出来了。
        }
        array[i] = buf;  //i和j相等

        return i;
    }

    private void quickSort(int[] array, int beigin, int end) {
        if (beigin < end) {
            int pos = partition(array, beigin, end);
            quickSort(array, beigin, pos-1);  //递归排序前半部分
            quickSort(array, pos+1, end);  //递归排序后半部分
        }
    }

 int array[] = {60, 11, 54, 85, 57, 39, 80, 70, 45, 82};
 quickSort(array, 0, array.length-1);


其实在日程编码中, 我们更可能会用Comparator, 例如:

      arrays.sort(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                if (o1 < o2) {
                    return -1;
                } else if (o1 == o2) {
                    return 0;
                } else {
                    return 1;
                }
            }
        });


Swift3.0语言版本(注意inout和&的用法, 语法建议不要修改函数参数):

func partition(array: inout Array<Int>, low: Int, high: Int) -> Int {
    var i = low
    var j = high
    let buf = array[low]
    
    while i < j {
        while i < j && array[j] >= buf {
            j -= 1
        }
        array[i] = array[j]
        while i < j && array[i] <= buf {
            i += 1
        }
    }
    array[i] = buf
    return i
}

func quickSort(list: inout Array<Int>, low: Int, high: Int) {
    if low < high {
        let pos = partition(array: &list, low: low, high: high)
        quickSort(list: &list, low: low, high: pos-1)
        quickSort(list: &list, low: pos+1, high: high)
    }
}

 var array1 = [3, 3, 1, 32, 34, 42, 11, 23, 26]
quickSort(list: &array1, low: 0, high: array1.count-1)  //array1数组改变为有序数组
var ret = array1.sorted(by: <)   //array1数组不变,返回有序数组ret


JavaScript写法:

var arr = [3, 1, 39, 21, 36, 37, 93, 56]
       quickSort(arr, 0, arr.length-1)  //测试
       
       function quickSort(array, low, high) {
       	   if (low < high) {
       	   	   var pos = partition(array, low, high)
       	   	   quickSort(array, low, pos-1)
       	   	   quickSort(array, pos+1, high)
       	   }
       }

       function partition(array, low, high) {
       	    var i = low
       	    var j = high
       	    var buf = array[low]

       	    while (i < j) {
       	    	while (i<j && array[j] >= buf) {
       	    		j--
       	    	}
       	    	array[i] = array[j]
       	    	while (i<j && array[i] <= buf) {
       	    		i++
       	    	}
       	    	array[j] = array[i]
       	    }
       	    array[i] = buf
       	    return i
       }

        对比Java,JavaScript和Swift3.0数组的定义方式不同, Java使用{}、Swift和JS使用[]。 其实Swift3.0排序是最方便的,调用sort方法就可以排序了,即:var ret = array.sorted(by: <)。

  

参考:https://juejin.im/post/5a08cc646fb9a045030f9174

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值