哈夫曼树的建立
一、实验目的
- 理解哈夫曼树及其应用。
- 掌握生成哈夫曼树的算法。
二、实验原理
哈夫曼树,即最优树,是带权路径长度最短的树。有着广泛的应用。在解决某些判定问题上,及字符编码上,有着重要的价值。
构造一棵哈夫曼树,哈夫曼最早给出了算法,称为哈夫曼算法:
(1)根据给定的N个权值 W1,W2,W3,……,Wn ,构成N棵二叉树的集合F= T1,T2,T3,……,Tn ,其中每棵二叉树T1只有一个带权为Wi的根结点,其左右子树均空。
(2)在 F中选出两棵根结点权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的权值为其左右子树上的根结点的权值之和。
(3)在F中删除这两棵树,同时将新得到的加到F之中。重复(2)和(3),直至F中只剩一个为止。
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define MAXSIZE 100
#include<stdio.h>
#include<malloc.h>
#define MAXSIZE 100
typedef struct HTnode
{
int weight;
int parent,lchild,rchild;
}STKzone;
typedef STKzone *STK,*stack;
typedef char **huffman;
STK HT,tree,tree1;
int a[20][20],count;
STK creat(){
int ye,number,quanzhi,shu1,shu2,shu3,i,jie,biao=0,min1=0,min2=1,j,k=0;
//ye代表叶子的数目nnumber代表 需要开辟多少个空间quanzhi需要输入的叶子的权值
//shu1代表第一个最小的数shu2代表第二个最小的数shu3代表shu1+shu2的和
//min1,min2代表第一个最小数的下标,第二个最小数的下标
printf("\n赫夫曼树的建立:\n");
printf("请输入权值(叶子)数目:");
scanf("%d",&ye);
while(ye<1){
printf("\n输入错误,请重新输入权值数目:");
scanf("%d",&ye);
printf("\n");
}
if(ye==1){
printf("\n只有一个权值,无须建立赫夫曼树!\n");
}else{
number=ye*2-1;//需要开辟空间的数目
tree=(struct HTnode *)malloc(number*sizeof(struct HTnode));//开辟空间
printf("\n 输入 %d权值(=>0),建立赫夫曼树:\n",ye);
count=ye;//编码用到
for(i=0;i<ye;i++){
scanf("%d",&quanzhi);//输入权植
while(quanzhi<=0){//全职小于0,重新输入
printf("\n 权值错(=>0),重新输入此权值:\n");
scanf("%d",&quanzhi);
}
(tree+i)->weight=quanzhi;//给叶子的权值赋值
(tree+i)->parent=0;
(tree+i)->lchild=0;
(tree+i)->rchild=0;
biao=i;//biao 用来记当前链表中用了几个节点
}
}
int wo1,wo2;
while(true){//while start1
for(i=0;i<=biao;i++)//找第一个最小的数
{
if(((tree+i)->parent)==0){//如果其父不为0,说明该节点已有父节点,则跳过该节点
if((tree+min1)->weight>(tree+i)->weight){
min1=i;//把最小的数的下表给min1
}
}
}
if(min1==min2){//判断min1和min2是不是同一个位置的数
(tree+min1)->parent=-1;//如果min1和min2是同一个数,则把min1的父等于-1
for(i=0;i<=biao;i++)//寻找第二个最小的数
{
if((tree+i)->parent==0){
min2=i;
break;
}
}
}else{//如果而这下标不想等的话,执行下面代码
for(i=0;i<=biao;i++)
{
if((tree+i)->parent==0){
if((tree+min2)->weight>(tree+i)->weight&&min1!=i){
min2=i;
}
}
}
}
biao=biao+1;//因为链表中多了一个数据所以要+1
shu1=0;shu2=0;//为shu1和shu2初始化
wo1=0;wo2=0;//标志位,用来判断shu1和shu2书否被赋值
for(i=0;i<=biao;i++){
if(min1==i){
shu1=(tree+min1)->weight;//给shu1赋值
wo1=1;
}
if(min2==i&&min1!=min2){
shu2=(tree+min2)->weight;//给shu2赋值
wo2=1;
}
if(wo1==1&&wo2==1){
shu3=shu1+shu2;
(tree+biao)->weight=shu3;//该节点就是两个最小节点的父节点
(tree+biao)->lchild=min1;//把最小值的下表给父节点的lchild
(tree+biao)->rchild=min2;
(tree+biao)->parent=0;//由于父节点现在还没有父节点,所以暂时=0
(tree+min1)->parent=biao;
(tree+min2)->parent=biao;//把父节点的下标给孩子
break;
}
}
min1=0;
min2=1;
for(i=0;i<=biao;i++)//为了给min1初始化
{
if((tree+i)->parent==0){
min1=i;
break;
}
}
for(i=0;i<=biao;i++)//为了给min2初始化
{
if((tree+i)->parent==0&&min1!=i){
min2=i;
}
}
if(biao==number-1){//如果链表满了就跳出循环 ,结束
break;
}
}//while end1
return tree;
}
void huffmancode(){
int i=0,start=0,c,f;
huffman HC;
char *cd;
for(i=0;i<2*count-1;i++){
printf("----%d---%d---%d---%d--\n",(tree+i)->parent,(tree+i)->lchild,(tree+i)->rchild,(tree+i)->weight);
}
HC=(huffman)malloc(count*sizeof(char *));
cd=(char *)malloc(count*sizeof(char));
cd[count-1]='\0';
for(i=0;i<count;++i){//因为从叶子节点开始查找,所以循环的次数就等于叶子数
start=count-1;
for(c=i,f=(tree+i)->parent;f!=0;c=f,f=(tree+f)->parent)//循环结束的条件是f=0;
if((tree+f)->lchild==c)
cd[--start]='0';
else
cd[--start]='1';
HC[i]=(char *)malloc((count-start)*sizeof(char));//开辟一个空间哈夫曼编码那么长的空间
strcpy(HC[i],&cd[start]);//把cd里面的数据给hc
}
printf("\n对应的二进制赫夫曼编码为:\n");
for(i=0;i<count;++i){
printf("%s",*(HC+i));
printf(" ");
}
}
int main()
{
tree1=creat();
huffmancode();
return 0;
}/*main_end*/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~