堆排序的算法及代碼實現「堆排序代碼解析」

目前這個系列的文章都挑着非常經典的,讓人眼前一亮的算法,今天的堆排序算法就是其中一個。 首先理解什麼是堆,這裡面堆(Heap)並不是程序中內存區域,而是一種完全二叉樹表示的數據結構。 堆具有以下特點

  • 是一個完全二叉樹
  • 堆的每個節點的值必須大於等於左右樹節點(大頂堆),或小於等於左右樹節點(小頂堆)。

簡單說明下,完全二叉樹是除了最後一層葉子節點外,其他的節點都有兩個子樹,而葉子節點可以沒有子樹,或者只有左子樹。 如下圖就是個大頂堆:

那些經典的算法-堆排序
那些經典的算法-堆排序

小頂堆

那些經典的算法-堆排序

堆存儲

堆因為是完全二叉樹,非常適合用數組存儲,上圖為大頂堆的存儲情況,其中a[0]不用, a[1]為大頂堆的頂點,也就是最大的數據,a[12]= 7 為左子樹頂點,a[12+1]= 6為右子樹的頂點,其他節點情況依次類推。

堆的兩種操作

向堆插入元素

用圖來表示如下:

那些經典的算法-堆排序

向堆插入元素,先插入到最後一個數組元素位置,然後和自己的父節點6比較,由於比6大不滿足大頂堆的條件,所以9和6交換,然後9再和堆頂元素8比較,又不滿足大頂堆條件,繼續交換,最後形成一個大頂堆,這個步驟叫堆化。

刪除堆頂元素

對於大頂堆來說,堆頂的元素為最大值,依次刪除堆頂元素並輸出,那麼就是將數字從大向小排列了。

這裡面又個技巧,就是刪除堆頂元素的時候,不能直接刪除,要用堆頂元素和最後一個元素做交換,然後根據堆的特點調整堆,直到滿足條件。

那些經典的算法-堆排序

完整代碼如下:

package com.dianneng.lms;

public class TestHeap {
    private int [] a;
    private int n;
    private int count;

    public TestHeap(int cap) {
        a = new int[cap+1];
        n = cap;
        count = 0;
    }

    public void swap(int i,int j) {
        int tmp = a[i];
        a[i] = a[j];
        a[j] = tmp;
        return;
    }

    public void print(){
        for (int i = 0; i <= count;i++) {
            System.out.print(a[i]+"t");
        }
    }

    public int insert( int v) {
        if (count == n) {
            System.out.println("Heap is full!");
            return -1;
        }else {
            a[++count] = v;
            int i = count;
            while (i/2 >0 && a[i] > a[i/2]) {
                swap(i,i/2);
                i = i/2;
            }
        }
        return 0;
    }

    public int  removeMax() {
        if (count == 0)  {
            return -1;
        }
        System.out.print(a[1]+"t");
        a[1] = a[count];
        --count;
        heapify(count,1);
        return 0;
    }

    private void heapify(int n, int i) {
        while(true) {
            int maxPos = i;
            //通過左右子樹頂點比較獲得最大數節點
            if (i*2 <= n && a[i] <a[i*2] ){
                maxPos = i*2;
            }
            if (i*2+1 <= n && a[maxPos] < a[i*2+1]) {
                maxPos = i*2+1;
            }
            //已經是最大的不用交換了
            if  (maxPos == i) {
                break;
            }
            //需要交換
            swap(i,maxPos);
            //i指向待交換的
            i = maxPos;
        }
    }

    public  static void main(String [] args) {
        TestHeap th = new TestHeap(18);
        th.insert(8);
        th.insert(7);
        th.insert(6);
        th.insert(5);
        th.insert(4);
        th.insert(3);
        th.print();
        System.out.println();
        while(th.removeMax() == 0) {

        }
    }
}

可以利用大頂堆的特性,對要排序的數組進行先堆化排序,然後依次交換堆頂元素和最後一個元素,交換後堆化,將堆的大小減一,最終這樣輸出的就是從小到大排序的數組。 借用老師的一個圖表示:

那些經典的算法-堆排序

原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/207730.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
投稿專員的頭像投稿專員
上一篇 2024-12-08 14:38
下一篇 2024-12-08 14:38

相關推薦

發表回復

登錄後才能評論