#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#define M 1000
using namespace std;
//哈夫曼树
typedef struct
{
char ch;
int weight;
int parent,lc,rc;
}HNode,*HuffmanTree;
//哈夫曼编码
typedef char **HuffmanCode;
struct Rule {
bool operator()(const char& a1,const char& a2)const {
int a=(int)a1,b=(int)a2;
return a<b;
}
};
void select(HuffmanTree &HT,int n,int &s1,int &s2);
void CreateHuff(HuffmanTree &HT,int *w,char *c,int n);
void CreateHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n);
void mySort(string str,char *node,int *w,int n);
//select函数
void select(HuffmanTree &HT,int n,int &s1,int &s2)//s1,s2为最小权重,分别作为i的左右孩子
{
int minum;
for(int i=1;i<=n;i++)//寻找第一个最小值
{
if(HT[i].parent==0)
{
minum=i;
break;
}
}
for(int i=1;i<=n;i++)
{
if(HT[i].parent==0)
{
if(HT[i].weight<HT[minum].weight)
{
minum=i;
}
}
}
s1=minum;
//寻找第二个最小值,并且与第一个不同
for(int i=1;i<=n;i++)
{
if(HT[i].parent==0&&i!=s1)
{
minum=i;
break;
}
}
for(int i=1;i<=n;i++)
{
if(HT[i].parent==0&&i!=s1)
{
if(HT[i].weight<HT[minum].weight)
{
minum=i;
}
}
}
s2=minum;
}
//创建哈夫曼树
void CreateHuff(HuffmanTree &HT,int *w,char *c,int n)
{
int m,s1,s2;
m=2*n-1;
HT=new HNode[m+1];//分配空间
for(int i=1;i<=n;i++)//1-n放叶子节点,还有(n-1)个存储空间放产生的新节点
{
HT[i].weight=w[i];
HT[i].ch=c[i];
HT[i].parent=0;
HT[i].lc=0;
HT[i].rc=0;
}
for(int i=n+1;i<=m;i++)
{
HT[i].weight=0;
HT[i].parent=0;
HT[i].lc=0;
HT[i].rc=0;
}
for(int i=n+1;i<=m;i++)//创建非叶子节点,建哈夫曼树
{//在HT[1]~HT[i-1]的范围里选择两个parent为0,且weight最小的两个结点,其序号分别赋给s1,s2
select(HT,i-1,s1,s2);
HT[s1].parent=i;
HT[s2].parent=i;
HT[i].lc=s1;
HT[i].rc=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;//生成的新树的权值
}
cout<<endl;
}
//关于weight的计算即字母出现的次序,选择的时候还要考虑字母表中的顺序
//根据哈夫曼树求哈夫曼编码
void CreateHuffmanCode(HuffmanTree HT,HuffmanCode &HC,int n)
{//从叶子到根逆向求每个字符的哈夫曼编码,存储在编码表HC中
HC=new char*[n+1];//分配存储n个字符编码的编码表空间
char* cd=new char[n];//字符串长度最长为n-1,cd[]最后一个位置存放结束符'\0',利用的只有n-1个位置
cd[n-1]='\0';
for(int i=1;i<=n;i++)//逐个字符求哈夫曼编码
{
int start=n-1;
int c=i;
int f=HT[i].parent;
while(f!=0)//只要不是根节点,就接着往上
{
start--;
if(HT[f].lc==c)
{
cd[start]='0';
}
else
{
cd[start]='1';
}
c=f;
f=HT[f].parent;//继续向上回溯
} //求出第i个字符的编码
HC[i]=new char[n-start];//为第i个字符编码分配空间
strcpy(HC[i],&cd[start]);
}
delete cd;
}
int main()
{
int n;
cin>>n;
while(n--) {
HuffmanTree HT;
HuffmanCode HC;
char c[M],t[M],h[M];//c[M]用来存输入数据并且输出时按照c[M]顺序t[M]来存去重后
int w[M]= {};
//按照ASCII码顺序的字符串,w[M]存t[M]对应的权值
string s;
cin>>s;
int len=s.length();
for(int i=0,j=1; i<len; i++,j++) {
c[j]=s[i];
t[j]=s[i];
}//数组下标从1开始
sort(t+1,t+len+1,Rule());
//aaaadddeeeggjk
h[0]='0';
h[1]=t[1];
w[1]=1;
int num=1;
for(int i=2; i<=len; i++) {
//cout<<"inbigfor"<<endl;
num++;
for(int j=i; j<=len; j++) {
//cout<<"insmallfor"<<endl;
if(t[j]==t[j-1]) {
w[num-1]++;
i++;
continue;
} else {
h[num]=t[i];
w[num]++;
break;
}
}
}
int n=strlen(h)-1;
CreateHuff(HT,w,h,n);
CreateHuffmanCode(HT,HC,n);
for(int i=1;i<=len;i++)
{
for(int j=1;j<=n;j++)
if(c[i]==HT[j].ch)
{
cout<<HC[j];
}
}
}
return 0;
}
/*2
avvvdddeeeffffgggggjk
eeeffrnvjshvhssnn
*/
实验4-哈夫曼编码实现电文压缩存储
最新推荐文章于 2023-03-22 22:38:42 发布