1、基本介绍

1)给定n个权值作为n个叶子结点,构造一棵二叉树,若该树的带权路径长度(wpl)达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree),还有的书翻译为霍夫曼树。
2)赫夫曼树是带权路径长度最短的树,权值较大的结点离根较近

2、实现思路

构成赫夫曼树的步骤:
1)从小到大进行排序,将每一个数据,每个数据都是一个节点,每个节点可以看成是一颗最简单的二叉树2)取出根节点权值最小的两颗二叉树
3)组成一颗新的二又树,该新的二叉树的根节点的权值是前面两颗二又树根节点权值的和
4)再将这颗新的二叉树,以根节点的权值大小再次排序,不断重复1-2-3-4的步骤,直到数列中,所有的数据都被处理,就得到一颗赫夫曼树

3、代码实现

package com.hblg.huffmantree;

import org.jetbrains.annotations.NotNull;

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

/**
 * @author i
 * @create 2019/10/17 19:27
 * @Description 赫夫曼树创建
 *
 * 主要实现思路:1.从小到达进行排序,将每一个数据,每个数据都是一个节点,每个节点都可以看成是一颗最简单的二叉树,
 * 2.取出根节点权值最小的两颗二叉树。
 * 3.组成一课新的二叉树,该树的二叉树的根节点的权值是前面两颗二叉树的根节点权值的值
 * 4.在将这颗新的二叉树,以根节点的权值大小 在此排序,不断重复 直至数列中,所有的数据被处理,就得到了一颗赫夫曼树。
 */
public class HuffmanTree {

    public static void main(String[] args) {
        HuffmanTree huffmanTree = new HuffmanTree();
        int[] array = {13, 7, 8, 1};
        Node rootNode = createHuffmanTree(array);
        preHuffmanTree(rootNode);
    }

    /***
     * 遍历赫夫曼树 - 前序遍历
     * @param rootNode
     */
    public static void preHuffmanTree(Node rootNode) {
        if (rootNode != null) {
            rootNode.preOrder();
        } else {
            System.out.println("空树!");
        }
    }

    //创建赫夫曼树
    public static Node createHuffmanTree(int[] array) {
        //数组转换成指定的赫夫曼树
        List<Node> nodes = new ArrayList<>();
        //遍历 将数组中的值添加到集合中
        for (Integer value : array) {
            nodes.add(new Node(value));
        }

        while (nodes.size() > 1) {

            //将集合中的元素,进行排序 从小到大
            Collections.sort(nodes);

            System.out.println(nodes);

            //获取最小权值的数
            Node leftNode = nodes.get(0);
            //获取次小权值的数
            Node rightNode = nodes.get(1);

            //添加新的节点 最小权值和次小权值的总数和
            Node parentNode = new Node(leftNode.getValue() + rightNode.getValue());
            parentNode.leftNode = leftNode;
            parentNode.rightNode = rightNode;

            //删除 最小权值节点 和 次小权值的节点
            nodes.remove(leftNode);
            nodes.remove(rightNode);
            //添加到父节点上
            nodes.add(parentNode);
        }
        return nodes.get(0);
    }


}

//创建一个节点
class Node implements Comparable {
    private Integer value;
    public Node leftNode;
    public Node rightNode;

    public Node() {
    }

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

    public Node(Integer value, Node leftNode, Node rightNode) {
        this.value = value;
        this.leftNode = leftNode;
        this.rightNode = rightNode;
    }

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

    public Integer getValue() {
        return value;
    }

    public void setValue(Integer value) {
        this.value = value;
    }

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

    //比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
    @Override
    public int compareTo(@NotNull Object o) {
        return this.value - ((Node) o).value;
    }
}