第17讲 哈夫曼树

合集下载

哈夫曼树

哈夫曼树


A:0
B:110
C:10
D:111 总长度是13
发送方:将ABACCDA 发送方 将ABACCDA
转换成 0110010101110
所得的译码是唯一的。
霍夫曼树 和 编码
思想:根据字符出现频率编码,使电文总长最据字符出现频率构造Huffman树,然后将树中结点引 向其左孩子的分支标 0 向其左孩子的分支标“0”,引向其右孩子的分支标 1 ;每 引向其右孩子的分支标“1”;每 个字符的编码即为从根到每个叶子的路径上得到的0、1序列。 要传输的字符集 D={C, A, S, T, ; }
霍夫曼树 和 编码
如何得到使二进制串总长最短编码 构造以字符使用频率 作为权值的哈夫曼树 a: b: c: d: e: f: g: h: h 0110 10 1110 1111 110 00 0111 010
100 42 23 11 5 19 8 3 29 14 7 58 29 15 8
霍夫曼树 和 编码
霍夫曼编码树
霍夫曼树 和 编码
在进行数据通讯时,涉及数据编码问题。所谓数据编码就 是数据与二进制字符串的转换。 例如:邮局发电报 原文 发送方 要传输的原文为ABACCDA 等长编码 A:00 B:01 C:10 D:11 发送方:将ABACCDA 转换成 00010010101100 接收方:将 接收方 将 00010010101100 还原为 ABACCDA 电文(二进制字符串) 接收方 原文
的二叉树,置新二叉树根结点权值为其左右子树上根结 点权值之和。
删除这两棵树,同时将新得到的二叉树加入集合中。 除 两棵树 同时将新得到的 叉树加 集合中 重复上述两步,直到集合中只含一棵树为止,这棵树即
是哈夫曼树

哈夫曼树的构造

哈夫曼树的构造

哈夫曼树的构造今天的内容,主要是给大家介绍如何通过哈夫曼树,构建一个可供其他人访问的应用程序。

今天我们首先来看一段简单的视频,哈夫曼树是一种可用于建立网络节点之间关系以及通过这些关系传递网络信息的分布式节点树。

对于区块链项目而言,这一点尤为重要。

它不仅能解决一些应用程序在运行过程中无法发现问题,而且它还能实现去中心化,以及分布式存储,使项目更加安全。

这是区块链技术在数字经济领域应用最为广泛和成功的一个表现形式。

因此我们今天主要来讲解一下一个可用于建立网络节点之间关系以及通过网络信息给用户的哈夫曼树。

这个结构是由三个节点(每一个节点)组成。

1.每个节点都有自己的密钥(节点名称)每个节点都有自己的密钥,这是为了保证这些密钥是安全的。

因为每一个访问该节点的用户都会看到自己的隐私(例如姓名、出生日期等)。

密钥和哈夫曼树的节点是彼此独立的,而不是彼此关联的。

每个密钥只有一个随机数。

如果不符合哈夫曼(Hoffman)所定义的条件,那么这颗树木将无法被接受而且它会破坏整个树的结构。

一旦产生新的节点加入了哈夫曼树时,它就会有一个新的随机数产生哈夫曼信号:这个信号将被认为能使其具有可被使用的性能以及可扩展性;从这个定义来看,它就有这样一个优点:可以有效防止恶意攻击者盗取密钥并使整个网络安全高效;并能保证每个节点都能获取到正确信息进行验证。

这意味着每个节点都有自己独立而又安全的密钥和一个可以被使用以及验证过(不被其他人知道)这样一个重要节点来传递网络信息!;所以哈夫曼树中就出现了这样一句话:“区块链技术不能通过改变现有规则来改变现有制度”!首先我们要了解如何构建一个哈夫曼树应用程序以及如何通过哈夫曼构建其应用程序来实现哈夫曼树并使其更加安全?对于一个简单而且非常有用!要注意哈夫曼树还可以实现分布式存储和去中心化网络中可追溯数据库信息能够被访问节点看到这些信息并且它可以被安全地存储到哈夫曼树中并且被其他人访问2.每一个节点都由一定数量的节点(例如1个)组成每个节点都有自己的独特功能,可以对网络中正在运行的程序或系统进行交互并存储数据。

