數據結構之堆

定義

堆是一種特別的樹狀結構,咱們首先來看看維基百科的上定義。java

(英語:Heap)是 計算機科學中的一種特別的樹狀 數據結構。如果知足如下特性,便可稱爲堆:「給定堆中任意節點 P 和 C,若 P 是 C 的母節點,那麼 P 的值會小於等於(或大於等於) C 的值」。若母節點的值恆 小於等於子節點的值,此堆稱爲 最小堆(min heap);反之,若母節點的值恆 大於等於子節點的值,此堆稱爲 最大堆(max heap)。在堆中最頂端的那一個節點,稱做 根節點(root node),根節點自己沒有 母節點(parent node)。

總結來講,堆是一個徹底二叉樹,最多隻有兩個子節點,而且必須保證根節點是最大的值或者最小的值,因此對於一個堆而言,根節點是最大的值或者是最小的值。node

存儲

由於堆是一棵徹底二叉樹,因此使用數組能夠高效的存儲數據。對於使用數組存儲的方式,有兩個性質很是關鍵,對於一個非根節點的節點i來講,若是它的下標爲k,那麼它的父節點的下標爲 (k -1)/2,子節點的下標爲2 *k +12 *k + 2git

基本操做

  • 堆化
  • 插入
  • 刪除
堆化

對於任意一個無序數組而言,實現堆化的步驟以下,咱們以構建一個最大堆爲例:算法

  1. 找到第一個非葉子節點,對這個節點的左子樹和右子樹與節點比較,將大的元素放置到父節點的位置,直到父節點已是最大值或者改節點已是葉子節點。
  2. 依次對全部的非葉子節點進行第一步的操做
private Heap(int[] data)
{
    int last_p = data.length - 1;
    //i是第一個非葉子節點
    for (int i = (last_p - 1) / 2; i >= 0; i--)
    {
        heapify(data, i, last_p);
    }
    this.data = data;
}

private void heapify(int[] data, int start, int end)
{
    int value = data[start];
    int current_p = start;
    //左孩子
    int left_p = 2 * current_p + 1;
    while (left_p <= end)
    {
        //右節點大於左節點
        if (left_p < end && data[left_p] < data[left_p + 1])
        {   
            //移動位置到右節點
            left_p++;
        }
        //當前的父節點已是最大值
        if (data[left_p] < value)
        {
            break;
        }
        else
        {   //子節點上移到父節點的位置
            data[current_p] = data[left_p];
            current_p = left_p;
            left_p = current_p * 2 + 1;
        }
    }
    data[current_p] = value;
}
插入

插入的算法以下:.將新增的節點放在數組的最末端,也就是數組的最後一個位置。而後計算出父節點的位置,讓當前節點與父節點比較,若是父節點比較小,交換位置。重複上述步驟,直到父節點大於當前節點或者當前節點是根節點。api

public int insert(int value)
{
    checkSize();
    int position = data.length - 1;
    data[position] = value;

    int current_p = position;
    int parent_p = (position - 1) / 2;
    while (current_p > 0)
    {
        if (data[parent_p] > value)
        {
            break;
        }
        else
        {
            data[current_p] = data[parent_p];
            current_p = parent_p;
            parent_p = (current_p - 1) / 2;
        }
    }
    data[current_p] = value;
    return position;
}
刪除

刪除的算法以下:將數組最後一個節點與當前須要刪除的節點替換,刪除最後一個節點,對於替換的節點來講,至關於進行了依次插入操做,不過此次是從上往下的插入。算法與remove相同,也是比較最大的值進行替換,直到不知足條件爲止。數組

刪除根節點
public int remove()
{
    int root = data[0];
    int last = data[data.length - 1];
    data[0] = last;
    data = Arrays.copyOf(data, data.length - 1);
    if (data.length == 0)
    {
        return root;
    }
    //從頂點開始調整
    int current_p = 0;
    int l = current_p * 2 + 1;
    int value = data[current_p];
    while (l < data.length)
    {
        if (l < data.length - 1 && data[l] < data[l + 1])
        {
            l++;  //右孩子大
        }
        if (data[l] <= value)
        {
            break;
        }
        else
        {
            data[current_p] = data[l];
            current_p = l;
            l = current_p * 2 + 1;
        }
    }
    data[current_p] = value;
    return root;
}

應用

堆應用比較多的一個用處就是堆排序,對於一個數組進行堆化以後,第一個數組是最大的值,而後交換第一個數和最後一個數,這樣最大的數就落在了最後一個數組的位置。縮小數組,重複以前的步驟,最後就獲得了一個排序好的數組。數據結構

int[] data = new int[] {20, 40, 80, 33, 111, 47, 21, 90, -1};
HeapSort hs = new HeapSort();
hs.heap_array(data, data.length - 1);

for (int i = 0; i < data.length - 1; i++)
{
    int tmp = data[0];
    data[0] = data[data.length - 1 - i];
    data[data.length - 1 - i] = tmp;
    hs.heap_array(data, data.length - 2 - i);
}
System.out.println(Arrays.toString(data));

代碼地址: https://gitee.com/devnew/Algo...this

相關文章
相關標籤/搜索