/************************************************************************ * * 文件名:HFtree.c * * 文件描述:本程序給出哈夫曼樹的鏈式構造法和哈夫曼的編碼 * 在turboc 2.0 調試通過,在其他編譯環境下請把 * gotoxy和getch兩個函數重寫 * * 創建人: 顏清國 2006年5月4日 * 說明: * 採用鏈式存儲結構構造哈夫曼樹,可以很方便的將樹的各種操作加 * 到哈夫曼樹上來,包括其編碼 ************************************************************************/ #include "stdio.h" #include "stdlib.h" #include "conio.h" #define LEN sizeof(HFtree) /*HFtree結構體大小*/ /*哈夫曼樹結構體*/ typedef struct tagHFtree { char data; /*結點數據,以後用到*/ double weight; /*結點的權重*/ struct tagHFtree* parent; /*雙親結點*/ struct tagHFtree* lchild; /*左孩子*/ struct tagHFtree* rchild; /*右孩子*/ struct tagHFtree* next; /*指向下一個結點*/ }HFtree; /*哈夫曼編碼結構體*/ struct tagHFcode { char data; /*結點數據*/ double weight; /*結點的權重*/ int code[20]; /*存放編碼*/ int top; /*編碼的位數*/ }; /*********************************************** 創建哈夫曼樹核心部分 ************************************************/ void Create(HFtree**head) { HFtree*lp,*temp,*lchild,*rchild; while((*head)->next->next!=NULL) { lchild=rchild=(*head); /*每次從頭開始查找,這裏(*head)的weight沒用,*/ /*剛好用來放左右孩子*/ temp=(*head)->next; /*最初的的weight*/ lchild->weight=rchild->weight=3.14e+38; /*重新找時每次將左右孩子的weight置爲最大*/ lp=(HFtree*)malloc(LEN); lp->parent=NULL; while(temp!=NULL) /*查找最小的作爲左孩子*/ { if(lchild->weight > temp->weight) { lchild=temp; } temp=temp->next; } temp=(*head)->next; /*重新定位到(*head)->next*/ while(temp!=NULL) /*查找次小的作爲右孩子*/ { /*注意這裏不要用temp->weight!=lchild->weigh*/ if(rchild->weight > temp->weight && temp!=lchild) { rchild=temp; } temp=temp->next; } lp->lchild=lchild; /*對LP及其左右孩子附值*/ lp->rchild=rchild; lchild->parent = rchild->parent =lp; lp->weight=lchild->weight + rchild->weight; /*將左右孩子的權值相加*/ lp->next=(*head)->next; /*將LP插到表頭*/ (*head)->next=lp; /*每次讓(*head)->next指向新加進來的結點*/ temp=lp; /*將lp和temp兩個指針重新定位,用來遍歷鏈表*/ lp=lp->next; while(lp!=NULL) /*將左右孩子從待創建的鏈表系列中刪除*/ { if(lp==lchild || lp==rchild) { temp->next=lp->next; lp->next=NULL; } else temp=lp; lp=temp->next; } } } /*********************************************** 創建哈夫曼樹 ************************************************/ void CreateHFtree(double nodewei[],int n,HFtree**head) { int i=0; HFtree*lp=(HFtree*)malloc(LEN),*rear; (*head)=(HFtree*)malloc(LEN); (*head)->parent=NULL; (*head)->next=rear=lp; /*head頭結點,保證指向剩餘的結點鏈*/ lp->parent=lp->lchild=lp->rchild=lp->next=NULL; while(iweight=nodewei[i++]; rear->next=lp; /*第一次REAR指向自身*/ rear=lp; lp=(HFtree*)malloc(LEN); lp->parent=lp->lchild=lp->rchild=lp->next=NULL; } free(lp); /*釋放最後一個結點*/ Create(head); /*創建一棵樹,樹的頭結點爲(*HEAD)->next*/ } /************************************************* 由先序遍歷求出哈夫曼樹求出哈夫曼編碼 **************************************************/ void HFcoding(HFtree*root,HFtree*temp,struct tagHFcode HFcode[],int*leaftop) { if(root!=NULL) { if(root->lchild==NULL && root->rchild==NULL) /*是葉子結點,求得編碼*/ { temp=root; HFcode[(*leaftop)].top=0; HFcode[(*leaftop)].weight=root->weight; HFcode[(*leaftop)].data=root->data; while(temp->parent!=NULL) { if(temp->parent->lchild==temp) HFcode[(*leaftop)].code[HFcode[(*leaftop)].top]=0; else HFcode[(*leaftop)].code[HFcode[(*leaftop)].top]=1; HFcode[(*leaftop)].top++; temp=temp->parent; } (*leaftop)++; } HFcoding(root->lchild,temp,HFcode,leaftop); HFcoding(root->rchild,temp,HFcode,leaftop); } } /*********************************************** 輸出求得的哈夫曼編碼 ************************************************/ void OutCoding(struct tagHFcode HFcode[],int leaftop) { int i=0,j=0;
for(;i<leaftop;i++)
{
printf("%.1f :",HFcode[i].weight);
j=HFcode[i].top-1;
while(j>=0 )
{
printf("%d",HFcode[i].code[j]);
j--;
}
printf("/n");
}
} /******************************************** 用括號表示法輸出樹 **********************************************/ void OutTree(HFtree *root) { if(root != NULL) { printf("%.1f",root->weight); /*先輸出根結點*/ if(root->lchild != NULL || root->rchild != NULL) { printf("("); OutTree(root->lchild); /*處理左子樹*/ if(root->rchild != NULL) { printf(","); } OutTree(root->rchild); /*處理右子樹*/ printf(")"); } } } /***************************************************************** 用樹形表示法輸出樹 ******************************************************************/ void DispTree(HFtree *root,int x,int y,int n) /*n用來控制第一層樹的高度*/ { int i=0; if(root !=NULL) { gotoxy(x,y); /*到相應結點輸出*/ printf("%.1f",root->weight); if(root->lchild != NULL) /*處理左子樹,這裏只有第一次N爲可變的,*/ { i=1; /*爲的是能夠輸出整棵樹,而不會被覆蓋,*/ while(ilchild,x-n,y+n,2); /*遞歸處理左子樹*/ } if(root->rchild != NULL) { i=1; while(irchild,x+n,y+n,2); /*遞歸處理右子樹*/ } } } /***************************************************************** 主函數入口 ******************************************************************/ void main() { double nodewei[20]; struct tagHFcode HFcode[20]; int leaftop=0,i=0; HFtree*temp=NULL; HFtree*head; textbackground(1); textcolor(2); clrscr(); printf("the HFtree and HFcoding demo/r/n"); printf("Input the leafnode weight:"); scanf("%lf",&nodewei[i]); while(nodewei[i++]!=0.0)/*接收數據,以0結尾*/ scanf("%lf",&nodewei[i]); CreateHFtree(nodewei,i-1,&head); /*根據接收的數據創建*/ printf("HFtree:"); OutTree(head->next); /*輸出哈夫曼樹括號表示法*/ HFcoding(head->next,temp,HFcode,&leaftop); /*根據哈夫曼樹,求出哈夫曼編碼*/ printf("/nthe HFcoding is:/n"); OutCoding(HFcode,leaftop); /*輸出哈夫曼編碼*/ DispTree(head->next,30,10,6); /*用樹形表示法輸出樹*/ getch(); }