五、快速排序(Quick Sort)
1. 基本思想:
在当前无序区R[1..H]中任取一个数据元素作为比较的"基准"(不妨记为X),用此基准将当前无序区划分为左右两个较小的无序区:R[1..I-1]和R[I+1..H],且左边的无序子区中数据元素均小于等于基准元素,右边的无序子区中数据元素均大于等于基准元素,而基准X则位于最终排序的位置上,即R[1..I-1]≤X.Key≤R[I+1..H](1≤I≤H),当R[1..I-1]和R[I+1..H]均非空时,分别对它们进行上述的划分过程,直至所有无序子区中的数据元素均已排序为止。
2. 排序过程:
【示例】:
初始关键字 [49 38 65 97 76 13 27 49]
一趟排序之后 [27 38 13]49 [76 97 65 49]
二趟排序之后 [13]27 [38]49 [49 65]76 [97]
三趟排序之后13 27 38 49 49 [65]76 97
最后的排序结果13 27 38 49 49 65 76 97
各趟排序之后的状态
java代码实现:
01.
04.
05.public class QuickSort {
06.
07.
14. //定义了一个这样的公有方法sort,在这个方法体里面执行私有方法quckSort(这种方式值得借鉴)。
15. public void sort(Integer[] array, int from, int end) {
16. quickSort(array, from, end);
17. }
18.
19.
26. private void quickSort(Integer[] array, int low, int high) {
27.
32. if (low < high) {
33. //对分区进行排序整理
34.
35. //int pivot = partition1(array, low, high);
36. int pivot = partition2(array, low, high);
37. //int pivot = partition3(array, low, high);
38.
39.
44. quickSort(array, low, pivot - 1);
45. quickSort(array, pivot + 1, high);
46. }
47.
48. }
49.
50.
59. private int partition1(Integer[] array, int low, int high) {
60. Integer pivotElem = array[low];//以第一个元素为中枢元素
61. //从前向后依次指向比中枢元素小的元素,刚开始时指向中枢,也是小于与大小中枢的元素的分界点
62. int border = low;
63.
64.
69. for (int i = low + 1; i <= high; i++) {
70. //如果找到一个比中枢元素小的元素
71. if ((array[i].compareTo(pivotElem)) < 0) {
72. swap(array, ++border, i);//border前移,表示有小于中枢元素的元素
73. }
74. }
75.
83. swap(array, border, low);
84. return border;
85. }
86.
87.
96. private int partition2(Integer[] array, int low, int high) {
97. int pivot = low;//中枢元素位置,我们以第一个元素为中枢元素
98. //退出条件这里只可能是low = high
99. while (true) {
100. if (pivot != high) {//如果中枢元素在低指针位置时,我们移动高指针
101. //如果高指针元素小于中枢元素时,则与中枢元素交换
102. if ((array[high].compareTo(array[pivot])) < 0) {
103. swap(array, high, pivot);
104. //交换后中枢元素在高指针位置了
105. pivot = high;
106. } else {//如果未找到小于中枢元素,则高指针前移继续找
107. high--;
108. }
109. } else {//否则中枢元素在高指针位置
110. //如果低指针元素大于中枢元素时,则与中枢元素交换
111. if ((array[low].compareTo(array[pivot])) > 0) {
112. swap(array, low, pivot);
113. //交换后中枢元素在低指针位置了
114. pivot = low;
115. } else {//如果未找到大于中枢元素,则低指针后移继续找
116. low++;
117. }
118. }
119. if (low == high) {
120. break;
121. }
122. }
123. //返回中枢元素所在位置,以便下次分区
124. return pivot;
125. }
126.
127.
136. private int partition3(Integer[] array, int low, int high) {
137. int pivot = low;//中枢元素位置,我们以第一个元素为中枢元素
138. low++;
139. //----调整高低指针所指向的元素顺序,把小于中枢元素的移到前部分,大于中枢元素的移到后面部分
140. //退出条件这里只可能是low = high
141.
142. while (true) {
143. //如果高指针未超出低指针
144. while (low < high) {
145. //如果低指针指向的元素大于或等于中枢元素时表示找到了,退出,注:等于时也要后移
146. if ((array[low].compareTo(array[pivot])) >= 0) {
147. break;
148. } else {//如果低指针指向的元素小于中枢元素时继续找
149. low++;
150. }
151. }
152.
153. while (high > low) {
154. //如果高指针指向的元素小于中枢元素时表示找到,退出
155. if ((array[high].compareTo(array[pivot])) < 0) {
156. break;
157. } else {//如果高指针指向的元素大于中枢元素时继续找
158. high--;
159. }
160. }
161. //退出上面循环时low = high
162. if (low == high) {
163. break;
164. }
165.
166. swap(array, low, high);
167. }
168.
169. //----高低指针所指向的元素排序完成后,还得要把中枢元素放到适当的位置
170. if ((array[pivot].compareTo(array[low])) > 0) {
171. //如果退出循环时中枢元素大于了低指针或高指针元素时,中枢元素需与low元素交换
172. swap(array, low, pivot);
173. pivot = low;
174. } else if ((array[pivot].compareTo(array[low])) <= 0) {
175. swap(array, low - 1, pivot);
176. pivot = low - 1;
177. }
178.
179. //返回中枢元素所在位置,以便下次分区
180. return pivot;
181. }
182.
183.
189. public void swap(Integer[] array, int i, int j) {
190. if (i != j) {//只有不是同一位置时才需交换
191. Integer tmp = array[i];
192. array[i] = array[j];
193. array[j] = tmp;
194. }
195. }
196.
197.
201. public static void main(String[] args) {
202. Integer[] intgArr = { 5, 9, 1, 4, 2, 6, 3, 8, 0, 7 };
203. QuickSort quicksort = new QuickSort();
204. quicksort.sort(intgArr,0,intgArr.length-1);
205. for(Integer intObj:intgArr){
206. System.out.print(intObj + " ");
207. }
208. }
209.}