该篇是以前篇二叉树为基础,主要类继承自前者
http://blog.csdn.net/leo_wc/article/details/72772789
初识
哈夫曼树是一种带权路径长度最短的二叉树,所以它又称为最优二叉树.
主要用途
利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码,例如设计电文总长最短的二进制前缀编码,就是以n个字符出现的频率作为权构造一棵哈夫曼树,由哈夫曼树求得的编码就是哈夫曼编码。
概念
- 路径和路径长度
在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1 - 结点的权及带权路径长度
若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。 - 树的带权路径长度
树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL
哈夫曼树图例
它们的带权路径长度分别为:
图a: WPL=5*2+7*2+2*2+13*2=54
图b: WPL=5*3+2*3+7*2+13*1=48
可见,图b的带权路径长度较小,我们可以证明图b就是哈夫曼树(也称为最优二叉树)。
哈夫曼树构建方式
1,将所有左,右子树都为空的作为根节点。
2,在森林中选出两棵根节点的权值最小的树作为一棵新树的左,右子树,且置新树的附加根节点的权值为其左,右子树上根节点的权值之和。注意,左子树的权值应小于右子树的权值。
3,从森林中删除这两棵树,同时把新树加入到森林中。
4,重复2,3步骤,直到森林中只有一棵树为止,此树便是哈夫曼树。
如图:
哈夫曼编码
树中从根到每个叶子节点都有一条路径,对路径上的各分支约定指向左子树的分支表示”0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为各个叶子节点对应的字符编码,即是哈夫曼编码。
就拿上图例子来说:
A,B,C,D对应的哈夫曼编码分别为:111,10,110,0
实现代码(c#)
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text;
/// <summary>
/// 继承自 二叉树节点
/// </summary>
public class HuffTreeNode : binary_tree_Node
{
public HuffTreeNode parent;//用于回溯计算哈夫曼编码
}
public class HuffTreeLinkList : LinkedList<HuffTreeNode>
{
//此链表以Node的value值升序排列
public void Add(HuffTreeNode node) {
Enumerator it = this.GetEnumerator();
while(it.MoveNext()){
HuffTreeNode oldNode = it.Current;
if (node.value < oldNode.value)
{
LinkedListNode<HuffTreeNode> preNode = this.Find(oldNode);
this.AddBefore(preNode,node);
return;
}
}
this.AddLast(node);
}
public void Print() {
Enumerator it = this.GetEnumerator();
string str = "";
while (it.MoveNext())
{
HuffTreeNode oldNode = it.Current;
str += oldNode.value + ",";
}
Debug.Log("初始化节点排序: " + str);
}
}
/// <summary>
/// 哈夫曼树 继承自二叉树
/// </summary>
public class HuffTree : binary_tree{
public HuffTree()
{
}
/// <summary>
/// 生成哈夫曼树
/// </summary>
/// <param name="trees"></param>
public void BuildTree(HuffTreeNode[] trees)
{
HuffTreeLinkList treeList = new HuffTreeLinkList();
for (int i = 0; i < trees.Length;i++ )
{
treeList.Add(trees[i]);
}
treeList.Print();
while (treeList.Count > 0)
{
HuffTreeNode node1 = null;
HuffTreeNode node2 = null;
if(selectMinTrees(treeList, ref node1, ref node2)){
HuffTreeNode parent = new HuffTreeNode();
node1.parent = node2.parent = parent;
parent.LeftNode = node1;
parent.RightNode = node2;
parent.value = node1.value + node2.value;
parent.parent = null;
treeList.Add(parent);
}
}
}
/// <summary>
/// 找出链表里最小的两个节点
/// </summary>
/// <param name="treeList"></param>
/// <param name="node1"></param>
/// <param name="node2"></param>
/// <returns></returns>
public bool selectMinTrees(HuffTreeLinkList treeList,ref HuffTreeNode node1,ref HuffTreeNode node2)
{
if (treeList.Count > 1)
{
node1 = treeList.First.Value;
treeList.RemoveFirst();
node2 = treeList.First.Value;
treeList.RemoveFirst();
return true;
}
root = treeList.First.Value;
treeList.RemoveFirst();
return false;//还剩一个Node(root)表明哈夫曼树建立完成
}
public void PrintCode() {
getHuffCode((HuffTreeNode)root);
}
private void getHuffCode(HuffTreeNode tree)
{
if (tree == null)
{
return;
}
StringBuilder code = new StringBuilder();
int weight = 0;
getParentCode(tree, ref weight,code);
Debug.Log("值:" + tree.value + " 权重" + weight * tree.value + " 编码:" + code);
getHuffCode((HuffTreeNode)tree.LeftNode);
getHuffCode((HuffTreeNode)tree.RightNode);
}
private void getParentCode(HuffTreeNode tree, ref int weight,StringBuilder code)
{
if(tree!= null && tree.parent != null){
if (tree.parent.LeftNode == tree)
{
code.Append("0",0,1);
}else if(tree.parent.RightNode == tree){
code.Append("1", 0, 1);
}
weight++;
getParentCode(tree.parent, ref weight,code);
}
}
}
public class TestTree : MonoBehaviour
{
void Start()
{
#region 二叉树测试
//binary_tree tree = new binary_tree();
//string rands = "";
//for (int i = 0; i < 8; i++)
//{
// int random = UnityEngine.Random.Range(0, 100);
// tree.Insert(random);
// rands += random + ",";
//}
//print("原始数列: " + rands);
//tree.Preorder();
//tree.Inorder();
//tree.PostOrder();
//tree.Reversal();//反转
//tree.Preorder();
//tree.Inorder();
//tree.PostOrder();
#endregion
#region 哈夫曼树测试
HuffTree hufftree = new HuffTree();
HuffTreeNode[] nodes = new HuffTreeNode[5];
string str = "";
for (int i = 0; i < 5;i++ )
{
HuffTreeNode node = new HuffTreeNode();
node.value = UnityEngine.Random.Range(0, 20);
nodes[i] = node;
str += node.value + ",";
}
Debug.Log("初始用节点: " + str);
hufftree.BuildTree(nodes);
hufftree.Inorder();
hufftree.PrintCode();//输出该树所能表示的哈夫曼编码
#endregion
}
}