基于哈夫曼树的数据压缩算法

 
描述

 

输入一串字符串,根据给定的字符串中字符出现的频率建立相应哈夫曼树,构造哈夫曼编码表,在此基础上可以对待压缩文件进行压缩(即编码),同时可以对压缩后的二进制编码文件进行解压(即译码)。


 

输入

多组数据,每组数据一行,为一个字符串(只考虑26个小写字母即可)。当输入字符串为“0”时,输入结束。

输出

每组数据输出2n+3行(n为输入串中字符类别的个数)。第一行为统计出来的字符出现频率(只输出存在的字符,格式为:字符:频度),每两组字符之间用一个空格分隔,字符按照ASCII码从小到大的顺序排列。第二行至第2n行为哈夫曼树的存储结构的终态(形如教材139页表5.2(b),一行当中的数据用空格分隔)。第2n+1行为每个字符的哈夫曼编码(只输出存在的字符,格式为:字符:编码),每两组字符之间用一个空格分隔,字符按照ASCII码从小到大的顺序排列。第2n+2行为编码后的字符串,第2n+3行为解码后的字符串(与输入的字符串相同)。

输入样例 1 

aaaaaaabbbbbccdddd
aabccc
0

输出样例 1

a:7 b:5 c:2 d:4
1 7 7 0 0
2 5 6 0 0
3 2 5 0 0
4 4 5 0 0
5 6 6 3 4
6 11 7 2 5
7 18 0 1 6
a:0 b:10 c:110 d:111
00000001010101010110110111111111111
aaaaaaabbbbbccdddd
a:2 b:1 c:3
1 2 4 0 0
2 1 4 0 0
3 3 5 0 0
4 3 5 2 1
5 6 0 3 4
a:11 b:10 c:0
111110000
aabccc
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;int d;int fre[26];int kn=0;int k=0;char namelist[26];

typedef struct{
	int vtag;
	int weight;
	int parent,lchild,rchild;
}HTNode,*HuffmanTree;

typedef char** HuffmanCode;

typedef struct{
	int Freque; 
	HuffmanCode HCC;
	char ch;
}Letter;

void Select(HuffmanTree HT,int len,int &s1,int &s2)
{
	int i,min1=0x3f3f3f3f,min2=0x3f3f3f3f;//先赋予最大值
	for(i=1;i<=len;i++)
	{
		if(HT[i].weight<min1&&HT[i].parent==0)
		{
			min1=HT[i].weight;
			s1=i;
		}	
	}
	int temp=HT[s1].weight;//将原值存放起来,然后先赋予最大值,防止s1被重复选择
	HT[s1].weight=0x3f3f3f3f;
	for(i=1;i<=len;i++)
	{
		if(HT[i].weight<min2&&HT[i].parent==0)
		{
			min2=HT[i].weight;
			s2=i;
		}
	}
	HT[s1].weight=temp;//恢复原来的值
}

void CreateHuffmanTree(HuffmanTree &HT,int n)
{
	int i;
	if(n<=1) return;
	int m=2*n-1;
	HT=new HTNode[m+1];
	for(i=1;i<=m;i++)
	{
		HT[i].parent=0;
		HT[i].lchild=0;
		HT[i].rchild=0;
	 } 
	for(i=1;i<=n;i++)
		HT[i].weight=fre[i-1];
	int s1,s2;
	for(i=n+1;i<=m;i++)
	{
		Select(HT,i-1,s1,s2);
		HT[s1].parent=i;
		HT[s2].parent=i;
		HT[i].lchild=s1;
		HT[i].rchild=s2;
		HT[i].weight=HT[s1].weight+HT[s2].weight;
	}
}

void FrequeStats(int n[],string s)
{
	int i=0;
	while(s[i]!='\0')
	{
		int e=(int) s[i];
		if(e>=97)
			n[e-97]++;
		i++;
	}
	d=i;
//	cout<<"一共输入了"<<d<<"个字符"<<endl;
	for(i=0;i<26;i++)
		if(n[i]) 
		{
				kn++;
		}
	for(i=0;i<26;i++)
		if(n[i]) 
		{
				char e=(char)(i+97);
				cout<<e<<":"<<n[i];
				if(k!=kn-1)cout<<" ";//多输出了一个 
				fre[k]=n[i];
				namelist[k]=e;
				k++;
		}
	//cout<<"一共有"<<k<<"个叶子结点"<<endl;
	cout<<endl;
}

void CreatHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n)
{
	//从叶子到根逆向求每个字符的赫夫曼编码,存储在编码表HC中
	int i,start,c,f;
	HC=new char*[n+1];         						//分配n个字符编码的头指针矢量
	char *cd=new char[n];							//分配临时存放编码的动态数组空间
	cd[n-1]='\0';                            		//编码结束符
	for(i=1;i<=n;++i)
	{                      							//逐个字符求赫夫曼编码
		start=n-1;                          		//start开始时指向最后,即编码结束符位置
		c=i; 
		f=HT[i].parent;                 			//f指向结点c的双亲结点
		while(f!=0)
		{                          					//从叶子结点开始向上回溯,直到根结点
			--start;                          		//回溯一次start向前指一个位置
			if(HT[f].lchild==c)  
				cd[start]='0';						//结点c是f的左孩子,则生成代码0
			else 
				cd[start]='1';                 		//结点c是f的右孩子,则生成代码1
			c=f; 
			f=HT[f].parent;             			//继续向上回溯
		}                                  			//求出第i个字符的编码      
		HC[i]=new char[n-start];         			// 为第i 个字符编码分配空间
		strcpy(HC[i], &cd[start]);        			//将求得的编码从临时空间cd复制到HC的当前行中
	}
	delete cd;                            			//释放临时空间
}													// CreatHuffanCode
void Show(HuffmanTree HT,HuffmanCode HC)
{
	for(int i=1;i<=2*k-1;i++)
		cout<<i<<" "<<HT[i].weight<<" "<<HT[i].parent<<" "<<HT[i].lchild<<" "<<HT[i].rchild<<endl; 

	for(int i=1;i<=k;i++)
	{
		cout<<namelist[i-1]<<":"<<HC[i];
		if(i!=k)cout<<" ";//多输出了一个 
	}
	cout<<endl; 
}

void Tranfer(HuffmanCode HC,string s)
{
	int i=0;
	while(s[i])
	{
		int j=0;
		while(j<26)
		{
			if(s[i]==namelist[j])//如果该字符与namelist中某个字符相等
			cout<<HC[j+1];//输出其对应编码 
			j++;
		}
		i++;
	}
	cout<<endl;
	
	i=0;
	while(s[i])
	{
		char e;
		e=s[i];
		cout<<e;
		i++; 
	}
	cout<<endl; 
}

void InitData(int fre[])
{
		
		for(int i=0;i<26;i++)
			fre[i]=0;
		//memset(fre,0,sizeof(fre));//不能用这个,为什么? 
		memset(namelist,0,sizeof(namelist));
		d=0;k=0;kn=0;

		return;
}

int main()
{
	while(1)
	{
		string s;
		cin>>s;
		if("0"==s) break;
		
		InitData(fre);
		FrequeStats(fre,s);
		HuffmanTree HT;
		HuffmanCode HC;
		CreateHuffmanTree(HT,k);
		CreatHuffmanCode(HT,HC,k);
		Show(HT,HC);
		Tranfer(HC,s);
	}
	return 0;
}
发布了100 篇原创文章 · 获赞 4 · 访问量 3662

猜你喜欢

转载自blog.csdn.net/weixin_43673589/article/details/104420856