数据结构:哈夫曼树,哈夫曼编码与译码系统

1).结构体类型 HaffmanfT:

typedefstruct{

      int weight;

      char ch;

      char chh[20];

      int lchild;

      int rchild;

      int parent;

 

}HaffmanT;/*结点结构体*/

2). (字母部分用的结构体)结构体类型 HaffmanfN

typedefstruct

{

      char ch;

      char bits[MB + 1];

      int start;//标志编码起始位

}HaffmanN;/*保存编码*/

3 ).单词部分的储存编码和权值用了三个数组(全局变量):

charstr2[MB][20];//单词字串

charstr3[MB][20];//输入串

intstrC[MB];//单词字串计数数组.对应每个单词串,拥有一个计算器

4).   (全局变量)charmi[MAXPLUS];//存放的是字符串编码

charcha[MAXPLUS];//存放的是句子

2.

实验所用到的全部函数有:

1).voidstrCount();//统计字母并计算每个字母出现的次数即权值

2).intwordCount();//统计单词并计算每个单词出现的次数即权值,返回出现的不同单词个数

3).void init(intn);//初始化

4).voidgetHaff(int n,int p);//把字母(单词)及权值保存到结构体中,n决定单词还是字母,p决定了结构体数组的大小

5).int creat2(int n);//创建哈夫曼树

6).voidCharSetHuffmanEncoding(int n,int wh);//给每一个结点编码,n代表结点个数

7).void bianma(intwh,int p);//给从文件中读到的文章整体编码,即压缩

8).void wriIn();//将对文件的编码写入新的TXT文档

9).void yima(intn,int wh);  //将哈夫曼编码解码为原文档        

10).int main();//综合调用并计算压缩率


详细代码如下:

//#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "io.h"

#define MB 300//最大编码的值
#define MAXPLUS 100000
typedef struct{
	int weight;
	char ch;
	char chh[20];
	int lchild;
	int rchild;
	int parent;

}HaffmanT;/*结点结构体*/
HaffmanT T[MB];
HaffmanT TW[MB];
typedef struct
{
	char ch;
	char bits[MB + 1];
	int start;//标志编码起始位
}HaffmanN;
HaffmanN N[MB];

char str2[MB][20];//单词字串结果存放数组
char str3[MB][20];//输入串或者用char *str2也可,这样可以
int strC[MB];//单词字串计数数组.对应每个单词串,拥有一个计算器
char mi[MAXPLUS];//存放的是字符串编码
char cha[MAXPLUS];//存放的是句子

void strCount();//统计字母并计算每个字母出现的次数即权值
int wordCount();//统计单词并计算每个单词出现的次数即权值,返回出现的不同单词个数
void init(int n);//初始化
void getHaff(int n,int p);//把字母(单词)及权值保存到结构体中,n决定单词还是字母,p决定了结构体数组的大小
int creat2(int n);//创建哈夫曼树
void CharSetHuffmanEncoding(int n,int wh);//给每一个结点编码,n代表结点个数
void bianma(int wh,int p);//给从文件中读到的文章整体编码,即压缩
void wriIn();//将对文件的编码写入新的TXT文档
void yima(int n,int wh);  //将哈夫曼编码解码为原文档   
int main()
{
    int t,k,cho;
    strCount();
	k=wordCount();
        int n = 29;
	printf("请选择编码:0,单词,1字母\n");
	scanf("%d",&cho);
	if(cho==0)
    {
        printf("你输入了”0“,将给出单词的频率及相应的哈夫曼编码\n");
        getHaff(cho,k);
        creat2(k);
        CharSetHuffmanEncoding(k-1,cho);//k-1
    printf("是否压缩:1:是,0:否:\n");
        scanf("%d",&cho);
        if(cho==0)
            return 0;
            if(cho==1)
        {

            printf("接下来是压缩环节\n");
            bianma(cho,k);
            wriIn();

        }
     printf("是否解压缩:1:是,0:否:\n");
        scanf("%d",&cho);
        if(cho==0)
        return 0;
        if(cho==1)
    {
        yima(k,cho);
    }
        printf("\n");
        printf("计算压缩率:\n");
        double ee=(double)strlen(mi)/(strlen(cha)*8);
        ee=1-ee;
            printf("压缩率为%.2f",ee*100);
            printf("%%");

    }
    if(cho==1)
      {
        printf("你输入了”1“,将给出字符的频率及相应的哈夫曼编码\n");
        getHaff(cho,n);
        creat2(n);
        CharSetHuffmanEncoding(n,cho);
            printf("是否压缩:1:是,0:否:\n");
        scanf("%d",&cho);
        if(cho==0)
            return 0;
        if(cho==1)
        {

            printf("接下来是压缩环节\n");
            bianma(cho,n);
            wriIn();

        }
     printf("是否解压缩:1:是,0:否:\n");
    scanf("%d",&cho);
    if(cho==0)
        return 0;
    if(cho==1)
    {
        yima(n,cho);
    }
    printf("\n");
    printf("计算压缩率:\n");
        double ee=(double)strlen(mi)/(strlen(cha)*8);
        ee=1-ee;
        printf("压缩率为%.2f",ee*100);
        printf("%%");
    }



}


