数字图像处理中的Huffman编码压缩C_实现

合集下载

哈夫曼编码无损数据压缩的原理和实现

哈夫曼编码无损数据压缩的原理和实现

哈夫曼编码无损数据压缩的原理和实现无损数据压缩技术是计算机领域中的一项重要技术,而哈夫曼编码作为其中一种经典的压缩算法,被广泛应用于数据传输和存储中。

本文将介绍哈夫曼编码的原理和实现方法。

一、原理哈夫曼编码是一种变长编码(Variable Length Code)技术,它利用出现频率较高的字符使用较短的编码,而出现频率较低的字符使用较长的编码,从而达到数据压缩的目的。

其原理如下:1. 统计字符频率:首先,需要统计待编码的数据中每个字符出现的频率。

这可以通过扫描整个数据流来实现。

统计结果可以用于构建哈夫曼树。

2. 构建哈夫曼树:根据字符频率构建哈夫曼树,其中频率越高的字符位于树的顶部,频率越低的字符位于树的底部。

构建哈夫曼树的过程中,使用最小堆来选择两个最小频率的节点,将它们合并为一个新的节点,并更新频率。

3. 分配编码:通过沿着哈夫曼树的路径,从根节点到达叶子节点,将0或1分配给每个字符。

注意,由于哈夫曼树的性质,没有一个字符的编码是另一个字符编码的前缀,因此哈夫曼编码是一种无前缀编码(Prefix-Free Code)。

4. 压缩数据:根据哈夫曼编码表,将原始数据中的每个字符替换为对应的编码,从而得到压缩后的数据。

二、实现哈夫曼编码的实现通常包括以下几个步骤:1. 统计字符频率:读取待编码的数据流,统计每个字符的频率,并构建字符频率表。

2. 构建哈夫曼树:根据字符频率表构建哈夫曼树。

可以使用最小堆来选择两个最小频率的节点进行合并,直至构建出完整的哈夫曼树。

3. 生成哈夫曼编码表:通过遍历哈夫曼树的路径,生成每个字符对应的哈夫曼编码。

可以使用递归算法或迭代算法来实现。

4. 压缩数据:根据生成的哈夫曼编码表,将原始数据中的每个字符替换为对应的编码。

同时,需要记录编码后数据的长度和哈夫曼编码表,以便解码时使用。

5. 解压缩数据:根据哈夫曼编码表,将编码后的数据解码为原始数据。

在实际应用中,哈夫曼编码通常用于对文本文件、图像、音频等数据进行压缩。

数字图像处理中的图像压缩算法

数字图像处理中的图像压缩算法

数字图像处理中的图像压缩算法随着科技和计算机技术的不断发展,数字图像处理成为了一个非常重要的领域。

数字图像处理技术广泛应用于各个领域,如图像储存、通信、医疗、工业等等。

在大量的图像处理中,图像压缩算法是非常关键的一环。

本文将介绍一些数字图像处理中的图像压缩算法。

一、无损压缩算法1. RLE 算法RLE(Run Length Encoding)算法是常见的图像无损压缩算法之一,它的主要思想是将连续的像素值用一个计数器表示。

比如将连续的“aaaa”压缩成“a4”。

RLE 算法相对比较简单,适用于连续的重复像素值较多的图像,如文字图片等。

2. Huffman 编码算法Huffman 编码算法是一种将可变长编码应用于数据压缩的算法,主要用于图像无损压缩中。

它的主要思想是将频率较高的字符用较短的编码,频率较低的字符用较长的编码。

将编码表储存在压缩文件中,解压时按照编码表进行解码。

Huffman 编码算法是一种效率较高的无损压缩算法。

二、有损压缩算法1. JPEG 压缩算法JPEG(Joint Photographic Experts Group)压缩算法是一种在有损压缩中广泛应用的算法。

该算法主要是针对连续色块和变化缓慢的图像进行处理。

JPEG 压缩算法的主要思想是采用离散余弦变换(DCT)将图像分割成小块,然后对每个小块进行频率分析,去除一些高频信息,再进行量化,最后采用 Huffman 编码进行压缩。

2. MPEG 压缩算法MPEG(Moving Picture Experts Group)压缩算法是一种针对视频压缩的算法,它主要是对视频序列中不同帧之间的冗余信息进行压缩。

该算法采用了空间域和时间域的压缩技术,包括分块变换编码和运动补偿等方法。

在分块变换编码中,采用离散余弦变换或小波变换来对视频序列进行压缩,再通过运动估计和补偿等方法,去除冗余信息。

三、总结数字图像处理中的图像压缩算法有很多种,其中无损压缩算法和有损压缩算法各有特点。

哈夫曼编码压缩c语言

哈夫曼编码压缩c语言

哈夫曼编码压缩c语言
哈夫曼编码是一种常用的数据压缩算法,也是一种非常基础的数
据结构。

它以出现频率为基础来构建编码表,将出现频率较高的字符
用较短的编码来表示,而出现频率较低的字符用较长的编码表示,从
而实现对数据的高效压缩。

在哈夫曼编码中,编码表的构建是非常关键的一步。

它需要统计
每个字符在数据中出现的频率,并且构建一棵哈夫曼树,从而得到每
个字符的编码。

具体的,哈夫曼树是一棵满足以下条件的二叉树:叶
节点代表每个字符,非叶节点代表编码,树的根节点代表整个编码表。

在哈夫曼树中,左子树代表编码的“0”位,右子树代表编码的“1”位。

一旦构建好了哈夫曼树,数据的压缩就非常简单了。

对于每个字符,将其对应的编码拼接起来即可。

因为哈夫曼编码是以出现频率为
基础的,所以出现频率较高的字符的编码较短,其压缩后的数据也较短;而出现频率较低的字符的编码较长,其压缩后的数据也较长。


样就实现了对数据的高效压缩。

在实际应用中,哈夫曼编码被广泛应用于数据压缩。

比如在通信
领域,它常被用于网络传输和存储;在计算机领域,它被用于文件压
缩和解压缩。

在这些应用中,哈夫曼编码可以帮助我们节省大量的存
储空间和网络带宽,从而提高通信和存储的效率。

总之,哈夫曼编码是一种非常重要的算法,在数据压缩和存储领
域都有着广泛的应用。

掌握哈夫曼编码可以帮助我们更好地理解数据
压缩的原理和实现方法,从而开发出更加高效的数据压缩算法和应用。

基于哈弗曼编码的数据压缩C语言实现

基于哈弗曼编码的数据压缩C语言实现

摘要数据压缩技术是一项重要实用的信息技术。

信息时代的到来,信息量迅速增长,使得数据压缩也显得越来越重要。

数据压缩有多种编码方法,大致可分为无损压缩编码和有损压缩编码。

其中,Huffman 编码是第一个实用的无损压缩编码技术,经过了多年的不断改进,已经形成了系统的理论和方法。

目前主要有两种类型的Huffman编码方式,即静态Huffman编码和动态Huffman编码。

Huffman编码有着广泛的应用,但是不再是压缩算法的全部,而是被当作最终的编码方法。

本文首先介绍了数据压缩的发展历史和数据压缩的基本原理,然后介绍了Huffman编码的原理和算法,并用C语言来实现哈夫曼算法。

