浅谈快速排序算法

Posted Bossky程序员

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈快速排序算法相关的知识,希望对你有一定的参考价值。

今天有个同学问起一道关于快排的考试题,一时竟没想起来,确实排序算法在日常工作中自己写的机会不多,所以也就遗忘了。

虽然用的机会不多,但是知道总是好的,所以趁着有空,恶补一下。


快速排序是交换排序的一种,是冒泡排序的改进,使用分治法策略来把一个序列(list)分为两个子序列(sub-lists)。


步骤为:

1.从数列中挑出一个元素,称为"基准"(pivot),

2.重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(相同的数可以到任何一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。

递归地(recursively)把小于基准值元素的子数列和大于基准值元素的子数列排序。

3.递归到最底部时,数列的大小是零或一,也就是已经排序好了。这个算法一定会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。


下面我们通过举例说明排序过程

待排元素

{73,13,70,23,95,16,5,68,26,45}


首先,我们要挑出一个元素为"基准",这个"基准"并没有硬性规定,但是为了处理方便,我们一般都选择数组的第一个元素。则对于待排元素

pivot=73

然后,我们拿pivot跟剩下的元素比较,我们先从后向前扫描,找到第一个比pivot小的则(后面的都要比pivot大的),同理,我们从前向后扫描,找到第一个比pivot大的(前面的 都要比pivot小)。

扫描后,我们得到了95跟45这两个数的位置不对。

这时,我们想一想把45跟95交换一下位置,是不是就符合要求了?

交换后,得出

{73,13,70,23,45,16,5,68,26,95}

现在我们从前扫描到了45的位置,确定了45之前的都比privot小,从后扫描到了95的位置,确定95之后都比privot大。

所以我们从这两个点继续扫描(第一次扫描还没结束的),

一样先从后往前,到26时,发现比privot小了。再从45开始从前向后扫描。

当扫描到26时,还是没找到比privot大的数,扫描结束(后面的都比privot大了)

我们得出了26之前的数(包括26)都比privot大小,26之后的数都比privot大(不包括26),这时我们就要考虑privot的位置了。

因为我们选择的是数据第一位做为基准,所以privot也是在26前面的。

并且privot>26,所以交换它们的位置。

最终第一次扫描的结束如下

{26,13,70,23,45,16,5,68,73,95}      


这时,我们得出了在基准位置(值73所在)前面的值都小于它,后面的则都大于它。有了这个,我们可以将数列分割成两个子数列

{26,13,70,23,45,16,5,68} ,{73}, {95}

之前的基准不需要在参与排序了。


我们开始第二次扫描,步骤与第一次扫描类似,分别对两个子数列扫描排序。

得出

{16,13,5,23,26,45,70,68},{73}, {95}


第一个子数列最终的基准位置在26,再次分割

第二个子数列{95}只有一个元素,所以是不需要再分隔跟排序的。

第二次扫描的结果为

{16,13,5,23},{26},{45,70,68},{73} , {95}


第三次扫描

{5,13,16,23},{26}{45,70,68} ,{73}, {95}

分割

{5,13},{16},{23},{26}{45,70,68} ,{73}, {95}


第四次扫描

{5,13},{16},{23},{26},{45,70,68} ,{73}, {95}

分割

{5},{13},{16},{23},{26},{45,70,68}  ,{73}, {95}


第五次扫描

{5},{13},{16},{23},{26},{45,70,68}  ,{73}, {95}

分割

{5},{13},{16},{23},{26}{45},{70,68}  ,{73}, {95}


第六次扫描

{5},{13},{16},{23},{26}{45},{68,70}  ,{73}, {95}

分割

{5},{13},{16},{23},{26}{45},{68},{70}  ,{73}, {95}


将上面的分析转换成代码

public static void quickSort(int[] arr) {

    quickSort(arr, 0, arr.length - 1);

}


static void quickSort(int[] arr, int first, int last) {

    if (first >= last) {

        return;

    }

    int pivot = arr[first];

    int low = first + 1;

    int high = last;

    while (high != low) {

        // 从后向前扫描,保证后面的大于pivot

while (low < high && arr[high] >= (pivot)) {

high--;

}

// 从前向后扫描,保证前面的小于pivot

while (low < high && arr[low] < (pivot)) {

low++;

}

       if (high != low) {// 还没相遇

int temp = arr[high];

arr[high] = arr[low];

arr[low] = temp;

}

    }

    int p = 0;

    if (pivot > arr[high]) {

arr[first] = arr[high];

arr[high] = pivot;

p = high;

    } else {

p = first;

    }

    quickSort(arr, first, p - 1);

    quickSort(arr, p + 1, last);

}



以上是关于浅谈快速排序算法的主要内容,如果未能解决你的问题,请参考以下文章

浅谈快速排序

排序算法系列:快速排序算法

算法排序算法之快速排序

十大经典排序算法总结(快速排序)

排序算法系列:快速排序算法

用C语言编程实现快速排序算法