java赫夫曼编码

news2025/6/8 7:06:58

1.基本介绍

  1. 赫夫曼编码也翻译为 哈夫曼编码(Huffman Coding),又称霍夫曼编码,是一种编码方式, 属于一种程序算法
  2. 赫夫曼编码是赫哈夫曼树在电讯通信中的经典的应用之一。
  3. 赫夫曼编码广泛地用于数据文件压缩。其压缩率通常在 20%~90%之间
  4. 赫夫曼码是可变字长编码(VLC)的一种。Huffman 于 1952 年提出一种编码方法,称之为最佳编码

2.原理剖析
通信领域中信息的处理方式 1-定长编码

在这里插入图片描述
通信领域中信息的处理方式 2-变长编码

在这里插入图片描述

通信领域中信息的处理方式 3-赫夫曼编码

步骤如下;

传输的 字符串

  1. i like like like java do you like a java

  2. d:1 y:1 u:1 j:2 v:2 o:2 l:4 k:4 e:4 i:5 a:5 :9 // 各个字符对应的个数

  3. 按照上面字符出现的次数构建一颗赫夫曼树, 次数作为权值
    步骤:

构成赫夫曼树的步骤:

  1. 从小到大进行排序, 将每一个数据,每个数据都是一个节点 , 每个
    节点可以看成是一颗最简单的二叉树

  2. 取出根节点权值最小的两颗二叉树

  3. 组成一颗新的二叉树, 该新的二叉树的根节点的权值是前面两颗二叉树根节点权值的和

  4. 再将这颗新的二叉树,以根节点的权值大小 再次排序, 不断重复 1-2-3-4 的步骤,直到数列中,所有的数据都被处理,
    就得到一颗赫夫曼树

在这里插入图片描述
4 根据赫夫曼树,给各个字符,规定编码 (前缀编码), 向左的路径为 0 向右的路径为 1 , 编码
如下:
o: 1000 u: 10010 d: 100110 y: 100111 i: 101
a : 110 k: 1110 e: 1111 j: 0000 v: 0001
l: 001 : 01

5 按照上面的赫夫曼编码,我们的"i like like like java do you like a java" 字符串对应的编码为 (注
意这里我们使用的无损压缩)
10101001101111011110100110111101111010011011110111101000011000011100110011110000110
01111000100100100110111101111011100100001100001110 通过赫夫曼编码处理 长度为 133

6 长度为 : 133
说明:
原来长度是 359 , 压缩了 (359-133)

此编码满足前缀编码, 即字符的编码都不能是其他字符编码的前缀。不会造成匹配的多义性
赫夫曼编码是无损处理方案

注意事项
注意, 这个赫夫曼树根据排序方法不同,也可能不太一样,这样对应的赫夫曼编码也不完全一样,但是 wpl 是
一样的,都是最小的, 最后生成的赫夫曼编码的长度是一样,比如: 如果我们让每次生成的新的二叉树总是排在权
值相同的二叉树的最后一个,则生成的二叉树为:

在这里插入图片描述
3.最佳实践-数据压缩(创建赫夫曼树)

将给出的一段文本,比如 “i like like like java do you like a java” , 根据前面的讲的赫夫曼编码原理,对其进行数
据 压 缩 处 理 , 形 式 如

"1010100110111101111010011011110111101001101111011110100001100001110011001111000011001111000100100100
110111101111011100100001100001110

"步骤 1:根据赫夫曼编码压缩数据的原理,需要创建 "i like like like java do you like a