关键词: 数据压缩,Huffman编码,动态Huffman编码ABSTRACTData compression is a very important and practical information technology. In the information age, data compression technology becomes more and more important because of the rapid growth of the quantity of information. There are many coding methods of data compression, substantially, can be divided into lossless and lossy compression coding. Huffman coding is the first practical lossy compression coding technology. After many years of continuous improvement, it has formed a system of the theory and method. Currently there are two major types of Huffman coding, static Huffman coding and dynamic Huffman coding. Huffman coding has extensive applications, which is no longer the all of the compression algorithm, but to be the final coding method.Firstly, this paper introduces the history and basic principles and methods of data compression, then introduces the theory and algorithm of huffman coding and using C language to implement it.KEY WORDS: data compression, Huffman coding, dynamic Huffman coding第一章绪论数据压缩技术早在计算机技术的萌芽时期就已经受到了足够的重视,信息论的产生和发展, 也使数据压缩技术由热门话题演变成真正的应用技术。

huffman编码的基本原理和步骤

huffman编码的基本原理和步骤

Huffman编码是一种常用的数据压缩算法,它通过对字符进行变长编码来实现数据的高效压缩。

本文将从基本原理和步骤两个方面来深入探讨Huffman编码。

一、基本原理Huffman编码的基本原理是根据待编码的字符在数据中出现的频率来构建不同长度的编码,频率越高的字符使用较短的编码,频率越低的字符使用较长的编码。

这样可以实现对常用字符的高效编码,从而实现数据的有效压缩。

在实际应用中,Huffman编码通常用于无损数据压缩,例如在通信领域、文件压缩领域等都有广泛的应用。

通过Huffman编码,可以大大减小数据的传输和存储成本,提高数据的传输效率,是一种非常重要的数据压缩算法。

二、步骤要实现Huffman编码,需要按照以下步骤进行:1. 统计字符出现的频率。

首先需要对待编码的数据进行扫描,统计每个字符在数据中出现的频率。

2. 构建Huffman树。

根据字符的频率构建Huffman树,频率越高的字符在树中的位置越靠近根节点,频率越低的字符在树中的位置越靠近叶子节点。

3. 生成Huffman编码。

根据构建的Huffman树,可以得出每个字符对应的Huffman编码,即根据字符在树中的位置来确定编码,从根节点到叶子节点的路径上的0和1分别代表不同的编码。

4. 进行数据编码。

根据生成的Huffman编码,可以对待编码的数据进行编码,将原始数据中的字符替换为对应的Huffman编码。

5. 进行数据解码。

接收方可以根据相同的Huffman树和编码规则来对接收到的数据进行解码,恢复出原始的数据。

总结回顾通过对Huffman编码的基本原理和步骤进行全面评估,我们可以深入地理解Huffman编码的工作原理和实现方法。

Huffman编码通过对字符出现频率的统计和树的构建来实现对数据的高效压缩,从而节省存储和传输成本,提高数据的传输效率。

在实际应用中,Huffman编码被广泛应用于数据压缩领域,为数据的高效管理和利用提供了重要支持。

huffman编码,可实现压缩功能

huffman编码,可实现压缩功能

#include<iostream>using namespace std;#include<iomanip>#include<fstream>#include<cstdlib>typedef struct Point{int parent;int weight;int left;int right;}POINT;class HUFFMAN{private:char Filech[258];POINT point[512]; //point[0]留作判断是否已经到文件的末尾了int root;char code[258][16];public:HUFFMANInit(char filename[]) //对huffman树进行一些初始化的操作{char ch;int i;for(i=0;i<512;i++){if(i<258)Filech[i]='\0';point[i].parent=point[i].weight=point[i].left=point[i].right=0;}Filech[0]=0;root=0;fstream FILE;FILE.open(filename,ios::in);if(!FILE){cout<<"打开文件失败"<<endl;exit(0);}while(!FILE.eof()){FILE.get(ch);if(FILE.fail())break;for(i=0;i<=strlen(Filech+1);i++){if(Filech[i]==ch){point[i].weight++;break;}}if(i==strlen(Filech+1)+1){Filech[i]=ch;point[i].weight++;}}buildhuffman();char s[2]="\0";gaincode(root,s);fstream FILEOUT; //将每个字符对应的二进制输出到文件中去FILEOUT.open("code.txt",ios::out);for(i=0;i<=strlen(Filech+1);i++){FILEOUT<<Filech[i]<<" "<<code[i]<<endl;}/* cout<<"各个字符在重新编码以后的码制:"<<endl; //输出各个字符在重新编码后的码制for(i=0;i<=strlen(Filech+1);i++)cout<<Filech[i]<<" "<<code[i]<<endl;for(i=1;i<=strlen(Filech+1);i++) //输出各个字符在统计之后的所占的比重cout<<i<<": "<<Filech[i]<<" "<<point[i].weight<<endl;*/}void buildhuffman() //构建huffman树{int compare[2][2];int i,j;int length;length=strlen(Filech+1);for(i=0;i<strlen(Filech+1);i++){compare[0][1]=compare[0][0]=0;compare[1][0]=compare[1][1]=0x7fffffff;for(j=0;j<=length;j++){if(!point[j].parent&&point[j].weight<compare[1][1]){if(point[j].weight<compare[1][0]){compare[0][1]=compare[0][0];compare[1][1]=compare[1][0];compare[0][0]=j;compare[1][0]=point[j].weight;}else{compare[0][1]=j;compare[1][1]=point[j].weight;}}}length++;point[compare[0][0]].parent=length;point[compare[0][1]].parent=length;point[length].left=compare[0][0];point[length].right=compare[0][1];point[length].weight=compare[1][0]+compare[1][1];}root=length;/* cout<<" 序号:父节点:左孩子:右孩子:比重:"<<endl;for(i=0;i<=root;i++)cout<<setw(4)<<i<<setw(8)<<point[i].parent<<setw(8)<<point[i].left<<setw(9)<<point[i].righ t<<setw(10)<<point[i].weight<<endl;*/}void gaincode(int address,char ch[]){if(point[address].left||point[address].right){int i=strlen(ch);char temp1[16];char temp2[16];strcpy(temp1,ch);strcpy(temp2,ch);temp1[i+1]='\0';temp1[i]='0';temp2[i+1]='\0';temp2[i]='1';gaincode(point[address].left,temp1);gaincode(point[address].right,temp2);}elsestrcpy(code[address],ch);}void jiami(char filename[],char fileoutname[]) //对文件进行编码后输出{fstream FileIn;fstream FileOut;FileIn.open(filename,ios::in);if(!FileIn){cout<<"打开文件失败"<<endl;exit(0);}FileOut.open(fileoutname,ios::out|ios::binary);if(!FileOut){cout<<"打开文件失败"<<endl;exit(0);}char ch;int num=0;int i=0,j,k;while(!FileIn.eof()){FileIn.get(ch);if(FileIn.fail())break;for(k=1;k<=strlen(Filech+1);k++)if(Filech[k]==ch)break;for(j=0;j<strlen(code[k]);j++){num<<=1;i++;if(code[k][j]=='1')num|=1;if(i==32){FileOut.write((char *)&num,sizeof(num));i=0;num=0;}}}for(j=0;j<strlen(code[0]);j++){num<<=1;i++;if(code[0][j]=='1')num|=1;if(i==32){FileOut.write((char *)&num,sizeof(num));i=0;num=0;}}if(i){num<<=32-i;FileOut.write((char *)&num,sizeof(num));}FileIn.close();FileOut.close();}void readFile(char filename[],char fileoutnmae[]) //将加密后的文件解密{fstream dataFileIn,dataFileOut;int i,j;int judge;int num;dataFileIn.open(filename,ios::in|ios::binary);if(!dataFileIn){cout<<"打开文件失败"<<endl;exit(0);}dataFileOut.open(fileoutnmae,ios::out);if(!dataFileOut){cout<<"打开文件失败"<<endl;exit(0);}j=root;while(!dataFileIn.eof()){dataFileIn.read((char *)&num,sizeof(num));if(dataFileIn.fail())break;for(i=31;i>=0;i--){if(point[j].left||point[j].right){judge=(num>>i)&1;if(judge)j=point[j].right;elsej=point[j].left;}else{i++;if(j==0)break;else{//cout<<Filech[j];dataFileOut.put(Filech[j]);j=root;}}}}}};。

