哈夫曼编码之大根堆小根堆揭西县

哈夫曼编码
根据数据出现的频率对数据进行编码,从而压缩原始数据。

例如对于一个文本文件,其中各种字符出现的次数如下:

a : 10
b : 20
c : 40
d : 80
可以将每种字符转换成二进制编码,例如将 a 转换为 00,b 转换为 01,c 转换为 10,d 转换为 11。这是最简单的一种编码方式,没有考虑各个字符的权值(出现频率)。而哈夫曼编码采用了贪心策略,使出现频率最高的字符的编码最短,从而保证整体的编码长度最短。

首先生成一颗哈夫曼树,每次生成过程中选取频率最少的两个节点,生成一个新节点作为它们的父节点,并且新节点的频率为两个节点的和。选取频率最少的原因是,生成过程使得先选取的节点位于树的更低层,那么需要的编码长度更长,频率更少可以使得总编码长度更少。
在这里插入图片描述

import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;

public class hufman {
private class Node implements Comparable<Node>{

	char ch;
	int frequency;
	boolean isleaf;
	Node left;
	Node right;
	public Node(char a,int f) {
		ch=a;
		frequency=f;
		isleaf=true;
	}
	public Node(Node left,Node right,int frequency) {
		this.left=left;
		this.right=right;
		this.frequency=frequency;
	}
	@Override
	public int compareTo(Node o) {
		// TODO Auto-generated method stub
		return this.frequency-o.frequency;
	
	}
}
	public Map<Character,String> encode(Map<Character,Integer> frquencyChar){
		PriorityQueue<Node> p=new PriorityQueue();
		for(char c:frquencyChar.keySet()) {
			p.add(new Node(c,frquencyChar.get(c)));
		}
		while(p.size()!=1) {
		Node n1=	p.poll();
		Node n2=	p.poll();
		p.add(new Node(n1,n2,n1.frequency+n2.frequency));
		}
		return Encode(p.poll());
		
	}
	
	public Map<Character,String> Encode(Node root){
		Map<Character,String> m=new HashMap();
		Encode(root,"",m);
		return m;
	}
	public void Encode(Node node,String a,Map<Character,String> m) {
		while(node.isleaf) {
			m.put(node.ch, a);
			return;
		}
		Encode(node.left,a+"0",m);
		Encode(node.right,a+"1",m);
	}

}

man.java
import java.util.HashMap;
import java.util.Map;

public class Teat {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Map <Character,Integer> frquencyChar=new HashMap();
		frquencyChar.put('a', 1);
		frquencyChar.put('c', 19);
		frquencyChar.put('2', 13);
		frquencyChar.put('5', 14);
	
		hufman a=new hufman();
		Map<Character,String> b=a.encode(frquencyChar);
		
		for(char m:b.keySet()) {
			System.out.println(m+b.get(m));
		}
	}

}

这是一个大根堆,所以重写了Node 对象中的compareTo 函数, 继承 Comparable 接口,
首先将字符与权重加入一个map中,我理解的是构建小根堆,这样每次都是最小的现出来。相加构成节点这个样子。
重写了函数之后,compare这个函数我觉得是》0 就要交换,<0 不交换,this.fre-o.fre>0 说明后来者小,进行交换。

PriorityQueue <Integer> maxHeap = new PriorityQueue<Integer>( new Comparator<Integer>() {
			 
			@Override
			public int compare(Integer o1, Integer o2) {
				// TODO Auto-generated method stub
				return o2.compareTo(o1);
			}
			
		});

还可以 通过这个样子重写进行大根堆 小根堆变换。
https://blog.csdn.net/liou825/article/details/21322403
https://blog.csdn.net/zcf1784266476/article/details/68961473

发布了39 篇原创文章 · 获赞 6 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/poppyl917/article/details/89452964