哈夫曼树的构造

哈夫曼树的构造

45
0
1
19
0
1
26
0
1
9
10
11 15
A0
1 B0
1
55
7
8
C 0
1D
E
2
3
F
G
谢谢学习
主讲教师:尹红丽
0
1
a
0
1
c
0
1
b
d
约定左分支表示字符‘0’
右分支表示字符‘1’
3
哈夫曼编码
例:一组字符{A, B, C, D, E, F, G}出现的频率分别是{9, 11, 5, 7, 8, 2, 3},
设计最经济的编码方案。 编码:
A: 00 B : 10 C : 010 D: 110 E : 111 F : 0110 G : 0111
ABCD 00 01 10 11
不等长编码: 为了缩短传送信息的总长度,让出现频率高的字符具有
较短的编码,出现频率低的字符具有较长的编码
ABCD
1 10 0 01 发送:A B A C C C C D A B
1 10 1 0 0 0 0 01 1 10—长度为13 1101可以译为AACA、ABA、AAD 为此引入前缀编码的概念
2 34 7
2
3 47
7
4 23
WPL=2×2+3×2+4×2+7×2 =32
WPL=2×1+3×2+4×3+7×3 =41
WPL=2×3+3×3+4×2+7×1 =30
特点:权值越大的叶子结点越靠近根结点,权值越小的叶子结点越远离根结点。
2 哈夫曼树的构造

哈夫曼树

哈夫曼树

实验4.2 最优二叉树(哈夫曼树)一、实验的目的要求1、了解树和哈夫曼树的特性,以及它们在实际问题中的应用。

2、掌握树和哈夫曼树的实现方法以及它们的基本操作,学会运用树和二叉树来解决问题。

二、实验的主要内容1、请设计一个算法,对于给定的n个结点的权值,建立一棵哈夫曼树。

具体要求如下:①算法输入:n个结点的权值。

②算法输出:哈夫曼树,打印出哈夫曼树的所有的结点序号、双亲结点、左孩子、右孩子和权值。

③测试数据:⑴设结点数n=7,权值分别为7、5、2、3、8、10、20;⑵设结点数n=8,权值分别为7、19、2、6、32、3、21、10。

三、解题思路建立哈夫曼树,然后对哈夫曼树进行操作。

