哈夫曼树(霍夫曼树)-详解

哈夫曼树(霍夫曼树)-详解

在了解哈佛曼树前,需要先了解,何为权值,何为路径,以及权值计算。

何为权值?我们看下百度百科的解释。

by:百度百科
在数学领域,权值指加权平均数中的每个数的频数,也称为权数或权重。
计算机领域中(数据结构)
权值就是定义的路径上面的值。可以这样理解为结点间的距离。通常指字符对应的二进制编码出现的概率。
至于[哈夫曼树]中的权值可以理解为:权值大表明出现概率大!
一个结点的权值实际上就是这个结点子树在整个树中所占的比例.
abcd四个[叶子结点]的权值为7,5,2,4, 这个7,5,2,4是根据实际情况得到的,比如说从一段文本中统计出abcd四个字母出现的次数分别为7,5,2,4. 说a结点的权值为7,意思是说a结点在系统中占有7这个份量。实际上也可以化为百分比来表示,但反而麻烦,实际上是一样的。

何为路径?

连接两个节点的线就是路径。

何为路径长度?

从顶点到 1,其需要经过 a 、b 路径。那么路径长度就为2

何为树的路径长度?

从树的顶点,到各个节点的路径长度总和,即为树的路径长度。

何为结点的带权路径长度?

结点权即为本身数值,而结点的带权路径长度为从树的订单到结点的路径长度与结点的权 数值乘积。
公式: 结点的带权路径长度 = 结点的路径长度 * 结点的带权值

例:上图,从顶点到对应结点,那么它的带权路径长度为 2 x 100 = 200

何为树的带权路径长度(WPL)?

树的带权路径长度为结点的带权路径长度之和。可参考上图。

哈夫曼树(霍夫曼树)介绍

by: 百度百科
给定n个权值作为n个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。

一个二叉树的带权路径长度(WPL)最小,才能为哈夫曼树。而要使得WPL最小,则需要结点权值最大越靠近顶点,而结点权值越小离顶点越远。
以下为图示的简单例子:

package com.base.data.tree;
/**
 * 创建一个结点,包含权重信息 * @param <E>
  */
public class HuffTreeNode<E> {
    E data;
    double weight;
    HuffTreeNode leftNode;
    HuffTreeNode rightNode;

    public HuffTreeNode(E data,double weight) {
        this.data = data;
        this.weight = weight;
    }

    public HuffTreeNode(E data, double weight, HuffTreeNode leftNode, HuffTreeNode rightNode) {
        this.data = data;
        this.weight = weight;
        this.leftNode = leftNode;
        this.rightNode = rightNode;
    }
}
package com.base.data.tree;

import java.util.*;

public class HuffTree {

    /**
     * 创建哈夫曼树 
     * @param huffTreeNodeList {@link HuffTreeNode}
     * @return 返回树
     */  
    public HuffTreeNode createHuffTree(List<HuffTreeNode> huffTreeNodeList){
        while(huffTreeNodeList.size() > 1){
            //排序
  sortHuffTrees(huffTreeNodeList);
            int size = huffTreeNodeList.size();
            //从尾部开始循环
  HuffTreeNode leftNode = huffTreeNodeList.get(size-1);
            HuffTreeNode rightNode = huffTreeNodeList.get(size-2);
            //创建父结点
  HuffTreeNode parentNode = new HuffTreeNode(null,leftNode.weight+rightNode.weight);
            parentNode.leftNode = leftNode;
            parentNode.rightNode = rightNode;

            huffTreeNodeList.remove(size-1);
            huffTreeNodeList.remove(size-2);

            huffTreeNodeList.add(parentNode);
        }
        return huffTreeNodeList.get(0);
    }

    /**
     * 冒泡排序 结点的权重信息 从大到小 
     * @param huffTreeNodeList
    */
  public void sortHuffTrees(List<HuffTreeNode> huffTreeNodeList){
        int i = huffTreeNodeList.size()-1;
        while (i > 0){
            int post = 0;
            for (int i1 = 0; i1 < i; i1++) {
                if(huffTreeNodeList.get(i1).weight < huffTreeNodeList.get(i1+1).weight){
                    post = i1;
                    HuffTreeNode temp = huffTreeNodeList.get(i1+1);
                    huffTreeNodeList.set(i1+1,huffTreeNodeList.get(i1));
                    huffTreeNodeList.set(i1,temp);
                }
            }
            i = post;
        }
    }

    public void printNode(HuffTreeNode huffTreeNode){
        System.out.println(huffTreeNode.weight);
        if(huffTreeNode.leftNode != null){
            System.out.println(huffTreeNode.leftNode.weight);
            printNode(huffTreeNode.leftNode);
        }
        if(huffTreeNode.rightNode != null){
            System.out.println(huffTreeNode.rightNode.weight);
            printNode(huffTreeNode.rightNode);
        }
    }

    public static void main(String[] args) {
        HuffTree huffTree = new HuffTree();
        List<HuffTreeNode> huffTreeNodeList = new ArrayList<>();
        for(int i=0;i<1000;i++){
            Random random = new Random();
            double randomDouble = random.nextInt(100000);
            huffTreeNodeList.add(new HuffTreeNode("A结点"+i, randomDouble));
        }
        huffTree.createHuffTree(huffTreeNodeList);
        huffTree.printNode(huffTreeNodeList.get(0));
    }
}
  • 3
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值