哈夫曼树(huffman)

article/2025/9/29 1:17:52

学完了huffman树,讲一下自己对它的理解

  • huffman树遵循二叉树的原则,每个节点最多有两个子节点,但是每个节点都带有一个权重,如果我们要将一组字符串 “ B D C A F E ” 插入huffman树,每个字符都会带有一个权重,“ B(8)D(15)C(15)A(27)F(5)E(30)”

  • 首先要根据字符的权重从小到大排序,得到 “ F(5)B(8)C(15)D(15)A(27)E(30)” ,然后取出最小的两个,F和B ,从树的叶子节点开始插,然后得到F和B 的权重和 13 当做他们的父节点,这时候再把13和之前的字符串重新排序,重新取出两个权重最小的节点出来拼接(注:取出来的节点要从原数据里删除),如果取出来的两个里有之前的13(父节点),就把另一个和它一块组合成两个孩子节点继续往上走,刚才这里会走到下图的13和C那边,C的权重比13大,所以在右边,小即左边,继续往上走时从字符串里取出了两个最小的D(15)和A(27) 都比刚才的28小,他们和28没有关联,所以会另外生成一个新的父节点(权重42),然后再取得时候才会取到28和E(30),他们合成的父节点58,最后字符串里只剩下2个无名节点(我们不需要关注的节点),最后全部插入结果如 图一:

在这里插入图片描述

图一
  • 我们会发现我们需要的数据会全部插在叶子节点上!这个有什么用呢,如果我们把树从根节点往下查找数据,往左走用0来表示, 右用1来表示,那么生成的编码都将是唯一的!

  • 看 图二:

在这里插入图片描述

图二
  • 比如D在此树的编码会是00,A 01,E 11,C 1101,F 1000,B 1001

  • 所以利用huffman树这一规则,我们可以来做压缩,压缩通俗的讲就是把内容转化成占内存空间更小的字节,比如01。

  • 下面我们用代码写出一颗哈夫曼树:

  • 树的节点里和二叉排序树一样 有值、左右孩子、父节点 这里加了一个权重,用来判断树的存放位置的,节点里有个比大小的方法compareTo

