java实现哈夫曼文件解压缩

本文深入探讨了哈夫曼压缩算法,详细介绍了其在字符和文件压缩中的应用。文章讲解了哈夫曼树的构建过程,包括字符统计、树的排序与合并,并提供了完整的Java实现代码。此外,还讨论了压缩与解压缩的具体步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 哈夫曼压缩对已经经过压缩处理的文件压缩率比较低,比如ppt和视频。
  2. 这个程序主要涉及到集合、树、IO相关知识。
    字符的统计可以用map集合进行统计。
    哈夫曼树的构建过程也并不复杂:
    ①先对树的集合按照根节点大小进行排序
    ②拿出根节点数值最小的两棵树,用它两构建成一颗新的树;
    ③从集合中删除之前那两颗根节点最小的数;
    ④把新生成的树加入到集合中
    一直循环重复上面的过程,直到集合的大小变成1为止;
    写出、读取文件时注意使用对象流Object流。
  3. 这个程序可以对字符进行压缩,也可以对文件进行压缩。代码中的主函数中只是调用了对文件解压缩的方法,若想对字符进行解压缩,可以调用对应的方法。
  4. 代码如下:
package huffmancode;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class HuffManCode 
{

	public static void main(String[] args) 
	{
		String srcFile="d://mydata.txt";//要压缩的文件
		String dstFile="d://mydata.zip";//压缩后的文件
		zipFile(srcFile, dstFile);//压缩文件
		System.out.println("压缩成功!");
		
		unZipFile(dstFile,"d://unzip.txt");//对刚才的文件进行解压,解压后的文件名称叫做unzip.txt
		System.out.println("解压文件成功!");		
	}
	
	public static void unZipFile(String zipFile,String dstFile)
	{
		InputStream inputStream=null;
		ObjectInputStream objectInputStream=null;
		OutputStream outputStream=null;
		try 
		{
			inputStream=new FileInputStream(zipFile);
			objectInputStream=new ObjectInputStream(inputStream);
			byte [] array= (byte [])objectInputStream.readObject();
			Map<Byte,String> map=(Map<Byte,String>)objectInputStream.readObject();
			byte[] decode = decode(map, array);
			outputStream=new FileOutputStream(dstFile);
			outputStream.write(decode);
		} catch (Exception e) 
		{
			System.out.println(e);
		}finally
		{
			try {
				outputStream.close();
				objectInputStream.close();
				inputStream.close();
				
			} catch (Exception e2) {
				System.out.println(e2);
			}
			
		}
		
		
	}
	
	public static void zipFile(String srcFile,String dstFile)
	{
		FileInputStream inputStream=null;
		OutputStream outputStream=null;
		ObjectOutputStream objectOutputStream=null;
		
		try 
		{
			inputStream=new FileInputStream(srcFile);
			byte [] b=new byte[inputStream.available()];
			inputStream.read(b);
			byte[] huffmanZip = huffmanZip(b);
			outputStream=new FileOutputStream(dstFile);
			objectOutputStream=new ObjectOutputStream(outputStream);
			objectOutputStream.writeObject(huffmanZip);
			objectOutputStream.writeObject(map);
		} catch (Exception e)
		{
			System.out.println(e);
		}
		finally 
		{
			if(inputStream!=null)
			{
				try 
				{
					objectOutputStream.close();
					outputStream.close();
					inputStream.close();//释放资源
				
				} catch (Exception e2) 
				{
					System.out.println(e2);
				}
				
			}		
		}
	}
	
	private static byte[] decode(Map<Byte, String> map,byte [] array)
	{
		StringBuilder stringBuilder = new StringBuilder();
		for(int i=0;i<array.length;i++)
		{
			boolean flag=(i==array.length-1);
			stringBuilder.append(byteToBitString(!flag, array[i]));
		}
		
		Map<String, Byte> map2=new HashMap<String, Byte>();//反向编码表
		Set<Byte> keySet = map.keySet();
		for(Byte b:keySet)
		{
			String value=map.get(b);
			map2.put(value, b);
		}
		List<Byte> list=new ArrayList<Byte>();
		for (int i = 0; i < stringBuilder.length();) 
		{
			int count=1;
			boolean flag=true;
			Byte byte1=null;
			while (flag) 
			{
				String substring = stringBuilder.substring(i, i+count);
				byte1 = map2.get(substring);
				if(byte1==null)
				{
					count++;
				}
				else 
				{
					flag=false;
				}
				
			}
			list.add(byte1);
			i+=count;		
		}
		
		byte [] by=new byte[list.size()];
		for(int i=0;i<by.length;i++)
		{
			by[i]=list.get(i);
		}
		return by;
	}
	
	private static String byteToBitString(boolean flag, byte b)
	{
		int temp=b;
		if(flag)
		{
			temp|=256;
		}
		
		String binaryString = Integer.toBinaryString(temp);
		if(flag)
		{
			return binaryString.substring(binaryString.length()-8);
		}
		else
		{
			return binaryString;
		}
		
	}
	
	private static byte[] huffmanZip(byte [] array)
	{
		List<Node> nodes = getNodes(array);
		Node createHuffManTree = createHuffManTree(nodes);
		Map<Byte, String> m=getCodes(createHuffManTree);
		byte[] zip = zip(array, m);
		return zip;	
	}
	
	//
	private static byte[] zip(byte [] array,Map<Byte,String> map)
	{
		StringBuilder sBuilder=new StringBuilder();
		for(byte item:array)
		{
			String value=map.get(item);
			sBuilder.append(value);
		}
		//System.out.println(sBuilder);
		int len;
		if(sBuilder.toString().length()%8==0)//如果可以整除
		{
			len=sBuilder.toString().length()/8;
		}
		else //如果不能整除
		{
			len=sBuilder.toString().length()/8+1;
		}
		
		byte [] by=new byte[len];
		int index=0;
		for(int i=0;i<sBuilder.length();i+=8)
		{
			String string;
			if((i+8)>sBuilder.length())
			{
				string=sBuilder.substring(i);
			}
			else 
			{
				string=sBuilder.substring(i, i+8);
			}
						
			by[index]=(byte)Integer.parseInt(string,2);
			index++;
		}
		
		return by;
			
	}
	
	
	//重载
	private static Map<Byte, String> getCodes(Node root)
	{
		if(root==null)
		{
			return null;
		}
		getCodes(root.leftNode,"0",sBuilder);
		getCodes(root.rightNode,"1",sBuilder);
		return map;
	}
	
	
	
	//获取哈夫曼编码
		static Map<Byte, String> map=new HashMap<>();
		static StringBuilder sBuilder=new StringBuilder();
		public static void getCodes(Node node,String code,StringBuilder stringBuilder)
		{
			StringBuilder stringBuilder2=new StringBuilder(stringBuilder);
			stringBuilder2.append(code);
			if(node!=null)
			{
				if(node.data==null)//非叶子结点
				{
					//向左递归
					getCodes(node.leftNode,"0",stringBuilder2);
					//向右递归
					getCodes(node.rightNode,"1",stringBuilder2);
				}
				else //如果是叶子结点
				{
					map.put(node.data,stringBuilder2.toString());
				}
			}
		}
	
	
	
	public static List<Node> getNodes(byte [] array)
	{
		List<Node> list=new ArrayList<Node>();
		Map<Byte, Integer> map=new HashMap<Byte, Integer>();
		for(Byte data:array)
		{
			Integer count=map.get(data);//通过键获取值
			if(count==null)//说明此时map集合中还没有改字符
			{
				map.put(data, 1);
			}
			else 
			{
				map.put(data,count+1);
			}
		}
		//遍历map集合
		Set<Byte> set=map.keySet();
		for(Byte key:set)
		{
			int value=map.get(key);
			Node node=new Node(key, value);
			list.add(node);
		}
		return list;
	}
	
	private static Node createHuffManTree(List<Node> list)
	{
		while(list.size()>1)
		{
			Collections.sort(list);//先对集合进行排序
			Node leftNode=list.get(0);
			Node rightNode=list.get(1);
			
			Node parentNode=new Node(null, leftNode.weight+rightNode.weight);
			parentNode.leftNode=leftNode;
			parentNode.rightNode=rightNode;
			
			list.remove(leftNode);
			list.remove(rightNode);
			
			list.add(parentNode);
		}
		return list.get(0);
		
	}

}

