《压缩》的总结

哈夫曼压缩:
1、读取文件,并统计文件中各字符出现的次数,存储到一个数组中,数组长度为256,然后每个索引都代表字符的AscII码所代表的值,每当多一个,就在这个索引下的值加一。代码如下:

	public void Output() {
		try {
			// 实例化一个File输入流对象
			InputStream is = new FileInputStream(path);
			// 实例化一个Buffer输入流对象
			BufferedInputStream bs = new BufferedInputStream(is);
			// 获得文件的长度
			int length = is.available();
			// 遍历
			for (int i = 0; i < length; i++) {
				// 统计每个字符出现的次数
				array[is.read()]++;
			}
			// 关闭流
			bs.close();
			is.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

 
2、对这个数组里的值进行排序(采用优先队列)
 ①循环创建节点,节点里存放AscII码和此AscII出现的次数
 ②优先队列里存放节点
 ③优先队列的排序方法通过继承Comparable<T>接口来实现
 代码如下:

 

	public void CreatThree() {
		// 定义一个计数器,记录有多少个叶子节点
		int count = 0;
		// 实例化一个优先队列
		PriorityQueue<hfmNode> node_queue = new PriorityQueue<hfmNode>();
		// 遍历数组,往优先队列里添加内容
		for (int i = 0; i < array.length; i++) {
		               if (array[i] != 0) {
			hfmNode node = new hfmNode(i, array[i]);
				node_queue.add(node);
				count++;
		                }
		}

 


3、构建一个哈夫曼树,并获取每个字符对应的码表
 ①首先从优先队列里获得2个最少出现的字符,并从队列中移除这两个
 ②然后构建一个小树,生成一个父节点,父节点的次数为这两个字符次数的合,并把这个父节点添加到优先队列里
 ③以此类推构建完哈夫曼树
 ④每一个父节点的左边路径作为0,右边路径作为1,然后生成每个字符所对应的码表
 代码如下

 

		// 构建哈夫曼树
		while (node_queue.size() > 1) {
			// 获得队列头,并移除这个队列头
			hfmNode node1 = node_queue.poll();
			// 获得队列头,并移除这个队列头
			hfmNode node2 = node_queue.poll();
			// 创建一个上面两个节点的父节点
			hfmNode parent_node = new hfmNode(0, node1.getCount()
					+ node2.getCount());
			// 设置父节点的左右节点
			parent_node.setLeftChild(node1);
			node1.setS("0");
			parent_node.setRightChild(node2);
			node2.setS("1");
			// 把这个节点添加进优先队列里
			node_queue.add(parent_node);
		}
		// 设置根节点
		root = node_queue.peek();
	}

 

	/**
	 * 给每个叶子节点添加码表值
	 * 
	 * @param node
	 */
	public void PrintLn(hfmNode node) {
		if (node.getLeftChild() == null && node.getRightChild() == null) {
			// 把叶子节点添加到节点数组里
			node_all[co] = node;
			co++;
		} else {
			// 获取当前节点的编码值
			String s = node.getS();
			// 左节点的编码值加上当前节点的编码值
			s += node.getLeftChild().getS();
			// 把加后的编码值赋值给左节点
			node.getLeftChild().setS(s);
			// 递归左节点
			PrintLn(node.getLeftChild());
			// 获取当前节点的编码值
			String s1 = node.getS();
			// 右节点的编码值加上当前节点的编码值
			s1 += node.getRightChild().getS();
			// 把加后的编码值赋值给右节点
			node.getRightChild().setS(s1);
			// 递归右节点
			PrintLn(node.getRightChild());
		}
	}

 
4、写入文件
 ①写入头信息
  I、写入字符
  II、写入该字符编码所占的字节数
  Ⅲ、每个字符对应的码表补了多少个0(补满8位)
  Ⅳ、写入每个字符所对应的码表

		for (int i = 0; i < node_all.length; i++) {
			//记录该节点编码有多少个字节
			count_array = node_all[i].getByteSize();
			// 写入该字符占有几个位置
			bos.write(node_all[i].getByteSize());
			// 写入字符
			bos.write(node_all[i].getObj());
			// 写入补了多少个0
			String str_zero = Integer.toString(node_all[i]
					.getAddZero());
			bos.write((int) str_zero.charAt(0));
			//获得当前字符的编码
			writes = node_all[i].getS();
			//循环写入编码
			for (int j = 0; j < count_array; j++) {
				//定义一个中转字符串
				String trans = "";
				//提取前八位
				for (int k = 0; k < 8; k++) {
					trans += writes.charAt(k);
				}
				//转换成整型写入文件
				int x = ChangeString(trans);
				// 写入转换后的整型
				bos.write(x);
				// 中转字符串清空
				trans = "";
				// 循环获得除去前八位后剩下的字符
				for (int k = 8; k < writes.length(); k++) {
					trans += writes.charAt(k);
				}
				// 把原先的字符串覆盖掉
				writes = trans;
				// 中转字符串清空
				trans = "";
			}
		}

 
 ②写入文件内容
  Ⅰ、把所有的字符转化成01串,每8位一个字节写入文件
  Ⅱ、最后不足八位则补零,然后写入补零个数

	// 遍历读取文件内容,并写入文件
	for (int i = 0; i < length; i++) {
		// 读取文件
		int x = bs.read();
		// 循环判断该字符所对应的编码
		for (int j = 0; j < str_all.length; j++) {
			if (x == node_all[j].getObj()) {
				// 把编码赋值给字符串中存储
			          str_matter += str_all[j];
			}
		}
		// 如果此时的字符串位数大于等于8
		if (str_matter.length() >= 8) {
			// 循环获得前八位
			for (int j = 0; j < 8; j++) {
				str_trans += str_matter.charAt(j);
			}
			// 把这8位字符串转化成整形
			int a = ChangeString(str_trans);
			// 写入转换后的整型
			bos.write(a);
			// 清空转换字符串
			str_trans = "";
			// 循环获得除去前八位后剩下的字符
			for (int j = 8; j < str_matter.length(); j++) {
				str_trans += str_matter.charAt(j);
			}
			// 把原先的字符串覆盖掉
			str_matter = str_trans;
			// 清空转换字符串
			str_trans = "";
		}
	}
	// 如果没有满八位,则补上0
	while (str_matter.length() % 8 != 0) {
		addzero++;
		str_matter += "0";
	}
	// 判断补零后的字符串是否为空
	if (str_matter.equals("")) {
	} // 把这8位字符串转化成整形
	else {
		int b = ChangeString(str_matter);
		// 写入转换后的整型
		bos.write(b);
	}
	// 写入补零计数器
	String so = Integer.toString(addzero);
	bos.write((int) so.charAt(0));

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值