二叉树的经典应用——哈夫曼树
1、问题描述:给定n个字符的权值数组w,根据哈夫曼编码与译码规则,实现一个哈夫曼编/译码系统。
2、利用顺序表存储及实现Huffman树,编码结果直接输出,要求利用栈,引入以前所写的栈实现函数。
算法逻辑:
①首先,定义一个存储哈夫曼树的数组HT[MAX],使用顺序存储结构;定义一个整型数n,用于控制输入的字符和对应的权值的数量;使用getchar()吸收回车;
②定义一个CreatHuffmanTree函数,用于构建哈夫曼树;并输出哈夫曼树每个节点的信息;定义一个Select函数,用于选择两个权值最小的节点,帮助构建哈夫曼树;
③构建完哈夫曼树之后,定义一个CreatHuffmanCode函数,用于创建哈夫曼编码;使用栈stack存储和输出每个字符对应的哈夫曼编码;
④定义一个整型数nn,用于控制输入的要译码的字符数量;使用getchar()吸收回车;
⑤定义一个TranslateHuffmanCode函数,用于译码;并输出哈夫曼编码对应的字符;
⑥程序结束。
源代码:
HuffmanTree.cpp文件:
#include<stdio.h>
#include<string.h>
#define MAX 100
typedef char ElemType;
#include"sqstack.h" //用栈把哈夫曼编码输出
typedef struct {
ElemType data; //data存储的数据为字符型
int weight; //weight是权值
int lchild,rchild,parent; //左孩子,右孩子,双亲节点
} HuffmanTree;
//选择两个权值最小的节点,并将他们的位置存在s1和s2中
void Select(HuffmanTree *HT,int n,int *s1,int *s2){
int min1=n,min2=n; //min1是权值最小,min2是权值次小,初始化为n
int i;
for (i=1;i<=n;i++){
if (HT[i].parent==-1){ //首先判断该节点是否已经被连接过
if (HT[i].weight<=HT[min1].weight){ //比较权值
min1=i;
}
}
}
for (i=1;i<=n;i++){
//剔除min1,并判断该节点是否已经被连接过
if (HT[i].parent==-1 && i!=min1){
if (HT[i].weight<=HT[min2].weight){ //比较权值
min2=i;
}
}
}
(*s1)=min1;//利用指针将节点的位置传回去
(*s2)=min2;
}
int m; //m为构造哈夫曼树需要的所有节点数
void CreatHuffmanTree(HuffmanTree *HT,int n){ //构造哈夫曼树
if (n<=1) return ; //若只有一个节点,函数结束
int i;
m=2*n-1; //原节点有n个,需再新增n-1个
for (i=1;i<=m;i++){
HT[i].data='*'; //将所有节点初始化
HT[i].lchild=-1;
HT[i].rchild=-1;
HT[i].parent=-1;
}
for (i=1;i<=n;i++){ //输入给定的数据
scanf("%c",&HT[i].data); //输入字符
getchar(); //吸收空格
scanf("%d",&HT[i].weight); //输入对应的权值
getchar(); //吸收回车
}
int s1,s2; //用来存Select函数的选择结果
for (i=n+1;i<=m;i++){ //构造哈夫曼树需创建新节点,从n+1开始
Select(HT,i-1,&s1,&s2); //从已创建的节点中选出两个权值最小的
HT[s1].parent=i; //将这两个节点连接到新节点
HT[s2].parent=i;
HT[i].lchild=s1; //新节点的左孩子为权值最小的节点
HT[i].rchild=s2; //右孩子为权值次小的节点
HT[i].weight=HT[s1].weight+HT[s2].weight;//新节点的权值为两个节点之和
}
printf("\n哈夫曼树:\n");
printf("(从左到右分别为:字符,位置,权值,左孩子,右孩子,双亲节点)\n");
for (i=1;i<=m;i++){ //将构造好的哈夫曼树输出
printf("%c,%d,%d,%d,%d,%d\n",HT[i].data,i,
HT[i].weight,HT[i].lchild,HT[i].rchild,HT[i].parent);
}
printf("\n");
}
void CreatHuffmanCode(HuffmanTree *HT,int n){ //创建哈夫曼编码
Stack S; //定义顺序栈S用于存储和输出哈夫曼编码
InitStack(&S); //初始化栈
int i,p,l;
for (i=1;i<=n;i++){ //从第一个叶子节点开始编码
p=HT[i].parent; //p用于存放当前叶子节点的双亲节点的位置
l=i; //l存放当前叶子节点位置
while (p!=-1){ //p不为根节点就执行循环体,将节点往前推
//判断当前叶子节点的双亲节点p的左孩子是不是当前叶子节点l
if (HT[p].lchild==l){
Push(&S,'0'); //若是,将字符0入栈
}else {
Push(&S,'1'); //若不是,则为右孩子,将字符1入栈
}
l=p; //往前一个推
p=HT[p].parent;
}
printf("%c的哈夫曼编码:",HT[i].data);
char ch; //存放出栈的字符
while (!StackEmpty(S)){ //将栈中的所有01字符输出
Pop(&S,&ch);
printf("%c,",ch);
}
printf("\n");
}
}
//哈夫曼译码
void TranslateHuffmanCode(HuffmanTree *HT,int nn){
char c[MAX]; //存放要译码的字符串
int i;
for (i=1;i<=nn;i++){
scanf("%c",&c[i]); //输入要译码的字符串
}
getchar();
int q=m; //p存放根节点的位置
printf("译码结果:\n");
for (i=1;i<=nn;i++){
if (c[i]=='0'){ //0往左边走
q=HT[q].lchild;
if (HT[q].lchild==-1){ //若左孩子为-1是叶子节点,即找到
printf("%c,",HT[q].data);
q=m; //从根节点重新开始
}
}
else if (c[i]=='1'){ //1往右边走
q=HT[q].rchild;
if (HT[q].lchild==-1){ //若左孩子为-1是叶子节点,即找到
printf("%c,",HT[q].data);
q=m; //从根节点重新开始
}
}
else { //非0和1的字符忽略
continue;
}
}
}
int main(){
HuffmanTree HT[MAX]; //创建存储哈夫曼树的数组
int n;
printf("请输入要编码的字符数量n\n");
scanf("%d",&n);
getchar(); //吸收回车
printf("请输入每个字符和对应的权值n\n");
CreatHuffmanTree(HT,n); //构建哈夫曼树
CreatHuffmanCode(HT,n); //创建哈夫曼编码
int nn;
printf("\n请输入要译码的字符数量nn\n");
scanf("%d",&nn);
getchar(); //吸收回车
printf("请输入要译码的字符\n");
TranslateHuffmanCode(HT,nn); //译码
printf("\n\n程序结束");
return 0;
}
sqstack.h文件:
#define MAXSIZE 100
typedef struct {
ElemType data[MAXSIZE];//存放数据元素 数据元素类型不同的应用有不同的类型
int top; //栈顶指针
} Stack;
//初始化
//功能 空表 last=-1
//单向传递
void InitStack(Stack *S){
S->top = -1;
}
//在线性表中第i个位置插入元素e
int Push(Stack *S,ElemType e)
{
if(S->top+1==MAXSIZE){
printf("stack overflow!\n");
return 0;
}
S->top++;
S->data[S->top]=e;
}
ElemType GetTop(Stack S)
{
return S.data[S.top];
}
int StackEmpty(Stack S)
{
if(S.top==-1)
return 1;
else
return 0;
}
int Pop(Stack *S,ElemType *e)
{
if(StackEmpty(*S))
return 0;
*e = S->data[S->top];
S->top--;
return 1;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具