基于数组实现的Huffman树和Huffman编码

一、Huffman树简介

1、定义

树的带权路径长度,就是树中所有的叶节点的权值乘上其到根节点的路径长度。

        在含有n 个带权叶子结点的二叉树中,其中带权路径长度(Weighted Path Length, WPL)最小的二叉树称为哈夫曼树, 也称最优二叉树。如图,c树的WPL=35最小,经验证其为哈夫曼树。

c树的WPL = 7*1 + 5*2 + 2*3 + 4*3 = 35

2、特点

假设有n个带权的节点

1)每个初始结点最终都成为叶结点,也就是这n个节点全都初始化为root节点。

2)构造过程中共新建了n-1个结点 (双分支结点),因此哈夫曼树的结点总数为2n- 1 。

3)每次构造都选择 2 棵树作为新结点的孩子,因此哈夫曼树中不存在度为1 的结点。

举例:数组的长度已定,为2n - 1

二、算法实现思路和代码

实现思路

以 a 7 b 5 c 2 d 4为例:

1、定义节点类:

2、构建huffman树

1、先初始化n个节点:他们的parent、lchild和rchild全为-1,且它们在数组中的索引分别为0、1、2、3

2、将这n个节点两个两个的合并:每次选两个权值weight最小且parent等于-1的节点(要写一个selectMin方法获取最小的节点)

第一步:选两个权值weight最小且parent等于-1的节点

第二步:合并他们,则父节点的权重等于这两个子节点的权重的个,父节点的左右孩子分别为这两个子节点的索引,父节点的data值设置为null,对应代码:

ht[i] = new Node<>(null,ht[s1].weight + ht[s2].weight,-1,s1,s2);

第三步:设置子节点的parent为父节点在数组中的索引,对应代码:

ht[s1].parent = ht[s2].parent = i;

重复该步骤

节点上面为数组的下标

第一次:

第二次:

第三次:

构建完成。

3、完整代码

Node类:

public class Node<T>{T data;//存放字符double weight;//权重int parent;//父节点int lchild;//左孩子int rchild;//右孩子public Node(T data, double weight, int parent, int lchild, int rchild) {this.data = data;this.weight = weight;this.parent = parent;this.lchild = lchild;this.rchild = rchild;}
}

HuffmanTree类:

public class HuffmanTree <T>{Node<T>[] ht;//n个元素对应的节点的个数,2*n + 1String[] hc;//对应的字符编码int n;//n个权值public HuffmanTree(int n) {this.ht = new Node[2*n - 1];this.hc = new String[n];this.n = n;}//在0-  m-1中选择权值最小的节点public int selectMin(int m){int k = 0,i;//第一个parent不等于-1的(根节点)for (i = 0;i < m; i++) {if (ht[i].parent == -1){//找到根k = i;break;}}for (i += 1;i < m; i++) {if (ht[i].parent == -1 && ht[i].weight < ht[k].weight){k = i;}}ht[k].parent = -2;return k;}public void createTree(){int i,s1,s2;Scanner scanner = new Scanner(System.in);System.out.println("请输入" + this.n + "个元素的权值,用空格分割:");//创建n个叶子节点for (i = 0; i < n; i++) {T d = (T)scanner.next();//数据域double w = scanner.nextDouble();//权值ht[i] = new Node<>(d, w, -1, -1, -1);}//构造huffman树for (;i < this.ht.length; i++) {//选择权值最小的两个节点,这两个节点的parent为-1s1 = selectMin(i);s2 = selectMin(i);ht[s1].parent = ht[s2].parent = i;ht[i] = new Node<>(null,ht[s1].weight + ht[s2].weight,-1,s1,s2);}}public void displayTree(){for (int i = 0; i < ht.length; i++) {System.out.println("元素:" + ht[i].data + ",权值:" + ht[i].weight + ",父元素:" + ht[i].parent + ",左孩子:" + ht[i].lchild + ",右孩子:" + ht[i].rchild);}}}

三、Huffman编码

对于一颗Huffman树,向左为0,向右为1

每个编码的长度不会超过n-1,char[] cd = new char[n - 1];

public String(char[] value,int offset,int count):分配一个新的 String,它包含取自字符数组参数一个子数组的字符。offset  参数是子数组第一个字符的索引,count 参数指定子数组的长度。该子数组的内容已被复制;后续对字符数组的修改不会影响新创建的字符串。

过程:

代码:

