C语言-哈夫曼编码解码程序

(老代码修复)

C语言-哈夫曼编码解码程序
功能:

  1. 输入一串大写英文字符,统计字母频率并输出哈夫曼编码
  2. 输入一串哈夫曼编码,解码成大写英文字母输出并统计字母频率
  3. 先续遍历创建的哈夫编码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define maxsize 100  /* 编码函数中,被编译的字符串的最大长度 */
#define max 100  /* 最大字符的个数 */

typedef struct  /* 定义一个HUFFNODE结点 */
{
  char data;    /* 数据域 */
  int weight;   /* 权值域 */
  int parent;   /* 双亲域 */
  int left;     /* 左孩子域 */
  int right;    /* 右孩子域 */
}huffnode;

typedef struct									/* 定义一个HUFFCODE结点 */
{
   char cd[max];								/* 数组cd存放哈夫曼编码 */
   int start;
}huffcode;

huffnode *input()								/* 输入函数,(与huffnode *init()函数有相同的功能) */
{
  static huffnode ht[2*max];//VC++环境中要加关键字static
  int i,n;
  printf("enter elem num:");
  scanf("%d",&n);								/* 输入字符数 */
  ht[0].weight=n;
  //printf("n:%d",n);
  for(i=1;i<=n;i++)  {
    getchar();
    printf("%d elem data weight:",i);
    scanf("%c%d",&ht[i].data,&ht[i].weight);	/* 输入字符和权值 */
  }
  return ht;
}
huffnode *init()								/* 初始化带权结点 */
{
  static huffnode ht[2*max];
  ht[0].weight=27;								/* 字符个数 */
  ht[1].data=' '; ht[1].weight=186;
  ht[2].data='A'; ht[2].weight=64;
  ht[3].data='B'; ht[3].weight=23;
  ht[4].data='C'; ht[4].weight=22;
  ht[5].data='D'; ht[5].weight=32;
  ht[6].data='E'; ht[6].weight=103;
  ht[7].data='F'; ht[7].weight=21;
  ht[8].data='G'; ht[8].weight=15;
  ht[9].data='H'; ht[9].weight=47;
  ht[10].data='I'; ht[10].weight=57;
  ht[11].data='J'; ht[11].weight=1;
  ht[12].data='K'; ht[12].weight=5;
  ht[13].data='L'; ht[13].weight=32;
  ht[14].data='M'; ht[14].weight=20;
  ht[15].data='N'; ht[15].weight=20;
  ht[16].data='O'; ht[16].weight=56;
  ht[17].data='P'; ht[17].weight=19;
  ht[18].data='Q'; ht[18].weight=2;
  ht[19].data='R'; ht[19].weight=50;
  ht[20].data='S'; ht[20].weight=51;
  ht[21].data='T'; ht[21].weight=55;
  ht[22].data='U'; ht[22].weight=30;
  ht[23].data='V'; ht[23].weight=10;
  ht[24].data='W'; ht[24].weight=11;
  ht[25].data='X'; ht[25].weight=2;
  ht[26].data='Y'; ht[26].weight=21;
  ht[27].data='Z'; ht[27].weight=2;
  
  return ht;
}

void hfmtree(huffnode ht[])						/* 创建一棵哈夫曼树 */
{
	 /* m1为最小权值,x1为其在ht中的下标;m2为第二小权值,x2为其下标 */
  int i,k,x1,x2,n,m1,m2;		
 
  n=ht[0].weight;
  for(i=1;i<=2*n-1;i++)
     ht[i].parent=ht[i].left=ht[i].right=0;  /* 对ht的parent,left,right域进行初始化 */
  for(i=n+1;i<=2*n-1;i++){
     m1=m2=10000;  /* m1,m2初值无限大 */
     x1=x2=0;      /* x1, x2初值为0 */
     for(k=1;k<=i-1;k++)  /* k为可以进行比较的结点的下标 */
       if(ht[k].parent==0)     /* 当前结点的父结点不存在时 */
	 if(ht[k].weight<m1)   /* 当前结点的权值比最小权值还小时 */
	 {
	   m2=m1;
	   x2=x1;
	   m1=ht[k].weight;
	   x1=k;
	 }
       else if(ht[k].weight<m2)    /* 当前结点的权值比最小权值大但比第二最小权值小时 */
	    {
	      m2=ht[k].weight;
	      x2=k;
	    }
     ht[x1].parent=i;
     ht[x2].parent=i;
     ht[i].weight=ht[x1].weight+ht[x2].weight;
     ht[i].left=x1;
     ht[i].right=x2;
  }
}

