排序演算法進階--排序演算法優化
排序演算法進階
上篇文章中我們主要介紹了經典的八大排序演算法,從演算法思想,動圖演示,程式碼實現,複雜度及穩定性分析等角度進行學習。還沒閱讀的童鞋可以點這裡進行瀏覽。
求知若渴的你肯定不會滿足於入門的內容,今天,小編在上一篇的基礎上,對多種排序演算法進行優化,讓我們一起來康康吧~~
01氣泡排序
1. 優化一
-
優化思路:優化外層迴圈,我們知道,氣泡排序的每一輪都會對未排序部分進行一次遍歷,如果在某次迴圈中沒有交換操作,就說明陣列已經有序,不用繼續排序。
-
實現程式碼
1 public static int[] bubbleSort(int[] array) { 2 if (array.length == 0) 3 return array; 4 for (int i = 0; i < array.length; i++){ 5 boolean isSwap = false;//標記是否已經有序 6 for (int j = 0; j < array.length - 1 - i; j++) 7 if (array[j + 1] < array[j]) { 8 int temp = array[j + 1]; 9 array[j + 1] = array[j]; 10 array[j] = temp; 11 isSwap = true; 12 } 13 if(!isSwap) 14 break; 15 } 16 return array; 17 }
2. 優化二
-
優化思路:優化內層迴圈,記住上一次發生交換的位置pos,則有序區擴充套件為[pos, len-1],下一趟排序只需遍歷[0, pos-1]即可。
-
實現程式碼
1 public static int[] bubbleSort(int[] array) { 2 if (array.length == 0) 3 return array; 4 int pos = 0;//標記最後一次交換的位置 5 int k = array.length-1; 6 for (int i = 0; i < array.length; i++){ 7 boolean isSwap = false; 8 for (int j = 0; j < k; j++) 9 if (array[j + 1] < array[j]) { 10 int temp = array[j + 1]; 11 array[j + 1] = array[j]; 12 array[j] = temp; 13 isSwap = true; 14 pos = j; 15 } 16 k=pos; 17 if(!isSwap) 18 break; 19 } 20 return array; 21 } 1570932802569
3. 優化三
-
優化思路:雙向氣泡排序(雞尾酒排序),先從前往後,再從後往前去比較序列中的元素大小,每一次排序分別能確定未排序序列的最大最小值並放在相應位置。
-
實現程式碼
1 public void cocktail_sort(int[] a){ 2 int left = 0, right = a.length-1; 3 int temp; 4 while(left<right){ 5 //找到當前排序元素裡最大的那個,放在右側 6 for(int i=left;i<right;i++){ 7 if(a[i]>a[i+1]){ 8 temp = a[i]; 9 a[i] = a[i+1] ; 10 a[i+1] = temp; 11 } 12 } 13 right--; 14 //找到當前排序元素裡最小的那個,放在左側 15 for(int j=right;j>left;j--){ 16 if(a[j-1]>a[j]){ 17 temp = a[j]; 18 a[i] = a[j+1] ; 19 a[j+1] = temp;} 20 } 21 left++; 22 } 23 }
當然,你也可以結合上述的優化演算法實現:優化外層迴圈+優化內層迴圈+雙向氣泡排序。
02選擇排序
1. 優化一
-
優化思路:折半插入排序,由於我們是要在有序的序列中找到一個位置插入元素,所以可以用二分查詢的方法來代替順序查詢,不過這種方法雖然減少了插入過程的比較次數,時間複雜度仍為O(n^2)。
-
實現程式碼
1 public static int[] selectSort(int[] array) { 2 if (array.length == 0) 3 return array; 4 int left = 0; 5 int right = array.length-1; 6 int min = left;//最小值下標 7 int max = right;//最大值下標 8 while(left<=right){ 9 min = left; 10 max = right; 11 for(int i=left; i<=right; i++){ 12 if(array[i]<array[min]){ 13 min = i; 14 } 15 if(array[i]>array[max]) 16 max = i; 17 } 18 swap(array[left],array[min]); 19 if(left==max) 20 max = min; 21 swap(array[right],array[max]); 22 ++left; 23 --right; 24 } 25 return array; 26 }
03插入排序
1. 優化一
-
優化思路:每一次查詢最大值的時候,也可以同時查詢最小值,然後分別放在相應的位置。
-
實現程式碼
1 public static int[] BinsertSort(int[] a){ 2 int left, right, m, num; 3 for(int i=1;i<a.length;i++){ 4 num = a[i]; 5 left = 0; 6 right = i-1; 7 //二分查詢 8 while(left<=right){ 9 m = (left+right)/2; 10 if(num<a[m]) 11 right = m-1; 12 else 13 left = m+1; 14 } 15 for(int j=i-1;j>=right+1;--j) 16 a[j+1]=a[j]; 17 a[right+1]=num; 18 } 19 return a; 20 }
04快速排序
1. 優化一
-
優化思路:優化基準值選取:採用固定基準的方法來對陣列進行劃分時,如果陣列元素基本有序,容易產生最壞時間複雜度O(n^2);所以可以採用隨機基準值確定;但是如果陣列值是隨機的,採用固定基準可能比隨機的要快;故可考慮三數取中:選取待排序陣列的開頭中間和結尾,通過比較,選取中間值作為基準;
-
實現程式碼
1 public static void swap(int[] arr,int left,int right) 2 { 3 int temp; 4 temp=arr[left]; 5 arr[left]=arr[right]; 6 arr[right]=temp; 7 } 8 public static int partition(int[] arr,int left,int right) 9 { 10 int m=left+(right-left)/2;//找到中間的數字的下標 11 if(arr[left]>arr[right])//最左大於最右的時候,交換左右 12 { 13 swap(arr,left,right); 14 } 15 if(arr[m]>arr[right])//如果中間的>right ,交換 16 { 17 swap(arr,m,right); 18 } 19 if(arr[m]>arr[left])//如果中間的>left,交換 20 { 21 swap(arr,m,right); 22 } 23 int temp=arr[left];//基準 24 while(left<right)//知道left和right重合的時候,才找到合適的位置 25 { //從後向前找到比小的數字 26 while(left<right && arr[right]>=temp) 27 { 28 right--; 29 } 30 arr[left]=arr[right];//當right的值小於temp的值的時候執行 31 while(left<right && arr[left] <= temp)//從前往後找到比基準大的數字 32 { 33 left++; 34 } 35 arr[right]=arr[left];//當left的值大於temp的時候執行 36 } 37 arr[left]=temp;//此時的left和right在同一個位置,此時為合適的位置,把temp的值給left 38 return left;//此時返回的值是temp合適的位置,即小於它的在它的左邊,大於它的在它的右邊 39 } 40 public static int[] Quicksort(int array[], int left, int right) { 41 if(left < right){ 42 int pos = partition(array, left, right); 43 Quicksort(array, left, pos - 1); 44 Quicksort(array, pos + 1, right); 45 } 46 return array; 47 }
2. 優化二
-
優化思路:序列長度達到一定大小時,使用插入排序:當快排達到一定深度後,劃分的區間很小,使用快排效率不高,可以使用插入排序;
-
實現程式碼
1 public static void quickSort(int[] arr,int left,int right) 2 { 3 int length=right-left; 4 if(length>max_len ) 5 { 6 int pivot=partition(arr,left,right); 7 quickSort(arr,left,pivot-1); 8 quickSort(arr,pivot+1,right); 9 } 10 else 11 { 12 BinsertSort(arr); 13 } 14 }
3. 優化三
-
優化思路:尾遞迴優化,快排的遞迴出現在函式的尾部,且它的返回值不作為表示式的一部分,即遞歸回溯後不需要做任何操作,編譯器檢測到尾遞迴時,他就覆蓋當前的活動記錄而不是在棧中去建立一個新的,節省了大量棧空間;
4. 優化四
-
優化思路:聚集元素,在一次分割結束後,將與本次基準相等的元素聚集在一起,再分割時,不再對聚集過的元素進行分割(可以在劃分過程中,將與本次基準相等元素放入陣列兩端,劃分結束後再將這些元素一道基準值周圍);
-
程式碼實現
1 //找基準 2 public static int partion(int[] array,int low,int high){//一次快排 3 int tmp=array[low]; 4 while(low < high){ 5 //從後找 6 while(low < high && array[high] >= tmp){ 7 --high; 8 } 9 if(low >= high){ 10 break; 11 }else{ 12 array[low] = array[high]; 13 } 14 //從前找 15 while(low < high && array[low] <= tmp){ 16 ++low; 17 } 18 if(low >= high){ 19 break; 20 }else{ 21 array[high] =array[low]; 22 } 23 } 24 array[low] = tmp; 25 return low; 26 } 27 //將相同元素聚集在一起 28 public static int[] focusNum(int[] array,int start,int end,int par){ 29 int tmp = 0; 30 //查詢範圍 31 int left=par-1; 32 int right=par+1; 33 //交換的指引變數 34 int parLeft=par-1; 35 int parRight=par+1; 36 //左邊找 37 for(int i = left;i >= start;i--){ 38 if(array[i] == array[par]){//遍歷過程中,有與par相同的元素時 39 if(i != parLeft){//若i 和parLeft相同,將兩下標所對應的元素交換 40 tmp = array[i]; 41 array[i] = array[parLeft]; 42 array[parLeft] = tmp; 43 parLeft--; 44 }else{ 45 parLeft--; 46 } 47 } 48 } 49 //右邊找 50 for(int j = right;j <= end;j++){//遍歷過程中,有與par相同的元素時 51 if(array[j] == array[par]){//若i 和parRight相同,將兩下標所對應的元素交換 52 if(j != parRight){ 53 tmp = array[j]; 54 array[j] = array[parRight]; 55 array[parRight] = tmp; 56 parRight++; 57 }else{ 58 parRight++; 59 } 60 } 61 } 62 int[] focus={parLeft,parRight}; 63 return focus; 64 } 65 //基準左右進行遞迴排序 66 public static void Quick(int[] array,int start,int end){ 67 int par = partion(array,start,end); 68 int[] brray = focusNum(array,start,end,par);//相同元素聚集在一起後,新的left和right 69 int left = brray[0]; 70 int right = brray[1]; 71 if(par > start+1){ 72 Quick(array,start,left); 73 } 74 if(par < end-1){ 75 Quick(array,right,end); 76 } 77 }
5. 優化五
-
優化思路:採用多執行緒,因為子問題是獨立的。
歡迎補充,指錯,提建議,感謝閱讀,感謝支援!
關注我 獲取更多知識長按掃碼關注你點的每個贊,我都認真當成了喜歡
&n