排序算法——快速排序

Posted

tags:

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

快速排序是对冒泡排序的一种改进。由C. A. R. Hoare在1962年提出。

 

基本思想:

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,递归这个过程,最终完成排序。

 

算法描述:

以升序为例。以最左边的数为基准数。设置左右两个指针,左指针初始位置为数组下标1位置,右指针初始位置为数组最大下标位置。

首先,右指针逐步向左移,直至找到一个比基准数的数,赋值到左指针所指为位置,

然后,左指针逐步向右移,直至找到一个比基准数的数,赋值到右指针所指为位置,

重复上述步骤,直至左、右指针位置重合

将此位置上的数字与基准数交换,

至此,本轮完成,基准数归位。

  对基准数左右两边的数,分别进行上述步骤,递归进行,完成排序。

过程如下图所示:

技术分享

 

Java代码实现:

 1 /**
 2  * 对数组进行升序快速排序
 3  *
 4  * @param arr:待排序数组
 5  */
 6 private static void quickSort(int[] arr) {
 7     if (arr == null || arr.length <= 1)
 8         return;
 9     _quickSort(arr, 0, arr.length - 1);
10 }
11 
12 /**
13  * 快速排序的底层方法
14  *
15  * @param arr:待排序数组
16  * @param left:数组下标下界
17  * @param right:数组下标上界
18  */
19 private static void _quickSort(int[] arr, int left, int right) {
20     if (left < right) {
21         int mid = getMid(arr, left, right);
22         //分治、递归
23         _quickSort(arr, left, mid - 1);
24         _quickSort(arr, mid + 1, right);
25     }
26 }
27 
28 /**
29  * 快速排序算法的一轮排序过程
30  *
31  * @param arr:待排序数组
32  * @param low:左指针初始位置
33  * @param high:右指针初始位置
34  * @return 基准数归位后的位置
35  */
36 private static int getMid(int[] arr, int low, int high) {
37     int key = arr[low];
38     while (low < high) {
39         //右指针向左遍历
40         while (low < high && arr[high] > key)
41             high--;
42         arr[low] = arr[high];
43         //左指针向右遍历
44         while (low < high && arr[low] < key)
45             low++;
46         arr[high] = arr[low];
47     }
48     //基准数归位
49     arr[low] = key;
50     return low;
51 }

 

 

特点:

1. 相对于冒泡排序,快速排序过程的比较和交换和是跳跃式的,因些总的比较和交换次数会变少。其平均时间复杂度是O(NlogN),最坏情况下的时间复杂度为冒泡排序一样,为O(N2)

2. 由于快速排序的交换基于基准数,如果待排序数组存在相同大小元素,过程中有可能会改变相同大小元素的顺序,因此快速排序是一种不稳定的排序算法。

3. 快速排序基于递归进行,因此会大量占用栈空间

 

优化:

对基准位置的选取,有3种方式:固定切分、随机切分和三数取中切分。上述采取的是固定切分方式,其效率并不理想。随机切分也较常用,效率稍高。最理想的是三数取中切分方式。

下面是三数取中切分方式的代码:

 1 /**
 2  * 快速排序算法的一轮排序过程
 3  *
 4  * @param arr:待排序数组
 5  * @param low:左指针初始位置
 6  * @param high:右指针初始位置
 7  * @return 基准数归位后的位置
 8  */
 9 private static int getMid(int[] arr, int low, int high) {
10     int key = getKey(arr, low, high); //基准数
11     while (low < high) {
12         //右指针向左遍历
13         while (low < high && arr[high] > key)
14             high--;
15         arr[low] = arr[high];
16         //左指针向右遍历
17         while (low < high && arr[low] < key)
18             low++;
19         arr[high] = arr[low];
20     }
21     //基准数归位
22     arr[low] = key;
23     return low;
24 }
25 
26 /**
27  * 三数取中方式获取基准数
28  *
29  * @param arr:待排序数组
30  * @param low:左指针初始位置
31  * @param high:右指针初始位置
32  * @return 基准数
33  */
34 private static int getKey(int[] arr, int low, int high) {
35     int mid = (high - low) / 2 + low;
36     if (arr[mid] > arr[high]) {
37         int temp = arr[mid];
38         arr[mid] = arr[high];
39         arr[high] = temp;
40     }
41     if (arr[low] > arr[high]) {
42         int temp = arr[low];
43         arr[low] = arr[high];
44         arr[high] = temp;
45     }
46     if (arr[mid] > arr[low]) {
47         int temp = arr[low];
48         arr[low] = arr[mid];
49         arr[mid] = temp;
50     }
51     return arr[low];
52 }

 

 

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

一行Python代码搞定快速排序算法

交换排序(冒泡排序快速排序的算法思想及代码实现)

排序算法 | 快速排序(含C++/Python代码实现)

[leetcode]排序算法(冒泡排序,选择排序,插入排序,快速排序,计数排序)

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

快速排序算法详解及代码实现