快速排序

快速排序

快速排序算法首先会在序列中随机选择一个基准值(pivot),然后将除了基准值以外的数分为“比基准值小的数”和“比基准值大的数”这两个类别,再将其排列成以下形式。

[比基准值小的数] 基准值 [比基准值大的数]

接着,对两个“[ ]”中的数据进行排序之后,整体的排序便完成了。对“[]”里面的数据进行排序时同样也会使用快速排序。

 

基本思路

快速排序是一种“分治法”。它将原本的问题分成两个子问题(比基准值小的数和比基准值大的数),然后再分别解决这两个问题。子问题,也就是子序列完成排序后,再像一开始说明的那样,把他们合并成一个序列,那么对原始序列的排序也就完成了。

不过,解决子问题的时候会再次使用快速排序,甚至在这个快速排序里仍然要使用快速排序。只有在子问题里只剩一个数字的时候,排序才算完成。

 

快速排序效率

分割子序列时需要选择基准值,如果每次选择的基准值都能使得两个子序列的长度为原本的一半,那么快速排序的运行时间和归并排序的一样,都为O(nlogn)。和归并排序类似,将序列对半分割log2n次之后,子序列里便只剩下一个数据,这时子序列的排序也就完成了。因此,如果像下图这样一行行地展现根据基准值分割序列的过程,那么总共会有log2n行。

 

 每行中每个数字都需要和基准值比较大小,因此每行所需的运行时间为O(n)。由此可知,整体的时间复杂度为O(nlogn)。

如果运气不好,每次都选择最小值作为基准值,那么每次都需要把其他数据移到基准值的右边,递归执行n行,运行时间也就成了O(n2)。这就相当于每次都选出最小值并把它移到了最左边,这个操作也就和选择排序一样了。此外,如果数据中的每个数字被选为基准值的概率都相等,那么需要的平均运行时间为O(nlogn)。

 

代码示例

示例1:

private static List<Integer> quicksort(List<Integer> list) {
    if (list.size() < 2) { // 基线条件:为空或只包含一个元素的数组是“有序”的
        // base case, arrays with 0 or 1 element are already "sorted"
        return list;
    } else {
        // recursive case
        // 递归条件
        Integer pivot = list.get(0);

        // sub-array of all the elements less than the pivot
        // 由所有小于基准值的元素组成的子数组
        List<Integer> less = list.stream().skip(1).filter(el -> el <= pivot).collect(Collectors.toList());

        // sub-array of all the elements greater than the pivot
        // 由所有大于基准值的元素组成的子数组
        List<Integer> greater = list.stream().skip(1).filter(el -> el > pivot).collect(Collectors.toList());

        return Stream.of(quicksort(less).stream(), Stream.of(pivot), quicksort(greater).stream())
                .flatMap(Function.identity()).collect(Collectors.toList());
    }
}

public static void main(String[] args) {
    System.out.println(quicksort(Arrays.asList(10, 5, 2, 3))); // [2, 3, 5, 10]
}

 

示例2:

static void quickSort(int[] arr, int left, int right) {
    int temp, ltemp = left, rtemp = right;
    int f = arr[(left + right) / 2];//分界值

    while (ltemp < rtemp) {
        while (arr[ltemp] < f) {//找出左边 大于分界值的 index
            ++ltemp;
        }
        while (arr[rtemp] > f) {//找出右边 大于分界值的 index
            --rtemp;
        }
        if (ltemp <= rtemp) {
            //ltemp和rtemp互换
            temp = arr[ltemp];
            arr[ltemp] = arr[rtemp];
            arr[rtemp] = temp;
            ++ltemp;
            --rtemp;
        }
    }
    if (ltemp == rtemp) {
        ltemp++;
    }
    if (left < rtemp) {
        quickSort(arr, left, ltemp - 1);
    }
    if (ltemp < right) {
        quickSort(arr, rtemp + 1, right);
    }
    System.out.println(ArrayUtils.toString(arr));
}

public static void main(String[] args) {
    quickSort(new int[]{5, 4, 3, 2, 1}, 0, 4);
}

 

参考:

百度百科-快速排序

Java常用算法手册-4.6

我的第一本算法书 2-7 快速排序

 

posted @ 2018-06-03 17:19  草木物语  阅读(212)  评论(0编辑  收藏  举报