哈夫曼树、哈夫曼编码

  • 哈夫曼树
  • 初始化哈夫曼树
  • 构造哈夫曼树
    • Select()
  • 哈夫曼编码
  • 根据哈夫曼树求哈夫曼编码
    • 测试代码
    • 运行实例

哈夫曼树

定义:带权路径长度最短的树


如上图三棵二叉树,都包含4个叶子结点a、b、c、d,分别带权7、5、2、4,它们的带权路径长度分别为36(a),46(b),35c。
显然,c树带权路径长度最小,经验证c树即为哈夫曼树。

哈夫曼树的结构:

typedef struct
{int weight;int parent,lchird,rchild;
}HTNode,*HuffmanTree;

初始化哈夫曼树

说明:初始化带有n个叶子结点的哈夫曼树。

void InitHuffmanTree(HuffmanTree &H,int n)
{if(n<=1) return ;int m=2*n-1;H=new HTNode[m+1];for (int i = 1; i <= m; i++){H[i].parent=0;H[i].lchird=0;H[i].rchild=0;}for (int i = 1; i <= n; i++){cin>>H[i].weight;}
}

实现:①二叉树的结点数m=2*n-1,n为二叉树的叶子结点数。
②为了实现方便,从数组下标为1的位置开始使用,所以分配m+1个空间。
③将叶子结点存储在前面1~n个位置,后面n-1个位置存储构造后的其他节点。


构造哈夫曼树

void CreateHuffmanTree(HuffmanTree &H,int n)
{int m=2*n-1;int s1,s2;for (int i = n+1; i <= m; i++){Select(H,i-1,s1,s2);H[s1].parent=i; H[s2].parent=i;H[i].lchird=s1; H[i].rchild=s2;H[i].weight=H[s1].weight+H[s2].weight;}
}

实现:Select()函数的作用为每次选择前1到i-1个结点,挑选两个双亲域为0且权值最小的节点,利用s1和s2返回两个结点的下标。
接着将两个节点的双亲域赋值为当前节点的下标i,将当前节点的孩子域分别置为s1和s2.
最后将两个节点权值相加,和储存在当前“生成”结点的weight。

此哈夫曼树带权路径长度为:23x2+29x2+11x3+14x3+3x4+5x4+7x4+8x4=271


Select()

bool cmp(HTNode a,HTNode b)
{return a.weight<b.weight;
}
void Select(HuffmanTree H,int l,int &s1,int &s2)
{HuffmanTree M;M=new HTNode[l+1];for (int i = 1; i <= l; i++){M[i].weight=H[i].weight;M[i].parent=H[i].parent;M[i].lchird=H[i].lchird;M[i].rchild=H[i].rchild;}sort(M+1,M+l+1,cmp);int a[2]={0};int num=0;for (int i = 1; i <= l; i++){if(M[i].parent==0) {for (int j = 1; j <= l; j++){if(M[i].weight==H[j].weight&&H[j].parent==0&&j!=a[0]){a[num++]=j;break;}}}if(num==2) break;}s1=a[0];s2=a[1];delete M;
}

实现:创建一个副本M,每次将待查找的前1-l个单元复制给M,接着对M按照权值由低到高排序。
接着匹配原树和副本,查找权值最小且双亲域为0的两个结点,存储这两个结点本身(在原树中)的下标。
j!=a[0]避免了权值相等时重复添加同一结点的情况。

创建副本的操作目的是不改变原树中结点的位置。
即1-n仍然是叶子结点,n+1~m为创建的节点。


哈夫曼编码

哈夫曼编码:对一棵具有n个叶子的哈夫曼树,若对树中的每个左分支赋0,右分支赋1,则从根到每个叶子的路径上,各分支的赋值分别构成一个二进制串,该二进制串就称为哈夫曼编码。
哈夫曼编码的基本思想是:为出现次数较多的字符编以较短的编码,在压缩原理中有重要作用。


如图,各叶子对应哈夫曼编码。
哈夫曼编码表的存储表示:

typedef char** HuffmanCode;

利用二级指针存储每个叶子的哈夫曼编码。


根据哈夫曼树求哈夫曼编码

void CreateHuffmanCode(HuffmanTree H,HuffmanCode &HC,int n)
{HC=new char*[n+1];char* cd=new char[n];cd[n-1]='\0';for (int i = 1; i <= n; i++){int start=n-1;int c=i;int f=H[i].parent;while (f!=0){--start;if (H[f].lchird==c){cd[start]='0';}else cd[start]='1';c=f;f=H[f].parent;}HC[i]=new char[n-start];strcpy(HC[i],&cd[start]);}delete cd;
}

利用cd存储每个字符的哈夫曼编码,start指向最后一个位置,f指向当前节点的双亲节点,c储存当前节点的下标。
不断向上遍历,若当前节点是双亲的左儿子就赋值0,右儿子就赋值1。
继续更新f和c向上遍历,直到走到树根,f==0(树根双亲域为0)。
接着申请[n-start]空间的内存,将求得的编码从临时空间cd复制到HC的当前行中。

哈夫曼树可以不是唯一的,只要满足和带权路径长度最小值相等的树都是哈夫曼树。显然,哈夫曼编码也不唯一。


测试代码

int main()
{HuffmanTree H;HuffmanCode HC;int n;cin>>n;InitHuffmanTree(H,n);CreateHuffmanTree(H,n);CreateHuffmanCode(H,HC,n);for (int i = 1; i <= n; i++){cout<<HC[i]<<endl;}return 0;
}

