目錄
1 問題描述
(1)實驗題目
用基於變治法的堆排序算法對任意一組給定的數據進行排序
(2)實驗目的
1)深刻理解並掌握變治法的設計思想;
2)掌握堆的概念以及如何用變治法把任意給定的一組數據改變成堆;
3)提高應用變治法設計算法的技能。
(3)實驗要求
1)設計與實現堆排序算法;
2)待排序的數據可以手工輸入(通常規模比較小,10個數據左右),用以檢測程序的正確性;也可以計算機隨機生成(通常規模比較大,1500-3000個數據左右),用以檢驗(用計數法)堆排序算法的時間效率。
2 解決方案
2.1 堆排序原理簡介
堆可以定義為一顆二叉樹,樹的節點中包含鍵(每個節點是一個鍵),並且滿足下面兩個條件:
(1)樹的形狀要求——這顆二叉樹是基本完備的(或者簡稱為完成二叉樹),這意味着,樹的每一層都是滿的,除了最后一層最右邊的元素有可能缺位。
(2)父母優勢要求,又稱為堆特性——每一個節點的鍵都要大於或等於它子女的鍵(對於任何孩子節點也要自動滿足父母優勢要求)。
2.2 變治法原理簡介
變治法:首先,在“變”的階段,出於這一或者那樣的原因,把問題的實例變得更容易求解(PS:類似本文求解問題,在排序前先把數組中數進行成堆處理);然后,在第二階段或者說“治”的階段,對實例進行求解。
根據我們對問題實例的變換方式,變治思想有3種主要的類型:
(1)變換為同樣問題的一個更簡單或者更方便的實例——我們稱之為實例化簡;
(2)變換為同樣實例的不同表現——我們稱之為改變表現;
(3)變換為另一個問題的實例,這種問題的算法是已知的——我們稱之為問題的化簡。
2.3 具體編碼
package com.liuzhen.heapsort; public class HeapSort { /*將array[a]和array[b]、array[c]中最大值進行比較,如果較小則將array[a]與array[b]、array[c]中最大值 進行交換,否則直接返回數組array*/ public static int[] getMaxA(int[] array,int a,int b ,int c){ int temp = 0; if(array[b] >= array[c]){ if(array[a] < array[b]){ temp = array[a]; array[a] = array[b]; array[b] = temp; } } else{ if(array[a] < array[c]){ temp = array[a]; array[a] = array[c]; array[c] = temp; } } return array; } //根據堆排序父母優勢規則,返回一個給定長度的數組的成堆結果 public static int[] getHeapSort(int[] array , int len){ boolean judge = true; while(judge){ //根據堆排序父母優先規則,對數組array進行排序 for(int i = 1;i <= len/2;i++){ if((2*i+1) < len) array = getMaxA(array,i,(2*i),(2*i+1)); if((2*i) == len-1){ //當2*i == len-1時,說明array[i]只有一個左孩子節點a[2*i] int temp = 0; if(array[i] < array[2*i]){ temp = array[i]; array[i] = array[2*i]; array[2*i] = temp; } } } //遍歷數組array,一旦出現根節點小於其葉子節點時,跳出for循環 int j; for(j = 1;j < len/2;j++){ if((2*j+1) < len){ if(array[j] < array[2*j]) break; if(array[j] < array[2*j+1]) break; } if((2*j) == len-1){ if(array[j] < array[2*j]) break; } } if(j == len/2) //如果j==len/2,說明遍歷結果符合堆排序規則,直接結束while循環 judge = false; } return array; } //使用數組成堆,對一個數組元素進行從小到大排序,並返回排序后的結果 public static int[] getResultSort(int[] array , int len){ array = getHeapSort(array , len); //首先對數組進行堆排序處理 int temp = 0; //數組值交換中間變量 int sortLen = len; //排序過程中,需要重新進行堆排序的數組長度,並初始化為array的總長度 while(sortLen > 2){ // for(int i = 1;i < len;i++) // System.out.print(array[i]+"\t"); // System.out.println(); temp = array[1]; //交換array[0]和array[sortLen-1]的值,即把最大的值放在未排序的數組最后一位 array[1] = array[sortLen-1]; array[sortLen-1] = temp; sortLen = sortLen - 1; //交換成功后,未排序的數組長度自動減1 array = getHeapSort(array,sortLen); //對未排序的數組,重新進行堆排序 } return array; } //初始化一個長度為n的隨機數組 public static int[] initArray(int n){ int[] result = new int[n]; result[0] = 0; for(int i = 1;i < n;i++) result[i] = (int)(Math.random()*1000); //采用隨機函數隨機生成0~1000之間的數 return result; } public static void main(String args[]){ int[] array = {0,1,4,5,3,5,23,45,12,23,34,56,78,23,24,25}; //此處定義數組,對array[1]到array[len-1]進行排序 int len = array.length; int[] result = getResultSort(array,len); System.out.println("手動輸入數組,使用堆排序,最終排序結果:"); for(int i = 1;i < len;i++){ System.out.print(result[i]+"\t"); } System.out.println(); System.out.println(); int[] oneArray = initArray(1000); int len1 = 1000; int[] result1 = getResultSort(oneArray,len1); System.out.println("系統隨機生成的長度為1000的數組(其值均在0~1000之間),使用堆排序,最終排序結果:"); for(int j = 1;j < len1;j++){ System.out.print(result1[j]+"\t"); if(j%15 == 0) System.out.println(); } } }
2.4 運行結果截圖