基于哈夫曼(haffuman)算法的文件压缩的实现(C语言)(转)

基于哈夫曼(haffuman)算法的文件压缩的实现(C语言)(转)

基于哈夫曼(haffuman)算法的⽂件压缩的实现(C语⾔)(转)本⽂⾸先简要阐述哈夫曼算法的基本思想,然后介绍了使⽤哈夫曼算法进⾏⽂件压缩和解压缩的处理步骤,最后给出了C语⾔实现的⽂件压缩和解压缩的源代码。

哈夫曼算法的主要思想是:①⾸先遍历要处理的字符串,得到每个字符的出现的次数;②将每个字符(以其出现次数为权值)分别构造为⼆叉树(注意此时的⼆叉树只有⼀个节点);③取所有⼆叉树种种字符出现次数最⼩的⼆叉树合并为⼀颗新的⼆叉树,新⼆叉树根节点的权值等于两个⼦节点的权值之和,新节点中的字符忽略;④重复过程③直到所有树被合并为同⼀棵⼆叉树⑤遍历最后得到的⼆叉树,⾃顶向下按路径编号,指向左节点的边编号0,指向右节点的边编号1,从根到叶节点的所有边上的0和1链接起来,就是叶⼦节点中字符的哈夫曼编码。

下图展⽰了哈夫曼编码的基本思想。

基于哈夫曼算法的⽂件压缩和解压缩过程分别说明如下:⼀、⽂件压缩:①统计词频:读取⽂件的每个字节,使⽤整数数组int statistic[MAX_CHARS]统计每个字符出现的次数,由于⼀个字节最多表⽰2^8-1个字符,所以MAX_CHARS=256就⾜够了。

在统计字符数的时候,对于每⼀个byte, 有statistic[(unsigned char)byte] 。

②构造哈夫曼树:根据statistic数组,基于哈夫曼树算法造哈夫曼树,由于构造的过程中每次都要取最⼩权值的字符,所以需要⽤优先队列来维护每棵树的根节点。

③⽣成编码:深度优先遍历哈弗曼树,得到每个叶⼦节点中的字符的编码并存⼊字符串数组char*dictionary[MAX_CHARS];④存储词频:新建存储压缩数据的⽂件,⾸先写⼊不同字符的个数,然后将每个字符及其对应的词频写⼊⽂件。

⑤存储压缩数据:再次读取待压缩⽂件的每个字节byte,由dictionary[(unsigned int)byte]得到对应的编码(注意每个字符编码的长度不⼀),使⽤位运算⼀次将编码中的每个位(BIT)设置到⼀个char类型的位缓冲中,可能多个编码才能填满⼀个位缓冲,每填满⼀次,将位缓冲区以单个字节的形式写⼊⽂件。

huffman无损压缩编码实验报告

huffman无损压缩编码实验报告

无损压缩编码(huffman编码)实验报告作者: 计一飞学号:1004210228学院(系):电子工程与光电技术学院专业: 电子信息工程题目: 无损压缩编码指导老师:康其桔摘要本文介绍了无损压缩编码中的霍夫曼(huffman)编码。

Huffman 编码是可变字长编码的一种,该方法完全依据字符出现概率来构造最优二叉树(huffman树),故有时又称为最佳编码。

在文中,我们使用C++语言进行编码,从下到上进行了熵编码。

关键词:huffman、最优二叉树、熵编码、C++AbstractThe huffman (Huffman) coding of Lossless coding were introduced in this paper . Huffman coding is a kind of variable-word- length coding.The method is completely based on the characters appear probability to construct the optimal binary tree (Huffman tree), so it is sometimes referred to as the optimal coding. In this paper, we use c + + language to code, from bottom to top in the entropy coding.Key words: huffman、optimal binary tree、entropy coding、C++一、实验目的1、理解无损压缩编码的优点和意义。

2、理解树、二叉树、huffman树的概念。

3、学会二叉树的C++编程,进行熵编码。

二、实验步骤步骤①:按照符号出现概率大小的顺序对符号进行排序。

步骤②:把概率最小的两个符号组成一个节点P1。

数字图像处理课程设计--Huffman编码理论及算法实现

数字图像处理课程设计--Huffman编码理论及算法实现

数字图像处理课程设计课程题目 Huffman编码原理及算法实现Huffman编码理论及算法实现一、基本介绍霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现机率的方法得到的,出现机率高的字母使用较短的编码,反之出现机率低的则使用较长的编码,这便使编码之后的字符串的平均长度、期望值降低,从而达到无损压缩数据的目的。

霍夫曼树又称最优二叉树,是一种带权路径长度最短的二叉树。

所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。

树的路径长度是从树根到每一结点的路径长度之和,记为WPL=(W1*L1+W2*L2+W3*L3+...+Wn*Ln)N个权值Wi(i=1,2,...n)构成一棵有N个叶结点的二叉树,相应的叶结点的路径长度为Li(i=1,2,...n)。

可以证明霍夫曼树的WPL是最小的。

输入符号集合S={s1,s2,···,Sn},其S集合的大小为n。

权重集合W={w1,w2,···,Wn},其W集合不为负数且Wi=weight(Si),1 ≤ i ≤ n。

输出一组编码C(S,W)={c1,c2,···Cn},其C集合是一组二进制编码且Ci为Si相对应的编码,1 ≤ i ≤ n。

霍夫曼树常处理符号编写工作。

根据整组数据中符号出现的频率高低,决定如何给符号编码。

如果符号出现的频率太高,则给符号的码越短,相反符号的号码越长。

假设我们要给一个英文单字"F O R G E T"进行霍夫曼编码,而每个英文字母出现的频率。

二、演算过程(一)进行霍夫曼编码前,我们先创建一个霍夫曼树。

⒈将每个英文霍夫曼树字母依照出现频率由小排到大,最小在左。

⒉每个字母都代表一个终端节点(叶节点),比较F.O.R.G.E.T五个字母中每个字母的出现频率,将最小的两个字母频率相加合成一个新的节点。

哈夫曼编码的压缩原理

哈夫曼编码的压缩原理

哈夫曼编码的压缩原理哈夫曼编码是一种常用的数据压缩算法,旨在通过消除数据中的冗余信息来减小文件的大小,从而提高文件的传输速度和存储效率。

