哈弗曼树相关知识总结:
1、概念:
给定一组权值,构造出的具有最小带权路径长度的二叉树称为Huffman树,又称为最优二叉树;
2、特性:
权值越大的叶结点离根结点越近,权值越小的叶结点离根结点越远,这样的二叉树的WPL最小;
3、哈弗曼算法思想:
关键是构造哈弗曼树的方法:
(1)将给定的权值按照从小到大排列成(w1,w2,w3,···,wn),并且构造出树林F =(T1,T2,···,Tm)。此时,其中的每棵树Ti(1=<i <= m)都为左右子树均为空的
二叉树,二叉树的根结点的权值为wi。
(2)把F中树根结点的权值最小的两棵二叉树T1和T2合并为一棵新的二叉树T,并令T的根结点的权值为T1和T2根结点的权值之和,然后将T按其根结点的权值大小依次加到树林
F中,同时从F中删除T1和T2这两棵二叉树。
(3)重复步骤2,直到构造成一棵二叉树。
哈弗曼编码的构造思想:
设D=(d1,d2,d3,···,dm)为需要进行编码的字符集合,W=(w1,w2,w3,···,wm)为每个字符在传送电文中出现次数的集合。
以Wi为权值构造出一棵哈弗曼树,以di为该树中被赋予权值的Wi的叶结点的名。在所构造出来的哈弗曼树中,规定从根结点到叶结点di的路径上每经过一条左树枝取一个
二进制0,每经过一条右树枝则取一个二进制1.
于是,从根结点到di的路径上所得到的有0和1组成的二进制位序列定义为di的哈弗曼编码。
注意:1、哈弗曼编码不是唯一的。
2、在对不等长编码的字符进行识别时,必须保证任意一个字符的编码不可能是另一个字符编码的前缀,哈弗曼编码正好具有这一特点。
原因:在哈弗曼树中,代表每个字符的结点都是叶结点,他不可能在从根结点到另一个字符的路径上,当然它的编码也不可能是另外一个字符编码的前缀。
由于哈弗曼编码是不等长的, 因此在对它进行译码时,还是比较困难的。
哈弗曼编码算法:
设该算法对m个字符进行编码,这m个字符用序号(1,2,3,4,···m)代表,对应的权值集合为W=(w1,w2,w3,···,wm)。根据二叉树的性质可知,具有m个叶结点的哈弗曼树
共有n=2m-1个结点。因此,算法中设置一个数组权值weight[0···n-1]分别存放n个结点的权值;数组parent[0···n-1]分别存放结点的双亲结点的位置;lchild[0···n-1]
分别存放结点的左孩子的位置;rchild[0···n-1]分别存放结点的右孩子位置(实际上哈弗曼树采用的是一种静态的三叉链表结构);
二维数组code[0···m-1][0···m-1]用来存放m个字符的哈弗曼编码,其中每个数组元素为一个二进制位,第i行中给出的是第i个字符的哈弗曼编码。
算法分成两部分:
一、构造出哈弗曼树
构造步骤:
1、初始时,输入weight[0]至weight[n-1]的值,而所有的parent,lchild与rchild域均置成0。于是,构成m棵树的树林。
2、利用子算法SELECT(i-1,s1,s2)在树林中选择两棵根的权值最小的子树,其根结点分别由s1和s2指出,把s1和s2合并为以i为根的二叉树,s1和s2的parent指向i而
不再是0;
3、重复步骤2,直到构成具有m个叶结点的哈弗曼树。
二、在哈弗曼树上完成对每个结点的编码。
代码实现:
#include "stdafx.h"
#include <iostream>
#define MaxSize 100
int w[MaxSize],weight[],parent[],lchild[],rchild[],start[],code[][MaxSize],n,m;
void Huff_Man_Code(w,weight,parent,lchild,rchild,start,code,n,m)
{
int s1,s2,c,f;
for (int i = 0;i < n;++ i)
{
parent[i] = 0;
lchild[i] = 0;
rchild[i] = 0;
}
for (int i = 0;i < m;++ i)
{
weight[i] = w[i];
}
for (int i = m;i < n;++ i)
{
select(i - 1,s1,s2);
// 选择两棵parent为0且权值最小的子树,根结点分别为s1和s2
parent[s1] = i;
parent[s2] = i;
lchild[i] = s1;
rchild[i] = s2;
weight[i] = weight[s1] + weight[s2];
} // 完成哈弗曼树的构造;
for (int i = 0;i < m;++ i)
{
start[i] = m;
f = parent[i];
c = i;
while(f != 0)
{
if (lchild[f] == c)
{
code[i][start[i]] = 0;
}
else
{
code[i][start[i]] = 1;
}
start[i] --;
c = f;
f = parent[f];
}
} //完成哈弗曼树的编码;
}
1、概念:
给定一组权值,构造出的具有最小带权路径长度的二叉树称为Huffman树,又称为最优二叉树;
2、特性:
权值越大的叶结点离根结点越近,权值越小的叶结点离根结点越远,这样的二叉树的WPL最小;
3、哈弗曼算法思想:
关键是构造哈弗曼树的方法:
(1)将给定的权值按照从小到大排列成(w1,w2,w3,···,wn),并且构造出树林F =(T1,T2,···,Tm)。此时,其中的每棵树Ti(1=<i <= m)都为左右子树均为空的
二叉树,二叉树的根结点的权值为wi。
(2)把F中树根结点的权值最小的两棵二叉树T1和T2合并为一棵新的二叉树T,并令T的根结点的权值为T1和T2根结点的权值之和,然后将T按其根结点的权值大小依次加到树林
F中,同时从F中删除T1和T2这两棵二叉树。
(3)重复步骤2,直到构造成一棵二叉树。
哈弗曼编码的构造思想:
设D=(d1,d2,d3,···,dm)为需要进行编码的字符集合,W=(w1,w2,w3,···,wm)为每个字符在传送电文中出现次数的集合。
以Wi为权值构造出一棵哈弗曼树,以di为该树中被赋予权值的Wi的叶结点的名。在所构造出来的哈弗曼树中,规定从根结点到叶结点di的路径上每经过一条左树枝取一个
二进制0,每经过一条右树枝则取一个二进制1.
于是,从根结点到di的路径上所得到的有0和1组成的二进制位序列定义为di的哈弗曼编码。
注意:1、哈弗曼编码不是唯一的。
2、在对不等长编码的字符进行识别时,必须保证任意一个字符的编码不可能是另一个字符编码的前缀,哈弗曼编码正好具有这一特点。
原因:在哈弗曼树中,代表每个字符的结点都是叶结点,他不可能在从根结点到另一个字符的路径上,当然它的编码也不可能是另外一个字符编码的前缀。
由于哈弗曼编码是不等长的, 因此在对它进行译码时,还是比较困难的。
哈弗曼编码算法:
设该算法对m个字符进行编码,这m个字符用序号(1,2,3,4,···m)代表,对应的权值集合为W=(w1,w2,w3,···,wm)。根据二叉树的性质可知,具有m个叶结点的哈弗曼树
共有n=2m-1个结点。因此,算法中设置一个数组权值weight[0···n-1]分别存放n个结点的权值;数组parent[0···n-1]分别存放结点的双亲结点的位置;lchild[0···n-1]
分别存放结点的左孩子的位置;rchild[0···n-1]分别存放结点的右孩子位置(实际上哈弗曼树采用的是一种静态的三叉链表结构);
二维数组code[0···m-1][0···m-1]用来存放m个字符的哈弗曼编码,其中每个数组元素为一个二进制位,第i行中给出的是第i个字符的哈弗曼编码。
算法分成两部分:
一、构造出哈弗曼树
构造步骤:
1、初始时,输入weight[0]至weight[n-1]的值,而所有的parent,lchild与rchild域均置成0。于是,构成m棵树的树林。
2、利用子算法SELECT(i-1,s1,s2)在树林中选择两棵根的权值最小的子树,其根结点分别由s1和s2指出,把s1和s2合并为以i为根的二叉树,s1和s2的parent指向i而
不再是0;
3、重复步骤2,直到构成具有m个叶结点的哈弗曼树。
二、在哈弗曼树上完成对每个结点的编码。
代码实现:
#include "stdafx.h"
#include <iostream>
#define MaxSize 100
int w[MaxSize],weight[],parent[],lchild[],rchild[],start[],code[][MaxSize],n,m;
void Huff_Man_Code(w,weight,parent,lchild,rchild,start,code,n,m)
{
int s1,s2,c,f;
for (int i = 0;i < n;++ i)
{
parent[i] = 0;
lchild[i] = 0;
rchild[i] = 0;
}
for (int i = 0;i < m;++ i)
{
weight[i] = w[i];
}
for (int i = m;i < n;++ i)
{
select(i - 1,s1,s2);
// 选择两棵parent为0且权值最小的子树,根结点分别为s1和s2
parent[s1] = i;
parent[s2] = i;
lchild[i] = s1;
rchild[i] = s2;
weight[i] = weight[s1] + weight[s2];
} // 完成哈弗曼树的构造;
for (int i = 0;i < m;++ i)
{
start[i] = m;
f = parent[i];
c = i;
while(f != 0)
{
if (lchild[f] == c)
{
code[i][start[i]] = 0;
}
else
{
code[i][start[i]] = 1;
}
start[i] --;
c = f;
f = parent[f];
}
} //完成哈弗曼树的编码;
}