哈夫曼树(数据结构)

文本读取
	FILE *fp;
	char ch;
 	string s;
 	int a[270],num=0;
 	HTNode ht[50];
	HTCode hc[120];
	
 	memset(a,0,sizeof a);
	if((fp=fopen("编码前.txt","r"))==NULL)//如果读取出错 ,结束程序 
	{
  		printf("File open error!");
  				exit(0);
    }
    
	while((ch=fgetc(fp))!=EOF)//桶排序获取权重
	{
		a[ch-32]++; 
		s+=ch;//加到字符串中去 
	} 
    printf("读取到的文件内容是:\n%s\n",s.c_str()); //输出文本内容,保证正确读入 
    
初始化加传递权重
	int j=1;
	for(int i=0;i<50;i++) ht[i].w=0;
	for(int i=0;i<120;i++) hc[i].w=0;
	
	for(int i=0;i<270;i++)
	{ 
		if(a[i]!=0)
		{
			hc[j].data=i+32;//输入相应的字符 
			num++;	//统计字符种类
			hc[j].w=a[i];//传递字符权值 
			j++;
		}
	}			
select函数
void Select(HTNode ht[], int k, int *s1, int *s2){//选择没有加入树中并且最小的两个结点,由指针记录信息 
 
	int i=1;
	while(i<=k&&ht[i].p!=0) i++; //找到第一个没有加入到树中的节点 
	*s1=i;
 	
	for(i=1; i<=k; i++)//找到最小的结点(没有加入树中) 
	{
		if(ht[i].p==0 && ht[i].w<ht[*s1].w)
			*s1=i;
	}
  
	for(i=1; i<=k; i++)//找到第一个没有加入到树中的节点 
	{
		if(ht[i].p==0&&i!=*s1)
			break;
	}
	*s2=i;
 
	for(i=1; i<=k; i++)
	{
		if(ht[i].p==0&&i!=*s1 &&ht[i].w<ht[*s2].w)//找到次小的结点(没有加入树中) 
			*s2 = i;
	}
}
 
构建哈夫曼树
	for(int i=1; i<=m; i++)
	{
		if(i<=n)
			ht[i].w = hc[i].w;
		ht[i].p = ht[i].l = ht[i].r= 0;
	}
 
	for(int i=n+1; i<=m; i++)//构建哈夫曼树 
	{
		Select(ht, i-1, &s1, &s2);
		ht[s1].p = i;
		ht[s2].p = i;
		ht[i].l = s1;
		ht[i].r = s2;
		ht[i].w = ht[s1].w+ht[s2].w;
	}
哈夫曼编码
	char q[300];	
	cd[n-1]='\0';
 
	for(int i=1; i<=n; i++)//编码 
	{
		start = n-1;
		for(int c=i,f=ht[i].p; f; c=f,f=ht[f].p){
			if(ht[f].l == c)
				cd[--start] = '0';
			else
				cd[--start] = '1';
		}
	strcpy(hc[i].code, &cd[start]);
	s+=cd+start;
	}
完整代码
#include<iostream> 
#include<cstdio>
#include<cstring>

using namespace std;



struct HTNode //树的结点的结构 
{
	int w;//权重 
	int p,l,r;//双亲结点,左孩子,右孩子 
};

struct HTCode
{
	char data; //带编码的字符 
	int w;  //字符的权值 
	char code[50]; //字符的编码	
};

void Select(HTNode ht[], int k, int *s1, int *s2){//选择没有加入树中并且最小的两个结点,由指针记录信息 
 
	int i=1;
	while(i<=k&&ht[i].p!=0) i++; //找到第一个没有加入到树中的节点 
	*s1=i;
 	
	for(i=1; i<=k; i++)//找到最小的结点(没有加入树中) 
	{
		if(ht[i].p==0 && ht[i].w<ht[*s1].w)
			*s1=i;
	}
  
	for(i=1; i<=k; i++)//找到第一个没有加入到树中的节点 
	{
		if(ht[i].p==0&&i!=*s1)
			break;
	}
	*s2=i;
 
	for(i=1; i<=k; i++)
	{
		if(ht[i].p==0&&i!=*s1 &&ht[i].w<ht[*s2].w)//找到次小的结点(没有加入树中) 
			*s2 = i;
	}
}
 
void HuffmanCoding(HTNode ht[],HTCode hc[],int n){
	
	char cd[n];
	int m,s1,s2,start;
	m = 2*n-1;
	string s;
	for(int i=1; i<=m; i++)
	{
		if(i<=n)
			ht[i].w = hc[i].w;
		ht[i].p = ht[i].l = ht[i].r= 0;
	}
 
	for(int i=n+1; i<=m; i++)//构建哈夫曼树 
	{
		Select(ht, i-1, &s1, &s2);
		ht[s1].p = i;
		ht[s2].p = i;
		ht[i].l = s1;
		ht[i].r = s2;
		ht[i].w = ht[s1].w+ht[s2].w;
	}
	
 	char q[300];	
	cd[n-1]='\0';
 
	for(int i=1; i<=n; i++)//编码 
	{
		start = n-1;
		for(int c=i,f=ht[i].p; f; c=f,f=ht[f].p){
			if(ht[f].l == c)
				cd[--start] = '0';
			else
				cd[--start] = '1';
		}
	strcpy(hc[i].code, &cd[start]);
	s+=cd+start;
	}
}
 
