哈夫曼树构造及编码

哈夫曼树:
树的带权路径长度是树中所有叶子结点的带权路径长度之和。一组具有确定权值的叶结点可以构成多个带权二叉树。带权路径长度最小的二叉树就称作最优二叉树,或者哈夫曼树。通过实践可以发现,哈夫曼树总是把权值大的叶结点放在靠近根结点的地方,权值小的结点放在深度大的地方。哈夫曼算法给出了构造哈夫曼树的基本思想:
1.给出n个权值各异的结点作为n颗二叉树的根结点,左右子树均空,组成二叉树集合F;
2.在F中找出两颗权值最小的树作为左右子树构成一颗新树,新树的根结点的权值是左右子树根结点的权值之和;
3.在F中删除刚刚选出的左右子树,把新树放进F;
4.重复2.3剩下的那颗树就是要求的哈夫曼树。
哈夫曼编码:
在数据通信中需要把电文字符转化成0,1(编码),在接收端需要将二进制码转化成对应的字符串(译码)。在发送电文时需要在保证正确的情况下让代码尽可能的短,这就要求原字符串中出现次数较多的字符的转化码要短,同时一段二进制码不能有二义性,即不能有多种翻译方式,这又要求任意字符的编码不能是另一个字符编码的前缀。我们把字符出现的次数看做权值,把所有的字符都放在叶子结点上,这样就解决了上述的两个问题。于是焦点就集中在了哈夫曼树上。这样的编码称为哈夫曼编码。

初始森林中有n颗只有根结点的树,要合成哈夫曼树必要进行n-1次合并,n-1次合并也就产生了n-1个新的结点,这些新结点的度是2,所以哈夫曼树的总结点数是2n-1,哈夫曼树没有度为1的分支结点(严格的或正则的二叉树)。编码:从叶子结点出发走到根;译码:从根结点走到叶子结点。

例子:

输入文件内容:

4
a 7
b 5
c 2
d 4
8
a 9
b 3
c 7
d 6
e 10
f 2
g 1
h 5

两者对应的最优二叉树:


#include <iostream>
#include<cstdio>
using namespace std;
const int maxn=50,INF=0x3f3f3f3f;
typedef struct {
	char date;
	int w,parent,lch,rch,flag;  //flag=-1:没有选,falg=1已经选过了 
}huffnode;
typedef struct{
	char str[maxn];
	int start;
}huffcode;
huffnode htree[2*maxn];
huffcode hcd[maxn];
int select(int a){
	int k=INF,i,q;   //令k等于一个极大值. 
	for(i=0;i<=a;i++){
		if(htree[i].w<k&&htree[i].flag==-1){
			k=htree[i].w;
			q=i;
		}
	}
	htree[q].flag=1;
	return q;
} 
void creat_hufftree(int n){
	int i,l,r;
	for(i=0;i<2*n-1;i++)htree[i].parent=htree[i].lch=htree[i].rch=htree[i].flag=-1;
    for(i=n;i<2*n-1;i++){
    	l=select(i-1);
    	r=select(i-1);
    	htree[l].parent=htree[r].parent=i;  // 树的深度越小,下标越大。 
    	htree[i].lch=l;
    	htree[i].rch=r;
    	htree[i].w=htree[l].w+htree[r].w;
    }
}
void creat_huffcode(int n){  //由叶子结点走到根结点,进行编码 
	int i,f,c;
	huffcode d;
	for(i=0;i<n;i++){   
		d.start=n+1;
		c=i;
		f=htree[i].parent;
		while(f!=-1){
			if(htree[f].lch==c)d.str[--d.start]='0';
			else d.str[--d.start]='1';
			//cout<<d.str[d.start]<<endl; 
			c=f;
			f=htree[f].parent;
		}
		//d.str[d.start-1]=0;
		hcd[i]=d;
	}
}
void disp_huffcode(int n){
	int i,k;
    cout<<"哈夫曼编码:\n";
	for(i=0;i<n;i++){
		cout<<htree[i].date<<": ";  //<<hcd[i].str<<endl;
		for(k=hcd[i].start;k<=n;k++){
			printf("%c",hcd[i].str[k]);
		}
		cout<<endl;
	}
} 
int main(int argc, char *argv[]) {
	freopen("cin.txt","r",stdin);
	int n,i,t=2;
	while(t--){
	    cin>>n;
	    for(i=0;i<n;i++){
		getchar();
		scanf("%c%d",&htree[i].date,&htree[i].w);
	    }
	    creat_hufftree(n);
	    creat_huffcode(n);
	    disp_huffcode(n);	
	}
	return 0;
}
输出:

哈夫曼编码:
a: 0
b: 10
c: 110
d: 111
哈夫曼编码:
a: 00
b: 1100
c: 111
d: 101
e: 01
f: 11011
g: 11010
h: 100

你可能感兴趣的:(算法)