四、原程序清单//c++程序#include<iostream>#include<string>#include<stdlib.h>using namespace std;#define MAXVAL 10000000 //定义一个足够大的数,方便之后的操作typedef int datatype;typedef struct//定义哈夫曼树结构体类型{double weight; //结点的权值int num;datatype lchild,rchild,parent; //结点的左、右孩子指针和父指针} htree;htree tree[100]; //定义全局变量,方便操作int n,m,flag=1; //n表示预处理的结点数,m表示处理的结点总数void create() //建立哈夫曼树的函数{int i,j,p1,p2; //i,j用于循环语句,p1、p2用于记录操作结果double small1,small2,w; //操作的中间变量cout<<"\n 请输入预处理的结点数:";cin>>n;m=2*n-1;if(n<=0){printf("\n*****************************************************\n");printf(" 这是一棵空树\n");printf("*****************************************************\n");return;}printf("\n*****************************************************\n");printf(" 请依次输入个结点的权值(各权值以空格隔开)\n");printf("*****************************************************\n");for(i=1;i<=n;i++) //为n个结点初始化{cin>>w;tree[i].weight=w;tree[i].num=i;tree[i].parent=0;tree[i].lchild=0;tree[i].rchild=0;}for(i=n+1;i<=m;i++){p1=0;p2=0;small1=MAXVAL;small2=MAXVAL;for(j=1;j<=i-1;j++)if(tree[j].parent==0){if(tree[j].weight<small1){small2=small1;small1=tree[j].weight;p2=p1;p1=j;}else if(tree[j].weight<small2){small2=tree[j].weight;p2=j;}}tree[p1].parent=i;tree[p2].parent=i;tree[i].num=i;tree[i].parent=0;tree[i].lchild=p1;tree[i].rchild=p2;tree[i].weight=tree[p1].weight+tree[p2].weight;}printf("\n*****************************************************\n");printf(" 哈夫曼树初始化完毕\n");printf("*****************************************************\n"); }void print1(htree t) //用于输出哈夫曼树的先序序列{cout<<'\t'<<'\t'<<t.num<<'\t'<<t.weight<<endl;if(t.lchild!=0)print1(tree[t.lchild]);if(t.rchild!=0)print1(tree[t.rchild]);}void print2(htree t) //用于输出哈夫曼树的中序序列{if(t.lchild!=0)print2(tree[t.lchild]);cout<<'\t'<<'\t'<<t.num<<'\t'<<t.weight<<endl;if(t.rchild!=0)print2(tree[t.rchild]);}void print3(htree t) //用于输出哈夫曼树的中序序列{if(t.lchild!=0)print3(tree[t.lchild]);if(t.rchild!=0)print3(tree[t.rchild]);cout<<'\t'<<'\t'<<t.num<<'\t'<<t.weight<<endl;}int high(htree t) //计算哈夫曼树的高度{int a,b;if(t.lchild==0&&t.rchild==0)return 1;a=high(tree[t.lchild])+1;b=high(tree[t.rchild])+1;if(a>b)return a;return b;}int main(){string i,j;while(1){printf("\n*****************************************************\n");printf(" 欢迎使用菜单驱动程序\n");printf("*****************************************************\n");if(flag==1){printf(" 1.初始化哈夫曼树\n"); //第一级菜单printf(" 2.清屏\n");printf(" 3.结束操作\n");printf("\n 请选择您要的操作:");cin>>i;if(i=="1"){create();flag=0;}else if(i=="2")system("cls");else if(i=="3"){printf("\n*****************************************************\n");printf(" 谢谢使用,再见\n");printf("*****************************************************\n");return 1;}else{printf("\n*****************************************************\n");printf(" 操作错误\n");printf("*****************************************************\n");}continue;}printf(" 1.重新初始化哈夫曼树\n"); //第二级菜单printf(" 2.输出哈夫曼树的高度\n");printf(" 3.输出哈夫曼树的叶子结点的个数\n");printf(" 4.输出哈夫曼树\n");printf(" 5.清屏\n");printf(" 0.结束操作\n");printf("\n 请选择您要的操作:");cin>>i;if(i=="1")create();else if(i=="2"){if(n==0){printf("\n*****************************************************\n");printf(" 这是一棵空树,高度为0\n");printf("*****************************************************\n");}else{printf("\n*****************************************************\n");printf(" 该树的高度为%d\n",high(tree[m]));printf("*****************************************************\n");}}else if(i=="3"){if(n==0){printf("\n*****************************************************\n");printf(" 这是一棵空树,叶子结点的个数为0\n");printf("*****************************************************\n");}else{printf("\n*****************************************************\n");printf(" 该树的叶子结点的个数为%d\n",n);printf("*****************************************************\n");}}else if(i=="4"){if(n==0){printf("\n*****************************************************\n");printf(" 这是一棵空树\n");printf("*****************************************************\n");continue;}while(1){printf("\n*****************************************************\n");printf(" 欢迎使用菜单驱动程序\n");printf("*****************************************************\n");printf(" 1.输出哈夫曼树的先序序列\n"); //第三级菜单printf(" 2.输出哈夫曼树的中序序列\n");printf(" 3.输出哈夫曼树的后序序列\n");printf(" 4.返回上层\n");printf(" 5.清屏\n");printf(" 0.结束操作\n");printf("\n 请输入您要的操作:");fflush(stdin);cin>>j;if(j=="1"){printf("\n*****************************************************\n");printf(" 哈夫曼树的先序序列如下(左为结点序号,右为为结点权值)\n");printf("*****************************************************\n");print1(tree[m]);}else if(j=="2"){printf("\n*****************************************************\n");printf(" 哈夫曼树的中序序列如下(左为结点序号,右为为结点权值)\n");printf("*****************************************************\n");print2(tree[m]);}else if(j=="3"){printf("\n*****************************************************\n");printf(" 哈夫曼树的后序序列如下(左为结点序号,右为为结点权值)\n");printf("*****************************************************\n");print3(tree[m]);}else if(j=="4")break;else if(j=="5")system("cls");else if(j=="0"){printf("\n*****************************************************\n");printf(" 谢谢使用,再见\n");printf("*****************************************************\n");return 1;}else{printf("\n*****************************************************\n");printf(" 操作错误\n");printf("*****************************************************\n");}}}else if(i=="5")system("cls");else if(i=="0"){printf("\n*****************************************************\n");printf(" 谢谢使用,再见\n");printf("*****************************************************\n");return 1;}else{printf("\n*****************************************************\n");printf(" 操作错误\n");printf("*****************************************************\n");}}}五. 调试小结(1).遇到的问题及解决方法1.输出函数中没有提示语句;2.p1,p2赋值错误;(2). 算法复杂度分析本实验纯属一般操作。

