1. 相关概念:
1. 结点的路径长度
定义: 从根结点到该结点的连接数
2. 树的路径长度
定义: 所有叶结点的路径长度之和
3. 结点的权
梗概: 根据实际问题需要, 每个结点都有一个实数, 作为该结点的权值
4. 结点的带权路径长度
定义: 结点的路径长度×该结点的权
5. 树的带权路径长度(WPL)
定于: 树中所有叶结点的带权路径长度之和
2. 哈夫曼树定义:
1. 梗概:
哈夫曼树是一种特殊二叉树
- 哈夫曼树的每个结点都储存有权重
- 由实际问题得到每个每个叶结点的权重, 双亲结点的权重由两个孩子结点得到
- 给定n个带权叶子结点, 其构造的所有二叉树中, 哈夫曼树的带权路径长度最小
- 哈夫曼树结点不存储数据, 用权来映射/代表数据
2. 哈夫曼树的结构:
每个结点有四个部分:
- 权值域
- 存储权值
- 双亲域(根结点域)
- 存储双亲位置
- 左孩子域
- 存储左孩子位置
- 右孩子域
- 村粗右孩子位置
3. 哈夫曼树性质:
- 结点总数=2×叶子结点数-1
- 直观理解:
- 直观理解:
4. 操作:
1. 构造哈夫曼树
梗概
- 是一个贪婪算法
- 每次都选取最小的两个节点形成父节点
步骤
- 给定n个具有权值的独立结点
- 选出权值最小的两个结点(从剩余叶结点和根结点中选), 构成一颗树
- 权值小的作为左孩子
- 构造一个新的结点A, 作为这两个结点的根结点, 并给该根结点赋予权值
- 该根结点的权值=左右孩子的权值之和
- 重复以上步骤, 直到所有独立结点都归并到哈夫曼树中
5. 在C语言中的实现:
1. 梗概:
1.1. 结构定义:
- 哈夫曼树的结点采用数组来存储
- 结点间的位置用数组下标表示
- 数组0下标不存储结点, 用来表示空结点
- 为方便使用, 1
n下标存放叶结点, n+12n-1存放双亲结点
1.2. 构造哈夫曼树
分两大步:
- 初始化哈夫曼树的结点容器
- 每个结点的各个域都赋值为0
- 根据权重确定哈夫曼树的结点位置
- 其中每次都在选剩的叶结点和构造的根结点中选最小的两个
- 因为双亲结点就是权最小的两结点的其中一个
- 其中每次都在选剩的叶结点和构造的根结点中选最小的两个
2. 代码的性质
- 某个权值的结点在哈夫曼树位置=对应权值在权值数组位置+1
- 因为哈夫曼树的数组中第0个元素不使用
3. 代码实现:
3.1. 哈夫曼树定义:
#define N 64 //叶子结点数的最大值,可修改
#define M 2*N-1 //总结点数的最大值,不可修改
typedef WeightType int
typedef struct {
WeightType weight;
int parent;
int LChild, RChild;
}HTNode, HuffmanTree[M+1];
3.2. 按值查找
int HTLocate(HuffmanTree ht,WeightType w,int n){
for (int i=1;i<=n;++i)
if(ht[i].weight==w)
return i;
}
3.3. 构造哈夫曼树
void CrtHuffmanTree (HuffmanTree ht, int w[],int n){
//ht为哈夫曼树数组空间,w[]为所需权重集合,n为权重个数
void select(HuffmanTree ht,int end,int *s1,int *s2){
//在ht数组中选权值最小的两个,较小的赋给s1,较大的赋给s2
int j,min1=36767,min2=32767;
for(j=1;j<=end;++j){
/*只有parent为0才能在其上构造双亲结点*/
if((ht[j].parent==0)&&(ht[j].weight<min2)){
if(ht[j].weight<min1){
min2=min1;
*s2=*s1;
min1=ht[j].weight;
*s1=j;
}
else {
min2=ht[j].weight;
*s2=j;
}
}
}
}
/*叶结点初始化*/
int i,m,s1,s2;
for (i=1;i<=n;i++){
ht[i].weight=w[i-1];
ht[i].parent=ht[i].LChild=ht[i].RChild=0;
}
/*双亲结点初始化*/
m= 2*n-1;
for(i=n+1;i<m;i++){
ht[i].weight=ht[i].parent=ht[i].LChild=ht[i].RChild=0;
}
/*根据权重确定位置关系*/
/*这里i指向刚构造的双亲结点*/
for(i=n+1;i<=m;i++){
/*在剩余叶结点和刚构造的根结点中选
最小的两个,分别赋给s1和s2*/
select(ht,i-1,&s1,&s2);
/*关系确立*/
ht[i].weight=ht[s1].weight+ht[s2].weight;
ht[s1].parent=i; ht[s2].parent=i;
ht[i].LChild=s1; ht[i].RChild=s2;
}
}
6. 哈夫曼树的应用:
1. 哈夫曼编码
child::哈夫曼编码