思路:前面已经分析过了,而且我们已然讲过了构建赫夫曼树的具体实现。
代码实现:

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class HuffmanCode {
	public static void main(String[] args) {
		String content = "i like like like java do you like a java";
		byte[] contentBytes = content.getBytes();
		System.out.println(contentBytes.length);
		List<Node> nodes = getNodes(contentBytes);
		System.out.println("nodes=" + nodes);
		
		//测试
		System.out.println("赫夫曼树");
		Node huffmanTreeRoot = createHuffManTree(nodes);
		System.out.println("前序遍历");
		huffmanTreeRoot.preOrder();
	}
	
	//前序遍历方法
	public static void preOrder(Node root) {
		if(root != null) {
			root.preOrder();
		}else {
			System.out.println("赫夫曼树为空");
		}
	}

	/**
	 * 
	 * @param bytes 接收字符
	 * @return 返回的就是List形式
	 */
	private static List<Node> getNodes(byte[] bytes) {

		// 1创建一个ArrayList
		ArrayList<Node> nodes = new ArrayList<Node>();

		// 遍历bytes,统计每一个byte出现的次数 ->map[key ,value]
		Map<Byte, Integer> counts = new HashMap<>();
		for (byte b : bytes) {
			Integer count = counts.get(b);
			if (count == null) {// Map还没有这个字符数据,第一次
				counts.put(b, 1);
			} else {
				counts.put(b, count + 1);
			}
		}

		// 把每一个键值对转成一个Node对象,并加入到nodes集合
		// 遍历map
		for (Map.Entry<Byte, Integer> entry : counts.entrySet()) {
			nodes.add(new Node(entry.getKey(), entry.getValue()));
		}
		return nodes;
	}

	// 可以通过List创建对应的赫夫曼树
	private static Node createHuffManTree(List<Node> node) {

		while (nodes.size() > 1) {
			// 排序, 从小到大
			Collections.sort(nodes);
			// 取出第一颗最小的二叉树
			Node leftNode = nodes.get(0);
			// 取出第二颗最小的二叉树
			Node rightNode = nodes.get(1);
			// 创建一颗新的二叉树,它的根节点 没有 data, 只有权值
			Node parent = new Node(null, leftNode.weight + rightNode.weight);
			parent.left = leftNode;
			parent.right = rightNode;
			// 将已经处理的两颗二叉树从 nodes 删除
			nodes.remove(leftNode);
			nodes.remove(rightNode);
			// 将新的二叉树,加入到 nodes
			nodes.add(parent);
		}
		// nodes 最后的结点,就是赫夫曼树的根结点
		return nodes.get(0);

	}
}

//创建Node,待数据和权值
class Node implements Comparable<Node> {
	Byte data;// 存放数据(字符)本身,比如'a' => 97 '' = 32
	int weight;// 权值,表示字符出现的次数
	Node left;
	Node right;

	public Node(Byte data, int weight) {
		this.data = data;
		this.weight = weight;
	}

	@Override
	public int compareTo(Node o) {
		// 从小到大排序
		return this.weight - o.weight;
	}

	public String toString() {
		return "Node [data=" + data + " weight=" + weight + "]";
	}

	// 前序遍历
	public void preOrder() {
		System.out.println(this);
		if (this.left != null) {
			this.left.preOrder();
		}
		if (this.right != null) {
			this.right.preOrder();
		}
	}

}

最佳实践-数据压缩(生成赫夫曼编码和赫夫曼编码后的数据)

我们已经生成了 赫夫曼树, 下面我们继续完成任务

  1. 生成赫夫曼树对应的赫夫曼编码 , 如下表: =01 a=100 d=11000 u=11001 e=1110 v=11011 i=101 y=11010 j=0010 k=1111 l=000 o=0011
  2. 使用赫夫曼编码来生成赫夫曼编码数据 ,即按照上面的赫夫曼编码,将"i like like like java do you like a java" 字符串生成对应的编码数据, 形式如下. 10101000101111111100100010111111110010001011111111001001010011011100011100000110111010001111001010
    00101111111100110001001010011011100
  3. 思路:前面已经分析过了,而且我们讲过了生成赫夫曼编码的具体实现。
  4. 代码实现:看老师演示:
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class HuffmanCode {
	public static void main(String[] args) {
		String content = "i like like like java do you like a java";
		byte[] contentBytes = content.getBytes();
		System.out.println(contentBytes.length);
		List<Node> nodes = getNodes(contentBytes);
		System.out.println("nodes=" + nodes);

		// 测试
		System.out.println("赫夫曼树");
		Node huffmanTreeRoot = createHuffManTree(nodes);
		System.out.println("前序遍历");
		huffmanTreeRoot.preOrder();
	}

	// 前序遍历方法
	public static void preOrder(Node root) {
		if (root != null) {
			root.preOrder();
		} else {
			System.out.println("赫夫曼树为空");
		}
	}

	/**
	 * 
	 * @param bytes 接收字符
	 * @return 返回的就是List形式
	 */
	private static List<Node> getNodes(byte[] bytes) {

		// 1创建一个ArrayList
		ArrayList<Node> nodes = new ArrayList<Node>();

		// 遍历bytes,统计每一个byte出现的次数 ->map[key ,value]
		Map<Byte, Integer> counts = new HashMap<>();
		for (byte b : bytes) {
			Integer count = counts.get(b);
			if (count == null) {// Map还没有这个字符数据,第一次
				counts.put(b, 1);
			} else {
				counts.put(b, count + 1);
			}
		}

		// 把每一个键值对转成一个Node对象,并加入到nodes集合
		// 遍历map
		for (Map.Entry<Byte, Integer> entry : counts.entrySet()) {
			nodes.add(new Node(entry.getKey(), entry.getValue()));
		}
		return nodes;
	}

	// 可以通过List创建对应的赫夫曼树
	private static Node createHuffManTree(List<Node> node) {

		while (nodes.size() > 1) {
			// 排序, 从小到大
			Collections.sort(nodes);
			// 取出第一颗最小的二叉树
			Node leftNode = nodes.get(0);
			// 取出第二颗最小的二叉树
			Node rightNode = nodes.get(1);
			// 创建一颗新的二叉树,它的根节点 没有 data, 只有权值
			Node parent = new Node(null, leftNode.weight + rightNode.weight);
			parent.left = leftNode;
			parent.right = rightNode;
			// 将已经处理的两颗二叉树从 nodes 删除
			nodes.remove(leftNode);
			nodes.remove(rightNode);
			// 将新的二叉树,加入到 nodes
			nodes.add(parent);
		}
		// nodes 最后的结点,就是赫夫曼树的根结点
		return nodes.get(0);

	}
}

