//严蔚敏《数据结构》
//赫夫曼树及其应用:创建顺序赫夫曼树创建及得到赫夫曼编码
//(从叶子结点到根逆向求每个字符的赫夫曼编码)以及(无栈非递归遍历赫夫曼树,求赫夫曼编码)
//自学中,加油!
//黎明到黄昏,终点就是起点
#include<iostream>
#include<cstring>
using namespace std;
typedef struct//利用顺序,动态分配内存
{
unsigned int weight;
unsigned int parent,lchild,rchild;
}HTNode,* HuffmanTree;
typedef char** HuffmanCode;//实际HuffmanCode是二维数组
void Select(HuffmanTree HT,int n,int& s1,int& s2)
//找 赫夫曼树HT中1~n的parent为0的最小的两个权值 的下标(HT的下标从1开始)
{
int min1=1000,min2=1000;
for(int i=1;i<=n;i++){
if(HT[i].parent==0&&HT[i].weight<min1){
min1=HT[i].weight;
s1=i;
}
}
for(int i=1;i<=n;i++){
if(HT[i].parent==0&&i!=s1&&HT[i].weight<min2){//i!=s1用来 排除s1的情况 找除最小值外的第二个最小值
min2=HT[i].weight;
s2=i;
}
}
}
void HuffmanCoding(HuffmanTree& HT,HuffmanCode& HC,int* w,int n)
//w数组存放n个字符的权值 构建赫夫曼树HT,并将n个字符的编码存入赫夫曼编码HC
{
if(n<=1)
return;
int m=2*n-1;
HT=new HTNode[m+1];//0号单位未用
int i;
for(i=1;i<=n;i++){
HT[i].parent=HT[i].lchild=HT[i].rchild=0;
HT[i].weight=*w++;
}
for(;i<=m;i++){
HT[i].parent=HT[i].lchild=HT[i].rchild=HT[i].weight=0;
}
//至此赫夫曼树完成初始化
int s1,s2;
for(i=n+1;i<=m;i++){//进行赫夫曼树的创建
Select(HT,i-1,s1,s2);
HT[i].lchild=s1;
HT[i].rchild=s2;
HT[s1].parent=HT[s2].parent=i;
HT[i].weight=HT[s1].weight+HT[s2].weight;
}
/*
//从叶子结点到根逆向求每个字符的赫夫曼编码
HC=new char*[n+1];//0号单位未用
char* ch=new char[n];
ch[n-1]='\0';
int c,f;
for(i=1;i<=n;i++){//求n个字符的赫夫曼树编码
int start=n-1;
for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent){
if(HT[f].lchild==c)
ch[--start]='0';
else
ch[--start]='1';
}
HC[i]=new char[n-start];
strcpy(HC[i],&ch[start]);//bug1:strcpy(HC[i],ch);是不行的,看严《数据结构》P147的理解
}
delete ch;
*/
//无栈非递归遍历赫夫曼树,求赫夫曼编码
HC=new char*[n+1];//0号单位未用
char* ch=new char[n];
int chlen=0;
int p=m;//从总根结点开始 p为结点下标
for(int i=1;i<=m;i++)//已经用过weight建立赫夫曼树,现在用weight作为遍历的标志变量
HT[i].weight=0;
while(p){//p为0时循环结束
if(HT[p].weight==0){//向左
HT[p].weight=1;
if(HT[p].lchild!=0){
p=HT[p].lchild;
ch[chlen++]='0';
}
else if(HT[p].rchild==0){//叶子结点的赫夫曼编码存入HC[p]中
HC[p]=new char[chlen+1];
ch[chlen]='\0';
strcpy(HC[p],ch);
}
}
else if(HT[p].weight==1){//向右
HT[p].weight=2;
if(HT[p].rchild!=0){
p=HT[p].rchild;
ch[chlen++]='1';
}
}
else{//返回到双亲结点,ch长度-1
HT[p].weight=0;
p=HT[p].parent;
chlen--;
}
}
delete ch;
}
void Output_HuffmanCode(HuffmanCode HC,int n)//HC下标从1开始
{
cout<<"----"<<endl;
for(int i=1;i<=n;i++){
for(int j=0;HC[i][j]!='\0';j++)
cout<<HC[i][j];
cout<<endl;
}
cout<<"\n----"<<endl;
}
int main()
{
HuffmanTree HT;
HuffmanCode HC;
int n=5;
int w[5]={10,5,23,1,4};//5个字符的权值
HuffmanCoding(HT,HC,w,n);
Output_HuffmanCode(HC,n);
return 0;
}
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/43da4aa94cbe82b39c82f4e70db8cdd1.jpeg)
----
00
010
1
0110
0111
----
Process returned 0 (0x0) execution time : 0.139 s
Press any key to continue.