public class HuffmanTree<Y> {public TreeNode<Y> root;   //根节点private String defaultParentItem = "Y";/*** 节点** @param <Y> 值*/public static class TreeNode<Y> implements Comparable<TreeNode<Y>> {Y item; //值int weight; //权重TreeNode<Y> left;   //左孩子TreeNode<Y> right;  //右孩子TreeNode<Y> parent; //父节点public TreeNode(Y item, int weight) {this.item = item;this.weight = weight;this.left = null;this.right = null;this.parent = null;}@Overridepublic int compareTo(@NonNull TreeNode<Y> o) {if (this.weight > o.weight) {return -1;} else if (this.weight < o.weight) {return 1;}return 0;}}
}

  • 这里用数组传进来 直接把一串内容插入到哈夫曼树里
    /*** 传一个数组进来 创建哈夫曼树** @param list 集合* @return 根节点*/public TreeNode<Y> createHuffmanTree(ArrayList<TreeNode<Y>> list) {//这里就当list里超过2个 就一直循环,知道删了只剩一个时出来 那时候这个节点就是根节点while (list.size() > 1) {//用Collections进行排序Collections.sort(list);//取list的最后2个当做左右孩子树TreeNode<Y> left = list.get(list.size() - 1);TreeNode<Y> right = list.get(list.size() - 2);//根据左右权重创建父节点TreeNode<Y> parent = new TreeNode<>((Y) defaultParentItem, left.weight + right.weight);//把左右树和父节点连接parent.left = left;left.parent = parent;parent.right = right;right.parent = parent;//从list里删除左右树list.remove(left);list.remove(right);//再把父节点添加进去list.add(parent);}root = list.get(0);return list.get(0);}

  • 这边输出我从根节点从左往右依次向下走 输出,利用了队列的先进先出原则
    /*** 横向依次输出树** @param root 根节点*/public void showHuffmanTree(TreeNode<Y> root) {//这里用LinkedList队列可以依次取出值LinkedList<TreeNode<Y>> list = new LinkedList<>();//入队list.offer(root);while (!list.isEmpty()) {//出队 直接输出TreeNode<Y> node = list.pop();if (node.item != defaultParentItem) {System.out.print(node.item + " ");}//如果左右还有孩子 就把左右孩子也入队,到下一个循环排在后面依次输出if (node.left != null) {list.offer(node.left);}if (node.right != null) {list.offer(node.right);}}}

  • 根据节点,取到自己的位置(编码)

  • 思想:根据节点依次向上走,如果自己是父节点的左孩子,就往栈里插入0,右孩子就插入1,一直到没有父节点时(即自己遍历到根节点了),然后从栈中取出数据返回即可

    /*** 根据节点获取编码** @param node 节点* @return 编码*/public String getCode(TreeNode<Y> node) {String str = "";TreeNode<Y> treeNode = node;//用栈装 待会拿出来就是正序了Stack<String> stack = new Stack<>();while (treeNode != null && treeNode.parent != null) {if (treeNode.parent.left == treeNode) {stack.push("0");} else if (treeNode.parent.right == treeNode) {stack.push("1");}treeNode = treeNode.parent;}//把stack里的值出栈while (!stack.isEmpty()) {str = str + stack.pop();}return str;}

  • 这边呢,我根据传进来的字符串编码,然后遍历它,得到字节,从根节点root出发向下走,如果是0就往左走,1往右走,如果走到的节点没有左孩子和右孩子了,即使我们要找的值,然后加进集合里 把node再次=根节点重新开始。。。
    /*** 根据传进来的编码返回一个list** @param code 编码字符串* @return 集合*/public ArrayList<TreeNode<Y>> getTreeNodeList(String code) {ArrayList<TreeNode<Y>> resultList = new ArrayList<>();TreeNode node = root;//依次循环 是0就往左边走 1右边走for (int i = 0; i < code.length(); i++) {if (code.charAt(i) == '0') {//如果左孩子不为空 就移到左孩子if (node.left != null) {node = node.left;//如果移动过后它的左孩子和右孩子都为空 则说明自己就是要取的值了 然后把node再次赋值为根节点,重新查if (node.left == null && node.right == null) {resultList.add(node);node = root;}}} else if (code.charAt(i) == '1') {if (node.right != null) {node = node.right;if (node.left == null && node.right == null) {resultList.add(node);node = root;}}}}return resultList;}

  • 好了 到这里程序的一些简单功能基本上写完了 让我们看看程序执行的效果:

  • 执行程序代码(这边用了注解):

    @org.junit.Testpublic void huffmanTreeTest() {ArrayList<HuffmanTree.TreeNode<String>> list = new ArrayList<>();HuffmanTree.TreeNode node1 = new HuffmanTree.TreeNode("good", 50);list.add(node1);HuffmanTree.TreeNode node2 = new HuffmanTree.TreeNode("morning", 10);list.add(node2);HuffmanTree.TreeNode node3 = new HuffmanTree.TreeNode("afternoon", 20);list.add(node3);HuffmanTree.TreeNode node4 = new HuffmanTree.TreeNode("hello", 110);list.add(node4);HuffmanTree.TreeNode node5 = new HuffmanTree.TreeNode("hi", 200);list.add(node5);System.out.print("原   数   据 :");for (int i = 0; i < list.size(); i++) {System.out.print(list.get(i).item + " ");}HuffmanTree<String> huffmanTree = new HuffmanTree<>();//创建树HuffmanTree.TreeNode root = huffmanTree.createHuffmanTree(list);//展示树System.out.print("\nhuffmanTree里:");huffmanTree.showHuffmanTree(root);String node1Code = huffmanTree.getCode(node1);String node2Code = huffmanTree.getCode(node2);String node3Code = huffmanTree.getCode(node3);String node4Code = huffmanTree.getCode(node4);String node5Code = huffmanTree.getCode(node5);//根据节点查询相应编码System.out.println("\n" + node1.item + "      在huffmanTree里的编码:" + node1Code);System.out.println(node2.item + "   在huffmanTree里的编码:" + node2Code);System.out.println(node3.item + " 在huffmanTree里的编码:" + node3Code);System.out.println(node4.item + "     在huffmanTree里的编码:" + node4Code);System.out.println(node5.item + "        在huffmanTree里的编码:" + node5Code);String code = node1Code + node2Code + node3Code + node4Code + node5Code;System.out.println("list里所有值的组成编码:" + code);System.out.println("================================解 码================================");ArrayList<HuffmanTree.TreeNode<String>> resultList = huffmanTree.getTreeNodeList(code);if (resultList != null) {for (int i = 0; i < resultList.size(); i++) {System.out.print(resultList.get(i).item + " ");}}}

  • 效果:

在这里插入图片描述

  • 怎么样 是不是感觉蛮有意思的。

  • 感觉观赏!


http://chatgpt.dhexx.cn/article/WnmWcqMX.shtml

相关文章

Huffman树和Huffman编码

文章目录 Huffman树的定义带权路径长度WPL Huffman树的构造Huffman树的特点 Huffman编码构造Huffman编码 Huffman树的定义 哈夫曼&#xff08;Huffman&#xff09;树&#xff0c;又称最优二叉树&#xff0c;是一类带权路径长度WPL最短的树。 带权路径长度WPL 要理解带权路径…

Huffman树(哈夫曼树)

哈夫曼树又称最优二叉树&#xff0c;是一种带权路径长度最短的二叉树。所谓树的带权路径长度&#xff0c;就是树中所有的叶结点的权值乘上其到根结点的路径长度&#xff08;若根结点为0层&#xff0c;叶结点到根结点的路径长度为叶结点的层数&#xff09;。树的带权路径长度记为…

虚拟机下安装BackTrack5 (BT5)教程及BT5汉化

isare邀请您访问Backtrack中文网 http://www.backtrack.org.cn/?fromuid50397 isare邀请您访问Backtrack中文网 http://www.backtrack.org.cn/?fromuserisare PS&#xff1a;back track 安装过程中有2点要注意&#xff1a;第一&#xff1a;复制到99%的时候会等大约10来分钟&a…

bt 下载工具 deluge 配置 优化 使用

目录 Ubuntu 18 配置 deluge Deluge 安卓远程客户端 Deluge 性能调优 deluge是基于libtorrentpython的跨平台bt/pt客户端&#xff0c;适合在Linux环境下使用 deluge完全开源免费&#xff0c;对IPv6支持良好&#xff0c;性能优于transmission&#xff1b;在嵌入式设备上使用d…

BT5的U盘完整安装

BT5是什么就不用多说了&#xff0c;从网上看了许多教程&#xff0c;大多是利用unetbootin工具将ISO文件直接解压到U盘上&#xff0c;这样并不能完全使用BT&#xff0c;保存好的文件&#xff0c;重启机器后就没了&#xff0c;其实就是当做光盘使用了&#xff0c;另外还有一个方法…

有哪些好用的BT下载器?

​​​​​​2022年5个好用的 BT/ 磁力链接下载工具推荐 &#xff5c;Windows 、安卓系统 | 科技雷达 A full-featured download manager

BT是如何下载的

BT协议简介 一、BT下载是怎么来的&#xff1f; 在互联网上下载文件的方式大概有这么几种&#xff1a;FTP、HTTP、BT、eMule(电驴)等&#xff0c; 浏览器会直接支持FTP和HTTP下载&#xff0c;BT和eMule下载一般需要专用的下载软件的支持。 接下来分别简单介绍一下他们的区别&…

ed2k下载

ed2k下载 在下载ed2k资源的时候&#xff0c;浏览器一般不能直接下载&#xff0c;这个时候该怎么办呢&#xff1f; 方法一&#xff1a;下载迅雷&#xff0c;直接安装 方法二&#xff1a;使用在线工具&#xff0c;将链接转化为别的形式 https://tool.lu/urlconvert/ 方法三&am…

BT是怎么下载的

BT协议简介 一、BT下载是怎么来的? 在互联网上下载文件的方式大概有这么几种:FTP、HTTP、BT、eMule(电驴)等, 浏览器会直接支持FTP和HTTP下载,BT和eMule下载一般需要专用的下载软件的支持。 接下来分别简单介绍一下他们的区别: FTP 是 File Transfer Protocol(文件…

最好用的bt下载器qbittorrent下载安装使用教程

qBittorrent绝对是我心目中BT下载工具中的NO.1&#xff0c;虽说我平时也会用迅雷下载国内的某些资源&#xff0c;但是仍然不妨碍它是我心目中的主力下载神器&#xff01;它可以说是我最早接触的除迅雷之外的一款BT下载神器。它是完全免费的种子和磁力链接下载工具&#xff0c;最…

BT5 WIFI破解

实验环境 VMwareWorkstation 9.0 BackTrack5 R3-GNOME-32 工具说明 VMware&#xff1a;著名的虚拟机软件&#xff0c;本实验采用虚拟机环境下安装BackTrack。 BackTrack&#xff1a;是一个基于Ubuntu GNU/Linux的发行版本&#xff0c;主要用做数字取证和入侵测试。其无线安全审…

BT5下载地址

http://www.backtrack-linux.org/downloads/ 下载方法&#xff1a; 1,先填写好网页里的三个框,如: Your Name(你的名字): ABC Email Address(邮箱): ABC163.com Country(国家): china 2,然后点"download" 3,按照自己的…

最全BT介绍

BitTorrent 简介 riba2534 2021年04月11日 19:26 阅读 851 关注 BitTorrent 简介 从 P2P 说起 经常在网上飙车的老司机应该都知道 BT 下载&#xff0c;但是有时候拿到了种子却下载不动&#xff0c;会不会很抓狂&#xff0c;是不是还觉得是自己网不行&#xff0c;那作为一…

034_Unicode标准

1. Unicode标准 1.1. 由于ASCII字符集、ISO字符集、GBK字符集列出的字符集都有容量限制, 而且不兼容多语言环境, Unicode联盟开发了Unicode标准。 1.2. Unicode标准涵盖了世界上的所有字符、标点和符号。 1.3. 不论是何种平台、程序或语言, Unicode都能够进行文本数据的处理…

24.字符编码

1.字符编码 1.1简介 字符编码只与文本文件和字符串有关。 字符编码&#xff1a;记录人类字符与二进制数的对应关系。计算机只能识别二进制&#xff0c;但是通过字符编码可以展示出各式各样的语言字符。1.2发展过程 1.计算机是美国人发明的&#xff0c;为了能够让加计算机能够…

汉字编码

http://blog.csdn.net/zzidea/article/details/8497532 C语言编程&#xff0c;基本的类型有字符型&#xff0c;整数型&#xff0c;浮点型。这些类型是我们对事物进行描述所必不可少的东西。即基础&#xff0c;又非常核心。所以必须掌握。 一、 字符集 ASCII GB2…

《Qt5:键盘事件》

QKeyEvent类用来描述了一个键盘事件。常用的键盘事件有两种&#xff1a;按键按下和按键释放&#xff0c;一般按键按下事件用的多一点&#xff0c;下面为键盘按下和释放事件的声明&#xff1a; public:void keyPressEvent(QKeyEvent *event);void keyReleaseEvent(QKeyEvent *ev…

小伙 这样你就可以在Mac 中运行 Office 办公软件了

小伙 这样你就可以在Mac 中运行 Office 办公软件了 请参考以下步骤&#xff1a; 1、打开已经安装好的 CrossOver&#xff0c;点击“安装 Windows 应用程序”&#xff0c;在选择应用中的搜索框中输入“office”&#xff0c;接下来在下拉列表中会出现非常多的已经列出的相关软件&…

Unicode 编码表

正则查找: 中文文字中文符号表情符号... [^\x00-\xff] 其中 \x00-\xff 匹配 ASCII 代码中十六进制代码为 00-ff 的字符&#xff0c; 加个取反 ^ &#xff0c;则就表示表示匹配非单字节的字符&#xff0c;例如汉字&#xff0c;汉字符号等字符集。 中文文字&#xff08;简体繁体…

arduino学习笔记-库函数解析_LiquidCrystal_i2c使用说明以及lcd1602的驱动

LiquidCrystal_i2c是一个通过i2c驱动lcd显示屏的库函数&#xff0c;具体使用说明如下 i2c转接芯片的型号 PCA8574 arduino R3 A05 为 SCL A04 为 SDL 在头文件下要初始化对象 LiquidCrystal_I2C lcd(0x27,16,2); 对象名 lcd 可以任意&#xff0c;这关系到下面你使用方法…