本文将介绍哈夫曼编码的原理和实现方式。

一、哈夫曼编码的基本原理哈夫曼编码的基本原理是根据待压缩数据中字符的出现频率,对不同的字符进行编码,使得出现频率较高的字符对应的编码较短,而出现频率较低的字符对应的编码较长。

这样,在压缩后的数据中,出现频率较高的字符所占空间较小,从而实现了数据的压缩。

具体步骤如下:1. 统计待压缩数据中不同字符的出现频率。

2. 将每个字符及其出现频率构建成一个字符频率表。

3. 创建一个哈夫曼树,该树的叶节点对应字符频率表中的字符,其权值对应字符的出现频率。

4. 通过哈夫曼树,可以得到每个字符对应的唯一编码。

编码的生成过程是从根节点开始,每次向左走为0,向右走为1,直到叶节点。

5. 将字符频率表及对应的编码存储在压缩文件中,以便解压时能正确还原原始数据。

6. 遍历待压缩数据,将每个字符对应的编码替换成相应的比特流。

7. 将替换后的比特流存储在压缩文件,即得到了压缩后的数据。

二、哈夫曼编码的实现方式哈夫曼编码的实现方式通常有两种:静态哈夫曼编码和动态哈夫曼编码。

1.静态哈夫曼编码静态哈夫曼编码是指在压缩前已知待压缩数据中各字符的出现频率,并根据这些频率进行编码。

由于在压缩时需要将字符频率表存储在压缩文件中,因此适用于压缩小文件或者数据不经常变化的情况。

2.动态哈夫曼编码动态哈夫曼编码是指在压缩过程中动态地调整字符频率表,并根据动态变化的频率重新构建哈夫曼树和编码。

相比静态哈夫曼编码,动态哈夫曼编码不需要存储字符频率表,因此适用于压缩大文件或者数据频率变化较大的情况。

三、哈夫曼编码的优势1. 高效的压缩率:哈夫曼编码根据字符的出现频率进行编码,使得频率较高的字符能够用较少的比特表示,从而大幅度减小了文件的大小,提高了存储和传输效率。

2. 无损压缩:哈夫曼编码是一种无损压缩算法,可以完整地还原原始数据,不会造成信息的损失。

C++实现Huffman的编解码

C++实现Huffman的编解码

C++实现Huffman的编解码Huffman编码主要是通过统计各元素出现的频率,进⽽⽣成编码最终达到压缩的⽬的。

这⾥是Huffman树中节点的结构。