//先是统计字符的功能
void strCount(){

    FILE * fp;
    char str1;
    if((fp=fopen("F:\\untitled\\DataStructure\\实验\\实验二\\aaa.txt","r"))==NULL)
    {
        printf("file cannot be opened\n");
        exit(1);
    }
    int x;//数组下标
    for(x=0;x<29;x++)
    {
        TW[x].ch='a'+x;
        TW[x].weight=0;
       // printf("%c",N[x].ch);
    }
    TW[26].ch=' ';
    TW[27].ch=',';
    TW[28].ch='.';
    x=0;

    while((str1=fgetc(fp))!=EOF)
    {
       //cha[x]+=str1;

        if(isalpha(str1))
        {
            str1=tolower(str1);
            ++TW[str1-'a'].weight;//直接用数组的ascii做下标
        }
        else
        if((int)str1==32)
            ++TW[26].weight;//这个是空格
        else if((int)str1==44)
            ++TW[27].weight;
        else if((int)str1==46)
            ++TW[28].weight;

            cha[x]=str1;
            x++;
   }
    //fgets(cha,10000,fp);
    printf("我的句子是:%s\n",&cha);


   fclose(fp);
}

//统计单词
int wordCount()
{

    int i=0,j=0,k=0,x,y=0;

     while(j<strlen(cha)+1)

    {
        for(;cha[j]==32||cha[j]==44||cha[j]==46;j++);

        while(k<20&&cha[j]!=32&&cha[j]!=44&cha[j]!=46)
        str2[i][k++]=cha[j++];
        str3[y][k++]=cha[j++];
        str2[i][k]='\0';
        strC[i]=1;
       // strcpy(str3[j],str2[j]);
        y++;
        for(x=0;x<i;x++)
            if(strncmp(str2[i],str2[x],20)==0)
            {
                strC[x]++;

                i--;
                break;
            }
            i++;
            k=0;
//printf("i是%d,值是%s\n",i,str2[i]);
    }
    str2[i+1][0]=' ';
    str2[i+2][0]=',';
    str2[i+3][0]='.';


    return i;
}
//创建树之前赶紧把权值给搞好
void getHaff(int n,int p)//n是操作符,p是数组大小
{
    int i=n;
    int k=p;
    int c=0;
    if(i==1)
        {
            for(;c<p;c++){
                T[c].weight=TW[c].weight;
                T[c].ch=TW[c].ch;}
        }

    if(i==0)
    {
        for(c=0;c<p-1;c++)
            T[c].weight=strC[c];
          //  strcpy(T[c].chh,str2[c]);
           // printf("%s,不输出啊吗",T[c].chh);
    }
}


//接下来构造一棵哈夫曼树
void init(int n)
{

	int i;
	for (i = 0; i<2 * n - 1; i++)
	{
		//T[i].weight = 0;//权值
		T[i].parent = -1;
		T[i].lchild = -1;
		T[i].rchild = -1;
	}

}

int creat2(int n)
{
	int i, j, p1, p2, w1, w2;//p1,p2分别是最小权值的位置,w1,w2代表最小权值
	//初始化结点
	int num = n;
	init(n);
	//循环构造哈夫曼树
	for (i = 0; i<num - 1; i++)
	{
		w1 = w2 = 10000;
		p1 = p2 = 0;
		for (j = 0; j<num + i; j++)//循环条件
		{
			if (T[j].weight<w1&&T[j].parent == -1)
			{
				w2 = w1;
				p2 = p1;
				w1 = T[j].weight;
				p1 = j;

			}
			else if (T[j].weight<w2&&T[j].parent == -1)
			{
				w2 = T[j].weight;
				p2 = j;
			}
		}//找到了p1,p2两个最小的位置
		//printf("%d %d我要看看p的值!\n",p1,p2);
		T[p1].parent = T[p2].parent = num + i;    //找到当前最小的两个节点 确定父节点
		T[num + i].lchild = p1;                   //设置父节点的左右子树和权值
		T[num + i].rchild = p2;
		T[num + i].weight = T[p1].weight + T[p2].weight;//特别注意一下是num+i
	}

	return i;
}


