• 数据结构之赫曼夫树(哈曼夫树)


    Java实现赫夫曼树(哈夫曼树)的创建

    目录

    一、赫夫曼树是什么?

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

    图1 一棵赫夫曼树

    img

    1.路径和路径长度

    在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。

    例如图1根节点到b节点之间的通路称为一条路径。

    在一条路径中,每经过一个结点,路径长度都要加 1 。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1。

    例如图1根节点到c节点的路径长度为 4 - 1 = 3

    2.节点的权和带权路径长度

    若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。

    例如图1中abcd节点的权值分别为12、5、6、21

    结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。

    例如图1节点c的带权路径长度为 3 * 6 = 18

    3.树的带权路径长度

    树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL。

    例如上图中的树的WPL = (5 + 6)* 3 + 12 * 2 + 21 = 78

    二、创建赫夫曼树

    1.图文创建过程

    假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为:

    img

    例如有四个叶子节点 a b c d 权值分别为 12、5、6、21

    创建赫夫曼树前森林如下

    (1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点);

    (2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;

    在森林中取出 b c节点 形成一棵新树M

    img

    (3)从森林中删除选取的两棵树,并将新树加入森林;

    将新树M添加到森林后 森林如下

    img

    (4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。

    • 4.1重复步骤(2)

    在森林中取出权为11的节点以及a节点组成一棵新树N

    img

    • 4.2重复步骤(3)

    将新树N添加到森林中 森林如下

    img

    • 4.3重复步骤(2)

    在森林中取出b节点和权为23的节点组成一棵新树S

    img

    则新树S就是我们要创建的赫夫曼树

    2.代码实现

    构建结点类

    package com.ma.tree.huffman;
    
    public class Node implements Comparable<Node>{
        public int value;
        public Node left;
        public Node right;
    
        public Node(int value) {
            this.value = value;
        }
    
    
        @Override
        public int compareTo(Node o) {
            return this.value - o.value;
        }
    
        //前序遍历
        public void preselect(){
            System.out.println(this);
            if (this.left != null){
                this.left.preselect();
            }
            if (this.right != null){
                this.right.preselect();
            }
        }
    
        @Override
        public String toString() {
            return "Node{" +
                    "value=" + value +
                    '}';
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    构建赫夫曼树

    package com.ma.tree.huffman;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.List;
    
    public class HuffmanTree {
        public static void main(String[] args) {
            int[] array = new int[]{1,432,2,11,34,45,542};
    
            preSelect( createHuffmanTree(array));
        }
    
        //把数列转化为赫夫曼树
        public static Node createHuffmanTree(int[] array){
            //1.遍历数组,
            //2.将每一个数组元素构成一个结点Node
            //3.将Node放入到集合中排序,从小到大
            List<Node> nodes = new ArrayList<Node>();
    
            for (int i = 0; i < array.length; i++) {
                Node node = new Node(array[i]);
                nodes.add(node);
            }
    
            //1.排序,从小到大
            //2.从取出最小的两个数 nodes.get(0),nodes.get(0)
            //3.创建一个新结点   Node root = new Node(nodes.get(0).value + nodes.get(1).value)
            //4.移除最小的两个 nodes.remove(0) nodes.remove(1)
            //5.在集合中添加新结点  nodes.add(root)
            //6.进入下一轮,排序........
    
            while (nodes.size() > 1){
                Collections.sort(nodes);
    
                System.out.println("集合中的元素:" + nodes);
                Node left = nodes.get(0);
                Node right = nodes.get(1);
    
                Node root = new Node(left.value + right.value);
    
                root.left = left;
                root.right = right;
    
                nodes.remove(left);
                nodes.remove(right);
    
                nodes.add(root);
            }
            return nodes.get(0);
        }
    
        //前序遍历
        public static void preSelect(Node root){
            if (root != null){
                root.preselect();
            }else {
                System.out.println("为空");
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    get(0);
    }

    //前序遍历
    public static void preSelect(Node root){
        if (root != null){
            root.preselect();
        }else {
            System.out.println("为空");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    }

    
    
    • 1
  • 相关阅读:
    算法通过村第十六关-滑动窗口|黄金笔记|结合堆的应用
    4.Tensors For Beginners-Vector Definition
    I/O设备管理
    【优化版】DOSBox及常用汇编工具的详细安装教程
    国内跨网数据传输有哪些难题,该如何解决?
    遥控车模的电机控制器
    【网络安全专栏目录】--企鹅专栏导航
    在矩池云上使用Syntaxnet解析文本
    使用keil 5.37版本编译FreeRTOS出错原因及解决办法
    java agent技术的注入利用与避坑点
  • 原文地址:https://blog.csdn.net/qq_47897078/article/details/124982868