数据结构15————哈夫曼树
来源:互联网 发布:杰科网络电视机顶盒gk 编辑:程序博客网 时间:2024/06/07 23:45
数据结构15————哈夫曼树
一.内容
1.哈夫曼树的定义和原理
2.哈夫曼树的建立
3.哈夫曼编码
4.哈夫曼算法的实现
- 结构体的设计
- 哈夫曼树的建立
- 编码
- 解码
- 带权路径长(WPL)
二.哈夫曼树的定义和原理
1.哈夫曼树的定义及作用
哈夫曼树的又称为最优二叉树,是带权路径最短的树,可用来构造最优编码,常用于数据压缩和信息传递
2.哈夫曼树的相关概念
- 路径:从一个结点到另一个结点之间的分支路径
- 路径长度:从一个结点到另一结点所经过的分支数目
- 结点的权值:树中每个结点所赋予的具有某种实际意义的实数
- 带权路径长度:从树根到某一结点的路径长度与该结点的权的乘积。
- 树的带权路径长度(WPL):树中从根到所有叶子结点的各个带权路径长度之和。
如图所示的树,其WPL=7x4+9x4+5x3+4x2+2x1=89
所以哈夫曼树就是,相同叶子结点所构成的树中,WPL最小的一颗。
三.哈夫曼树的建立
如果给定叶子节点的权值,如何构造出一颗WPL最小的树呢?这个过程就是构造哈夫曼树的过程
1.思想
每次选择节点集合中最小的两个节点,构成一颗树,根节点的权值为两个之和,将根节点加入节点集合,重复上述过程。
形式化表述
1.根据给定的n个权值{w1,w2……wn},构造出n颗二叉树的集合F={T1.T2……Tn},其中每一棵二叉树均只含一个带权值为wi的根节点,其左右子树为空树
2.在F中选择其根节点为权值最小的两颗二叉树,分别作为左右子树构造出一颗新的二叉树。并置这颗新树根节点权值为左右根节点的权值之和。
3.在F中删去这两棵树,同时加入新生成的树
4.重复23过程,直到F中只剩一颗树为止。
2.例
3.如何存储
哈夫曼树的存储可以使用三叉链表和静态三叉链表,为了简单考虑,一般选择静态三叉链表来实现哈夫曼树的存储
4.静态三叉链表实现二叉树的存储
四.哈夫曼编码
我们前文说过,哈夫曼树主要应用是在数据压缩信息传递中,而如何应用哈夫曼树进行数据的压缩,这就涉及到哈夫曼树编码。
1.编码
编码是什么?
举个例子如果我们需要通过网络传输一段文字;ABCDEFGH,那么很容易想到,让A=000,B=001,C=010,D=011,F=100,G=101,H=111。所以ABCDEFG就可以表示为000.001.010.011.100.101.110.111。通过这个规则,就可以表示ABCDEFG所构成的任意一段文字。文字转换出的二进制就是编码。
上面的编码可以解决大部分的问题,但是否可以进行更好的优化,比如让它编码后的二进制长度尽可能的达到更小。
如何达到呢?我们可以通过让出现频率大的编码尽可能的短,出现概率小的编码啊可以适当的长点。但是存在一个问题,比如说AB出现的频率大,让A=0,B=1,C出现的频率小,让C=01。那么问题来了,01代表AB还是代表C。所以如果要设计长度不等的编码必须满足
任何一个字符编码都不是另一个字符的编码的前缀,这种编码就是前缀编码
2.哈夫曼编码
哈夫曼编码就是一种前缀编码,而且是编码后最短的前缀编码。
哈夫曼树的构建
将每个字符出现的次数作为权值,按照哈夫曼树的构建过程组成的一颗二叉树
哈夫曼编码
从哈夫曼树的根节点出发,左子树输出0,右子树输出1。知道达到叶子节点后停止,此时输出的二进制就是该叶子节点的哈夫曼编码
3.例
五.哈夫曼算法
我的代码设计未舍弃下标为0的位置,所以叶子节点从0开始
1.结构体的设计
#include <stdio.h>#define N 30#define M 2*N-1typedef struct{ int weight; char data; int parent,Lchild,Rchild;}HTNode,HuffmanTree[M+1];
2.哈夫曼树的建立
void CrtHuffmanTree(HuffmanTree ht,int n){ //创建哈夫曼树 int m=2*n-1; int i; int s1,s2; for(i=0;i<n;i++){ //初始化叶子节点 scanf("%d",&ht[i].weight); ht[i].data = 'A'+i; ht[i].parent=-1; ht[i].Lchild=-1; ht[i].Rchild=-1; } for(i=n;i<m;i++){ //初始化非叶子节点 ht[i].weight=0; ht[i].parent=-1; ht[i].Lchild=-1; ht[i].Rchild=-1; } for(i=n;i<m;i++) //创建哈夫曼树 { seek(ht,i,&s1,&s2); //寻找ht中i之前最小的两个元素下标,s1<s2; ht[s1].parent=i; ht[s2].parent=i; ht[i].weight = ht[s1].weight+ht[s2].weight; ht[i].Lchild = s1; ht[i].Rchild = s2; }}void seek(HuffmanTree ht,int n,int *s1,int *s2){ //寻找ht中i之前最小的两个元素下标,s1<s2; int i,j; for(i=0;i<n&&ht[i].parent!=-1;i++); //s1,s2的初始化 j=i; i++; for(;i<n&&ht[i].parent!=-1;i++); *s1 = ht[i].weight<ht[j].weight?i:j; *s2 = ht[i].weight<ht[j].weight?j:i; i++; while(i<n){ if(ht[i].parent!=-1){ }else if(ht[i].weight<ht[*s1].weight){ *s2 = *s1; *s1 = i; }else if(ht[i].weight<ht[*s2].weight){ *s2 = i; } i++; }}
3.输出所有字符的编码
void codinghuffman(HuffmanTree ht,int n){ //编码所有的叶子节点 int i,j; char str[N]; int p,q; //p当前节点,q是p的双亲节点 for(i=0;i<n;i++){ p=i; for(j=0;ht[p].parent!=-1;j++){ q=ht[p].parent; if(p==ht[q].Lchild){ //如果是左节点,则为0 str[j]='0'; }else{ //如果是右节点,则为1 str[j]='1'; } p=ht[p].parent; } printf("%c:",ht[i].data); //打印结果 for(j=j-1;j>=0;j--){ printf("%c",str[j],j); } printf("\n"); }}
4.编码字符串
void aCodinghuffman(HuffmanTree ht){ //编码字符串 int i,j; char in[N]; char str[N]; int p,q; getchar(); gets(in); for(i=0;in[i];i++){ //遍历每个字母 p=in[i]-'A'; //确定该叶子节点存储的位置,这句根据具体问题而定 for(j=0;ht[p].parent!=-1;j++){ //解码每个字母 q=ht[p].parent; if(p==ht[q].Lchild){ //如果是左孩子 str[j]='0'; }else{ //如果是右孩子 str[j]='1'; } p=ht[p].parent; } for(j=j-1;j>=0;j--){ //打印结果 printf("%c",str[j],j); } } printf("\n");}
5.译码
void decodeHuffmanTree(HuffmanTree ht,int n){ //译码 int i,j; char str[N]; int p=2*n-2; // p当前节点,p当前节点儿子 gets(str); for(i=0;str[i];i++){ if(str[i]=='1'){ p = ht[p].Rchild; }else if(str[i]=='0'){ p = ht[p].Lchild; } if(ht[p].Lchild==-1&&ht[p].Rchild==-1){ //当前字段解码完毕 printf("%c",ht[p].data); p =2*n-2; } } }
6.带权路径长(WPL)
int WPL(HuffmanTree ht,int n){ int wpl=0; int h; int p; int i; for(i=0;i<n;i++){ h=0; for(p=i;ht[p].parent!=-1;p=ht[p].parent){ h++; } wpl = wpl+ h*ht[i].weight; } return wpl;}
六.源代码
text15中
参考资料《大话数据结构》《数据结构与算法分析》
- 【数据结构——哈夫曼树】
- 数据结构——什么是数据结构
- 【大话数据结构】——-数据结构
- 数据结构 —— 数据结构概述
- [数据结构]数据结构——链表法
- 数据结构—哈夫曼树
- 数据结构15————哈夫曼树
- 数据结构例程——哈夫曼树
- 数据结构——哈夫曼树实现
- PHP数据结构之一:PHP数据结构基本概念—数据结构
- 数据结构——基本数据结构之栈
- 数据结构——基本数据结构之队列
- 数据结构——基本数据结构之有根树
- 数据结构——基本数据结构之栈
- 数据结构——基本数据结构之队列
- 数据结构——大话数据结构源码
- 数据结构学习总结——数据结构概述
- 大话数据结构——数据结构绪论
- 苹果操作系统:安装Ubuntu1604虚拟机实例并配置bitcoin代码编译开发环境
- SNMP++在vs2008下的编译
- 利用Python向mysql插入中文时出错的解决办法
- ALLEGRO光绘文件生成常用项(二层)
- AdaBoost
- 数据结构15————哈夫曼树
- (C++)用迭代法求 。求平方根的迭代公式为: X[n+1]=1/2(X[n]+a/X[n]) 要求前后两次求出的得差的绝对值少于0.00001。 输出保留3位小数
- ros中串口的使用
- 给自己定个小目标_Java入门
- QML之自定义模态可拖拽窗口
- 替换空格(java)
- 解决Android 离线文档 不能搜索的问题
- AndroidStudio音乐播放器进度条和歌曲时间的操作
- 微信聊天记录删除快速恢复教程