huffcode *output(huffnode ht[])  /* 输出哈夫曼编码 */
{
  static huffcode hcd[max];
  huffcode d;
  int i,n,c,f,k,x;
  n=ht[0].weight;
  for(i=1;i<=n;i++)
  {
    d.start=n+1; /* d.start为栈顶 */
    c=i;   /* c存放当前结点 */
    f=ht[i].parent;   /* f存放当前结点的父结点 */
    while(f!=0)
    {
      if(ht[f].left==c)  /* 若当前结点在其父结点的左边时 */
	     d.cd[--d.start]='0';
      else
	     d.cd[--d.start]='1'; /* 当前结点在其父结点的右边时 */
         c=f;   /*  当前结点的父结点赋予c */
         f=ht[f].parent;  /* c的父结点赋予f */
    }
    hcd[i]=d;  /* 将当前结点的哈夫曼编码赋予hcd[i]数组 */
  }
  printf("output huffman code:\n");
  for(i=1;i<=n;i++)  /* 输出各个结点的哈夫曼编码 */
  {
	if(i==1) printf("\n");
	if(i==2) printf("\n");
    printf("\t   %c:",ht[i].data);
    x=hcd[i].start;
    for(k=x;k<=n;k++)  /* 通过栈输出哈夫曼编码 */
      printf("%c",hcd[i].cd[k]);
	int m=(k-x)%12;
	for(int l=0;l<12-m;l++)
		printf(" ");
	if(i%4==0)
		printf("\n");
  }
  return hcd;
}
void coding(huffcode hcd[],huffnode ht[]) /* 编码函数,给定一个字符串,输出其对应的哈夫曼编码 */
{
  int i,j,n,m,k,x;
  char in[maxsize],out[2*maxsize]; /* in存放需编译的字符串,out存放编译后的代码 */
  int count[26]={0};
  m=0; /* m为out数组的下标 */
  printf("enter a string:");
  getchar();
  gets(in);
  n=strlen(in);
  
  for(i=0;i<n;i++)
  {
	  if(in[i]>='A'&&in[i]<'Z'){
		  count[in[i]-'A']++;//字符的次数count[in[i]-'A']增1 
	  }
	  if(in[i]=='0') break;
  }

  for(i=0;i<n;i++)
  {
    for(j=1;j<=ht[0].weight;j++)  /* ht[0].weight存放的是带权结点的个数 */
      if(in[i]==ht[j].data)  /* 若输入字符和一个带权结点相同 */
	{
          x=hcd[j].start;
	  for(k=x;k<=ht[0].weight;k++)
	   out[m++]=hcd[j].cd[k];
	}
  }
  printf("the coding result is:\n");
  for(i=0;i<m;i++)
   printf("%c",out[i]);
  printf("\n");
  
  printf("出现的频率:\n");
  
  for(i=0;i<26;i++)
	{
		if(count[i]==0) continue;
		double p=count[i]*1.0*100/n;
		printf("count of %c is %.2lf%%",'A'+i,p);
		printf("\n");
	}
}

void decoding(huffcode hcd[],huffnode ht[]) /* 译码函数,输入一个代码流,输出其对应的字符 */
{
  int i,j,n,k,x,m,w;
  char in[maxsize*2],out[maxsize];  /* in数组存放代码流,out数组存放对应字母 */
  int count[26]={0};
  printf("enter code stream:\n");
  scanf("%s",in);
  n=strlen(in);
  i=0; m=0;   /* i为in数组的下标,m为out数组的下标 */
  while(i<n)
  {
    for(j=1;j<=ht[0].weight;j++)  /* ht[0].weight为带权结点的个数 */
      {
        x=hcd[j].start;
        for(k=x,w=i;k<=ht[0].weight;k++,w++)   /* k为hcd[j].cd[]的下标 */
          if(in[w]!=hcd[j].cd[k])
             break;
	if(k>ht[0].weight)
          {
             out[m++]=ht[j].data;
	     break;
          }
      }
    i=w;
  }
  for(i=0;i<m;i++)       /* 输出结果 */
    printf("%c",out[i]);
  printf("\n");
  for(i=0;i<n;i++)
  {
	  if(out[i]>='A'&&out[i]<'Z'){
		  count[out[i]-'A']++;//字符的次数count[in[i]-'A']增1 
	  }
	  if(out[i]=='0') break;
  }
printf("出现的频率:\n");
  
  for(i=0;i<26;i++)
	{
		if(count[i]==0) continue;
		double p=count[i]*1.0*100/m;
		printf("count of %c is %.2lf%%",'A'+i,p);
		printf("\n");
	}
}



void disp(huffnode ht[])  /* 先续遍历创建的哈夫编码 */
{
  int top,i,j,stack[maxsize];
  top=0;
  printf("the tree is:");
  for(i=1;i<=ht[0].weight*2-1;i++)  /* 寻找父结点为0的结点 */
    if(ht[i].parent==0)
      break;
  do
  {
    if(i!=0)  /* i为根结点 */
      {
	printf("%d ",ht[i].weight);
	stack[top++]=i;  /* 根结点进栈 */
	while(ht[i].left!=0)
	  {
	    i=ht[i].left; /* 子树的根结点赋予i */
	    printf("%d ",ht[i].weight);
	    stack[top++]=i;
	  }
      }
    j=stack[--top]; 
    i=ht[j].right;
  }while(top>=0||i!=0);
  printf("\n");
}
int main()
{
	int select;
	huffnode *ht;//其实是个为分配内存的动态数组
  huffcode *hcd;
  ht=init();
  hfmtree(ht);
  hcd=output(ht);
  do
  {
	printf("\n");
	printf("\n");
	printf("\n");
	printf("\t\t|--------------------------Menu-----------------------------|\n");
	printf("\t\t|\t\t 0. exit                                    |\n");
	printf("\t\t|\t\t 1. 输入字母(大写),编码,统计频率          |\n");
	printf("\t\t|\t\t 2. 输入编码,解码成大写字母输出            |\n");
	printf("\t\t|\t\t 3. disp                                    |\n");
	printf("\t\t|-----------------------------------------------------------|\n\n");
    printf("enter(0---3): ");
    scanf("%d",&select);
    if(select==0)
      {
	printf("THANK YOU USE THE SOFTWARE!\n");
	exit(1);
      }
    if(select==1) coding(hcd,ht);
    else if(select==2) decoding(hcd,ht);
    else disp(ht);
  }while(1);
  return 0;
}


TEST
主界面
主界面
解码
解码
编码
编码

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值