堆的基本操作解析

堆排序
用堆封裝優先級隊列
海量數據TopK問題
堆的完整源代碼

什麼是堆

首先,堆是完全二叉樹。
小堆: 任何一個節點的值都小於它的左右孩子的值,位於堆頂節結點的值是最小的,從根結點到每個結點的路徑上數組元素組成的序列是遞增的。
大堆:任何一個節點的值都大於它的左右孩子的值,位於堆頂節結點的值是最大的,從根結點到每個結點的路徑上數組元素組成的序列是遞減的。

堆的基本操作簡單解析

建堆
  • 先申請一塊空間,然後在對其賦值形成二叉樹,在對二叉樹調整使之形成小堆
  • 這裏要注意,每次向下調整隻是對一個元素調整,因此需要一個for循環。
//創建堆
void CreateHeap(Heap *hp, DataType *array, int size)
 {
    assert(hp);

    //申請空間
    hp->_array = (DataType *)malloc(sizeof(DataType)*size);
    if (NULL == hp)
        assert(0);
    hp->_size = 0;
    hp->_capacity = size;

    //賦值
    for (int i = 0; i < size; ++i)
    {
        hp->_array[i] = array[i];
        hp->_size += 1;
    }
    hp->_capacity = size;
    //找出最後一個非葉子節點
    int root = (size - 1 - 1) >> 1;

    //調整元素
    for (; root >= 0; root--)
        AdjustDown(hp,root);
}
向下調整算法(小堆爲例)
  • 設該結點的下標爲parent
  • 找到該結點的左孩子(child = (parent<<1)+1;)
  • 如果右孩子存在,則找出左右孩子中最小的孩子(建立大堆,則找出最大的孩子)
  • 比較parent和child的大小,如果parent小於child,則調整結束,否則,交換parent的child的值,此時如果其子樹還不滿足,則繼續調整,直至子樹也滿足堆的性質
void AdjustDown(Heap  *hp, DataType parent)
{
    int child = (parent<<1)+1;

    if (NULL == hp)
        return;
    while (child < hp->_size)
    {
        //找到孩子中較小的一個
        if ((child+1) < hp->_size && 
            hp->cmp(hp->_array[child+1], hp->_array[child]))
        {
            child += 1;
        }
        //如果雙親大於孩子,則交換
        if (hp->cmp(hp->_array[child], hp->_array[parent]))
        {
            Swop(&hp->_array[parent], &hp->_array[child]);
            parent = child;
            child = (parent << 1) + 1;
        }
        else
        {
            break;
        }
    }
}
插入元素
  • 如果堆爲空,返回
  • 檢測容量,看是否還有空間,沒有則擴容
  • 將元素添加到二叉堆的最後
  • 然後調整堆

void InsertHeap(Heap *hp, DataType data)
{
    if (NULL == hp)
        return;
    CheckCatacity(hp);
    hp->_array[hp->_size] = data;
    hp->_size++;

    if (hp->_size > 1)
    AdjustUp(hp, hp->_size - 1);
}
向上調整算法(插入元素)

在插入之前堆已經使最小堆了,因此插入元素之後,需要重新對堆進行調整。

  • 比較新插入的元素和parent的值的大小,如果大於,則返回,如果小於,則需要交換parent和child的值,然後繼續比較,調整後的parent和他的parent的大小,直至滿足小堆的性質
void AdjustUp(Heap *hp, int child)
{
    int parent = (child - 1) >> 1;

    while (child)
    {
        if (hp->cmp(hp->_array[child] , hp->_array[parent]))
        {
            Swop(&hp->_array[parent], &hp->_array[child]);
            child = parent;
            parent = (child - 1) >> 1;
        }
        else
            break;
    }
}
刪除元素
  • 將堆中最後一個元素和堆頂元素交換
  • 將堆的元素個數減少一個,相當於刪除堆中最後一個元素
  • 然後利用向下調整,使其滿足最小堆的性質
void DeleteHeap(Heap *hp)
{
    assert(hp);
    if (NULL == hp)
        return;
    if (EmptyHeap(hp))
        return;

    Swop(&hp->_array[0], &hp->_array[hp->_size-1]);
    hp->_size--;
    AdjustDown(hp, 0);
}
發佈了82 篇原創文章 · 獲贊 30 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章