这道题的原题代码实在过于混乱,且存在诸多无用的输出和格式错误。
若读者想要在原题基础上完成,不妨参考这篇文章:(1条消息) SCAU 8609 哈夫曼树_Maoxim的博客-CSDN博客 [作者:小汤汤汤汤]
这篇文章直接给出了一份完整的代码实现方式,且代码对可能的问题提供了充分的注释。
若读者对哈夫曼树的构造和编码仍有疑问,不妨在评论区留下你的问题。
#include <stdio.h>
#include <string.h>
typedef struct //哈夫曼树的各节点存储在数组中,且0号单元不使用。因此总共需要大小为2n的数组,其中1~n号单元存储叶子结点,后面的n-1个单元存储其他节点
{
int weight;
int parent, lchild, rchild;
} HTNode, *HuffmanTree;
typedef char **HuffmanCode; //哈夫曼编码表是一个二维数组,存储着n个一维数组,每个一维数组存储这一个节点的哈夫曼编码
void Select(HuffmanTree HT, int n, int &s1, int &s2)
{
int i, min1 = 9999, min2 = 10000; //min1是最小值,min2是第二小的值
s1 = s2 = 0; //s1为最小值编号,s2为第二小的值的编号
for (i = 1; i <= n; i++)
{
if (!HT[i].parent)
{
if (HT[i].weight < min1) //发现一个节点值比最小值还要小
{
s2 = s1, s1 = i;
min2 = min1, min1 = HT[i].weight;
}
else if (HT[i].weight >= min1 && HT[i].weight < min2) //发现一个节点值可以作为第二小的值
s2 = i, min2 = HT[i].weight;
}
}
}
void CreateHuffmanTree(HuffmanTree &HT, int n)
{
if (n <= 1)
return; //用于构造哈夫曼树的带权值的节点数不大于1时直接返回
int m = 2 * n - 1; //存储共需2n-1个单元
HT = new HTNode[m + 1]; //由于0号单元不使用,开辟2n个单元的空间用于存储
for (int i = 1; i <= m; i++)
HT[i].parent = HT[i].lchild = HT[i].rchild = 0; //初始化将要用于存储的2n-1个单元
for (int i = 1; i <= n; i++)
scanf("%d", &HT[i].weight); //输入用于建树的n个节点的权值
for (int i = n + 1; i <= m; i++)
{
int s1, s2; //s1,s2存储目前双亲域为0且权值最小的两个节点
Select(HT, i - 1, s1, s2); //选出当前权值最小的两个节点
HT[s1].parent = HT[s2].parent = i; //将选出来的两个节点的双亲域置为i,于是在接下来的Select中他们便不会被纳入选择范围
HT[i].lchild = s1, HT[i].rchild = s2; //将新节点往后存储,并令s1,s2分别为它的左右孩子,即加入一个新节点到用于建树的节点堆中
HT[i].weight = HT[s1].weight + HT[s2].weight; //新节点权值为当前权值最小的两个节点权值之和
}
}
void CreateHuffmanCode(HuffmanTree HT, HuffmanCode &HC, int n) //HC是二维数组的指针,指向哈夫曼编码表
{
HC = new char *[n + 1]; //HC的元素就是一个个一维数组
char *cd = new char[n]; //cd是一个临时的一维数组,用于存储编号为n的节点的哈夫曼编码
cd[n - 1] = '\0'; //编码结束符
for (int i = 1; i <= n; i++) //对每一个节点进行编码
{
int start = n - 1; //start指向最后的位置,也就是编码结束的位置,每完成一个字符的输入,start前移一个单位
int c = i, f = HT[i].parent; //f指向节点c的双亲节点
while (f) //f最终指向整棵树的根节点时编码最后一位,之后由于根节点无双亲节点,循环结束
{
start--; //start回溯一个位置
if (HT[f].lchild == c) //判断编码为'0'还是'1'
cd[start] = '0';
else
cd[start] = '1';
c = f;
f = HT[f].parent; //递归,逆序编码,因此编码顺序在cd表现出来是从后往前的
}
HC[i] = new char[n - start]; //为第i个字符分配编码空间
strcpy(HC[i], &cd[start]); //复制cd的内容到HC[i]
}
delete cd; //释放临时空间cd
}
int main()
{
int n;
scanf("%d", &n); //输入权值个数
HuffmanTree HT;
CreateHuffmanTree(HT, n); //建树
HuffmanCode HC;
CreateHuffmanCode(HT, HC, n); //求哈夫曼编码表
for (int i = 1; i <= n; i++)
puts(HC[i]); //输出哈夫曼编码表
return 0;
}