基于哈夫曼编码的图像压缩算法实现

第一章  概述

        本章主要内容为本次实验主题基于哈夫曼编码的图像压缩算法的研究与发展现状以及本次实验的设计背景及意义。

1.1 设计背景及意义

        随着信息技术的不断发展,数字图像在我们的日常生活中变得越来越常见。然而,由于数字图像具有非常大的数据量,如何高效地存储和传输这些图像数据成为了一个重要的问题。

        因此,图像压缩技术应运而生。图像压缩技术的基本思路是通过对图像中冗余信息的消除,从而减少图像文件的存储空间和传输带宽。哈夫曼编码就是一种非常常见的图像压缩技术,它通过对像素值进行编码,从而实现对图像数据的压缩。

        哈夫曼编码的设计意义在于实现对数据的高效压缩,从而减小数据的存储空间和传输带宽。哈夫曼编码的核心思想是通过对数据出现频率的分析,将出现频率较高的数据用较短的编码表示,而将出现频率较低的数据用较长的编码表示。在具有相同信源概率分布的前提下,它的平均码字长度比其他任何一种有效编码方法都短[1]。

        由于哈夫曼编码可以根据图像数据的特性进行调整,在不同的图像数据上都能够获得较好的压缩效果。因此,哈夫曼编码的图像压缩已经成为了一种非常常见的图像压缩算法,并在众多的应用中得到了广泛的使用。

        此外,哈夫曼编码的设计方法具有普适性和灵活性。根据不同的数据特点和需要,可以采用不同的哈夫曼编码策略来实现更优的压缩效果。因此,哈夫曼编码的设计意义在于提供了一种通用的、可灵活应用的编码方法,为各种信息处理应用带来了更高效和更可靠的数据传输和存储方案。

1.2 哈夫曼编码的研究与发展现状

        哈夫曼编码作为一种经典的压缩算法,自诞生以来就被广泛地应用于图像压缩领域。随着计算机技术的不断进步,哈夫曼编码的图像压缩应用也在不断发展。在过去的几十年间,许多研究工作都致力于改进基于哈夫曼编码的图像压缩算法,从而获得更高的压缩性能。

        目前,哈夫曼编码的图像压缩研究和发展主要有以下方向:

        1. 基于快速哈夫曼编码算法的优化。传统的哈夫曼编码算法的压缩效率受到编码和解码速度的限制,而快速哈夫曼编码算法可以显著提高编码和解码速度,从而实现更高效的图像压缩。

        2. 基于哈夫曼编码与其他编码方法的结合。通过将哈夫曼编码与其他高效的压缩算法和数据处理方法结合使用,可以获得更高的压缩性能。例如,可以将哈夫曼编码和离散余弦变换结合使用来实现JPEG图像压缩。

        3. 基于自适应哈夫曼编码的图像压缩算法。传统的哈夫曼编码算法需要预先知道数据集中各个符号出现的概率,而自适应哈夫曼编码算法可以根据数据实际出现频率来生成编码,从而实现更高的压缩效率。

        4. 基于哈夫曼编码的无损压缩算法的研究和发展。传统的哈夫曼编码算法在压缩率和压缩速度上存在一定的矛盾,而基于哈夫曼编码的无损压缩算法可以实现更高的压缩比和较快的压缩速度。

        5. 基于哈夫曼编码的高级压缩算法。在保持哈夫曼编码优点的同时,结合其他的编码和解码策略,可以实现更高效的压缩算法。例如,预测编码和哈夫曼编码结合使用可以提高图像压缩性能。

        总之,哈夫曼编码作为图像压缩领域中具有广泛应用的代表性算法,目前正不断地迎来新的发展。这些研究结果将有望推动哈夫曼编码在图像和视频领域等新方向中的应用。

