選擇排序、樹形排序、堆排序的java程式碼實現
阿新 • • 發佈:2019-02-03
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