/*
*功能描述:
*1.输入任意字符串str[]
*2.检索并统计不同的字符,将相异字符存入ch[]并将字符对应的个数作为权值存入weight[]
*3.由权值,构造huffman树,对各个字符进行编码,并存入HC[]
*4.输出各字符的编码
*5.输出总字符串的编码
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define OK 0
#define ERROR 1
#define MAX 100
typedef int Status;
typedef struct HTNode
{
int weight;
int parent,lchild,rchild;
}HTNode,*HuffmanTree;
typedef char **HuffmanCode;
Status creatHuffmanTree(HuffmanTree &HT,int *w,int n);//w存放n个字符的权值,生成HuffmanTree HT
Status huffmanEnCoding(HuffmanTree HT,HuffmanCode &HC,int n);
Status huffmanDeCoding();
Status str_to_huffmancode(char *str,char *ch,HuffmanCode HC,char *HC_for_Str);//根据ch[]、HC[]Huffman编码表,将str中相应的字符转换成huffman编码,存入HC_for_Str[]
Status get_ch_num(char *str,char *ch,int &num);//由str生成ch[]
Status get_weight(char *str,char *ch,int *weight);//由str生成ch[]中每个元素的个数,作为权值
Status select(HuffmanTree HT,int n,int &s1,int &s2);//寻找权值最小的两个节点,序号为s1,s2 s1<s2
int main()
{
HuffmanTree HT;
HuffmanCode HC;//HC[i][]从0号单元存储字符huffmancode
int i,j;
int num;//存储相异字符个数
int *weight;//存储各字符的权值
char str[MAX],ch[MAX];//str[]存储输入的字符传串,ch[]存储单个字符
char *HC_for_Str;//存放str字符串的huffman编码
printf("输入任意字符串:");
for(i=1;i<MAX;i++)
{
scanf("%c",&str[i]);
if(str[i]=='#')
break;
}
str[0]='#';//str[]从1号单元开始,0号单元初始化
str[i]='\0';//加‘\0’作为结束符
get_ch_num(str,ch,num);//统计不同字符个数,并存入ch[]
weight=(int *)malloc((num+1)*sizeof(int));//初始化数组
get_weight(str,ch,weight);//获得每个ch[i]的权值存入weight[i]中
creatHuffmanTree(HT,weight,num);//创建huffman树
huffmanEnCoding(HT,HC,num);//对huffman树进行编码
for(i=1;i<=num;i++)//打印对应字符的Huffman编码
printf("%c:%s\n",ch[i],HC[i]);
HC_for_Str=(char *)malloc((num*num)*sizeof(char));//初始化数组HC_for_Str[]
str_to_huffmancode(str,ch,HC,HC_for_Str);//根据ch[]、HC[]Huffman编码表,将str中相应的字符转换成huffman编码,存入HC_for_Str[]
printf("%s",HC_for_Str);//打印所输入的字符串的Huffman编码
system("pause");
return 0;
}
Status creatHuffmanTree(HuffmanTree &HT,int *w,int n)//w存放n个字符的权值,生成HuffmanTree HT
{
int i,m;//m用于存放总结点数
HuffmanTree p;
if(n<=1)
{
printf("无需编码\n");
return ERROR;
}
m=2*n-1;//生成的Huffman Tree中有m个节点
HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//序号从1开始,节点序号与下标一致
for(p=HT+1,i=1;i<=n;i++,p++)//初始化字符HUffman表
{
p->weight=w[i];
p->parent=0;
p->lchild=0;
p->rchild=0;
}
for(;i<=m;i++,p++)//初始化分支节点HUffman表
{
p->weight=0;
p->parent=0;
p->lchild=0;
p->rchild=0;
}
int s1,s2;//存放select函数的参数值
for(i=n+1;i<=m;i++)//建立HUffman树
{
select(HT,i-1,s1,s2);//寻找权值最小的两个节点,序号为s1,s2
HT[s1].parent=HT[s2].parent=i;//将i赋为s1,s2的parent
//建立i的结构,此处设置lchild的权值<=rchild的权值
HT[i].lchild=s1;
HT[i].rchild=s2;
HT[i].weight=HT[s1].weight+HT[s2].weight;
}
return OK;
}
Status huffmanEnCoding(HuffmanTree HT,HuffmanCode &HC,int n)//由生成的HuffmanTree HT求出各字符编码存入HC
{
int i;
//根据Huffman树对每个字符进行编码,由叶子节点依次向上
HC=(HuffmanCode)malloc((n+1)*sizeof(char*));//下标从1号开始
char *cd;//存放每次遍历求得当前叶子节点的huffmancode
cd=(char *)malloc(n*sizeof(char));
cd[n-1]='\0';//由树的性质,n个字符的huffman Code最多有n-1位
int start,cur=0,flag=0;//叶子节点依次向上遍历,所得值逆向存于cd[]中,start为cd[]当前下标
for(i=1;i<=n;i++)//每个叶子节点,依次遍历至树根,
{
start=n-1;
for(cur=i,flag=HT[i].parent;flag!=0;cur=flag,flag=HT[flag].parent)
if(HT[flag].lchild==cur)
cd[--start]='0';
else
cd[--start]='1';
//将cd中的编码复制到HuffmanCode[i]中
HC[i]=(char *)malloc((n-start)*sizeof(char));//HC[i]中编码有n-start位
for(flag=start;flag<n;flag++)//HC[i][}从0号单元存储字符huffmancode
HC[i][flag-start]=cd[flag];
}
free(cd);
return OK;
}
Status select(HuffmanTree HT,int n,int &s1,int &s2)//寻找权值最小的两个节点,序号为s1,s2
{
int i;
s1=s2=0;
for(i=1;i<=n;i++)
if(HT[i].parent==0)
{
if(s1==0)
s1=i;
else if(s2==0)
s2=i;
else
{
if(HT[s1].weight<HT[s2].weight)//选择较大值与当前值比较
{
if(HT[i].weight<HT[s2].weight)
s2=i;
}
else
{
if(HT[i].weight<HT[s1].weight)
s1=i;
}
}
}
if(HT[s1].weight>HT[s2].weight)//设定s1<=s2
{
i=s1;
s1=s2;
s2=i;
}
return OK;
}
Status get_ch_num(char *str,char *ch,int &num)//由str生成ch[]
{
int i,j;
for(i=0;i<=strlen(str);i++)//初始化ch
{
ch[i]='#';
}
num=0;
for(i=1;i<strlen(str);i++)
{
for(j=i+1;j<=strlen(str);j++)//从i+1号向后检索,如果有相同元素退出
if(str[i]==str[j])
break;
if(j>strlen(str))//str中i以后没有str[i]元素,加入ch
ch[++num]=str[i];
}
ch[num+1]='\0';
return OK;
}
Status get_weight(char *str,char *ch,int *weight)//由str生成ch[]中每个元素的个数,作为权值
{
int i,j;
for(i=0;i<=strlen(ch);i++)//初始化weight[]
{
weight[i]=0;
}
for(i=1;i<=strlen(ch);i++)
for(j=1;j<strlen(str);j++)//对每个ch[i],遍历str[],求得权值
if(ch[i]==str[j])
weight[i]++;
return OK;
}
Status str_to_huffmancode(char *str,char *ch,HuffmanCode HC,char *HC_for_Str)//根据ch[]、HC[]Huffman编码表,将str中相应的字符转换成huffman编码,存入HC_for_Str[]
{
int i,j,n;
static int m=0;//存储HC_for_Str时作为标志位
for(i=1;i<strlen(str);i++)
for(j=1;j<strlen(ch);j++)
if(str[i]==ch[j])//将str中相应的字符转换成huffman编码,存入HC_for_Str[]
{
for(n=0;n<strlen(HC[j]);n++)
HC_for_Str[m++]=HC[j][n];
}
HC_for_Str[m]='\0';
return OK;
}
huffman树的小小应用
最新推荐文章于 2022-04-22 20:09:37 发布