哈夫曼压缩算法C语言实现——步骤,详细注释源码

哈夫曼压缩算法的详细实现步骤:

1、定义哈夫曼树节点,用结构体。

2、利用C语言文件读写,统计字符个数。

3、根据字符个数创建哈夫曼树(不懂haffman数据结构的自己查下资料,我这里就不再重复了)

4、根据哈夫曼树为每个出现的字符编码

5、压缩:这里涉及到位操作,用char8位来储存字符编码(压缩的关键)。

6、解压缩:读压缩文件,在char中从左到右按位遍历哈夫曼树

(再不懂的看源码,注释够意思了。)

#include
#include
#include 
//定义一个哈夫曼节点,它是个结构体
struct haffNode{
	int weight;//权重,就是这个字符出现的个数;如果这个节点是个父节点的话 ,就是两个子节点权重的和 
	char data;//这个用来存字符本身,比如字符是'c',data='c'; 
	struct haffNode *leftChild=NULL,*rightChild=NULL;//定义左右子节点指针 
}; 
char code[256][50];//用二维数组来储存字符的哈夫曼编码,其中第一维的下标表示的是这个字符的ASCII码  
haffNode left[50];//用来储存所有的左子节点 
haffNode right[50];//用来储存所有的右子节点 
unsigned char saveChar = 0; //用来保存二进制文件,因为char类型是1个字节,所以每8位储存一次 ,而且用unsigned无符号型,避免符号位干扰 
unsigned char slidChar;//定义一个字符备用,以应对可能需要的操作 
//排序函数,第一个参数是哈夫曼的节点数组,第二个是数组的长度,这里用冒泡排序 
void sort(haffNode* node,int length){
	int i,j; 
	haffNode t;
	for(i=0; ileftChild == NULL || node->rightChild == NULL){
		keepCode[length] ='\0';//给编码一个终止符,形成一个完整的字符串,方便拷贝,以防拷贝到之前的编码。 
		strcpy(code[node->data-0],keepCode);//调用strcpy函数拷贝字符串,其中code的下标用节点的字符(data)-0得到 
		return; 
	}
	keepCode[length] = '0';
	coding(node->leftChild,keepCode,length+1);
	keepCode[length] = '1';
	coding(node->rightChild,keepCode,length+1);
} 
//解压缩  
haffNode* unzip(haffNode *node,int flag){
	if(flag == 0)
	return node->leftChild;
	if(flag == 1)
	return node->rightChild;
} 
int main(){
    int count[128]={0};//用来统计字符个数,一开始清零,其中它的下标号表示这个字符的ASCII码
    char keepCode[50];//用于在生成编码的时候 临时储存编码 ,真正储存编码的地方看代码最上面的code[][]数组 
    char reder;//用来存文件中的字符 
    int fileLength=0;//用来计算原文长度 
    int zipLength=0;//用来计算压缩文长度 
    int i; 
    int num=0;//用来计算出现的字符的个数 和其它一些计数功能 
    haffNode node[100];//用来储存哈夫曼节点,这里我申请100个空间事实上不需要那么大,大概需要26+26+20(26个英文字母大小写+标点符号) 
	FILE *fpr = fopen("E:\\input.txt","r");//读入文件,其中input.txt的路径你要自己设置,可以自己建立一个文本,写一些英文进去 
	FILE *fpw = fopen("E:\\output1","wb");//写入文件,wb是写入二进制文件,路径设置随意,但是要符合格式,写入的时候文件自动生成。
	FILE *fpr1= fopen("E:\\output1","rb");;//用于解压缩时读入文件 ,rb是读入二进制文件 
	FILE *fpw1 = fopen("E:\\output3.txt","w"); //用于解压缩时写入文件 
	//解压需要用的 
	char op;
	haffNode *z;
	//读取文件 
	while((reder=fgetc(fpr))!=EOF){//一个一个地读入字符 
		fileLength ++;//每读进一个字原文长度+1 
		count[reder-0]++;//reder-0可以得到字符的ASCII码,然后累加统计 
	} 
	//循环数组,因为ASCII表中有255个字符,所以数组中有些字符是完全没有出现过的,我们要将出现过的存在charNode数组里。 
	for(i=0; i<128; i++){
		if(count[i]!=0){
			node[num].data=i;//之前说过,下标就是出现的字符的ASCII码
			node[num].weight=count[i];//count[i]存的就是字符出现的次数
			num++;//计数加1 
		}
	}
	//构建哈夫曼树
	creatHaffman(node,num); 
	//计算哈夫曼编码
	coding(&node[0],keepCode,0); 
	//根据哈夫曼编码把原来的文本压缩储存 
	//读取文件 
	num=0;//计数 
	fseek(fpr,0L,0);//因为上面已经读过文件了,fpr指针已经向下移动,所以这边使用 fseek函数将指针复原到离0(文件起始位置)0L(第0个字节)处 
	while((reder=fgetc(fpr))!=EOF){ //一个一个地读入字符 
		for(i=0; i>7;
		z = unzip(z,slidChar-0);
		if(z->leftChild == NULL || z->rightChild == NULL){
			fprintf(fpw1,"%c",z->data);
			num++;//每写进一个字符+1 
			z = &node[0];
		}
	}
	}
	fclose(fpr1);
	fclose(fpw1);
	//计算压缩率	
	printf("原文件:%dK\n",fileLength/1024+1);
	printf("压缩完成!请查看output1:%dK\n",zipLength/1024+1); 
	printf("解压缩完成!请查看output3.txt:\%dK\n",fileLength/1024+1); 
	printf("压缩率:%.2f%%\n",(float)(fileLength-zipLength)/fileLength*100);	
    return 0;
    } 
    




你可能感兴趣的:(编程)