【数据结构】堆 笔记
什么是堆
優(yōu)先隊(duì)列(Priority Queue):特殊的“隊(duì)列”,取出元素的順序是依照元素的優(yōu)先權(quán)(關(guān)鍵字)大小,而不是元素進(jìn)入隊(duì)列的先后順序。
若采用數(shù)組或鏈表實(shí)現(xiàn)優(yōu)先隊(duì)列
數(shù)組 :
插入 — 元素總是插入尾部 ~ Θ\ThetaΘ ( 1 )
刪除 — 查找最大(或最小)關(guān)鍵字 ~ Θ\ThetaΘ ( n )
從數(shù)組中刪去需要移動(dòng)元素 ~ O( n )
鏈表:
插入 — 元素總是插入鏈表的頭部 ~ Θ\ThetaΘ ( 1 )
刪除 — 查找最大(或最小)關(guān)鍵字 ~ Θ\ThetaΘ ( n )
刪去結(jié)點(diǎn) ~ Θ\ThetaΘ ( 1 )
有序數(shù)組:
插入 — 找到合適的位置 ~ O( n ) 或 O(log2log_2log2? n )
移動(dòng)元素并插入 ~ O( n )
刪除 — 刪去最后一個(gè)元素 ~ Θ\ThetaΘ ( 1 )
有序鏈表:
插入 — 找到合適的位置 ~ O( n )
插入元素 ~ Θ\ThetaΘ ( 1 )
刪除 — 刪除首元素或最后元素 ~ Θ\ThetaΘ ( 1 )
是否可以采用二叉樹存儲(chǔ)結(jié)構(gòu)?
二叉搜索樹? 一直刪除最大的結(jié)點(diǎn)導(dǎo)致樹變斜,不能采用
如果采用二叉樹結(jié)構(gòu),需要做兩個(gè)操作:插入任何結(jié)點(diǎn)、刪除最大值,其中更應(yīng)關(guān)注刪除最大值(因?yàn)楦y做)。可以考慮將樹構(gòu)造成 將最大值放在樹根,刪除最大值就將根結(jié)點(diǎn)拿掉,這就是最大堆。使用完全二叉樹存儲(chǔ)。
優(yōu)先隊(duì)列的完全二叉樹表示
堆的兩個(gè)特性
“最大堆(MaxHeap)”,也稱“大頂堆”:最大值
“最小堆(MinHeap)”,也稱“小頂堆” :最小值
【例子】:
最大堆:
最小堆:
不是堆:
不是完全二叉樹
不滿足根結(jié)點(diǎn)是最大的/最小的
注意:從根結(jié)點(diǎn)到任意結(jié)點(diǎn)路徑上結(jié)點(diǎn)序列的有序性!
堆的抽象數(shù)據(jù)類型描述
類型名稱:最大堆(MaxHeap)
數(shù)據(jù)對(duì)象集:完全二叉樹,每個(gè)結(jié)點(diǎn)的元素值不小于其子結(jié)點(diǎn)的元素值
操作集:最大堆H ∈\in∈MaxHeap,元素item ∈\in∈ ElementType,主要操作有:
?MaxHeap Create( int MaxSize ):創(chuàng)建一個(gè)空的最大堆。
?Boolean IsFull( MaxHeap H ):判斷最大堆H是否已滿。
?Insert( MaxHeap H, ElementType item ):將元素item插入最大堆H。
?Boolean IsEmpty( MaxHeap H ):判斷最大堆H是否為空。
?ElementType DeleteMax( MaxHeap H ):返回H中最大元素(高優(yōu)先級(jí))。
最大堆的操作
創(chuàng)建
typedef struct HeapStruct *MaxHeap;struct HeapStruct {ElementType *Elements; /* 存儲(chǔ)堆元素的數(shù)組 */int Size; /* 堆的當(dāng)前元素個(gè)數(shù) */int Capacity; /* 堆的最大容量 */ }; MaxHeap Create( int MaxSize ) { /* 創(chuàng)建容量為MaxSize的空的最大堆 */MaxHeap H = malloc( sizeof( struct HeapStruct ) );H->Elements = malloc( (MaxSize+1) * sizeof(ElementType));H->Size = 0;H->Capacity = MaxSize;H->Elements[0] = MaxData;/* 定義“哨兵”為大于堆中所有可能元素的值,便于以后更快操作 */return H; }插入
算法:將新增結(jié)點(diǎn)插入到從其父結(jié)點(diǎn)到根結(jié)點(diǎn)的有序序列中
void Insert( MaxHeap H, ElementType item ) { /* 將元素item 插入最大堆H, 其中H->Elements[0]已經(jīng)定義為哨兵 */int i;if ( IsFull(H) ) {printf("最大堆已滿");return; } i= ++H->Size; /* i指向插入后堆中的最后一個(gè)元素的位置 */ for ( ; H->Elements[i/2] < item; i/=2 )H->Elements[i] = H->Elements[i/2]; /* 向下過濾結(jié)點(diǎn) */ H->Elements[i] = item; /* 將item 插入 */ }我們?cè)O(shè)置H->Element[ 0 ] 是哨兵元素,它不小于堆中的最大元素,控制循環(huán)結(jié)束。
時(shí)間復(fù)雜度T(N) = log2log_2log2? N (樹的高度)
刪除
ElementType DeleteMax( MaxHeap H ) { /* 從最大堆H中取出鍵值為最大的元素, 并刪除一個(gè)結(jié)點(diǎn) */int Parent, Child;ElementType MaxItem, temp;if ( IsEmpty(H) ) {printf("最大堆已為空");return;}MaxItem = H->Elements[1]; /* 取出根結(jié)點(diǎn)最大值 *//* 用最大堆中最后一個(gè)元素從根結(jié)點(diǎn)開始向上過濾下層結(jié)點(diǎn) */temp = H->Elements[H->Size--];for( Parent=1; Parent*2<=H->Size; Parent=Child ) {Child = Parent * 2;if( (Child!= H->Size) &&(H->Elements[Child] < H->Elements[Child+1]) )Child++; /* Child指向左右子結(jié)點(diǎn)的較大者 */if( temp >= H->Elements[Child] ) break;else /* 移動(dòng)temp元素到下一層 */H->Elements[Parent] = H->Elements[Child];} H->Elements[Parent] = temp;return MaxItem;最大堆的建立
建立最大堆: 將已經(jīng)存在的N個(gè)元素按最大堆的要求存放在一個(gè)一維數(shù)組中
方法1: 通過插入操作,將N個(gè)元素一個(gè)個(gè)相繼插入到一個(gè)初
始為空的堆中去,其時(shí)間代價(jià)最大為O(N logN)。
方法2: 在線性時(shí)間復(fù)雜度下建立最大堆。
(1)將N個(gè)元素按輸入順序存入,先滿足完全二叉樹的結(jié)構(gòu)特性
(2)調(diào)整各結(jié)點(diǎn)位置,以滿足最大堆的有序特性。
完整代碼
typedef struct HNode *Heap; /* 堆的類型定義 */ struct HNode {ElementType *Data; /* 存儲(chǔ)元素的數(shù)組 */int Size; /* 堆中當(dāng)前元素個(gè)數(shù) */int Capacity; /* 堆的最大容量 */ }; typedef Heap MaxHeap; /* 最大堆 */ typedef Heap MinHeap; /* 最小堆 */#define MAXDATA 1000 /* 該值應(yīng)根據(jù)具體情況定義為大于堆中所有可能元素的值 */MaxHeap CreateHeap( int MaxSize ) { /* 創(chuàng)建容量為MaxSize的空的最大堆 */MaxHeap H = (MaxHeap)malloc(sizeof(struct HNode));H->Data = (ElementType *)malloc((MaxSize+1)*sizeof(ElementType));H->Size = 0;H->Capacity = MaxSize;H->Data[0] = MAXDATA; /* 定義"哨兵"為大于堆中所有可能元素的值*/return H; }bool IsFull( MaxHeap H ) {return (H->Size == H->Capacity); }bool Insert( MaxHeap H, ElementType X ) { /* 將元素X插入最大堆H,其中H->Data[0]已經(jīng)定義為哨兵 */int i;if ( IsFull(H) ) { printf("最大堆已滿");return false;}i = ++H->Size; /* i指向插入后堆中的最后一個(gè)元素的位置 */for ( ; H->Data[i/2] < X; i/=2 )H->Data[i] = H->Data[i/2]; /* 上濾X */H->Data[i] = X; /* 將X插入 */return true; }#define ERROR -1 /* 錯(cuò)誤標(biāo)識(shí)應(yīng)根據(jù)具體情況定義為堆中不可能出現(xiàn)的元素值 */bool IsEmpty( MaxHeap H ) {return (H->Size == 0); }ElementType DeleteMax( MaxHeap H ) { /* 從最大堆H中取出鍵值為最大的元素,并刪除一個(gè)結(jié)點(diǎn) */int Parent, Child;ElementType MaxItem, X;if ( IsEmpty(H) ) {printf("最大堆已為空");return ERROR;}MaxItem = H->Data[1]; /* 取出根結(jié)點(diǎn)存放的最大值 *//* 用最大堆中最后一個(gè)元素從根結(jié)點(diǎn)開始向上過濾下層結(jié)點(diǎn) */X = H->Data[H->Size--]; /* 注意當(dāng)前堆的規(guī)模要減小 */for( Parent=1; Parent*2<=H->Size; Parent=Child ) {Child = Parent * 2;if( (Child!=H->Size) && (H->Data[Child]<H->Data[Child+1]) )Child++; /* Child指向左右子結(jié)點(diǎn)的較大者 */if( X >= H->Data[Child] ) break; /* 找到了合適位置 */else /* 下濾X */H->Data[Parent] = H->Data[Child];}H->Data[Parent] = X;return MaxItem; } /*----------- 建造最大堆 -----------*/ void PercDown( MaxHeap H, int p ) { /* 下濾:將H中以H->Data[p]為根的子堆調(diào)整為最大堆 */int Parent, Child;ElementType X;X = H->Data[p]; /* 取出根結(jié)點(diǎn)存放的值 */for( Parent=p; Parent*2<=H->Size; Parent=Child ) {Child = Parent * 2;if( (Child!=H->Size) && (H->Data[Child]<H->Data[Child+1]) )Child++; /* Child指向左右子結(jié)點(diǎn)的較大者 */if( X >= H->Data[Child] ) break; /* 找到了合適位置 */else /* 下濾X */H->Data[Parent] = H->Data[Child];}H->Data[Parent] = X; }void BuildHeap( MaxHeap H ) { /* 調(diào)整H->Data[]中的元素,使?jié)M足最大堆的有序性 *//* 這里假設(shè)所有H->Size個(gè)元素已經(jīng)存在H->Data[]中 */int i;/* 從最后一個(gè)結(jié)點(diǎn)的父節(jié)點(diǎn)開始,到根結(jié)點(diǎn)1 */for( i = H->Size/2; i>0; i-- )PercDown( H, i ); }總結(jié)
以上是生活随笔為你收集整理的【数据结构】堆 笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 04-树7 二叉搜索树的操作集(c语言实
- 下一篇: 【数据结构】哈夫曼树与哈夫曼编码