//创建Node,待数据和权值
class Node implements Comparable<Node> {
	Byte data;// 存放数据(字符)本身,比如'a' => 97 '' = 32
	int weight;// 权值,表示字符出现的次数
	Node left;
	Node right;

	public Node(Byte data, int weight) {
		this.data = data;
		this.weight = weight;
	}

	@Override
	public int compareTo(Node o) {
		// 从小到大排序
		return this.weight - o.weight;
	}

	public String toString() {
		return "Node [data=" + data + " weight=" + weight + "]";
	}

	// 前序遍历
	public void preOrder() {
		System.out.println(this);
		if (this.left != null) {
			this.left.preOrder();
		}
		if (this.right != null) {
			this.right.preOrder();
		}
	}

}

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

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

相关文章

[Android]网络框架之Retrofit(kotlin)

目录 Retrofit简介 Retrofit基本使用 Retrofit的注解 Retrofit的转换器 文件的上传与下载 Retrofit简介 Retrofit是一款由Square公司开发的网络库&#xff0c;但是它和OkHttp的定位完全不同。 OkHttp侧重的是底层通信的实现&#xff0c;而Retrofit侧重的是上层接口的封装…

永磁同步电机中BEMF电阻的作用

一、电路原理图 二、原理分析 如图一我们测的是相电压&#xff0c;从理论上我们知道我们测得相电压是一个马鞍波形&#xff0c;马鞍波形中并没有隐含 转子的位置和速度信息。那么为什么我们还要有这样一个电路呢&#xff1f; 这个问题其实困惑了我好久&#xff1f;直到有一天…

曹云金对德云社最大的贡献,就是促进了薪酬体系改革

虽然曹云金已经离开德云社&#xff0c;但是关于他和德云社的话题&#xff0c;却从来没有间断过&#xff0c;尤其是他和小岳岳的对比&#xff0c;更是很有争议的一个话题。实话实说&#xff0c;曹云金在德云社的这些年&#xff0c;对这个这个民间相声社团发展&#xff0c;还是做…

Docker实战

目录一、FROM 语法二、label语法三、run语法四、workdir 语法五、add 和copy 语法六、ENV语法七、volume 和expose 语法八、run、cmd 和entrypoint一、FROM 语法scratch -- 从头开始尽量来使用官方提供的imageFROM 指定基础镜像&#xff0c;最好挑一些apline&#xff0c;slim之…

Qml学习——控件状态

最近在学习Qml&#xff0c;但对Qml的各种用法都不太熟悉&#xff0c;总是会搞忘&#xff0c;所以写几篇文章对学习过程中的遇到的东西做一个记录。 学习参考视频&#xff1a;https://www.bilibili.com/video/BV1Ay4y1W7xd?p1&vd_source0b527ff208c63f0b1150450fd7023fd8 其…

Apache安全加固配置教程(小白篇)

Apache安全加固配置教程(小白篇) 资源宝分享&#xff1a;www.httple.net 一&#xff0c;Apache服务器的介绍 Apache服务器它是Internet网上应用最为广泛的Web服务器软件之一。Apache服务器源自美国国家超级技术计算应用中心&#xff08;NCSA&#xff09;的 Web服务器项目中。目…

SAS应用入门学习笔记3

操作数据集的观测&#xff1a; Eg. 修改变量值等 变量的值取出来&#xff0c;那么我们需要对变量的值进行修改 weight height bmi? Missing 用到条件语if then、赋值语句、表达式 等。 表达式是操作数和操作符的序列。 例如&#xff1a;3 x x1 1、操作数&#xff1a;…

每日学术速递2.9

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.CV、cs.AI、cs.LG、cs.IR 1.Graph Signal Sampling for Inductive One-Bit Matrix Completion: a Closed-form Solution(ICLR 2023) 标题&#xff1a;归纳单比特矩阵完成的图信号采样&am…

程序员该不该在年后跳槽?3个问句给你答案

