/*
*創建哈弗曼樹
*創建樹
*每次遍歷最小的兩個節點
*譯碼
*遍歷樹(解碼的過程)
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define n 4//樹的葉子節點數
#define m (2*n-1)//樹的節點總數
#define MAXVALUE 1000 //權重最大值
typedef struct htreetype
{
int weight;//權重
int parent;//雙親節點
int Rchild;
int Lchild;//左右孩子節點
char name[5];//節點名稱
}HtreeType;//樹節點的結構體
typedef struct hcodetype
{
char bit[n];//用於存放編碼的數組
char name[5];//儲存節點的名稱
int start;//編碼開始的下標
}HcodeType;//編碼節點的結構體
void select_htree(HtreeType tree[],int position,int *node1,int *node2);//選擇最小的兩個
void htree_code(HtreeType tree[],HcodeType code[]);//譯碼的過程
void creat_htree(HtreeType tree[]);//哈夫曼樹的創建
void show_htree(HcodeType code[] );//輸出
int main()
{
HtreeType tree[m];
HcodeType code[n];
htree_code(tree,code);
show_htree(code);
return 0;
}
void creat_htree(HtreeType tree[])//哈夫曼樹的創建
{
/*
*初始化樹的節點
*給樹的葉子節點賦值
*利用選擇函數進行分支節點的創建
*/
int node1,node2;
char name[5];//臨時字符串
int now_weight;//臨時變量
int i,j,k;
node1=node2=0;
for(i=0;i<m;i++)
{
tree[i].weight=0;
tree[i].Rchild=-1;
tree[i].Lchild=-1;
tree[i].parent=-1;
}
printf("一共有%d個葉子節點\n",n);
for(j=0;j<n;j++)
{
printf("請輸入節點的數據:");
scanf("%s",name);
printf("請輸入葉子節點的權重:");
scanf("%d",&now_weight);
tree[j].weight=now_weight;
strcpy(tree[j].name,name);
}
for(k=n;k<m;k++)
{
select_htree(tree,k,&node1,&node2);
tree[node1].parent=k;
tree[node2].parent=k;
tree[k].Rchild=node2;
tree[k].Lchild=node1;
tree[k].weight=tree[node1].weight+tree[node2].weight;
}
}
void select_htree(HtreeType tree[],int position,int *node1,int *node2)
//選擇最小的兩個
{
/*
*以position爲起始點進行尋找最小的兩個節點的下標
*每次調用之後返回
*/
int i;
int min1,min2;
min1=min2=MAXVALUE;
*node1=*node2=0;
for(i=0;i<position;i++)
{
if(tree[i].parent==-1&&tree[i].weight<min1)
{
min2=min1;
min1=tree[i].weight;
*node2=*node1;
*node1=i;
}
else if(tree[i].parent==-1&&tree[i].weight<min2)
{
min2=tree[i].weight;
*node2=i;
}
}
}
void htree_code(HtreeType tree[],HcodeType code[] )//譯碼的過程
{
HcodeType cd;//臨時儲存節點的編碼
int i;//循環變量
creat_htree(tree);
int parent_position,now_position;
for(i=0;i<n;i++)
{
cd.start=n;
strcpy(cd.name,tree[i].name);
now_position=i;
parent_position=tree[i].parent;
while(parent_position!=-1)//從下往上遍歷指點根節點結束
{
cd.start--;//作爲數組的循環下標
if(tree[parent_position].Lchild==now_position)
cd.bit[cd.start]='0';
else
{
cd.bit[cd.start]='1';
}
now_position=parent_position;
parent_position=tree[now_position].parent;
}
code[i]=cd;//傳遞編碼到code數組去
}
}
void show_htree(HcodeType code[] )//輸出
{
int i,j;
for(i=0;i<n;i++)
{
printf("%s ",code[i].name);
for(j=code[i].start;j<n;j++)
printf("%c",code[i].bit[j]);
printf("\n");
}
}