Java實現幾種常見排序方法

日常操作中常見的排序方法有:冒泡排序、快速排序、選擇排序、插入排序、希爾排序,甚至還有基數排序、雞尾酒排序、桶排序、鴿巢排序、歸併排序等。

冒泡排序是一種簡單的排序算法。它重複地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個算法的名字由來是因爲越小的元素會經由交換慢慢“浮”到數列的頂端。

快速排序使用分治法策略來把一個序列分爲兩個子序列。

  1. /**  
  2.  * 快速排序<br/>  
  3.  * <ul>  
  4.  * <li>從數列中挑出一個元素,稱爲“基準”</li>  
  5.  * <li>重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。在這個分割之後,  
  6.  * 該基準是它的最後位置。這個稱爲分割(partition)操作。</li>  
  7.  * <li>遞歸地把小於基準值元素的子數列和大於基準值元素的子數列排序。</li>  
  8.  * </ul>  
  9.  *   
  10.  * @param numbers  
  11.  * @param start  
  12.  * @param end  
  13.  */   
  14. public   static   void  quickSort( int [] numbers,  int  start,  int  end) {  
  15.     if  (start < end) {  
  16.         int  base = numbers[start];  // 選定的基準值(第一個數值作爲基準值)   
  17.         int  temp;  // 記錄臨時中間值   
  18.         int  i = start, j = end;  
  19.         do  {  
  20.             while  ((numbers[i] < base) && (i < end))  
  21.                 i++;  
  22.             while  ((numbers[j] > base) && (j > start))  
  23.                 j--;  
  24.             if  (i <= j) {  
  25.                 temp = numbers[i];  
  26.                 numbers[i] = numbers[j];  
  27.                 numbers[j] = temp;  
  28.                 i++;  
  29.                 j--;  
  30.             }  
  31.         } while  (i <= j);  
  32.         if  (start < j)  
  33.             quickSort(numbers, start, j);  
  34.         if  (end > i)  
  35.             quickSort(numbers, i, end);  
  36.     }  
  37. }  

