赫夫曼树
- 路径
- 路径长度
- 节点的权
- 节点带权路径长度
- 树的带权路径长度
public class Demo{
// 遍历
public static void preOrder(Node root){
if(root!=null){
root.preOrder();
}else{
System.out.println("空树");
}
}
// 创建赫夫曼树
public static Node createHuffmanTree(int[] arr){
// 遍历arr
// 将arr构成Node
// 将node放入ArrayList
List nods = new ArrayList();
for(int value : arr){
node.add(new Node(value))
}
while(nodes.size()>1){
// 排序,从小到大
Collections.sort(nodes);
// 取出根节点权值最小的二叉树
// 取出全局最小的节点
Node leftNode = nodes.get(0);
// 取出第二小
Node rightNode = nodes.get(1);
// 构建新二叉树
Node parent = new Node(leftNode.value+rightNode.value);
parent.left = leftNode;
praent.right = rightNode;
// 从arrayList中删除处理过的二叉树
nodes.remove(leftNode);
nodes.remove(rightNode);
// 将parent加入nodes
nodes.add(parent);
}
return nodes.get(0);
}
}
// 创建节点类
// 实现Compareable 利于排序
class Node implements Compareable{
int value;// 节点权
Node left;// 左子节点
Node right;// 右子节点
public Node(int value){
this.value = value;
}
public int compareTo(Node o){
// 从小到大排序
return this.value - o.value;
}
// 遍历
public void preOrder(){
System.out.println(this);
if(this.left!=null){
this.left.preOrder();
}
if(this.right!=null){
this.reight.preOrder();
}
}
}
数据压缩
public class HuffmanCode{
// 将赫夫曼编码存放到Map
static Map huffmanBCodes = new HashMap();
// 生成哈夫曼编码表,需要字符串拼接
static StringBuilder stringBuilder = new StringBuilder();
public static void main(String[] args){
String content = "xxxxxxxxxxxxxxxxxxxxx";
byte[] contentBytes = content.getBytes();
List nodes = getNodes(contentBytes);
Node huffmanTreeRoot = createHuffman(nodes);
preOrder(huffmanTreeRoot);
// 生成对应赫夫曼编码
Map huffmanCodes = getCodes(huffmanTreeRoot);
byte[] huffmanCodeBytes = zip(contentBytes,huffmanCodes)
}
// 将压缩方法封装
private static byte[] huffmanXip(byte[] bytes){
List nodes = getNodes(bytes);
// 创建huffman树
Node huffmanTreeRoot = createHuffman(nodes);
// 生成对应赫夫曼编码
Map huffmanCodes = getCodes(huffmanTreeRoot);
// 压缩
byte[] huffmanCodeBytes = zip(contentBytes,huffmanCodes)
return huffmanCodeBytes;
}
// 将字符串对应的byte[] 通过赫夫曼编码,返回压缩后的byte[]
private static byte[] zip(byte[] bytes,Map huffmanCodes){
// 利用huffmanCodes 将bytes转成对应字符串
StringBuilder stringBuilder = new StringBuilder();
for(byte b : bytes){
stringBuilder.append(hyffmanCodes.get(b));
}
// 统计返回的byte[] huffmanCodeBytes长度
int len; // len =(stringBuilder.length()+7 )/8;
if(stringBuilder.length%8==0){
len = stringBuilder.length()/8;
}else{
len = stringBuilder.length()/8+1;
}
// 创建压缩后的byte数组
byte[] huffmanCodeBytes = new byte[len];
int index = 0;
for(int i=0;i
String strByte;
if(i+8>stringBuilder.length()){
strByte = stringBuilder.subString(i)
}else{
strByte = stringBuilder.substring(i,i+8);
}
// 将strByte转化byte,并放入huffmanCodeBytes
huffmanCodeBytes[index] = (byte)Integer.parseInt(strByte,2);
index++;
}
return huffmanCodeBytes;
}
private static Map getCodes(Node root){
if(root==null){
return null;
}
getCodes(root.left,"0",stringBuilder);
getCOdes(root.right,"1",stringBuilder);
}
// 将传入的node的所有叶子节点的赫夫曼编码得到,并放入到huffmanBCodes
// code 路径 左子节点0 右子节点1
private static void getCodes(Node node,String code,StringBuilder stringBuilder){
StringBuilder stringBulder2 = new StringBuilder(stringBuilder);
stringBulder2.append(code);
if(node!=null){
// 当前node是叶子节点还是非叶子节点
if(node.data==null){
// 非叶子节点
// 向左递归
getCodes(node.left,"0",stringBuilder2);
// 向右递归
getCodes(node.right,"1",stringBuilder2);
}else{
// 叶子节点
huffmanCodes.put(node.data,stringBuilder2.toString());
}
}
}
// 遍历
public static void preOrder(Node root){
if(root!=null){
root.preOrder();
}else{
System.out.println("空");
}
}
private static List getNodes(byte[] bytes){
// 创建一个ArrayList
ArrayList nodes = new ArrayList();
// 遍历bytes,统计每个byte出现的次数
Map counts = new HashMap();
for(byte b:bytes){
Integer count = counts.get(b);
if(count==null){
counts.put(b,1);
}else{
counts.put(b,count+1);
}
}
// 将map转成node
for(Map.Entry entry:counts.entrySet()){
nodes.add(new Node(entry.getLKey(),entry.getValue()));
}
return nodes;
}
// 创建赫夫曼树
private static Node createHuffman(List nodes){
while(nodes.size()>1){
Collections.sort(nodes);
// 取出第一个最小
Node leftNode = nodes.get(0);
// 取出第二个
Node rightNode = nodes.get(1);
Node parent = new Node(null,leftNode.weight+rightNode.weight);
parent.left = leftNode;
parent.right = rightNode;
// 删除
nodes.remove(leftNode);
nodes.remvoe(rightNode);
nodes.add(parent);
}
return nodes.get(0);
}
// 生成赫夫曼树对应的赫夫曼编码
}
class Node{
Byte data;// 存放数据本身
int weight;// 权值,表示字符出现的次数
Node left;
Node right;
public Node(Byte data,int weight){
this.data = data;
this.weight = weight;
}
public int compareTo(Node o){
// 从小到大
return this.weight - o.weight;
}
public String toString(){
return "Node[data="+data+"weight="+weight+"]";
}
// 遍历
public void preOrder(){
System.out.println(this);
if(this.left!=null){
this.left.preOrder();
}
if(this.right != null ){
this.right.preOrder();
}
}
}
解压
// 将huffmanCodeBytes转对应的二进制字符串
// 将二进制字符串对照编码表转化为原字符串
// huffmanCodes 编码表
// huffmanBytes 获得的字节数组
public static byte[] decode(Map huffmanCodes,byte[] huffmanBytes){
// 得到huffmanBytes对应的二进制字符串
StringBuilder stringBuilder = new StringBuilder();
for(int i=0;i
// 判断是不是最后一个
boolean flag = (i==huffmanBytes.length-1);
stringBuilder.append(byteToBitString(!flag,huffmanBytes[i]));
}
// 将字符串按赫夫曼编码进行解码
Map map = new HashMap();
for(Map.Entry entry:huffmanCodes.entrySet()){
map.put(entry.getValue(),entry.getKey());
}
// 创建集合,存放byte
List list = new ArrayList<>();
for(int i=0;i
int count = 1;
boolean flag = true;
Byte b = null;
while(flag){
// 取出一个'1' '0'
String key = stringBuilder.substring(i,i+count);
b = map.get(key);
if(b==null){
// 没有匹配到
count++;
}else{
// 匹配到
flag = false;
}
}
list.add(b);
i+=count;
}
byte b = new byte[list.size];
for(int i=0;i
b[i] = list.get(i);
}
return b;
}
// 将一个byte转化为二进制字符串
// flag true 需要补高位 false 不需要
private static String byteToBitString(boolean flag,byte b){
int temp = b;
// 如果是正数,需要补高位
if(flag){
temp |= 256; // 按位或 256 1000 0000
}
String str = Integer.toBinaryString(temp);// 返回二进制补码
if(flag){
return str.substring(str.length()-8);
}else{
return str;
}
}
文件压缩
// srcFile 压缩前文件
// dstFile 压缩后文件
public static void zipFile(String srcFile,String dstFile){
// 创建输出流
OutputStream os = null;
ObjectOutputStream = null;
// 创建文件输入流
FileInputStream is = null;
try{
is = new FileInputStream(srcFile);
byte[] b = new byte[is.available()];
// 读取文件
is.read(b);
// 文件压缩
byte[] huffmanZip = huffmanZip(b);
os = new FileOutputStream(dstFile);
// 创建一个与文件输出流关联的ObjectOutputStream
oos = new ObjectOutputStream(os);
oos.writeObject(huffmanBytes);
// 以对象流方式写入赫夫曼编码,以便恢复源文件
oos.writeObject(huffmanCodes)
}catch(Exception e){
}finally{
try{
is.close();
oos.close();
os.clsoe();
}catch(Exception e){
}
}
}
解压文件
public static void unZipFile(Sring zipFile,String dstFile){
// 定义文件输入流
InputStream is = null;
// 定义一个对象输入流
ObjectInputStream ois = null;
// 文件输出流
OutputStream os = null;
try{
// 创建文件输入流
is = new FileInputStream(zipFile);
oos = new ObjectInputStream(is);
// 读取byte数组 huffmanBytes
byte[] huffmanBytes = (byte[])ois.readObject();
// 读取赫夫曼编码表
Map huffmanCodes = (Map)ois.readObject();
// 解码
byte[] bytes = decode(huffmanCodes,huffmanBytes);
// 将bytes数组写入目标文件
os = new FileOutputStream(dsFile);
// 写数据
os.write(bytes);
}catch(Exception e){
}finally{
try{
os.close();
ois.close();
is.close();
}catcah(Exception e){
}
}
}