逻辑结构
树结构
物理存储结构
数组
算法图解
代码
哈夫曼树结构体
typedef struct
{
int weight;
int lchild, rchild, parent;
}HTNode, *HuffmanTree;
//*HuffmanTree 是指向 HTNode 结构体 的指针;
//malloc分配数组内存,存储最优二叉树
typedef char * * HuffmanCode;
//char** 别名 HuffmanCode ⇒ 视为 char[][]
//malloc分配数组内存,存储最优二叉树编码表(哈夫曼码表)
哈夫曼编码
/*
参数列表:
存储HuffmanTree类型元素的数组首地址(指针存储首地址) HT
存储HuffmanCode类型元素的数组首地址(指针存储首地址) HC
存储int类型元素的数组首地址(指针存储首地址) w
叶子节点个数 n
*/
void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int * w, int n) {
if (n <= 1)
return;
//0.定义
int m = 2 * n - 1; //m 为 总节点数
HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode)); //赋值HT
//1.初始化 哈夫曼树状态
HuffmanTree p = HT;
*p = { 1000,0,0,0 };
p = HT + 1;
int i = 1;
for (;i <= n; ++i, ++p, ++w)
*p = { *w,0,0,0 };
for(;i<=m;++i,++p)
*p = { 0,0,0,0 };
//2.演变最终 哈夫曼树状态
for (i = n + 1; i <= m; ++i) { //BUG1 现象:最后一个节点的 parent == -8000+ ,最后一个节点未初始化。解决:调整 p 大小
//定义Select所需参数 //BUG2 现象:最后两个节点的 parent 与 w 有误,之前的节点全部正确。解决:使用 未被使用的0号节点,存储大权值1000
int s1 = 0;
int s2 = 0;
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;
}
//3.从叶子 --> 根 逆向求解每个字符的哈夫曼编码
//HC = (HuffmanCode)malloc((n + 1) * sizeof(char *));
HC = (HuffmanCode)malloc((n + 1) * sizeof(char *));
char * cd = (char *)malloc(n * sizeof(char));
cd[n - 1] = '\0';
for (int i = 1; i <= n; ++i) {
int start = n - 1;
int c,f = 0;
c=i;
f = HT[i].parent;
for (; f != 0; ) {
if (HT[f].lchild == c)
cd[--start] = '0';
else
cd[--start] = '1';
HC[i] = (char *)malloc((n - start) * sizeof(char));
strcpy(HC[i], &cd[start]);
c = f;
f = HT[f].parent;
}
}
free(cd); //BUG3 现象:free(cd)异常.解决:cd内存的释放,应在HC字符编码全部完成后。
}
选择两最小权值
//在已知节点中,挑选 parent==0 且 权值最小的两个节点
void Select(HuffmanTree &HT, int range, int &s1, int &s2) {
//得出s1
for (int i = 1; i <= range; i++) {
//如果当前节点parent不为0,则跳过此次循环
if (HT[i].parent != 0)
continue;
if (HT[i].weight <= HT[s1].weight)
s1 = i;
}
//得出s2
for (int i = 1; i <= range; i++) {
//如果当前节点parent不为0,则跳过此次循环
if (i == s1)
continue;
if (HT[i].parent != 0)
continue;
if (HT[i].weight <= HT[s2].weight)
s2 = i;
}
}
主函数测试
int main() {
//0.定义=声明+赋值 HuffmanCoding 函数所需 参数
char c[] = { 'a','b','c','d' };
int w[] = {7,5,2,4}; //权值数组
//0.只声明
HuffmanTree HT;
HuffmanCode HC;
//1.调用 HuffmanCoding
HuffmanCoding(HT, HC, w, N);
//2.打印 HC 哈夫曼编码
for (int i = 1; i <= sizeof(HC); i++)
{
cout << c[i - 1] << ":" << HC[i] << endl; //BUG4 现象:HC[i]访问异常.解决:HC[0]未被使用,i 从 1 -> sizeof(HC)。
}
return 0;
}
注:为什么,不从 0 开始使用,可能是书上为了更贴合 人类思维,从1开始。
参考资料
内容 | 网址 |
---|---|
ASCII | https://baike.baidu.com/item/ASCII/309296?fr=aladdin |
char * & char ** | https://blog.csdn.net/crazyeden/article/details/81124414 |
参数传递方式*3 | https://blog.csdn.net/weibo1230123/article/details/75541862 |
残缺·哈夫曼编码实现 | https://blog.csdn.net/weixin_42261396/article/details/85174621 |
struct {} Node,*PNode; | https://bbs.csdn.net/topics/270018485 |