寫個快速排序看看:java
public static void sort(int[] a, int low, int high) { int i,j,t,temp; if(low>high) { return; } temp=a[low]; //基準 i=low; j=high; while(i!=j) { while(a[j]>=temp && i<j)//順序很重要 { j--; } while(a[i]<=temp && i<j) { i++; } if(i<j) { t=a[i]; a[i]=a[j]; a[j]=t; } }//再把基準數進行交換 a[low]=a[i]; a[i]=temp; sort(a,low,i-1);//遞歸 sort(a,i+1,high); }
快速排序使用分治的思想,經過一趟排序將待排序列分割成兩部分,其中一部分記錄的關鍵字均比另外一部分記錄的關鍵字小,另外一部分比基準點。以後分別對這兩部分記錄繼續進行排序,以達到整個序列有序的目的。數組
準備數據測一下:函數
int[] array = {12,21,15,16,15,1,36,40,3,9,66,9,34,25,77,7,2,56,-15,56,-3,69}; System.out.print("待排序:"); for (int aa:array ) { System.out.print(aa + " "); } System.out.println(""); int start = 0; int end = array.length-1; sort(array,start,end); // sort2(array,start,end); System.out.print("排序完:"); for (int a:array) { System.out.print(a + " "); }
排序的結果:性能
上面的操做是從右往左找到比基準小的,從左往右找到比基準大的,而後交換,最後交換基準位置。優化
還看到一種操做套路是把基準交換來換去,最後的效果也是同樣的。我是以爲第一種好一點,沒有那麼多交換操做排序
public static void sort2(int[] a, int low, int high){ int start = low; int end = high; int key = a[low]; while(end>start){ //從後往前比較 while(end>start&&a[end]>=key) { end--; } if(a[end]<key){ int temp = a[end]; a[end] = a[start]; a[start] = temp; } //從前日後比較 while(end>start&&a[start]<=key) { start++; } if(a[start]>key){ int temp = a[start]; a[start] = a[end]; a[end] = temp; } } //遞歸 if(start>low) { sort2(a, low, start - 1); } if(end<high) { sort2(a, end + 1, high); } }
這邊的選擇基準點就是選第一個數據,若是在數據基本有序的狀況下,你選擇第一個數據是比較糟糕的,因此若是針對的都是這樣的數據,那麼能夠考慮選擇隨機的位置做爲基準點,總不至於那麼倒黴吧,固然糟糕的時候仍是糟糕的,你懂我說的糟糕的時間的複雜度。遞歸
最佳的劃分是將待排序的序列分紅等長的子序列,最佳的狀態咱們可使用序列的中間的值。咱們但是學過中位數的數,前人們總結了一個隨機取三數(隨機也能夠直接取左邊,右邊,和中間,由於反正數據是隨機的,再弄一個隨機也不必),而後取中位數做爲基準,至少避開了那種最倒黴的狀況哈哈。咱們這邊只是取了三個數,若是加大樣本的數據,是方便了和加快了排序,可是前期就花了很多時間,具體仍是要根據排序數據規模來處理,並非放之四海皆準。編譯器
還有前輩們說對於很小和部分有序的數組,快排不如插排好。當待排序序列的長度分割到必定大小後,繼續分割的效率比插入排序要差,此時可使用插排而不是快排。我還不知道怎麼分析出來的,可是這樣有個地方,看排序的後面有個遞歸,若是待排序的序列劃分極端不平衡,遞歸的深度將趨近於n,而棧的大小是頗有限的,每次遞歸調用都會耗費必定的棧空間,函數的參數越多,每次遞歸耗費的空間也越多。因此這邊還能夠改爲尾遞歸,優化後,能夠縮減堆棧深度,聽說能夠由原來的O(n)縮減爲O(logn),將會提升性能,可是用java寫,說是編譯器沒對尾遞歸這種作過多的優化,因此......編譯