#笔记整理
树的定义参照前文:
二叉树、遍历二叉树与线索二叉树等树的定义与解析、二叉树遍历实现
哈夫曼树(也称赫夫曼树)
相关概念:
① 路径长度
从树中一个结点到另一个结点之间的分支(树枝)构成这两个结点之间的路径, 路径上的分支(树枝)数目称做路径长度。
② 树的路径长度
从树根到每一结点的路径长度之和(所有结点到根的路径长度的和)。
③ 结点的权和带权路径长度
给树的每个结点赋予一个具有某种实际意义的实数,我们称该实数为这个结点的权。
在树形结构中,我们把从树根到某一结点的路径长度与该结点的权的乘积,叫做该结点的带权路径长度(Weighted Path Length of Tree,WPL)。
④ 二叉树的带权路径长度
设二叉树具有n个带权值的叶子结点,那么从根结点到各个叶子结点的路径长度与相应叶子结点权值的乘积的和,叫做二叉树的带权路径长度。
哈夫曼树(最优二叉树)
具有最小带权路径长度的二叉树称为哈夫曼树。
如下图 ( c )
构建哈夫曼树(哈夫曼算法)
- 由给定的n个权值 W 1 , W 2 , . . . , W n {W1,W2,...,Wn} W1,W2,...,Wn,构造 n 棵只有一个结点的二叉树,从而得到一个二叉树的集合 F = T 1 , T 2 , . . . , T n F={T1,T2,...,Tn} F=T1,T2,...,Tn;
- 在F中选取根结点的权值最小和次小的两棵二叉树作为左、右子树构造一棵新的二叉树,这棵新的二叉树根结点的权值为其左、右子树根结点权值之和;
- 在集合F中删除作为左、右子树的两棵二叉树,并将新建立的二叉树加入到集合F中;
- 重复(2)、(3)两步,当F中只剩下一棵二叉树时,这棵二叉树便是所要建立的赫夫曼树。
示例:
哈夫曼树中没有度为 1 的结点(可称为严格的(或正则的)二叉树),因此一棵有 n 个叶子节点的哈夫曼树一共有 2n - 1 个结点,可以存储在一个大小为 2n - 1 的一维数组中。
算法实现:
// 创建哈夫曼树 hTree
void createHuffTree(vector<HuffTreeNode> &hTree){
int n, s1, s2, len;
char c; // 字符
int weight; // 字符权值
cout << "请输入字符集大小(即叶子数):" << endl;
cin >> n;
len = 2 * n - 1; // 哈夫曼树的结点数
hTree.resize(len);
cout << n << "个字符及其的权值是:(输入格式如:a1 b5 d23,空格分隔)" << endl;
for(int i = 0; i < n; i++){
cin >> c >> weight;
hTree[i].data = c;
hTree[i].weight = weight;
hTree[i].parent = -1;
hTree[i].