1. 程式人生 > >排序演算法進階--排序演算法優化

排序演算法進階--排序演算法優化

排序演算法進階

        上篇文章中我們主要介紹了經典的八大排序演算法,從演算法思想,動圖演示,程式碼實現,複雜度及穩定性分析等角度進行學習。還沒閱讀的童鞋可以點這裡進行瀏覽。

        求知若渴的你肯定不會滿足於入門的內容,今天,小編在上一篇的基礎上,對多種排序演算法進行優化,讓我們一起來康康吧~~

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