哈夫曼树的构造过程:

(1) 以权值分别为W1,W2...Wn的n各结点,构成n棵二叉树T1,T2,...Tn并组成森林F={T1,T2,...Tn},其中每棵二叉树 Ti仅有一个权值为 Wi的根结点;

(2) 在F中选取两棵根结点权值最小的树作为左右子树构造一棵新二叉树,并且置新二叉树根结点权值为左右子树上根结点的权值之和(根结点的权值=左右孩子权值之和,叶结点的权值= Wi)

(3) 从F中删除这两棵二叉树,同时将新二叉树加入到F中;

(4) 重复(2)、(3)直到F中只含一棵二叉树为止,这棵二叉树就是Huffman树。

参考《数据结构(C语言版)(第二版)》(严蔚敏编)第138页)

哈夫曼树存储结构:

一棵有n个叶子结点的哈夫曼树共有2n-1个结点,可以将其存于一个大小为2n-1的数组中,为了方便(第i个结点用下标为i表示),所以将数组0号单元置空,故数组的大小为2n。哈夫曼树对于一个结点来说需要存储其权值、双亲及左右孩子,因此哈夫曼树的存储表示如下:

typedef struct {//定义一个结构体数组int weight;//权重int p, lc, rc;//结点双亲及左右孩子下标
}*HuffmanTree,HTNode;

将叶子结点集中存储在1~n的位置,后面的n-1个位置存储非叶子结点。

哈夫曼树构造的算法实现:

构造huffmantree大致分为两大步骤:

1.初始化

2.创建树

严蔚敏版的《数据结构(c语言版)(第二版)》对其算法描述如下:

