数据结构实验——基于哈夫曼树的数据压缩算法

/*

注:输入为多行字符串,以“0”结尾;例:abc def 0

此程序无法执行由单个字符组成的字符串。

*/

#include<iostream>

#include<string>
#include<map>
using namespace std;


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


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;//恢复原来的值
}


//用算法5.10构造赫夫曼树
void CreatHuffmanTree(HuffmanTree &HT,int n,map<char,int> & maps)
{
//构造赫夫曼树HT
int m,s1,s2,i;
if(n<=1) return;
m=2*n-1;
HT=new HTNode[m+1];   //0号单元未用,所以需要动态分配m+1个单元,HT[m]表示根结点   
for(i=1;i<=m;++i)         //将1~m号单元中的双亲、左孩子,右孩子的下标都初始化为0   
  { HT[i].parent=0;  HT[i].lchild=0;  HT[i].rchild=0; }




map<char,int>::iterator it;
it=maps.begin();
for(i=1;i<=n;++i,it++)         //输入前n个单元中叶子结点的权值  
HT[i].weight=it->second; 
/*――――――――――初始化工作结束,下面开始创建赫夫曼树――――――――――*/ 
for(i=n+1;i<=m;++i) 
{   //通过n-1次的选择、删除、合并来创建赫夫曼树
Select(HT,i-1,s1,s2);
//在HT[k](1≤k≤i-1)中选择两个其双亲域为0且权值最小的结点,
// 并返回它们在HT中的序号s1和s2
HT[s1].parent=i;
HT[s2].parent=i;   
//得到新结点i,从森林中删除s1,s2,将s1和s2的双亲域由0改为i
HT[i].lchild=s1;   
HT[i].rchild=s2 ; //s1,s2分别作为i的左右孩子
HT[i].weight=HT[s1].weight+HT[s2].weight; //i 的权值为左右孩子权值之和
} //for
}
// CreatHuffmanTree
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;                             //释放临时空间
}




void select_yuan_su(string a1,map<char,int> & maps,int &n,string &h)
{
map<char,int>::iterator it,is;

for(int i=0;i<a1.length();i++)
{
it = maps.find(a1[i]);
if(it != maps.end())  
(it->second)++;
            else
{ maps[ a1[i] ] = 1; n++;}
}


is=maps.end();
is--;

for(it=maps.begin();it!=maps.end();it++)
{
h+=it->first;
cout<<it->first<<":"<<it->second;
if(it!=is) cout<<" ";
}
cout<<endl;
}




void shuchu_zhongtai(HuffmanTree ht,int n)
{
for(int i=1;i<2*n;i++)
{
cout<<i<<" "<<ht[i].weight<<" "<<ht[i].parent
<<" "<<ht[i].lchild<<" "<<ht[i].rchild<<endl;
}


}




void shuchu_bian_ma(HuffmanCode hc,int n,map<char,int> &maps)
{
    map<char,int>::iterator it,is;


it=maps.begin();
is=maps.end();
is--;
    for(int i=1;i<=n;++i,it++) 
{
cout<<it->first<<":"<<hc[i];
if(it!=is) cout<<" ";
}
cout<<endl;


}




string bian_ma(string a1,string h,HuffmanCode hc,int n)
{
string m;
char m2;
for(int i=0;i<a1.length();i++)
{
m2=a1[i];
for(int j=0;j<n;j++)
{
if(m2==h[j]) 
{
m+=hc[j+1];
break;

}

}
cout<<m<<endl;
return m;
}




void jie_ma(string m,string h,HuffmanCode hc,int n)
{


string y,x;
for(int i=0;i<m.length();i++)
{
y+=m[i];
for(int j=1;j<=n;j++)
{
if(y==hc[j]) 
{
x+=h[j-1];
y.erase();
break;

}
}
cout<<x<<endl;
}





void main()
{
string a1;
string b1="0";


cin>>a1;

while(a1!=b1)
{
map<char,int> maps;
int i,n;
string h;
n=0;
select_yuan_su(a1,maps,n,h);




HuffmanTree ht;
   HuffmanCode hc;


CreatHuffmanTree(ht,n,maps);
shuchu_zhongtai(ht,n);



   CreatHuffmanCode(ht,hc,n);
shuchu_bian_ma(hc,n,maps);




string m=bian_ma(a1,h,hc,n);


jie_ma(m,h,hc,n);




cin>>a1;
}


}

猜你喜欢

转载自blog.csdn.net/u013595395/article/details/80600726