树(三,赫夫曼树)

timg (2).jpg
huffman树
1.概念

从树中一个结点到另一个结点的分支称为两个结点之间的路径,路径上的分支数称为路径长度.
如果考虑到带权的结点,结点的带权路径长度就是结点到树根的路径长度与结点权重的乘积.
树的带权路径长度就是树的所有叶子结点带权路径长度之和.
如果有n个带权的结点,生成一棵二叉树,带权路径长度最小的二叉树即为赫夫曼树.

2.Huffman树的构造

那么,如何构造一颗赫夫曼树呢?

  1. 先把带权叶子结点按照从小到大顺序排列成一个有序序列,即:A5,E10,B15,D30,C40.(字母表示结点名称,数字表示结点权值).
  2. 取出头两个权值最小的结点作为新结点N1的左右孩子结点,权值小的为右孩子,权值大的为左孩子.即:
image.png
  1. 将N1替代A和E插入到序列中,保持从小到大排列.即:N1 15,B15,D30,C40.
  2. 重复2,即:取出N1和B15,作为新结点N2的子节点


    image.png
  3. 重复3.即将N2替代N1和B,插入有序序列,即:N2 30,D30,C40.
  4. 重复上述步骤,直到所有结点都被安排.


    image.png
3.Huffman编码

那么,Huffman树有什么用呢?
Huffman树最开始研究出来,是为了解决电报传输最优编码问题.即Huffman编码.

比如我们有一段文字内容为"BADCADFEED"需要传输给别人,用二进制表示

A B C D E F
000 001 010 011 100 101

假设这6个字母的频率分别是A 27,B 8,C 15,D 15,E 30,F 5.构建成Huffman树就是

image.png

将树的左分支换成0,右分支换成1,构成的新Huffman树就是


image.png

此时,我们用这6个字母到树根的路径来表示字母的编码,即


image.png

我们将"BADCADFEED"重新编码.即
image.png

也就是说,通多Huffman编码我们的数据被压缩了,节约了大约17%的存储和传输成本

4.代码

说了这么多,有什么用呢?还不如直接上代码

import org.junit.Test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Stack;

public class HuffmanTree {

    TreeNode root;//根节点

    public TreeNode createHuffmanTree(ArrayList list){

        while (list.size()>1){
            Collections.sort(list);
            TreeNode right = list.get(0);
            TreeNode left = list.get(1);
            TreeNode parent = new TreeNode("p",left.weight+right.weight);
            parent.leftChild = left;
            left.parent = parent;
            parent.rightChild = right;
            right.parent = parent;
            list.remove(left);
            list.remove(right);
            list.add(parent);
        }

        root = list.get(0);
        return root;
    }

    public void showHuffmanTree(TreeNode root){
        LinkedList list = new LinkedList<>();
        list.offer(root);
        while(!list.isEmpty()){
            TreeNode node = list.pop();
            System.out.println(node.data);
            if (node.leftChild!=null){
                list.offer(node.leftChild);
            }
            if (node.rightChild!=null){
                list.offer(node.rightChild);
            }
        }
    }

    public void getCode(TreeNode node){
        TreeNode tNode = node;
        Stack stack = new Stack<>();
        while (tNode!=null&&tNode.parent!=null){
            if (tNode.parent.rightChild==tNode){
                stack.push("1");
            }else{
                stack.push("0");
            }
            tNode = tNode.parent;
        }

        while (!stack.isEmpty()){
            System.out.print(stack.pop());
        }
    }

    @Test
    public void test() {
        ArrayList list = new ArrayList<>();
        TreeNode node = new TreeNode("good", 50);
        list.add(node);
        list.add(new TreeNode("morning", 10));
        TreeNode node2 =new TreeNode("afternoon", 20);
        list.add(node2);
        list.add(new TreeNode("hell", 110));
        list.add(new TreeNode("hi", 200));
        HuffmanTree tree = new HuffmanTree();
        tree.createHuffmanTree(list);
        tree.showHuffmanTree(tree.root);
        getCode(node2);
    }

    /**
     * 结点
     * @param 
     */
    public static class TreeNode implements Comparable>{

        T data;
        int weight;
        TreeNode leftChild;
        TreeNode rightChild;
        TreeNode parent;

        public TreeNode(T data, int weight) {
            this.data = data;
            this.weight = weight;
            leftChild = null;
            rightChild = null;
            parent = null;
        }

        @Override
        public int compareTo(TreeNode o) {
            if (this.weight>o.weight){
                return 1;
            }else if (this.weight

你可能感兴趣的:(树(三,赫夫曼树))