void CreateHuffmanTree(HuffmanTree &T, int n){
//初始化if(n <= 1) return;m = 2*n-1;T = new HTNode[m+1];//0号单元未用,动态分配m+1个单元for(1 = 1;i <= m;i++){T[i].p = 0;T[i].lc = 0;T[i].rc = 0;}for(i = 1;i <= n;i++){cin>>T[i].weight  //依次输入前n个叶子结点的权值}/*----------------初始化结束,下面开始创建哈夫曼树--------------------*/for(i = n+1;i <= m;i++){//n个叶子结点,2n-1个结点,共要n-1次合并产生n-1个新的结点Select(T,i-1,s1,s2);//在T[k]中 (k范围为[1,i-1])找到两个权值最小且双亲域为0的结点,返回它们在T中的序号s1,s2T[s1].p = i; T[s2].p = i; //得到新结点i,从森林中删除s1、s2,将s1、s2的双亲域改为iT[i].lc = s1; T[i].rc = s2; //s1、s2分别作为i的左右孩子T[i].weight = T[s1].weight + T[s2].weight; //i的权值为左右孩子之和}}

具体实现的时候,除了一些初始化和语法规范,主要的是写出select函数,由于刚刚开始学,自身代码水平不行笔者在写select函数的时候遇到了不少麻烦。

要找权值最小的两个下标可以如下实现:

int min1 = 100;
int min2 = 100;//定义min1,min2分别为最小值和次小值,赋一个很大的值(至少比叶子结点最大的权重要大)这里以100为例子
for (int j = 1;j <= i - 1;j++) {if (T[j].p == 0) {//条件为双亲域为0if (T[j].weight < min1) {min2 = min1;   min1 = T[j].weight;//如果第j个结点的权重比最小值小,min2更新为min1,min1更新为第j个结点的权重}else if (T[j].weight <= min2) {min2 = T[j].weight;//如果第j个结点的权重比次小值min2还小,那min2更新为该值}}}//上述循环中找到两个最小值,但要求的是两个下标,故再次循环找for (int j = 1;j <= i - 1;j++) {if (T[j].p == 0 && T[j].weight == min1) {s1 = j;//这里要注意不要忘记双亲域为0的条件,如果已经合并过的结点(双亲域不为0)的权值恰好等于这一次合并的最小值,就会出错}}for (int j = 1;j <= i - 1;j++){if (T[j].p == 0 && T[j].weight == min2 && j != s1) {s2 = j;//这里还得添加一个条件,也就是s1!=s2//如果min1 = min2,但此时j1!=j2,也就是下标不同,如果不加该条件的话s1和s2的值相同,也就是只找到了一个值,也会报错}

如果像算法描述的那样,s1、s2作为select的参数很难定义和初始化,因此不如将:

T[s1].p = i;
    T[s2].p = i;
    T[i].lc = s1;
    T[i].rc = s2;
    T[i].weight = T[s1].weight + T[s2].weight;

这一段放到select函数里实现,再将i作为参数传到select函数中就会方便许多。

完整代码实现:

测试的以书上的例题w = {5,29,7,8,14,23,3,11} 为例,n = 8,m = 15

测试第14、15个结点的权值、双亲及左右孩子的结点(因为一开始逐步调试的时候这两个结点的错误最多)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<Windows.h>
#include<malloc.h>typedef struct {//定义一个结构体数组int weight;//权重int p, lc, rc;//结点双亲及左右孩子下标
}*HuffmanTree,HTNode;void select(HuffmanTree& T, int n, int i) {//找T中下标范围1----i-1且双亲域为0的权重最小的两个结点下标为s1,s2int min1 = 100;int min2 = 100;int s1 = 0;int s2 = 0;for (int j = 1;j <= i - 1;j++) {if (T[j].p == 0) {if (T[j].weight < min1) {min2 = min1;min1 = T[j].weight;}else if (T[j].weight <= min2) {min2 = T[j].weight;}}}for (int j = 1;j <= i - 1;j++) {if (T[j].p == 0 && T[j].weight == min1) {s1 = j;}}for (int j = 1;j <= i - 1;j++){if (T[j].p == 0 && T[j].weight == min2 && j != s1) {s2 = j;}}T[s1].p = i;T[s2].p = i;T[i].lc = s1;T[i].rc = s2;T[i].weight = T[s1].weight + T[s2].weight;}
void CreateHuffmanTree(HuffmanTree& T, int n) {if (n <= 1) {return;}int m = 2 * n - 1;//1.初始化数组T = new HTNode[m + 1];for (int i = 1;i <= m;i++) {T[i].p = 0;T[i].lc = 0;T[i].rc = 0;}for (int i = 1;i <= n;i++) {printf("第%d个结点权重为:\n", i);scanf("%d", &(T[i].weight));}//2.创建哈夫曼树for (int i = n + 1;i <= m;i++) {//n-1次合并,n-1次循环select(T, n, i);//找T中下标范围1----i-1且双亲域为0的权重最小的两个结点}}int main() {HuffmanTree T;//测试用w = {5,29,7,8,14,23,3,11}CreateHuffmanTree(T, 8);printf("%第十四个结点的权重为%d,双亲为%d结点,左孩子为%d结点,右孩子为%d结点\n", T[14].weight,T[14].p,T[14].lc,T[14].rc);//测试用数据printf("第十五个结点的权重为%d,双亲为%d结点,左孩子为%d结点,右孩子为%d结点\n", T[15].weight,T[15].p,T[15].lc,T[15].rc);system("pause");
}

测试结果如下:

ps:笔者第一次写博客,若有代码错误和表述不清还请见谅,谢谢!!!!!!!!!!

哈夫曼树的构造及C++代码实现相关推荐

  1. 哈夫曼树的构造C/C++代码实现

    哈夫曼树: 所谓哈夫曼(Huffman)树就是最优二叉树,是带权路径长度WPL最小的二叉树. 哈夫曼树的构造: 根据哈夫曼树的特点:权值越大的结点离根结点越近. 具体方法:依次选择权值最小的二个结点作 ...

  2. 数据结构学习记录——哈夫曼树(什么是哈夫曼树、哈夫曼树的定义、哈夫曼树的构造、哈夫曼树的特点、哈夫曼编码)

    目录 什么是哈夫曼树 哈夫曼树的定义 哈夫曼树的构造 图解操作 代码实现 代码解析 哈夫曼树的特点 哈夫曼编码 不等长编码 二叉树用于编码 哈夫曼编码实例 什么是哈夫曼树 我们先举个例子: 要将百分制 ...

  3. c语言最优树的构造,哈夫曼树的构造及编码 Haffman树的构造及其编码

    写出构造完整的哈夫曼树的编码 void HuffmanCoding(HuffmanCode HC[], int w[], int n) // w存放n个字符的权值(均>0),构造哈夫曼树HT, ...

  4. 哈夫曼树的构造算法代码

    代码: #include<stdio.h> #define ERROR 0 #define OK 1 typedef int Status; //采用顺序存储结构,一维结构数组 //定义结 ...

  5. 哈夫曼树的构造(C语言实现)

    哈夫曼树的构造过程可以详见推荐博客:哈夫曼树以及哈夫曼编码的构造步骤 建议先看完推荐博客中的文字说明,或者自己找一本数据结构的树来仔细阅读以下关于哈夫曼树的构造 然后再来看下面给出的code 这里给出 ...

  6. 数据结构教程—哈夫曼树的构造算法

    哈夫曼树算法如下 (1)根据给定的n个权值,使对应节点构成n棵二叉树的森林,其中每棵二叉树都只有一个根节点,其左右子树均为空. (2)在森林中选取两棵节点权值最小的子树分别作为左右子树构造一棵新的二叉 ...

  7. 哈夫曼树的构造(手写图解)

    哈夫曼树的构造

  8. 哈夫曼树的构造及应用

    哈夫曼树的构造及应用 文章目录 哈夫曼树的构造及应用 带权路径长度 哈夫曼树定义 哈夫曼树的性质: 构造哈夫曼树 构造哈夫曼树存储及生成算法 算法框架 代码实操: 应用: 哈夫曼编码 带权路径长度 设 ...

  9. 哈夫曼树的构造 java_Java实现哈夫曼树的构造

    哈夫曼树的内容这里不作解释,请自己搜索.下面给出哈夫曼树构造过程的 Java 实现. 结点类: 1./**2. * 二叉树节点3. */4.public class Node implements C ...

最新文章

  1. postman+newman(2)
  2. SSH-Auditor:一款SSH弱密码探测工具
  3. hdu 4336 Card Collector
  4. python报错:TypeError: cant multiply sequence by non-int of type float(bug)(csdn标题没法用英文引号,以后注意别搜引号)
  5. 金蝶系统服务器要求,金蝶服务器安装及其相关要求.doc
  6. mac上python3安装HTMLTestRunner
  7. c语言课程设计 职工工资处理系统,院职工工资管理系统_C语言课程设计-2017年10月.doc...
  8. 【求救】如何调用Windows系统自带的“选择用户”、“选择组”的对话框?
  9. sqlServer数据库自动备份
  10. Appium下载和安装
  11. matlab 线性回归 参数显著性,matlab做多元线性回归后回归系数的显著性检验
  12. 51单片机AD模数转换(SPI通信)
  13. 学习.NET好书推荐
  14. 高客单价项目,适合新手操作的网络项目
  15. 【弄nèng - Zookeeper】Zookeeper入门教程(三)—— 客户端Curator的基本API使用(Curator framework)
  16. 烂笔头 | OpenMMLab 第一讲
  17. 现代数据库及大数据管理—常见问题与技术归纳
  18. 如何判断一棵树是否是满二叉树
  19. Mysql莫名其妙的错误,语法没错却报语法错误
  20. UltraISO 绿色多国语言版

热门文章

  1. 布莱克斯科尔斯模型(一)
  2. IP数据包的路由转发
  3. MFRC522模块开发笔记
  4. ajax上传文件:ajaxSubmit使用
  5. 台达DOP系列触摸屏与电脑通讯不上时,如何进入系统设置画面修改系统设置从而正常通讯?
  6. CC3200 —— No.1 环境搭建(更新于2020年5月1日)
  7. jQuery遍历对象/数组/集合
  8. html代码制作的个人简历
  9. php好趣网抓取_PHP抓取卫视直播源
  10. 嵌入式软件面试题整理