赞
踩
路径:从树中一个结点到另一个结点之间的分支构成这两个结点间的路径
结点的路径长度:两结点间路径上的分支数
树的路径长度:从树根到每一个结点的路径长度之和,记作TL
权(weight):将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权
结点的带权路径长度:从根结点到该结点之间的路径长度与该结点的权的乘积
树的带权路径长度(WPL):树中所有叶子结点的带权路径长度之和
记作:
W
P
L
=
∑
i
=
0
k
w
k
l
k
WPL=\sum_{i=0}^{k} w_ k l_k
WPL=i=0∑kwklk
ω
\omega
ω——权值
l
k
l_k
lk——结点到根的路径长度
哈夫曼树:最优树——带权路径长度(WPL)最短的树
贪心算法:构造哈夫曼树首先选择权值小的叶子结点
哈夫曼算法(构造哈夫曼树的方法)
口诀:
哈夫曼树的结点的度数为0或2,没有度为1的结点;
包含n个叶子结点的哈夫曼树共有2n-1个结点;
包含n棵树的森林要经过n-1次合并才能形成哈夫曼树,共产生n-1个新结点;
总结:
可见:哈夫曼树中共有 n+n-1 = 2n-1个结点,且其所有的分支结点的度均不为1
采用顺序存储结构—— 一维结构数组
结点类型定义:
typedef struct{
int weight;
int parent, lch, rch;
}HTNode, *HuffmanTree;
哈夫曼树中共有2n-1个结点,不使用0下标,数组大小为2n
例如:第一个结点权值为5,即可表示为 H[i].weight = 5;
例:有n = 8,权值为 W = {7, 19, 2, 6, 32, 3, 21, 10}, 构造哈夫曼树
//构造哈夫曼树——哈夫曼算法 void CreatHuffmanTree(HuffmanTree &HT, int n){ if(n <= 1) return; m = 2 * n - 1; //数组共2n-1个元素 HT = new HTNode[m + 1]; //0号单元未用,HT[m]表示根结点 for(i =1; i <= m; ++i){ //将2n-1个元素的lch、rch、parent置为0 HT[i].lch = 0; HT[i].rch = 0; HT[i].parent = 0; } for(i = 1; i <= n; ++i) cin >> HT[i].ewight; //输入前n个元素的weight值 //初始化结束,下面开始建立哈夫曼树 //合并产生n-1个结点——构造哈夫曼树 for(i = n + 1; i <= m; i++){ Select(HT, i - 1, s1, s2); //在HT[k] (1 ≤ k ≤ i-1)中选择两个其双亲域为0, //且权值最小的结点,并返回他们在HT中的序号s1和s2 HT[s1].parent = i; //表示从F中删除s1,s2 HT[s2].parent = i; HT[i].lch = s1; //s1,s2分别为i的左右孩子 HT[i].rch = s2; HT[i].weight = HT[s1].weight +HT[s2].weight; //i的权值为左右孩子权值之和 } }
例:设n = 8, w = {5, 29, 7, 8, 14, 23, 3, 11},试设计Huffman code
(m = 2*8-1 = 15)
问题:什么样的前缀码能使得电文总长最短 ? —— 哈夫曼编码
哈夫曼编码算法的讲解:https://www.bilibili.com/video/BV1nJ411V7bdp=106&spm_id_from=pageDriver
哈夫曼编码算法的实现:
//从叶子到逆根向求每个字符的哈夫曼编码,存储在编码表HC中 void CreatHuffmanCode(HuffmanTree HT, HuffmanCode &HC, int n){ HC = new char *[n + 1]; //分配n个字符编码的头指针矢量 cd = new char [n]; //分配临时存放编码的动态数组空间 cd[n - 1] = '\0' ; //编码结束符 for(i = 1; i <= n; ++i){ //逐个字符求哈夫曼编码 start = n - 1; c = i; f = HT[i].parent; while(f != 0){ //从叶子结点开始向上回溯,直到根结点 --start; //回溯一次start向前指一个位置 if(HT[f].lchild == c) //结点c是f的左孩子,则生产代码0 cd[start] = '0' ; else //结点c是f的右孩子,则生成代码1 cd[start] = '1' ; c = f; //继续向上回溯 f = HT[f].parent; } //求出第i个字符的编码 HC[i] = new char [n - start]; //为第i个字符串编码分配空间 strcpy(HC[i], &cd[start]); //将求得的编码从临时空间cd复制到HC的当前行中 } delete cd; //释放临时空间 } //CreatHuffanCode
一、编码:
① 输入各字符及其权值
② 构造哈夫曼树——HT[i]
③ 进行哈夫曼编码——HC[i]
④ 查HC[i],得到各字符的哈夫曼编码
二、解码:
① 构造哈夫曼树
② 依次读入二进制码
③ 读入0,则走向左孩子;读入1,则走向右孩子
④ 一旦到达某叶子时,即可译出字符
⑤ 然后再从根出发继续译码,直到结束
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。