过完春节&#xff0c;2023年也迎来了第二个月份&#xff0c;有些程序员虽然还在公司上班&#xff0c;但是私底下跳槽的心蠢蠢欲动&#xff0c;简历说不定都改到第三版了。 在各大社交平台上&#xff0c;经常能看到不少程序员分享自己的跳槽经历&#xff0c;尤其是春节后更是如…

13薪|运营策划[北京市 - 海淀区]-10k-15k

"众推职聘”以交付结果为宗旨的全流程化招聘服务平台&#xff01;今日招聘信息↓【工作内容】1、根据项目要求&#xff0c;收集相关数据&#xff0c;策划撰写项目运营方案&#xff1b;2、运营合作环节中&#xff0c;监督管理执行&#xff1b;3、参与项目的评估&#xff1b…

WorkTool无障碍服务实现企业微信机器人接口

前言 想要实现一个企业微信机器人&#xff0c;如京东/拼多多福利群、美团瑞幸定时营销群、自助订单查询、智能咨询或社群管理机器人等&#xff0c;首先官方未提供外部群/客户群的机器人API&#xff0c;会话存档也只在一定场景下适用&#xff0c;及时使用会话存档也存在只能收不…

56 门控循环单元(GRU)【动手学深度学习v2】

56 门控循环单元&#xff08;GRU&#xff09;【动手学深度学习v2】 深度学习学习笔记 学习视频&#xff1a;https://www.bilibili.com/video/BV1mf4y157N2/?spm_id_fromautoNext&vd_source75dce036dc8244310435eaf03de4e330 门控循环单元GRU GRU和LSTM 实际上效果差不多。…

030_SSS_MaskSketch Unpaired Structure-guided Masked Image Generation

MaskSketch: Unpaired Structure-guided Masked Image Generation 1. Introduction 本文在MaskGIT的基础上进行了改进&#xff0c;提出了MaskSketch用于sketch-to-photo。MaskSketch直接使用预训练好的MaskGIT&#xff0c;不需要进行模型的训练&#xff0c;而且不需要成对的监…

29 - 面向对象的三大特征 - 多态

目录 一、理解多态 1、概念 2、使用场景 3、特点 二、多态案例1 1、需求 2、代码实现 一、理解多态 1、概念 不同的子类对象调用相同的父类方法&#xff0c;产生不同的执行结果2、使用场景 以继承和重写父类方法为前提是调用方法的技巧&#xff0c;不会影响到类的内部设计3、特…

Kubernetes那点事儿——健康检查

K8s应用程序生命周期管理——健康检查前言一、重启策略二、健康检查三、健康监控方式前言 官网&#xff1a;https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-readiness-probes 一、重启策略 Always&a…

云原生技术在容器方面的应用

随着近几年云原生生态的不断壮大&#xff0c;众多企业纷纷开展了用云上云的工作&#xff0c;学习和了解云原生及容器技术对于现代工程师是必不可少的&#xff0c;本文主要为大家介绍云原生及其在容器方面的应用。 1.1 什么是云原生 云原生技术有利于各组织在公有云、私有云和…

基于可视化 BI 工具 DataEase 制作第七次人口普查数据分析大屏

一、制作第七次人口普查数据大屏的背景介绍&#xff1a;第七次人口普查刚刚结束&#xff0c;想要制作一个大屏&#xff0c;能够直观的看到人口总数、出生人数、死亡人数等的情况&#xff1b;希望能够直观的看到人口分布的情况、各种比例、年龄结构等有一定的了解&#xff1b;直…

【网络原理篇2】TCP报头详解

在这一篇文章当中&#xff0c;了解到TCP是属于传输层的协议&#xff1b;当数据从应用层向传输层发送的时候&#xff0c;如果使用的是TCP协议&#xff0c;那么就需要把应用层的数据加上TCP报头。初识网络&#xff1a;IP、端口、网络协议、TCP-IP五层模型_革凡成圣211的博客-CSDN…

2023年去培训机构学前端还是Java?

选择专业肯定是优先考虑更有发展前景和钱途的专业。毕竟IT专业的培训费都不低&#xff0c;基本都要一两万左右&#xff0c;咱们花钱总是希望获得最大回报。 那么到底哪个更有发展前景呢&#xff1f; 零基础能学得会吗&#xff1f; 就业薪资如何呢&#xff1f; 前言 不知道大家有…

Python运算符优先级

以下表格列出了从最高到最低优先级的所有运算符&#xff1a;运算符描述**指数 (最高优先级)~ -按位翻转, 一元加号和减号 (最后两个的方法名为 和 -)* / % //乘&#xff0c;除&#xff0c;取模和取整除 -加法减法>> <<右移&#xff0c;左移运算符&位 AND^ |位…