哈夫曼树.ppt

哈夫曼树.ppt

n
w i pi
最小,其中
i 1
Wi是第i个字符的使用频度,而Pi是第i个字符的编码长度, 这正是度量报文的平均长度的式子。
2020/3/5
21
例2:要传输的电文是{CAS;CAT;SAT;AT}
要传输的字符集是 D={C,A,S,T, ;}
每个字符出现的频率是W={ 2,4, 2,3, 3 }
PL=0+1+1+2+2=6
2020/3/5
9
问题2:什么样的带权树路径长度最小?
例如:给定一个权值序列{2,3,4,7},可构造的多种 二叉树的形态。
2
3
4
7
2 34 7
(a) WPL=2×2+2×3+2×4+2×7=32 (b) WPL=1×2+2×3+3×4+3×7=41
2020/3/5
7
4
3
2
(c) WPL=1×7+2×4+3×3+3×2=30
10
哈夫曼树的构造
例:给定权值{7,5,2,4},构造哈夫曼树。
6
方法: 75 2 4
75
(1)a 初始b化:由c 原始d数据生成森林a ; b c
d
(次2小)的找二最叉小(树a树) 作:为在左森右林子中树选构取造两一棵棵根新结的点二权叉值树最(,小b)其的根和
A)先序遍历
B)中序遍历
C)后序遍历
D)从根开始进行层次遍历
2、某二叉树的先序序列和后序序列正好相反,则该二叉
树一定是( B )的二叉树。
A)空或只有一个结点
B)高度等于其结点数
C)任一结点无左孩子
D)任一结点无右孩子

重学数据结构之哈夫曼树

重学数据结构之哈夫曼树

重学数据结构之哈夫曼树一、哈夫曼树1.带权扩充二叉树的外部路径长度扩充二叉树的外部路径长度,即根到其叶子节点的路径长度之和。

例如下面这两种带权扩充二叉树:左边的二叉树的外部路径长度为:(2 + 3 + 6 + 9) * 2 = 38。

右边的二叉树的外部路径长度为:9 + 6 * 2 + (2 + 3) * 3 = 36。

2.哈夫曼树哈夫曼树(Huffman Tree)是一种重要的二叉树,在信息领域有重要的理论和实际价值。

设有实数集W = {W0 ,W1 ,···,W m-1 },T 是一颗扩充二叉树,其m 个外部节点分别以W i (i = 1, 2, n - 1) 为权,而且T 的带权外部路径长度在所有这样的扩充二叉树中达到最小,则称T 为数据集W 的最优二叉树或者哈夫曼树。

二、哈夫曼算法1.基本概念哈夫曼(D.A.Huffman)提出了一个算法,它能从任意的实数集合构造出与之对应的哈夫曼树。

这个构造算法描述如下:算法的输入为实数集合W = {W0 ,W1 ,···,W m-1 }。

在构造中维护一个包含k 个二叉树集合的集合F,开始时k=m 且F = {T0 ,T1 ,···,T m-1 },其中每个T i 是一颗只包含权为W i 的根节点的二叉树。

该算法的构造过程中会重复执行以下两个步骤,直到集合F 中只剩下一棵树为止:1. 构造一颗二叉树,其左右子树是从集合 F 中选取的两颗权值最小的二叉树,其根节点的权值设置为这两颗子树的根节点的权值之和。

