带权路径长度(WPL):
从树根到任意结点的路径长度与该结点权值的乘积。
树的带权路径长度:
树中所有叶子结点的带权路径长度之和。
哈夫曼树(最优二叉树):WPL最小的二叉树。
//哈夫曼树
#include <stdio.h>
typedef struct TreeNode{
int weight;
struct TreeNode *Left, *Right;
}TNode;
typedef TNode* HuffmanTree;
HuffmanTree Huffman( MinHeap H ); //构建一颗哈夫曼树,传入参数是一个指向最小堆的指针
哈夫曼树的构造:
每次把权值最小的两个二叉树合并。
HuffmanTree Huffman( MinHeap H )
{
HuffmanTree T;
CreatMinHead( H ); //建立最小堆
int i;
for( i = 1; i < H -> Size; i++ ){ //进行H->Size - 1次合并
T = ( HuffmanTree )malloc( sizeof( TNode ) ); //构造一个新结点
T -> Left = DeleteMin( H ); //从最小堆中取出堆顶元素(即对应森林中最小的二叉树)作为新结点的左孩子
T -> Right = DeleteMin( H ); //同理再取出一个最小的作为新结点的右孩子
T -> weight = T -> Left -> weight + T -> Right -> weight; //新结点的权重为左右孩子权重之和
Insert( H, T ); //把新结点插入最小堆中
}
T = DeleteMin( H );
return T;
}
这里对堆的一些理解还不是很清楚,所以完整程序等之后学完堆之后再补上来。
哈夫曼树的特点:
(1)哈夫曼树中没有度为1的结点;
(2)n个叶子结点的哈夫曼树共有2*n - 1个结点;
(3)哈夫曼树的任意非叶节点的左右子树交换后仍是哈夫曼树;
(4)对同一组权值可能存在同构的哈夫曼树,但它们的WPL值相同;
(5)每个最初结点最终都成为叶结点,权值越小的结点到根结点的路径长度越大。
编码:
(1)等长码:每个字符都用同样长度的二进制表示;
(2)可变长度编码:对不同字符用不同的长度的二进制位进行表示。
可变长度编码可以起到压缩数据的作用。
前缀码(prefix code):任何字符的编码都不是其它任意字符编码的前缀。
前缀码可以无二义地解码。
哈夫曼编码:
(1)左右分支对应:0,1;
(2)字符只在叶节点上(实现前缀码的效果)。
通过哈夫曼编码得到的哈夫曼树的带权路径长度即为最终编码得到的二进制编码的总长度。