Java实现哈夫曼编码和解码
最近无意中想到关于api返回值加密的问题,譬如我们的api需要返回一些比较敏感或者重要不想让截获者得到的信息,像如果是做原创图文的,文章明文返回的话则有可能被抓包者窃取。
关于请求时加密的方式比较多,像常见的如阿里某api就是根据所有参数ascii码升序排序并加盐加密,这样能避免黑客篡改请求值。那关于返回值加密的,我觉得用哈夫曼编码就不错。
大家都知道哈夫曼是用来做压缩解压的算法,通过哈夫曼压缩后的数据其实就相当于加密了,我们可以把返回值用哈夫曼算法压缩得到一串的0101,然后再随便头尾补个乱码什么的值,到客户端再把乱码去除,在一定程度上就能让截获者迷惑了,而且传输的数据量也小了一些,节省流量。
这里有一篇是讲java实现哈夫曼的。
题目:将一个字符串进行哈夫曼编码;编码过程中,会得到每个字符的编码,通过已知的每个字符的编码对之前的编码进行解码。
分析:
首先是哈夫曼编码算法,引用李泽年写的《多媒体技术教程》中对哈夫曼编码算法的描述:
- package com.liyuncong.algorithms.algorithms_huffman;
- import java.util.Map;
- /**
- * 对字符串编码后的结果:包括编码后的字符串和字符/编码对
- * @author yuncong
- *
- */
- public class EncodeResult {
- // 字符串编码后的结果
- private String encode;
- // 字符编码对
- private Map<Character, String> letterCode;
- public EncodeResult(String encode, Map<Character, String> letterCode) {
- super();
- this.encode = encode;
- this.letterCode = letterCode;
- }
- public String getEncode() {
- return encode;
- }
- public Map<Character, String> getLetterCode() {
- return letterCode;
- }
- }
- package com.liyuncong.algorithms.algorithms_huffman;
- public interface HuffmanAlgorithm {
- /**
- * 编码字符串。
- * @param str 指定的需要编码的字符串
- * @return 编码结果
- */
- public EncodeResult encode(String str);
- /**
- * 根据编码结果返回原来的字符串。
- * @param decodeResult 原来字符串的编码结果。
- * @return 解码出来的字符串。
- */
- public String decode(EncodeResult encodeResult);
- }
- package com.liyuncong.algorithms.algorithms_huffman;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.Set;
- import com.liyuncong.application.commontools.FileTools;
- public abstract class HuffmanAlgorithmAbstract implements HuffmanAlgorithm {
- @Override
- public EncodeResult encode(String str) {
- ArrayList<Node> letterList = toList(str);
- Node rootNode = createTree(letterList);
- Map<Character, String> letterCode = getLetterCode(rootNode);
- EncodeResult result = encode(letterCode, str);
- return result;
- }
- /**
- * 把一个字符串转化为节点列表
- * @param letters
- * @return
- */
- private ArrayList<Node> toList(String letters) {
- ArrayList<Node> letterList = new ArrayList<Node>();
- Map<Character, Integer> ci = new HashMap<Character, Integer>();
- for (int i = 0; i < letters.length(); i++) {
- Character character = letters.charAt(i);
- if (!ci.keySet().contains(character)) {
- ci.put(character, 1);
- } else {
- Integer oldValue = ci.get(character);
- ci.put(character, oldValue + 1);
- }
- }
- Set<Character> keys = ci.keySet();
- for (Character key : keys) {
- Node node = new Node();
- Data data = new Data();
- data.setC(key);
- data.setFrequency(ci.get(key));
- node.setData(data);
- letterList.add(node);
- }
- return letterList;
- }
- protected abstract Node createTree(ArrayList<Node> letterList);
- /**
- * 编码字符串。
- * @param letterCode 字符/编码对集合。
- * @param letters 指定的需要编码的字符串。
- * @return 编码结果
- */
- private EncodeResult encode(Map<Character, String> letterCode, String letters) {
- StringBuilder encode = new StringBuilder();
- for (int i = 0, length = letters.length(); i < length; i++) {
- Character character = letters.charAt(i);
- encode.append(letterCode.get(character));
- }
- EncodeResult result = new EncodeResult(encode.toString(), letterCode);
- return result;
- }
- /**
- * 获得所有字符编码对
- *
- * @param rootNode哈夫曼树的根节点
- * @return 所有字符编码对
- */
- private Map<Character, String> getLetterCode(Node rootNode) {
- Map<Character, String> letterCode = new HashMap<Character, String>();
- // 处理只有一个节点的情况
- if (rootNode.getLeftChild() == null && rootNode.getRightChild() == null) {
- letterCode.put(rootNode.getData().getC(), "1");
- return letterCode;
- }
- getLetterCode(rootNode, "", letterCode);
- return letterCode;
- }
- /**
- * 先序遍历哈夫曼树,获得所有字符编码对。
- *
- * @param rooNode 哈夫曼树根结点
- * @param suffix 编码前缀,也就是编码这个字符时,之前路径上的所有编码
- * @param letterCode 用于保存字符编码结果
- */
- private void getLetterCode(Node rooNode, String suffix,
- Map<Character, String> letterCode) {
- if (rooNode != null) {
- if (rooNode.getLeftChild() == null
- && rooNode.getRightChild() == null) {
- Character character = rooNode.getData().getC();
- letterCode.put(character, suffix);
- }
- getLetterCode(rooNode.getLeftChild(), suffix + "0", letterCode);
- getLetterCode(rooNode.getRightChild(), suffix + "1", letterCode);
- }
- }
- public String decode(EncodeResult decodeResult) {
- // 解码得到的字符串
- StringBuffer decodeStr = new StringBuffer();
- // 获得解码器
- Map<String, Character> decodeMap = getDecoder(decodeResult
- .getLetterCode());
- // 解码器键集合
- Set<String> keys = decodeMap.keySet();
- // 待解码的(被编码的)字符串
- String encode = decodeResult.getEncode();
- // 从最短的开始匹配之所以能够成功,是因为哈夫曼编码的唯一前缀性质
- // 临时的可能的键值
- String temp = "";
- // 改变temp值大小的游标
- int i = 1;
- while (encode.length() > 0) {
- temp = encode.substring(0, i);
- if (keys.contains(temp)) {
- Character character = decodeMap.get(temp);
- decodeStr.append(character);
- encode = encode.substring(i);
- i = 1;
- } else {
- i++;
- }
- }
- return decodeStr.toString();
- }
- /**
- * 获得解码器,也就是通过字母/编码对得到编码/字符对。
- *
- * @param letterCode
- * @return
- */
- private Map<String, Character> getDecoder(Map<Character, String> letterCode) {
- Map<String, Character> decodeMap = new HashMap<String, Character>();
- Set<Character> keys = letterCode.keySet();
- for (Character key : keys) {
- String value = letterCode.get(key);
- decodeMap.put(value, key);
- }
- return decodeMap;
- }
- }
- package com.liyuncong.algorithms.algorithms_huffman;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.Set;
- /**
- * 算法实现参考《多媒体技术教程》
- * @author yuncong
- *
- */
- public class HuffmanAlgorithmImpl1 extends HuffmanAlgorithmAbstract {
- /*
- * 创建哈夫曼树; 丢失了letterList中的数据,深拷贝letterList是需要完善的地方
- */
- @Override
- protected Node createTree(ArrayList<Node> letterList) {
- init(letterList);
- while (letterList.size() != 1) {
- int size = letterList.size();
- // 小的节点放在右边(眼睛看到的左边)
- Node nodeLeft = letterList.get(size - 1);
- Node nodeRight = letterList.get(size - 2);
- Node nodeParent = new Node();
- nodeParent.setLeftChild(nodeLeft);
- nodeParent.setRightChild(nodeRight);
- Data data = new Data();
- data.setFrequency(nodeRight.getData().getFrequency()
- + nodeLeft.getData().getFrequency());
- nodeParent.setData(data);
- letterList.set(size - 2, nodeParent);
- letterList.remove(size - 1);
- sort(letterList);
- }
- Node rootNode = letterList.get(0);
- return rootNode;
- }
- /**
- * 初始化 让节点列表有序
- */
- private void init(ArrayList<Node> letterList) {
- sort(letterList);
- }
- /**
- * 冒泡排序,把小的放在最后
- */
- private void sort(ArrayList<Node> letterList) {
- int size = letterList.size();
- // 处理只有一个元素的情况,也就是说,不需要排序
- if (size == 1) {
- return;
- }
- for (int i = 0; i < size; i++) {
- for (int j = 0; j < size - 1 - i; j++) {
- if (letterList.get(j).getData().getFrequency() < letterList
- .get(j + 1).getData().getFrequency()) {
- Node tempNode = letterList.get(j);
- letterList.set(j, letterList.get(j + 1));
- letterList.set(j + 1, tempNode);
- }
- }
- }
- }
- }
- package com.liyuncong.algorithms.algorithms_huffman;
- import static org.junit.Assert.*;
- import org.junit.Test;
- public class HuffmanAlgorithmImpl1Test {
- @Test
- public void testEncodeString() {
- HuffmanAlgorithmImpl1 huffmanImpl1 = new HuffmanAlgorithmImpl1();
- EncodeResult result = huffmanImpl1.encode("abcdda");
- System.out.println(result.getEncode());
- }
- @Test
- public void testDecode() {
- HuffmanAlgorithmImpl1 huffmanImpl1 = new HuffmanAlgorithmImpl1();
- EncodeResult result = huffmanImpl1.encode("abcdda");
- String decode = huffmanImpl1.decode(result);
- System.out.println(decode);
- }
- }
原文地址:http://blog.csdn.net/l294265421/article/details/44778989
Java实现哈夫曼编码和解码的更多相关文章
- java实现哈夫曼编码
java实现哈夫曼编码 哈夫曼树 既然是学习哈夫曼编码,我们首先需要知道什么是哈夫曼树:给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫 ...
- 哈夫曼编码与解码的C++实现:建立哈夫曼树、进行哈夫曼编码与解码
最近完成了数据结构课程设计,被分到的题目是<哈夫曼编码和解码>,现在在这篇博文里分享一下自己的成果. 我在设计时,在网上参考了很多老师和前辈的算法和代码,向他们表示感谢!他们的成果给了我很 ...
- 20172332 2017-2018-2 《程序设计与数据结构》Java哈夫曼编码实验--哈夫曼树的建立,编码与解码
20172332 2017-2018-2 <程序设计与数据结构>Java哈夫曼编码实验--哈夫曼树的建立,编码与解码 哈夫曼树 1.路径和路径长度 在一棵树中,从一个结点往下可以达到的孩子 ...
- Java数据结构(十二)—— 霍夫曼树及霍夫曼编码
霍夫曼树 基本介绍和创建 基本介绍 又称哈夫曼树,赫夫曼树 给定n个权值作为n个叶子节点,构造一棵二叉树,若该树的带权路径长度(wpl)达到最小,称为最优二叉树 霍夫曼树是带权路径长度最短的树,权值较 ...
- 【视频编解码·学习笔记】7. 熵编码算法:基础知识 & 哈夫曼编码
一.熵编码概念: 熵越大越混乱 信息学中的熵: 用于度量消息的平均信息量,和信息的不确定性 越是随机的.前后不相关的信息,其熵越高 信源编码定理: 说明了香农熵越信源符号概率之间的关系 信息的熵为信源 ...
- 图像压缩编解码实验(DCT编码+量化+熵编码(哈夫曼编码))【MATLAB】
课程要求 Assignment IV Transform + Quantization + Entropy Coding Input: an intra-frame or a residue pict ...
- java使用优先级队列实现哈夫曼编码
思路: 构建小根堆 根据小根堆实现哈夫曼树 根据哈夫曼树对数据进行编码 代码实现如下: /** * @Author: DaleyZou * @Description: 使用java实现一个哈夫曼编码的 ...
- c++实现哈夫曼树,哈夫曼编码,哈夫曼解码(字符串去重,并统计频率)
#include <iostream> #include <iomanip> #include <string> #include <cstdlib> ...
- Java 树结构实际应用 二(哈夫曼树和哈夫曼编码)
赫夫曼树 1 基本介绍 1) 给定 n 个权值作为 n 个叶子结点,构造一棵二叉树,若该树的带权路径长度(wpl)达到最小,称这样的二叉树为 最优二叉树,也称为哈夫曼树(Huffman Tree), ...
随机推荐
- # WinForm关闭窗体确认
private void Lba_IE_Form_FormClosing(object sender, FormClosingEventArgs e) { if (MessageBox.Show(&q ...
- 【Python】【上下文管理器】
"""#[备注]#1⃣️try :仅当try块中没有异常抛出时才运行else块.#2⃣️for:仅当for循环运行完毕(即for循环没有被break语句终止)才运行els ...
- python 将元组解析为多个参数
#create a tuple tuplex = , , print(tuplex) n1, n2, n3 = tuplex #unpack a tuple in variables print(n1 ...
- Beta冲刺三——《WAP团队》
β冲刺第三天 1. 今日完成任务情况以及遇到的问题. ①马麒.杜有海:管理员审核表的进一步完善 ②郝明宇:登录.注册界面的完善 ③马宏伟.周欣:继续完善前端数据借用与后台的连接 ④乌勒扎:登录与注册 ...
- Redis 安装到linux系统
下载地址 : http://download.redis.io/releases/redis-3.0.3.tar.gz ). tar -zxvf redis-.tar.gz -C /usr/share ...
- Lua面向对象 --- 多态
多态,简单的理解就是事物的多种形态.专业的术语说就是:同一个实现接口,使用不同的实例而执行不同的操作. 工程结构: BaseRoom.lua: BaseRoom = {} function BaseR ...
- 云服务器ECS挖矿木马病毒处理和解决方案
云服务器ECS挖矿木马病毒处理和解决方案 最近由于网络环境安全意识低的原因,导致一些云服务器ECS中了挖矿病毒的坑. 总结了一些解决挖矿病毒的一些思路.由于病毒更新速度快仅供参考. 1.查看cpu爆满 ...
- 20170709pptVBA递归删除LOGO图片与文字
Public Sub StartRecursionFolder() Dim Pre As Presentation Dim FolderPath As String Dim pp As String ...
- 1月10日 ruby基础教程,查漏补缺; 2月22日 Exception补充
https://ruby-doc.org/core-2.5.0/Exception.html 1月20日练习完1,2章. 第一章 初探 ‘’单引号不执行转义符. \t 制表符.\n 换行符. p me ...
- Confluence 6 LDAP 高级设置
启用嵌套组(Enable Nested Groups) 为嵌套组启用或禁用支持. 一些目录服务器能够允许你在一个组中定义另外一个组.在这种结构下的用户组称为用户组嵌套.嵌套组的配置能够让子用户组继承上 ...