哈夫曼树简介及实现

该篇是以前篇二叉树为基础,主要类继承自前者
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
    }
}

输出结果

这里写图片描述

完,学习之余别忘了听我分享的歌~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值