1.3 主要内容与章节安排

        本次报告将从四个方面进行总结,分别是:哈夫曼编码概述、编码算法与设计方案、图像压缩编码的实现和测试结果与分析。

        在第一章中介绍了此次实验基于哈夫曼编码的图像压缩的设计背景及意义、哈夫曼编码图像压缩的研究和发展现状等。

        在第二章中介绍了基于哈夫曼编码的图像编码原理及其设计方案等。

        在第三章中介绍了图像预处理、图像压缩、图像重建、可视化界面等。

        在第四章中介绍了基于哈夫曼编码的图片压缩算法的测试结果、评测指标与结果分析。


第二章  编码算法与设计方案

        本章节将具体介绍本次实验的编码原理与计算推导过程分析、介绍以及设计方案的总体框架、设计的步骤、数据的存储结构。

2.1 图像编码原理

        哈夫曼编码又称统计编码,是哈夫曼在1952年提出的一种无失真压缩技术,它是通过用更有效的代码代替数据来实现的。哈夫曼编码最初是为了对文本文件进行压缩而建立的,迄今已经有很多变体。它的基本思想是出现频率越高的值,其对应的编码长度越短,反之出现频率越低的值,其对应的编码长度越长。其原理是将欲压缩的字串,先读一遍,将字串中的每一个相异单字元的出现频率作统计,依此构建哈夫曼树。

        每一相异单字元,用0与1予以编码。出现次数越多者,给予较少的位元编码,最后将这些位元串组合起来并加入哈夫曼树成为压缩档案。

        基于哈夫曼编码的图像压缩算法中,图片的编码原理主要涉及到如何将像素点的值转化为相应的哈夫曼编码。

        首先,该压缩算法需要对原图像进行预处理,求出每个字符出现的次数,也就是权值。然后利用哈夫曼编码将其转换为一系列的二进制码序列来表示。在哈夫曼编码过程中,通过对这些数值进行频率分析,将出现频率高的数值用短的二进制码表示,而将出现频率低的数值用长的二进制码表示。通过将每个块内的数值用哈夫曼编码的方式表示,就可以大大减小保存和传输数据时所需的空间和时间成本。

        总结来说,基于哈夫曼编码的图像压缩算法编码原理的核心就是通过使用哈夫曼编码来减小压缩图像所需的空间和时间成本,以获得更高的压缩效率。

2.2 设计方案

        总体设计框架如下:从文件中读取图片中每个字符出现的次数,也就是图片的权值。然后利用数组保存下来,再根据哈夫曼树与哈夫曼编码的原理,将图片的权值进行编码,最后用编码替换原来字符生成新文件,这样基于哈夫曼编码的图片压缩就完成了。

