<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
/************************************************************************** 文件名: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();}