huffman qi.cpp

来自「本程序不能编译除大小写字母之外的编码 本程序需事先建立字母权值文后件才可运行」· C++ 代码 · 共 277 行

CPP
277
字号
//预先在程序文件的目录下建立文件HFMT。DAT中放入如下文字(字母和权值)
//a64b13c22d32e103f21g15h47i57j1k5l32m20n57o63p15q1r48s51t80u23v8w18x1y16z1


//赫夫曼编码器
#include <stdio.h>
#include <stdlib.h>

#include <conio.h>
#define OK 	1
#define ERROR	0

typedef int Status;

typedef struct
{	char data;
	unsigned int weight;
	unsigned int parent,lchild,rchild;
}HTNode,*HuffmanTree;

Status Initialization(HuffmanTree *Tb,int n); 	//建立赫夫曼树
Status Encoding(HuffmanTree HT, int n);		//编码
Status Decoding(HuffmanTree HT, int n);		//解码
void Tree_Print(HuffmanTree HT,int n);		//打印赫夫曼树

void main()
{   HuffmanTree HT=NULL;
    FILE *fp_hfmt,*fp_tobetran,*fp_code,fp_textfile;
//文件hfmt中放各字母权值,tobetran放待译文, codefile中为赫夫曼码
    int n=1,d;
    char x,c;

    do{

	printf("       Main Menu\n");
	printf("------------------------------\n");
	printf("   Build Huffman Tree\n");	
	printf("   Read Huffman Tree\n");
	printf("   Encoding\n");
	printf("   Decoding\n");
	printf("   Scan & Encoding\n");
	printf("   Decoding & OutPut\n");
	printf("   Huffman Tree printing\n");
	printf("   Quit\n");
	printf("------------------------------");
	printf("\nYour Choice: ");

	x=getchar();
	switch(x)
	{  case 'q': case 'Q':
		break;
	   case 'b': case 'B':
		if((fp_hfmt=fopen("hfmt.dat","w"))==NULL)
		  { printf("file cannot be opened.\nPress any key to continue...");
		    getch();	exit(1);
		  }
		printf("enter data & weight: \nctrl+z to end \n?");
		scanf(" %c%d",&c,&d);

		while(!feof(stdin))
		 {
		   fprintf(fp_hfmt,"%c%d",c,d);
		   ++n;
		   printf("?");
		   scanf(" %c%d",&c,&d);
		 }
		 Initialization(&HT,n);
		 fclose(fp_hfmt);
		 break;
	   case 'r': case 'R':
		 if((fp_hfmt=fopen("hfmt.dat","r"))==NULL)
		  { printf("file cannot be opened.\nPress any key to continue...");
		    getch();	exit(1);
		  }
		 while(fscanf(fp_hfmt,"%c",&c)!=EOF)
		      if(!(c<='9'&c>='0'))  ++n;

		 Initialization(&HT,n);
		 fclose(fp_hfmt);
		 printf("read HuffmanTree finish !\nany key to continue...");
		 getch();
		 break;
	   case 'e': case 'E':
		 if(n == 0)
		   {  printf("no HuffmanTree found!\nany key to continue...");
		      getch();
		      break;
		   }
		 if(Encoding(HT, n))
		     printf("Encoding Finished!");
		 else   printf("Cannot Encoding!");
		 printf("\nPress any key to continue...");
		 getch();
		 break;
	   case 'd': case 'D':
		 if(n == 0)
		   {  printf("no HuffmanTree found!\nany key to continue...");
		      getch();
		      break;
		   }
		 if(Decoding(HT, n))
		    printf("Decoding Finished !");
		 else
		    printf("Cannot Decoding!");
		 printf("Press any key to continue...");
		 getch();
		 break;
	   case 's': case 'S':
		if((fp_tobetran=fopen("ToBeTran.dat","w"))==NULL)
			break;
		printf("enter( # for end) :");
		while((scanf("%c",&c),c)!='#')
		    fprintf(fp_tobetran,"%c",c);
		fclose(fp_tobetran);
		if(Encoding(HT, n))
		   {  printf("Encoding Finished!\nany key to continue...");
		      getch();
		      break;
		   }
	   case 'o': case 'O':
		 if(Decoding(HT, n))
		    {	fp_code=fopen("codefile.dat","r");
			while(!feof(fp_code)){
			  fscanf(fp_code, "%c",&c);
			  printf("%c",c);
			  }
			printf("\ndone.");
		    }
		  else{
		      printf("Cannot Decode.");
		  }
		  fclose(fp_code);
		  printf("\nany key to continue...");
		  getch();
		  break;
	   case 'h': case 'H':
		 if(n == 0)
		   {  printf("no HuffmanTree found!\nany key to continue...");
		      getch();
		      break;
		   }
		 Tree_Print(HT,2*n-1);
		 printf("\n HuffmanTree Printed!\nany key to continue...");
		 getch();
		 break;

	}//switch
    }while(x!='q');


}


