一、算法原理
基于分治的思想,是冒泡排序的改进型。首先在数组中选择一个基准点(该基准点的选取可能影响快速排序的效率,后面讲解选取的方法),然后分别从数组的两端扫描数组,设两个指示标志(low指向起始位置,high指向末尾),首先从后半部分开始,如果发现有元素比该基准点的值小,就交换low和high位置的值,然后从前半部分开始扫秒,发现有元素大于基准点的值,就交换low和hi位置的值,如此往复循环,直到low>=high,然后把基准点的值放到hi这个位置。一次排序就完成了。以后采用递归的方式分别对前半部分和后半部分排序,当前半部分和后半部分均有序时该数组就自然有序了。
二、算法举例

三、算法实现
1 /**
2 * 查找出中轴(默认是最低位low)的在numbers数组排序后所在位置
3 *
4 * @param array 待查找数组
5 * @param lo 开始位置
6 * @param hi 结束位置
7 * @return 中轴所在位置
8 */
9 static int getMiddle(int []array,int lo,int hi) {
10 //固定的切分方式
11 int key=array[lo];
12 while(lo<hi){
13 //从后半部分向前扫描
14 while(array[hi]>=key&&hi>lo){
15 hi--;
16 }
17 array[lo]=array[hi];
18 //从前半部分向后扫描
19 while(array[lo]<=key&&hi>lo){
20 lo++;
21 }
22 array[hi]=array[lo];
23 }
24 array[hi]=key;
25 return hi;
26 }
27
28 /**
29 *
30 * @param numbers 带排序数组
31 * @param low 开始位置
32 * @param high 结束位置
33 */
34 static int[] quickSort(int[] numbers,int low,int high) {
35 if(low < high) {
36 int middle = getMiddle(numbers,low,high); //将numbers数组进行一分为二
37 quickSort(numbers, low, middle-1); //对低字段表进行递归排序
38 quickSort(numbers, middle+1, high); //对高字段表进行递归排序
39 }
40 return numbers;
41 }
快速排序的时间复杂度为O(NlogN)。
四、算法优化
对于基准位置的选取一般有三种方法:固定切分,随机切分和三取样切分。固定切分的效率并不是太好,随机切分是常用的一种切分,效率比较高,最坏情况下时间复杂度有可能为O(N2).对于三数取中选择基准点是最理想的一种。
1 /**
2 *
3 * @param array 待排序的数组
4 * @param lo 开始位置
5 * @param hi 结束位置
6 * @return 基准值所在位置
7 */
8 static int partition(int []array,int lo,int hi){
9 //三数取中
10 int mid=lo+(hi-lo)/2;
11 if(array[mid]>array[hi]){
12 swap(array[mid],array[hi]);
13 }
14 if(array[lo]>array[hi]){
15 swap(array[lo],array[hi]);
16 }
17 if(array[mid]>array[lo]){
18 swap(array[mid],array[lo]);
19 }
20 int key=array[lo];
21
22 while(lo<hi){
23 while(array[hi]>=key&&hi>lo){
24 hi--;
25 }
26 array[lo]=array[hi];
27 while(array[lo]<=key&&hi>lo){
28 lo++;
29 }
30 array[hi]=array[lo];
31 }
32 array[hi]=key;
33 return hi;
34 }
35
36 /**
37 * 交换a,b的值
38 * @param a 待交换a
39 * @param b 待交换b
40 */
41 static void swap(int a,int b){
42 int temp=a;
43 a=b;
44 b=temp;
45 }
46
47 /**
48 *
49 * @param array 带排序数组
50 * @param lo 开始位置
51 * @param hi 结束位置
52 */
53 static int[] sort(int[] array,int lo ,int hi){
54 if(lo>=hi){
55 return array;
56 }
57 int index=partition(array,lo,hi);
58 sort(array,lo,index-1);
59 sort(array,index+1,hi);
60 return array;
61 }
快速排序在序列中元素很少时,效率将比较低,不然插入排序,因此一般在序列中元素很少时使用插入排序,这样可以提高整体效率。
测试用例:
1 package recursion;
2
3 import java.util.Arrays;
4
5 /**
6 * @author zsh
7 * @company wlgzs
8 * @create 2019-02-17 15:32
9 * @Describe 快速排序
10 */
11 public class QuickSort {
12
13 /**
14 * 查找出中轴(默认是最低位low)的在numbers数组排序后所在位置
15 *
16 * @param array 待查找数组
17 * @param lo 开始位置
18 * @param hi 结束位置
19 * @return 中轴所在位置
20 */
21 static int getMiddle(int []array,int lo,int hi) {
22 //固定的切分方式
23 int key=array[lo];
24 while(lo<hi){
25 //从后半部分向前扫描
26 while(array[hi]>=key&&hi>lo){
27 hi--;
28 }
29 array[lo]=array[hi];
30 //从前半部分向后扫描
31 while(array[lo]<=key&&hi>lo){
32 lo++;
33 }
34 array[hi]=array[lo];
35 }
36 array[hi]=key;
37 return hi;
38 }
39
40 /**
41 *
42 * @param numbers 带排序数组
43 * @param low 开始位置
44 * @param high 结束位置
45 */
46 static int[] quickSort(int[] numbers,int low,int high) {
47 if(low < high) {
48 int middle = getMiddle(numbers,low,high); //将numbers数组进行一分为二
49 quickSort(numbers, low, middle-1); //对低字段表进行递归排序
50 quickSort(numbers, middle+1, high); //对高字段表进行递归排序
51 }
52 return numbers;
53 }
54
55 /**
56 *
57 * @param array 待排序的数组
58 * @param lo 开始位置
59 * @param hi 结束位置
60 * @return 基准值所在位置
61 */
62 static int partition(int []array,int lo,int hi){
63 //三数取中
64 int mid=lo+(hi-lo)/2;
65 if(array[mid]>array[hi]){
66 swap(array[mid],array[hi]);
67 }
68 if(array[lo]>array[hi]){
69 swap(array[lo],array[hi]);
70 }
71 if(array[mid]>array[lo]){
72 swap(array[mid],array[lo]);
73 }
74 int key=array[lo];
75
76 while(lo<hi){
77 while(array[hi]>=key&&hi>lo){
78 hi--;
79 }
80 array[lo]=array[hi];
81 while(array[lo]<=key&&hi>lo){
82 lo++;
83 }
84 array[hi]=array[lo];
85 }
86 array[hi]=key;
87 return hi;
88 }
89
90 /**
91 * 交换a,b的值
92 * @param a 待交换a
93 * @param b 待交换b
94 */
95 static void swap(int a,int b){
96 int temp=a;
97 a=b;
98 b=temp;
99 }
100
101 /**
102 *
103 * @param array 带排序数组
104 * @param lo 开始位置
105 * @param hi 结束位置
106 */
107 static int[] sort(int[] array,int lo ,int hi){
108 if(lo>=hi){
109 return array;
110 }
111 int index=partition(array,lo,hi);
112 sort(array,lo,index-1);
113 sort(array,index+1,hi);
114 return array;
115 }
116
117 /**
118 * insertSort(arr,k) 递归实现插入排序
119 * 找重复:insertSort(arr,k-1) 将k-1个排序后,把arr[k]插入到前面的数据中 --子问题
120 * 找变化:变化的量应该作为参数 k。
121 * 找边界:出口 终止的条件 k == 0
122 */
123 static int[] insertSort(int[] arr,int k){
124 if (k == 0){
125 return arr;
126 }
127 //对前k-1个元素排序
128 insertSort(arr,k-1);
129 //把k位置上的元素插入到前面的部分
130 int x = arr[k];
131 int index = k -1;
132 while (index >= 0 && x <arr[index]){
133 arr[index+1] = arr[index];
134 index--;
135 }
136 arr[index+1] = x;
137 return arr;
138 }
139
140 /**
141 * 优化后的快速排序算法
142 * @param array 待排序数组
143 * @param lo 开始位置
144 * @param hi 结束位置
145 * @return 已排序的数组
146 */
147 static int[] quick(int []array ,int lo,int hi){
148 if(hi-lo+1<10){
149 return insertSort(array,array.length-1);
150 }else{
151 return sort(array,lo,hi);
152 }
153 }
154
155 public static void main(String[] args) {
156 int[] arr = new int[]{6,3,7,4,1,5,8,9,5,44,6,5};
157 System.out.println(Arrays.toString(quickSort(arr,0,arr.length-1)));
158 System.out.println(Arrays.toString(sort(arr,0,arr.length-1)));
159 System.out.println(Arrays.toString(quick(arr,0,arr.length-1)));
160 }
161 }
来源:https://www.cnblogs.com/zsh-blogs/p/10391541.html