Huffman(赫夫曼树)

1.Huffman设计了一个贪心算法来构造最优前缀码,可以有效地压缩数据,按频率(大小)来编码。
2.构造huffman树最普通的算法是每次选出两个最小的元素作为它的左右子树。依次从叶节点向上回溯,即可构造一棵huffman树。
3基于上面的思想,由于每次选出两个最小的元素,可以用到最小堆的性质在O(logn)时间内找最小的元素。(优先
队列就是靠最小堆(最大堆)实现的)。

</pre></p><p>1.普通算法</p><pre code_snippet_id="537518" snippet_file_name="blog_20141130_2_9111669" name="code" class="java">package datastructure;

import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.Scanner;

/**
 * 
 *暑假作业(Huffman树,以及Huffman编码)
 *@author ChenHaiJun
 *@date 2014年7月21日
 *@version 1.7
 */
public class HuffmanTree {
	private Huffman[] hm;
	private int[][] huffmanCode;
	private int size;
	private int node;
	class Huffman{
		public int getParent() {
			return parent;
		}
		public void setParent(int parent) {
			this.parent = parent;
		}
		public int getRchild() {
			return rchild;
		}
		public void setRchild(int rchild) {
			this.rchild = rchild;
		}
		public int getLchild() {
			return lchild;
		}
		public void setLchild(int lchild) {
			this.lchild = lchild;
		}
		public int getWeight() {
			return weight;
		}
		public void setWeight(int weight) {
			this.weight = weight;
		}
		public boolean isFlag() {
			return flag;
		}
		public void setFlag(boolean flag) {
			this.flag = flag;
		}
		int parent;
	    int rchild;
		int lchild;
		int weight;
		boolean flag;
		public Huffman(){
			 parent=-1;
		     rchild=-1;
			 lchild=-1;
			 weight=0;
			 flag=false;
		}
		
	}
	
	public HuffmanTree(int n){
		node=n;
	    hm=new Huffman[2*node];
		huffmanCode=new int[2*node][node];
		for(int i=0;i<2*node;i++){
			Arrays.fill(huffmanCode[i], -1);
		}
		size=node;
	}
	/**
	 * 该算法利用了贪心思想(最优子结构)
	 * 但算法复杂度为O(n^2)
	 */
	public void createHuffmanTree(){
		System.out.println("输入"+node+"个点的权值:");
		for(int i=1;i<=node;i++){
			hm[i]=new Huffman();
			hm[i].weight=getInt();
		}
		int min1,min2,j;
		hm[0]=new Huffman();
		hm[0].weight=Integer.MAX_VALUE;
		for(int i=1;i<node;i++){
			min1=min2=0;
			for(j=1;j<=size;j++){
				if(hm[j].weight<hm[min1].weight&&(!hm[j].flag)){
					min1=j;
				}
			}
			hm[min1].flag=true;
			for(j=1;j<=size;j++){
				if(hm[j].weight<hm[min2].weight&&(!hm[j].flag)){
					min2=j;
				}
			}
			hm[min2].flag=true;
			size++;
			hm[size]=new Huffman();
		    hm[size].weight=hm[min1].weight+hm[min2].weight;
			hm[size].lchild=min1;
			hm[size].rchild=min2;
			hm[min1].parent=size;
			hm[min2].parent=size;
		}
	}
	public int getHuffmanWeigt(){
		int j,l;
		int[] weight=new int[node+1];
		for(int i=1;i<=node;i++){
			j=i;
			l=0;
			while(hm[j].parent!=-1){
				l++;
				j=hm[j].parent;
			}
			weight[i]=l*hm[i].weight;
		}
		int sum=0;
		for(int i=1;i<=node;i++){
			sum+=weight[i];
		}
		return sum;
	}
	