Status Initialization(HuffmanTree *Tb,int n){
//Tb实际上是返回的赫夫曼数组的头指针
//n为赫夫曼树的叶子数
//从文件hfmT.dat建立赫夫曼树

	FILE *fp_hfmt;
	HuffmanTree HT,pt;
	int i=0,j,m,k,l,r,wei;
	char c;

	if((fp_hfmt=fopen("hfmt.dat","r"))==NULL)
		return ERROR;

	m=2*n-1;

	HT = (HuffmanTree)malloc((m+1)*sizeof(HTNode));
	for(i=1; !feof(fp_hfmt); ++i){	  //输入叶子结点
		fscanf(fp_hfmt,"%c%d",&c,&wei);
		HT[i].data = c;
		HT[i].weight = wei;
		HT[i].parent = HT[i].lchild = HT[i].rchild = 0;
	}
	for(; i<=m; i++){		//初始化父母兄弟
		HT[i].data = '*';
		HT[i].weight = 1000;
		HT[i].parent=HT[i].lchild=HT[i].rchild=0;
	}

	for(i=n+1; i<=m; i++){
		int m1,m2, l,r;
		m1=m2=1000;l=r=0;
		for(k=1; k<=m; k++)  //该循环实际是函数select 取最小的两个值
			if(HT[k].parent==0)
				if(HT[k].weight<m1)
				{  m2=m1;
				   r=l;
				   m1=HT[k].weight;
				   l=k;
				}
				else if(HT[k].weight<m2)
				{ m2=HT[k].weight;
				  r=k;
				}
		HT[l].parent = i;
		HT[r].parent = i;
		HT[i].weight = HT[l].weight + HT[r].weight;
		HT[i].lchild = l;
		HT[i].rchild = r;
	}//for

	fclose(fp_hfmt);
	*Tb=HT;		//返回huffmantree
	return OK;
}//Initialization


Status Encoding(HuffmanTree HT, int n){
//建立编码
	FILE *fp_tbt,*fp_code;
	char c0,*ch;
	int i,start,f,c;

	ch = (char *)malloc(n*sizeof(char));
	ch[n-1] = '\0';
	if((fp_tbt=fopen("tobetran.dat","r"))==NULL)   return ERROR;
	if((fp_code=fopen("codefile.dat","wb"))==NULL) return ERROR;

	while(fscanf(fp_tbt,"%c",&c0)!=EOF){
		start = n-1;
		for(c=1;  HT[c].data!=c0&&c<n+1; c++) ;//在树中寻找该字母

		if(c>n)  continue;		//没找到
		for(f = HT[c].parent; f!=0; c=f,f=HT[f].parent)
			if(HT[f].lchild==c)  ch[--start] = '0';
			else	ch[--start] = '1';
		for(i=start; i<n; i++)
			fprintf(fp_code,"%c",ch[i]);	//写入文件
	}
	fclose(fp_tbt);
	fclose(fp_code);
	return OK;
}//Encoding

Status Decoding(HuffmanTree HT, int n){
//解码,将解码后的数据放入文件textfile中       
	FILE *fp_code,*fp_txt;
	char c;
	int i;

	if((fp_code=fopen("codefile.dat","r"))==NULL) return ERROR;
	if((fp_txt= fopen("textfile.dat","w"))==NULL) return ERROR;

	i=2*n-1;//树根
	while(fscanf(fp_code,"%c",&c)!=EOF){
	 if(c=='1')  i=HT[i].rchild;
	 if(c=='0')  i=HT[i].lchild;
	 if(HT[i].lchild==0) //找到叶子
		{ fprintf(fp_txt,"%c",HT[i].data);//写入文件
		  i=2*n-1; //再从根开始
		}
	}
	fclose(fp_txt);
	fclose(fp_code);
	return OK;
}//Decoding

void Tree_Print(HuffmanTree HT,int n){
//递归算法打印赫夫曼树
	if(n){ 	printf("(%c,%d)",HT[n].data,HT[n].weight);
		if(HT[n].lchild||HT[n].rchild)
		{  printf("[");
		   Tree_Print(HT, HT[n].lchild);
		   if(HT[n].rchild) printf(",");
		   Tree_Print(HT,HT[n].rchild);
		   printf("]");
		}
	}
}//Tree_Print


//本程序不能编译除大小写字母之外的编码
//本程序需事先建立字母权值文后件才可运行
//本程序从文件中读入文字,编译后写入文件,所以屏幕上不会直接出现答案

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?