运行实例

详解哈夫曼树和哈夫曼编码相关推荐

  1. 数据结构图文解析之:哈夫曼树与哈夫曼编码详解及C++模板实现

    0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...

  2. 哈夫曼树(霍夫曼树)-详解

    哈夫曼树(霍夫曼树)-详解 哈夫曼树(霍夫曼树)-详解 何为权值?我们看下百度百科的解释. 何为路径? 何为路径长度? 何为树的路径长度? 何为结点的带权路径长度? 何为树的带权路径长度(WPL)? ...

  3. 哈夫曼树、哈夫曼编码详解

    哈夫曼树介绍 hello,大家好,我是bigsai.本以为哈夫曼树.哈夫曼编码很难,结果很容易嘛! 哈夫曼树.哈夫曼编码很多人可能听过,但是可能并没有认真学习了解,今天这篇就比较详细的讲一下哈夫曼树. ...

  4. 哈夫曼树及哈夫曼编码详解

    一.预备知识 • 结点的路径长度:从根结点到该结点的路径上所包括的边的数目: • 树的内路径长度:除叶结点外,从根到树中其他所有结点的路径长度之和: • 树的外路径长度:从根结点到树中所有叶子结点的路 ...

  5. 哈夫曼树(赫夫曼树、最优树)详解

    赫夫曼树,别名"哈夫曼树"."最优树"以及"最优二叉树".学习哈夫曼树之前,首先要了解几个名词. 哈夫曼树相关的几个名词 路径:在一棵树中, ...

  6. 【数据结构】-哈夫曼树以及哈夫曼编码

    哈夫曼树的几个定义 哈夫曼树又叫最优二叉树:特点是带权路径最短 带权路径长度:该结点到根结点的路径长度乘以该结点的权值. 树的带权路径长度(WPL):所有叶子结点到根结点的带全路径长度之和. 最优二叉 ...

  7. 【Java数据结构与算法】第十二章 哈夫曼树和哈夫曼编码

    第十二章 哈夫曼树和哈夫曼编码 文章目录 第十二章 哈夫曼树和哈夫曼编码 一.哈夫曼树 1.基本术语 2.构建思路 3.代码实现 三.哈夫曼编码 1.引入 2.介绍 3.代码实现哈夫曼编码综合案例 一 ...

  8. 【数据结构】树与树的表示、二叉树存储结构及其遍历、二叉搜索树、平衡二叉树、堆、哈夫曼树与哈夫曼编码、集合及其运算

    1.树与树的表示 什么是树? 客观世界中许多事物存在层次关系 人类社会家谱 社会组织结构 图书信息管理 分层次组织在管理上具有更高的效率! 数据管理的基本操作之一:查找(根据某个给定关键字K,从集合R ...

  9. 哈夫曼树和哈夫曼编码应用之图片压缩编码c++实现

    本人正在学习数据结构,在前几天做了压缩图片的项目,感觉到有必要分享给大家.因此今天我就分享给大家c语言数据结构有关哈夫曼树压缩图片的项目实现. 一:下面先介绍有关的知识: 1.背景 压缩软件是用特定算 ...

  10. Huffman霍夫曼树,霍夫曼编码

    霍夫曼树基本概念: 路径:从一个结点往下到孩子或孙子结点之间的同理 路径长度:如结点1到结点7的路径长度=2 结点的权:将结点的某一属性值作为结点的权 带权路径长度:从根节点到该结点*该结点的权:如结 ...

最新文章

  1. 浅析营销型网站SEO优化的四大原则!
  2. 机器学习经典分类算法 —— C4.5算法(附python实现代码)
  3. python 接口自动化测试_python接口自动化测试之接口数据依赖
  4. vue中 使用md5加密
  5. Springboot集成axis1.4
  6. BZOJ 1041 数学
  7. Tensorflow2.0:使用Keras自定义网络实战
  8. boost安装_Boost编译与使用
  9. chattr和lsattr的基本用法
  10. qt定时器暂停与重新开始_Qt编写自定义控件22-蚂蚁线
  11. T61|NV显卡门|根据售后维修部数据显示爆发期来临|预防显卡门|解决显卡门
  12. veeam_backup的几种备份方式
  13. Verilog 练习 7段数码管译码器
  14. C# Word文档添加水印
  15. 微信这几个好用的功能,你该知道
  16. CAD自学笔记21条,零基础学CAD可以看看
  17. 径向渐变加阴影html,CSS径向渐变阴影 - 反转
  18. 编译原理实验一:词法分析程序设计与实现
  19. 安卓 7.0 无法获取外置SD卡问题解决方案 | Failed to find configured root that contains
  20. 英语dyamaund钻石dyamaund单词

热门文章

  1. Unity场景打包AssetBundle并加载
  2. LoadRunner教程(22)-LoadRunner C语言脚本
  3. Objective-C 函数
  4. ret2text涉及到的堆栈平衡问题
  5. 老电脑xp系统最流畅的浏览器_1步打造极限精简的win10系统,让老电脑像新机般流畅,再也不卡了...
  6. 小川opencv100例 之 准备食材 之 读取视频
  7. python实例(二):判断输入的车牌归属地
  8. 如何在SOLIDWORKS中使用PDM模板?
  9. android最新adt下载地址,Android SDK和最新ADT下载地址
  10. 防火墙服务器-iptables