数据结构与算法之构建哈夫曼树

哈夫曼树的介绍
Huffman Tree,中文名是哈夫曼树或霍夫曼树或者赫夫曼树,它是最优二叉树。

定义:给定n个权值作为n个叶子结点,构造一棵二叉树,若树的带权路径长度达到最小,则这棵树被称为哈夫曼树。

(01) 路径和路径长度

定义:在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。

(02) 结点的权及带权路径长度

定义:若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。

(03) 树的带权路径长度

定义:树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL。
————————————————
版权声明:本文为CSDN博主「liujc_love」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u012532559/article/details/44589997

哈夫曼树并不唯一,但带权路径长度一定是相同的。

(1)8个结点的权值大小如下:

在这里插入图片描述
(2)从19,21,2,3,6,7,10,32中选择两个权小结点。选中2,3。同时算出这两个结点的和5。
在这里插入图片描述

(3)从19,21,6,7,10,32,5中选出两个权小结点。选中5,6。同时计算出它们的和11。
在这里插入图片描述

(4)从19,21,7,10,32,11中选出两个权小结点。选中7,10。同时计算出它们的和17。
(BTW:这时选出的两个数字都不是已经构造好的二叉树里面的结点,所以要另外开一棵二叉树;或者说,如果两个数的和正好是下一步的两个最小数的其中的一个,那么这个树直接往上生长就可以了,如果这两个数的和比较大,不是下一步的两个最小数的其中一个,那么就并列生长。)
在这里插入图片描述

(5)从19,21,32,11,17中选出两个权小结点。选中11,17。同时计算出它们的和28。
在这里插入图片描述

(6)从19,21,32,28中选出两个权小结点。选中19,21。同时计算出它们的和40。另起一颗二叉树。
在这里插入图片描述

(7)从32,28, 40中选出两个权小结点。选中28,32。同时计算出它们的和60。
在这里插入图片描述

(8)从 40, 60中选出两个权小结点。选中40,60。同时计算出它们的和100。 好了,此时哈夫曼树已经构建好了。

在这里插入图片描述

————————————————
版权声明:本文为CSDN博主「阿伟_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_33990383/article/details/53073825

代码实现

package com.yg.tree;/*
@author  Mu_Mu
@date    2020/3/7  10:32
哈夫曼树
*/

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class HuffmanTree {
    public static void main(String[] args) {
int []arr={1,5,9,8,4,2,3,7};
        Node root = createHuffmanTree(arr);
        preOrder(root);
    }

    //创建Huffman树
    public static Node createHuffmanTree(int []arr) {
        if (arr == null || arr.length == 0) {
            return null;
        }
        List<Node>nodes=arrTransferToNodeList(arr);

        while (nodes.size() > 1) {
            Collections.sort(nodes);
            Node leftNode=nodes.get(0);
            Node rightNode=nodes.get(1);
            //组合新的node
            Node parent = new Node(leftNode.value + rightNode.value);
            parent.left=leftNode;
            parent.right=rightNode;
            //删除原先的两个node,将新的node添加到list中
            nodes.remove(leftNode);
            nodes.remove(rightNode);
            nodes.add(parent);

        }
        return nodes.get(0);

    }

    //将数组变为Node存入list集合中
    public static List arrTransferToNodeList(int []arr){

        List<Node>nodes=new ArrayList<Node>();
        //将数组变为node节点存入list集合中方便后续排序
        for (int value : arr) {
            nodes.add(new Node(value));
        }
        return nodes;
    }

    //前序遍历
    public static void preOrder(Node root) {
        if (root == null) {
            return;
        }
        root.preOrder();
    }

}


class Node implements Comparable<Node> {
    public int value;
    public Node left;
    public Node right;

    public Node(int value) {
        this.value = value;
    }

    //前序遍历
    public  void preOrder( ) {
        System.out.println(this);
        if (this.left != null) {
            this.left.preOrder();
        }
        if (this.right != null) {
            this.right.preOrder();
        }

    }

    @Override
    public String toString() {
        return "Node{" +
                "value=" + value +
                '}';
    }

    @Override
    public int compareTo(Node o) {
        //从小到大
        return this.value- o.value;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值