1. 程式人生 > >選擇排序、樹形排序、堆排序的java程式碼實現

選擇排序、樹形排序、堆排序的java程式碼實現

package com.sort;  
  
/** 
 * 選擇排序: 
 * 簡單選擇排序,樹形選擇排序與堆排序 
 *  
 */  
public class SelecSortDemo {  
      
    /** 
     * -------------------------------------------- 
     * 簡單選擇排序 
     * 原理:假設列表中有n個元素,從第一個元素開始,在第一個元素 
     * 與最後一個元素之間選擇一個最小的元素與第一個元素交換, 
     * 然後從第二個元素開始,在第二個元素與最後一個元素之間選擇 
     * 最小的元素與第二個元素交換,以此類推,最後列表有序。 
     */  
    public static void simpleSelectSort(Object[] a){  
        int len = a.length;  
        for(int i = 0,j;i<len;i++){  
            j = selectMin(a, i);  
            if(i!=j)    //等於就沒有必要交換了  
                a[i] = a[j];  
        }  
    }  
    /** 
     * 簡單選擇排序的輔助方法 
     * 從指定位置i開始到最後位置選擇出一個最小的元素 
     * 並且返回它的索引值 
     */  
    private static int selectMin(Object[] a,int low){  
        int min = low;  //假設第一個元素為最小值  
        for(int i = low+1;i<a.length;i++){  
            if(((Comparable)a[i]).compareTo(a[min])<0){  
                min = i;  
            }  
        }  
        return min;  
    }  
      
      
      
     /**  
     * ---------------------------------------  
     * 樹形選擇排序 : 
     * 對於簡單排序來說,主要是進行n-1趟元素的比較,每趟比較n-2次, 
     * 每趟比較取出一個最小值(也可以是最大值),逐步使列表有序。 
     * 但是第一趟的比較是可以為後續的比較提供資訊的,使後續的比較次數大大減少, 
     * 而後續的比較又可以為更後續的比較提供資訊,這樣就減少了比較的次數,減少了 
     * 時間複雜度。 
     *  
     * 實現原理: 
     * 第一步,首先對n個記錄進行兩兩比較,得到較小的n/2個數再依次比較,依次類推 
     * 直到得到一個最小值,這是一個構造完全二叉樹的過程,根節點即為最小元素,葉子節點為列表元素。 
     * 構造的此樹的儲存結構可以用陣列表示方法,陣列長度為2n-1。填充此樹,比如 
     * 列表元素為:49    38     65    97   76    13    27   49 
     * 構造的樹為:                     13 
     *                     38               13 
     *                38       65       13       27 
     *              19  38   65  97   76  13   27  49 
     * 13為根結點位最小值,列表元素為葉子節點 
     *  
     * 第二步,移走最小元素,此時可重新為陣列a的第一個位置賦值為此最小值, 
     * 之後如果找出次小值則可以為第二個位置賦值,...... 
     *  
     * 第三步,找出次小值,找出最小值在葉子節點的位置,從該節點開始,和其兄弟節點 
     * 進行比較,修改從葉子節點到根節點的元素值,比較完畢後,根節點為次小值。 
     * 第三步比較是利用了第一次比較提供的資訊,因為第一步已經得到了兩兩比較的 
     * 較小值,只要拿第一次與最小值比較的元素(即最小值的兄弟節點)與它們比較即可得最小值。 
     * 即拿上述例子的76與27比較,然後27與38比較得到次小值27。 
     * 重複第二和第三步,排序完成。 
     *  
     * PS:這裡把移出去的葉子節點都要重設為最大值,可對此方法進行稍微改動 
     * 可傳一個最大值進來,這裡是整型所以用了Integer.MAX_VALUE 
     */    
    public static void treeSelectSort(Object[] a){    
       int len = a.length;  
       int treeSize = 2 * len - 1;  //完全二叉樹的節點數  
       int low = 0;  
       Object[] tree = new Object[treeSize];    //臨時的樹儲存空間  
       //由後向前填充此樹,索引從0開始  
       for(int i = len-1,j=0 ;i >= 0; --i,j++){      //填充葉子節點  
           tree[treeSize-1-j] = a[i];  
       }  
         
       for(int i = treeSize-1;i>0;i-=2){ //填充非終端節點  
           tree[(i-1)/2] = ((Comparable)tree[i-1]).compareTo(tree[i]) < 0 ? tree[i-1]:tree[i];  
       }  
         
       //不斷移走最小節點  
       int minIndex;  
       while(low < len){  
           Object min = tree[0];    //最小值  
           a[low++] = min;  
           minIndex = treeSize-1;         
           //找到最小值的索引  
           while(((Comparable)tree[minIndex]).compareTo(min)!=0){  
               minIndex--;  
           }  
           tree[minIndex] = Integer.MAX_VALUE;  //設定一個最大值標誌  
           //找到其兄弟節點  
           while(minIndex > 0){      //如果其還有父節點  
               if(minIndex % 2 == 0){   //如果是右節點  
                   tree[(minIndex-1)/2] = ((Comparable)tree[minIndex-1]).compareTo(tree[minIndex])  
                        < 0 ? tree[minIndex-1]:tree[minIndex];  
                   minIndex = (minIndex-1)/2;  
               }else{                   //如果是左節點  
                    tree[minIndex/2] = ((Comparable)tree[minIndex]).compareTo(tree[minIndex+1])  
                        < 0 ? tree[minIndex]:tree[minIndex+1];  
                    minIndex = minIndex/2;  
               }  
           }  
             
       }  
    }  
  
  
      