class Node implements Comparable<Node>
{
	Byte data;//字符
	int weight;//字符出现的次数
	Node leftNode;
	Node rightNode;
	
	public Node(Byte data,int weight)//构造器
	{
		this.data=data;
		this.weight=weight;
	}

	@Override
	public int compareTo(Node o) 
	{
		return this.weight-o.weight;
	}

	@Override
	public String toString() 
	{
		return "Node [data=" + data + ", weight=" + weight + "]";
	}
	
	//前序遍历
	public void preOrder()
	{
		System.out.println(this);
		if(this.leftNode!=null)
		{
			this.leftNode.preOrder();
		}
		if(this.rightNode!=null)
		{
			this.rightNode.preOrder();
		}
	}
	
	
}

### 银河麒麟 V10 路由追踪命令或工具使用教程 在银河麒麟 V10 系统中,可以使用 `traceroute` 命令来实现路由追踪功能。该命令用于显示数据包到达目标主机所经过的路由器路径,帮助网络管理员诊断网络连接问题并分析延迟情况。 #### traceroute 的基本语法 以下是 `traceroute` 命令的基本语法: ```bash traceroute [选项] 目标地址 ``` 常见的选项包括但不限于以下几种: - `-I`: 使用 ICMP ECHO 请求而不是 UDP 数据报。 - `-T`: 使用 TCP SYN 数据包进行探测。 - `-m <跳数>`: 设置最大跃点数,默认为 30。 - `-q <次数>`: 设置每次探查发送的数据包数量,默认为 3。 - `-w <秒数>`: 设置等待响应的时间长度[^1]。 #### 示例操作 下面是一些常用的 `traceroute` 实际应用案例: ##### 1. 默认方式跟踪路由 最简单的用法是直接指定目标 IP 地址或域名: ```bash traceroute www.example.com ``` ##### 2. 使用 ICMP 协议跟踪路由 如果默认使用的 UDP 探测被防火墙阻止,则可以过 ICMP 方式尝试: ```bash traceroute -I www.example.com ``` ##### 3. 自定义最大跃点数 当怀疑某些中间节点未响应时,可调整最大跃点数以更精确地定位问题所在: ```bash traceroute -m 20 www.example.com ``` ##### 4. 减少每轮查询的数量加快速度 为了减少整体耗时,可以降低单次测试中的数据包数目: ```bash traceroute -q 1 www.example.com ``` #### 注意事项 需要注意的是,在实际部署环境中可能遇到各种限制条件影响正常工作效果。例如企业内部网络安全策略可能会屏蔽掉部分端口或者协议类型导致无法获得完整的路由信息。此时可以根据具体情况选用不同的参数组合甚至考虑更换其他替代方案如 mtr 工具等[^2]。 ```bash sudo apt install mtr # 对于基于 Debian 的发行版安装 MTR yum install mtr # 对于 RHEL/CentOS 类型系统安装 MTR ``` MTR 是一种集成了 ping 和 trace route 功能于一体的实时监测软件,能够提供更加直观详细的统计图表展示当前链路状态变化趋势。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值