huffman树的小小应用

/*
*功能描述:
*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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值