2. 将所选取的两颗二叉树从集合 F 中删除,把新构造的二叉树加入到集合F 中。

注意:给定集合W 上的哈夫曼树并不唯一!2.示例对于实数集合W = {2, 1, 3, 7, 8, 4, 5},下面的图1到图7 表示了从这个实数集合开始,构造一个哈夫曼树的过程:图1:图2:图3:图4:图5:图6:图7:三、哈夫曼算法的实现1.实现思路要实现哈夫曼算法,需要维护一组二叉树,而且要知道每颗二叉树的根节点的权值,这个可以使用前面定义的二叉树的节点来构造哈夫曼树,只需要在根节点处记录该树的权值。

数据结构哈夫曼树

数据结构哈夫曼树

数据结构哈夫曼树哈夫曼树(Huffman tree)是一种用于编码的树形数据结构,由美国计算机科学家大卫·哈夫曼(David A. Huffman)于1952年提出。

它是一种利用最高频率字符具有最短编码长度的特性来进行数据压缩的算法。

在介绍哈夫曼树之前,我们先来了解一下哈夫曼编码(Huffman coding)。

哈夫曼编码是一种变长前缀编码,即每个字符的编码长度不固定,不会出现编码前缀相同的情况,具有唯一可解码性。

它是为了满足字符编码长度尽可能短且无编码前缀相同的要求而产生的。

构建哈夫曼树的过程可以分为以下几步:1.统计字符频率:首先对于需要压缩的文件,统计每个字符出现的频率。

频率可以理解为该字符出现的次数。

统计之后,可以得到每个字符与其对应的频率。

2.构建节点:将每个字符以及其频率作为叶子节点构建成一个森林(每个节点都是一个独立的树)。

3.合并节点:从森林中选取频率最小的两个节点合并为一个新的节点,频率为其子节点频率之和。

将新的节点继续加入森林中,重复此过程,直到森林中只剩下一个节点为止。

4.构建哈夫曼树:最后剩下的那个节点就是哈夫曼树的根节点。

从构建的过程可以看出,频率较高的字符会位于树的较低层,而频率较低的字符会位于树的较高层。

5.生成编码:根据哈夫曼树的特点,路径的左边为0,右边为1,从根节点开始,走到每个叶子节点的路径就是该叶子节点的哈夫曼编码。

通过以上步骤,我们就构建了一颗哈夫曼树,并生成了对应的哈夫曼编码。

利用哈夫曼编码,可以将原始数据进行压缩,使其占用的存储空间减小。

举个例子来说明哈夫曼树的构建过程和编码生成过程:假设有一个包含5个不同字符的文件,每个字符及其频率如下:A:5B:9C:12D:13E:16首先按照步骤1统计字符频率,得到每个字符及其频率。

然后按照步骤2构建叶子节点,每个字符和其频率构成一个叶子节点。

接着按照步骤3合并节点,选取频率最小的两个节点合并为一个新的节点,直到森林中只剩下一个节点。

哈夫曼树

哈夫曼树

哈夫曼树及其应用路径长度树中一个结点到另一个结点之间的路径由这两个结点之间的分枝构成,路径上的分枝数目称为它的路径长度。

由树的定义可知,从根结点到达树的每个结点有且仅有一条路径。

我们曾规定树的根的层数为1,如果树中某个结点的层数为k ,则从树的根到该结点的路径长度为(k-1)。

例如,在图1(a )中,从根A 到结点B 、C 、D 、E 、F 、G 、H 的路径长度分别为1、1、2、2、3、3、4。

树的路径长度是从树的根结点到树的各个结点的路径长度之和,记作PL 。

例如,图1所示的3棵二叉树的路径长度分别为:PL(a) = 0+1+1+2+2+3+3+4 = 6 PL(b) = 0+1+1+2+2+2+2+3 = 13 PL(c) = 0+1+1+2+2+2+2+3 = 13由于二叉树中第k 层的结点最多为2k-1个,而树的根到第k 层的结点的路径长度为k-1,换句话说,二叉树中路径长度为k-1的这样的结点最多有2k-1个。

显然,在n 个结点的各二叉树中,完全二叉树具有最小的路径长度。

