堆排序算法剖析

1.將待排序列以一個徹底二叉樹存儲,設二叉樹的深度爲h,除第 h 層外,其它各層 (1~h-1) 的結點數都達到最大個數,第h層全部的結點都連續集中在最左邊,這就是徹底二叉樹。數組

  

2.第一趟排序,從二叉樹的最後一個根節點(有步驟1可知是值爲12的節點)開始,調整當前節點所在的堆,使當前節點大於全部子節點的值,最終獲得的堆是最大根堆。spa

(1)12->363d

(2)73->81code

(3)49->98對象

(4)55->81->73blog

(5)40->98->49排序

3.第二趟排序,每趟排序後,待排序列中的最大值將被移動到根節點,將根節點元素與待排序列中最後一個元素交換位置,紅色元素表示已經排好的序列,紅色元素不參與下輪的排序過程class

(1)98->12二叉樹

(2)12->81->73->64im

(3)81->12

(4)12->73->64->55

(5)73->12

(6)12->64->55

(7)64->40

 

(8)40->55

(9)55->27

(10)27->49

(11)49->36

(12)36->40

(13)40->12

(14)12->36

(15)36->27

 

(16)27->12

(16)12->12

 

代碼:

package com.zjl.tool.sort;

/**
 * 堆排序
 * @author huanongying
 *
 */
public class HeapSort {

    /**
     * @param args
     */
    public static void main(String[] args) {
        int[] arr = {40,55,49,73,12,27,98,81,64,36};//待排序數組
        HeapSort(arr, arr.length - 1);//將arr按照降序排列
        //打印排序後的數組
        for(int value : arr) {
            System.out.print(value + " ");
        }
    }

    /**
     * 待排序列(R1,R2,...,Rk,...Rn)看做是徹底二叉樹,經過比較、交換,父節點和孩子節點的值,
     * 使得對於任意元素Rk(k<=n/2),知足Rk>=R(2k),Rk>=R(2k+1)
     * @param arr    數組對象
     * @param start    數組的開始下標
     * @param end    數組的結束下標
     */
    private static void HeapAdjust(int[] arr, int start, int end) {
        //當下標爲start的元素有孩子元素時
        while(start <= end/2) {
            //left和right分別爲左右孩子元素的下標,max爲左右孩子中值較大的孩子的元素下標
            int left = 2 * start+1;
            int right = 2 * start+2;
            int max = 0;
            
            //若是既有左孩子,又有右孩子
            if(left < end&&right <= end) {
                //若是左孩子小於右孩子的值,max = right,不然爲max = left
                if(arr[left] <= arr[right])
                    max = right;
                else
                    max = left;
            }
            //若是隻有左孩子,沒有右孩子,max值爲left
            if(left <= end&&right > end) {
                max = left;
            }
            //若是沒有孩子,則代表到了徹底二叉樹的葉子節點
            if(left > end) {
                break;
            }
            
            //若是當前節點值小於兩孩子中的值較大者,那麼將當前節點值與max交換
            if(arr[start] < arr[max]){
                int tmp = arr[start];
                arr[start] = arr[max];
                arr[max] = tmp;
            }
            //當前節點向孩子節點迭代
            start = max;
        }
    }

    /**
     * @param arr 數組
     * @param end    數組結束下標
     */
    private static void HeapSort(int[] arr, int end) {
        //由最後一個非葉子節點,向根節點迭代,建立最大堆,數組中的最大值將被移動到根節點
        for(int start = end/2;start >= 0;start--) {
            HeapAdjust(arr, start, end);
        }
        
        while(end > 0){
            //交換arr[0]和arr[end]的值
            int tmp = arr[0];
            arr[0] = arr[end];
            arr[end] = tmp;
            
            //排序範圍變爲(0,end-1)
            HeapAdjust(arr, 0, end - 1);
            end--;
        }
    }

}
相關文章
相關標籤/搜索