上次我们介绍了线索二叉树的实现,这次介绍树这一章的最后一个程序——赫夫曼树的实现。
还是老规矩:
程序在码云上可以下载。
地址:https://git.oschina.net/601345138/DataStructureCLanguage.git
赫夫曼树设计的初衷是为了提高电报传输的效率,缩短字符的编码长度。利用赫夫曼树可以构造一种不等长的二进制编码,并且构造所得的赫夫曼编码是一种最优前缀编码,使所传电文的总长度最短。
书上P148页有一个这样的例子:
例:已知某系统在通讯联络中只可能出现八种字符A,B,C,D,E,F,G,H, 其概率分别为:
0.05, 0.29, 0.07, 0.08, 0.14, 0.23,0.03,0.11
试设计赫夫曼编码.
设权 w = { 5, 29, 7, 8, 14, 23, 3, 11 },则权值个数n=8,赫夫曼树总结点数m=2n-1=15。
赫夫曼树:
赫夫曼编码: 0110, 10, 1110, 1111, 110, 00, 0111, 010
赫夫曼树的程序如下:
//>>>>>>>>>>>>>>>>>>>>>>>>>引入头文件<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
#include <stdio.h> //使用了标准库函数
#include <stdlib.h> //使用了动态内存分配函数
#include <string.h> //使用了字符串处理函数strcpy
//>>>>>>>>>>>>>>>>>>>>>>>自定义符号常量<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
#define OVERFLOW -2 //内存溢出错误常量
#define OK 1 //表示操作正确的常量
#define ERROR 0 //表示操作错误的常量
//>>>>>>>>>>>>>>>>>>>>>>>自定义数据类型<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
typedef int Status; //用typedef给int起个别名,也便于程序的维护
//----------------赫夫曼树和赫夫曼编码的存储表示-------------------
typedef struct{
unsigned int weight; //权值
unsigned int parent, lchild, rchild; //双亲,左孩子,右孩子
}HTNode, * HuffmanTree; //动态分配数组存储赫夫曼树
typedef char * * HuffmanCode; //动态分配数组存储赫夫曼编码表
//----------------------赫夫曼树的主要操作--------------------------
/*
函数:min
参数:HuffmanTree HT 指向赫夫曼树结点的指针
int i 在HT中查找最小值范围的上限(就是个下标)
返回值:被选中的权值最小的结点在HT中的下标
作用:从HT指示的赫夫曼树的[1..i-1]范围的结点中选出权值最小的结点。
该函数被Select函数调用
*/
int min(HuffmanTree HT, int i){
//j是临时变量,flag记录了权值最小的结点在HT中的下标
int j, flag = 1;
//设置k的值为一个结点的权值极难超越的最大值
unsigned int k = 10000;
//从赫夫曼树的所有结点中选出权值最小的结点并记录其在HT中的下标
for(j = 1; j <= i; j++){
//k保存了目前最小的权值,若有结点的权值比k小,更新k值为该结点权值
//flag保存了目前最小权值,若发现比k更小的权值,更新flag为该结点下标
//HT[j].parent == 0 说明该结点还没有被选中过(选过的结点不能再选)
if(HT[j].weight < k && HT[j].parent == 0){
k = HT[j].weight, flag = j;
}//if
}//for
//循环结束后,k保存了赫夫曼树所有备选结点中权值的最小值
//flag保存了权值最小结点在HT中的下标
//此时被选中的权值最小的结点就是HT[flag]
//修改被选中结点的双亲,防止这个结点再次被选中
//调用一次Select函数会调用两次min函数,假设此次是第一次调用min函数,
//如果不设置双亲的值为1则后续的一次min函数调用还会重复选中这个结点,
//那生成的赫夫曼树结果就不对了。
HT[flag].parent = 1;
//返回被选中的权值最小的结点在HT中的下标
return flag;
}//min
/*
函数:Select
参数:HuffmanTree HT 指向赫夫曼树结点的指针
int i 在HT中查找最小值范围的上限(就是个下标)
int &s1 带回找出的第一个权值最小结点在HT中的下标
int &s2 带回找出的第二个权值最小结点在HT中的下标,且s2 >= s1
返回值:无
作用:在HT[1..i-1]选择parent为0且weight最小的两个结点,
其序号分别为是s1和s2。
*/
void Select(HuffmanTree HT, int i, int &s1, int &s2){ //选择函数
//临时变量j
int j;
//找出第一个权值最小结点在HT中的下标s1
s1 = min(HT, i);
//找出第二个权值最小结点在HT中的下标s2
s2 = min(HT, i);
//若s1和s2位置不对,则对调一下
if(s1 > s2){
j = s1;
s1 = s2;
s2 = j;
}//if
}//Select
/*
函数:PrintHT
参数:HuffmanTree HT 指向赫夫曼树结点的指针
int n 权值个数
返回值:无
作用:按照书上P149页格式打印HT的存储结构表
*/
void PrintHT(HuffmanTree HT, int n){
//n个字符构造的赫夫曼树共有2*n-1个结点
int m = 2 * n - 1;
printf("\n+-------------------------------------------------------------+\n");
printf("| 赫夫曼树HT的存储结构 |\n");
printf("+----------+----------+----------+--------------+-------------+\n");
printf("| 结点编号 | weight | parent | leftchild | rightchild |\n");
printf("+----------+----------+----------+--------------+-------------+\n");
for(int i = 1; i <= m; i++){
printf("| %4d | %4d | %4d | %4d | %4d |\n",
i, HT[i].weight, HT[i].parent, HT[i].lchild, HT[i].rchild);
printf("+----------+----------+----------+--------------+-------------+\n");
}//for
}//PrintHT
/*
函数:HuffmanCoding
参数:HuffmanTree &HT 赫夫曼树的引用
HuffmanCode &HC 根据赫夫曼树构造的赫夫曼编码
int *w 指向放n个字符的权值内存区域的指针
int n 有n个字符要生成赫夫曼编码
返回值:状态码,操作成功返回OK,否则返回ERROR
作用:w存放n个字符的权值(均>0),构造赫夫曼树 HT,
并求出n个字符的赫夫曼编码 HC
*/
Status HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n){
//s1和s2保存选出的两个权值最小的结点在HT中的下标
//i是临时变量,循环用
//start指示了赫夫曼编码结束符在cd指示的求编码的临时空间中的位置
//f是s1和s2的双亲在HT中的下标
int s1, s2, i, start, f;
//cd指向动态分配的求编码的临时空间
char *cd;
printf("->构造赫夫曼树过程分析:\n");
//p是工作指针,指向赫夫曼树中的结点
HuffmanTree p = NULL;
//检查权值个数参数n是否合法
if(n <= 1) {
return ERROR;
}//if
//n个字符构造的赫夫曼树共有m = 2*n-1个结点
int m = 2 * n - 1;
printf("->待构造的赫夫曼树共有2 ×%d - 1 = %d个结点\n", n, m);
//申请赫夫曼树结点占用的内存空间,0号单元不用
if(!(HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode)))) {
exit(OVERFLOW);
}//if
printf("->赫夫曼树共分配了%d个结点空间,其中包含一个不用的0号单元\n", m + 1);
//初始化HT内部各个分量的值
printf("->初始化所有叶子节点的权值,父亲和孩子:\n");
for(p = HT + 1, i = 1; i <= n; ++i, ++p, ++w){
//填入用户输入的权值
p->weight = *w;
//双亲初始值为0,表示此结点还没有被选择最小的算法选择过
p->parent = 0;
//左右孩子初始化为0,表示空
p->lchild = 0;
p->rchild = 0;
//打印初始化结果(书上没有)
printf("->初始化叶子结点%d的权值为%d,父亲为%d,左右孩子分别为%d,%d\n",
i, p->weight, p->parent, p->lchild, p->rchild);
}//for
//赫夫曼树生成过程中会循环选择两个权值最小的的结点求出权值之和生成一个新的结点
//然后把新生成的结点插入HT中。所以HT除了权值(叶子结点)还需要预留一些空间
//存储生成的非叶子结点。 这些结点暂时还没生成,所以暂时将它们的各个分量初值置零。
for(; i <= m; i++, p++){
p->weight = 0;
p->parent = 0;
p->lchild = 0;
p->rchild = 0;
}//for
//打印初始的赫夫曼树存储结构HT内部的情况,以便和后续的生成过程进行比较
PrintHT(HT,n);
//暂停程序,让用户看到当前输出的HT
system("pause");
//开始构造赫夫曼树
printf("->开始利用输入的权值构造一棵赫夫曼树:\n");
//n是输入权值的个数,也是叶子结点的个数。刚初始化完的赫夫曼树HT
//中,0号单元不用,从1-n存放的是输入的权值(叶子结点,暂时没双亲)
//所以我们生成新结点要从HT的第n+1个位置开始到m结束
for(i = n + 1; i <= m; ++i){
//在HT[1..i-1]选择parent为0且weight最小的两个结点,其序号分别为是s1和s2
//注意:每次选择的时候要把新生成的结点也算进来。
Select(HT, i - 1, s1, s2);
printf("->选择从1-%d的最小权值的结点%d[%d]和%d[%d]\n",
i - 1, s1, HT[s1].weight, s2, HT[s2].weight);
//选出的两个权值最小的结点的双亲就是即将生成的结点
HT[s1].parent = i;
HT[s2].parent = i;
//即将生成的结点左孩子是s1,右孩子是s2,
//因为s1比s2先选,所以s1总是小于等于s2
HT[i].lchild = s1;
HT[i].rchild = s2;
//即将生成结点的权值就是两个权值最小的结点的权值之和
HT[i].weight = HT[s1].weight + HT[s2].weight;
//打印初始化结果
printf("->初始化非叶子结点%d的权值为左右孩子%d,%d的权值之和%d+%d=%d,左右孩子的父亲为%d\n",
i, s1, s2, HT[s1].weight, HT[s2].weight, HT[i].weight, HT[s1].parent);
PrintHT(HT, n);
//暂停程序执行,让用户动态观察HT存储结构内数据的变化过程
system("pause");
}//for
//构造操作完成
printf("->赫夫曼树构造完成\n");
//---------------从叶子到根逆向求每个字符的赫夫曼编码------------------
printf("->根据构造好的赫夫曼树从叶子到根求每个字符的赫夫曼编码:\n");
//申请赫夫曼编码占用的内存空间
if(!(HC = (HuffmanCode)malloc((n + 1) * sizeof(char *)))) {
exit(OVERFLOW);
}//if
//申请求编码的工作空间
if(!(cd = (char *)malloc(n * sizeof(char)))) {
exit(OVERFLOW);
}//if
//编码结束符——字符串结束标志\0
cd[n-1] = '\0';
//逐个字符求赫夫曼编码
for(int i = 1; i <= n; ++i){
//编码结束符位置
start = n - 1;
//从叶子到根逆向求编码
for(int c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent) {
//叶子结点根结点的左孩子
if(HT[f].lchild == c) {
//生成编码0
cd[--start] = '0';
}//if
else { //叶子结点根结点的右孩子
//生成编码1
cd[--start] = '1';
}//else
}//for
//申请一段内存空间用于保存生成的赫夫曼编码
if(!(HC[i] = (char *)malloc((n - start) * sizeof(char)))) {
exit(OVERFLOW);
}//if
//将临时工作空间cd中拷贝计算出的赫夫曼编码到HC对应的位置上
strcpy(HC[i], &cd[start]);
//打印生成的赫夫曼编码
printf("->叶子节点%d的赫夫曼编码为:%s\n", i, HC[i]);
}//for
//释放临时工作空间cd
free(cd);
//操作成功
return OK;
}//HuffmanCoding
//-----------------------主函数------------------------
int main(int argc, char *argv[]) {
printf("---------------------------------赫夫曼树引用版---------------------------------\n");
//指向赫夫曼树的指针
HuffmanTree HT;
//指向存储赫夫曼编码存储区域的指针
HuffmanCode HC;
//n是输入权值的个数
//w是指向权值存储区域的指针
int *w, n;
printf("->请输入所要建立赫夫曼树权值的个数(>1):");
scanf("%d", &n);
//根据输入权值的个数申请保存权值的存储空间
if(!(w = (int *)malloc(n * sizeof(int)))) {
exit(OVERFLOW);
}//if
//从键盘接收n个权值并保存到w指示的内存区域中
printf("->请依次输入%d个权值(整型,用空格隔开):\n",n);
for(int i = 0; i <= n - 1; i++) {
scanf("%d", w + i);
}//for
//调用算法得出赫夫曼编码
HuffmanCoding(HT, HC, w, n);
//输出赫夫曼编码
printf("->您建立的赫夫曼树对应的赫夫曼编码如下:\n");
for(int i = 1; i <= n; i++) {
puts(HC[i]);
}//for
//释放掉存放权值的内存空间
free(w);
w = NULL;
//释放掉赫夫曼树HT占用的内存空间
free(HT);
HT = NULL;
//释放赫夫曼编码HC占用的内存空间
free(HC);
HC = NULL;
return 0;
}//main
本程序为动态演示版本,你可以通过观察HT的存储结构中数据的变化以及输出信息理解赫夫曼树建立的过程。
本程序使用的是课本P148页的赫夫曼树(也就是本文例子中的那张图片)作为测试的例子,请自行验证其正确性,下面是测试数据:
---------------------------------赫夫曼树引用版---------------------------------
->请输入所要建立赫夫曼树权值的个数(>1):8
->请依次输入8个权值(整型,用空格隔开):
5 29 7 8 14 23 3 11
->构造赫夫曼树过程分析:
->待构造的赫夫曼树共有2 ×8 - 1 = 15个结点
->赫夫曼树共分配了16个结点空间,其中包含一个不用的0号单元
->初始化所有叶子节点的权值,父亲和孩子:
->初始化叶子结点1的权值为5,父亲为0,左右孩子分别为0,0
->初始化叶子结点2的权值为29,父亲为0,左右孩子分别为0,0
->初始化叶子结点3的权值为7,父亲为0,左右孩子分别为0,0
->初始化叶子结点4的权值为8,父亲为0,左右孩子分别为0,0
->初始化叶子结点5的权值为14,父亲为0,左右孩子分别为0,0
->初始化叶子结点6的权值为23,父亲为0,左右孩子分别为0,0
->初始化叶子结点7的权值为3,父亲为0,左右孩子分别为0,0
->初始化叶子结点8的权值为11,父亲为0,左右孩子分别为0,0
+-------------------------------------------------------------+
| 赫夫曼树HT的存储结构 |
+----------+----------+----------+--------------+-------------+
| 结点编号 | weight | parent | leftchild | rightchild |
+----------+----------+----------+--------------+-------------+
| 1 | 5 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 2 | 29 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 3 | 7 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 4 | 8 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 5 | 14 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 6 | 23 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 7 | 3 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 8 | 11 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 9 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 10 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 11 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 12 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 13 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 14 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 15 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
请按任意键继续. . .
->开始利用输入的权值构造一棵赫夫曼树:
->选择从1-8的最小权值的结点1[5]和7[3]
->初始化非叶子结点9的权值为左右孩子1,7的权值之和5+3=8,左右孩子的父亲为9
+-------------------------------------------------------------+
| 赫夫曼树HT的存储结构 |
+----------+----------+----------+--------------+-------------+
| 结点编号 | weight | parent | leftchild | rightchild |
+----------+----------+----------+--------------+-------------+
| 1 | 5 | 9 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 2 | 29 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 3 | 7 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 4 | 8 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 5 | 14 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 6 | 23 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 7 | 3 | 9 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 8 | 11 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 9 | 8 | 0 | 1 | 7 |
+----------+----------+----------+--------------+-------------+
| 10 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 11 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 12 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 13 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 14 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 15 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
请按任意键继续. . .
->选择从1-9的最小权值的结点3[7]和4[8]
->初始化非叶子结点10的权值为左右孩子3,4的权值之和7+8=15,左右孩子的父亲为10
+-------------------------------------------------------------+
| 赫夫曼树HT的存储结构 |
+----------+----------+----------+--------------+-------------+
| 结点编号 | weight | parent | leftchild | rightchild |
+----------+----------+----------+--------------+-------------+
| 1 | 5 | 9 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 2 | 29 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 3 | 7 | 10 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 4 | 8 | 10 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 5 | 14 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 6 | 23 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 7 | 3 | 9 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 8 | 11 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 9 | 8 | 0 | 1 | 7 |
+----------+----------+----------+--------------+-------------+
| 10 | 15 | 0 | 3 | 4 |
+----------+----------+----------+--------------+-------------+
| 11 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 12 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 13 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 14 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 15 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
请按任意键继续. . .
->选择从1-10的最小权值的结点8[11]和9[8]
->初始化非叶子结点11的权值为左右孩子8,9的权值之和11+8=19,左右孩子的父亲为11
+-------------------------------------------------------------+
| 赫夫曼树HT的存储结构 |
+----------+----------+----------+--------------+-------------+
| 结点编号 | weight | parent | leftchild | rightchild |
+----------+----------+----------+--------------+-------------+
| 1 | 5 | 9 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 2 | 29 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 3 | 7 | 10 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 4 | 8 | 10 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 5 | 14 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 6 | 23 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 7 | 3 | 9 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 8 | 11 | 11 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 9 | 8 | 11 | 1 | 7 |
+----------+----------+----------+--------------+-------------+
| 10 | 15 | 0 | 3 | 4 |
+----------+----------+----------+--------------+-------------+
| 11 | 19 | 0 | 8 | 9 |
+----------+----------+----------+--------------+-------------+
| 12 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 13 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 14 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 15 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
请按任意键继续. . .
->选择从1-11的最小权值的结点5[14]和10[15]
->初始化非叶子结点12的权值为左右孩子5,10的权值之和14+15=29,左右孩子的父亲为12
+-------------------------------------------------------------+
| 赫夫曼树HT的存储结构 |
+----------+----------+----------+--------------+-------------+
| 结点编号 | weight | parent | leftchild | rightchild |
+----------+----------+----------+--------------+-------------+
| 1 | 5 | 9 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 2 | 29 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 3 | 7 | 10 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 4 | 8 | 10 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 5 | 14 | 12 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 6 | 23 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 7 | 3 | 9 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 8 | 11 | 11 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 9 | 8 | 11 | 1 | 7 |
+----------+----------+----------+--------------+-------------+
| 10 | 15 | 12 | 3 | 4 |
+----------+----------+----------+--------------+-------------+
| 11 | 19 | 0 | 8 | 9 |
+----------+----------+----------+--------------+-------------+
| 12 | 29 | 0 | 5 | 10 |
+----------+----------+----------+--------------+-------------+
| 13 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 14 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 15 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
请按任意键继续. . .
->选择从1-12的最小权值的结点6[23]和11[19]
->初始化非叶子结点13的权值为左右孩子6,11的权值之和23+19=42,左右孩子的父亲为13
+-------------------------------------------------------------+
| 赫夫曼树HT的存储结构 |
+----------+----------+----------+--------------+-------------+
| 结点编号 | weight | parent | leftchild | rightchild |
+----------+----------+----------+--------------+-------------+
| 1 | 5 | 9 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 2 | 29 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 3 | 7 | 10 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 4 | 8 | 10 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 5 | 14 | 12 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 6 | 23 | 13 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 7 | 3 | 9 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 8 | 11 | 11 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 9 | 8 | 11 | 1 | 7 |
+----------+----------+----------+--------------+-------------+
| 10 | 15 | 12 | 3 | 4 |
+----------+----------+----------+--------------+-------------+
| 11 | 19 | 13 | 8 | 9 |
+----------+----------+----------+--------------+-------------+
| 12 | 29 | 0 | 5 | 10 |
+----------+----------+----------+--------------+-------------+
| 13 | 42 | 0 | 6 | 11 |
+----------+----------+----------+--------------+-------------+
| 14 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 15 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
请按任意键继续. . .
->选择从1-13的最小权值的结点2[29]和12[29]
->初始化非叶子结点14的权值为左右孩子2,12的权值之和29+29=58,左右孩子的父亲为14
+-------------------------------------------------------------+
| 赫夫曼树HT的存储结构 |
+----------+----------+----------+--------------+-------------+
| 结点编号 | weight | parent | leftchild | rightchild |
+----------+----------+----------+--------------+-------------+
| 1 | 5 | 9 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 2 | 29 | 14 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 3 | 7 | 10 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 4 | 8 | 10 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 5 | 14 | 12 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 6 | 23 | 13 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 7 | 3 | 9 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 8 | 11 | 11 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 9 | 8 | 11 | 1 | 7 |
+----------+----------+----------+--------------+-------------+
| 10 | 15 | 12 | 3 | 4 |
+----------+----------+----------+--------------+-------------+
| 11 | 19 | 13 | 8 | 9 |
+----------+----------+----------+--------------+-------------+
| 12 | 29 | 14 | 5 | 10 |
+----------+----------+----------+--------------+-------------+
| 13 | 42 | 0 | 6 | 11 |
+----------+----------+----------+--------------+-------------+
| 14 | 58 | 0 | 2 | 12 |
+----------+----------+----------+--------------+-------------+
| 15 | 0 | 0 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
请按任意键继续. . .
->选择从1-14的最小权值的结点13[42]和14[58]
->初始化非叶子结点15的权值为左右孩子13,14的权值之和42+58=100,左右孩子的父亲为15
+-------------------------------------------------------------+
| 赫夫曼树HT的存储结构 |
+----------+----------+----------+--------------+-------------+
| 结点编号 | weight | parent | leftchild | rightchild |
+----------+----------+----------+--------------+-------------+
| 1 | 5 | 9 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 2 | 29 | 14 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 3 | 7 | 10 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 4 | 8 | 10 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 5 | 14 | 12 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 6 | 23 | 13 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 7 | 3 | 9 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 8 | 11 | 11 | 0 | 0 |
+----------+----------+----------+--------------+-------------+
| 9 | 8 | 11 | 1 | 7 |
+----------+----------+----------+--------------+-------------+
| 10 | 15 | 12 | 3 | 4 |
+----------+----------+----------+--------------+-------------+
| 11 | 19 | 13 | 8 | 9 |
+----------+----------+----------+--------------+-------------+
| 12 | 29 | 14 | 5 | 10 |
+----------+----------+----------+--------------+-------------+
| 13 | 42 | 15 | 6 | 11 |
+----------+----------+----------+--------------+-------------+
| 14 | 58 | 15 | 2 | 12 |
+----------+----------+----------+--------------+-------------+
| 15 | 100 | 0 | 13 | 14 |
+----------+----------+----------+--------------+-------------+
请按任意键继续. . .
->赫夫曼树构造完成
->根据构造好的赫夫曼树从叶子到根求每个字符的赫夫曼编码:
->叶子节点1的赫夫曼编码为:0110
->叶子节点2的赫夫曼编码为:10
->叶子节点3的赫夫曼编码为:1110
->叶子节点4的赫夫曼编码为:1111
->叶子节点5的赫夫曼编码为:110
->叶子节点6的赫夫曼编码为:00
->叶子节点7的赫夫曼编码为:0111
->叶子节点8的赫夫曼编码为:010
->您建立的赫夫曼树对应的赫夫曼编码如下:
0110
10
1110
1111
110
00
0111
010
--------------------------------
Process exited with return value 0
Press any key to continue . . .
下次的文章会介绍基于邻接矩阵存储结构的图的各种基本操作的实现以及图的深度优先遍历、广度优先遍历算法的实现。感谢大家一直以来的支持和鼓励!希望大家继续关注我的博客,也希望我的文章能帮助大家更好的理解书上的算法。再见!