typedef struct Tree{int freq;//频率int key;//键值struct Tree *left, *right;Tree(int fr=0, int k=0,Tree *l=nullptr, Tree *r=nullptr):freq(fr),key(k),left(l),right(r){};}Tree,*pTree;⾸先⽤⼀个名为freq的hashtable来记录各个元素的频率:void read(){int a;std::ios::sync_with_stdio(false);while(cin>>a){if(freq.find(a)==freq.end()) {freq[a]=1;}else {freq[a]++;}}}Huffman树的构建过程如下代码所⽰:void huffman(){int i;string c;int fr;auto it = freq.begin();while(it!=freq.end()){Tree *pt= new Tree;pt->key = it->first;pt->freq = it->second;it++;th.Insert(pt);//此处的th为⼀种优先队列}while(true)//构建哈夫曼树{Tree *proot = new Tree;pTree pl,pr;pl = th.findMin();th.Delete(0);if(th.isEmpty()){th.Insert(pl);break;}pr = th.findMin();th.Delete(0);//合并节点proot->freq = pl->freq + pr->freq;std::ios::sync_with_stdio(false);proot->left = pl;proot->right = pr;th.Insert(proot);//合并后再插⼊}string s;print_Code(th.findMin(), s);del(th.findMin());}其中print_Code和del函数如下:void print_Code(Tree *proot, string st)//从根节点开始打印,左0右1{if(proot == NULL)return ;if(proot->left){st +='0';}print_Code(proot->left, st);std::ios::sync_with_stdio(false);if(!proot->left && !proot->right){cout<<proot->key<<" ";for(size_t i=0; i<st.length(); ++i){cout<<st[i];ml+=st[i];}cout<<endl;encoded[proot->key]=ml;ml="";}st.pop_back();if(proot->right)st+='1';print_Code(proot->right, st);}void del(Tree *proot){if(proot == nullptr)return ;del(proot->left);del(proot->right);delete proot;}⾄此就完成了Huffman的编码。

Huffman编码与解码实现文件压缩与解压

Huffman编码与解码实现文件压缩与解压

数据结构课程设计报告Huffman编码与解码实现文件压缩与解压学号:06080711姓名:李爱武指导教师:陈波二○一零年九月三日目录目录 (2)目标任务和问题分析 (3)算法及思想描述 (3)---------建立哈夫曼树、压缩、解压缩程序结构及测试流程 (5)测试结果分析 (12)收获与体会 (12)参考文献 (13)Huffman编码与解码实现文件压缩与解压一、目标任务与问题分析1.1目标任务采用哈夫曼编码思想实现文件的压缩和解压缩功能,可以将任意文件压缩成任意的压缩文件类型,并且能将压缩后的文件解压成相应的源文件。

1.2问题分析本问题首先应该是利用哈夫曼思想,对需要压缩的文件中的个字符进行频率统计,为了能对任意的文件进行处理,应该所有的文件以二进制的方式进行处理,即对文件(不管包含的是字母还是汉字)采取一个个的字节(unsigned char)处理,然后根据统计的频率结果构造哈夫曼树,然后对每个字符进行哈夫曼编码,然后逐一对被压缩的文件的每个字符构建的新的哈夫曼编码存入新的文件中即得到的压缩文件。

解压过程则利用相应的哈夫曼树及压缩文件中的二进制码将编码序列译码,对文件进行解压,得到解压文件。

二、算法思想描述2.1 构造哈夫曼树要利用哈夫曼编码对文本文件进行压缩,首先必须知道期字符相应的哈夫曼编码。

为了得到文件中字符的频率,一般的做法是扫描整个文本进行统计,编写程序统计文件中各个字符出现的频率。

由于一个字符的范围在[0-255]之间,即共256个状态,所以可以直接用256个哈夫曼树节点即数组(后面有节点的定义)空间来存储整个文件的信息,节点中包括对应字符信息,其中包括频率。

2.1.1 哈夫曼树节点的设计用结构体NODE来存储节点的信息,其中有成员频率weight、父节点parent、左枝节点lchild、右枝节点rchild、对应的编码code。

2.1.2文件字符频率处理由于所有的文件都采用字节存取,字符的最多个数就只能是256个,即ASCII码在0-255之间,而我们用的是数组来存储文件的信息,我们用NODE[256]来统计文件的所有信息。

数据压缩算法---霍夫曼编码的分析与实现

数据压缩算法---霍夫曼编码的分析与实现

数据压缩算法---霍夫曼编码的分析与实现霍夫曼编码是⼀种基于最⼩冗余编码的压缩算法。

最⼩冗余编码是指,如果知道⼀组数据中符号出现的频率,就可以⽤⼀种特殊的⽅式来表⽰符号从⽽减少数据需要的存储空间。

⼀种⽅法是使⽤较少的位对出现频率⾼的符号编码,⽤较多的位对出现频率低的符号编码。

我们要意识到,⼀个符号不⼀定必须是⽂本字符,它可以是任何⼤⼩的数据,但往往它只占⼀个字节。

熵和最⼩冗余每个数据集都有⼀定的信息量,这就是所谓的熵。

⼀组数据的熵是数据中每个符号熵的总和。

符号z的熵S定义为:S z = -lg2 P z其中,P z就数据集中z出现的频率。

来看⼀个例⼦,如果z在有32个符号的数据集中出现了8次,也就是1/4的概率,那么z的熵就是:-lg 2(1/4) = 2位这意味着如果⽤超过两位的数来表⽰z将是⼀种浪费。

如果在⼀般情况下⽤⼀个字节(即8位)来表⽰⼀个符号,那么在这种情况下使⽤压缩算法可以⼤幅减⼩数据的容量。

下表展⽰如何计算⼀个有72个数据实例熵的例⼦(其中有5个不同的符号)。

要做到这⼀点,需将每个字符的熵相加。

以U为例,它在数据集中出现了12次,所以每个U的实例的熵计算如下:符号概率每个实例的熵总的熵U12/72 2.584 96331.019 55V18/72 2.000 00036.000 00W7/72 3.362 57023.537 99X15/72 2.263 03433.945 52Y20/72 1.847 99736.959 94-lg2(12/72) = 2.584 963 位由于U在数据中出现了12次,因此整个数据的熵为:2.584 963 * 12 = 31.019 55 位为了计算数据集整体的熵,将每个字符所贡献的熵相加。

每个字符的熵在表中已经计算出来了:31.019 55 + 36.000 00 + 23.537 99 + 33.945 52 + 36.959 94 = 161.463 00 位如果使⽤8位来表⽰每个符号,需要72 * 8 = 576位的空间,所以理论上来说,可以最多将此数据压缩:1 - (161.463 000/576) = 72%构造霍夫曼树霍夫曼编码展现了⼀种基于熵的数据近似的最佳表现形式。

哈夫曼编解码压缩解压文件—C++实现

哈夫曼编解码压缩解压文件—C++实现

哈夫曼编解码压缩解压⽂件—C++实现前⾔哈夫曼编码是⼀种贪⼼算法和⼆叉树结合的字符编码⽅式,具有⼴泛的应⽤背景,最直观的是⽂件压缩。

本⽂主要讲述如何⽤哈夫曼编解码实现⽂件的压缩和解压,并给出代码实现。

哈夫曼编码的概念哈夫曼树⼜称作最优树,是⼀种带权路径长度最短的树,⽽通过哈夫曼树构造出的编码⽅式称作哈夫曼编码。

也就是说哈夫曼编码是⼀个通过哈夫曼树进⾏的⼀种编码,⼀般情况下,以字符 “0” 与 “1” 表⽰。

编码的实现过程很简单,只要实现哈夫曼树,通过遍历哈夫曼树,这⾥我们从根节点开始向下遍历,如果下个节点是左孩⼦,则在字符串后⾯追加 “0”,如果为其右孩⼦,则在字符串后追加 “1”。

结束条件为当前节点为叶⼦节点,得到的字符串就是叶⼦节点对应的字符的编码。

哈夫曼树实现根据贪⼼算法的思想实现,把字符出现频率较多的字符⽤稍微短⼀点的编码,⽽出现频率较少的字符⽤稍微长⼀点的编码。

哈夫曼树就是按照这种思想实现,下⾯将举例分析创建哈夫曼树的具体过程。

下⾯表格的每⼀⾏分别对应字符及出现频率,根据这些信息就能创建⼀棵哈夫曼树。

字符出现频率编码总⼆进制位数a5001500b25001500c120001360d600001240e3000001150f2000000100如下图,将每个字符看作⼀个节点,将带有频率的字符全部放到优先队列中,每次从队列中取频率最⼩的两个节点 a 和b(这⾥频率最⼩的 a 作为左⼦树),然后新建⼀个节点R,把节点设置为两个节点的频率之和,然后把这个新节点R作为节点A和B的⽗亲节点。

最后再把R放到优先队列中。

重复这个过程,直到队列中只有⼀个元素,即为哈夫曼树的根节点。

由上分析可得,哈夫曼编码的需要的总⼆进制位数为 500 + 500 + 360 + 240 + 150 + 100 = 1850。

上⾯的例⼦如果⽤等长的编码对字符进⾏压缩,实现起来更简单,6 个字符必须要 3 位⼆进制位表⽰,解压缩的时候每次从⽂本中读取 3 位⼆进制码就能翻译成对应的字符,如 000,001,010,011,100,101 分别表⽰a,b,c,d,e,f。

用C++实现Huffman文件编码和解码

用C++实现Huffman文件编码和解码

这个是代码是昨天写完的,一开始的时候还出了点小bug,这个bug在晚上去吃饭的路上想明白的,回来更改之后运行立刻完成最后一步,大获成功。

简单说下huffman编码和文件压缩主要的技术。

Huffman编码,解码:I 创建Huffman树II 根据Huffman树实现编码,并将编码结果和要编码的数据建立映射关系。

III Huffman解码,也就是根据获取的Huffman码来逆向获取解码信息,而且你从解压文件中一次性获取的数据是一个很长的字符串,没有预处理好的成段字符串式Huffman码。

1I 首先,如何创建Huffman树?在这个我在前天的那篇文章中简单的提了一下,现在好好说一下。

如果你不知道什么是Huffman树,请google之~对于获取到的文件,首先要做的就是,建立一个长度为256的int数组,全部置零,然后以字节流的形式读取文件,并对字节流中的字节出现次数进行统计,方法就是以字节数值为数组偏移地址,对应的数组元素进行+1操作。

另外这里需要提一下的就是,用于存储文件字节流的缓冲区最好是unsigned char类型,因为这样能直接使用,如果是char的,在转化为int类型的时候,一旦数值大于127,因为补码问题,你就直接乘上了通往未知数值的高铁~完成统计之后,将这个数组中出现次数不为0的元素添加对应大小的二叉树节点数组中,然后以出现次数为Key值,进行排序。

在排序完成之后,就能开始构建Huffman树了。

操作如下:1 如果数组中元素个数不为1,将前两个元素构造为一个临时节点的子树,此时临时节点的Key值为两个元素Key值之和,然后删除数组中的第一个元素(从数组中删除),再将临时节点赋值给当前数组的第一个元素。

(其实就是将前两个元素添加到一个临时节点的左右根节点,然后在原数组中删除这两个元素,,接着再将这个临时节点插入到数组头部,充当新的节点。

上面的那段描述我觉得说的不是很清楚,但是那个是我在代码中发现的一个可以优化的地方,减少了一个元素的删除操作)2 此时数组依据key值的排序很有可能已经不再有序,而又因为仅有一个乱序元素,所以专门设计了一个函数,一次完成排序,效率,应该是最高的了。

数字图像处理中的Huffman编码压缩C++实现

数字图像处理中的Huffman编码压缩C++实现

数字图像处理中的Huffman编码压缩C++实现
刘光灿;刘简达
【期刊名称】《光电技术应用》
【年(卷),期】2004(19)5
【摘要】介绍了用C++实现数字图像处理中的Huffman编码压缩的技术细节,包括总流程,数据结构,编码原理,索引建立,文件写入和解压缩.最后还论述了Huffman 压缩以及字典压缩的优缺点.
【总页数】5页(P17-20,24)
【作者】刘光灿;刘简达
【作者单位】长沙学院,湖南,长沙,410003;上海交通大学,上海,200240
【正文语种】中文
【中图分类】TP274+.2
【相关文献】
1.用Huffman编码对文件进行压缩的C语言实现 [J], 路炜;门玉梅;李建俊
2.结合Huffman编码和 SPIHT算法实现高效图像压缩方法 [J], 张倩妮;刘昌华
3.基于Huffman编码的XML文件压缩存储算法研究与实现 [J], 周伟
4.基于Huffman编码的XML文件压缩存储算法研究与实现 [J], 周伟
5.结合Huffman编码和SPIHT算法实现高效图像压缩方法 [J], 张倩妮;刘昌华因版权原因,仅展示原文概要,查看原文内容请购买。

用哈夫曼编码C语言实现文件压缩

用哈夫曼编码C语言实现文件压缩

《用哈夫曼编码实现文件压缩》实验报告课程名称数据结构B实验学期2012 至2013 学年第一学期学生所在系部计算机学院年级2011 专业班级信管B111学生姓名学号任课教师兰芸实验成绩用哈夫曼编码实现文件压缩1、了解文件的概念。

2、掌握线性链表的插入、删除等算法。

3、掌握Huffman树的概念及构造方法。

4、掌握二叉树的存储结构及遍历算法。

5、利用Huffman树及Huffman编码,掌握实现文件压缩的一般原理。

微型计算机、Windows 系列操作系统、Visual C++6.0软件根据ascii码文件中各ascii字符出现的频率情况创建Haffman树,再将各字符对应的哈夫曼编码写入文件中,实现文件压缩。

(1)构造Hufffman树的方法—Hufffman算法构造Huffman树步骤:I.根据给定的n个权值{w1,w2,……wn},构造n棵只有根结点的二叉树,令起权值为wj。

II.在森林中选取两棵根结点权值最小的树作左右子树,构造一棵新的二叉树,置新二叉树根结点权值为其左右子树根结点权值之和。

III.在森林中删除这两棵树,同时将新得到的二叉树加入森林中。

IV.重复上述两步,直到只含一棵树为止,这棵树即哈夫曼树。

(2)Huffman编码:数据通信用的二进制编码思想:根据字符出现频率编码,使电文总长最短编码:根据字符出现频率构造Huffman树,然后将树中结点引向其左孩子的分支标“0”,引向其右孩子的分支标“1”;每个字符的编码即为从根到每个叶子的路径上得到的0、1序列。

(3) 解压根据存放在文件中的编码表和文件压缩后的编码,进行一对一的翻译过程。

压缩的代码#include <stdio.h>#include <string.h>#include <stdlib.h>#include <conio.h>struct head{unsigned char b; /*the charactor*/long count; /*the frequency*/long parent,lch,rch; /*make a tree*/char bits[256]; /*the haffuman code*/}header[512],tmp;void yasuo() /*压缩*/{char filename[255],outputfile[255],buf[512];unsigned char c; char wenjianming[255];long i,j,m,n,f;long min1,pt1,flength;FILE *ifp,*ofp;printf("输入文件地址及文件名:");gets(filename);ifp=fopen(filename,"rb"); /*打开源文件*/while(ifp==NULL){ printf("打开文件出错\n");printf("重新输入文件地址及文件名");gets(filename);ifp=fopen(filename,"rb");}printf("输入压缩后的文件地址和文件名及后缀:");gets(wenjianming);ofp=fopen(wenjianming,"wb"); /*创建并打开目的文件*/ while(ofp==NULL){printf("重新输入压缩后的文件地址和文件名及后缀:");ofp=fopen(wenjianming,"wb");}flength=0;while(!feof(ifp)) /*读取ifp文件*/{fread(&c,1,1,ifp); /*按位读取*/header[c].count++;flength++;}flength-1;header[c].count-1; /*读取文件结束*/for(i=0;i<512;i++) /*构造哈弗曼树*/{if(header[i].count!=0)header[i].b=(unsigned char)i;elseheader[i].b=0;header[i].parent=-1;header[i].lch=header[i].rch=-1;}for(i=0;i<256;i++){for(j=i+1;j<256;j++){if(header[i].count<header[j].count){tmp=header[i];header[i]=header[j];header[j]=tmp;}}}for(i=0;i<256;i++)if(header[i].count==0)break;n=i;m=2*n-1;for(i=n;i<m;i++){min1=999999999;for(j=0;j<i;j++){if(header[j].parent!=-1)continue;if(min1>header[j].count){pt1=j;min1=header[j].count;continue;}}header[i].count=header[pt1].count;header[pt1].parent=i;header[i].lch=pt1;min1=999999999;for(j=0;j<i;j++){if(header[j].parent!=-1)continue;if(min1>header[j].count){pt1=j;min1=header[j].count;continue;}}header[i].count+=header[pt1].count;header[i].rch=pt1;header[pt1].parent=i;}for(i=0;i<n;i++){f=i;header[i].bits[0]=0;while(header[f].parent!=-1){j=f;f=header[f].parent;if(header[f].lch==j){j=strlen(header[i].bits);memmove(header[i].bits+1,header[i].bits,j+1);header[i].bits[0]='0';}else{j=strlen(header[i].bits);memmove(header[i].bits+1,header[i].bits,j+1);header[i].bits[0]='1';}}} /*哈弗曼构造结束*/fseek(ifp,0,SEEK_SET); /*把文件指针指向文件的开头*/ fwrite(&flength,sizeof(int),1,ofp); //把哈弗曼代码写入ofp文件fseek(ofp,8,SEEK_SET);buf[0]=0;f=0;pt1=8;while(!feof(ifp)){c=fgetc(ifp); //从流中读取一个字符,并增加文件指针的位置f++;for(i=0;i<n;i++){if(c==header[i].b) break;}strcat(buf,header[i].bits); //把header[i].bits所指字符串添加到buf结尾处j=strlen(buf); //计算字符串buf的长度c=0;while(j>=8){for(i=0;i<8;i++){if(buf[i]=='1') c=(c<<1)|1;else c=c<<1;}fwrite(&c,1,1,ofp);pt1++;strcpy(buf,buf+8);j=strlen(buf);}if(f==flength)break;}if(j>0){strcat(buf,"00000000");for(i=0;i<8;i++){if(buf[i]=='1') c=(c<<1)|1;else c=c<<1;}fwrite(&c,1,1,ofp);pt1++;}fseek(ofp,4,SEEK_SET); /*fseek 用于二进制方式打开的文件,移动文件读写指针位置.第一个是文件流,第3个是指针零点位置,第2个是把指针移动到的地点. */ fwrite(&pt1,sizeof(long),1,ofp); /*是要输出数据的地址,每次写入的位数,数据项的个数,目标文件地址*/fseek(ofp,pt1,SEEK_SET);fwrite(&n,sizeof(long),1,ofp);for(i=0;i<n;i++){fwrite(&(header[i].b),1,1,ofp);c=strlen(header[i].bits);fwrite(&c,1,1,ofp);j=strlen(header[i].bits);if(j%8!=0) /*按八位读取*/{for(f=j%8;f<8;f++)strcat(header[i].bits,"0");}while(header[i].bits[0]!=0){c=0;for(j=0;j<8;j++){if(header[i].bits[j]=='1') c=(c<<1)|1;else c=c<<1;}strcpy(header[i].bits,header[i].bits+8); /*把从header[i].bits+8地址开始且含有NULL结束符的字符串赋值到以header[i].bits开始的地址空间*/fwrite(&c,1,1,ofp);}}fclose(ifp);fclose(ofp);printf("压缩成功\n");}void main() /*主函数*/{printf("输入a开始压缩\n");printf("输入b结束压缩\n");while(1){char c;c=getch();if(c=='a')yasuo();else{ if(c=='b')return;}}}压缩的图解解压的代码#include <stdio.h>#include <string.h>#include <stdlib.h>#include <conio.h>struct head{unsigned char b; /*the charactor*/long count; /*the frequency*/long parent,lch,rch; /*make a tree*/char bits[256]; /*the haffuman code*/}header[512],tmp;void jieya() /*解压*/ {char filename[255],outputfile[255],buf[255],bx[255];unsigned char c; char wenjianming[255];long i,j,m,n,f,p,l;long flength;FILE *ifp,*ofp;printf("要解压的文件:");gets(filename);ifp=fopen(filename,"rb"); /*打开源文件*/while(ifp==NULL){ printf("打开文件出错\n");printf("重新输入文件地址及文件名");gets(filename);ifp=fopen(filename,"rb");}printf("输入解压后的文件地址和文件名及后缀:");gets(wenjianming);ofp=fopen(wenjianming,"wb"); /*创建并打开目的文件*/ while(ofp==NULL){ofp=fopen("d:\\123\\解压的文件.txt","wb");}fread(&flength,sizeof(long),1,ifp);fread(&f,sizeof(long),1,ifp);fseek(ifp,f,SEEK_SET);fread(&n,sizeof(long),1,ifp);for(i=0;i<n;i++){fread(&header[i].b,1,1,ifp);fread(&c,1,1,ifp);p=(long)c;header[i].count=p;header[i].bits[0]=0;if(p%8>0) m=p/8+1;else m=p/8;for(j=0;j<m;j++){fread(&c,1,1,ifp);f=c;itoa(f,buf,2);f=strlen(buf);for(l=8;l>f;l--){strcat(header[i].bits,"0");}strcat(header[i].bits,buf);}header[i].bits[p]=0;}for(i=0;i<n;i++){for(j=i+1;j<n;j++){if(strlen(header[i].bits)>strlen(header[j].bits)){tmp=header[i];header[i]=header[j];header[j]=tmp;}}}p=strlen(header[n-1].bits);fseek(ifp,8,SEEK_SET);m=0;bx[0]=0;while(1){while(strlen(bx)<(unsigned int)p){fread(&c,1,1,ifp);f=c;itoa(f,buf,2);f=strlen(buf);for(l=8;l>f;l--){strcat(bx,"0");}strcat(bx,buf);}for(i=0;i<n;i++){if(memcmp(header[i].bits,bx,header[i].count)==0) break;}strcpy(bx,bx+header[i].count);c=header[i].b;fwrite(&c,1,1,ofp);m++;if(m==flength) break;}fclose(ifp);fclose(ofp);printf("解压成功\n");return;}void main() /*主函数*/{printf("输入a开始解压\n");printf("输入b结束解压\n");while(1){char c;c=getch();if(c=='a')jieya();else{ if(c=='b')return;}}}七、测试结果及分析:压缩前的文件夹中的内容压缩后的文件夹中的内容解压后文件夹中的内容八、教师评语:.。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Huffm an 编码是基于 Huff man 树的一种非 等长编码 .Huff man 树是一种 0 -1 编码树 , 由 0 -1 编码树的性质可知 , 由 0 -1 编码树生成的 编码为前缀码 .这样 , 就可以得到任意一个序列 的不可能发生混淆的重编码 .Huf fman 编码原理
最早是由美国数学家 D .A .Huf fman 提出的 .编 码的原理是 :将使用次数多的代码转换成长度较 短的代码 , 而使用次数少的可以使用较长的编 码 , 并且保持编码的唯一可解性 .Huffman 算法 的最根本的原则是 :累计的权值(字符的统计数 字 *字符的编码长度)的和为最小 .在以色列人 发明基于字典的 LZ W 压缩算法 以前 , Huf fman 编码一 直是主流 的压缩算 法 .直 至今天 , Huf fman 编码依然是一种重要的数据压缩算法 , 在数 字图像压缩 , 数码水印等方面发挥了关键性的作 用 , 而许多程序员在编一个大型软件的过程中 , 如果遇到需要数据压缩的情况 , 他们的首选还是 Huf fman 编码 , 因为它高效 、无损又易于实现 .所 以 , 笔者编制 了一个基于 Huff man 编码的 压缩 程序 , 并在具体实现过程中提出了一些有创见的 方案 .
收稿日期 :2004 -06 -23 作者简介 :刘光灿(1958 -), 男 , 湖南人 , 长沙学院教授 , 北京理工大学博士研究生 , 主要从事光电技术研究工作 .
1 8 光 电 技 术 应 用 第 19 卷
1 算法实现
第 5 期 刘光灿等 :数字图像处理中的 Huffman 编码压缩 C++实现 1 9
(in .get(c)), 即以 ist ream & get(unsigned char &)函数 的返回值作为 遍历是否结束的 判断条 件 , 收到了满意的效果 .
刘光灿1 , 刘简达2
(1 .长沙学院 , 湖南 长沙 410003 ;2 .上海交通大学 , 上海 200240)
摘 要 :介绍了用 C ++实现数字图 像处理 中的 Huffman 编码压 缩的 技术细 节 , 包括 总流程 , 数 据结构 , 编 码原 理 , 索引建立 , 文件写入和解压缩 .最后还论述了 Huffman 压缩以及字典压缩的优缺点 .
1 .1 总流程 这个程序的总流程如图 1 所示 , 运行界面十
分简洁 , 如图 2 所示 .本程序的特点在于对所有
图 1 总流程图
图 2 运行界面
文件采取二进制(ios ::binary)方式强制打开 , 所 以可 以压缩任意格式的文件 , 无论是文本文件 *.t xt , 可执 行文 件 *.exe , 还 是数 据文 件 *. dat , 本程序都可以压缩 , 只是具体的压缩比取决 于各文件的实际情况 .而用户在选取压缩后的文 件名时 , 也可以任意指定后缀名(系统默认为 *. huf), 充分发挥用户的个性 .本程序完全是基于 流的方式来处理数据 , 任何文件格式对程序运行 没有影响 .笔者认为这一点是相当必要的 , 现行 的压缩软件都对生成的压缩文件采用固定的后 缀名如 *.zip , *.rar 等 , 使之成为了某 些病毒 的攻击目标 , 从而用户的数据不再安全 .而使用 本程序压缩文件时 , 用户可以通过指定个性化后 缀名的方式免招病毒袭击 , 虽然本程序只是一个
Key words:Huffm an encoding ;data compression ;algo rit hm ;data st ruct ure
数字图像信号有很多优点 , 但相比模拟信号 其频带大大加宽 , 例如一路 6 MHz 的普通电视 信号数字化后 , 其数码率将高达 167 Mb/ s , 对储 存器容量要求很大 , 占有的带宽将达 80 MHz 左 右 , 这样将使数字图像信号失去实用价值 .数字 图像压缩技术很好地解决了上述困难 , 压缩后信 号所占用的频带大大低于原模拟信号的频带 .因 此说 , 数字图像压缩编码技术是使数字信号走向 实用化的关键技术 之一 .而 Huf fman 编 码压缩 作为一种最为常见的压缩技术 , 在数字图像压缩 处理领域内得到了广泛的应用 .
微型软件 , 但类似的思路无疑是将来大型压缩软 件的发展方向 . 1 .2 数据结构
本程序使用的数据结构主要有链表和二叉 树 , 二叉树的储存方式为连续空间储存 .部分代 码如下 :
ty pedef struct{ unsigned char valve ; / / 结点值 int weig ht ; // 算法 ;数据结 构 中图分类号 :TP274 +.2 文献标识码 :A
Implementation of Huffman Encoding and Compression in the Area of Digital Image Manipulation in C ++
编码完成后 , 还有一个重要的工作 , 就是为 生成的压缩文件建立索引 .索引就是文件解压时 所需的各种数据 , 它将被写在压缩文件的开头 . 索引包括原文件名 ;文件中出现的字符数(范围 1 ~ 256);原文件大小(单位 :字节);各字符出现 的频率 .原文件名可以使解压缩生成的文件与原 文件同名 .文件中出现的字符数是解压缩时重建 Huf fman 树必须的数据 .而原文件大小主要是为 了解决以下问题 :当一个文件压缩到末尾时 , 可 能只剩下少于 8 位的编码要写入文件 , 但这时还 是要写入一个字节 .例如剩余的是 011 , 于是写 入 011x xx xx , 其中 x 表示随机代码 , 那么在解压 时 , 就必须防止发生 这样的情况 :x xx xx 的前 n 位(n ≤5)正好为一个 合法的 H uff man 编码 , 于 是解压后的文件比原文件多一个字符 .而现在用 原文件大小来控制解压后文件的大小 , 上述问题 就不会发生了 .关于直接储存各字符出现的频率 的问题 , 还有 一种替代 方案是把 整棵 Huf fman
在所有字符的出现频率都统计完成之后 , 就 可以开始建立 Huf fman 树了 , 下面举例 说明建 树及求 Huff man 编码的过程 .
如有以下数据 : A BFA CG CAHG BBAA C EC DFG FAA EAB BB 先进行统计得 A(8)B(6)C(4)D(1)E(2) F(3)G(3)H(1).括号里面的是统计次数 . 生成 Huf fman 树 :每次取 最小的那两 个节 点(node)合并成一个节点(node), 并且将累计数 值相加作为新的节点的累计数值 , 最顶层的是根 节点(root).(注 :列表中最小节点的是指包括合 并了的节点在内的所有节点 , 已经合并的节点不 在列表中) 运算的过程如下 : 1 :D +H(2) 2 :DH +E(4) 3 :F +G(6) 4 :C +DHE(8) 5 :B +FG(12) 6 :A +DHEC(16) 7 :DHECA +BFG(28)
在这 256 种字符中 , 有一种特殊的字符 , 即 所谓的文件结束符 .在 Window s 系统下 , 文件结 束符为 255 , 即二进制编码为 11111111 的字符 , 如果使用 iost ream 类提供的 eof()函数判断文件 是否结束 , 则在遍历某些文件时会发生未完全遍 历的情况 .例如某些 *.exe 文件 , 其中可能含有 多个文 件结 束 符 .所以 实际 中 采用 语 句 w hile
图 3 Huffman 树
那么转化为 Huf fman 树就如图 3 所示 .取 左面是 1 右面是 0 则可得到各字符的 Huffm an 编码 .(见表 1)
表 1 Huffman 编码对 照表 字符 A B C D E F G H 编码 10 01 110 11111 1110 001 000 11110
算法上除了 Huf fman 编码外还用到了插入法排 序 , 鉴于篇幅 , 代码略 . 1 .3 编码原理
由压缩技术原理 可知 , 压缩 = 模型 + 编 码 .Huff man 编码 利 用 的模 型 是“ 静 态统 计 模 型” , 也就是说在编码前统计要编码的信息中所 有字符的出现频率 , 让后根据统计出的信息建立 编码树 , 进行编码 .在具体操作中 , 采用一个二维 数组 ini t[ ] [ ] 来储存 各字符出现 的频率(即 权 值).这里有一个问题要说明一下 :在本程序中字 符的写入和读出都采取无符号字符型(unsigned char)的格式 , 根据 ASCII 码共有 0 ~ 255 总 计 256 种可能出现的字符 , 所以 ini t[ ] [ ] 数组的规 模为 256 ×2 , 256 行分别代表 256 种字符 , 第一 列存字符序号 , 第二列存出现频率 .这里不直接 用数组下标表示字符序号 , 是因为在正式编码前 还要根据出现频率对数组进行排序 , 这样将大大 加快编码的速度 , 在考虑时间和空间的矛盾时 , 笔者首选了时间 .
第 19 卷第 5 期 2004 年 10 月
光电技术应用 ELECT RO -O PT IC T ECHNO LOG Y APP LICAT IO N
文章编号 :CN21-1495(2004)05-0017-04
V ol.19 , No .5 October .2004
数字图像处理中的 Huffman 编码压缩 C ++实现
可以看出 Huf fman 编码是唯一可解的 (uniquely decodable), 如果你读到 110 就一定是
C , 不会有任何一个编码是以 110 开始的 . 关于编码的储存 , 必须用一个二维数组来实
现 .数组的行数是文件中出现的字符数目 Num , 列数为 34 .因为在 最坏的 情况 下 , 一 个字符 的 Huf fman 编码可能长达 256 =8 ×32 位 , 这就需 要 32 个字节的空间来储存 , 还有第一列要用来 储存字符本身, 第二列用来记录编码的有效位 数 , 这就需要 34 列 .为什么要记录编码的有效位 数呢 ? 因为如果一个字符的编码小于 8 位例如 011 , 记 录 时 必 须 用 一 个 字 节 来 记 录 , 即 00000011 , 这样假如另一个编码是 11 , 无法分辨 了 .还有编码大于 8 位时 , 例如 10110011010 , 必 须 用 两 个 字 节 来 记 录 , 记 为 “ 10110011 , 00000010” , 这样重新提取时就不知道原编码是 101100110010 还是 10110011010 .显然只有记录 下有效编码的位数 , 才能从中正确的提取出原来 的编码 .至于为什么要用一个字节来表示 8 位编 码而不是一个字节表示一位编码则是因为在文 件写入时位操作的速度是最快的 , 而这样表示可 以毫无阻碍的进行位操作 , 达到最高的效率 .实 测表明 , 本程序的压缩速度不亚于 WinRAR , 在 压缩较大 的文件(>10 MB)时 甚至快 于 WinRAR . 1 .4 索引建立
相关文档
最新文档