由于本次为了创造更美观的界面,设计具体步骤如下:

        1.首先用windows库文件中的color函数改变界面和字体的颜色,接着进行功能的选择并定义weight数组用来保存图片的权值。

        2.现在开始读取图片,输入文件名后,根据输入的文件名及其位置打开文件并将读取的文件信息保存在weight数组中。此处我采用了创新方法,将weight数组中的非0 信息保存在另外一个数组weight1中,然后将非0权值的字符保存在b数组中。

        3.根据非0数组中b的大小构建哈夫曼树。哈夫曼树构建思路如下:用ht数组存放哈夫曼树,对于具有n个叶子结点的哈夫曼树,总共有2n-1个结点。其算法思路是,n个叶子结点(存放在ht[0]-ht[n-1]中只有data和weight域值,先将2n-1个结点的parent、lchild和rchild域值置为初值-1。然后处理每个非叶子结点ht[i](存放在ht[n]-ht[2n-2]中):从ht[0]-ht[i-1]中找出根结点(其parent域为-1)最小的两个结点ht[Inode]和ht[rnode],将它们作为ht[i]的左、右子树,将ht[Inode]和ht[rnode]的双亲结点置为ht[i],并且ht[i].weight=ht[lnode].weight+ht[rnode].weight。如此这样,直到n-1个非叶子结点处理完毕。

        4.根据哈夫曼数进行哈夫曼编码,编码步骤如下:具体构造方法如下:设需要编码的字符集合为(d1,d2…dn),各个字符在电文中出现的次数集合为(w1,w2…wn)以d1、d2…dn作为叶子结点,以w1、w2…wn,作为各根结点到每个叶子结点的权值构造一棵哈夫曼树,规定哈夫曼树中的左分支为0,右分支为1。则从根结点到每个叶子结点所经过的分支对应的0和1组成的序列便是该结点应学符的编码,这样的编码称为哈夫曼编码。哈夫曼编码的实质就是使用频率越高的字符采用越短的编码。由于哈夫曼树中每个叶子结点的哈夫曼编码长度不同,为此采用HCode类型变量的cd[start…n]存放当前结点的哈夫曼编码,只需对叶子结点求哈夫曼编码。对于当前叶子结点ht[i],先将对应的哈夫曼编码hcd[i]的start域值置初值n。找其双亲结点ht[f],若当前结点是双亲结点的左孩子结点,则在hcd[i]的cd 数组中添加'0',若当前结点是双亲结点的右孩子结点,则在hcd[i]的cd数组中添加'1',并将start域减1。再对双亲结点进行同样字符的操作,如此这样,直到无双亲结点(即到达根结点),所以 start 指向哈夫曼编码最开始的字符。

        5.编码后就可进行压缩,将得到的字符的编码按照原来的位置替换原来的字符。

        数据的存储结构:哈夫曼树和哈夫曼编码用结构体存储,数组权值用数组保存,文件类型也是用结构体保存。


第三章  图像压缩编码的实现

        本章主要介绍图像预处理步骤或具体功能模块的设计与实现、图像压缩的方法、图像重建、可视化界面的实现等。

3.1 图像预处理

        在进行图片压缩前,我们需要对图片进行预处理。

        1.明确我们图片处理的类型:我们要对文件后缀为bmp的文件进行处理。

        2.设置一个char类型的数组,用来存储文件名。

        3.输入文件名,包括文件的位置及其类型。为了防止输入错误,应该设置输入错误时重新输入或者退出的操作。

        4.输入文件名字后,需要用数组weight保存字符出现的次数,也就是图片的权值。此处我又用到了一个新的数组weight1保存weight数组中非0字符的权值,也用到了一个新的数组b保存非0字符,这样在进行编码的时候可以提高效率。以免权值为0的字符在编码的时候影响这个字符的编码。

3.2 图像压缩

        在获得图片权值的编码后就可以进行图片的压缩,具体原理已经在前面提及到,这里不在进行赘述。由于在原来的基础上进行了改进,所以在压缩步骤会麻烦一些。由于在二进制中8个字符为一个字节,所以在压缩之前要先进行字节的计算,将总共的所有编码的数值除以8得到的就是字节的个数,然后进行压缩。还是先进行扫描文件,将文件中出现的字符在我们的b数组中查找,如若查找成功,将标志flag置1。在标志为1的时候将此字符对应的编码保存在一个临时变量中,再将这个临时变量放在原来字符所在的位置上。此次过程的保存是在一个数组中,只是位置是相对与图片位置。

3.3 图像重建

        压缩后返回的是一个字符数组,然后根据这个数组进行重建。建立结构体HEAD保存图片的信息,如长度,类型等。然后新建一个字符数组保存新文件的名称,根据刚才的结构体将文件信息复制上去,并用strcat函数在新文件后面加上huf来区分原来的文件。写入新的信息需要用到文件操作:

        1.打开文件,并且用wb表示写入。

        2.用fwrite函数写入上面得到的返回值。

        3.关闭文件,表示写入完成。

        这样,新图片文件就构造成功。

3.4 可视化界面

        首先下载easyx文件,这是关键。

        1.创建一个480×360的窗口,我们需要使用initgraph函数。用win_width,win_height来定义窗口的宽度和高度,然后用initgraph(win_width,win_height)表示初始化窗口(黑屏)。通过循环和setbkcolor函数设置一个逐渐变亮的界面背景,原来默认黑色再用cleardevice清屏。Sleep(15)表示每次延时15ms变亮。最后用closegraph函数关闭绘图界面。

        2.设置三个按钮的参数r1表示输入文件名按钮的矩形参数,r2表示运行按钮的矩形参数。r3表/退出按钮的矩形参数。RECT R1表示矩形指针R1;RECT R2表示矩形指针R2;RECT R3表示矩形指针R3。LOGFONT f表示字体样式指针,gettextstyle函数用来获取字体样式,用_tcscpy函数设置字体,settextcolor函数设置字体颜色 ,drawtext函数控制我们矩形框中的文字。

        3.作为一个图形化界面的C程序,鼠标操作是不能少的。鼠标是输入设备,只要发生以下的事件,就会暂存在鼠标消息列表中,我们的操作系统就会依次响应列表中的鼠标消息事件,常用的鼠标事件如下:

        (1)WM_MOUSEMOVE——鼠标移动

        (2)WM_MOUSEWHEEL——鼠标滚轮滚动

        (3)WM_LBUTTONDOWN——鼠标左键按下

        (4)WM_LBUTTONUP——鼠标左键弹起

        (5)WM_LBUTTONDBLCLK——鼠标左键双击

        (6)WM_RBUTTONDOWN——鼠标右键按下

        (7)WM_RBUTTONUP——鼠标右键弹起

        (8)WM_RBUTTONDBLCLK——鼠标左键双击

        (9)WM_MBUTTONDOWN——鼠标中键按下

        (10)WM_MBUTTONUP——鼠标中键弹起

        (11)WM_MBUTTONDBLCLK——鼠标中键双击

        我们希望鼠标移到按钮上时按钮会有所变化,移开按钮时又会回到原样。这里我们采用一种简单的填充颜色的方法,就是按钮变色。我们需要解决一个问题就是按钮变色了但是按钮的文字不能被覆盖,那么我们还是需要使用到二元光栅。只是我们这次的模式改成了同或。为了方便起见,存放三个按钮的数组我们合并为了一个二维数组,在鼠标事件中更容易使用和分配任务。


第四章  测试结果与分析

        本章节主要介绍代码的测试结果,及其相关系数的数值。

4.1 测试结果

        输入结果如图4.1所示:

c802b74c6c35423685f4e89b47b51ca5.png

图4.1 输入测试图1

        点击运行后我们可以发现图4.2-4.3的变化,点击退出则会马上退出该界面。

bf7e49fc92f746f2918cf4128fcd6307.png

图4.2 变化1

e0cfea5f3cd249ab9f168a5c535d921b.png

图4.3 变化2

4.2 评价指标

        如下图4.4,4.5所示结果,可以看到平均编码长度与图片信息熵的结果。

8cae86d6fadf4f2a96c2b01a1a5ee013.png

 图4.4 平均编码长度

b3d5d324adbb4e999e6d437fea7dd745.png

 图4.5 图片信息熵

4.3 结果分析

946ccb725d0a4da1a3e7b3ae83a6f2a9.png

图4.6 结果比较

        根据上图4.6与下图4.7和4.8进行比较,可以发现我们压缩成功并且大小大概是原来的四分之一左右。

8bede98b165f4b438c5e3af1ff26af6e.png

图4.7 原来图片大小 

 

687e88decac34ca1988da42d0e230692.png

 图4.8压缩后图片大小


总 结

        哈夫曼编码是一种无损压缩算法,常用于文本、图像和音频的压缩。在图像压缩中,哈夫曼编码可以通过将像素灰度值映射为对应的编码,从而减少存储所需的位数。

        以下是基于哈夫曼编码的图片压缩算法的总结:

        1. 图像采样:图像压缩首先需要对图像进行采样,即将原始图像分成多个像素,并且采集这些像素的颜色和位置信息。

        2. 构建哈夫曼树:在哈夫曼编码中,需要构建哈夫曼树来确定每个符号的编码。哈夫曼树是一种二叉树,其叶子节点表示每个符号,根据符号的出现频率,将符号分配到左子树或右子树。构建哈夫曼树的过程中,需要对符号按照出现频率进行排序,并且使用贪心算法来选择节点。

        3. 哈夫曼编码:在哈夫曼树构建完成后,每个符号对应的编码就可以由哈夫曼树中的路径得到。符号表中的每个符号通过从根节点到叶子节点的路径得到一个二进制编码,其中左分支表示0,右分支表示1。图像的每个像素颜色值都可以通过其对应符号的编码来表示,从而将图像数据压缩到更小的存储空间中。

        4. 压缩率计算:对于哈夫曼编码的图像压缩算法,压缩率取决于像素颜色值的分布情况和哈夫曼树的构建。通常情况下,图像中像素颜色的分布越离散,哈夫曼树的分支越多,压缩比就越高。

        图像压缩技术, 是当前很热门和实用的信息技术,图像压缩技术研究了几十年,取得了很大的成绩,但还有许多不足,值得我们进一步研究。Huffman编码压缩作为一种简单 高效的编码方法 ,在文本、图像、音频等压缩技术中都有着广泛的应用。从整个课题中可以看到,Huffman编码算法只对图像压缩一次,要想提高压缩比,可以对图像进行两次压缩或多次压缩。另外,还可以与人眼视觉特性相结合实现有损压缩。总之, 图像压缩是一个非常有发展前途的研究领域, 这一领域的突破对于我们的信息生活和通信事业的发展有着深远的意义。


代码 

 下面的代码没有UI界面,是我自己最开始的代码,界面制作请自行搜索相关文章

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h> 
#include<windows.h>
#define N 50
#define SIZE 256
int n=0;//非零结点个数 
int length[256];//编码长度 
int weight1[256];//权值 
int b[256];//非零结点 
typedef int ElemType;
typedef char InfoType;
typedef struct
{
	int weight;
	int parent;
	int lchild;
	int rchild;
}HTNode;
typedef struct
{
	char cd[N];
	int start;
}HCode;
struct HEAD
{
	char type[4];
	int length;
	int weight[256]; 
};
void CreatHT(HTNode ht[],int weight1[],int n)
{
	int i,j;
	int x1,x2;
	double min1,min2;
	for(int i=0;i<(2*n-1);i++)
	{
		if(i<n)
		{
			ht[i].weight=weight1[i];	
		} 
		else
		{
			ht[i].weight=0;
		}
		ht[i].parent=-1;
		ht[i].lchild=-1;
		ht[i].rchild=-1;
	}
	for(i=n;i<2*n-1;i++)
	{
		min1=min2=10000000;
		x1=x2=-1;
		for(j=0;j<=i-1;j++)
		{
			if((ht[j].weight<min1)&&(ht[j].parent==-1))	
			{
				min2=min1;
				x2=x1;
				min1=ht[j].weight;
				x1=j;
			}
			else if(ht[j].weight<min2&&ht[j].parent==-1)		
			{
				min2=ht[j].weight;	
				x2=j;
			}
		}
		ht[x1].parent=i;	
		ht[x2].parent=i;		
		ht[i].weight=ht[x1].weight+ht[x2].weight;
		ht[i].lchild=x1;	
		ht[i].rchild=x2;	
	}
	/*printf("字节种类 权值 双亲结点下标 左孩子结点下标 右孩子结点下标\n");
	for(int i=0;i<n;i++)
	{
		printf("ht[%d]\t%d\t  %d\t   	%d\t   	%d\n",i,ht[i].weight,ht[i].parent,ht[i].lchild,ht[i].rchild);
	}*/
}
void HTNodeCodeing(HTNode ht[],HCode hc[],int n)
{
	HCode ncd;
	int i,c,f;
	for(i=0;i<n;i++)
	{
		ncd.start=n;
		c=i;
		f=ht[i].parent;
		while(f!=-1)
		{
			if(ht[f].lchild==c)
				ncd.cd[ncd.start--]='0';
			else
				ncd.cd[ncd.start--]='1';
			c=f;
			f=ht[f].parent;
		}
		ncd.start++;
		hc[i]=ncd; 
	}
}
float DispHCode(HTNode ht[],HCode hc[],int n)
{
	int i,k,j; 
	int sum=0,m=0;
	printf("输出哈夫曼编码:\n");
	for(i=0;i<n;i++)
	{
		j=0;
		printf("权重:%6d\t   \t编码:",ht[i].weight); 
		for(k=hc[i].start;k<=n;k++)
		{
			printf("%c",hc[i].cd[k]);
			j++;
		}
		length[i]=j;
		printf("\n");
		m+=ht[i].weight;
		sum+=ht[i].weight*j;
	}	
	printf("\n平均编码长度:");
	return 1.0*sum/m;
}
int getlength(int weight1[], int n)
{
	int sum=0;
	for (int i=0;i<n;i++)
	{
		sum+=weight1[i]*length[i];
	}
	return sum;
}
int getsize(int sum)
{
	int size=sum%8? sum/8+1:sum/8;
	return size;
}
char str2byte(char *s)
{
	char b = 0x00;
	for (int i=0;i<8;i++) 
	{
		b=b<<1;
		if (s[i] == '1')
		{
			b=b | 0x01;
		}
	}
	return b;
}
char* HTyasuo(char filename[], int size, HCode hc[],int b[],int n)
{
	char* out = (char*)malloc(size * sizeof(char));
	char temp[256]={0};
	int pos=0;
	int ch;
	FILE* in=fopen(filename, "rb");
	if (in==NULL) 
		printf("打开文件失败\n");
	while ((ch=fgetc(in))!= EOF)
	{
		int i=0;
		bool flag=0;
		for(i=0;i<n;)
		{
			if(ch!=b[i])
				i++;
			else if(ch==b[i]) 
			{
				flag=1;
				break; 
			}
		}
		if(flag==1)
		{
			char c[N];
			int k,j;
			for(k=0,j=hc[i].start;j<n;j++,k++)
			{
				c[k]=hc[i].cd[j];
			}
			strcat(temp,c);
			for(i=0;i<N;i++)//置空 
				c[i]='\0';
			while (strlen(temp)>=8)
			{
				out[pos++]=str2byte(temp);
				for (int i=0;i<SIZE-8;i++) 
				{
					temp[i]=temp[i+8];
				}
			}
		}
	}
	if (strlen(temp)>0)
		out[pos++]=str2byte(temp);	
	fclose(in);
	return out;
}
int initHead(int weight1[],HEAD &sHead)
{
	int i;
	strcpy(sHead.type,"bmp");
	sHead.length=0;
	for(i=0;i<n;i++)
	{
		sHead.weight[i]=0;
	}
	for(i=0;i<n;i++)
	{
		sHead.weight[i]=weight1[i];
		sHead.length++;
	}
	return 0;
}
int  xinxishang(char filename[])
{
	FILE* fp;
	unsigned char imgdata[512][512];   // 图像数组
	double hist[256], prob[256], entropy = 0.0;
	int i, j, width = 512, height = 512;   // 图像尺寸
	// 打开图像文件
	if ((fp = fopen(filename, "rb")) == NULL)
	{
		printf("打开文件失败\n");
		return 0;
	}

	// 读取图像数据
	fread(imgdata, sizeof(unsigned char), width * height, fp);
	fclose(fp);

	// 计算像素灰度直方图
	for (int i = 0; i < 256; i++)
	{
		hist[i] = 0.0;
	}
	for (int i = 0; i < height; i++)
	{
		for (j = 0; j < width; j++)
		{
			hist[imgdata[i][j]]++;
		}
	}

	// 计算像素灰度概率分布
	for (int i = 0; i < 256; i++)
	{
		prob[i] = hist[i] / (double)(width * height);
	}

	// 计算图像信息熵
	for (i = 0; i < 256; i++)
	{
		if (prob[i] > 0)
		{
			entropy += prob[i] * log2(1.0 / prob[i]);
		}
	}

	printf("图像信息熵: %f\n", entropy);

	return 0;
}
int meau()
{
	printf("\n						请选择以下功能:\n");
	printf("						1.进图像压缩与计算平均码长\n");
	printf("						2.查看图像权重与信源熵\n");
	printf("						3.退出程序\n");
	int m;
	printf("请输入您的选择:");
	scanf("%d",&m);
	return m;
 } 
int main()
{
	system("color F1");
	printf("\t------------------------------------基于哈夫曼编码的图像压缩算法实现------------------------------------\t");
	int r=0;//功能选择 
	int m=meau();
	int weight[256]={0};
	int weight2[256]={0};
	for(int i=0;i<256;i++)
		weight[i]=0;
	if(m==1||r==1)
	{
		printf("请输入文件名:");
		char filename[256];
		restart1:scanf("%s",&filename);
    	int ch;
		FILE* in=fopen(filename,"rb");
		if(in==NULL)
		{
			printf("打开文件失败!");
			printf("请重新输入文件名:");
			goto restart1; 
		}
		while((ch=fgetc(in))!=EOF)
		{
			weight[ch]++;
		}
		fclose(in);
		for(int i=0;i<256;i++)
		{
			if(weight[i]!=0)
			{
				b[n]=i;
				n++;
			}	
		}
		for(int i=0,j=0;i<n&&j<256;j++)
		{
			if(weight[j]!=0)
			{
				weight1[i]=weight[j];
				i++;
			}	
		}
		HTNode ht[2*n-1];
		CreatHT(ht,weight1,n);
		HCode hc[n];
		HTNodeCodeing(ht,hc,n);
		float h;
		h=DispHCode(ht,hc,n);
		printf("%f\n",h);
		int l=getlength(weight1,n);
		int size;
		size=getsize(l);
		char *s=HTyasuo(filename,size,hc,b,n);
		HEAD sHead;
		initHead(weight1,sHead);
		char newfilename[256]={0};
		strcpy(newfilename,filename);
		strcat(newfilename,".huf");
		FILE* out = fopen(newfilename,"wb");
		fwrite(s,sizeof(char),size,out);
		fclose(out);
		out=NULL;
		printf("\n生成压缩文件:%s\n",newfilename);
		printf("\n");
		system("pause");
		system("cls");
		r=meau();
	}
	if(m==2||r==2)
	{
		printf("请输入文件名:");
		char filename[256];
		restart2:scanf("%s",&filename);
    	int ch;
		FILE* in=fopen(filename,"rb");
		if(in==NULL)
		{
			printf("打开文件失败!");
			printf("请重新输入文件名:");
			goto restart2; 
		}
		while((ch=fgetc(in))!=EOF)
		{
			weight2[ch]++;
		}
		fclose(in);
		printf("Byte Weight\n");
		for(int i=0;i<256;i++)
			if(weight2[i]!=0)
				printf("0x%02X %d\n",i,weight2[i]);
		xinxishang(filename);
		system("pause");
		system("cls");
		r=meau();
			
	}
	if(r==3||m==3)
	{
		printf("已经退出本程序\n"); 
		system("pause");
		system("cls");
		return 0;		
	}	

}

有些注释掉的是测试部分,可有可无。

本代码由于写的时候没有考虑的太多,存在一些BUG,如只能从1-3按顺序执行。

 

 

 

 

  • 13
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值