排序算法是比較常見的算法,道理也比較簡單,雙指針法。今天被朋友問了個舍伍德排序算法,也是快速排序那種形式。尷尬,第一次據說,特地學了一下。結合快速排序,寫了三個方法。
第一種:java
//不須要將基準值歸位的快速排序 public static void quickSort(int []a,int left,int right) { if(left>=right) return ; int i = left ;//左指針 int j = right ;//右指針 int key = a[i];//基準值 while(i<j) { //右指針先遍歷,直到找到一個小於基準值的 while(i<j&&a[j]>=key) j--; //交換右指針與左指針的值 if(i<j&&a[j]<key) { int temp = a[i]; a[i] = a[j]; a[j] = temp; } //左指針遍歷,直到找到一個大於基準值的 while(i<j&&a[i]<=key)i++; //交換左右指針的值 if(i<j&&a[j]>key) { int temp = a[i]; a[i] = a[j]; a[j] = temp; } } //遞歸處理左右數組 quickSort(a,left,i-1); quickSort(a,i+1,right); }
第二種:web
//須要將基準值歸位的快速排序 public static void quickSort2(int []a,int left,int right) { if(left>=right) return ; int i = left ;//左指針 int j = right ;//右指針 int key = a[i];//基準值 while(i<j) { //右指針先遍歷,直到找到一個小於基準值的 while(i<j&&a[j]>=key) j--; //左指針遍歷,直到找到一個大於基準值的 while(i<j&&a[i]<=key)i++; //交換左右指針的值 if(i<j) { int temp = a[i]; a[i] = a[j]; a[j] = temp; } } a[left]=a[j]; a[j] = key; //遞歸處理左右數組 quickSort(a,left,i-1); quickSort(a,i+1,right); }
第三種:舍伍德算法
通常快速排序存在最好最壞狀況。
最好狀況:
當一組數無序,每次劃分紅兩個數組時,都能均勻的分紅兩部分。這樣最好狀況複雜度爲nlogn。()
最壞狀況:
當一組數有序,每次劃分都只能劃分掉一個數,最終複雜度爲n^2.
如1 2 3 4 5 第一次分爲 1 2345
第二次分爲 2 345
第三次分爲 3 45
第四次 4 5
這樣至關於要劃分n次,每次比較數也看作n,則爲n^2。
雖然快速排序平均複雜度能夠看作nlogn.但算法複雜度與輸入實例之間有關係,未必都是平均時間複雜度。
這就是要採用舍伍德快速排序的緣由,消除掉算法複雜度與輸入實例之間的關係。算法
//舍伍德快速排序算法(找到第K大的數) public static int quickSort3(int []a,int k) throws Exception { if(k>a.length||k<=0) throw new Exception("k值輸入不在異常"); int l= 0; int r = a.length-1; while(true) { if(l>=r) return a[l]; int i = l; //隨機獲取一個基準 Random rnd = new Random(); int j = 1+rnd.nextInt(r-1); //交換a[i]與基準的值,使得基準爲左邊第一個 swap(a,i,j); j = r+1; int pivot = a[l]; while(true) { //找到大於pivot的值後,跳出循環 while(i<a.length-1&&a[++i]<pivot) ; //找到小於pivot的值後,跳出循環 while(j>0&&a[--j]>pivot) ; if(i>=j) break; swap(a,i,j); } //第一次循環結束後,判斷此時的j,處在第幾大的位置 if(j-l+1 == k) return pivot; //基準歸位,由於此時j的值小於基準,而基準在第一個位置,下面 //兩條語句交換完後,保證左邊的數都小於基準,右邊的都大於 a[l] = a[j]; a[j] = pivot; //對子數組從新進行劃分 if(j-l+1<k) { k = k-j+l-1; l=j+1;//若是左邊的數小於K個,l=j+1從右邊數組繼續劃分 }else r=j-1; } }