二项堆 算法基础篇(二)

View Code
  1 // 二项堆.cpp : 定义控制台应用程序的入口点。
  2 //
  3 /***********************************************************
  4 
  5 二项堆,算法数据结构复习
  6 
  7 Designer By cslave
  8 
  9 
 10 
 11 **************************************************************/
 12 
 13 
 14 #include "stdafx.h"
 15 #include <stdio.h>
 16 #include <stdlib.h>
 17 #include <iostream>
 18 using namespace std;
 19 #define MaxTrees 14
 20 #define INF (30000L)
 21 #define Capacity (16383)
 22 #define FatalError(Str) fprintf(stderr,"%s\n",Str),exit(1)
 23 typedef int ElementType ;
 24 typedef struct BinNode* Position;
 25 typedef struct BinNode* BinTree;
 26 struct BinNode                        //二项堆树节点
 27 {
 28     ElementType Element;                     
 29     Position    LeftChild;            
 30     Position    NextSibling;
 31 };
 32 struct Collection                     //二项堆
 33 {
 34     int CurrentSize;
 35     BinTree TheTrees[MaxTrees];
 36 };
 37 
 38 typedef struct Collection* BinQueue;       //二项堆类型的指针
 39 
 40 bool IsEmpy(BinQueue H)                //二项堆是否为空 即是否含有节点       
 41 {
 42     return H->CurrentSize==0;
 43 }
 44 
 45 bool IsFul(BinQueue H)                //二项堆是否为满,即节点数是否满载
 46 {
 47     return H->CurrentSize==Capacity;
 48 }
 49 
 50 BinQueue Initialize()                   //二项堆初始化          
 51 {
 52     BinQueue H;
 53     int i ;
 54     H=(BinQueue)malloc(sizeof (struct Collection));
 55     if(H==NULL)
 56     FatalError("out of space");
 57     H->CurrentSize=0;
 58     for(i=0;i<MaxTrees;i++)
 59         H->TheTrees[i]=NULL;           //初始化每一个二项堆树节点为空
 60     return H;
 61 }
 62 
 63 void DestroyTree(BinTree T)             //二项堆树节点的析构
 64 {
 65     if(T!=NULL)
 66     {
 67         DestroyTree(T->LeftChild);
 68         DestroyTree(T->NextSibling);
 69         free(T);
 70     }
 71 }
 72 
 73 void Destroy(BinQueue H)               //二项堆的析构
 74 {
 75     int i;
 76     for(i=0;i<MaxTrees;i++)
 77         DestroyTree(H->TheTrees[i]);
 78 }
 79 
 80 
 81 BinQueue MakeEmpty(BinQueue H)  //二项堆的置空
 82 {
 83     int i;
 84     Destroy(H);
 85     for(i=0;i<MaxTrees;i++)
 86         H->TheTrees[i]=NULL;
 87     H->CurrentSize=0;
 88     return H;
 89 }
 90 
 91 BinTree CombineTrees(BinTree T1,BinTree T2) //子二项树的合并
 92 {
 93     if(T1->Element>T2->Element)
 94         return CombineTrees(T2,T1);       //调整节点,根较小的二项树作为主合并点
 95     T2->NextSibling=T1->LeftChild;        //二项堆为了快速找出根的子树,采用的是左孩子,右兄弟存储策略 将小根的左孩子作为大根的右兄弟
 96     T1->LeftChild=T2;                    //将大根作为小根的左孩子
 97     return T1;
 98 }
 99 
