数据结构作业--哈夫曼树

题目:哈夫曼编码

背景:

哈夫曼编码是一种被广泛应用而且非常有效的数据压缩编码,它是可变长度编码。可变长编码即可以对待处理字符串中不同字符使用不等长的二进制位表示,可变长编码比固定长度编码好很多,可以对频率高的字符赋予短编码,而对频率较低的字符则赋予较长一些的编码,从而可以使平均编码长度减短,起到压缩数据的效果。

       哈夫曼编码是前缀编码。如果没有一个编码是另一个编码的前缀,则称这样的编码为前缀编码。对前缀编码的解码也是相对简单的,因为没有一个码是另一个编码的前缀,所以可以识别出第一个编码,将它翻译为原码,再对余下的编码文件重复同样操作。

        哈夫曼编码首先要构造一棵哈夫曼树,首先,将每个出现的字符当做一个独立的结点,其权值作为它出现的频度(或次数),然后构造哈夫曼树。显然所有字符节点均出现在叶子结点中。我们可以将字符的编码解释为从根至该字符路径上标记的序列,其中标记为0表示"转向左孩子",标记为1表示为"转向右孩子"。

#include<stdio.h>
#include<malloc.h>
#include<iostream>
#include<stdlib.h>
#include<string.h>
#define max 10
#define max2 1000
using namespace std;

typedef struct{       //哈夫曼树 
	int weight;  //存放权重 
	int parent,lchild,rchild;
	char code[max];  //哈夫曼编码 
	char ch;  //字母 
}huff;
char encode[15];char dcode[max];
void inithuff(huff *H,int *w,char *z,int n){
	int i;
	for(i=0;i<n*2-1;i++){
		H[i].ch=z[i];
		H[i].weight=w[i];
		H[i].parent=-1;
		H[i].lchild=-1;
		H[i].rchild=-1;
	}
} 
void gethuff(huff *H,int n){
	int x1,x2;
	int m1,m2;
	int i,j;
	for(i=n;i<2*n-1;i++){
		x1=x2=0;
		m1=m2=max2;
		for(j=0;j<i;j++){
			if(H[j].parent==-1&&H[j].weight<m1){
				m2=m1;
				x2=x1;
				m1=H[j].weight;
				x1=j;
			}
			else if(H[j].parent==-1&&H[j].weight<m2){
				m2=H[j].weight;
				x2=j;
			}
		}
		H[x1].parent=i;
		H[x2].parent=i;
		H[i].lchild=x1;
		H[i].rchild=x2;
		H[i].weight=m1+m2;
	}
	
}
void bmhuff(huff *H,int n){
	FILE *fp1;
	char t[max];
	int i,j,k,p,parent;
	int g=0;
	int len;     //记录编码长度 
	for(i=0;i<n;i++){
		len=0; 
		parent=H[i].parent;  //储存双亲结点下表
		p=i;     //用p来更新孩子的下标 
		while(parent!=-1){        //没到根节点 
			if(H[parent].lchild==p){    //左孩子 
				t[len]='0';len++;
			}
			else if(H[parent].rchild==p){
				t[len]='1';len++;
			}
			p=parent;        //更新孩子以及双亲下表 
			parent=H[parent].parent;
		} 
		
		for(j=0,k=len-1;j<len;j++,k--)      //将反向的编码调正 
			H[i].code[j]=t[k];
		H[i].code[j]='\0';   //结束符
		for(j=0;j<len;j++){
			encode[g]=H[i].code[j];
			g++;
		}
		
	}
    encode[g]='\0';
    fp1=fopen("code1.txt","w");
    fprintf(fp1,"%s",encode);
    fclose(fp1);
    
}
void ymhuff(huff *H,char *code,int n){    //译码 
	int i,j=0;
	int k=0;
    FILE *fp2;
	i=2*n-2;
	while (code[j] != '\0')
	{
		if (code[j] == '0')           //如果为'0',则指向其左孩子
			i = H[i].lchild;
		else if (code[j] == '1')      //如果为'1',则指向其左孩子
			i = H[i].rchild;
		if (H[i].lchild == -1)       //直到叶子节点
		{                  
			dcode[k]=H[i].ch;
			k++;
			i = 2*n-2;
		}
		j++;          //再读下一个字符
	}
	fp2=fopen("code2.txt","w");
	fprintf(fp2,"%s",dcode);
	fclose(fp2);
}
void print(huff *H,int n){
	int i,t;
	for(i=0;i<n*2-1;i++){
		
		printf("%d  %d  %d  %d",i,H[i].lchild,H[i].rchild,H[i].parent);
		
		printf("\n");
	}
}
int main(){
	int i,n,a;      //n为叶子个数
	char *z,Z;      //存放字母
	int  w[max],W;  //存放权重
	huff H[max];
	printf("请输入叶子个数:");
	scanf("%d",&n);
	printf("菜单:输入1编码,2译码, 3展示,4退出:\n");
	for(int j=0;;j++){
	printf("请输入:");
	scanf("%d",&a);
	if(a==1){
	z=(char*)malloc(n*sizeof(char));
	for(i=0;i<n;i++)
    {
        printf("请输入第%d个字符:",i+1);
        cin>>z[i];
        printf("请输入第%d个字符的权:",i+1);
        cin>>w[i];
    }
	inithuff(H,w,z,n);
	gethuff(H,n);
	bmhuff(H,n);
	for(i=0;i<n;i++){
		printf("%c:%s ",H[i].ch,H[i].code);
	}
	printf("\n");
	printf("完整编码为:%s\n",encode);
	
    }
    else if(a==2){
    	ymhuff(H,encode,n);
    	printf("译码后:%s\n",dcode);
	    printf("\n");
	}
	else if(a==3){
        printf("i lc rc p\n");
		print(H,n);
	}
	else{
		exit(0);
	  }
	}
	return 0;
}

运行结果及分析:

1编码,输入叶子节点对应的字母和权值,进行编码

2译码,将编码翻译成字母。

3对树进行展示

本文介绍了数据结构作业---哈夫曼树,欢迎大家评论关注。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

微雨盈萍cbb

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值