Huffman 编码 (贪心)

以字母出现的频率建一颗二叉树,频率越大的字母的赫夫曼编码越短,这样保证任意一个字母的编码不会是另一个字母编码的前缀,然后遍历吧.(赫夫曼编码不是唯一的)

//Word .java,存字母信息
public class Word {
	char c;
	int w;//出现次数
}


//HuffmanNode.java,每个赫夫曼节点信息
public class HuffmanNode {
	char c;
	int weight;
	int tag;//tag是一个标记,用于建树时的Select函数,也就是看这个点是否已经在树中
	int father;
	int lchild;
	int rchild;
	StringBuilder s;
	HuffmanNode(){
		weight=0;
		tag=father=lchild=rchild=-1;
		s=new StringBuilder("");
	}
}

//HuffmanTree.java
public class HuffmanTree {
	HuffmanNode[] tree;
	int num;
	HuffmanTree(int n,Word[] w){//n个字母的赫夫曼树有n*2-1个节点,生成这n*2-1个节点
		num=n*2-1;
		tree = new HuffmanNode[num];
		for(int i=0;i<num;i++)
			tree[i]=new HuffmanNode();
		for(int i=0;i<n;i++){
			tree[i].c=w[i].c;
			tree[i].weight=w[i].w;
		}
	}
	int Select(){//选出当前没被选过的节点中权值最小的
		int ans=1000000000,pos=-1;
		for(int i=0;i<num;i++){
			if(tree[i].tag==-1&&tree[i].weight!=0){
				if(tree[i].weight<ans){
					ans=tree[i].weight;
					pos=i;
				}
			}
		}
		tree[pos].tag=1;//标记为已选
		return pos;
	}
	void BuildTree(int n){//建树
		for(int i=n;i<num;i++){
			int i1=Select();
			int i2=Select();
			tree[i1].father=tree[i2].father=i;
			tree[i].lchild=i1;
			tree[i].rchild=i2;
			tree[i].weight=tree[i1].weight+tree[i2].weight;
		}
	}
	void HuffmanCode(int n){//编码
		for(int i=0;i<n;i++){
			int j=i;
			StringBuilder ans=new StringBuilder("");
			while(tree[j].father!=-1){
				int fa=tree[j].father;
				if(tree[fa].lchild==j) ans.append("0");
				else ans.append('1');
				j=fa;
			}
			tree[i].s=ans;
			System.out.print(tree[i].c+"的赫夫曼编码是: ");
			System.out.println(ans.reverse());
		}
	}
}


//测试程序
import java.util.*;
public class Main {
	public static void main(String[] args){
		Scanner in = new Scanner(System.in);
		String s = in.next();
		int[] vis = new int[26];
		Arrays.fill(vis, 0);
		int num=0,t=0;
		//统计每个字符的频率,此测试程序的输入只能是小写字母。
		for(int i=0;i<s.length();i++){
			int a=s.charAt(i)-'a';
			if(vis[a]==0) num++;
			vis[a]++;
		}
		//一共出现了num个字母
		Word[] word = new Word[num];
		for(int i=0;i<num;i++){
			word[i] = new Word();
		}
		//把num个字母存入Word.
		for(int i=0;i<26;i++){
			if(vis[i]!=0){
				word[t].c=(char)('a'+i);
				word[t].w=vis[i];
				t++;
			}
		}
		HuffmanTree tree = new HuffmanTree(num,word);
		tree.BuildTree(num);
		tree.HuffmanCode(num);
	}
}





评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值