100 BinQueue Merge(BinQueue H1,BinQueue H2)  //子二项树的合并
101 {
102     BinTree T1,T2,Carry=NULL;                               
103     int i,j;
104     if(H1->CurrentSize+H2->CurrentSize>Capacity)   //边界判定
105         FatalError("Node Num too large!");
106     H1->CurrentSize+=H2->CurrentSize;               
107     for(i=0,j=1;j<=H1->CurrentSize;i++,j*=2)   //j作为判定条件,判断二项堆可以合并为几阶
108     {
109         T1=H1->TheTrees[i];                     //抽取对等子二项树树根
110         T2=H2->TheTrees[i];
111         switch(!!T1+2*!!T2+4*!!Carry)         //此处用法很巧妙 1  !!取一个数的布尔真值  2 我们用三个变量的二进制三位码表征八种情况
112         {
113         case 0:                             //没有子二项树
114         case 1:break;                        //只有T1 因为我们返回H1 所以什么都不用做。
115         case 2:                             //只有T2,我们仅需将T2赋值给H1即可
116             H1->TheTrees[i]=T2;
117             H2->TheTrees[i]=NULL;
118             break;
119         case 4:                              //上一阶二项树有合并到本阶 ,本阶无二项树
120             H1->TheTrees[i]=Carry;
121             Carry=NULL;
122             break;
123         case 3:                          //本阶两堆都有要合并的子二项树,则产生高阶进位
124             Carry=CombineTrees(T1,T2);
125             H1->TheTrees[i]=H2->TheTrees[i]=NULL;    
126             break;
127         case 5:                           //有低阶来的进位,同时又自身的T1 则合并进位和T1
128             Carry=CombineTrees(T1,Carry);
129             H1->TheTrees[i]=NULL;
130             break;
131         case 6:                           //  有低阶来的进位,同时又自身的T2 则合并进位和T2
132             Carry=CombineTrees(T2,Carry);
133             H2->TheTrees[i]=NULL;
134             break;
135         case 7:                          //此处尚有迷惑,我个人感觉因该是先Tmp=Carry; Carry=CombineTrees(T1,T2);H1->TheTrees[i]=Tmp
136             H1->TheTrees[i]=Carry;
137             Carry=CombineTrees(T1,T2);
138             H2->TheTrees[i]=NULL;
139             break;
140         }
141 
142     }
143     return H1;
144 }
145 
146 
147 BinQueue insert(BinQueue H,ElementType X) //节点的插入,在二项堆插入节点值X 
148 {
149     BinQueue TmpQue;
150     BinTree NewNode;
151     NewNode=(BinTree)malloc(sizeof(struct BinNode));
152     if(NewNode==NULL)
153         FatalError("memory insufficient!");
154     NewNode->Element=X;
155     NewNode->LeftChild=NULL;
156     NewNode->NextSibling=NULL;
157     TmpQue=Initialize();
158     TmpQue->CurrentSize=1;
159     TmpQue->TheTrees[0]=NewNode;          //创建仅含一个树节点的二项堆再与原来的堆做合并操作
160     return Merge(H,TmpQue);
161 }
162 
163 ElementType DeleteMin(BinQueue H)        //删除二项堆最小元素
164 {
165     int i,j;
166     int MinTree;
167     BinQueue DeleteQueue;
168     Position DeleteTree,OldRoot;
169     ElementType MinItem;
170     if(IsEmpy(H))
171     {
172         FatalError("BinQueue is Empty!");
173         return -INF;
174     }
175     MinItem= INF;
176     for(i=0;i<MaxTrees;i++)           //由二项堆性质可知,二项堆最小元素必然在每一个二项树的树根
177     {
178         if(H->TheTrees[i]&&H->TheTrees[i]->Element<MinItem) //找到并保存二项堆的最小值和索引i
179         {
180             MinItem=H->TheTrees[i]->Element;
181             MinTree=i;
182         }
183     }
184     DeleteTree=H->TheTrees[MinTree];      
185     OldRoot=DeleteTree;
186     DeleteTree=DeleteTree->LeftChild; //指向左儿子
187     free(OldRoot);
188     DeleteQueue=Initialize();        //初始化一二项堆
189     DeleteQueue->CurrentSize=(1<<MinTree)-1; //更新堆元素个数
190     for(j=MinTree-1;j>=0;j--)
191     {
192         DeleteQueue->TheTrees[j]=DeleteTree;//将左儿子作为堆的小一阶二项树
193         DeleteTree=DeleteTree->NextSibling;        //将左儿子的右兄弟作为下一个处理对象
194         DeleteQueue->TheTrees[j]->NextSibling=NULL; //处理后将二项树根节点右兄弟置空
195     }
196     H->TheTrees[MinTree]=NULL;//已经处理完最小树,将该树在堆数组中的元素置空
197     H->CurrentSize-=DeleteQueue->CurrentSize+1;//从原始堆中减去处理掉的二项树元素个数,加1是因为还有二项树根我们删除了
198     Merge(H,DeleteQueue);//合并H和新二项堆。
199     return MinItem;
200 
201 
202 
203 }
204 
205 
206 
207 
208 
209  
210 
211 
212 
213 
214 
215 int _tmain(int argc, _TCHAR* argv[])
216 {
217     ElementType arr[8]={12,24,21,65,14,16,18,26};
218     BinQueue H=Initialize();
219     for(int i=0;i<8;i++)
220         insert(H, arr[i]);
221     for(int j=0;j<8;j++)
222         cout<<DeleteMin(H)<<" ";
223     
224     return 0;
225 }
原文地址:https://www.cnblogs.com/cslave/p/2546534.html