1 package sorting;
2
3 import java.util.*;
4 //import java.util.Comparator;
5 //import java.util.PriorityQueue;
6 //import java.util.Queue;
7
8 public class Sorting {
9 /************************************序言**********************************************/
10 /**
11 * 排序方法:冒泡排序,插入排序,希尔排序,堆排序(2),归并排序(2),快排(2)...
12 * */
13
14 /**
15 * 最小值函数
16 * */
17 private static <AnyType extends Comparable<? super AnyType>> AnyType min(AnyType a, AnyType b){
18 if(a.compareTo(b) <= 0)
19 return a;
20 else
21 return b;
22 }
23
24 /**
25 * 交换函数
26 * */
27 private static <AnyType extends Comparable<? super AnyType>> void swap(AnyType [] a, int m, int n){
28 AnyType tmp = a[n];
29 a[n] = a[m];
30 a[m] = tmp;
31 }
32 /**********************************BubleSort*****************************************/
33 /**
34 * 冒泡排序:BubleSort
35 * 每次内层循环最大的都被滤到最后
36 * */
37 public static <AnyType extends Comparable<? super AnyType>> void bubleSort(AnyType [] a){
38 for(int i=0;i<a.length;i++){
39 for(int j=0;j<a.length-1-i;j++){
40 if(a[j].compareTo(a[j+1]) > 0){ //如果后一个数小于前一个数交换
41 AnyType tmp=a[j];
42 a[j]=a[j+1];
43 a[j+1]=tmp;
44 }
45 }
46 }
47 }
48 /*************************SelectSort*************************************************/
49 /***
50 * 选择排序:SelectSort
51 * 每次内层循环最小的被滤到最前
52 */
53 public static <AnyType extends Comparable<? super AnyType>> void selectSort(AnyType[] a) {
54 int minIndex;
55 for (int i = 0; i < a.length; i++) {
56 minIndex = i;
57 for (int j = i + 1; j < a.length; j++) {
58 if ((a[j].compareTo(a[minIndex])) < 0) {
59 minIndex = j;
60 }
61 }
62 swap(a, i, minIndex);
63 }
64 }
65
66 /*************************InsertionSort**********************************************/
67 /***
68 * 插入排序:InsertionSort
69 * @param a
70 * 插入排序的实质是从a[1]~a[a.length-1]开始,逐个比较a[p](p=1,2,...,a.length-1)与a[j-1]的值,直至找到a[p]的位置。
71 */
72 public static <AnyType extends Comparable<? super AnyType>> void insertionSort(AnyType [] a){
73 int j;
74 for(int p = 1; p < a.length; p++){
75 AnyType tmp = a[p]; //务必使用tmp变量,否则可能第一轮比较过后啊a[p]也即a[j]的值被覆盖
76 for(j = p; j > 0 && tmp.compareTo(a[j - 1])<0;j--){//等于就不挪了,省一次操作
77 a[j] = a[j-1];
78 }
79 a[j] = tmp;
80
81 }
82 }
83 /*************************ShellSort**********************************************/
84 /**
85 * 希尔排序:ShellSort 最坏情形:O(N2)
86 * @param a
87 * 希尔排序(即间隔排序)的作用:对于间隔k,希尔排序即对k个独立的子数组的一次插入排序
88 */
89 public static <AnyType extends Comparable<? super AnyType>> void shellSort(AnyType [] a){
90 int j;
91 for(int gap = a.length / 2; gap > 0; gap /= 2 ){
92 //同时对k个子数组进行间隔排序,相当于和并单独子数组排序的两个for循环 for(int i=0;i<gap;i++){for(int p=i;i<a.length;p+=gap){}}
93 for(int i = gap;i < a.length;i++){
94 //每个子数组的插入排序
95 AnyType tmp = a[i];
96 for(j = i;j >= gap && tmp.compareTo(a[j-gap])<0;j-=gap){//等于就不挪了,省一次操作
97 a[j] = a[j-gap];
98 }
99 a[j] = tmp;
100 }
101 }
102 }
103 /*************************HeapSort**********************************************/
104 /**
105 * 堆排序:HeapSort1 最坏情形:O(Nlog(N)) 堆排序要比希尔排序要慢
106 * @param a
107 * 堆排序使用优先队列java.util.PriorityQueue实现
108 */
109 public static <AnyType extends Comparable<? super AnyType>> void heapSort1(AnyType [] a){
110 Comparator<AnyType> comparator = new Comparator<AnyType>(){
111 public int compare(AnyType left, AnyType right){
112 return left.compareTo(right) ;
113 }
114 };
115 Queue<AnyType> heap = new PriorityQueue<AnyType>(a.length,comparator);
116 for(AnyType e:a){
117 heap.add(e);
118 }
119 int i = 0;
120 while(!heap.isEmpty()){
121 a[i++] = heap.poll();
122 }
123 }
124 /****************************************************************************************/
125 /**
126 * 堆排序:HeapSort2 最坏情形:O(Nlog(N))
127 * @param a
128 * 使用基础代码实现,建堆,排序
129 */
130 /**
131 * 求左子节点
132 * */
133 private static int leftChild(int i){
134 return 2 * i + 1;
135 }
136 /**
137 * 下滤函数:deleteMin(deleteMax)时候使用
138 * 对于大根堆下滤期间,大数被逐次滤上去(一步一步),小数被一直滤到它该到的位置(for结束后)
139 * @param a 堆数组
140 * @param i 开始下滤的起点
141 * @param n 堆的有效数组长度,随着不断deleteMax操作,堆中元素会不断减少,有效数组长度n也会逐渐减小
142 */
143 private static <AnyType extends Comparable<? super AnyType>> void percolateDown(AnyType[] a, int i, int n){
144 int child;//左右子中较小的那个节点
145 AnyType tmp = a[i];
146
147 for(; leftChild(i)< n; i = child){//leftChild(i)< n 判断是否到达最后一个叶子节点
148 child = leftChild(i);
149 //如果只有一个左子节点,那么不必判断那个更大了
150 if(child != n-1 && a[child].compareTo( a[child + 1] ) < 0)//child!=n-1为了确定是否有两个子节点
151 child++;//将两个儿子中大的那个滤上去
152 if(tmp.compareTo( a[child]) < 0 ){//等于就不挪了,省一次操作
153 a[i]=a[child];//大数被逐次滤上去(一步一步)
154 }else
155 break;
156 }
157 a[i]=tmp;//小数被for一直滤下来
158 }
159
160 /**
161 * 排序结果:升序 ,使用大根堆
162 * 建立大根堆,deleteMin操作,得到排序数组
163 * 下虑操作:在建立二叉堆和deleteMin中都有使用
164 * */
165 public static <AnyType extends Comparable<? super AnyType>> void heapSort2(AnyType [] a){
166 /* 在无序数组上直接下滤建立大根堆
167 * 从低向上开始下滤,即最后一个节点的父节点下滤即a[length/2]
168 * 堆从数组索引0开始,因此左子节点为2*i+1,右子节点为2*i+2
169 * */
170 for(int i = a.length/2; i >= 0; i--){
171 percolateDown(a, i, a.length);
172 }
173 /* 堆排序:不断deleteMax将堆中最大的元素放置于数组a的末端
174 * */
175 for(int j = a.length-1; j >= 0; j--){
176 //deleteMax
177 AnyType tmp = a[j];
178 a[j] = a[0];
179 //将队尾元素放置堆根处,开始下滤
180 a[0] = tmp;
181 percolateDown(a, 0, j);//初始时刻j为a.length-1
182 }
183 }
184 /*************************MergeSort**********************************************/
185 /**
186 * 归并排序:MergeSort1 最坏运行时间O(Nlog(N)) 对空间有要求,线性内存 比较次数最少
187 * 注意: 归并排序严重依赖于比较元素和数组中移动元素的相对开销,是语言相关的。
188 * 其中:java中,执行一次泛型排序(Comparator)时 ,比较(不容易内嵌,动态调度)的的开销要大于移动元素(引用赋值);由于比较次数最少,是标准java类库中泛型排序所使用的算法。
189 * 而 C++则相反,其泛型排序中如果对象庞大,拷贝对象开销大,比较相对省时。C++库中使用快速排序方法。
190 * @param a
191 * 实现方式:递归,本质就是一直讲待排序的数组二分下去,直至每一半均只有一个元素然后依次合并,完成排序。
192 * */
193
194 /**
195 * 实际完成归并排序的过程的程序
196 * */
197 private static <AnyType extends Comparable<? super AnyType>> void merge(AnyType [] a, AnyType [] tmpArray, int leftPos, int rightPos, int rightEnd){
198 int leftEnd = rightPos - 1;
199 int tmpPos = leftPos;
200 int numElements = rightEnd - leftPos + 1;
201
202 while(leftPos <= leftEnd && rightPos <= rightEnd){
203 if(a[leftPos].compareTo(a[rightPos]) <= 0)//等不等于都得拷贝
204 tmpArray[tmpPos++] = a[leftPos++];
205 else
206 tmpArray[tmpPos++] = a[rightPos++];
207 }
208 while(leftPos <= leftEnd){
209 tmpArray[tmpPos++] = a[leftPos++];
210 }
211 while(rightPos <= rightEnd){
212 tmpArray[tmpPos++] = a[rightPos++];
213 }
214 for(int i = numElements; i >0; i--){
215 a[rightEnd] = tmpArray[rightEnd];
216 rightEnd--;//注意rightEnd要单独拿出来自减,否则在上个语句中会自减两次
217 }
218 }
219
220 /**
221 * 主递归程序
222 * */
223 private static <AnyType extends Comparable<? super AnyType>> void mergeSort(AnyType [] a, AnyType [] tmpArray, int left, int right){
224 if(left < right){
225 int center = (left + right)/2;
226 mergeSort(a, tmpArray, left, center);
227 mergeSort(a, tmpArray, center + 1, right);
228 merge(a, tmpArray, left, center + 1, right);//实际完成排序过程
229 }
230 }
231
232 /**
233 * 归并排序驱动程序
234 * */
235 public static <AnyType extends Comparable<? super AnyType>> void MergeSort1(AnyType [] a){
236 AnyType [] tmpArray = (AnyType[]) new Comparable[a.length];
237 mergeSort(a, tmpArray, 0, a.length - 1);
238 }
239
240 /********************************************************************************/
241 /**
242 * 归并排序:MergeSort2 最坏运行时间O(Nlog(N))
243 * @param a
244 * 实现方式:非递归,从单个元素开始归并合成小组,然后小组之间归并直至归并成一个完整的数组,依旧使用MergeSort1使用的merge函数
245 * */
246 public static <AnyType extends Comparable<? super AnyType>> void MergeSort2(AnyType [] a){
247 int n = a.length;
248 AnyType[] tmpArray = (AnyType[]) new Comparable[n];
249 for(int subList = 1; subList < n; subList *=2){
250 int leftPos = 0;
251 while(leftPos + subList < n){
252 int rightPos = leftPos + subList;
253 // int leftEnd = rightPos - 1;
254 int rightEnd = min(n-1, rightPos + subList - 1); //一定要注意不能越界 min
255 merge(a, tmpArray, leftPos, rightPos, rightEnd);
256 leftPos = rightEnd + 1; //等同于leftPos += 2 * subList;
257 }
258 }
259 }
260 /*************************QuickSort**********************************************/
261 /**
262 * 快速排序:QuickSort1 平均运行时间:O(NlogN) 最坏运行时间:O(N2)
263 * 使用三数中值分割法选取枢纽元
264 * 由于对于小数组(N<=20),快速排序的递归会不如插入排序,因此该程序调用插入排序函数。截止范围CUTOFF=10
265 * */
266
267
268 /**
269 * 三数中值分割法:取左端,右端,中心位置的三个元素的中值作为枢纽元
270 * 实在值得注意的一点是:三数中值分割法有效的条件是left+2<=right(即至少要有三个元素)的时候才成立,对于2个及2个一下元素将会出现错误。
271 * 排序后最小的将位于a[left],最大的位于a[right],枢纽元即中间值a[center]将被放置于a[right-1](亦即交换a[center]与a[right-1])
272 * 这样在分隔阶段,i,j将从left+1和right-2开始比较
273 * 三数中值分割法的好处:a[left]比枢纽元小,将作为j的警戒标记;而a[right-1]存放着枢纽元,则自然作为i的警戒标记。
274 * */
275 private static <AnyType extends Comparable<? super AnyType>> AnyType median3(AnyType [] a, int left, int right){
276 int center = (left + right)/2;
277 if(a[center].compareTo(a[left]) < 0)
278 swap(a, center, left);
279 if(a[right].compareTo(a[left]) < 0)
280 swap(a, right, left);
281 if(a[right].compareTo(a[center]) < 0)
282 swap(a, right, center);
283 //将枢纽元至于a[right - 1]的位置上
284 swap(a, center, right - 1);
285 return a[right - 1];
286 }
287 /**
288 * 分割策略
289 * */
290 private static <AnyType extends Comparable<? super AnyType>> int partition(AnyType [] a, int left, int right){
291 AnyType pivot = median3(a, left, right);
292 //由于pivot放置在了a[right - 1]的位置(暂存pivot),因此i,j的取值应该为 left + 1,和right - 2
293 int i = left, j = right - 1;
294 for(;;){
295 //在遇到i,j处值都等于pivot时候停下,但是还得继续道,j<i才算结束,因此while编写要格外注意
296 while(a[++i].compareTo(pivot) < 0){}//遇到跟pivot枢纽元值相等的值要停下,否则N2效率低下
297 while(a[--j].compareTo(pivot) > 0){}
298 if(i < j)
299 swap(a, i, j);
300 else
301 break;
302 }
303 // for(;;){
304 // while(a[i].compareTo(pivot) < 0){i++;}
305 // while(a[j].compareTo(pivot) > 0){j--;}
306 // if(i < j){
307 // swap(a, i, j);
308 // i++;j--;
309 // }
310 // else
311 // break;
312 // }
313 swap(a, i, right - 1);
314 return i;
315 }
316 /**
317 * 快速排序递归程序,主体程序,遇到跟pivot枢纽元值相等的值要停下
318 * 前提条件:left+1<right(即left+2<=right)
319 * 实在值得注意的一点是:三数中值分割法有效的条件是left+2<=right(即至少要有三个元素)的时候才成立,对于2个及2个一下元素将会出现错误;
320 * 而这里当CUTOFF设置为1时候,仍旧没有错误的原因是else条件下的insertionSort(a)起了作用
321 * */
322 private static final int CUTOFF = 10;//CUTOFF>=2
323 private static <AnyType extends Comparable<? super AnyType>> void qSort(AnyType [] a, int left, int right){
324 //利用截止范围判断数据量
325 if(left + CUTOFF <= right){
326 //获取枢纽元
327 // AnyType pivot = median3(a, left, right);
328 // //由于pivot放置在了a[right - 1]的位置(暂存pivot),因此i,j的取值应该为 left + 1,和right - 2
329 // int i = left, j = right - 1;
330 // for(;;){
331 // //在遇到i,j处值都等于pivot时候停下,但是还得继续道,j<i才算结束,因此while编写要格外注意
332 // while(a[++i].compareTo(pivot) < 0){}//遇到跟pivot枢纽元值相等的值要停下,否则N2效率低下
333 // while(a[--j].compareTo(pivot) > 0){}
334 // if(i < j)
335 // swap(a, i, j);
336 // else
337 // break;
338 // }
339 // for(;;){
340 // while(a[i].compareTo(pivot) < 0){i++;}
341 // while(a[j].compareTo(pivot) > 0){j--;}
342 // if(i < j){
343 // swap(a, i, j);
344 // i++;j--;
345 // }
346 // else
347 // break;
348 // }
349 //因为i左边都比pivot小,i及i右边除了right-1除存放着pivot外都比pivot大,因此将i处值与right-1处值交换
350 //即得到i左边都比其小,右边都比其大,i即pivot排序好的正确位置(换回pivot)
351 // swap(a, i, right - 1);
352 int i = partition(a, left, right);
353 //i已排好序
354 qSort(a, left, i - 1);
355 qSort(a, i + 1, right);
356 }else{
357 insertionSort(a);//在这里处理了当CUTOFF等于1时的情景不会出错。当CUTOFF等于0时首先是不允许的(那样left就等于right了),其次这会导致median3()函数数组索引越界异常
358 }
359 }
360 /**
361 * 快速排序驱动程序
362 * */
363 public static <AnyType extends Comparable<? super AnyType>> void quickSort(AnyType [] a){
364 qSort(a, 0, a.length - 1);
365 }
366
367 /*********************************QuickSort2***************************************/
368 /**
369 * 分割策略
370 * */
371 private static <AnyType extends Comparable<? super AnyType>> int partition2(AnyType [] a, int start, int end){
372 int i = start, j = end;
373 AnyType base = a[start];
374 while(i < j ){
375 while((a[j].compareTo(base) > 0) && (j > i))
376 j--;
377 if(i < j){
378 a[i] = a[j];
379 i++;//
380 }
381 while((a[i].compareTo(base) < 0) && (i < j))
382 i++;
383 if(i < j){
384 a[j] = a[i];
385 j--;//
386 }
387
388 }//while
389 a[i] = base;
390 return i;
391 }
392 /**
393 * 使用数组第一位作为枢纽元
394 * 前提条件:start<end
395 * */
396 private static <AnyType extends Comparable<? super AnyType>> void qSort2(AnyType [] a, int start, int end){
397 if(start < end){
398 // int i = start, j = end;
399 // AnyType base = a[start];
400 // while(i < j ){
401 // while((a[j].compareTo(base) > 0) && (j > i))
402 // j--;
403 // if(i < j){
404 // a[i] = a[j];
405 // i++;//
406 // }
407 // while((a[i].compareTo(base) < 0) && (i < j))
408 // i++;
409 // if(i < j){
410 // a[j] = a[i];
411 // j--;//
412 // }
413 //
414 // }//while
415 // a[i] = base;
416 int i = partition2(a, start, end);
417
418 qSort2(a, start, i-1);
419 qSort2(a, i+1, end);
420 }
421
422 }
423 /**
424 * 驱动程序
425 * 使用数组第一位作为枢纽元
426 * */
427 public static <AnyType extends Comparable<? super AnyType>> void quickSort2(AnyType [] a){
428 qSort2(a, 0, a.length-1);
429 }
430 /*********************************QuickSort3***************************************/
431 /**
432 * 三数中值分割的使用非递归的快速排序
433 * */
434 public static <AnyType extends Comparable<? super AnyType>> void quickSort3(AnyType [] a){
435 if(a==null||a.length<=0)return;
436 Stack<Integer> index=new Stack<Integer>();
437 int start=0;
438 int end=a.length-1;
439
440 int pivotPos;
441
442 index.push(start);
443 index.push(end);
444
445 while(!index.isEmpty()){
446 end=index.pop();
447 start=index.pop();
448 if(start+1<end){//三数中值必备
449 pivotPos=partition(a,start,end);
450
451 if(start<pivotPos-1){
452 index.push(start);
453 index.push(pivotPos-1);
454 }
455 if(end>pivotPos+1){
456 index.push(pivotPos+1);
457 index.push(end);
458
459 }
460 }else{//三数中值必备
461 if(a[start].compareTo(a[end])>0)
462 swap(a, start, end);
463 }
464 }
465 }
466 /*********************************QuickSort4***************************************/
467 /**
468 * 使用第一值为枢纽元的使用非递归的快速排序
469 * */
470 public static <AnyType extends Comparable<? super AnyType>> void quickSort4(AnyType [] a){
471 if(a==null||a.length<=0)return;
472 Stack<Integer> index=new Stack<Integer>();
473 int start=0;
474 int end=a.length-1;
475
476 int pivotPos;
477
478 index.push(start);
479 index.push(end);
480
481 while(!index.isEmpty()){
482 end=index.pop();
483 start=index.pop();
484 // if(start<end){ //可有可无,因为压栈的时候已能确定start<end,此处判断是恒成立的
485 pivotPos=partition2(a,start,end);
486
487 if(start<pivotPos-1){
488 index.push(start);
489 index.push(pivotPos-1);
490 }
491 if(end>pivotPos+1){
492 index.push(pivotPos+1);
493 index.push(end);
494
495 }
496 // }
497 }
498 }
499
500 /*-----------------------------------------main-------------------------------------------------*/
501 public static void main(String[] args) {
502 // TODO Auto-generated method stub
503 /**
504 * Test case: Sort the array.
505 * */
506 // Integer[] a ={3,1,4,1,5,9,111,2,6,142,543,123,65,453,123,879,572,434,111,242,811,102};
507 Integer[] a ={3,1,4,1,5,9,2,6};
508 System.out.println("Before sorting:");
509 for(Integer i:a){
510 System.out.print(i+",");
511 }
512 System.out.println();
513
514 Sorting.quickSort4(a);//排序方法调用
515 System.out.println("After sorting:");
516 for(Integer i:a){
517 System.out.print(i+",");
518 }
519 System.out.println();
520
521
522 }
523
524 }