Blog is a kind of art.It describes the progress of your running on this road.
Here comes the words from my god.
It is a capital mistake to theorize before one has data.Insensibly one begins to twist facts to suit theories,instead of theories to suit facts.------Sherlock Holmes
许久不写博客,意味着意识的懈怠,也许也意味着方向的迷茫,补上一篇很早时候做的经典算法,无损编码之哈弗曼编码。
一.哈弗曼编码是什么
哈弗曼编码是一种变长编码,普通编码采用定长编码的方式,比如使用三位二进制来表示八个不同的码值,这样是很耗空间的,哈弗曼编码一是为了使用变长编码来表示更多的编码提高信源编码的有效性,二是针对字符概率的差异所设计的编码能大大提高内存空间的利用率。
二.哈弗曼树生成的方法
哈弗曼编码的生成方式是基于一种贪心法的策略(GA)。
(1)首先统计信源中符号的个数和出现的频率并排序,up or down whatever。
(2)从统计队列中取出两个最小值合成一个节点并添加到原来队列中再排序。(合成节点频率为两小者之和,合成后两小者移出队列)
(3)重复(2)直到只剩下一个节点
三.哈弗曼编码
上一步得到了一个根节点,所有的信源已经在逻辑上关联成树形结构了,而编码就是从根节点出发经过左子树编码为0,经过右子树编码为1。取个范例给大家看看。
符号 概率 码值
如图所示,所有的有用信息都是存在叶子节点,而从根节点到达叶子节点所走过的路径可为0011所编码,叶子所在的深度越深表明信源出现的频率越低,使用高频短码低频长码编辑的哈弗曼码制具有良好的压缩性。
生成方法有两种,可用队列和链表实现,本质上都是一个PQ,保证实时有序.
CodeList.java
package demo1; public class CodeList { int number=1; HuffmanNode[] node=new HuffmanNode[number]; //添加进入码表 public void add(HuffmanNode end) { HuffmanNode newend =new HuffmanNode(); if(number!=1) { HuffmanNode[] newNode =new HuffmanNode[number]; for(int i=0;i<newNode.length-1;i++) { newNode[i]=new HuffmanNode(); newNode[i]=node[i]; } newend.setKey(end.getKey()); newend.setValue(end.getValue()); newend.setCode(end.getCode()); newNode[number-1]=newend; node=newNode; } else { newend.setKey(end.getKey()); newend.setValue(end.getValue()); newend.setCode(end.getCode()); node[0]=newend; } number++; } //遍历码表 public void readCode() { for(int i=0;i<number-1;i++) System.out.println(node[i].getKey()+" "+node[i].getValue()+" "+node[i].getCode()); } //匹配码表字符 public String matchCode(char c) { int index=-1; for(int i=0;i<node.length;i++) { if(node[i].getKey()==c) { index=i; break; } } if(index==-1) return null; else return node[index].getCode(); } }
HuffmanNode.java
package demo1; /** * 哈弗曼树的节点累 存储数据 left right 提供关联节点的方法 * HuffmanNode left; HuffmanNode right; char key; int value; 属性的getter和setter * * @author me * */ public class HuffmanNode { HuffmanNode left; HuffmanNode right; char key; int value; String code; public String getCode() { return code; } public void setCode(String code) { this.code = code; } public HuffmanNode getLeft() { return left; } public void setLeft(HuffmanNode left) { this.left = left; } public HuffmanNode getRight() { return right; } public void setRight(HuffmanNode right) { this.right = right; } public char getKey() { return key; } public void setKey(char key) { this.key = key; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } }
MainCode .java
package demo1; import java.util.HashMap; import java.util.Iterator; import java.util.PriorityQueue; import java.util.Set; /**哈弗曼压缩程序的入口 * * * 哈弗曼树是一个基于频率统计的编码树 * 使用长码对频率小的数据进行编码,使用短码进行频率高的数据进行编码 * 哈树第一步 统计频率并排序 * 哈树第二步 建树---使用优先队列实现:频率低的生成一个父节点并再排序进入一个长度比原先少一个长度的数组中,循环往复直到长度为1 * 哈树第三步 编码 左子树为0右子树为1 直到叶子节点才能拥有自己的编码 * 哈树压缩第一步 文件读写和码表的保存 * * * */ public class MainCode { public static void main(String[] args) { String test="aaabbbbccd"; String s=""; MainCode main =new MainCode(); HashMap map=main.countStr(test); Set key=map.keySet(); Iterator retu=key.iterator(); char[] freconcy=new char[map.size()]; int[] getValue=new int[map.size()]; //获得键,值的集合 for(int i=0;retu.hasNext();i++) { Object keyget=retu.next(); freconcy[i]=(Character)keyget; getValue[i]=(Integer)map.get(freconcy[i]); } main.sort(freconcy,getValue); //优先队列 HuffmanNode[] Nodes =new HuffmanNode[freconcy.length]; for(int i=0;i<freconcy.length;i++) { Nodes[i]=new HuffmanNode(); Nodes[i].setValue(getValue[i]); Nodes[i].setKey(freconcy[i]); } //新建一个优先队列 PQueue queue=new PQueue(Nodes); //建树的主要部分 while(queue.getLen()>=2) { HuffmanNode parent=new HuffmanNode(); //设置左右孩子 parent.setLeft(queue.getNodes()[queue.getLen()-1]); parent.setRight(queue.getNodes()[queue.getLen()-2]); //合并成父节点 parent.setValue(queue.getNodes()[queue.getLen()-1].getValue()+ queue.getNodes()[queue.getLen()-2].getValue()); //加入父节点并排序 queue.DeleteNode(parent); queue.sortNode(); } //遍历出树 HuffmanNode root=new HuffmanNode(); root=queue.getNodes()[0]; CodeList list=new CodeList(); main.read(root,s,list); list.readCode(); System.out.println(test); char[] getMsg=test.toCharArray(); for(int i=0;i<getMsg.length;i++) System.out.print(list.matchCode(getMsg[i])); } //统计字符串中字符出现的频率 //使用HashMap作为工具 public HashMap countStr(String str) { HashMap<Character,Integer> map=new HashMap<Character,Integer>(); char[] arr=str.toCharArray(); for(int i=0;i<arr.length;i++) { char key=arr[i]; if(!map.containsKey(key)) map.put(key, 1); else { Integer value=map.get(key); value++; map.put(key, value); } } return map; } //排序 public void sort(char[] array,int getValue[]) { char temp; int temp1; for(int i=0;i<array.length;i++) for(int j=i;j<array.length;j++) { if(getValue[i]<getValue[j]) { temp=array[i]; array[i]=array[j]; array[j]=temp; temp1=getValue[i]; getValue[i]=getValue[j]; getValue[j]=temp1; } } } //遍历算法 //编码 public void read(HuffmanNode root,String s,CodeList list) { if(root.getLeft()!=null) { read(root.getLeft(),s+"0",list); } if(root.getRight()!=null) { read(root.getRight(),s+"1",list); } if(root.getLeft()==null && root.getRight()==null) { HuffmanNode temp=new HuffmanNode(); temp.setKey(root.getKey()); temp.setValue(root.getValue()); temp.setCode(s); list.add(temp); System.out.println(root.getKey()+" running in the read "+root.getValue()+" code="+s); } } }
PQueue.java
package demo1; /** * 自实现一个优先队列 * @author me * */ public class PQueue { int length; HuffmanNode[] nodes; public PQueue(HuffmanNode[] G) { length=G.length; nodes=new HuffmanNode[length]; for(int i=0;i<length;i++) { nodes[i]=new HuffmanNode(); nodes[i].setValue(G[i].getValue()); nodes[i].setKey(G[i].getKey()); } sortNode(); } //节点排序 public void sortNode() { HuffmanNode temp; for(int i=0;i<length;i++) for(int j=i;j<length;j++) { if(nodes[i].getValue()<nodes[j].getValue()) { temp=nodes[i]; nodes[i]=nodes[j]; nodes[j]=temp; } } for(int i=0;i<nodes.length;i++) { System.out.println(nodes[i].getKey()+" run in the queue "+nodes[i].getValue()); } System.out.println(); } //删除一个节点 public void DeleteNode(HuffmanNode combine) { HuffmanNode[] newNode =new HuffmanNode[length-1]; //拷贝数据 for(int i=0;i<newNode.length-1;i++) { newNode[i]=new HuffmanNode(); newNode[i]=nodes[i]; } newNode[newNode.length-1]=combine; length=newNode.length; nodes=newNode; } //返回长度 public int getLen() { return length; } //返回节点 public HuffmanNode[] getNodes() { return nodes; } }
相关推荐
Huffman编码是一种高效的数据压缩算法,它基于字符出现频率构建最优前缀树,进而为每个字符分配唯一的二进制编码。在Java环境下实现Huffman编码,我们需要理解以下几个关键概念: 1. **字符频率统计**:首先,我们...
### Quake3自适应Huffman编码分析 #### 一、Huffman编码原理及Quake3应用背景 Huffman编码是一种广泛应用于数据压缩领域的算法,它能够有效地减少存储或传输的数据量,尤其适用于文本数据的压缩。Huffman编码的...
在数据压缩技术中,Huffman编码是一种广泛使用的无损数据压缩算法,它基于字符频率进行编码,使得频繁出现的字符拥有较短的编码,从而提高压缩效率。本项目将深入探讨如何使用C语言实现Huffman树和Huffman编码。 ...
### 图像的Huffman编码详解 #### 一、Huffman编码原理 Huffman编码是一种用于数据压缩的熵编码算法,由David A. Huffman在1952年提出。该算法的核心是通过构建一棵Huffman树(又称为最优二叉树),来为数据中的每...
### Huffman编码和解码的C语言实现 #### 引言 随着信息技术的快速发展,数据量呈爆炸式增长,这对存储设备的容量、通信线路的带宽以及计算机的处理能力提出了更高要求。在这种背景下,数据压缩技术变得尤为重要。...
Huffman编码是一种基于频率的无损数据压缩方法,由David A. Huffman于1952年提出。在信息论和计算机科学中,它被广泛应用于文本、图像、音频和其他类型的数据压缩。这个压缩包文件“Huffman编码测试文件”包含了各种...
### Huffman编码C++源代码解析 #### 一、Huffman编码简介 Huffman编码是一种广泛应用于数据压缩领域的编码方法,其基本思想是根据符号出现的频率来决定编码的长度,出现频率高的符号会分配较短的编码,而出现频率...
Huffman编码是一种基于频率的无损数据压缩方法,最初由D.E. Huffman在1952年提出。本项目实现了在Matlab环境下对图像进行Huffman编码的过程,包括图像的灰度化、编码、解码以及计算压缩比和执行时间。 首先,我们要...
Huffman树,也被称为哈夫曼树或霍夫曼树,是一种特殊的二叉树,用于在数据压缩领域实现高效的编码方法——Huffman编码。这种编码技术是基于频率的,能够为出现频率高的字符分配较短的编码,而为出现频率低的字符分配...
Huffman编码是一种高效的数据压缩算法,由David A. Huffman在1952年提出,主要用于无损数据压缩。它的核心思想是构建一棵特殊的二叉树——Huffman树,通过这棵树来为每个字符生成唯一的二进制编码。下面将详细阐述...
Huffman编码C++实现 Huffman编码是一种变长前缀编码算法,广泛应用于数据压缩、图像处理、文本处理等领域。下面是对Huffman编码C++实现的详细解释。 Huffman树 Huffman树是一种特殊的二叉树,它的叶子结点代表...
实验三、Huffman编码(二叉树) 实验目的:熟练掌握二叉树应用(Huffman编码)的基本算法实现。 实现功能:对输入的一串电文字符实现Huffman编码,再对Huffman编码生成的代码串进行译码,输出电文字符串。实现...
Huffman编码是一种基于二叉树的数据压缩方法,由David A. Huffman在1952年提出,主要用于无损数据压缩。它的核心思想是利用字符出现频率的差异来创建一棵特殊的二叉树——Huffman树,使得频繁出现的字符拥有较短的...
Huffman编码是一种高效的数据压缩算法,由David A. Huffman在1952年提出,主要用于文本数据的压缩。它的核心思想是构建一棵特殊的二叉树——哈夫曼树,通过这棵树来为每个字符生成一个唯一的前缀编码,使得频繁出现...
Huffman编码是一种基于贪心策略的数据压缩算法,由David A. Huffman在1952年提出。它通过构建一棵特殊的二叉树——哈夫曼树(Huffman Tree),来为输入符号(通常是一些字符)分配不同的二进制编码,使得出现频率高...
JPEG文件格式中使用了多种技术来实现压缩,其中Huffman编码就是关键技术之一。Huffman编码是一种广泛使用的熵编码方法,属于无损压缩技术,它可以将数据转换为变长编码,使得频繁出现的字符使用较短的编码,不常见的...
### 用Huffman编码对文件进行压缩的C语言实现 #### 一、引言 随着计算机技术的发展,数据量的增长速度越来越快,如何有效地管理和处理这些数据成为了亟待解决的问题。其中,数据压缩技术因其能够有效减少数据占用...
3. **生成Huffman编码**:调用`HuffmanCode()`函数生成每个字符的Huffman编码。 4. **显示编码结果**:使用`HShowCode()`函数展示每个字符及其对应的编码。 5. **文件编码**:通过`CharCodeFile()`函数对文件进行...