例如,图1(b )所示为完全二叉树,其路径长度是13。

但具有最小路径长度的不一定是完全二叉树。

例如,图1(c )所示为非完全二叉树,它也具有最小路径长度。

一般来说,若深度为k 的n 个结点的二叉树具有最小路径长度,那么从根结点到第k-1层具有最多的结点数2k-1-1,余下的n-2k-1+1个结点在第k 层的任一位置上。

哈夫曼树首先我们考虑带权的二叉树。

假如给定一个有n 个权值的集合{w 1,w 2,…,w n },其中wi ≥0(1≤i ≤n )。

若T 是一棵有n 个叶子的二叉树,而且将权w 1,w 2,…,w n 分别赋给T 的n 个叶子,那么我们称T 是权w 1,w 2,…,w n 的二叉树。

叶子的带权路径长度为T 的根到该叶子之间的路径长度与该叶子中权的乘积。

n 个叶子的二叉树的带权路径长度定义为:∑==ni i i l w WPL 1其中:w i 为叶子i 的权,l i 为根结点到叶子i 之间的路径长度。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

根据给定的 n 个权值 {w1, w2, …, wn},
F = {T1, T2, … , Tn},
其中每棵二叉树中均只含一个带权值
为 wi 的根结点,其左、右子树为空树;
(2) 在 F 中选取其根结点的权值为最 小的两棵二叉树,分别作为左、
右子树构造一棵新的二叉树,并
置这棵新的二叉树根结点的权值 为其左、右子树根结点的权值之
Huffman码的WPL=2(0.19+0.32+0.21) + 4(0.07+0.06+0.10) +5(0.02+0.03)
=1.44+0.92+0.25=2.61
二进制等长码的WPL=3(0.19+0.32+0.21+0.07+0.06+0.10+0.02+0.03)=3
√ —√ 11
— 17 — 40
√ — 28√ 60 100
0
0
0
0
0
0
请注意:赫夫曼 树样式不惟一, 编程时应该有约 定
2 c
3 f
对应的赫夫曼编码:
符 编码 1110 00 11010 1100 10 11011 01 1111 频率 符 编码
按左0右1标注
频率
100
0
0 40 1 0
1
60 1
p
0 0
l
0 0 0 0 0 0 0 0 0 3 0 4 0
r
0 0 0 0 0 0 0 0 0 6 0 9 0
左右孩子
100
40 19 b
60 21 32 28 g e 11
9 √ 0 6 √ 10 0
32
√ 3 √
0 0 9 0 0 0 10 0 0
17
7 a 10 h
21√ 10√ —5
d
6
5
解:先将概率放大100倍,以方便构造赫夫曼树。 放大后的权值集合 w={ 7, 19, 2, 6, 32, 3, 21, 10 }, 按赫夫曼树构造规则(合并、删除、替换),可得到赫夫曼树。
w={ 7, 19, 2, 6, 32, 3, 21, 10 }在机内存储形式为:
双亲
w
1 2 3 4 5 6 7 8 9 10 11 12 13 7√ 19√ 2
A : 0 T : 10 C : 110 S : 111 它的总编码长度:7*1+5*2+( 2+4 )*3 = 35。 比等长编码的情形要短。 总编码长度正好等于哈夫 1 0 曼树的带权路径长度WPL。 7 1 0 赫夫曼编码是一种无前缀 5 0 编码。解码时不会混淆。 1
2 4
赫夫曼编码树
前缀编码
和;
(3) 从F中删去这两棵树,同时加入 刚生成的新树; (4) 重复 (2) 和 (3) 两步,直至 F 中只
含一棵树为止。
例如: 已知权值 W={ 5, 6, 2, 9, 7 } 5 6 6 9 2 7 5 9 7 2 7
9
5
7
2 6
13
7
9
5
7
2 6
13
7 0 13 0 6 00 1 7 01 0 9 10 29 1 16 0 5 110 1
(1)由于Huffman树的WPL最小,说明编码所 需要的比特数最少。
这种编码已广泛应 用于网络通信中。
(2) Huffman树肯定没有度为1的结点;
(3)一棵有n 0个叶子结点的Huffman树,共有2n0-1个结点; (因为n=n0+n1+n2=2n0-1)
(4) Huffman编码时是从叶子走到根;而译码时又要从根走 到叶子,因此每个结点需要增开双亲指针分量(连同结点权值 共要开5个分量)
0
1
0 1 0 7 2 5 A C T
1 4 S
若按各个字符出现的概率不同而给予不等 长编码,可望减少总编码长度。 各字符出现概率为{ 2/18, 7/18, 4/18, 5/18 }, 化整为 { 2, 7, 4, 5 }。以它们为各叶结点上的 权值, 建立赫夫曼树。左分支赋 0,右分支赋 1,得赫夫曼编码(变长编码)。
a
b c d
0.07
0.19 0.02 0.06
a
b c d
000
001 010 011
0.07
0.19 0.02 0.06
19 b
e
f g h
0.32
0.03 0.21 0.10
e
f g h
100
101 110 111
0.32
0.03 0.21 0.10
21 32 28 1 g e 0 11 17 1 0 1 0 6 5 7 10 d 0 1 a h 2 3 c f
7
1 2 111
三、赫夫曼编码
主要用途是实现数据压缩。 设给出一段报文: CAST CAST SAT AT A TASA 字符集合是 { C, A, S, T },各个字符出现 的频度(次数)是 W={ 2, 7, 4, 5 }。 若给每个字符以等长编码 A : 00 T : 10 C : 01 S : 11 则总编码长度为 ( 2+7+4+5 ) * 2 = 36.
第17讲赫夫曼树
黄复贤 2012年7月15日星期日
一、最优树的定义
结点的路径长度定义为: 从根结点到该结点的路径上分支的 数目。
树的路径长度定义为: 树中每个结点的路径长度之和。 树的带权路径长度定义为:
树中所有叶子结点的带权路径长度之和
WPL(T) = wklk (对所有叶子结点)。
2
7
5
2 4
9
5 7 9
4
WPL(T)= 72+52+23+ 43+92 =60
WPL(T)= 74+94+53+ 42+21 =89
在所有含 n 个叶子结点、并带相同权 值的 m 叉树中,必存在一棵其带权路

