哈夫曼樹的建立和操作
阿新 • • 發佈:2018-12-22
哈夫曼樹的引進是與帶有權重的二叉樹有關的
首先定義帶權路徑長度(WPL):設二叉樹有n個葉子結點,每個葉子結點帶有權值
最優二叉樹或哈夫曼樹:WPL最小的二叉樹
那麼如何建立一棵哈夫曼樹呢,哈夫曼提出了一種方法,就是每次把權值最小的兩棵二叉樹合併,例如下圖所示
這就可以用到堆,每次把新生成的樹插入進堆,然後彈出兩個樹依次就是最小的樹,揭下來就是具體的實現了,首先是把之前的最小堆改為最大堆,然後把Elements的型別改掉,最後是寫Huffman樹
#include <stdio.h>
#include <stdlib.h>
#define MinData -1000;
#define ERROR -1; /* 錯誤標識應根據具體情況定義為堆中不可能出現的元素值 */
struct TreeNode{
int Weight;
TreeNode *Left;
TreeNode *Right;
};
typedef struct TreeNode *HuffmanTree;
typedef HuffmanTree ElementType;
struct HeapStruct{
ElementType *Elements;//儲存堆元素的陣列
int Size;//堆的當前元素個數
int Capacity;//堆的最大容量
};
typedef struct HeapStruct *MinHeap;
//建立容量為MinSize的空的最小堆
MinHeap Create(int MinSize);
//判斷最小堆是否已滿
int IsFull(MinHeap H);
//最小堆的插入
void Insert(MinHeap &H,ElementType item);
//判斷最小堆是否為空
int IsEmpty(MinHeap H);
//從堆中刪除一個元素
ElementType DeleteMin(MinHeap H);
//建造最小堆
void PercDown( MinHeap H, int p );
void BuildHeap( MinHeap H );
//列印堆中元素
void Print(MinHeap H);
//建立Huffman樹
HuffmanTree Huffman(MinHeap H);
//遍歷樹
void preOrder(HuffmanTree t); //先序遍歷
void intOrder(HuffmanTree t); //中序遍歷
void postOrder(HuffmanTree t); //後序遍歷
int main(){
MinHeap H= Create(15);
int a[]={1,2,3,4,5};
int len=sizeof(a)/sizeof(int);
H->Size=len;
for(int i=0;i<len;i++)
H->Elements[i+1]->Weight=a[i];
Print(H);
HuffmanTree T;
T=Huffman(H);
printf("前序遍歷:");
preOrder(T) ;
printf("\n");
printf("中序遍歷:");
intOrder(T);
printf("\n");
printf("後序遍歷:");
postOrder(T);
printf("\n");
system("pause");
}
//建立容量為MinSize的空的最小堆
MinHeap Create(int MinSize){
MinHeap H=(MinHeap)malloc(sizeof(struct HeapStruct));
H->Elements=(ElementType *)malloc((MinSize+1)*sizeof(ElementType));//從小標為1的地方開始存放
//for(int i=0;i<=MinSize;i++)
//H->Elements[i]=(HuffmanTree)malloc(sizeof(TreeNode));
for(int i=0;i<=MinSize;i++)
{
H->Elements[i]=(ElementType )malloc(sizeof(ElementType));//從小標為1的地方開始存放
H->Elements[i]->Weight=0;//定義“哨兵”為大於堆中所有可能元素的值,便於以後更快操作
H->Elements[i]->Left=NULL;
H->Elements[i]->Right=NULL;
}
H->Size=0;
H->Capacity=MinSize;
H->Elements[0]->Weight=MinData;//定義“哨兵”為大於堆中所有可能元素的值,便於以後更快操作
return H;
//時間複雜性是O(logN)
};
//判斷最小堆是否已滿
int IsFull(MinHeap H){
return(H->Size==H->Capacity);
};
//最小堆的插入
void Insert(MinHeap &H,ElementType item)
{//將元素item插入最小堆H,其中H->Elements[0]已經定義為哨兵
int i;
if(IsFull(H)){
printf("最小堆已滿\n");
return;
}
i=++H->Size;//先Size自加1再賦給i,i指向插入後堆中的最後一個元素
for(;H->Elements[i/2]->Weight>item->Weight;i/=2)
H->Elements[i]=H->Elements[i/2];//向下過濾結點
//哨兵的作用就是避免插入的值比Elements[0]還小
H->Elements[i]=item;//將item插入,執行速度比交換快
//時間複雜性是O(logN)
};
//判斷最小堆是否為空
int IsEmpty(MinHeap H){
return(H->Size==0);
};
//從堆中刪除一個元素
ElementType DeleteMin(MinHeap H){//從最小堆H中取出鍵值最小的元素,並刪除一個結點
int Parent,Child;
ElementType MinItem,temp;
if(IsEmpty(H)){
printf("最小堆已為空\n");
return NULL;
}
MinItem=H->Elements[1];//取出根節點(最小值)
//用最小堆中的最後一個元素從根節點開始向上過濾下層結點
temp=H->Elements[H->Size--];
for(Parent=1;Parent*2<=H->Size;Parent=Child){
Child=Parent*2;
if((Child!=H->Size)&&(H->Elements[Child]->Weight>H->Elements[Child+1]->Weight))
Child++;//Child指向左右子結點中較小的
if(temp->Weight<=H->Elements[Child]->Weight)break;
else//移動temp到下一層
H->Elements[Parent]=H->Elements[Child];
}
H->Elements[Parent]=temp;
return MinItem;
}
/*----------- 建造最小堆 -----------*/
void PercDown( MinHeap H, int p )
{ /* 下濾:將H中以H->Data[p]為根的子堆調整為最小堆 */
int Parent, Child;
ElementType X= H->Elements[p]; /* 取出根結點存放的值 */
for( Parent=p; Parent*2<=H->Size; Parent=Child ) {
Child = Parent * 2;
if( (Child!=H->Size) && (H->Elements[Child]->Weight>H->Elements[Child+1]->Weight) )
Child++; /* Child指向左右子結點的較小者 */
if( X->Weight <= H->Elements[Child]->Weight ) break; /* 找到了合適位置 */
else /* 下濾X */
H->Elements[Parent] = H->Elements[Child];
}
H->Elements[Parent] = X;
}
void BuildHeap( MinHeap H )
{ /* 調整H->Data[]中的元素,使滿足最小堆的有序性 */
/* 這裡假設所有H->Size個元素已經存在H->Data[]中 */
int i;
/* 從最後一個結點的父節點開始,到根結點1 */
for( i = H->Size/2; i>0; i-- )
PercDown( H, i );
}
//列印堆中元素
void Print(MinHeap H){
printf("H中的元素為:\n");
for(int i=1;i<=H->Size;i++)
printf("%d ",H->Elements[i]->Weight);
printf("\n");
}
//建立Huffman樹
HuffmanTree Huffman(MinHeap H){
//假設H->Size個權值已經存在H->Elements[]->Weight裡
int i;HuffmanTree T;
BuildHeap(H);//將堆調整為最小堆
int len=H->Size;
for(i=1;i<len;i++){//做H->Size-1次合併
T=(HuffmanTree)malloc(sizeof(struct TreeNode));//建立新結點
T->Left=DeleteMin(H);
T->Right=DeleteMin(H);
T->Weight=T->Left->Weight+T->Right->Weight;
Insert(H,T);
}
T=DeleteMin(H);
return T;
};
//遍歷樹
void preOrder(HuffmanTree t) //先序遍歷
{
if(t)
{
printf("%d ",t->Weight);
preOrder(t->Left);
preOrder(t->Right);
}
}
void intOrder(HuffmanTree t) //中序遍歷
{
if(t)
{
intOrder(t->Left);
printf("%d ",t->Weight);
intOrder(t->Right);
}
}
void postOrder(HuffmanTree t) //後序遍歷
{
if(t)
{
postOrder(t->Left);
postOrder(t->Right);
printf("%d ",t->Weight);
}
}
重點有這麼兩個地方
MinHeap Create(int MinSize){
MinHeap H=(MinHeap)malloc(sizeof(struct HeapStruct));
H->Elements=(ElementType *)malloc((MinSize+1)*sizeof(ElementType));//從小標為1的地方開始存放
//for(int i=0;i<=MinSize;i++)
//H->Elements[i]=(HuffmanTree)malloc(sizeof(TreeNode));
for(int i=0;i<=MinSize;i++)
{
H->Elements[i]=(ElementType )malloc(sizeof(ElementType));//從小標為1的地方開始存放
H->Elements[i]->Weight=0;//定義“哨兵”為大於堆中所有可能元素的值,便於以後更快操作
H->Elements[i]->Left=NULL;
H->Elements[i]->Right=NULL;
}
H->Size=0;
H->Capacity=MinSize;
H->Elements[0]->Weight=MinData;//定義“哨兵”為大於堆中所有可能元素的值,便於以後更快操作
return H;
//時間複雜性是O(logN)
};
一個是這裡建立時的malloc竟然有三次。。還是請同學幫我解決的
另外一個是下面Huffman樹的生成函式
HuffmanTree Huffman(MinHeap H){
//假設H->Size個權值已經存在H->Elements[]->Weight裡
int i;HuffmanTree T;
BuildHeap(H);//將堆調整為最小堆
int len=H->Size;
for(i=1;i<len;i++){//做H->Size-1次合併
T=(HuffmanTree)malloc(sizeof(struct TreeNode));//建立新結點
T->Left=DeleteMin(H);
T->Right=DeleteMin(H);
T->Weight=T->Left->Weight+T->Right->Weight;
Insert(H,T);
}
T=DeleteMin(H);
return T;
};
下面是實現效果
最後附上一段小程式碼
//整數轉化為樹之後再插入
void Insertint(MinHeap &H,int item){
int i;
if(IsFull(H)){
printf("最小堆已滿\n");
return;
}
i=++H->Size;//先Size自加1再賦給i,i指向插入後堆中的最後一個元素
ElementType E1=(ElementType )malloc(sizeof(ElementType));
E1->Right=E1->Left=NULL;
E1->Weight=item;
for(;H->Elements[i/2]->Weight>E1->Weight;i/=2)
H->Elements[i]=H->Elements[i/2];//向下過濾結點
//哨兵的作用就是避免插入的值比Elements[0]還小
H->Elements[i]=E1;//將item插入,執行速度比交換快
//時間複雜性是O(logN)
};
這樣就可以呼叫
MinHeap H= Create(15);
Insertint(H,55);
Insertint(H,79);
Insertint(H,66);
Insertint(H,83);
Insertint(H,72);
Insertint(H,30);
Insertint(H,49);
Insertint(H,91);
Insertint(H,87);
Insertint(H,43);
Insertint(H,9);
Insertint(H,38);
Print(H);
DeleteMin(H);
DeleteMin(H);
Print(H);
等語句,哦耶終於完成啦^^