⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 huffmancode.cpp

📁 /*哈夫曼编/译码器 完成Huffman 编码的译码过程。 即输入一个码串
💻 CPP
字号:
  /*哈夫曼编/译码器
完成Huffman 编码的译码过程。
即输入一个码串,请翻译成相应的字符串。
要求有编码过程和解码过程。*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#define WordNUM 28//字符集中字符个数
#define MessageNUM 100000//最大信息量

typedef struct {
	int N;
	int SumWeight;
	char word[WordNUM+1];
	int weight[WordNUM+1]; 
}Word,*Wordset;//字符集及其权重.0号单元未用

typedef int Boolean;
typedef char* Message;//动态分配字符串数组存储信息

typedef struct {
	int n;//n序号
    char data;
	int weight;//权重值
	int parent,lchild,rchild;
}HTNode,*HuffmanTree;//动态分配数组存储哈夫曼树;

typedef struct{
    char data;
	char* Code;//动态分配字符串数组存储哈夫曼编码表
}HCode,*HuffmanCode;//动态分配字符串数组存储哈夫曼编码表

void printstar(){
	printf("************************************************************\n");
}//printstar

Boolean UserSaysYes(){//与用户对话函数
	int c,t;
	printf("(y,n)?");
	do{
		while((c=getchar())=='\n');//Ignore new line character.
        if(c=='y'||c=='Y'||c=='n'||c=='N')
		{	
			while((t=getchar())!='\n');//读去'\n'
			return(c=='y'||c=='Y');
		}
		printf("Please respond by typing one of the letters y or n\n");
	}while(1);
}

//字符集Wordset操作
void CreatWordset(Wordset w){//建立自定义字符集和权重
    int i;
	char word[WordNUM+1]={
		'#',' ','\n',
		'a','b','c','d','e','f','g',
		'h','i','j','k','l','m','n',
		'o','p','q','r','s','t',
		'u','v','w','x','y','z'};
	int weight[WordNUM+1]={
		0,186,4,
		60,13,22,32,103,21,15,
		47,57,1,5,32,20,57,
		63,15,1,48,51,80,
		23,8,18,1,16,1};
	w->N =WordNUM;//记录字符个数
	w->SumWeight=0;//记录总的权重值
	for(i=1;i<=w->N;i++)
	{
		w->word [i]=word[i];
		w->weight [i]=weight[i];
		w->SumWeight+=weight[i];
	}
}		

void SaveWordsetFile(Wordset w){//保存到文件
	FILE*fp;
	if(!(fp=fopen("wordset","wb")))puts("cann't open file.");
	if(fwrite(w,sizeof(Word),1,fp)!=1)puts("SaveWordsetFile write error!");
	fclose(fp);	
}

void OpenWordsetFile(Wordset w){//读文件
	FILE*fp;
	w=(Wordset)malloc(sizeof(Word));//字符集及其权重所占空间分配
	if(!(fp=fopen("wordset","rb")))puts("cann't open file.");
	fread(w,sizeof(Word),1,fp);
}

void OutputWordset(Wordset w){//输出
	int i;
    for(i=1;i<=w->N;i++){
		printf("%c %d\t",w->word [i],w->weight [i]);
	}
	printf("SumWeight=%d\n",w->SumWeight);

}


//Huffman操作
void Select(HuffmanTree HT,int t,int*s1,int*s2){//在HT[1...i-1]选择parent为0且weight最小的两个结点,其序号为s1,s2.
	int i;
	HuffmanTree p;
	int weight=99999 ;
	*s1=*s2=0;
	for(i=1,p=HT+1;i<=t;++i,++p)
	{
		if(p->parent==0 )
			if(weight>p->weight)
			{
				*s1=i;
				weight=p->weight ;
			}
	}
	weight=99999 ;
	for(i=1,p=HT+1;i<=t;++i,++p)
	{
		if(p->parent==0 && i!=*s1)
			if(weight>p->weight)
			{
				*s2=i;
                weight=p->weight ;
			}
	}
}

void CreatHuffmanTree(HuffmanTree HT,Wordset w){//建立HuffmanTree
	//w存放n个字符的权值(均>0),构造哈夫曼树HT,并求出n个字符的哈夫曼编码HC。
	int i,n,m,s1,s2;
	HuffmanTree p;
    if(w->N<=1)return;
	n=w->N;
	m=2*n-1;//一棵有n个叶子结点的赫夫曼树共有2n-1个结点
	for(p=HT,i=0;i<=n;++i,++p)//HuffmanTree initing
	{
		p->n =i;
		p->data =w->word [i];
		p->weight =w->weight [i];
		p->lchild =0; p->parent =0; p->rchild =0;
	}
	for(;i<=m;++i,++p){
		p->n =i;p->lchild =0;p->data ='#';p->parent =0;p->rchild =0;p->weight =0;
	}
	printf("初始Huffman树:\n");
	for(p=&HT[1],i=1;i<=n;++i,++p)
	{
		printf("%d %c %d %d %d %d\t",p->n,p->data,p->weight,p->lchild,p->parent,p->rchild);
	}
	printf("\nCreat HTTree:\n");
	for(i=n+1;i<=m;++i){//建哈夫曼树
		//在HT[1...i-1]选择parent为0且weight最小的两个结点,其序号为s1,s2.
		Select(HT,i-1,&s1,&s2);
		HT[s1].parent=i;HT[s2].parent=i;
		HT[i].lchild=s1;HT[i].rchild=s2;
		HT[i].weight=HT[s1].weight+HT[s2].weight;
		printf("%d %d %d %d %d\t",HT[i].n,HT[i].weight,HT[i].lchild,HT[i].parent,HT[i].rchild);
	}
	printf("\n");
}

void CreatHuffmanCode(HuffmanTree HT,HuffmanCode HC,Wordset w){//建立HuffmanCode
	//---从叶子结点到根逆向求每个字符的哈夫曼编码---
	char* cd;
	int i,n,start,c,f;
	n=w->N ;
    for(i=1;i<=n;i++)HC[i].data=w->word[i];  
	cd=(char*)malloc(n*sizeof(char));//分配求编码的工作空间
	cd[n-1]='\0';//编码结束符
	for(i=1;i<=n;++i){//逐个字符球哈夫曼编码
		start=n-1;//编码结束符位置
		for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent){//从叶子结点到根逆向求编码
			if(HT[f].lchild==c) cd[--start]='0';//左0右1
			else cd[--start]='1';
		}
		HC[i].Code=(char*)malloc((n-start)*sizeof(char));//为第i个字符编码分配空间
		strcpy(HC[i].Code,&cd[start]);
	}
	free(cd);
	for(i=1;i<=n;i++)
		printf("%c %s\n",HC[i].data,HC[i].Code);
    printf("\n");
}//HuffmanCoding

void SaveHuffmanFile(HuffmanTree HT,HuffmanCode HC,int m,int n){//保存HuffmanTree和HuffmanCode
	FILE*fp1,*fp2;
	int i;

	//写出到文件
	if((fp1=fopen("HT","wb"))==NULL)
	{puts("can't open file \"HT.dat\" .");exit(0); }
	if((fp2=fopen("HC","wb"))==NULL)
	{puts("can't open file \"HC.dat\" .");exit(0); }
	for(i=0;i<=m;i++)
	    if(fwrite(&HT[i],sizeof(HTNode),1,fp1)!=1)puts("write error!\n");
	for(i=0;i<=n;i++)
	    if(fwrite(&HC[i],sizeof(HC[i]),1,fp2)!=1)puts("write error!\n");
	fclose(fp1);fclose(fp2);

}

void OpenHuffmanFile(HuffmanTree HT,HuffmanCode HC){	//从文件读入
	FILE*fp1,*fp2;

   	HT=(HuffmanTree)malloc((WordNUM+1)*sizeof(HTNode));//0号单元未用
	HC=(HuffmanCode)malloc((WordNUM+1)*sizeof(char*));//分配n个字符编码的头指针向量
	if((fp1=fopen("HT","rb"))==NULL)
	{puts("can't open file \"HT.dat\" .");exit(0); }
	if((fp2=fopen("HC","rb"))==NULL)
	{puts("can't open file \"HC.dat\" .");exit(0); }
	fread(&HT,sizeof(HT),1,fp1);
	fread(&HC,sizeof(HC),1,fp2);
	fclose(fp1);fclose(fp2);
}

 void OutputHuffmanTree(HuffmanTree HT,int n,int m){//输出HuffmanTree
	int i;
	puts("Huffman Tree:");
	printf("%d leaves %d HTNode :\n",n,m);
	puts("非叶节点的data域不是有效字符,不予输出!");
	for(i=1;i<=m;i++)//非叶节点的data域不是有效字符,不予输出
	{
		if(i<=n)printf("%d %c %d %d %d %d\t",HT[i].n,HT[i].data,HT[i].weight,HT[i].lchild,HT[i].parent,HT[i].rchild);
		else printf("%d %d %d %d %d\t",HT[i].n,HT[i].weight,HT[i].lchild,HT[i].parent,HT[i].rchild);
	}
	printf("\n");
}

void OutputHuffmanCode(HuffmanCode HC,int n){//输出HuffmanCode
	int i;
	puts("Huffman Code:");
	for(i=1;i<=n;i++)
		printf("%c %s\n",HC[i].data,HC[i].Code);
    printf("\n");
}

 void MessageInput(Message M){//信息输入
   char  s[1000]={'\0'};//输入缓冲
   M[0]='\0';
   while(strlen(gets(s))>0)//提供多行信息输入
   {
	   strcat(M,s);
	   strcat(M,"\n");
   }
}

void SaveMessageFile(Message M){//信息保存
   FILE  *fp;
   if((fp=fopen("Message.txt","w"))==NULL)
   {   printf("cann't open file");exit(0); }
   fputs(M,fp);
   fclose(fp);
}

void MessageFileOutput(Message M){//打开信息文件并输出
   FILE*fp;
   char s[1000];
   M[0]='\0';
   puts("The message in the Message File is :");
   if((fp=fopen("Message.txt","r"))==NULL){printf("cann't open file");exit(0); }
   while(fgets(s,1000,fp)!=NULL){
      fputs(s,stdout);
	  strcat(M,s);
   }
   fclose(fp);
   printstar();
   puts("MessageSource we code is:");
   puts(M);
}

void MessageCoding(Message M,Message MD,HuffmanCode HC,int n){//信息编码函数
    int i,k; 
	MD[0]='\0';
	for(i=0;M[i]!='\0';i++)
		for(k=1;k<=n;k++)
			if(M[i]==HC[k].data)strcat(MD,HC[k].Code);
}

void SaveMessageCode(Message MD){//信息编码保存到文件
   FILE  *fp;
   if((fp=fopen("MessageCode.txt","w"))==NULL)
   {   printf("cann't open file");exit(0); }
   fputs(MD,fp);
   fclose(fp);
}

void OutputMessageCode(Message MD){//信息编码输出
   puts("MessageCode is:");
   puts(MD);
   printstar();
   strcat(MD,"#");//作为结束标志
}

 void MessageDecoding(Message MD,HuffmanTree HT){//信息解码函数
   int i,root,r;
   for(i=1;HT[i].parent!=0;i++);//找根
   r=root=i;
   for(i=0;MD[i]!='#';){
	   while(HT[r].lchild&&HT[r].rchild){//0左走1右走,直到叶节点
		   if(MD[i]=='1')r=HT[r].rchild;
		   else r=HT[r].lchild;
		   i++;
	   }
	   putchar(HT[r].data);//输出叶节点
	   r=root;
   }
   putchar('\n');
}

void welcome(){
	puts("-----------------HuffmanCoding---------------");
	puts("\t\t\t\tJS000603-060059-李建平");
}

 void main(){//主函数,安排流程。
	HuffmanTree HT;
	HuffmanCode HC;
	Wordset w;
	Message M,MD;
	int n=WordNUM,m,i; 
	m=2*n-1;//一棵有n个叶子结点的赫夫曼树共有2n-1个结点
	printstar();
	welcome();
	printstar();
    
	//初始化
	for(i=0;i<5E8;i++);
	printstar();
	puts("初始化....");
	printstar();
	HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//0号单元未用
	HC=(HuffmanCode)malloc((n+1)*sizeof(HCode));//分配n个字符编码的头指针向量
	w=(Wordset)malloc(sizeof(Word));//字符集及其权重所占空间分配
    MD=(Message)malloc(MessageNUM*sizeof(char));
	M=(Message)malloc(MessageNUM*sizeof(char));
	for(i=0;i<5E8;i++);
	puts("Init OK!");
	printstar();

	//字符集操作与保存
	puts("创建字符集和权重....");
	printstar();
	for(i=0;i<5E8;i++);
	CreatWordset(w);//创建字符集和权重
    puts("CreatWordset ok!");
	printstar();
	for(i=0;i<5E8;i++);
	puts("Saving to file....");
	printstar();
	for(i=0;i<5E8;i++);
	SaveWordsetFile(w);//保存到文件
	puts("save OK!");
	printstar();
	puts("reading from the wordset file...");
	printstar();
	for(i=0;i<5E8;i++);
	OpenWordsetFile(w);//读文件
	puts("The wordset and each word's weight are:");
	printstar();
 	OutputWordset(w);//输出
	printstar();

    //HuffmanTree和HuffmanCode的建立与保存
	puts("建立HuffmanTree....");
	printstar();
	for(i=0;i<5E8;i++);
    CreatHuffmanTree(HT, w);//建立HuffmanTree
	printstar();
	puts("建立HuffmanCode....");
	printstar();
	for(i=0;i<5E8;i++);
	CreatHuffmanCode(HT,HC,w);//建立HuffmanCode
	printstar();
	puts("写入文件前输出HuffmanTree和HuffmanCode....");//写入文件前输出
	printstar();
	for(i=0;i<5E8;i++);
	OutputHuffmanTree(HT,n,m);//输出HuffmanTree
	printstar();
	for(i=0;i<5E8;i++);
    OutputHuffmanCode(HC,n);//输出HuffmanCode
	printstar();
	puts("Saving to file....");
    printstar();
	for(i=0;i<5E8;i++);
	SaveHuffmanFile(HT,HC,n,m);//保存HuffmanTree和HuffmanCode到文件
	puts("save OK!");
	printstar();
    puts("从文件读入后输出HuffmanTree和HuffmanCode....");//读入文件后输出
	printstar();
	for(i=0;i<5E8;i++);
	OpenHuffmanFile(HT,HC);//打开HuffmanTree和HuffmanCode文件
	OutputHuffmanTree(HT,n,m);//输出HuffmanTree
	printstar();
	for(i=0;i<5E8;i++);
    OutputHuffmanCode(HC,n);//输出HuffmanCode
	printstar();
    
	do{//信息输入及其编码与解码
		puts("please input the message you want to code....");
		printstar();
		MessageInput(M);//信息输入
		printstar();
		puts("saving to file....");//保存信息至文件
		printstar();
	    for(i=0;i<5E8;i++);
        SaveMessageFile(M);
        puts("MessageSave OK!");
	    printstar();
		puts("信息从文件读出并输出....");
		printstar();
	    for(i=0;i<5E8;i++);
	    MessageFileOutput(M);//信息从文件读出并输出
	    printstar();
		puts("信息编码....");
	    for(i=0;i<5E8;i++);
	    MessageCoding(M,MD,HC,n);//信息编码
	    printstar();
		puts("saving to file....");
		printstar();
	    for(i=0;i<5E8;i++);
        SaveMessageCode(MD);
		puts("save OK!");
		printstar();
		puts("编码输出");
		printstar();
	    OutputMessageCode(MD);//编码输出
	    printstar();
		puts("信息解码....");
		for(i=0;i<5E8;i++);
	    printf("The message after decoding is:\n");
		MessageDecoding(MD,HT);//解码输出
	    printstar();
		puts("源码输出对比....");
	    for(i=0;i<5E8;i++);
        puts("The MessageSource is:");
        puts(M);//源码输出对比
		printstar();
		printf("Try again?");
	}while(UserSaysYes());//提供重复进行信息输入
}//main

⌨️ 快捷键说明

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