來源百度百科:html
堆排序(Heapsort)是指利用堆積樹(堆)這種數據結構所設計的一種排序算法,它是選擇排序的一種。能夠利用數組的特色快速定位指定索引的元素。堆分爲大根堆和小根堆,是 徹底二叉樹。
前面我已經有二叉樹入門的文章了,當時講解的是二叉查找樹,那上面所說的徹底二叉樹是怎麼樣的一種二叉樹呢??還有滿二叉樹又是怎麼的一種二叉樹呢??甚至還有完滿二叉樹??java
下面用圖來講話:算法
參考資料:api
簡單來講:堆排序是將數據當作是徹底二叉樹、根據徹底二叉樹的特性來進行排序的一種算法數組
這裏咱們討論最大堆:當前每一個父節點都大於子節點微信
徹底二叉樹有個特性:左邊子節點位置 = 當前父節點的兩倍 + 1
,右邊子節點位置 = 當前父節點的兩倍 + 2
數據結構
如今咱們有一個徹底二叉樹:左子樹和右子樹都符合最大堆-->父>子
spa
可是咱們會發現:根元素所在的數並不符合,明顯的是:1是小於7的設計
咱們就對其進行交換,交換完以後咱們會發現:右子樹又不符合了~3d
由於,右子樹變成了這樣:
最後,咱們將右子數的最大值也交換到右子樹的根元素上
因而咱們第一次的建堆操做就完成了!
能夠發現的是:一次堆創建完以後,咱們的最大值就在了堆的根節點上
隨後將堆頂最大值和數組最後的元素進行替換,咱們就完成了一趟排序了。
接下來,剩下的數不斷進行建堆,交換就能夠完成咱們的堆排序了
.........建堆,交換....建堆,交換...建堆,交換...建堆,交換..
比較當前父節點是否大於子節點,若是大於就交換,直到一趟建堆完成~
/** * 建堆 * * @param arrays 看做是徹底二叉樹 * @param currentRootNode 當前父節點位置 * @param size 節點總數 */ public static void heapify(int[] arrays, int currentRootNode, int size) { if (currentRootNode < size) { //左子樹和右字數的位置 int left = 2 * currentRootNode + 1; int right = 2 * currentRootNode + 2; //把當前父節點位置當作是最大的 int max = currentRootNode; if (left < size) { //若是比當前根元素要大,記錄它的位置 if (arrays[max] < arrays[left]) { max = left; } } if (right < size) { //若是比當前根元素要大,記錄它的位置 if (arrays[max] < arrays[right]) { max = right; } } //若是最大的不是根元素位置,那麼就交換 if (max != currentRootNode) { int temp = arrays[max]; arrays[max] = arrays[currentRootNode]; arrays[currentRootNode] = temp; //繼續比較,直到完成一次建堆 heapify(arrays, max, size); } } }
值得注意的是:在上面體驗堆排序時,咱們是左子樹和右子數都是已經有父>子
這麼一個條件的了。
/** * 完成一次建堆,最大值在堆的頂部(根節點) */ public static void maxHeapify(int[] arrays, int size) { // 從數組的尾部開始,直到第一個元素(角標爲0) for (int i = size - 1; i >= 0; i--) { heapify(arrays, i, size); } }
完成第一次建堆以後,咱們會發現最大值會在數組的首位:
接下來不斷建堆,而後讓數組最後一位與當前堆頂(數組第一位)進行交換便可排序:
for (int i = 0; i < arrays.length; i++) { //每次建堆就能夠排除一個元素了 maxHeapify(arrays, arrays.length - i); //交換 int temp = arrays[0]; arrays[0] = arrays[(arrays.length - 1) - i]; arrays[(arrays.length - 1) - i] = temp; }
堆排序是比其餘排序要難一點,他用到了徹底二叉樹這麼一個特性來進行排序,代碼實現上也比其餘排序要複雜一點。
參考資料:
若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同窗,能夠 關注微信公衆號:Java3y