实验内容:
1.设置7个字符a~g的权值,以它们为叶子构造哈夫曼树
2. 输出它们的哈夫曼编码。
哈夫曼树:
#include<stdio.h>
#include<stdlib.h>
#include"string.h"
//哈夫曼树
#define MAXLEAF 100 //最多叶子节点数
#define MAXVALUE 100 //最大权值
typedef struct {
int weight;//权值
int parent;//父节点
int lchild;//左孩子
int rchild;//右孩子
}hnodetype;
int n = 7;//叶子节点个数,全局变量
//哈夫曼算法生成哈夫曼树(最优二叉树)
void huffmantree(hnodetype huffnode[MAXLEAF], int n) {
int i = 0, j = 0;
for (i = 0; i < 2 * n - 1; i++) //初始化huffnode数组
{
huffnode[i].weight = 0; huffnode[i].parent = -1;
huffnode[i].lchild = -1; huffnode[i].rchild = -1;
}
for (i = 0; i < n; i++)
scanf_s("%d", &huffnode[i].weight);
//找最小值与次小值
for (i = 0; i < n - 1; i++) //找最小值m1和次小值m2循环 n - 1轮,如5个叶子节点要循环4次,所以是n-1
{
int m1, m2, x1, x2;
m1 = m2 = MAXVALUE;//权值
x1 = x2 = -1;//权值所在的下标
//寻找最小值m1和次小值m2
for (j = 0; j < n + i; j++) {
if (huffnode[j].weight < m1 && huffnode[j].parent == -1) //当前值是j,和m1相比
//加huffnode[j].parent == -1这个条件是为了排除已经有父节点的结点,即已经合并过的结点
//进行合并的时候要选那些没有父节点的结点
{
m2 = m1;
x2 = x1;
m1 = huffnode[j].weight;
x1 = j;
}//如果j<m1,则m1变成当前值j,同时m2变成m1,x1变成j,x2变成x1
else if (huffnode[j].weight < m2 && huffnode[j].parent == -1)
{
m2 = huffnode[j].weight;
x2 = j;
}//与m2相比,就把m2赋值为当前值j即可
}
//选中x1,x2进行合并
huffnode[n + i].weight = m1 + m2;//合并后新节点的下标是n+i,i代表当前第几轮,第一轮i=0,新节点的权值为m1 + m2
huffnode[n + i].lchild = x1; huffnode[n + i].rchild = x2;//对左右孩子进行赋值
huffnode[x1].parent = n + i; huffnode[x2].parent = n + i;//修正下标x1和x2对应的父节点为新节点
}
}
//输出所有节点的权值
void output(hnodetype huffnode[MAXLEAF], int n) {
int i = 0;
for (i = 0; i < 2 * n - 1; i++) {
printf("%d\t", huffnode[i].weight);
}
printf("\n");
}
//求哈夫曼编码:递归做法
void getcode1(hnodetype huffnode[MAXLEAF], int i, char dest[], int len)
//i是根节点的下标,dest[]是编码保存的地方,保存在一个字符串数组,len是长度
{
if (huffnode[i].lchild == -1 && huffnode[i].rchild == -1) {
dest[len] = 0;//字符串结束字符
printf("%-6c%-8d%-10s\n", i + 97, huffnode[i].weight, dest);
return;
}
if (huffnode[i].lchild != -1) {
dest[len] = '0';
getcode1(huffnode, huffnode[i].lchild, dest, len + 1);//()里是参数情况
}//判断左孩子,并对做递归调用
if (huffnode[i].rchild != -1) {
dest[len] = '1';
getcode1(huffnode, huffnode[i].rchild, dest, len + 1);
}
}
//求哈夫曼编码:循环
void getcode2(hnodetype huffnode[MAXLEAF], int n) {
int i = 0;
for (i = 0; i < n; i++) {
int c = i;//第i个,第一个时c=i,i=1
int f = 0;//父节点下标
int j = 0;
int code[MAXLEAF] = { 0 };//编码数组,记录编码
int len = 0;
f = huffnode[c].parent;
while (f >= 0) {//父节点不为-1的时候
//printf("%d,%d\n", huffnode[f].weight, huffnode[f].lchild);
if (huffnode[f].lchild == c)
code[len++] = 0;
else
code[len++] = 1;//记录一下是左孩子还是右孩子
c = f;//把当前结点变成f
f = huffnode[c].parent;//f记成f的下一个
}
//反向输出数组,即编码
printf("%-6c%-8d", i + 97, huffnode[i].weight);
for (j = len - 1; j >= 0; j--)
printf("%d", code[j]);
printf("\n");
}
}
int main(void)
{
int n = 7;
printf("输入a~g的权值:");
hnodetype huffnode[MAXLEAF];
huffmantree(huffnode, n);
printf("所有节点权值:");
output(huffnode, n);
char dest[MAXLEAF] = "";
printf("\n递归方法:\n");
printf("%-6s%-8s%-10s\n", "字符", "权值", "编码");
getcode1(huffnode, 2 * n - 2, dest, 0);
printf("\n循环方法:\n");
printf("%-6s%-8s%-10s\n", "字符", "权值", "编码");
getcode2(huffnode, n);
printf("\n");
return 0;
}
运行结果:
?
?
|