	public void huffmanCode(){
		int j,k,index;
		int[] code=new int[node];
		for(int i=1;i<=node;i++){
			j=i;
			index=-1;
			while(hm[j].parent!=-1){
				k=j;
				j=hm[j].parent;
				index++;
				if(hm[j].lchild==k){
					code[index]=0;
				}
				else{
					code[index]=1;
				}
			}
			for(j=index;j>=0;j--){
				huffmanCode[i][index-j]=code[j];
			}
		}
	}
	
	public void showHuffmanTree(){
		for(int i=1;i<=node;i++){
			int j=0;
			System.out.print("hm["+i+"]="+hm[i].weight+" Code:");
			while(huffmanCode[i][j]!=-1){
				System.out.print(huffmanCode[i][j]);
				j++;
			}
			System.out.println("");
		}
	}
	
	public static int getInt(){
		Scanner sc=new Scanner(System.in);
		return sc.nextInt();
	}
	
	public static void main(String[] args){
		System.out.println("输入哈夫曼的叶结点个数:");
		int n=getInt();
		HuffmanTree tree=new HuffmanTree(n);
		tree.createHuffmanTree();
		tree.huffmanCode();
		tree.showHuffmanTree();
		System.out.println("HuffmanTree的权重:"+tree.getHuffmanWeigt());
	}

}


2.改进算法:

package datastructure;

import java.util.PriorityQueue;
import java.util.Scanner;

public class HuffmanTree2 {
	private Node root=new Node();
	private boolean[] code=new boolean[100];
	private PriorityQueue<Node> queue=new PriorityQueue<Node>();
	private class Node implements Comparable<Node>{
		private Node lChild;
		private Node rChild;
		private int data;
		public Node(int data) {
			super();
			this.data = data;
		}
		public Node(){
			
		}
		public Node getlChild() {
			return lChild;
		}
		public void setlChild(Node lChild) {
			this.lChild = lChild;
		}
		public Node getrChild() {
			return rChild;
		}
		public void setrChild(Node rChild) {
			this.rChild = rChild;
		}
		public int getData() {
			return data;
		}
		public void setData(int data) {
			this.data = data;
		}
		@Override
		public int compareTo(Node o) {
			return this.data-o.getData();
		}
	
	
	}
	/**
	 * 构造huffman树
	 * 算法是贪心算法,有优先队列实现
	 */
	public void createHuffmanTreee(){
		int nodeCount=0;
		System.out.print("请输入节点的个数:");
		nodeCount=getInt();
		System.out.print("输入"+nodeCount+"个点的权值:");
		for(int i=1;i<=nodeCount;i++){
			Node node=new Node(getInt());
			node.lChild=null;
			node.rChild=null;
			queue.add(node);
		}
		Node lchild=null;
		Node rchild=null;
		while(true){
			lchild=queue.poll();
			rchild=queue.poll();
			if(queue.isEmpty()) break;
			Node tmp=new Node();
			tmp.setData(lchild.data+rchild.data);
			tmp.lChild=lchild;
			tmp.rChild=rchild;
			queue.add(tmp);
		}
		root.data=lchild.data+(rchild!=null?rchild.data:0);
		root.lChild=lchild;
		root.rChild=rchild;
	}
	/**
	 * 打印huffman编码
	 * 左边的位0,右边的位1
	 * @return
	 */
	public void huffmanCode(Node root,int pos){
		if(root==null){
			throw new IllegalArgumentException("树根不能为空");
		}
		if(root.lChild!=null){
			code[pos]=false;
			huffmanCode(root.lChild,pos+1);
		}
		if(root.rChild!=null){
			code[pos]=true;
			huffmanCode(root.rChild,pos+1);
		}
		if(root.lChild==null||root.rChild==null){
			System.out.print(root.data+":");
			for(int i=0;i<pos;i++){
				System.out.print(code[i]?1:0);
			}
			System.out.println("");
		}
	}
	public static int getInt(){
		Scanner sc=new Scanner(System.in);
		return sc.nextInt();
	}
	public static void main(String[] args){
		HuffmanTree2 tree=new HuffmanTree2();
		tree.createHuffmanTreee();
		tree.huffmanCode(tree.root,0);
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值