        /** 
     * ---------------------------------- 
     * 堆排序 
     *    堆排序是在樹形選擇排序的基礎上進一步進行優化 
     * 只需要一個額外的儲存空間,且不需根據標誌判斷是不是最大值。 
     * 堆的定義:在1到n/2的元素中,有k(i)<=k(2i),k(i)<=k(2i+1) 
     * 或k(i)>=k(2i),k(i)>=k(2i+1) 
     * 簡單來說:就是假如將此序列看成一棵完全二叉樹,要使這個無序列表 
     * 變成堆,則小於等於n/2(最後一個非終端節點就是n/2)的某個節點i的左右子節點均大於此節點, 
     * 即堆的定義k(i)<=k(2i),k(i)<=k(2i+1)。 
     *  
     * 實現原理: 
     *    首先將序列看成一個樹形結構, 
     * 1.構建堆的過程:找到最後一個非終端節點n/2,與它的左右子節點比較, 
     * 比較結果使此父節點為這三個節點的最小值。再找n/2-1這個節點, 
     * 與其左右子節點比較,得到最小值,以此類推....,最後根節點即為最小值 
     * 比如:49  38   65   97   76   13   27   49 
     * 初始樹為: 
     *              49 
     *        38              65 
     *    97      76      13       27 
     * 49 
     * 構造堆後的樹為 
     *              13 
     *       38              27 
     *    49    76       65       49 
     *  97 
     *  交換資料的順序為:97<——>49, 13<--->65,38不用換,49<-->13,13<-->27 
     * 2.輸出堆頂元素並調整建新堆的過程 
     *    輸出堆頂最小值後,假設以最後一個值替代之,由於其左右子樹的堆結構並沒有被破壞 
     * 只需要自上而下進行調整。比如把上圖的13輸出後以97替代,然後可以把97與27交換, 
     * 然後97又與49交換,此時最小值為根元素27,輸出27後以又用最後一個值替換根元素, 
     * 以此類推,則最終得到有序序列  
     */  
    public static void heapSort(Object[] a){    
        int len = a.length;    
        //構建堆    
        for(int i=(len-1)/2;i>=0;i--){    
            heapAdjust(a,i,len);    
        }    
            
        //輸出堆頂元素並調整建新堆的過程    
        int count = len-1;    
        while(count > 0 ){    
            //交換樹根與最後一個值    
            swap(a,0,count);    
            count -- ;    
            heapAdjust(a,0,count);    
        }    
    }    
        
    /**  
     * 調整某一個節點極其左右子節點的位置 ,並選擇左右節點中的較大者 
     * 繼續向下調整 
     */    
    private static void heapAdjust(Object[] a,int i,int len){    
        Object parent = a[i];  
        for(int j = (i+1) * 2 - 1;j < len; j = (j+1) * 2 - 1){   //沿著左右節點中的較小者繼續往下搜尋  
            if(j < len-1 && ((Comparable)a[j]).compareTo(a[j+1]) < 0 ){  
                ++j;        //如果左節點較大過度到右節點  
            }  
            if(((Comparable)parent).compareTo(a[j]) > 0) //左右節點均小於父節點則不必要繼續向下搜尋  
                break;    
            a[i] = a[j];  
            i = j ;  
        }  
        a[i] = parent;      //parent插入到正確的位置  
          
    }  
      
    /** 
     * 交換陣列中兩元素的值 
     */  
    private static void swap(Object[] a,int i,int j){  
        Object temp = null;  
        temp = a[i];  
        a[i] = a[j];  
        a[j] = temp;  
    }  
      
    //just for test  
    public static void main(String[] args) {  
        Integer[] data = {49,38,65,97,76,13,27,49};  
        SelecSortDemo.treeSelectSort(data);  
        for(Integer d:data){  
            System.out.println(d);  
        }  
    }  
}  

轉載自:http://zhouyunan2010.iteye.com/blog/1217462