哈夫曼树
路径:从一个结点到另一个结点之间的分支构成这两个结点之间路径
树的路径长度:从Root到每一个结点的路径长度之和
结点数码相同的二叉树中,完全二叉树是路径长度最短的二叉树 (路径长度最短的二叉树不一定是完全二叉树)
权:给结点赋一个具有某种含义的值
结点的带权路径长度:Root到该结点之间的路径长度 * 权值
WPL树的带权路径长度:树种所有Leaf结点的带权路径长度之和
哈夫曼树:最优树:WPL最短的树
具有相同带权结点的哈夫曼树不唯一
哈夫曼树中只有度为0、2的结点,没有度为1的结点
包含n个叶子结点的哈夫曼树中共有2n-1个结点
顺序存储结构
typedef struct{
int weight; //权
int parent,lch,rch;
}HTNode,*HuffmanTree;
共有2n-1个结点,不使用0为下标,2n
void CreatHuffmanTree(HuffmanTree HT, int n){ //构造一个n个叶子哈夫曼树
if(n<=1) return;s
m= 2*n - 1; //数组共2n-1个元素
HT = new HTNode[m+1]; //0号单元未使用,HT[m]表示根结点
for(i=1; i<=m;++i){
HT[i].lch = 0;
HT[i].rch = 0;
HT[i].parent = 0;
}
for(i = 1; i<=n; ++i) cin>>HT[i].weight;//输入前n个元素的weight
//接下来通过n-1次合并一次产生n-1个结点HT[i],i=n+1……2n-1
for(i = n+1; i <= m; i++){ //合并产生n-1个结点
Select(HT, i-1, s1, s2) //在HT[k](1 <= k <= i-1) 中选择两个其双亲域为0
//这函数自己写 //且,weight最小的结点,返回他们在HT中的序号s1、s2
HT[s1].parent = i; HT[s1].parent = i; //从表中删除s1、s2
HT[i].lch = s1; HT[i].rch = s2; //s1、s2分别作为i的左右孩子
HT[i].weight = HT[s1].weight + HT[s2].weight//i的权值为s1、s2之和
}
}
哈夫曼编码(看书)
任意一个编码都不是另一个字符的编码的前缀 ---前缀编码
为什么哈夫曼编码是前缀编码呢? 因为没有一个树叶是另一片的祖先
为什么Huffman编码能够保证字符编码总长最短 因为Huffman树的带权路径长度最短
左分支 0 右分支 1 一看就懂,真的
BUT,这种方法我们看好看,计算机具体算法实现较为困难
计算机从叶子往上找较为方便
假设要得到G 从七号结点开始,取7号的parent值8,八号结点是其双亲, 查8号的左右孩子,是左孩子就0、右孩子1, 一直这样找,找到parent = 0 最后逆序取 有几个结点就要做多少次
我是没太懂
void CreatHuffmanCode(Huffman HT, HuffmanCode & HC, int n){
从叶子到root逆向求每个字符的哈夫曼编码,存储在编码表HC中
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){ //从叶子结点开始向上回溯,知道root
--start; //回溯一次start向前指一个位置
if(HT[f].lchild = c) cd[start] = '0';
else cd[start] = '1';
c = f;f = HT[f].parent; //继续回溯
}
HC[i] = new char[n-start]; //为第i个字符串编码分配空间
strcpy(HC[i], &cd[start]); //将求得的编码从临时空间cd复制到HC的当前行中
}
delete cd; //释放临时空间
}