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

📄 huffman.c

📁 哈夫曼编码——构建哈夫曼树并对其进行编码
💻 C
字号:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXNODE 20                  //需要编码的字符的最大个数
#define MAXWEIGHT 200               //权值最大值            
#define MAXCHARS 200                //所给文章的最大字符数
#define MAX     1000                //01序列的最大字符数


//------------哈夫曼树和哈夫曼编码的存储表示---------------
typedef struct{
    char data;
	int weight;
	int parent,lchild,rchild;
}HTnode,*HuffmanTree;                 //动态分配数组存储哈夫曼数
typedef char ** HuffmanCode;          //动态分配数组存储哈夫曼编码表


//------------------------函数说明-----------------------------
void Huffmanlist(HuffmanTree HT,int *W,char *D,int n,int m);
   //W存放n个字符的权值(均为〉0的整数),D存放的是需要编码的字符,构造哈夫曼树HT.
void Huffmancoding(HuffmanTree HT,HuffmanCode HC,int n,int m);
   //根据已编的哈夫曼树给字符编码
void Select(HuffmanTree HT,int num,int *s1,int *s2);
   //选择两个权值最小的结点,并且以s1,s2返回
void Messagecoding(HuffmanTree HT,HuffmanCode HC,int n);
   //给一段字符串编码
void FMessagecoding(HuffmanTree HT,HuffmanCode HC,int n);
   //给一段01码译码成原文 
void Substring(char Message[],char Temp[],int front,int rear);
   //求从front到rear的一段子串,用Temp带回子串

main()
{
	int nodenumber;               //需要编码的字符的数目
	int wweight[MAXNODE];         //权值
	int *WEIGHT=wweight;
	char ddata[MAXNODE];	      //字符
	char *DATA=ddata;
	HuffmanTree HT;                
	HuffmanCode HC;
	int i;
	int m;            //实际需要的存储单元
	printf("输入需编码的字符个数(最多输%d个):\n",MAXNODE);
	scanf("%d",&nodenumber);
	printf("输入需编码的字符(不间断连续输入)");
	scanf("%s",ddata);
    printf("依次输入对应的字符的权值(最大为%d):\n",MAXWEIGHT);
	for(i=0;i<nodenumber;++i)
		scanf("%d",&wweight[i]);
    m=2*nodenumber-1;               //有nodenumber个结点的哈夫曼树具有(2nodenumber-1)个结点
	HT=(HuffmanTree)malloc((m+1)*sizeof(HTnode));         //0号单元不用
	Huffmanlist(HT,WEIGHT,DATA,nodenumber,m);
	HC=(HuffmanCode)malloc((nodenumber+1)*sizeof(char *));          //分配nodenumber个字符的头指针向量
	Huffmancoding(HT,HC,nodenumber,m);                    //字符编码
	Messagecoding(HT,HC,nodenumber);                      //一段文字编码
	FMessagecoding(HT,HC,nodenumber);	                  //一段01码译码成原文
}

void Huffmanlist(HuffmanTree HT,int *W,char *D,int n,int m)
{
	int i;
	int s1,s2;                    //weight最小的两个结点
	if(n<=1)
		return;
	for(i=1;i<=n;++i)              //叶子结点给初值
	{
		HT[i].data=*(D++);
		HT[i].weight=*(W++);
		HT[i].parent=0;
		HT[i].lchild=0;
		HT[i].rchild=0;
	}
	for(i=n+1;i<=m;i++)           //非叶子结点给初值
	{
		HT[i].parent=0;
		HT[i].lchild=0;
		HT[i].rchild=0;
	}
    for(i=n+1;i<=m;++i)             //建哈夫曼树
	{
		//在HT[1..i-1]选择perent为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;
	}
	
}

//------------从叶子到根逆向求每个字符的哈夫曼编码---------------
void Huffmancoding(HuffmanTree HT,HuffmanCode HC,int n,int m)
{
	char *cd;
	int i;
	int c,f;
	int start;            
	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
			else cd[--start]='1';                         //右孩子编码为1
		}
		HC[i] = (char *)malloc((n-start)*sizeof(char));          //为第i个字符编码分配空间
		strcpy(HC[i],&cd[start]);                 //从cd复制编码(串)到HC
	}
	free(cd);                            //释放工作空间
	printf("编码情况:\n");
	for(i=1;i<=n;i++)
	{
	   printf("%c:%s\n",HT[i].data,HC[i]);            //输出编码
	}

}

void Select(HuffmanTree HT,int num,int *s1,int *s2)
{
	int i;
	int temp1,temp2;            //temp1中存最小的数,temp2中存次小的数
	temp1=temp2=MAXWEIGHT;      //给temp1,temp2赋初值
	for(i=1;i<=num;++i)                 //选择perent为0且weight最小的结点。
	{
		if(HT[i].parent==0 && HT[i].weight<temp1)
		{
			temp1=HT[i].weight;
			*s1=i;
		}
	}
	for(i=1;i<=num;++i)                  //选择perent为0且weight次小的结点。
	{
		if(HT[i].parent==0 && HT[i].weight<temp2 && i!=*s1)
		{
			temp2=HT[i].weight;
			*s2=i;
		}
	}
}

void Messagecoding(HuffmanTree HT,HuffmanCode HC,int n)          
{
	int i,j;
	char message[MAXCHARS];                  //文字字符存储
	printf("以下是给一段字符编码:\n请输入一段正文(最多%d个字符),由以上字符组成:\n",MAXCHARS);
	scanf("%s",message);
	for(i=0;message[i]!='\0';i++)
	{
		for(j=1;j<=n;j++)
		{
			if(message[i]==HT[j].data)          //字符相匹配
				printf("%s",HC[j]);             //输出字符对应的码
		}
	}
}

void FMessagecoding(HuffmanTree HT,HuffmanCode HC,int n)
{   
	int i,j,t;
	char ch;
	char message[MAX];               //01字符串存储
	char temp[MAXNODE];
	printf("\nDo you want to code these 0&1 character string into prototype?\n");
	printf("Y:continue\nN:exit\n");
    ch=getchar();
	while(ch=='\n')
		ch=getchar();
	if(ch=='Y')              //继续译码求过程
	{
		printf("请输入01字符序列(最多%d个字符):\n",MAX);
        scanf("%s",message);
		i=j=0;
		while(message[i]!='\0')
		{
			Substring(message,temp,i,j);           //得到从i到j的子串
		    for(t=1;t<=n;t++)
			{
			   if(strcmp(temp,HC[t])==0)          //字串相匹配
			   {
				   printf("%c",HT[t].data);       //输出字串对应的字符
				   i=j+1;                         //i指针后移
				   j=i;
				   break;
			   }   
			}//for
			if(t==n+1)
				j++;
		}//while
	}//if
	else if(ch=='N')             //结束程序
	    exit(0);
}

void Substring(char Message[],char Temp[],int front,int rear)
{
    int t;
	int i;
	for(i=0,t=front;t<=rear;t++,i++)
	{
		Temp[i]=Message[t];
	}
	Temp[i]='\0';
}


⌨️ 快捷键说明

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