優先隊列(堆) -數據結構(C語言實現)
阿新 • • 發佈:2018-09-08
++ eem enter ext lock 二次 arr 快速 left
數據結構與算法分析
優先隊列
模型
- Insert(插入) == Enqueue(入隊)
- DeleteMin(刪除最小者) == Dequeue(出隊)
基本實現
簡單鏈表:在表頭插入,並遍歷該鏈表以刪除最小元
時間代價昂貴
二叉查找樹
二叉查找樹支持許多不需要的操作,實現麻煩,不值得
最合適:二叉堆
二叉堆
堆的兩種性質
結構性
- 完全二叉樹:除底層外完全填滿,底層也是從左至右填
- 完全二叉樹的高為
log N
- 分布很有規律可以用數組實現
左兒子 = 2i
右兒子 = 2i + 1
堆序性
- 樹的最小元應該在根節點上
- 每個節點X,X的父親的關鍵字應該小於或等於X的關鍵字
實現
優先隊列的聲明
struct HeapStrcut ; typedef struct HeapStruct *PriorityQueue ; PriorityQueue Intialize(int MaxElement) ; void Destory(PriorityQueue H) ; void MakeEmpty(PriorityQueue H) ; void Insert(ElementType X, PriorityQueue H) ; ElementType DeleteMin(PriotityQueue H) ; ElementType Find(PritityQueue H) ; int IsEmpty(PriorityQueue H) ; int IsFull(PriorityQueue H) ; srtuct HeapStruct { int Capacity ; int Size l ElementType *Elements ; }
初始化
PriorityQueue Intialize(int MaxElement) { PriorityQueue H ; H->Elements = malloc((MaxElement + 1) * sizeof(ElementType) ; if(H->Elements == NULL) FatalError("內存不足"); H->Capacity = MaxElement ; H->Size = 0; H->Elements[0] = MinData ;//在根節點賦一個絕對的小的值 return H ; }
Insert操作
上濾
void Insert(ElementType X, PriorityQueue H)
{
int i ;
if(IsFull(H))
Error("堆滿") ;
for(i = ++H->Size;H->Elements[i/2] > X;i/2)
H->Elenemts[i] = H->Elements[i/2] ;
H->Elements[i] = X ;
return H ;
}
Delete函數
下濾
先拿到最後一個元素,和當前被刪除後剩下的空穴的最小兒子比較,如果兒子小則換至空穴,繼續下濾,反之將最後一個元素放置空穴結束下濾
ElementType Insert(PriorityQueue H)
{
int i,Child ;
ElementType MinElement,LastElement ;
if(IsEmpty(H))
{
Error("堆為空") ;
return H->Elements[0] ;
}
MinElement = H->Elements[1];
LastElement = H->Elements[H->Size--] ;
for(i = 1; i * 2 <= H->Size;i = Child)
{
Child = i * 2;
if(Child != H->Size && H->Element[Child] > H->Elements[Child + 1])
Child ++ ;
if(LastElement > H->Elements[Child)
H->Elements[i] = H->Elements[Child] ;
else break ;
}
H->Elements[i] = LastElement ;
return MinElenemt;
}
左式堆
性質
高效支持Merge操作
和二叉樹唯一區別在於:左式堆不是理想平衡的
對於堆中的每一個節點X,左兒子的零路徑長NPL大於右兒子的零路徑長NPL
- 零路徑長(NPL):從該節點到一個沒有兩個兒子的節點的最短路徑長
左式堆的類型聲明
PriorityQueue Intailize(void) ;
ElementType FindMin(PriorityQueue H) ;
int IsEmpty(PriorityQueue H) ;
PriorityQueue Merge(PriorityQueue H1,PriorityQueue H2) ;
#define Insert(X,H) (H = Insert1(X,H)) ; //為了兼容二叉堆
PriorityQueue Insert1(ElementType, PriorityQueue H) ;
PriorityQueue DeleteMin(PriorityQueue H) ;
sturct TreeNode
{
ElementType Element ;
PriorityQueue Left ;
PriorityQueue Right ;
int Npl ;
}
Merge操作
驅動程序
PriorityQueue Merge(PriorityQueue H1,PriorityQueue H2)
{
if(H1 == NULL)
return H2 ;
eles if(H2 == NULL)
return H1 ;
else if(H1->Element > H2->Element)
return Merge1(H1,H2) ;
else
return Merge1(H1S,H2) ;
}
實際操作
PriorityQueue Merge1(PriortyQueue H1,PriorityQueue H2)
{
if(H1->Left == NULL)
H1->Left = H2 ;
else
{
H2->Right = Merge1(H1->Right,H2) ;
if(H1->Left->Npl < H1->Right->Npl)
SwapChildren(H1) ;
H1->Npl = H1->Right->Npl + 1;
}
return H1 ;
}
Insert操作
PriorityQueue Insert(ElementType X,PriorityQueue H)
{
PriorityQueue SinglNode ;
SinglNode = malloc(sizeof(TreeNode)) ;
if(SinglNode == NULL)
FatalError("內存不足") ;
else
{
SingleNode->Element = X ;
SingleNode->Npl = 0 ;
SingleNode->Left = SingleNode->Right = NULL ;
Merge(SingleNode,H) ;
}
return H ;
}
Delete操作
PriorityQueue DeleteMin1(PriorityQueue H)
{
PriorityQueue LeftHeap,RightHeap ;
if(IsEmpty(H))
FatalError("隊列為空") ;
else
{
LeftHeap = H1->Left ;
RightHeap = H1->Right ;
free(H) ;
Merge(LeftHeap,RightHeap) ;
}
}
二項隊列
結構
- 二項隊列是堆序樹的集合,稱為森林
- 堆序中每顆樹都是有約束的樹,稱為二項樹
- 高度為k的二項樹有一顆二項樹Bk-1附接到另一顆二項樹Bk-1的根上
二項隊列的實現
二項隊列將是二項樹的數組
二項樹的每個節點包含數據,第一個兒子和兄弟
二項隊列的類型聲明 `
typedef struct BinNode *Position ;
typedef struct Collection *BinQueue ;
struct BinNode
{
ElementType Element ;
Position LeftChild ;
Position NextBiling ;
}
typedef Position BinTree ;
struct Collection
{
int CurrentSize ;
BinTree TheTrees[MaxTree] ;
}
Merge操作
合並兩個相同大小的兩顆二項樹
BinTree ConbineTrees(BinTree T1,BinTree T2)
{
if(T1->Element > T2->Element)
return CombineTree(T2,T1) ;
T2->NextBling = T1->LeftChild ;
T1->LeftChild = T2 ;
return T1 ;
}
合並兩個優先隊列
BinQueue Merge(BinQueue H1,BinQueue H2)
{
BinTree T1,T2,Carry = NULL ;
int i ,j ;
if(H1->CurrentSize + H2->CurrentSize > Capacity)
Error("合並後過大") ;
H1->CurrentSize += H2->CurrentSize ;
for(i = 0;j = 1;j <= H1->CurrentSize; i++,j *= 2)
{
T1 = H1->TheTree[i] ;
T2 = H2->TheTree[i] ;
switch(!!T1 + 2 * !!T2 + 4 * !!Carry)
{
case 0 : //空樹
case 1:
break ; //只有H1
case 2:
H1->TheTree[i] = T2
H2->TheTree[i] = NULL ;
break ;
case 4:
H1->TheTree[i] = Carry ;
Carry = NULL ;
case 3: //h1 and h2
Carry = CombineTrees(T1,T2) ;
H1->TheTree[i] = H1->TheTree[i] = NULL ;
break ;
case 5: //h1 and carry
Carry = ConbineTrees(T1,Carry) ;
H1->TheTrees[i] = NULL ;
case 6:
Carry = ConbineTrees(T2,Carry) ;
H2->TheTrees[i] = NULL ;
case 7: //都有
H1->TheTree[i] = Carry ;
Carry = CombineTrees(T1,T2) ;
H2->TheTrees[i] = NULL ;
break ;
}
}
return H1 ;
}
總結
優先隊列可以用二叉堆實現,簡單快速
但考慮到Merge操作,又延申了左式堆和二次隊列
優先隊列(堆) -數據結構(C語言實現)