美文网首页
赫夫曼树(待完善)

赫夫曼树(待完善)

作者: 愿你我皆是黑马 | 来源:发表于2021-07-17 22:06 被阅读0次

什么是赫夫曼树

所有带权节点的,带权路径和,最小的二叉树,称为赫夫曼树。


手写3,2,1,5,7,13,8的这些权重为一个赫夫曼树

  1. 步骤一:将上述排序3,2,1,5,7,13,8。 为:1,2,3,5,7,8,13
  2. 步骤二:取出较小的两个12 组成以及他们的和3组成一个树(小左大右)。为:


    image.png
  3. 步骤三:将算出来的,再放入并去除12,再次排序。为3,3,5,7,8,13
  4. 步骤四:再次取出较小的两个3,3 因为里面的一个3个原来的1,2的和,所以将他们放到一起。为:


    image.png
  5. 步骤四:重复步骤3。为:5,6,7,8,13。继续取出56。为:


    image.png
  6. 步骤五:再次去除并排序。为 7,8,11,13。取出7,8
  7. 步骤六:由于取出的7,8其中没有原来相加的和,所以写在另一边。


    image.png
  8. 步骤七:再次去除并排序。为 11,15,13。取出11,15,为:


    image.png
  9. 步骤八:再次去除并排序。为 15,26。取出15,26,为:


    image.png

PS:计算WPL:WPL =节点权重*距顶点的线条个数,的和

WPL = 15 * 1 + 7 * 3 + 8 * 3 + 5 * 3 + 3 * 4 + 1 * 5 + 2 * 5 = 102


加出来的节点有什么用?

image.png

去除相加出来的节点,存色填充后,可以发现如下两个情况

  1. 任何一个字母到头结点的路径,都不会包含其他字母。(即赫夫曼树的前缀编码依据)
  2. 权重越小的距离顶节点距离越小。

当多个权值相等的时候怎么排序和放置(2个,3个,...n个一样的情况)?


赫夫曼树编码

将上述图:



所有左节点的连接线编码为0,所以右节点的线编码为1:



获得字母编码表:
字母 编码
a 0
b 100
c 101
d 110
e 1110
f 11110
g 11111

上述表中

  1. 权重越多,标识出现次数越多。编码位数越小
  2. 任何一个编码都不会是其他编码的子串。

使用代码实现赫夫曼树编码和解码

import java.util.*;

/************************************* 节点Bean ***************************************/
class 赫夫曼树节点 {
    char 真实字母;
    int 到顶节点的线条个数;
    int 该赫夫曼树节点的权重;
    boolean 是字母节点_不是求和得到的虚拟节点;
    赫夫曼树节点 左节点;
    赫夫曼树节点 右节点;
    boolean 有被遍历过 = false;
}

/************************************* 赫夫曼树 ***************************************/
public class 赫夫曼树 {
    private 赫夫曼树节点 跟节点;
    Map<Character, String> 赫夫曼树字符编码对应表 = new HashMap();
    Map<String, Character> 赫夫曼树编码字符对应表 = new HashMap();

    public Map<Character, Integer> 解析字符串_并且_返回每个字符的_权重对应关系(String 被编码字符串) {
        Map<Character, Integer> 权重对应表 = new HashMap();
        char 被编码字符串字符数组[] = 被编码字符串.toCharArray();
        Integer n;
        for (int 被编码字符串第i个字符_下标 = 0; 被编码字符串第i个字符_下标 < 被编码字符串字符数组.length; 被编码字符串第i个字符_下标++) {
            char 被编码字符串_第i个字符 = 被编码字符串字符数组[被编码字符串第i个字符_下标];
            if ((n = 权重对应表.get(被编码字符串_第i个字符)) != null) {
                权重对应表.put(被编码字符串_第i个字符, ++n);
            } else {
                权重对应表.put(被编码字符串_第i个字符, 1);
            }
        }
        return 权重对应表;
    }

    public void 根据上面返回的_权重对应表_生成赫夫曼树(Map<Character, Integer> 权重对应表) {
        if (权重对应表 == null) {
            return;
        }
        Set<Character> 权重对应表中的字母集 = 权重对应表.keySet();
        Collection<Integer> 权重对应表中的权重集 = 权重对应表.values();

        赫夫曼树节点 新的赫夫曼树左节点 = new 赫夫曼树节点(); //较小的那个
        赫夫曼树节点 新的赫夫曼树节点右节点 = new 赫夫曼树节点();
        赫夫曼树节点 新的赫夫曼树节点求和父节点 = new 赫夫曼树节点();
        新的赫夫曼树节点求和父节点.左节点 = 新的赫夫曼树左节点;
        新的赫夫曼树节点求和父节点.右节点 = 新的赫夫曼树节点右节点;
        新的赫夫曼树节点求和父节点.该赫夫曼树节点的权重 = 新的赫夫曼树节点求和父节点.左节点.该赫夫曼树节点的权重 + 新的赫夫曼树节点求和父节点.右节点.该赫夫曼树节点的权重;
    }

    private Stack<String> 编码01节点栈 = new Stack<>();

    public void 遍历赫夫曼树_并_设置字符编码和编码字符Hash表() {
        if (跟节点 == null) {
            System.out.println("需要先调用方法:根据上面返回的_权重对应表_生成赫夫曼树()");
            return;
        }
        //TODO 初始化数据
        //...
        遍历赫夫曼树用的递归方法(跟节点);
    }