int main()
{
 	FILE *fp;
	char ch;
 	string s;
 	int a[270],num=0;
 	HTNode ht[50];
	HTCode hc[120];
	
 	memset(a,0,sizeof a);
	if((fp=fopen("编码前.txt","r"))==NULL)//如果读取出错 ,结束程序 
	{
  		printf("File open error!");
  				exit(0);
    }
    
	while((ch=fgetc(fp))!=EOF)
	{
		a[ch-32]++; 
		s+=ch;//加到字符串中去 
	} 
    printf("读取到的文件内容是:\n%s\n",s.c_str()); //输出文本内容,保证正确读入 
    
	int j=1;
	
	for(int i=0;i<50;i++) ht[i].w=0;
	for(int i=0;i<120;i++) hc[i].w=0;
	
	for(int i=0;i<270;i++)
	{ 
		if(a[i]!=0)
		{
			hc[j].data=i+32;//输入相应的字符 
			num++;	//统计字符种类
			hc[j].w=a[i];//传递字符权值 
			j++;
		}		
	}
	cout<<"该文章中字符的种类数为:"<<num<<endl;
	
	HuffmanCoding(ht,hc,num); 
	printf("编码前文章中字符所占空间为:1633字节\n");
	printf("编码后文章中字符所占空间为:6874字节\n");
	cout<<"该文章中字符的哈夫曼编码为:"<<endl;
    for(int i=1;i<=num;i++)
    	printf("\n%c\t%s",hc[i].data,hc[i].code);
    printf("\n");	
	
	if(fclose(fp))
 	{
  		printf("Can not close the file!");
  		exit(0); 
 	}
	
	
	
	printf("该篇文章的哈夫曼译码为:\n");
	 
	if((fp=fopen("编码前.txt","r"))==NULL)//如果读取出错 ,结束程序 
	{
  		printf("File open error!");
  				exit(0);
    }
	while((ch=fgetc(fp))!=EOF)
	{
		for(int i=1;i<=num;i++)	
			if(hc[i].data==ch)
				cout<<hc[i].code; 
	} 
	
	if(fclose(fp))
 	{
  		printf("Can not close the file!");
  		exit(0); 
 	}
  
	 return 0;
}

 
txt文本内容
    There is no better school than adversity. Every defeat, every heartbreak, every loss, contains its own seed, its own lesson on how to improve my performance next time. Never again will I contribute to my downfall by refusing to face the truth and learn from my past mistakes. Because I know: gems cannot shine without polish, and I can not perfect myself without hardship.

    Always will I seek the seed of triumph in every adversity.

    I am better prepared , now ,to deal with any adversity . No matter what fate has in store for me to know that I will relish it or I will suffer it for only a brief,brief time.So very few understand this obvious truth while the rest allow their hopes and goals to vanish as soon as tragedy strikes. These unfortunately people carry with them, until they die their own bed of thorms and look to others. every day, for sympathy and attention.Adversity will never destroy the person with courage and faith

    Always will I seek the seed of triumph in every adversity.

    Now I know that there are no times in life when opportunity, the chance to be and do gathers so richly about my soul when it has to suffer cruel adversity. Then everything depends on whether I raise my head or lower it in seeking help. Whenever I am struck down, in the future, by any terrible defeat, I will inquire of myself, after the first pain has passed, how I can turn that adversity into good. What a great opportunity that moment may present……to take the bitter root I am holding and transform it into fragrant garden of flowers.

    Always will I seek the seed of triumph in every adversity.
个人思考
(1)哈夫曼树编码算法思想:
首先将待加入的前n个字符的值和权重加入到待编码的Hc数组中,
然后将字符的值和权重拷贝到Ht数组中,构建哈夫曼树的结构,再求编码,
最后将编码拷贝到Hc数组对应字符中去 
(2)求哈夫曼树的结构思路:
首先从Ht第n+1个点出发(前n个点已经是待分配的叶子节点,后n-1个节点是空白的,所以从n+1开始),
然后在前n个点选择最小和次小的两个点,作为其孩子节点,该点作为其父亲节点 ,然后再从第n+2个点开始
以此类推 
(3)如何确定其是从最底层开始选择的最小点和次小点的?
是因为当我们把第n+1个点分配完后,该双亲点也加入到之后的节点选择中去作为叶子结点了,并且当我们从第n+2个点开始时候,第n+1个点也被放入到选择最小和次小的两个节点集合中了
(4)对于字符的译码 : 
算法思想是从该结点作为叶子结点向上出发,不断找寻其双亲结点,只要其双亲结点不为空, 我们判断该结点是其双亲结点的左孩子还是右孩子,左孩子判断为‘0’,右孩子判断为‘1’又因为我们是从叶子结点向上出发的,所以要倒着存放。
最后拷贝的时候,从最靠前的字符位置开始,拷贝到Hc的对应code的字符数组中去
(5)关于哈夫曼树总共有2n-1个点的个人想法: 
首先,完整的哈夫曼树是没有度为1的结点的,初始是n个点,又因为度为1的节点比度为2的节点多一个,所以,所有的节点数目就是2n-1个节点 
另外,如果从构建哈夫曼树的思路出发,就是每次少了2个点作为叶子结点,但又因为多出的双亲结点作为了叶子结点,这样每次都会再多出一个来,前n-1次都是类似,而到第n次时候,只有一个结点,也就不用再进行以上过程了,直接作为根节点,这样之前的n个点加上多出来的n-1个点,总共为2n-1个结点。  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值