Huffman编码

Huffman编码

哈夫曼编码(Huffman Coding),是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做Huffman编码 。

  1. 预备知识

    • 哈夫曼树的存储结构

      typedef struct

      {

      unsigned int weight;

      unsigned int parent, lchild, rchild;

      }HTNode,*HuffmanTree; //动态分配数组存储哈夫曼树

    • 哈夫曼编码的存储结构

      typedef char * *HuffmanCode;

      ​ //动态分配数组存储哈夫曼编码表

  2. 实验题目

    从键盘接收任意一个字符串。以字符串中某字符出现的次数,作为该字符的权值。利用得到的权值构造huffman树、并输出每个字符对应的huffman编码。

代码运行的预编译命令

#include <stdio.h>
#include <malloc.h>
#include <string.h>

所用的函数的声明以及结构体定义

#include "CommonDef.h"
typedef struct{
	int weight;
	int parent,lchild,rchild;
}HTNode,*HuffmanTree;
typedef struct{
	char ch;
	int weight;
	}ww,*W;
typedef char **HuffmanCode;
void select(HuffmanTree *HT,int n,int *s1,int *s2);
void HuffmanCoding(HuffmanTree *HT,W *w,int n);
void Huffman(HuffmanTree HT,HuffmanCode *HC,W *w,int n);

具体的函数实现

Huffman树的构建

void HuffmanCoding(HuffmanTree *HT,W *w,int n){
	HuffmanTree p;
	int s1,s2,m,i;
	if(n<=1) return;
	m=2*n-1;
	*HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));
	for(p=*HT+1,i=1;i<=n;i++,p++){
		p->weight=w[i-1]->weight;
		p->lchild=0;
		p->parent=0;
		p->rchild=0;
	}
	for(;i<=m;i++,p++){
		p->weight=0;
		p->lchild=0;
		p->parent=0;
		p->rchild=0;
	}
	for(i=n+1;i<=m;i++){
		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;
	}
	for(p=*HT+1,i=1;i<=m;i++){
	printf("%d %d %d %d\n",p->weight,p->parent,p->lchild,p->rchild);
	p++;
	}
}

构建Huffman树中找查最小值与次小值的实现

void select(HuffmanTree *HT,int n,int *s1,int *s2){
	int i=1,min,cmin;
	HuffmanTree p;
	p=*HT+1;
	while(p->parent!=0){
		p++;
		i++;}
	min=p->weight;*s1=i;//最小 
		p++;i++;
    while(p->parent!=0){
		p++;
		i++;}
	cmin=p->weight;*s2=i;//次小 
	
	for(i=1,p=*HT+1;i<=n;i++,p++){
		if(p->parent==0){
		if(p->weight<min){
			cmin=min;
			min=p->weight;
			*s2=*s1;
			*s1=i;
		}
		else if(p->weight<cmin&&(*s1!=i)){
			cmin=p->weight;
			*s2=i;
		}
	}
	}
}

通过Huffman树实现Huffman编码

void Huffman(HuffmanTree HT,HuffmanCode *HC,W *w,int n){
	char *cd;
	int i,start,c,f;
	*HC=(HuffmanCode)malloc((n+1)*sizeof(char *));
	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';
			else cd[--start]='1';
		}
		(*HC)[i]=(char *)malloc((n-start)*sizeof(char));
    	strcpy((*HC)[i],&cd[start]);
	}
	free(cd);
}

测试代码

int main(){
	W w[26];
	int n,n1,i,j;
	int zifu[26]={0};
	char *s;
	FILE *fp1,*fp2; 
	HuffmanTree HT;
	HuffmanCode HC;
	s=(char *)malloc(100*sizeof(char));
	fp1=fopen("input.txt","r");
	fp2=fopen("output.txt","w");
	if(!fp1)
	{
		printf("can't open file\n");
		return -1;
	}
	fscanf (fp1,"%s",s);
	n=strlen(s);
	for(i=0;i<26;i++){
		w[i]=(W)malloc(sizeof(ww));//结构体数组分配空间 
	}
	for(i=0;i<n;i++){
		zifu[s[i]-'a']++;
	}
	for(i=0,j=0;i<26;i++){
		if(zifu[i]!=0){
			w[j]->ch=i+'a';
			w[j]->weight=zifu[i];//给每个数组赋值 
			j++;
		}
	}
	n1=j;
	for(i=0;i<n1;i++){
		printf("%c的权值%d\n",w[i]->ch,w[i]->weight);
		fprintf(fp2,"%c的权值%d\n",w[i]->ch,w[i]->weight);
	}	
	HuffmanCoding(&HT,w,n1);
	Huffman(HT,&HC,w,n1);
	for(i=1;i<=n1;i++){
		printf("%c的编码:%s\n",w[i-1]->ch,(HC)[i]);
		fprintf(fp2,"%c的编码:%s\n",w[i-1]->ch,(HC)[i]);
	}
	return 0;
}

一些注意事项

  1. 测试代码中的数据是从文件读入,然后再写入文件中。读入的文件全为字母,我的测试数据中全用的小写字母。

  2. 代码首先对读入字母进行统计出现的个数,然后再实现编码。

  3. 本来只把算出来的编码写入文件中,但是为了更好观看,也打印在屏幕中了。

  4. 本来代码中无法对应每个字母,如图

为了更好看出每个字母对应的编码,采用了结构体来存储每个字母的权值,这样既可以存储权值,也可以把字母存储进去。

测试数据

  1. input文件的数据: aaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbcccccccddddddddeeeeeeeeeeeeeefffffffffffffffffffffffggghhhhhhhhhhh

  2. 所得到的Huffman编码

posted @ 2020-12-04 21:25  sleepzzw  阅读(234)  评论(0)    收藏  举报