    private void 遍历赫夫曼树用的递归方法(赫夫曼树节点 当前递归到的节点) {
        当前递归到的节点.有被遍历过 = true;
        if (当前递归到的节点.是字母节点_不是求和得到的虚拟节点) {
            String 当前节点编码 = 编码01节点栈.toString().replaceAll(",| |\\]|\\[", "");
            赫夫曼树字符编码对应表.put(当前递归到的节点.真实字母, 当前节点编码);
            赫夫曼树编码字符对应表.put(当前节点编码, 当前递归到的节点.真实字母);
        } else { //是虚拟节点
            if (当前递归到的节点.左节点 != null && !当前递归到的节点.左节点.有被遍历过) {
                编码01节点栈.push("0");//往左节点走,就push一个0编码
                遍历赫夫曼树用的递归方法(当前递归到的节点.左节点);
            }

            if (当前递归到的节点.右节点 != null && !当前递归到的节点.右节点.有被遍历过) {
                编码01节点栈.push("1");//往右节点走,就push一个1编码
                遍历赫夫曼树用的递归方法(当前递归到的节点.右节点);
            }
        }
        //真实节点或虚拟节点的左右子树都遍历过了,弹出最后一个编码记录
        编码01节点栈.pop();
    }

    /*********************************** 编码&译码 ***********************************/
    public String 编码(String 被编码字符串) {
        StringBuilder 编码结果字符串 = new StringBuilder();
        for (int 被编码字符串第i个字符 = 0; 被编码字符串第i个字符 < 被编码字符串.length(); 被编码字符串第i个字符++) {
            if (赫夫曼树字符编码对应表.containsKey(被编码字符串.charAt(被编码字符串第i个字符))) {
                编码结果字符串.append(赫夫曼树编码字符对应表.get(被编码字符串.charAt(被编码字符串第i个字符)));
            } else {
                throw new RuntimeException("赫夫曼树编码字符对应表中,没有对应编码:" + 被编码字符串.charAt(被编码字符串第i个字符), null);
            }
        }
        return 编码结果字符串.toString();
    }

    public String 译码(String 编码后的字符串) {
        StringBuilder 译码结果字符串 = new StringBuilder();
        StringBuilder 当前发现的编码 = new StringBuilder();
        for (int 编码后的字符串第i个字符 = 0; 编码后的字符串第i个字符 < 编码后的字符串.length(); 编码后的字符串第i个字符++) {
            当前发现的编码.append(编码后的字符串.charAt(编码后的字符串第i个字符));
            if (赫夫曼树编码字符对应表.containsKey(当前发现的编码.toString())) {
                译码结果字符串.append(赫夫曼树编码字符对应表.get(当前发现的编码.toString()));
                当前发现的编码.delete(0, 当前发现的编码.length());
            }
        }
        return 译码结果字符串.toString();
    }

}


class 测试 {
    public static void main(String[] args) {
        赫夫曼树 测试赫夫曼树 = new 赫夫曼树();
        String 测试字符串 = "afafdsfsfd";

        Map<Character, Integer> 权重对应关系 = 测试赫夫曼树.解析字符串_并且_返回每个字符的_权重对应关系(测试字符串);
        System.out.println("权重对应关系:" + 权重对应关系);
        测试赫夫曼树.根据上面返回的_权重对应表_生成赫夫曼树(权重对应关系);
        测试赫夫曼树.遍历赫夫曼树_并_设置字符编码和编码字符Hash表();
        System.out.println("赫夫曼树字符编码对应表:" + 测试赫夫曼树.赫夫曼树字符编码对应表);
        System.out.println("赫夫曼树编码字符对应表:" + 测试赫夫曼树.赫夫曼树编码字符对应表);
        String 编码后的字符串 = 测试赫夫曼树.编码(测试字符串);
        测试赫夫曼树.译码(编码后的字符串);
    }
}

相关文章

  • 赫夫曼树(待完善)

    什么是赫夫曼树 所有带权节点的,带权路径和,最小的二叉树,称为赫夫曼树。 手写3,2,1,5,7,13,8的这些权...

  • Java_二叉树用途

    赫夫曼树 赫夫曼树的构造 赫夫曼树构造过程 查找二叉树

  • 赫夫曼编码对文件进行压缩与解密

    理论 赫夫曼树 先有赫夫曼树,才有赫夫曼编码。所以,首先简单介绍一下什么是赫夫曼树。 假设一共五个叶子节点,分别是...

  • 赫夫曼编码&解码

    之前说到了如何构建赫夫曼树,那么赫夫曼树有什么用呢?赫夫曼树经典的应用之一就是赫夫曼编码。 1. 赫夫曼编码是什么...

  • 哈夫曼树(赫夫曼树、最优树)及C语言实现

    from:http://data.biancheng.net/view/33.html 赫夫曼树,别名“哈夫曼树”...

  • 赫夫曼树

    赫夫曼树 Q:什么是赫夫曼树(也叫最优二叉树,有点像得到最优解的贪心法)? A:带权路径长度最小的二叉树 Q:如何...

  • 赫夫曼树

    带权路径最短的树,构建赫夫曼树的思路 排序,将最小与次小转为节点,并根据权生成父节点,将父节点加入到结合, 移除最...

  • 赫夫曼树

    1. 基本介绍: 路径:从一个节点到达其后辈节点的通路,称为路径。通路中分支的数目称为路径长度。上面这棵二叉树,黄...

  • 赫夫曼树与赫夫曼编码

    赫夫曼树与赫夫曼编码 一、赫夫曼树 在数据膨胀、信息爆炸的今天,数据压缩的意义不言而喻。谈到数据压缩,就不能不提赫...

  • 数据结构(五):哈夫曼树(Huffman Tree)

    哈夫曼树 哈夫曼树(或者赫夫曼树、霍夫曼树),指的是一种满二叉树,该类型二叉树具有一项特性,即树的带权路径长最小,...

网友评论

      本文标题:赫夫曼树(待完善)

      本文链接:https://www.haomeiwen.com/subject/algwpltx.html