選擇排序是一種簡單直觀的排序方法,每次尋找序列中的最小值,然後放在最末尾的位置。

  1. /**  
  2.  * 選擇排序<br/>  
  3.  * <ul>  
  4.  * <li>在未排序序列中找到最小元素,存放到排序序列的起始位置</li>  
  5.  * <li>再從剩餘未排序元素中繼續尋找最小元素,然後放到排序序列末尾。</li>  
  6.  * <li>以此類推,直到所有元素均排序完畢。</li>  
  7.  * </ul>  
  8.  *   
  9.  * @param numbers  
  10.  */   
  11. public   static   void  selectSort( int [] numbers) {  
  12.     int  size = numbers.length, temp;  
  13.     for  ( int  i =  0 ; i < size; i++) {  
  14.         int  k = i;  
  15.         for  ( int  j = size -  1 ; j >i; j--)  {  
  16.             if  (numbers[j] < numbers[k])  k = j;  
  17.         }  
  18.         temp = numbers[i];  
  19.         numbers[i] = numbers[k];  
  20.         numbers[k] = temp;  
  21.     }  

 

插入排序的工作原理是通過構建有序序列,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入。其具體步驟參見代碼及註釋。

  1. /**  
  2.  * 插入排序<br/>  
  3.  * <ul>  
  4.  * <li>從第一個元素開始,該元素可以認爲已經被排序</li>  
  5.  * <li>取出下一個元素,在已經排序的元素序列中從後向前掃描</li>  
  6.  * <li>如果該元素(已排序)大於新元素,將該元素移到下一位置</li>  
  7.  * <li>重複步驟3,直到找到已排序的元素小於或者等於新元素的位置</li>  
  8.  * <li>將新元素插入到該位置中</li>  
  9.  * <li>重複步驟2</li>  
  10.  * </ul>  
  11.  *   
  12.  * @param numbers  
  13.  */   
  14. public   static   void  insertSort( int [] numbers) {  
  15.     int  size = numbers.length, temp, j;  
  16.     for ( int  i= 1 ; i<size; i++) {  
  17.         temp = numbers[i];  
  18.         for (j = i; j >  0  && temp < numbers[j- 1 ]; j--)  
  19.             numbers[j] = numbers[j-1 ];  
  20.         numbers[j] = temp;  
  21.     }  
  22. }  

歸併排序是建立在歸併操作上的一種有效的排序算法,歸併是指將兩個已經排序的序列合併成一個序列的操作。參考代碼如下:

  1. /**  
  2.  * 歸併排序<br/>  
  3.  * <ul>  
  4.  * <li>申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列</li>  
  5.  * <li>設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置</li>  
  6.  * <li>比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置</li>  
  7.  * <li>重複步驟3直到某一指針達到序列尾</li>  
  8.  * <li>將另一序列剩下的所有元素直接複製到合併序列尾</li>  
  9.  * </ul>  
  10.  * 算法參考:<a href="http://www.cnitblog.com/intrl/" mce_href="http://www.cnitblog.com/intrl/">Java部落</a>  
  11.  *   
  12.  * @param numbers  
  13.  */   
  14. public   static   void  mergeSort( int [] numbers,  int  left,  int  right) {  
  15.     int  t =  1 ; // 每組元素個數   
  16.     int  size = right - left +  1 ;  
  17.     while  (t < size) {  
  18.         int  s = t; // 本次循環每組元素個數   
  19.         t = 2  * s;  
  20.         int  i = left;  
  21.         while  (i + (t -  1 ) < size) {  
  22.             merge(numbers, i, i + (s - 1 ), i + (t -  1 ));  
  23.             i += t;  
  24.         }  
  25.         if  (i + (s -  1 ) < right)  
  26.             merge(numbers, i, i + (s - 1 ), right);  
  27.     }  
  28. }  
  29. /**  
  30.  * 歸併算法實現  
  31.  *   
  32.  * @param data  
  33.  * @param p  
  34.  * @param q  
  35.  * @param r  
  36.  */   
  37. private   static   void  merge( int [] data,  int  p,  int  q,  int  r) {  
  38.     int [] B =  new   int [data.length];  
  39.     int  s = p;  
  40.     int  t = q +  1 ;  
  41.     int  k = p;  
  42.     while  (s <= q && t <= r) {  
  43.         if  (data[s] <= data[t]) {  
  44.             B[k] = data[s];  
  45.             s++;  
  46.         } else  {  
  47.             B[k] = data[t];  
  48.             t++;  
  49.         }  
  50.         k++;  
  51.     }  
  52.     if  (s == q +  1 )  
  53.         B[k++] = data[t++];  
  54.     else   
  55.         B[k++] = data[s++];  
  56.     for  ( int  i = p; i <= r; i++)  
  57.         data[i] = B[i];  
  58. }  

將之前介紹的所有排序算法整理成NumberSort類,代碼

  1. /**  
  2.  * BubbleSort.class  
  3.  */   
  4. package  test.sort;  
  5. import  java.util.Random;  
  6. /**  
  7.  * Java實現的排序類  
  8.  *   
  9.  * @author cyq  
  10.  *   
  11.  */   
  12. public   class  NumberSort {  
  13.     /**  
  14.      * 私有構造方法,禁止實例化  
  15.      */   
  16.     private  NumberSort() {  
  17.         super ();  
  18.     }  
  19.     /**  
  20.      * 冒泡法排序<br/>  
  21.      * <ul>  
  22.      * <li>比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。</li>  
  23.      * <li>對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。在這一點,最後的元素應該會是最大的數。</li>  
  24.      * <li>針對所有的元素重複以上的步驟,除了最後一個。</li>  
  25.      * <li>持續每次對越來越少的元素重複上面的步驟,直到沒有任何一對數字需要比較。</li>  
  26.      * </ul>  
  27.      *   
  28.      * @param numbers  
  29.      *            需要排序的整型數組  
  30.      */   
  31.     public   static   void  bubbleSort( int [] numbers) {  
  32.         int  temp;  // 記錄臨時中間值   
  33.         int  size = numbers.length;  // 數組大小   
  34.         for  ( int  i =  0 ; i < size -  1 ; i++) {  
  35.             for  ( int  j = i +  1 ; j < size; j++) {  
  36.                 if  (numbers[i] < numbers[j]) {  // 交換兩數的位置   
  37.                     temp = numbers[i];  
  38.                     numbers[i] = numbers[j];  
  39.                     numbers[j] = temp;  
  40.                 }  
  41.             }  
  42.         }  
  43.     }  
  44.     /**  
  45.      * 快速排序<br/>  
  46.      * <ul>  
  47.      * <li>從數列中挑出一個元素,稱爲“基準”</li>  
  48.      * <li>重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。在這個分割之後,  
  49.      * 該基準是它的最後位置。這個稱爲分割(partition)操作。</li>  
  50.      * <li>遞歸地把小於基準值元素的子數列和大於基準值元素的子數列排序。</li>  
  51.      * </ul>  
  52.      *   
  53.      * @param numbers  
  54.      * @param start  
  55.      * @param end  
  56.      */   
  57.     public   static   void  quickSort( int [] numbers,  int  start,  int  end) {  
  58.         if  (start < end) {  
  59.             int  base = numbers[start];  // 選定的基準值(第一個數值作爲基準值)   
  60.             int  temp;  // 記錄臨時中間值   
  61.             int  i = start, j = end;  
  62.             do  {  
  63.                 while  ((numbers[i] < base) && (i < end))  
  64.                     i++;  
  65.                 while  ((numbers[j] > base) && (j > start))  
  66.                     j--;  
  67.                 if  (i <= j) {  
  68.                     temp = numbers[i];  
  69.                     numbers[i] = numbers[j];  
  70.                     numbers[j] = temp;  
  71.                     i++;  
  72.                     j--;  
  73.                 }  
  74.             } while  (i <= j);  
  75.             if  (start < j)  
  76.                 quickSort(numbers, start, j);  
  77.             if  (end > i)  
  78.                 quickSort(numbers, i, end);  
  79.         }  
  80.     }  
  81.     /**  
  82.      * 選擇排序<br/>  
  83.      * <ul>  
  84.      * <li>在未排序序列中找到最小元素,存放到排序序列的起始位置</li>  
  85.      * <li>再從剩餘未排序元素中繼續尋找最小元素,然後放到排序序列末尾。</li>  
  86.      * <li>以此類推,直到所有元素均排序完畢。</li>  
  87.      * </ul>  
  88.      *   
  89.      * @param numbers  
  90.      */   
  91.     public   static   void  selectSort( int [] numbers) {  
  92.         int  size = numbers.length, temp;  
  93.         for  ( int  i =  0 ; i < size; i++) {  
  94.             int  k = i;  
  95.             for  ( int  j = size -  1 ; j > i; j--) {  
  96.                 if  (numbers[j] < numbers[k])  
  97.                     k = j;  
  98.             }  
  99.             temp = numbers[i];  
  100.             numbers[i] = numbers[k];  
  101.             numbers[k] = temp;  
  102.         }  
  103.     }  
  104.     /**  
  105.      * 插入排序<br/>  
  106.      * <ul>  
  107.      * <li>從第一個元素開始,該元素可以認爲已經被排序</li>  
  108.      * <li>取出下一個元素,在已經排序的元素序列中從後向前掃描</li>  
  109.      * <li>如果該元素(已排序)大於新元素,將該元素移到下一位置</li>  
  110.      * <li>重複步驟3,直到找到已排序的元素小於或者等於新元素的位置</li>  
  111.      * <li>將新元素插入到該位置中</li>  
  112.      * <li>重複步驟2</li>  
  113.      * </ul>  
  114.      *   
  115.      * @param numbers  
  116.      */   
  117.     public   static   void  insertSort( int [] numbers) {  
  118.         int  size = numbers.length, temp, j;  
  119.         for  ( int  i =  1 ; i < size; i++) {  
  120.             temp = numbers[i];  
  121.             for  (j = i; j >  0  && temp < numbers[j -  1 ]; j--)  
  122.                 numbers[j] = numbers[j - 1 ];  
  123.             numbers[j] = temp;  
  124.         }  
  125.     }  
  126.     /**  
  127.      * 歸併排序<br/>  
  128.      * <ul>  
  129.      * <li>申請空間,使其大小爲兩個已經排序序列之和,該空間用來存放合併後的序列</li>  
  130.      * <li>設定兩個指針,最初位置分別爲兩個已經排序序列的起始位置</li>  
  131.      * <li>比較兩個指針所指向的元素,選擇相對小的元素放入到合併空間,並移動指針到下一位置</li>  
  132.      * <li>重複步驟3直到某一指針達到序列尾</li>  
  133.      * <li>將另一序列剩下的所有元素直接複製到合併序列尾</li>  
  134.      * </ul>  
  135.      * 算法參考:<a href="http://www.cnitblog.com/intrl/" mce_href="http://www.cnitblog.com/intrl/">Java部落</a>  
  136.      *   
  137.      * @param numbers  
  138.      */   
  139.     public   static   void  mergeSort( int [] numbers,  int  left,  int  right) {  
  140.         int  t =  1 ; // 每組元素個數   
  141.         int  size = right - left +  1 ;  
  142.         while  (t < size) {  
  143.             int  s = t; // 本次循環每組元素個數   
  144.             t = 2  * s;  
  145.             int  i = left;  
  146.             while  (i + (t -  1 ) < size) {  
  147.                 merge(numbers, i, i + (s - 1 ), i + (t -  1 ));  
  148.                 i += t;  
  149.             }  
  150.             if  (i + (s -  1 ) < right)  
  151.                 merge(numbers, i, i + (s - 1 ), right);  
  152.         }  
  153.     }  
  154.     /**  
  155.      * 歸併算法實現  
  156.      *   
  157.      * @param data  
  158.      * @param p  
  159.      * @param q  
  160.      * @param r  
  161.      */   
  162.     private   static   void  merge( int [] data,  int  p,  int  q,  int  r) {  
  163.         int [] B =  new   int [data.length];  
  164.         int  s = p;  
  165.         int  t = q +  1 ;  
  166.         int  k = p;  
  167.         while  (s <= q && t <= r) {  
  168.             if  (data[s] <= data[t]) {  
  169.                 B[k] = data[s];  
  170.                 s++;  
  171.             } else  {  
  172.                 B[k] = data[t];  
  173.                 t++;  
  174.             }  
  175.             k++;  
  176.         }  
  177.         if  (s == q +  1 )  
  178.             B[k++] = data[t++];  
  179.         else   
  180.             B[k++] = data[s++];  
  181.         for  ( int  i = p; i <= r; i++)  
  182.             data[i] = B[i];  
  183.     }  
  184.   
  185. }  

數字排序算法通常用來作爲算法入門課程的基本內容,在實際應用(尤其是普通商業軟件)中使用的頻率較低,但是通過排序算法的實現,可以深入瞭解計算機語言的特點,可以以此作爲學習各種編程語言的基礎。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章