資料結構 - 堆(Heap)
1.堆的定義
堆的形式滿足完全二叉樹的定義:
- 若
i < ceil(n/2)
,則節點i
為分支節點,否則為葉子節點 - 葉子節點只可能在最大的兩層出現,而最大層次上的葉子節點都依次排列在該層最左側的位置上
- 如果有度為
1
的節點,那麼只可能有一個,且該節點只有左孩子
根據堆定義的不同,分為大根堆和小根堆:
- 大根堆每個節點的值都大於其子節點的值
- 小根堆每個節點的值都小於其子節點的值
除此之外還有一個重要的內容:
- 單節點也符合堆的特質
2.堆的初始化
堆的初始化可以可以分為如下幾個步驟(以初始化最大根堆為例):
- 首先初始化為完全二叉樹形式。
- 從最後一個具有孩子節點的節點進行調整,如果以該元素為根的子樹是最大根堆,則不進行操作,否則將該子樹調整為最大根堆(調整思路為不斷與子節點進行比較和交換,直至滿足最大根堆要求為止)。
- 陣列:
[2,7,26,25,19,17,90,3]
,初始化為完全二叉樹形式。
- 調整最後一個具有孩子節點的節點
[4]
,符合最大根堆要求,不進行操作。
- 調整節點
[3]
,以滿足最大根堆要求,交換[3]
和[7]
。
- 調整節點
[2]
,以滿足最大根堆要求,交換[2]
和[5]
。
- 調整節點
[1]
,以滿足最大根堆要求,交換[1]
和[3]
後繼續交換[3]
和[7]
,最終完成初始化,滿足最大根堆要求。
3.堆節點的插入和調整
如上圖所示,在如上所示圖中插入44
- 與父節點比較
[4]
小於[9]
,進行交換。
- 與父節點比較
[2]
小於[4]
,進行交換。
- 與父節點比較
[1]
大於[2]
,調整結束。
- 堆的初始化和插入的C++語言程式碼描述
/**
*@Author : Kindear
*@Intro : DataStrcut C++ Code 以最大根堆為例
**/
#include <bits/stdc++.h>
#define ARR_SIZE 20
using namespace std;
typedef int ElementType;
void AdjustUp(ElementType A[],int k, int len) //該方法用於堆插入調整
{
int Tmp = A[k]; //暫存k位置的數值
int i = k/2; //父節點的下標
while(i > 0 && A[i] < Tmp)
{
//如果該節點大於父節點,那麼就交換兩者的位置,滿足最大根堆的要求
A[k] = A[i];
k = i;
i = k/2; //繼續向上尋找並調整,直至滿足最大根堆要求
}
A[k] = Tmp; //
}
void AdjustDown(ElementType A[],int k,int len) //該方法用於堆的初始化
{
int Tmp = A[k];
for(int i = 2*k; i <= len; i*=2) //向下篩選
{
if(i < len && A[i] < A[i+1]) i++;
if(Tmp > A[i]) break;
else
{
A[k] = A[i];
k = i;
}
}
A[k] = Tmp;
}
void BuildMaxHeap(ElementType A[],int len)
{
for(int i= len/2 ; i > 0; i--)
{
AdjustDown(A,i,len);
}
}
void PrintfElementArray(ElementType A[],int len)
{
for(int i=1;i<=len;i++)
{
printf("%d%c",A[i],i==len?'\n':' ');
}
}
int main()
{
ElementType A[] = {0,2,7,26,25,19,17,90,3};
ElementType B[ARR_SIZE];
BuildMaxHeap(A,8);
PrintfElementArray(A,8);
for(int i=0;i<=8;i++)
{
B[i] = A[i];
}
B[9] = 44;//插入44
AdjustUp(B,9,9);
PrintfElementArray(B,9);
}