哈弗曼压缩总结

哈弗曼压缩

     对于初学哈弗曼压缩,技术不是十分娴熟,按我自己的方法将之分为以下7个大步骤:

一. 先定义节点属性方法

   (0). 定义节点的属性和方法

             在TreeNode节点类中定义了 左节点(left),右节点(right),父节点(last),数据内容(obj),频率  

   (num),编码(src)属性;定义了每个属性对应的get,set的方法。

private TreeNode left;// 左节点
private TreeNode right;// 右节点
private TreeNode last;// 父节点
private String src = "0";// 数据对应的哈弗曼编码
private byte obj;// 数据
private int num;// 出现的频率

 


二. 将源文件数据按字节读取(共256个字节)。
   (1). 获取文件路径。 (path是String类型的)

// 创建一个文件选择器
javax.swing.JFileChooser ch = new javax.swing.JFileChooser();
// 设置只能选择文件
ch.setFileSelectionMode(javax.swing.JFileChooser.FILES_ONLY);
    int t = ch.showOpenDialog(null);
    if (t == 0) {
        // 获得要压缩的文件的路径
     path = ch.getSelectedFile().getAbsolutePath();
     }


   (2). 获得文件大小。

java.io.File file = new java.io.File(path);
long num = file.length();

 

   (3). 读入数据并统计


三. 统计每个字节出现的频率。

   (4). 通过路径,来统计文件中每个字节出现的频率。

             先构建一个节点队列,然后将读取的一个字节当做节点的数据转化成一个节点,与队列中的元素进行

     比较,如果原队列中未曾出现这个节点,就将之添加到队列中,反之则节点频率+1。返回一个节点队列(qi)。

public QueueImg<TreeNode> tongji(String path) throws IOException {
    // 创建一个节点队列
    QueueImg<TreeNode> qi = new QueueImg<TreeNode>();
    // 读入数据
    java.io.InputStream ins = new java.io.FileInputStream(path);
      java.io.BufferedInputStream bis = new java.io.BufferedInputStream(ins);
      java.io.DataInputStream dis = new java.io.DataInputStream(bis);
    // 读入数据,如果不是结尾继续往下读
    java.io.File file = new java.io.File(path);
      long num = file.length();
      for (long i = 0; i < num; i++) {
            byte x = dis.readByte();
          // 将字节转化为节点
        TreeNode node = new TreeNode(x);
          // 当队列中不只一个元素时
        for (int j = 0; j <= qi.size(); j++) {
                // 如果队列中没有对应节点
            if (j == qi.size()) {
                  node.setNum(1);
                  qi.add(node);
                  break;
             }
           // 如果队列中有对应节点
        else if (qi.get(j).getObj() == node.getObj()) {
            qi.get(j).setNum(qi.get(j).getNum() + 1);
            break;
            }
       }
   }
    ins.close();
    return qi;
}

 

 

四. 根据频率构建哈弗曼树,在每个节点上注明哈弗曼编码。

   (5). 建树

             传入一个节点队列,将其中的节点按频率大小,选出最小的节点(a),再从队列中移除,再选出一次(b),再 

    移除。将这两个节点构建成新的节点。返回根节点(root)

public TreeNode createTree(QueueImg<TreeNode> qi) {
	TreeNode a, b, c;
	// 当队列中有两个或两个以上的元素时
	while (qi.size() > 1) {
		// 取最小的节点
		a = min(qi);
		qi.remove(a);
		b = min(qi);
		qi.remove(b);
		c = new TreeNode((byte) 0);
		build(c, b, a);
		qi.add(c);
	}
	TreeNode root = qi.get(0);
	return root;
}

     (6). 建码

               传入一个根节点,按左1右0的方式编码。再将所需节点放入队列(queue)中备用。

public void createBM(TreeNode root) {
	// 左边为1
	if (root.getLeft() != null) {
		root.getLeft().setSrc(root.getSrc() + 1);
		createBM(root.getLeft());
	}
	// 右边为0
	if (root.getRight() != null) {
		root.getRight().setSrc(root.getSrc() + 0);
		createBM(root.getRight());
	} else
		queue.add(root);
}

 


五. 将原来的文件数据,按哈弗曼编码的形式翻译成字符串。

    (7). 通过与队列(queue)中的元素比较,相同则输出其编码。

java.io.File file = new java.io.File(path);
long num = file.length();
String src = "";
for (long i = 0; i < num; i++) {
	byte x = dis.readByte();
	for (int j = 0; j < queue.size(); j++) {
		if (x == queue.get(j).getObj())
		src = src + queue.get(j).getSrc();
	}
}

 
六. 以8个位为一个字节,组成新的数据,再写入。

    (8). 先写入对应法则;再将原数据补齐至8的整数倍(后尾补0),写入补齐数(skip);最后写入新数据本身。

     这里用了substring(int beginIndex, int endIndex) 的方法来切割字符串,beginIndex是开始的索引处

    (包括),endIndex是结束的索引处(不包括)。再用parseInt(String s, int radix) 方法,radix是基数。

     这里是2进制转10进制,所以是2.

// 写入对应法则
for (int i = 0; i < queue.size(); i++) {
	// 数据
	dos.write(queue.get(i).getObj());
	// 哈弗曼编码
	dos.write(Integer.parseInt(queue.get(i).getSrc(), 2));
}
// 补齐位数
byte skip = 0;
if (src.length() % 8 != 0) {
	skip = (byte) (8 - src.length() % 8);
	for (int i = 0; i < skip; i++) {
		src = src + 0;
	}
}
// 补齐了skip个
dos.write(skip);
// 将字符串转化为字节
for (int i = 0; i < src.length() / 8; i++) {
	String src1 = src.substring(0 + 8 * i, 8 + 8 * i);
	int b = Integer.parseInt(src1, 2);
	dos.write(b);
}

  七. 总结

       因为是初学java,还有许多不足之处,比如说在编写时,思路不够清晰,结构混乱,数据冗杂,数据利用率不高。与此同时在遇到了许多难点,比如 如何在建好的树上添加对应的编码?如何将字符串转化为整型?如何加快压缩的速度?其中大部分已经解决,其他的也用较为复杂的方法实现。附件中还有解压缩的部分。请多指教。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值