哈夫曼树(Huffman tree )

哈夫曼树(Huffman tree )

Scroll Down

介绍

定义:

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

简而言之,就是按照一个贪心思想和规则进行树的构造,而构造出来的这个树的权值最小。

对于哈夫曼树,他的每个非叶子节点都有两个孩子,因为哈夫曼树的构造就是自底向上的构造,两两合并。

WPL:树的所有叶子节点的气带权路径长度之和。
WPL计算方法:
WPL=从根节点到各个叶子节点的路径长度与对应叶子节点权值的乘积之和
image.png

哈夫曼树的构造

  • 初始时候各个数值都是一个单节点森林,然后进行排序
    image.png
  • 排序后每次取两个最小权值节点,构造父节点(父节点value=left.value+right.value)
  • 如果队列为空,那么返回节点,并且这个节点为根节点root
    image.png
  • 否则继续加入队列进行排序。重复上述操作,直到队列为空
    image.png
    在计算带权路径长度的时候,需要重新计算树的高度(从下往上),因为哈夫曼树是从下往上构造的,所以对于高度不太好维护,可以构造好然后计算高度。
    上述的WPL为:23+33+62+82+9*2=(2+3)*3+(6+8+9)*2=61。

代码实现

package com.mrdeer.controller;

/**
 * 树节点
 *
 * @author pang
 *
 * @param <T>
 */
public class Node<T> implements Comparable<Node<T>> {
    private T data;
    private int weight;
    private Node<T> left;
    private Node<T> right;

    public Node(T data, int weight) {
        this.data = data;
        this.weight = weight;
    }

    @Override
    public String toString() {
        // TODO Auto-generated method stub
        return "data:" + this.data + ",weight:" + this.weight + ";   ";
    }

    @Override
    public int compareTo(Node<T> o) {
        // TODO Auto-generated method stub
        if (o.weight > this.weight) {
            return 1;
        } else if (o.weight < this.weight) {
            return -1;
        }
        return 0;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public Node<T> getLeft() {
        return left;
    }

    public void setLeft(Node<T> left) {
        this.left = left;
    }

    public Node<T> getRight() {
        return right;
    }

    public void setRight(Node<T> right) {
        this.right = right;
    }

}
package com.mrdeer.controller;



import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class HuffmanTree<T> {

    public static <T> Node<T> createTree(List<Node<T>> nodes) {
        while (nodes.size() > 1) {
            Collections.sort(nodes);
            Node<T> left = nodes.get(nodes.size() - 1);
            Node<T> right = nodes.get(nodes.size() - 2);
            Node<T> parent = new Node<T>(null, left.getWeight()
                    + right.getWeight());
            parent.setLeft(left);
            parent.setRight(right);
            nodes.remove(left);
            nodes.remove(right);
            nodes.add(parent);
        }
        return nodes.get(0);
    }

    public static <T> List<Node<T>> breath(Node<T> root) {
        List<Node<T>> list = new ArrayList<Node<T>>();
        Queue<Node<T>> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            Node<T> pNode = queue.poll();
            list.add(pNode);
            if (pNode.getLeft() != null) {
                queue.add(pNode.getLeft());
            }
            if (pNode.getRight() != null) {
                queue.add(pNode.getRight());
            }
        }
        return list;
    }

}

测试类

package com.mrdeer.controller;

import java.util.ArrayList;
import java.util.List;

public class HuffmanTreeTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        List<Node<String>> nodes = new ArrayList<Node<String>>();
        nodes.add(new Node<String>("b", 5));
        nodes.add(new Node<String>("a", 7));
        nodes.add(new Node<String>("d", 2));
        nodes.add(new Node<String>("c", 4));
        Node<String> root = HuffmanTree.createTree(nodes);
        System.out.println(HuffmanTree.breath(root));
    }

}