哈夫曼树树生成及编码解码

题目

哈夫曼编码
Time Limit: 1000/2000 MS (C/Others)   Memory Limit: 32768/32768 K (C/Others)
Problem Description:
由若干个值无重复的结点及其权值,建立相应的哈夫曼树。在合并过程中,若出现权值相同的情况,则优先选取编号小的进行合并;要求哈夫曼树中所有左孩子编号小于右孩子编号(以结点的输入顺序做为其编号)。对所建的哈夫曼树,根据左0右1的原则,对各结点进行编码。设计一个算法,对给定的若干码串进行相应的解码,并输出解码结果。
Input:
有多组测试数据,每组数据由结点信息和码串两部分组成。结点信息部分的第一行为一个整数n(n<=20),表示以下有n个结点信息,每个结点信息包括一个字符和一个整数,表示结点值和权值;码串部分的第一行为一个整数m,表示以下有m个码串(每个串长不超过100),码串由0和1构成,且均有效。

Output:
输出各码串对应的解码结果,每个解码结果占一行,每组测试数据后有一空行。

Sample Input:
4
A7
G5
O2
D4
2
10110110111
11111010
Sample Output:
GOOD
DOG

代码

#include<iostream>
#include<cstring>
#include<string.h>
using namespace std;
struct hf{
	char data;
	int weight,l,r,p;
	char b[105];//逆序存储data的编码
}; 
int i1,i2;
void select(hf huff[],int k){//查找最小和次小
	int min,cmin;
	for(int i=0;i<k;i++){//给最小赋初值
		if(huff[i].p==-1){//遇到的第一个根节点
			min=huff[i].weight;
			i1=i;
			break; 
		}
	}
	for(int i=i1+1;i<k;i++){//min和cmin不能设为一样的值,否则遇到min已经最小时无法找到cmin 
		if(huff[i].p==-1){//min的根节点后的第一个根节点
			cmin=huff[i].weight;
			i2=i;
			if(min>cmin){//判断次小和最小的大小
				int k=min;
				min=cmin;
				cmin=k;
				k=i1;
				i1=i2;
				i2=k;
			}
			break; 
		}
	}
//	cout<<i1<<i2<<endl; 
	for(int i=i1;i<k;i++){//开始找次小和最小
		if(huff[i].p==-1){
			if(huff[i].weight<min){
				i1=i;
				min=huff[i].weight;
			}
			else if(huff[i].weight>=min&&huff[i].weight<cmin&&i!=i1){
				i2=i;//i!=i1和>=min确保当最小和次小相同时的判断
				cmin=huff[i].weight;
			}
		 }
		
	}
	if(min==cmin) {//当权值相等时,i1为序号比较小的
		int t=i1;
		i1=i1>i2?i2:i1;
		i2=i2<t?t:i2;
	}
}
int main(){
	int n,m;
	char s[105];
	while(cin>>n){
		hf huff[50];
		i1=i2=0; 
		for(int i=0;i<n;i++){
			cin>>huff[i].data>>huff[i].weight;
		}
		for(int i=0;i<2*n-1;i++){//初始化 
			huff[i].l=huff[i].r=huff[i].p=-1;
			memset(huff[i].b,0,sizeof(huff[i].b));
		}
		for(int k=n;k<2*n-1;k++){//生成哈夫曼树
			select(huff,k);
			huff[i1].p=huff[i2].p=k;
			huff[k].weight=huff[i1].weight+huff[i2].weight;
			huff[k].l=i1;
			huff[k].r=i2;
		}
		for(int i=0;i<n;i++){//创建每个data的编码
			int k=0;
			int c=i;
			while(huff[c].p!=-1){
				int p=huff[c].p;//从下往上找,所以逆序存入b
				if(huff[p].l==c){
					huff[i].b[k]='0';
					k++;
				}
				else if(huff[p].r==c){
					huff[i].b[k]='1';
					k++;
				}
				c=p;
			}
		//	cout<<huff[i].b<<endl;
		}
		cin>>m;
		while(m--){
			cin>>s;
			int len=strlen(s);
			int i,j,z;
			for( i=0;i<len;i++){
				for( j=0;j<n;j++){
					int x=i;
					for( z=strlen(huff[j].b)-1;z>=0;z--){//把b倒过来和s比较
						if(s[x]!=huff[j].b[z])
							break;
						else{
							x++;
						}
					}
					if(z==-1)
					//因为是哈夫曼树,每个叶子节点都是data的节点,所以每个data的编码都一样,
					//不存在哪个data的编码是另一个data的前缀,导致多种解码情况。
					{
						cout<<huff[j].data;
						i+=strlen(huff[j].b)-1;//加上b的长度-1
						break; 
					}	
				}
			
			}
			cout<<endl;
		}
		cout<<endl;
	}
	return 0;
}	


测试数据:
4
A7
G5
O2
D4
2
10110110111
11111010

6
a2
b3
c5
d8
e4
f4
1
0101010

3
b4
e2
f3
4
000
110
1011
1110011

存在的问题:

  1. 第一次写的时候没有对huff[i].b(huff[i]的编码的逆序存储)进行初始化,导致输入不同的测试数据是出错。我以为每次输入n再创建huff数组就不用对b进行初始化了。
  2. 生成树和判断等都可以写成函数,但我的初始化和传递值有点麻烦
  • 0
    点赞
  • 0
    评论
  • 2
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值