#include <stdio.h>
#include <malloc.h>
#define N 100 //叶子结点数
#define M 2*N-1 //树中结点总数
#define MAXN 0x7fffffff
typedef char ElemType;
typedef struct Node
{
ElemType data;
Node *Lchild,*Rchild;
} BiTNode,*BiTree;
typedef struct//哈夫曼树的节点结构类型
{
char data; //结点值
double weight; //权重
int parent; //双亲结点
int lchild; //左孩子结点
int rchild; //右孩子结点
} HTNode;
typedef struct//每个节点哈夫曼编码的结构类型
{
char cd[N]; //存放哈夫曼码
int start;
} HCode;
typedef struct node
{
BiTree data;
node *next;
} Node1,*LinkQueueNode;
typedef struct
{
LinkQueueNode front; //队头指针
LinkQueueNode rear; //队尾指针
} LinkQueue;
BiTree CreateBiTree();//建立二叉树
int Leaf(BiTree T);//分治法统计叶子节点数目
bool LayerOrder(BiTree bt);//层次遍历二叉树
bool InitQueue(LinkQueue *Q);//链队列初始化
bool EnterQueue(LinkQueue *Q,BiTree x);//入队,将数据元素x插入到队列Q中
bool DeleteQueue(LinkQueue *Q,BiTree *x);//出队,将队列Q的队头元素出队并保存到x所指的存储空间中
bool IsEmpty(LinkQueue *Q);//判断链队列是否为空
void PreOrder(BiTree T);//先序
void InOrder(BiTree T);//中序
void PostOrder(BiTree T);//后序
void CreateHT(HTNode ht[],int n);//构造哈夫曼树
void CreateHCode(HTNode ht[],HCode hcd[],int n);//实现哈夫曼编码
void DispHCode(HTNode ht[],HCode hcd[],int n);//输出哈夫曼编码
int main(void)
{
int count;
int n=7;
char str[8]= {'a', 'b', 'c', 'd', 'e', 'f', 'g'};
double fnum[7]= {0.40,0.30,0.15,0.05,0.04,0.03,0.03};
HTNode ht[M];
HCode hcd[N];
for (int i=0; i<n; i++)
{
ht[i].data=str[i];
ht[i].weight=fnum[i];
}
BiTree root=CreateBiTree();
CreateHT(ht,n);
CreateHCode(ht,hcd,n);
printf("先序遍历二叉树:\n");
PreOrder(root);//先序
printf("\n");
printf("中序遍历二叉树:\n");
InOrder(root);//中序
printf("\n");
printf("后序遍历二叉树:\n");
PostOrder(root);//后序
printf("\n");
printf("层次遍历二叉树:\n");
LayerOrder(root);
printf("\n");
count=Leaf(root);
printf("叶子节点的数目为:\n");
printf("%d\n",count);
DispHCode(ht,hcd,n);
printf("\n");
return 0;
}
BiTree CreateBiTree()//建立二叉树
{
ElemType x;
BiTree T;
scanf("%c",&x);
if(x=='#')
T=NULL;
else
{
T=(BiTree)malloc(sizeof(BiTNode));
T->data=x;
T->Lchild=CreateBiTree();
T->Rchild=CreateBiTree();
}
return T;
}
bool LayerOrder(BiTree bt)//层次遍历二叉树
{
LinkQueue Q;
BiTree p;
InitQueue(&Q);
if(bt==NULL)
return false;
EnterQueue(&Q,bt);
while(!IsEmpty(&Q))
{
DeleteQueue(&Q,&p);
printf("%c ",p->data);
if(p->Lchild)
EnterQueue(&Q,p->Lchild);
if(p->Rchild)
EnterQueue(&Q,p->Rchild);
}
return true;
}
bool InitQueue(LinkQueue *Q)//链队列初始化
{
Q->front=(LinkQueueNode)malloc(sizeof(Node));
if(Q->front!=NULL)
{
Q->rear=Q->front;
Q->front->next=NULL;
return true;
}
else
return false;//溢出
}
bool EnterQueue(LinkQueue *Q,BiTree x)//入队,将数据元素x插入到队列Q中
{
LinkQueueNode NewNode;
NewNode=(LinkQueueNode)malloc(sizeof(Node));
if(NewNode!=NULL)
{
NewNode->data=x;
NewNode->next=NULL;
Q->rear->next=NewNode;
Q->rear=NewNode;
}
else
return false;//溢出
}
bool DeleteQueue(LinkQueue *Q,BiTree *x)//出队,将队列Q的队头元素出队并保存到x所指的存储空间中
{
LinkQueueNode p;
if(Q->front==Q->rear)//表示队列已空
return false;
p=Q->front->next;
Q->front->next=p->next;//队头元素p出队
if(Q->rear==p)//如果队中只有一个元素p,则p出队后成为空队
Q->rear=Q->front;
*x=p->data;
free(p);//释放存储空间
return true;
}
bool IsEmpty(LinkQueue *Q)//判断链队列是否为空
{
return Q->front == Q->rear;
}
int Leaf(BiTree T)//分治法统计叶子节点数目
{
int count;
if(T==NULL)
count=0;
else if(T->Lchild==NULL&&T->Rchild==NULL)
count=1;
else
count=Leaf(T->Lchild)+Leaf(T->Rchild);
return count;
}
void PreOrder(BiTree T)//先序
{
if(T!=NULL)
{
printf("%c ",T->data);
PreOrder(T->Lchild);
PreOrder(T->Rchild);
}
}
void InOrder(BiTree T)//中序
{
if(T!=NULL)
{
InOrder(T->Lchild);
printf("%c ",T->data);
InOrder(T->Rchild);
}
}
void PostOrder(BiTree T)//后序
{
if(T!=NULL)
{
PostOrder(T->Lchild);
PostOrder(T->Rchild);
printf("%c ",T->data);
}
}
void CreateHT(HTNode ht[],int n)//构造哈夫曼树
{
int i,k,lnode,rnode;
double min1,min2;
for (i=0; i<2*n-1; i++) //所有结点的相关域置初值-1
ht[i].parent=ht[i].lchild=ht[i].rchild=-1;
for (i=n; i<2*n-1; i++) //构造哈夫曼树
{
min1=min2=MAXN; //lnode和rnode为最小权重的两个结点位置
lnode=rnode=-1;
for (k=0; k<=i-1; k++)
{
if (ht[k].parent==-1) //只在尚未构造二叉树的结点中查找
{
if (ht[k].weight<min1)
{
min2=min1;
rnode=lnode;
min1=ht[k].weight;
lnode=k;
}
else if (ht[k].weight<min2)
{
min2=ht[k].weight;
rnode=k;
}
}
}
ht[i].weight=ht[lnode].weight+ht[rnode].weight;
ht[i].lchild=lnode;
ht[i].rchild=rnode;
ht[lnode].parent=i;
ht[rnode].parent=i;
}
}
void CreateHCode(HTNode ht[],HCode hcd[],int n)//实现哈夫曼编码
{
int i,f,c;
HCode hc;
for (i=0; i<n; i++) //根据哈夫曼树求哈夫曼编码
{
hc.start=n;
c=i;
f=ht[i].parent;
while (f!=-1) //循序直到树根结点
{
if (ht[f].lchild==c) //处理左孩子结点
hc.cd[hc.start--]='0';
else //处理右孩子结点
hc.cd[hc.start--]='1';
c=f;
f=ht[f].parent;
}
hc.start++; //start指向哈夫曼编码最开始字符
hcd[i]=hc;
}
}
void DispHCode(HTNode ht[],HCode hcd[],int n)//输出哈夫曼编码
{
int i,k;
double sum=0,m=0;
int j;
printf(" 输出哈夫曼编码:\n"); //输出哈夫曼编码
for (i=0; i<n; i++)
{
j=0;
printf(" %c:\t",ht[i].data);
for (k=hcd[i].start; k<=n; k++)
{
printf("%c",hcd[i].cd[k]);
j++;
}
m+=ht[i].weight;
sum+=ht[i].weight*j;
printf("\n");
}
printf("\n 平均长度=%.2lf\n",1.0*sum/m);
}
二叉树的层次遍历、哈夫曼树及哈夫曼编码的建立
最新推荐文章于 2022-11-23 22:15:41 发布
本文介绍了一种使用C语言实现哈夫曼树的方法,并详细展示了如何通过构造哈夫曼树来获得哈夫曼编码的过程。此外,还提供了层次遍历、先序遍历、中序遍历和后序遍历二叉树的功能。
579

被折叠的 条评论
为什么被折叠?