 public void createCode(){for (int i = 0; i < n; i++) {//按顺序生成元素的codechar[] cd = new char[n - 1];int start = n - 2;//从后往前填充cd数组//从最下一层开始向上遍历,直到根节点,现在就根节点的parent=-1,其他的都不是-1for (int c = i, f = ht[c].parent; f != -1; c = f, f = ht[c].parent) {//找到当前节点是父节点的左孩子还是右孩子if (ht[f].lchild == c) {//左孩子cd[start--] = '0';} else {//右孩子cd[start--] = '1';}}hc[i] = new String(cd,start + 1,n - start - 2);}}

四、对电文进行解码和编码

1、编码

直接和ht数组的data比较,相同的话就拼接hc对应的code

 //将要发送的电文进行编码后返回public String textCode(String text){String codeStr = "";for (int i = 0; i < text.length(); i++) {//转换成String进行比较String s = String.valueOf(text.charAt(i));for (int j = 0; j < hc.length; j++) {if (ht[j].data.equals(s)){codeStr += hc[j];break;}}}return codeStr;}

2、解码

 //解码的操作public String textDecode(String text){String decodeStr = "";for (int i = 0; i < text.length();  i++) {int p = this.ht.length - 1;//从根开始进行遍历//遍历到叶子节点,叶子节点的lchild和rchild都是-1while(ht[p].lchild != -1 && ht[p].rchild != -1){char ch = text.charAt(i);//可能会数组越界if (ch == '0'){p = ht[p].lchild;}else{p = ht[p].rchild;}i++;}decodeStr += ht[p].data;i--;//循环结束后,i已经加1了,所以要减1,回退到上一个字符,不然会数组越界}return decodeStr;}

五、主类测试输出

public class Main {public static void main(String[] args) {System.out.println("请输入元素的个数:");Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();HuffmanTree<Character> huffmanTree = new HuffmanTree<>(n);huffmanTree.createTree();huffmanTree.displayTree();huffmanTree.createCode();huffmanTree.displayCode();String afterdataearareartarea = huffmanTree.textCode("abcd");System.out.println(afterdataearareartarea);String s = huffmanTree.textDecode(afterdataearareartarea);System.out.println(s);}
}

输出结果:

请输入元素的个数:
4
请输入4个元素的权值,用空格分割:a 7 b 5 c 2 d 4
元素:a,权值:7.0,父元素:6,左孩子:-1,右孩子:-1
元素:b,权值:5.0,父元素:5,左孩子:-1,右孩子:-1
元素:c,权值:2.0,父元素:4,左孩子:-1,右孩子:-1
元素:d,权值:4.0,父元素:4,左孩子:-1,右孩子:-1
元素:null,权值:6.0,父元素:5,左孩子:2,右孩子:3
元素:null,权值:11.0,父元素:6,左孩子:1,右孩子:4
元素:null,权值:18.0,父元素:-1,左孩子:0,右孩子:5
a元素的编码是:0
b元素的编码是:10
c元素的编码是:110
d元素的编码是:111
010110111
abcd

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/7795.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

图说复变函数论重大错误:将无穷多各异平面误为同一面

黄小宁 医学若将前所未知的“新冠”病毒误为已熟知的流感病毒&#xff0c;后果...&#xff1b;数学将前所未知的点集误为已熟知的集就会引出一连串的重大错误。 h定理&#xff1a;点集AB的必要条件是A≌B。 证&#xff1a;&#xff08;1&#xff09;任何图≌自己是几何学最起码…

SDL简介和初次尝试

文章目录 SDL的用途和概念SDL下载 SDL的用途和概念 SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台开发库 &#xff0c;使用C语言写成&#xff0c;SDL提供了数种 操作 图像 &#xff0c;声音输入输出的函数&#xff0c;让开发者使用 相识的代码 就能够开发出跨平台的…

WiFi一直获取不到IP地址是怎么回事?

在当今这个信息化时代&#xff0c;WiFi已成为我们日常生活中不可或缺的一部分。无论是家庭、办公室还是公共场所&#xff0c;WiFi都为我们提供了便捷的无线互联网接入。然而&#xff0c;有时我们可能会遇到WiFi连接后无法获取IP地址的问题&#xff0c;这不仅影响了我们的网络使…

【车道线检测】一、传统车道线检测:基于霍夫变换的车道线检测史诗级详细教程

1、定义图像显示函数 首先定义一个函数&#xff0c;函数的作用是通过plt库显示两幅图&#xff0c;为后续实验做准备。该函数的主要功能是&#xff1a; 从指定路径加载图像显示图像的基本信息将图像从BGR格式转换为RGB格式并在一个图形窗口中显示两幅图像进行对比 import nump…

Ftrans数据跨境传输方案:保护隐私与促进合作

数据跨境传输是指在不同国家、地区和法律框架下进行的数据交换和传输&#xff0c;数据跨境传输流程周期是数据产生--数据传输--数据接收&#xff0c;而困境来源也来自这3个环节&#xff1a; 1.本地合规限制 数据出口国&#xff08;数据输出国&#xff09;的法律对于数据收集的…

Mybatis学习笔记(三)

十、MyBatis的逆向工程 (一)逆向工程介绍 MyBatis的一个主要的特点就是需要程序员自己编写sql&#xff0c;那么如果表太多的话&#xff0c;难免会很麻烦&#xff0c;所以mybatis官方提供了一个逆向工程&#xff0c;可以针对单表自动生成mybatis执行所需要的代码&#xff08;包…

Github 2024-11-08Java开源项目日报 Top9

根据Github Trendings的统计,今日(2024-11-08统计)共有9个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Java项目9Vue项目1经验丰富的Java(后端)开发人员核心面试问题和答案 | 互联网Java工程师进阶知识完全扫盲 创建周期:2085 天开发语言:Java协议…

【新闻文本分类识别】Python+CNN卷积神经网络算法+深度学习+人工智能+机器学习+文本处理

一、介绍 文本分类识别系统。本系统使用Python作为主要开发语言&#xff0c;首先收集了10种中文文本数据集&#xff08;“体育类”, “财经类”, “房产类”, “家居类”, “教育类”, “科技类”, “时尚类”, “时政类”, “游戏类”, “娱乐类”&#xff09;&#xff0c;然…

数据结构 ——— 链式二叉树的前中后序遍历递归实现

目录 前言 链式二叉树示意图​编辑 手搓一个链式二叉树 链式二叉树的前序遍历 链式二叉树的中序遍历 链式二叉树的后序遍历 前言 在上一章学习了链式二叉树的前中后序遍历的解析 数据结构 ——— 链式二叉树的前中后序遍历解析-CSDN博客 接下来要学习的是代码实现链式…

<项目代码>YOLOv8 pcb板缺陷检测<目标检测>

YOLOv8是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为一个回归问题&#xff0c;能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法&#xff08;如Faster R-CNN&#xff09;&#xff0c;YOLOv8具有更高的…

yarn报错`warning ..\..\package.json: No license field`:已解决

出现这个报错有两个原因 1、项目中没有配置许可证 在项目根目录package.json添加 {"name": "next-starter","version": "1.0.0",# 添加这一行"license": "MIT", }或者配置私有防止发布到外部仓库 {"priv…

大模型学习笔记------CLIP模型解读与思考

大模型学习笔记------CLIP模型详解 1、为什么提出CLIP模型2、CLIP模型详解3、CLIP模型的意义4、一些思考 上文说到&#xff0c;多模态大模型应该是非常有发展前景的&#xff0c;首先来学习 CLIP&#xff08;Contrastive Language-Image Pretraining&#xff09;这个多模态模型…

昇思25天学习打卡营第1天|快速入门

昇思25天学习打卡营第1天|快速入门 目录 昇思25天学习打卡营第1天|快速入门实操教程 一、MindSpore内容简介 主要特点&#xff1a; MindSpore的组成部分&#xff1a; 二、入门实操步骤 1. 安装必要的依赖包 2. 下载并处理数据集 3. 构建网络模型 4. 训练模型 5. 测试…

【Python TensorFlow】入门到精通

TensorFlow 是一个开源的机器学习框架&#xff0c;由 Google 开发&#xff0c;广泛应用于机器学习和深度学习领域。本篇将详细介绍 TensorFlow 的基础知识&#xff0c;并通过一系列示例来帮助读者从入门到精通 TensorFlow 的使用。 1. TensorFlow 简介 1.1 什么是 TensorFlow…

Python 学习完基础语法知识后,如何进一步提高?

入门Python后&#xff0c;就可以拿些小案例练手了&#xff0c;这时候千万不要傻乎乎地成天啃语法书。 编程是一门实践的手艺&#xff0c;讲究孰能生巧。不管是去手撸算法、或者照葫芦画瓢写几个小游戏都可以让你的Python突飞猛进。 之前看github比较多&#xff0c;推荐给大家…

Java:数据结构-再谈String类

字符串常量池 首先我们来思考这段代码&#xff0c;为什么运行结果一个是true&#xff0c;一个是false呢&#xff1f; public class Test {public static void main(String[] args) {String s1"123";String s2"123";String s3new String("555")…

书生第四期实训营基础岛——L1G2000 玩转书生「多模态对话」与「AI搜索」产品

基础任务 MindSearch使用示例 书生浦语使用示例 书生万象使用示例 进阶任务 问题&#xff1a;目前生成式AI在学术和工业界有什么最新进展&#xff1f; 回答截图&#xff1a; 知乎回答链接&#xff1a;目前生成式AI在学术和工业界有什么最新进展&#xff1f;

ReactPress:重塑内容管理的未来

ReactPress Github项目地址&#xff1a;https://github.com/fecommunity/reactpress 欢迎提出宝贵的建议&#xff0c;欢迎一起共建&#xff0c;感谢Star。 ReactPress&#xff1a;重塑内容管理的未来 在当今信息爆炸的时代&#xff0c;一个高效、易用的内容管理系统&#xff0…

短视频矩阵系统源码/抖去推源头技术4年开发

#短视频矩阵系统# #短视频矩阵系统源码# #短视频矩阵系统源码开发# #短视频矩阵系统源头技术开发# 抖音短视频矩阵系统集成开发是指利用抖音平台的开放接口和API&#xff0c;构建一个系统&#xff0c;该系统能够管理多个抖音矩阵账号&#xff0c;实现内容的统一发布、账号管理、…

CJ/T188-2004 报文举例

CJ/T188-2004 报文举例 # 读水表地址 # 请求报文&#xff1a; FE FE FE FE 68 AA AA AA AA AA AA AA AA 03 03 81 0A 00 49 16FE FE FE FE &#xff1a;前导字符 FE68 &#xff1a;起始字符AA &#xff1a;仪表类型AA AA AA AA AA AA AA &#xff1a;仪表地址&#xff08;当…