/*设计思路,采用线性标存储,用数组存储二叉树,数组从1开始存储,舍弃a[0],所有非叶子节点的info存储字符#,不影响对#的编码,
把编码结果保存在HT数组中*/ //测试样例 输入:aaaaabbbbcccdde 111000011010
#include<bits/stdc++.h>
using namespace std;
typedef struct
{
char info;//关联字符信息
int weight;//每个节点的权值
int parent,lchild,rchild;//索引
}TNode,*Huffmancode;
typedef struct
{
char ch;
string s;
}Coding;
int count(TNode a[],string s)
{
int i=1,n;
string::iterator it1;//指向string的迭代器
map<char,int> T;
map<char,int>::iterator it;//it指向T
T.clear();//清空T
for(it1=s.begin();it1!=s.end();it1++)
{
T[*it1]++;
}
for(it=T.begin();it!=T.end();it++)
{
pair<char,int>item=*it;
a[i].info=item.first;
a[i++].weight=item.second;
}
n=i-1;
cout<<"叶子节点的数量为"<<n<<endl;
for(i=1;i<=n;i++)
{
cout<<a[i].info<<"---->"<<a[i].weight<<endl;//打印每个叶子的info,及weight
}
return n;//叶子节点数
}
TNode initalize(TNode a[],int n)//初始化函数
{
int i;//一颗有n个节点的哈夫曼树有2n-个节点
for(i=1;i<=n;i++)
{
a[i].parent=0;
a[i].rchild=0;
a[i].lchild=0;
}
for(i=n+1;i<=2*n-1;i++)
{
a[i].parent=0;
a[i].rchild=0;
a[i].lchild=0;
a[i].weight=0;
a[i].info='#';
}
}
TNode HuffmanTree(TNode a[],int n)
{
int m=2*n-1,i,j,k;
int min1,min2;
if(n>1) //当n=1时,m=1,不能构建HuffmanTree,直接对该字符编1,没有深度为一的哈夫曼树
{
for(i=n+1;i<=m;i++)
{
int min1=min2=0;
a[min1].weight=1<<30,a[min2].weight=1<<30;
for(j=1;j<i;j++)
{
if(!a[j].parent&&a[j].weight<a[min1].weight)
{
min1=j;
}
}//第一小weight
a[min1].parent=1;//1表示已被选取,便于选取第二小
for(j=1;j<i;j++)
{
if(!a[j].parent&&a[j].weight<a[min2].weight)
{
min2=j;
}
}//第二小weight
a[i].weight=a[min1].weight+a[min2].weight;
a[i].lchild=min1;
a[i].rchild=min2;
a[min1].parent=i;
a[min2].parent=i;
}
}
}//Huffmantree构建完成
TNode Huffmancodeing(Coding b[],Coding HT[],TNode a[],int n)//编码函数,向右走为1,向左走为0;
{
int i,j;
string s;
char ch;
int c,p;
for(i=1;i<=n;i++)//求编号为1-n的叶子节点的编码
{
c=i;//child索引
p=a[i].parent;//找到parent的索引
while(1)
{
if(!a[c].parent)
{
break;//根节点跳出循环
}
else if(a[c].parent)//p=0则说明到根节点,在2*n-的节点中根节点的parent=0
{
if(a[p].rchild==c)//i为p的右孩子
{
s=s+'1';//cout<<'1';
}
else if(a[p].lchild==c)//i为p的左孩子
{
s=s+'0';//cout<<'1';
}
}
c=p;//继续从p走直到根节点
p=a[c].parent;
}
b[i].ch=a[i].info;
b[i].s=s;
s.clear();
}//从叶子节点向跟节点走,记录所走的路径,即为对应的编码 //接下来让路径反转
string::iterator it;
cout<<"输出对应编码"<<endl;
for(i=1;i<=n;i++)
{
string s1;
s1.clear();
s=b[i].s;
for(it=s.end()-1;it>=s.begin();it--)
{
s1=s1+*it;
}
HT[i].ch=b[i].ch;
HT[i].s=s1;
cout<<HT[i].ch<<"--->"<<HT[i].s<<endl;
s.clear();
}
}//从叶子节点向跟节点走,记录所走的路径,即为对应的编码
string decoder(TNode a[],string s1,string str,int n)//译码函数,对串s1进行树的遍历,将结果保存在str串中
{
int m=2*n-1;
str.clear();
string::iterator it;
int c=m,y=m;//当前结点,y为叶子节点
s1=s1+'#';
for(it=s1.begin();it!=s1.end();it++)
{
if(c>=1&&c<=n)//判断当前节点是否为叶子节点
{
str+=a[c].info;
it--;
c=m;
}
else
{
if(*it=='1')
{
c=a[c].rchild;
}
else if(*it=='0')
{
c=a[c].lchild;
}
}
}
return str;
}
int main()
{
string s,s1;
int n;//叶子节点数
TNode a[200];//存放需进行编码的字符的数组
Coding b[200],HT[200];//存储NI编码的数组,编码数组HT
getline(cin,s);//可以读入带空格的字符串
n=count(a,s);//统计函数
initalize(a,n);//初始化函数
HuffmanTree(a,n);//建树函数
Huffmancodeing(b,HT,a,n);//编码函数
getline(cin,s1);//译码输入时需要以任意字符结尾,随便输入一个字符就可以,否则最后一个字符不能输出
string str;
str=decoder(a,s1,str,n);
cout<<str<<endl;
}
解决
原文作者: 汉诺塔问题
原文地址: https://blog.csdn.net/yanyuqingchen/article/details/78973698
本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
原文地址: https://blog.csdn.net/yanyuqingchen/article/details/78973698
本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。