void CharSetHuffmanEncoding(int n,int wh)//n表示多少个节点
{
	//根据树求编码表
	//int n=init();
	int c, p, i, j;
	HaffmanN cd;//临时变量来存放求解编码时的信息
	for (i = 0; i < n; i++)
	{
		cd.start = n - 1;
		c = i;

		while ((p = T[c].parent) != -1)   /* 父结点存在 */
		{
			cd.bits[cd.start] = (T[p].lchild == c) ? '0' : '1';
			cd.start--;        /* 求编码的低一位 */
			c = p;
		} /* end while */
		/* 保存求出的每个叶结点的哈夫曼编码和编码的起始位 */
		for (j = cd.start + 1; j<n; j++)
			N[i].bits[j] = cd.bits[j];
		N[i].start = cd.start;
	} /* end for */

	/* 输出已保存好的所有存在编码的哈夫曼编码 */
	int n1; char temp;
	for (i = 0; i<n; i++)
	{
		if(wh==1){
		N[i].ch = T[i].ch;
		printf("%c 出现的次数是%d,它的编码是: ", T[i].ch,T[i].weight);}
		//for (n=0)
		if(wh==0)
          printf("第%d项,%s 出现的次数是%d,它的编码是: ", i,str2[i],T[i].weight);
		for (j = N[i].start + 1,n1=0; j < n; j++,n1++)
		{
			temp = N[i].bits[j];
			N[i].bits[n1] = temp;
		//	printf("%c对比", N[i].bits[j]);
			printf("%c", N[i].bits[n1]);
		}
		//printf(" start:%d", N[i].start);

		printf("\n");

	}

}
//接下来是给字符串编码
void bianma(int wh,int p)
{
    int n1=strlen(cha);
    int n2=strlen(str3);
    int i,j;
    if(wh==1)
    {



    for(i=0;i<=n1;i++)
    {

        for(j=0;j<29;j++)
        {

            if(cha[i]==N[j].ch)
            {
                //mi[i].bits=gets(N[j].bits);
                printf("%s",N[j].bits);
                strcat (mi,N[j].bits);
                break;
            }
        }
    }
    }else if(wh==0)
    {
        for(i=0;i<=n2;i++)
    {

        for(j=0;j<p;j++)
        {

            if(strncmp(str3[i],T[j].chh,20)==0)
            {
                //mi[i].bits=gets(N[j].bits);
                printf("%s",N[j].bits);
                strcat (mi,N[j].bits);
                break;
            }
        }
    }
    }
    printf("\n");



}
//然后把字符串的码写到文件中
void wriIn()
{
    FILE *pFile = fopen("F:\\untitled\\DataStructure\\实验\\实验二\\aab.txt", //打开文件的名称
                    "w"); // 文件打开方式 如果原来有内容也会销毁
//向文件写数据
    fwrite (mi, //要输入的文字
         1,//文字每一项的大小
       strlen(mi),//单元个数 
         pFile //我们刚刚获得到的地址
         );
        // printf("测试下mi的值%c:\n",mi[0]);

fflush(pFile);
}

//译码的实现
void yima(int n,int wh) {

	int m = 2*n - 2;//原来是这里!!!!!!!!!!
	int temp = m;
	int i = 0;
	printf("译码:\n");
	/*char str[MAXPLUS];
	gets(str);*/

	//printf("weisheme ");
	//char str[3]={'0','1'};
	//for ()
	while (mi[i] != '\0') {
		//挨个读入电文
		//printf("看一下有没有出粗哦%c第几位%d\n", str[i], i);
		if (mi[i] == '0')
			//如果是0进入左子树   如果是1进入右子树
		{
		//	printf("is0do");
			temp = T[temp].lchild;
			//printf("现在我的值是:%c\n", T[temp].ch);
		}
		else if (mi[i] == '1')
			temp = T[temp].rchild;
		if (T[temp].lchild == -1 && T[temp].rchild == -1) {
                            if(wh==1)//如果该节点左右均为空 即到达字母结点 输出
			printf("%c", T[temp].ch);
                else if(wh==0)
                    printf("%s", T[temp].chh);
			temp = m;                                               //重新回到根节点 进行下一字符的译码
		}
		i++;
	}

getchar();
}



  • 9
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值