`
甘艳丽
  • 浏览: 51719 次
  • 性别: Icon_minigender_2
  • 来自: 湖南
社区版块
存档分类
最新评论

文件压缩(哈弗曼编码)

 
阅读更多

哈弗曼文件压缩的基本原理:

1.统计要压缩文件中各字符出现的频率。采用哈弗曼压缩的前提是:待压缩的文件中各字符出现的频率相差甚远,这样才体现出哈弗曼压缩的优点。

   该方法可以通过使用hashMap()来统计次数。

public static HashMap<Byte, Integer> count(String path) {
		HashMap<Byte, Integer> map = new HashMap<Byte, Integer>();//
		// 创建一个HashMap得对象,用来放数字以及该数字出现的次数
		try {

			File f = new File(path);

			FileInputStream fis = new FileInputStream(f);// 申明一个文件输入流
			// 转成缓冲流
			BufferedInputStream bis = new BufferedInputStream(fis);
			// name = f.getName();
			int t = bis.read();
			while (t != -1) {// 如果未到达结尾
				byte b = (byte) t;
				if (map.containsKey(b)) {// 如果map里面包含number键
					int value = map.get(b);// 就可以通过get函数得到number对应的value的值
					value++;// 使次数加1
					map.put(b, value);
				} else {// 如果map里面不包含number键
					map.put(b, 1);// number的次数只有一次
				}
				// 继续读取下一个
				t = bis.read();

			}

		} catch (Exception ef) {
			ef.printStackTrace();
		}

		return map;
	}

 

2.通过字节频率构造结点对象,并将所有的结点对象放到优先队列中去。每个结点对象包含两个域:从文件中读到的字节和该字节出现的频率,两者是一一对应起来的。

public static PriorityQueue<TreeNode> createQueue(HashMap<Byte, Integer> map) {
		PriorityQueue<TreeNode> nodeQueue = new PriorityQueue<TreeNode>(10,
				new Comparator<TreeNode>() {// 构造一个优先队列
					public int compare(cn.gyl608.TreeNode o1,
							cn.gyl608.TreeNode o2) {// 自动排序的方法
						return o1.count - o2.count;
					}

				});
		// 遍历
		Set<Byte> keys = map.keySet();
		// 得到迭代器
		Iterator<Byte> iter = keys.iterator();
		while (iter.hasNext()) {// 如果后面还有元素
			byte key = iter.next();// 取得K
			int value = map.get(key);// 根据K得到v

			TreeNode node = new TreeNode(key, value);// 构造成一个结点

			nodeQueue.add(node);// 将结点加到优先队列中去
		}
		return nodeQueue;// 返回这个优先队列
	}

 3.根据优先队列中的结点对象来创建哈弗曼树。

创建哈弗曼树的基本思路:

(1)先得到队列中结点对象的字节频率域最小和次小的两个结点对象,并将这两个结点对象从队列中移除。

(2)将这两个结点对象构造成新的结点对象(该结点的频率域值是:将得到的两个结点对象的频率域值相加,数据域值在压缩中没用到,故可以不考虑)并将新得到的结点对象加入到队列中。

(3)重复(1)(2)步骤,直到队列中只剩下一个结点对象。

 

 

public static TreeNode createHfmTree(PriorityQueue<TreeNode> nodeQueue) {
		TreeNode last = null;// 申明一個指向隊列最後一個結點,也就是樹的根部
		while (nodeQueue.size() > 1) {// 如果隊列中至少還存在兩個結點
			TreeNode node1 = nodeQueue.poll();// 取出并移除隊列的頭
			TreeNode node2 = nodeQueue.poll();
			TreeNode node3 = new TreeNode();// 重新生成一個新的結點
			node3.setCount(node1.getCount() + node2.getCount());// 它的頻率則是前兩個頻率之和
			node3.setLeft(node1);// 將這三個結點建立樹形結构
			node3.setRight(node2);
			node1.setParent(node3);
			node2.setParent(node3);
			nodeQueue.add(node3);// 將新生成的結點加到最優隊列中去,它會自動將其排序
			if (nodeQueue.size() == 1) {// 如果只剩下一个结点
				last = nodeQueue.poll();// 得到这个结点
				last.setParent(null);// 并将这个结点的父结点设为空
			}
		}
		return last;// 返回根结点
	}

 

 4.对叶子结点进行哈弗曼编码

我们必须要明白一点:是对叶子结点的数据域(文件中出现的各字符)进行编码,而并非是频率域,频率域只是方便我们建哈弗曼树而已。

public static HashMap<Byte, String> getHfmCode(TreeNode node, String s) {
		if (node.getLeft() != null) {// 如果根结点的左子树不为空
			getHfmCode(node.getLeft(), s + "0");// 递归调用
		}// if
		if (node.getRight() != null) {// 如果根结点的右子树不为空
			getHfmCode(node.getRight(), s + "1");// 递归调用
		}// if
		if (node.getLeft() == null || node.getRight() == null) {// 如果是叶子结点
			map.put(node.getData(), s);// 则将叶子结点的值以及该字节的编码写到map中去。
		}// if
		return map;// 返回map表
	}

 

5.通过哈弗曼编码将待压缩文件的字符转换成01字符串

6.将得到的字符串转换成byte数组。

(1)先判断该字符串是否能被8整除,如果能被8整除,该字节数组的长度是整除8得到的商+1,数组中最后一个元素的值是倒数第二个补0的个数。如果不能被8整除,该字节数组的长度就应该是整除8得到的商+2,数组中最后一个元素的值是倒数第二个补0的个数。

(2)然后将每8个字符转换成一个10进制,存到byte数组中去。

public static byte[] createByteArray(String str01) {
		int chu=str01.length()/8;
		String s1=str01.substring(chu*8);//截取得到字符串8整数后的字符
		byte c[]=s1.getBytes();
		int s = 0;
		int i = 0, j;
		int temp = 0;
		for(int n=0;n<c.length;n++){
			temp+=(c[n]-48)*Math.pow(2, 7-n);//求倒数第2个字节的大小
		}
		byte b[] = str01.getBytes();// 将字符数组转换成字节数组,方便将二进制转为十进制
		for (int k = 0; k < b.length; k++) {
			b[k] = (byte) (b[k] - 48);
		}
		byte a[];
		if (b.length % 8 == 0) {// 如果该字符串正好是8的倍数
			a = new byte[b.length / 8 + 1];
			a[a.length - 1] = 0;// 那么要返回数组的最后一个数就为0
		} else {
			a = new byte[b.length / 8 + 2];
			a[a.length - 1] = (byte) (8 - b.length % 8);// 那么该数组的最后一个数就是补0的个数
		}
		while (i < a.length - 2) {// a数组中最后一个是补0的个数,实际操作到次后个元素
			for (j = 0; j < b.length; j++) {
				if (b[j] == 1) {// 如果数组c的值为1
					s = (int) (s + Math.pow(2, (7 - (j - 8 * i))));// 累积求和
				}// if
				if (j == 8 * (i + 1) - 1) {// 当有8个元素时
					a[i] = (byte) s;// 就将求出的和放到a数组中去
					i++;
					s = 0;// 并从新使s的值赋为0
				}// if
				
			}// for
		}// while
		a[a.length - 2] = (byte) temp;
		return a;
	}

 

 

7.将待压缩文件的文件名,以及字节——哈弗曼编码的码表,字节数组写到文件中。以便解压缩过程中需要用到。

 

解压缩的基本思路:

1.先将带压缩文件的文件名,码表和字节数组读取出来。

2.将字节数组中的每个元素值转换成二进制,并将其连接成一个字符串。

3.将字符串中的每个字符与码表中的编码比较,若相等,则从下个字符开始比较,若不相等,在继续跟下一个字符组成新的字符串,再与编码比较,依次进行比较。

4.将解析得到的字符写到文件中。

 

分享到:
评论
2 楼 fenger_chui 2011-09-02  
基本功很扎实呀
1 楼 pclnn 2011-08-13  
初学者路过,瞻仰,多有收获,多谢分享。

相关推荐

    哈弗曼编码 压缩 解压 文件

    在压缩文件时,按照哈弗曼编码表,将文件中的每一个字符替换为对应的编码。因为高频字符的编码通常较短,低频字符的编码较长,所以整体上可以降低文件大小。 解压文件的过程则相反。读取压缩文件中的每一位,根据...

    用哈弗曼编码对文件进行压缩与解压

    通过对哈弗曼编码原理及其在文件压缩与解压中的应用进行深入剖析,我们了解到这是一种非常有效的无损压缩算法。通过构建哈弗曼树和生成编码表,可以显著减少文件的存储空间,提高数据传输效率。此外,通过计算压缩...

    基于哈弗曼编码的压缩文件

    将原文件进行哈弗曼编码后在利用哈弗曼编码进行压缩,建立哈弗曼树

    哈弗曼编码实现文件压缩

    哈弗曼编码是一种高效的数据编码方法,主要用于无损数据压缩,尤其在文本、图像和音频文件的压缩中广泛应用。它的核心思想是通过构建一棵特殊的二叉树(哈弗曼树)来为每个符号分配最短的唯一二进制码,使得频繁出现...

    利用哈弗曼编码做的压缩程序 源代码

    在本压缩程序中,我们看到它利用了哈弗曼编码的核心思想来实现文件的压缩。 哈弗曼编码的基本原理是构建一棵特殊的二叉树——哈弗曼树(或最优二叉树)。在这个树中,出现频率较高的字符对应的路径较短,而出现频率...

    哈弗曼编码文件2进制压缩并解压缩

    哈弗曼编码文件2进制压缩并解压缩,纯C++代码。可以将文本文档压缩成2进制编码(打开压缩文档是乱码)、还可以解压缩。压缩比例20%-50%

    哈弗曼编码实现文本文件和图片的压缩

    以下是关于哈弗曼编码实现文本文件和图片压缩的详细知识讲解。 一、哈弗曼编码原理 哈弗曼编码的基本思想是构建一棵特殊的二叉树,称为哈弗曼树。这棵树满足以下两个特性: 1. 所有叶子节点代表待编码的原始数据...

    哈弗曼编码的编码解码

    哈弗曼编码是一种高效的数据压缩方法,由美国学者大卫·哈弗曼于1952年提出,广泛应用于数据通信、文件压缩等领域。其核心思想是利用最优的二叉树结构,为每个字符分配最短的唯一二进制编码,使得频繁出现的字符拥有...

    基于哈弗曼编码的压缩率问题进行介绍

    ### 基于哈弗曼编码的压缩率问题详解 #### 一、引言 哈弗曼编码(Huffman Coding)是一种广泛应用于数据压缩领域的编码方式,尤其在无损压缩中有着不可替代的地位。它是由David A. Huffman在1952年提出的,主要...

    哈弗曼编码(C语言)

    哈弗曼编码是一种变长前缀编码,用于无损数据压缩。该编码方法利用了字符出现频率的差异,高频字符使用短码,而低频字符使用长码。哈弗曼树是哈弗曼编码的核心结构,通过构建哈弗曼树,可以生成最优的前缀编码。 在...

    哈弗曼编码的实现过程

    哈弗曼编码是一种高效的数据压缩方法,主要用于无损数据压缩,尤其在文本、图像和音频文件的压缩中广泛应用。它的核心思想是通过构建一棵特殊的二叉树——哈弗曼树(也称为最优二叉树),为每个字符或符号分配一个...

    哈弗曼编码/译码器

    哈弗曼编码在实际应用中广泛用于数据压缩,如在文件压缩软件中,如ZIP、RAR等都采用了类似的技术。在本例中,"哈弗曼.exe"可能是一个实现了哈弗曼编码和解码功能的工具。用户可以通过这个工具,对文本或数据进行压缩...

    哈弗曼编码译码器的实现

    在这个项目中,学生需要实现哈弗曼树的建立,以及基于哈弗曼编码的文件压缩和解压缩功能。以下是关于这个主题的详细知识讲解: 1. **哈弗曼树(Huffman Tree)**:哈弗曼树是一种特殊的二叉树,也称为最优二叉树。...

    哈弗曼编码数据结构课程设计

    哈弗曼编码是一种高效的数据压缩方法,源自于数据结构中的树形结构——哈弗曼树(Huffman Tree),常用于文本、图像等数据的无损压缩。在本课程设计中,我们将深入理解哈弗曼编码的基本原理,并使用C++语言实现一个...

    VC++中哈弗曼编码实现

    哈弗曼编码是一种高效的数据压缩方法,主要用于无损数据压缩,由哈弗曼在1952年提出。它的核心思想是构建一棵特殊的二叉树,即哈弗曼树,其中每个叶节点代表一个需要编码的字符,而内部节点则表示路径。字符出现频率...

    基于哈弗曼编码实现的对于ASCII文件的压缩示例

    哈弗曼编码的优势在于它能对频繁出现的字符赋予较短的编码,而较少出现的字符则分配较长的编码,这样在编码过程中,频繁出现的字符可以占用更少的存储空间,从而实现整体的文件压缩。 在VC6.0环境下,这个程序可以...

    数据结构--哈弗曼编码实验报告

    - **实验题目**:使用哈弗曼编码实现文件压缩。 - **实验目的**: 1. 理解文件的基本概念。 2. 掌握线性链表的基本操作,包括插入、删除等算法。 3. 学习哈弗曼树的概念及其构建方法。 4. 掌握二叉树的存储结构...

    哈弗曼编码算法源代码

    哈弗曼编码是一种高效的数据压缩方法,主要用于无损数据压缩。它是基于频率的变字长编码方式,由美国计算机科学家戴维·哈弗曼在1952年提出。哈弗曼编码的基本思想是通过构建一棵特殊的二叉树——哈弗曼树(也称为...

    哈弗曼编码实现压缩和解压缩

    【哈弗曼编码实现压缩和解压缩】 哈弗曼编码是一种高效的无损数据压缩方法,由哈弗曼在1952年提出。其核心思想是利用字符出现频率构建一棵特殊的二叉树——哈弗曼树(也称为最优二叉树或最小带权路径长度树),其中...

Global site tag (gtag.js) - Google Analytics