长度取最小值的树,称为“最优树”。
二、如何构造最优树
(赫夫曼算法) 以二叉树为例: (1) 构造 n 棵二叉树的集合
双亲
w p 0 l 0 r 0
指针型指针
1
2 3
7
19
2
0
90Leabharlann 000HT[3].parent=9
……
Huffman编码举例
例1:假设用于通信的电文仅由8个字母 {a, b, c, d, e, f, g, h} 构成, 它们在电文中出现的概率分别为{ 0.07, 0.19, 0.02, 0.06, 0.32, 0.03, 0.21, 0.10 },试为这8个字母设计赫夫曼编码。
各叶子结点的编码存储在另一“复合”数组HC[1..n]中。 (n个权值对应n个叶子)
先构造Huffman树HT, 再求出N个字符的Huffman编码HC。
Huffman树和Huffman树编码的存储表示:
typedef struct{ unsigned int weight;//权值分量(可放大取整) unsigned int parent,lchild,rchild; //双亲和孩子分量 }HTNode,*HuffmanTree;//用动态数组存储Huffman树 typedef char**HuffmanCode; //动态数组存储Huffman编码表 *HuffmanTree或 HT向量样式:
(5)用计算机实现时,顺序和链式两种存储结构都要用到。
参见教材P147 如何编程实现Huffman编码?
建议1:Huffman树中结点的结构可设计成4或5分量形式:
char weight parent lchild rchild
建议2: Huffman树的存储结构可采用顺序存储结构:
将整个Huffman树的结点存储在一个数组HT[1..n..m]中; (内外结点总数m=2n-1)
指的是,任何一个字符的编码都 不是同一字符集中另一个字符的编码 的前缀。
利用赫夫曼树可以构造一种不等长 的二进制编码,并且构造所得的赫夫 曼编码是一种最优前缀编码,即使所 传电文的总长度最短。
Huffman编码
赫夫曼编码的基本思想是——
出现概率大的信息用短码,概率小的用长码,最小冗余
分析Huffman树和编码的特点:
相关文档
最新文档