安卓数据结构06-哈夫曼树与哈夫曼编码

数据结构06-哈夫曼树

一、哈夫曼树的基本概念

1.哈夫曼树

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

哈夫曼树一般是用来数据压缩的,比如哈夫曼编码。

2.路径和路径长度

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

3.节点的权及带权路径长度

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

4.树的带权路径长度

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

二、哈夫曼树的实现

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

  1. 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个节点);
  2. 在森林中选出两个根节点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根节点权值为其左、右子树根节点权值之和;
  3. 从森林中删除选取的两棵树,并将新树加入森林;
  4. 重复2、3步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。
/**
 * 添加元素:添加时从小到大的权重顺序添加
 *
 * @param node 需要添加的节点
 */
public void put(Node<E> node) {
    if (root == null) {
        root = node;
        return;
    }

    Node<E> old = root;
    root = new Node<E>();
    root.bran = old.bran + node.bran;
    if (old.bran < node.bran) {
        root.left = old;
        root.right = node;
    } else {
        root.left = node;
        root.right = old;
    }
    old.parent = root;
    node.parent = root;
}

三、哈夫曼编码

将字符用0和1组成的不同长度的编码表示,每个字符的编码从头比较时,都不会相互包含,这样就可以正确识别每一个字符。现在将出现次数最多的字符用最小长度的编码表示,将出现次数最少的字符用最大长度的编码表示,这样得到的数据比用传统编码表示的数据要小,从而实现数据压缩。这样的编码就是哈夫曼编码。

/**
 * 将哈夫曼树转为哈夫曼编码
 * 哈夫曼树每个节点都有叶子节点,最下面的分支节点有两个叶子节点,我们现在要遍历所有的叶子节点,并用0和1表示,即为哈夫曼编码。
 */
public List<HuffmanCode<E>> getHuffmanCode() {
    Node<E> curr = root;
    if (curr == null) {
        return null;
    }
    List<HuffmanCode<E>> list = new ArrayList<>();
    String code = "";
    while (curr != null) {
        Node<E> left = curr.left;
        Node<E> right = curr.right;
        //到达叶子节点就退出
        if (left == null && right == null) {
            //只有一个节点时
            if (curr == root) {
                list.add(new HuffmanCode<E>(curr.data, code + "0"));
            }
            break;
        }
        //如果左子节点为叶子节点,则将其取出,并用0表示,然后遍历右子节点
        if (left.left == null && right.left != null) {
            list.add(new HuffmanCode<E>(left.data, code + "0"));
            curr = right;
            code += "1";
            //如果右子节点为叶子节点,则将其取出,并用1表示,然后遍历左子节点
        } else if (right.left == null && left.left != null) {
            list.add(new HuffmanCode<E>(right.data, code + "1"));
            curr = left;
            code += "0";
            //如果左右子节点都是叶子节点,则都取出,并且遍历结束
        } else if (right.left == null && left.left == null) {
            list.add(new HuffmanCode<E>(right.data, code + "1"));
            list.add(new HuffmanCode<E>(left.data, code + "0"));
            curr = null;
        }
    }
    return list;
}

最后

代码地址:https://gitee.com/yanhuo2008/Common/blob/master/Tool/src/main/java/gsw/tool/datastructure/tree/TreeHuffman.java

数据结构与算法专题:https://www.jianshu.com/nb/25128590

喜欢请点赞,谢谢!

    原文作者:最爱的火
    原文地址: https://www.jianshu.com/p/5d4eb3af2509
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