压缩编码算法设计与实现实验报告

合集下载

压缩技术实验编码

压缩技术实验编码

压缩技术实验编码实验一统计编码一、实验目的1.熟悉统计编码的原理2.掌握r元Huffman编码的方法;3.了解Huffman编码效率及冗余度的计算;二、实验原理霍夫曼编码, 又称最佳编码,根据字符出现概率来构造平均长度最短的变长编码。

Huffman编码步骤:(1)把信源符号x i(i=1,2,…,N)按出现概率的值由大到小的顺序排列;(2)对两个概率最小的符号分别分配以“0”和“1”,然后把这两个概率相加作为一个新的辅助符号的概率;(3)将这个新的辅助符号与其他符号一起重新按概率大小顺序排列;(4)跳到第2步,直到出现概率相加为1为止;(5)用线将符号连接起来,从而得到一个码树,树的N个端点对应N个信源符号;(6)从最后一个概率为1的节点开始,沿着到达信源的每个符号,将一路遇到的二进制码“0”或“1”顺序排列起来,就是端点所对应的信源符号的码字。

以上是二元霍夫曼编码。

如果是r元霍夫曼编码,则应该如何做呢?在HUFFMAN编码方案中,为出现概率较小的信源输出分配较长的码字,而对那些出现可能性较大的信源输出分配较短的码字。

为此,首先将r个最小可能的信源输出合并成为一个新的输出,该输出的概率就是上述的r个输出的概率之和。

重复进行该过程直到只剩下一个输出为止。

信源符号的个数q与r必须满足如下的关系式:q = (r-1) n + r n为整数如果不满足上述关系式,可通过添加概率为零的信源符号来满足。

这样就生成了一个树,从该树的根节点出发并将0、1……分别分配给任何r个来自于相同节点的分支,生成编码。

可以证明用这种方法产生的编码在前向树类编码中具有最小的平均长度。

举例:对于取值为u={u1,u2,u3,u4,u5,u6}其相应的概率为p={0.1,0.3,0.05,0.09,0.21,0.25}的信源,试设计一个3元HUFFMAN码,求出码子的平均长度与编码效率。

注:因为是3元编码,所以每次3个概率值相加。

《压缩编码》之设计报告

《压缩编码》之设计报告

《压缩编码》之设计报告——短汉字的压缩指导教师: 林嘉宇 熊春林院 队: 一院五队学 号: XS09012057姓 名: 徐海一目录引言 (2)“学”DCT & BWT (2)ⅰ. DCT (2)ⅱ. BWT (2)“道”能量集中与重分 (3)ⅰ. First-Attempt (3)ⅱ. Second-Attempt (3)ⅲ. Third-Attempt (4)ⅳ. Final-Attempt (5)“术”压缩与解压缩 (6)ⅰ.compress (6)ⅱ.decompress (7)源程序 (8)ⅰ. 核心程序compre-c (8)ⅱ. 核心程序compre-d (15)引言本课程设计是针对短汉字进行压缩编码的一个实验,题目的要求中需要注意的点是:①课题为短汉字压缩,应重点了解汉字编码的特点;②符号中包括了汉字、英文和标点,这三者在计算机内是采用的不同的编码方式;③不超过105个字符,长度短,一般压缩方式的效果会不太理想;④测试文件集内容为类似给老师写条短信息的形式,因此编辑的文字一般不会太复杂;⑤压缩比的统计数据占据评分的最大比重,是应该主要考虑的性能因素。

根据以上提到的一些注意要点,本实验的特点主要在于对于汉字压缩的设计,由于汉字的长度有限,应该充分考虑汉字独有的特点,充分挖掘其冗余,只有这样才能很大程度地去提高压缩比。

另外,由于汉字(标点可视为中文字符标点)与英文特点有所不同,对于两者的压缩可以考虑采用不同的方式。

还有,通常汉字的出现频率是很平均的,不会发生集中在某几个汉字出现的情形,也是可以在设计过程中进行考虑的。

最后,传统的建模方法是基于统计模型或者是字典模型,能否找到可以充分体现汉字编码本质的第三种简单的建模方法。

考虑到汉字编码的特殊性,贯穿本设计的主要思路是:能量的集中与重分。

主要特点是抓住了最根本的物理特性,从最底层化繁为简,重分利用ASCII码的编码特性,用最简单的一个思路完成了符合汉字压缩特点的一种压缩方式。

数据压缩实验报告(3篇)

数据压缩实验报告(3篇)

第1篇一、实验目的1. 了解数据压缩的基本原理和方法。

2. 掌握常用数据压缩算法的应用。

3. 分析不同数据压缩算法的性能和适用场景。

二、实验环境1. 操作系统:Windows 102. 编程语言:Python3. 数据压缩工具:Huffman编码、LZ77、LZ78、RLE、JPEG、PNG三、实验内容1. Huffman编码2. LZ77编码3. LZ78编码4. RLE编码5. 图像压缩:JPEG、PNG四、实验步骤1. Huffman编码(1)设计Huffman编码树,计算每个字符的频率。

(2)根据频率构建Huffman编码树,为每个字符分配编码。

(3)将原始数据按照Huffman编码进行编码,得到压缩数据。

(4)解压缩:根据编码表还原原始数据。

2. LZ77编码(1)设计LZ77编码算法,查找匹配的字符串。

(2)将原始数据按照LZ77编码进行编码,得到压缩数据。

(3)解压缩:根据编码表还原原始数据。

3. LZ78编码(1)设计LZ78编码算法,查找匹配的字符串。

(2)将原始数据按照LZ78编码进行编码,得到压缩数据。

(3)解压缩:根据编码表还原原始数据。

4. RLE编码(1)设计RLE编码算法,统计连续字符的个数。

(2)将原始数据按照RLE编码进行编码,得到压缩数据。

(3)解压缩:根据编码表还原原始数据。

5. 图像压缩:JPEG、PNG(1)使用JPEG和PNG工具对图像进行压缩。

(2)比较压缩前后图像的质量和大小。

五、实验结果与分析1. Huffman编码(1)压缩前后数据大小:原始数据大小为100KB,压缩后大小为25KB。

(2)压缩效率:压缩比约为4:1。

2. LZ77编码(1)压缩前后数据大小:原始数据大小为100KB,压缩后大小为35KB。

(2)压缩效率:压缩比约为3:1。

3. LZ78编码(1)压缩前后数据大小:原始数据大小为100KB,压缩后大小为30KB。

(2)压缩效率:压缩比约为3.3:1。

数字图像处理 实验六 压缩编码

数字图像处理 实验六 压缩编码

实验六 统计压缩编码一、实验目的:1,掌握不等长编码的基本原理及方法2,掌握衡量压缩效果的技术指标3,掌握Huffman 编码的方法二,实验条件1,MATLAB2,典型的灰度、彩色图像文件三,原理1.去除数据冗余度可以有效的压缩数据2.图像编码的主要技术指标:压缩比、客观评价值SNR 、主观评价值 四,实验内容:1,通过MATLAB 编程,对8*8图像子块实施Hiffman 编码并计算平均码长 2,计算上述编码的效率,压缩比并对相应数据作出解释。

五,实验步骤1,Huffman 编码的方法与步骤如下所示:(1)将概率按从小到大的顺序排列(2)给两个概率最小的信源符号1()P a 和2()P a 各分配一个码位“0”和“1”,将这两个信源符号合并成一个新符号,并用这两个最小的概率之和最为新符号的概率,结果得到一个只包含(n-1)个信源符号的新信源,称为信源的第一次缩减信源,用S1表示。

(3)将缩减信源S1的符号仍按概率从大到小的顺序排列,重复步骤2,得到只含(n-2)个符号的缩减信源S2。

(4)重复上述步骤,直至缩减信源只剩两个符号为止,此时所剩的两个符号的概率之和为1。

然后从最后一级缩减信源开始,依编码路径向前返回,就得到各信源符号所对应的码字。

2,假设这个8*8的字块是由0-5这六个像素组成,对这个字块进行概率统计,并按概率从小到大的顺序排列,如下所示:P=(0.25 0.25 0.2 0.15 0.1 0.05)则对于假设的字块进行Huffman编码的matlab程序如下所示:n=input('N=');%L=0; H=0;for i=1:nP(i)=input('P=');%输入像素概率分布s=s+P(i);endif s~=1error('不符合概率分布');endP=sort(P);p=P;mark=zeros(n-1,n); %mark为n-1行,n列矩阵,用来记录每行概率排列次序for i=1:n-1[P,num]=sort(P); %对输入元素排序并记录mark(i,:)=[num(1:n-i+1),zeros(1,i-1)];P=[P(1)+P(2),P(3:n),1];endfor i=1:n-1table(i,:)=blanks(n*n); %blanks 创建空格串endtable(n-1,n)='1';table(n-1,2*n)='0'for i=2:n-1table(n-i,1:n-1)=table(n-i+1,n*(find(mark(n-i+1,:)==1))-(n-2):n*(find(mar k(n-i+1,:)==1))); %按mark的记录依次赋值table(n-i,n)='1';table(n-i,n+1:2*n-1)=table(n-i,1:n-1);table(n-i,2*n)='0';for j=1:i-1table(n-i,(j+1)*n+1:(j+2)*n)=table(n-i+1,n*(find(mark(n-i+1,:)==j+1)-1)+1:n*find(mark(n-i+1,:)==j+1));%mark的记录依次赋值endend%得到编码后的码字for i=1:nW(i,1:n)=table(1,n*(find(mark(1,:)==i)-1)+1:find(mark(1,:)==i)*n);l(i)=length(find(abs(W(i,:))~=32));%32表示空字符,要找不是空字符的个数,即为每个数编码的个数L=L+p(i)*l(i); %计算平均码长H=H-p(i)*log2(p(i));%计算信源熵endxiaolv=H/L; %计算编码效率disp('输出每个概率的编码');disp(W);disp('输出平均码长L:');disp(L);disp('输出编码效率xiaolv:');disp(xiaolv);3,计算结果如下:(1)输出每个灰度级的编码00010000001111001(2)计算其平均码长和编码效率平均码长L=2.4500编码效率xiaolv=0.9891图一运行及结果六,实验总结:在实验中,假设了灰度级为6,即像素值为0-5。

LZ77 压缩算法实验报告 一

LZ77 压缩算法实验报告 一

LZ77 压缩算法实验报告一、实验内容:使用 C++编程实现 LZ77 压缩算法的实现。

二、实验目的:用 LZ77 实现文件的压缩。

三、实验环境: 1、软件环境:Visual C++ 6.02、编程语言:C++四、实验原理: LZ77 算法在某种意义上又可以称为“滑动窗口压缩”,这是由于该算法将一个虚拟的,可以跟随压缩进程滑动的窗口作为术语字典,要压缩的字符串如果在该窗口中出现,则输出其出现位置和长度。

使用固定大小窗口进行术语匹配,而不是在所有已经编码的信息中匹配,是因为匹配算法的时间消耗往往很多,必须限制字典的大小才能保证算法的效率;随着压缩的进程滑动字典窗口,使其中总包含最近编码过的信息,是因为对大多数信息而言,要编码的字符串往往在最近的上下文中更容易找到匹配串。

五、 LZ77 算法的基本流程:1、从当前压缩位置开始,考察未编码的数据,并试图在滑动窗口中找出最长的匹配字符串,如果找到,则进行步骤2,否则进行步骤 3。

2、输出三元符号组 ( off, len, c )。

其中 off 为窗口中匹配字符串相对窗口边界的偏移,len 为可匹配的长度,c 为下一个字符。

然后将窗口向后滑动 len + 1 个字符,继续步骤 1。

3、输出三元符号组 ( 0, 0, c )。

其中 c 为下一个字符。

然后将窗口向后滑动 len + 1 个字符,继续步骤 1。

代码如下:#include<windows.h>#include<stdio.h>#include<memory.h>#include"lz77.h"//////////////////////////////////////////////////////////////////// out file format:// 0;flag2;buffer;0;flag2;buffer;...flag1;flag2;bufferlast// flag1 - 2 bytes, source buffer block length// if block size is 65536, be zero// flag2 - 2 bytes, compressed buffer length// if can not compress, be same with flag1//////////////////////////////////////////////////////////////////void main(int argc, char* argv[]){/*if (argc != 4){puts("Usage: ");printf(" Compress : %s c sourcefile destfile\n", argv[0]); printf(" Decompress : %s d sourcefile destfile\n", argv[0]); return;} */BYTE soubuf[65536];BYTE destbuf[65536 + 16];FILE* in;FILE* out;/* in = fopen("input.txt", "rb");if (in == NULL){puts("Can't open source file");return;}out = fopen("compress.txt", "wb");if (out == NULL){puts("Can't open dest file");fclose(in);return;}fseek(in, 0, SEEK_END);long soulen = ftell(in);fseek(in, 0, SEEK_SET);CCompressLZ77 cc;WORD flag1, flag2; */int temp;printf("compress(0) or decompress(1)?:");scanf("%d",&temp);if (temp == 0) // compress{in = fopen("input.txt", "rb");if (in == NULL){puts("Can't open source file");return;}out = fopen("compress.txt", "wb");if (out == NULL){puts("Can't open dest file");fclose(in);return;}fseek(in, 0, SEEK_END);long soulen = ftell(in);fseek(in, 0, SEEK_SET);CCompressLZ77cc;WORD flag1, flag2;int last = soulen, act;while ( last > 0 ){act = min(65536, last);fread(soubuf, act, 1, in);last -= act;if (act == 65536) // out 65536 bytesflag1 = 0;else// out last blocksflag1 = act;fwrite(&flag1, sizeof(WORD), 1, out);int destlen = press((BYTE*)soubuf, act, (BYTE*)destbuf);if (destlen == 0) // can't compress the block{flag2 = flag1;fwrite(&flag2, sizeof(WORD), 1, out);fwrite(soubuf, act, 1, out);}else{flag2 = (WORD)destlen;fwrite(&flag2, sizeof(WORD), 1, out);fwrite(destbuf, destlen, 1, out);}}}else if (temp == 1) // decompress{in = fopen("compress.txt", "rb");if (in == NULL){puts("Can't open source file");return;}out = fopen("decompress.txt", "wb");if (out == NULL){puts("Can't open dest file");fclose(in);return;}fseek(in, 0, SEEK_END);long soulen = ftell(in);fseek(in, 0, SEEK_SET);CCompressLZ77cc;WORD flag1, flag2;int last = soulen, act;while (last > 0){fread(&flag1, sizeof(WORD), 1, in);fread(&flag2, sizeof(WORD), 1, in);last -= 2 * sizeof(WORD);if (flag1 == 0)act = 65536;elseact = flag1;last-= flag2 ? (flag2) : act;if (flag2 == flag1){fread(soubuf, act, 1, in);}else{fread(destbuf, flag2, 1, in);if (!cc.Decompress((BYTE*)soubuf, act, (BYTE*)destbuf)){puts("Decompress error");fclose(in);fclose(out);return;}}fwrite((BYTE*)soubuf, act, 1, out);}}else{puts("Usage: ");printf(" Compress : %s c sourcefile destfile\n", argv[0]);printf(" Decompress : %s d sourcefile destfile\n", argv[0]);}fclose(in);fclose(out);}//////////////////////////////// LZ77.h//////////////////////////////// 使用在自己的堆中分配索引节点,不滑动窗口// 每次最多压缩65536 字节数据// 的优化版本#ifndef_WIX_LZ77_COMPRESS_HEADER_001_#define_WIX_LZ77_COMPRESS_HEADER_001_// 滑动窗口的字节大小#define_MAX_WINDOW_SIZE65536class CCompress{public:CCompress() {};virtual ~CCompress() {};public:virtual int Compress(BYTE* src, int srclen, BYTE* dest) = 0;virtual BOOL Decompress(BYTE* src, int srclen, BYTE* dest) = 0;protected:// tools/////////////////////////////////////////////////////////// CopyBitsInAByte : 在一个字节范围内复制位流// 参数含义同CopyBits 的参数// 说明:// 此函数由CopyBits 调用,不做错误检查,即// 假定要复制的位都在一个字节范围内void CopyBitsInAByte(BYTE* memDest, int nDestPos,BYTE* memSrc, int nSrcPos, int nBits);////////////////////////////////////////////////////////// CopyBits : 复制内存中的位流// memDest - 目标数据区// nDestPos - 目标数据区第一个字节中的起始位// memSrc - 源数据区// nSrcPos - 源数据区第一个字节的中起始位// nBits - 要复制的位数// 说明:// 起始位的表示约定为从字节的高位至低位(由左至右)// 依次为0,,... , 7// 要复制的两块数据区不能有重合void CopyBits(BYTE* memDest, int nDestPos,BYTE* memSrc, int nSrcPos, int nBits);//////////////////////////////////////////////////////////////// 将DWORD值从高位字节到低位字节排列void InvertDWord(DWORD* pDW);/////////////////////////////////////////////////////////////// 设置byte的第iBit位为aBit// iBit顺序为高位起从记数(左起)void SetBit(BYTE* byte, int iBit, BYTE aBit);////////////////////////////////////////////////////////////// 得到字节byte第pos位的值// pos顺序为高位起从记数(左起)BYTE GetBit(BYTE byte, int pos);////////////////////////////////////////////////////////////// 将位指针*piByte(字节偏移), *piBit(字节内位偏移)后移num位void MovePos(int* piByte, int* piBit, int num);/////////////////////////////////////////////////////////// 取log2(n)的upper_boundint UpperLog2(int n);/////////////////////////////////////////////////////////// 取log2(n)的lower_boundint LowerLog2(int n);};class CCompressLZ77 : public CCompress{public:CCompressLZ77();virtual ~CCompressLZ77();public://///////////////////////////////////////////// 压缩一段字节流// src - 源数据区// srclen - 源数据区字节长度, srclen <= 65536// dest - 压缩数据区,调用前分配srclen字节内存// 返回值> 0 压缩数据长度// 返回值= 0 数据无法压缩// 返回值< 0 压缩中异常错误int Compress(BYTE* src, int srclen, BYTE* dest);/////////////////////////////////////////////// 解压缩一段字节流// src - 接收原始数据的内存区, srclen <= 65536// srclen - 源数据区字节长度// dest - 压缩数据区// 返回值- 成功与否BOOL Decompress(BYTE* src, int srclen, BYTE* dest);protected:BYTE* pWnd;// 窗口大小最大为64k ,并且不做滑动// 每次最多只压缩64k 数据,这样可以方便从文件中间开始解压// 当前窗口的长度int nWndSize;// 对滑动窗口中每一个字节串排序// 排序是为了进行快速术语匹配// 排序的方法是用一个k大小的指针数组// 数组下标依次对应每一个字节串:(00 00) (00 01) ... (01 00) (01 01) ...// 每一个指针指向一个链表,链表中的节点为该字节串的每一个出现位置struct STIDXNODE{WORD off; // 在src中的偏移WORD off2; // 用于对应的字节串为重复字节的节点// 指从off 到off2 都对应了该字节串WORD next; // 在SortHeap中的指针};WORD SortTable[65536]; // 256 * 256 指向SortHeap中下标的指针// 因为窗口不滑动,没有删除节点的操作,所以// 节点可以在SortHeap 中连续分配struct STIDXNODE* SortHeap;int HeapPos; // 当前分配位置// 当前输出位置(字节偏移及位偏移)int CurByte, CurBit;protected:////////////////////////////////////////// 输出压缩码// code - 要输出的数// bits - 要输出的位数(对isGamma=TRUE时无效)// isGamma - 是否输出为γ编码void_OutCode(BYTE* dest, DWORD code, int bits, BOOL isGamma);///////////////////////////////////////////////////////////// 在滑动窗口中查找术语// nSeekStart - 从何处开始匹配// offset, len - 用于接收结果,表示在滑动窗口内的偏移和长度// 返回值- 是否查到长度为或以上的匹配字节串BOOL_SeekPhase(BYTE* src, int srclen, int nSeekStart, int* offset, int* len);///////////////////////////////////////////////////////////// 得到已经匹配了个字节的窗口位置offset// 共能匹配多少个字节inline int_GetSameLen(BYTE* src, int srclen, int nSeekStart, int offset);//////////////////////////////////////////// 将窗口向右滑动n个字节inline void_ScrollWindow(int n);// 向索引中添加一个字节串inline void_InsertIndexItem(int off);// 初始化索引表,释放上次压缩用的空间void_InitSortTable();};#endif// _WIX_LZW_COMPRESS_HEADER_001_ //////////////////////////////// LZ77.CPP//////////////////////////////#include<windows.h>#include<stdio.h>#include<memory.h>#include<crtdbg.h>#include"lz77.h"///////////////////////////////////////////////////////// // 取log2(n)的upper_boundint CCompress::UpperLog2(int n){int i = 0;if (n > 0){int m = 1;while(1){if (m >= n)return i;m <<= 1;i++;}}elsereturn -1;}// UpperLog2////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 取log2(n)的lower_boundint CCompress::LowerLog2(int n){int i = 0;if (n > 0){int m = 1;while(1){if (m == n)return i;if (m > n)return i - 1;m <<= 1;i++;}}elsereturn -1;}// LowerLog2/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 将位指针*piByte(字节偏移), *piBit(字节内位偏移)后移num位void CCompress::MovePos(int* piByte, int* piBit, int num) {num += (*piBit);(*piByte) += num / 8;(*piBit) = num % 8;}// MovePos////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 得到字节byte第pos位的值// pos顺序为高位起从记数(左起)BYTE CCompress::GetBit(BYTE byte, int pos){int j = 1;j <<= 7 - pos;if (byte & j)return 1;elsereturn 0;}// GetBit//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 设置byte的第iBit位为aBit// iBit顺序为高位起从记数(左起)void CCompress::SetBit(BYTE* byte, int iBit, BYTE aBit){if (aBit)(*byte) |= (1 << (7 - iBit));else(*byte) &= ~(1 << (7 - iBit));}// SetBit////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 将DWORD值从高位字节到低位字节排列void CCompress::InvertDWord(DWORD* pDW){union UDWORD{ DWORD dw; BYTE b[4]; };UDWORD* pUDW = (UDWORD*)pDW;BYTE b;b = pUDW->b[0]; pUDW->b[0] = pUDW->b[3]; pUDW->b[3] = b;b = pUDW->b[1]; pUDW->b[1] = pUDW->b[2]; pUDW->b[2] = b; }// InvertDWord//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// CopyBits : 复制内存中的位流// memDest - 目标数据区// nDestPos - 目标数据区第一个字节中的起始位// memSrc - 源数据区// nSrcPos - 源数据区第一个字节的中起始位// nBits - 要复制的位数// 说明:// 起始位的表示约定为从字节的高位至低位(由左至右)// 依次为0,,... , 7// 要复制的两块数据区不能有重合void CCompress::CopyBits(BYTE* memDest, int nDestPos,BYTE* memSrc, int nSrcPos, int nBits){int iByteDest = 0, iBitDest;int iByteSrc = 0, iBitSrc = nSrcPos;int nBitsToFill, nBitsCanFill;while (nBits > 0){// 计算要在目标区当前字节填充的位数nBitsToFill = min(nBits, iByteDest ? 8 : 8 - nDestPos);// 目标区当前字节要填充的起始位iBitDest = iByteDest ? 0 : nDestPos;// 计算可以一次从源数据区中复制的位数nBitsCanFill = min(nBitsToFill, 8 - iBitSrc);// 字节内复制CopyBitsInAByte(memDest + iByteDest, iBitDest,memSrc + iByteSrc, iBitSrc, nBitsCanFill);// 如果还没有复制完nBitsToFill 个if (nBitsToFill > nBitsCanFill){iByteSrc++; iBitSrc = 0; iBitDest += nBitsCanFill;CopyBitsInAByte(memDest + iByteDest, iBitDest,memSrc + iByteSrc, iBitSrc,nBitsToFill - nBitsCanFill);iBitSrc += nBitsToFill - nBitsCanFill;}else{iBitSrc += nBitsCanFill;if (iBitSrc >= 8){iByteSrc++; iBitSrc = 0;}}nBits -= nBitsToFill; // 已经填充了nBitsToFill位iByteDest++;}}// CopyBits//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// CopyBitsInAByte : 在一个字节范围内复制位流// 参数含义同CopyBits 的参数// 说明:// 此函数由CopyBits 调用,不做错误检查,即// 假定要复制的位都在一个字节范围内void CCompress::CopyBitsInAByte(BYTE* memDest, int nDestPos, BYTE* memSrc, int nSrcPos, int nBits){BYTE b1, b2;b1 <<= nSrcPos; b1 >>= 8 - nBits; // 将不用复制的位清b1 <<= 8 - nBits - nDestPos; // 将源和目的字节对齐*memDest |= b1; // 复制值为的位b2 = 0xff; b2 <<= 8 - nDestPos; // 将不用复制的位置b1 |= b2;b2 = 0xff; b2 >>= nDestPos + nBits;b1 |= b2;*memDest &= b1; // 复制值为的位}// CopyBitsInAByte///////////////////////////////////////////////////////////------------------------------------------------------------------CCompressLZ77::CCompressLZ77(){SortHeap = new struct STIDXNODE[_MAX_WINDOW_SIZE]; }CCompressLZ77::~CCompressLZ77(){delete[] SortHeap;}// 初始化索引表,释放上次压缩用的空间void CCompressLZ77::_InitSortTable(){memset(SortTable, 0, sizeof(WORD) * 65536);nWndSize = 0;HeapPos = 1;}// 向索引中添加一个字节串void CCompressLZ77::_InsertIndexItem(int off){WORD q;BYTE ch1, ch2;ch1 = pWnd[off]; ch2 = pWnd[off + 1];if (ch1 != ch2){// 新建节点HeapPos++;SortHeap[q].off = off;SortHeap[q].next = SortTable[ch1 * 256 + ch2];SortTable[ch1 * 256 + ch2] = q;}else{// 对重复字节串// 因为没有虚拟偏移也没有删除操作,只要比较第一个节点// 是否和off 相连接即可q = SortTable[ch1 * 256 + ch2];if (q != 0 && off == SortHeap[q].off2 + 1){// 节点合并SortHeap[q].off2 = off;}else{// 新建节点q = HeapPos;HeapPos++;SortHeap[q].off = off;SortHeap[q].off2 = off;SortHeap[q].next = SortTable[ch1 * 256 + ch2];SortTable[ch1 * 256 + ch2] = q;}}}//////////////////////////////////////////// 将窗口向右滑动n个字节void CCompressLZ77::_ScrollWindow(int n){for (int i = 0; i < n; i++){nWndSize++;if (nWndSize > 1)_InsertIndexItem(nWndSize - 2);}}///////////////////////////////////////////////////////////// 得到已经匹配了个字节的窗口位置offset// 共能匹配多少个字节int CCompressLZ77::_GetSameLen(BYTE* src, int srclen, int nSeekStart, int offset) {int i = 2; // 已经匹配了个字节int maxsame = min(srclen - nSeekStart, nWndSize - offset);while (i < maxsame&& src[nSeekStart + i] == pWnd[offset + i])i++;_ASSERT(nSeekStart + i <= srclen && offset + i <= nWndSize);return i;}///////////////////////////////////////////////////////////// 在滑动窗口中查找术语// nSeekStart - 从何处开始匹配// offset, len - 用于接收结果,表示在滑动窗口内的偏移和长度// 返回值- 是否查到长度为或以上的匹配字节串BOOL CCompressLZ77::_SeekPhase(BYTE* src, int srclen, int nSeekStart, int* offset, int* len){int j, m, n;if (nSeekStart < srclen - 1){BYTE ch1, ch2;ch1 = src[nSeekStart]; ch2 = src[nSeekStart + 1];WORD p;p = SortTable[ch1 * 256 + ch2];if (p != 0){m = 2; n = SortHeap[p].off;while (p != 0){j = _GetSameLen(src, srclen,nSeekStart, SortHeap[p].off);if ( j > m ){m = j;n = SortHeap[p].off;}p = SortHeap[p].next;}(*offset) = n;(*len) = m;return TRUE;}}return FALSE;}////////////////////////////////////////// 输出压缩码// code - 要输出的数// bits - 要输出的位数(对isGamma=TRUE时无效)// isGamma - 是否输出为γ编码void CCompressLZ77::_OutCode(BYTE* dest, DWORD code, int bits, BOOL isGamma){if ( isGamma ){BYTE* pb;DWORD out;// 计算输出位数int GammaCode = (int)code - 1;int q = LowerLog2(GammaCode);if (q > 0){out = 0xffff;pb = (BYTE*)&out;// 输出q个CopyBits(dest + CurByte, CurBit,pb, 0, q);MovePos(&CurByte, &CurBit, q);}// 输出一个out = 0;pb = (BYTE*)&out;CopyBits(dest + CurByte, CurBit, pb + 3, 7, 1);MovePos(&CurByte, &CurBit, 1);if (q > 0){// 输出余数, q位int sh = 1;sh <<= q;out = GammaCode - sh;pb = (BYTE*)&out;InvertDWord(&out);CopyBits(dest + CurByte, CurBit,pb + (32 - q) / 8, (32 - q) % 8, q);MovePos(&CurByte, &CurBit, q);}}else{DWORD dw = (DWORD)code;BYTE* pb = (BYTE*)&dw;InvertDWord(&dw);CopyBits(dest + CurByte, CurBit,pb + (32 - bits) / 8, (32 - bits) % 8, bits);MovePos(&CurByte, &CurBit, bits);}}/////////////////////////////////////////////// 压缩一段字节流// src - 源数据区// srclen - 源数据区字节长度// dest - 压缩数据区,调用前分配srclen+5字节内存// 返回值> 0 压缩数据长度// 返回值= 0 数据无法压缩// 返回值< 0 压缩中异常错误int CCompressLZ77::Compress(BYTE* src, int srclen, BYTE* dest) {int i;CurByte = 0; CurBit = 0;int off, len;if (srclen > 65536)return -1;pWnd = src;_InitSortTable();for (i = 0; i < srclen; i++){if (CurByte >= srclen)return 0;if (_SeekPhase(src, srclen, i, &off, &len)){// 输出匹配术语flag(1bit) + len(γ编码) + offset(最大bit)_OutCode(dest, 1, 1, FALSE);_OutCode(dest, len, 0, TRUE);// 在窗口不满k大小时,不需要位存储偏移_OutCode(dest, off, UpperLog2(nWndSize), FALSE);_ScrollWindow(len);i += len - 1;}else{// 输出单个非匹配字符0(1bit) + char(8bit)_OutCode(dest, 0, 1, FALSE);_OutCode(dest, (DWORD)(src[i]), 8, FALSE);_ScrollWindow(1);}}int destlen = CurByte + ((CurBit) ? 1 : 0);if (destlen >= srclen)return 0;return destlen;}/////////////////////////////////////////////// 解压缩一段字节流// src - 接收原始数据的内存区// srclen - 源数据区字节长度// dest - 压缩数据区// 返回值- 成功与否BOOL CCompressLZ77::Decompress(BYTE* src, int srclen, BYTE* dest) {int i;CurByte = 0; CurBit = 0;pWnd = src; // 初始化窗口nWndSize = 0;if (srclen > 65536)return FALSE;for (i = 0; i < srclen; i++){BYTE b = GetBit(dest[CurByte], CurBit);MovePos(&CurByte, &CurBit, 1);if (b == 0) // 单个字符{CopyBits(src + i, 0, dest + CurByte, CurBit, 8);MovePos(&CurByte, &CurBit, 8);nWndSize++;}else// 窗口内的术语{int q = -1;while (b != 0){q++;b = GetBit(dest[CurByte], CurBit);MovePos(&CurByte, &CurBit, 1);}int len, off;DWORD dw = 0;BYTE* pb;if (q > 0){pb = (BYTE*)&dw;CopyBits(pb + (32 - q) / 8, (32 - q) % 8, dest + CurByte, CurBit, q);MovePos(&CurByte, &CurBit, q);InvertDWord(&dw);len = 1;len <<= q;len += dw;len += 1;}elselen = 2;// 在窗口不满k大小时,不需要位存储偏移dw = 0;pb = (BYTE*)&dw;int bits = UpperLog2(nWndSize);CopyBits(pb + (32 - bits) / 8, (32 - bits) % 8, dest + CurByte, CurBit, bits);MovePos(&CurByte, &CurBit, bits);InvertDWord(&dw);off = (int)dw;// 输出术语for (int j = 0; j < len; j++){_ASSERT(i + j < srclen);_ASSERT(off + j < _MAX_WINDOW_SIZE);src[i + j] = pWnd[off + j];}nWndSize += len;i += len - 1;}// 滑动窗口if (nWndSize > _MAX_WINDOW_SIZE){pWnd += nWndSize - _MAX_WINDOW_SIZE;nWndSize = _MAX_WINDOW_SIZE;}}return TRUE;}。

霍夫曼树编码实验报告(3篇)

霍夫曼树编码实验报告(3篇)

第1篇一、实验背景霍夫曼树编码是一种基于字符频率进行数据压缩的算法,由David A. Huffman在1952年提出。

该算法通过构建霍夫曼树,为不同频率的字符分配不同长度的编码,从而实现数据压缩。

本实验旨在通过C语言实现霍夫曼树编码,并验证其压缩和解压缩效果。

二、实验目的1. 理解霍夫曼树编码的基本原理和步骤。

2. 掌握C语言实现霍夫曼树编码的方法。

3. 评估霍夫曼树编码的压缩效果和解压缩准确性。

三、实验原理霍夫曼树编码的核心思想是构建一棵霍夫曼树,该树由字符和它们的频率构成。

霍夫曼树的构建过程如下:1. 统计输入数据中每个字符的频率。

2. 将字符和频率作为节点,构建最小堆(优先队列)。

3. 重复以下步骤,直到堆中只剩下一个节点:a. 从堆中取出两个频率最小的节点,作为左右子节点。

b. 将这两个节点合并为一个新节点,其频率为两个节点频率之和。

c. 将新节点插入堆中。

4. 最小堆中的最后一个节点即为霍夫曼树的根节点。

霍夫曼树的叶子节点代表字符,非叶子节点代表子节点的频率之和。

根据霍夫曼树的构建,可以生成每个字符的编码,频率高的字符分配较短的编码,频率低的字符分配较长的编码。

四、实验步骤1. 数据准备:选择一段文本数据作为实验对象。

2. 字符频率统计:统计文本数据中每个字符的出现次数。

3. 构建霍夫曼树:根据字符频率构建霍夫曼树。

4. 生成编码表:根据霍夫曼树生成字符编码表。

5. 编码数据:使用编码表对文本数据进行编码。

6. 解压缩数据:根据编码表对编码后的数据进行解压缩。

7. 结果分析:比较原始数据和压缩数据的差异,评估压缩效果和解压缩准确性。

五、实验结果1. 字符频率统计:统计结果显示,字符“e”、“t”、“a”等在文本中出现的频率较高。

2. 构建霍夫曼树:成功构建了霍夫曼树,树中包含了所有字符及其频率。

3. 生成编码表:根据霍夫曼树生成了字符编码表,频率高的字符分配了较短的编码。

4. 编码数据:使用编码表对文本数据进行编码,成功生成了压缩数据。

用哈夫曼编码实现文件压缩.doc

用哈夫曼编码实现文件压缩.doc

《用哈夫曼编码实现文件压缩》实验报告课程名称数据结构(B)实验学期2009 至2010 学年第 1 学期学生所在系部计算机系年级2007 专业班级计算机B071学生姓名陆永芳学号200707014105任课教师盛建瓴实验成绩用哈夫曼编码实现文件压缩1、了解文件的概念。

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

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

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

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

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

本次实验采用将字符用长度尽可能短的二进制数位表示方法,即对于文件中出现的字符,无须全部都用8位的ASCII码进行存储,根据他们在文件中出现色频率不同,我们利用Haffman算法使每个字符都能以最短的二进制字符进行存储,以达到节省存储空间,压缩文件的目的。

解决了压缩需采用的算法,程序的思路就清晰了:1.统计需压缩文件中每个字符出现的频率2.将每个字符的出现频率作为叶子结点构建Haffman树,然后将树中结点引向其左孩子的分支标“0”,引向其右孩子的分支标“1”;每个字符的编码即为从根到每个叶子的路径得到0、1的序列,这样便能完成了Haffman的编码,将每个字符用最短的二进制字符表示。

3.打开需压缩文件,再将需压缩文件中的每个ascii码对应的Haffman编码按bit单位输出。

4.文件压缩结束。

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

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

实验一:语音压缩编码的实现

实验一:语音压缩编码的实现

实验一 语音压缩编码的实现——增量调制一、 实验目的(1) 会用MATLAB 语言表示基本的信号 (2) 用MA TLAB 实现语音信号的采集(3) 理解增量调制(DM )的原理并编程实现编译码二、 实验原理1、信号是随时间变化的物理量,它的本质是时间的函数。

信号可以分为时间连续信号和时间离散信号。

连续信号是指除了若干不连续的时间点外,每个时间点上都有对应的数值的信号。

离散信号则是只在某些不连续的点上有信号值,其它的时间点上信号没有定义的一类信号。

离散信号一般可以由连续信号经过模数转换而得到。

语音信号是模拟信号,经麦克风输入计算机后,就存为数字信号。

2、增量调制编码基本原理是采用一位二进制数码“1”或“0”来表示信号在抽样时刻的值相对于预测器输出的值是增大还是减小,增大则输出“1”码,减小则输出“0”码。

收端译码器每收到一个1码,译码器的输出相对于前一个时刻的值上升一个量化阶,而收到一个0码,译码器的输出相对于前一个时刻的值下降一个量化阶。

增量调制的系统结构框图如课本上图3.3-1所示。

在编码端,由前一个输入信号的编码值经解码器解码可得到下一个信号的预测值。

输入的模拟音频信号与预测值在比较器上相减,从而得到差值。

差值的极性可以是正也可以是负。

若为正,则编码输出为1;若为负,则编码输出为0。

这样,在增量调制的输出端可以得到一串1位编码的DM 码。

图3.3-1 增量调制的系统结构框图三、 实验内容与方法(一)、用windows 自带的录音机录一段自己的语音(3s 内),存为“.wav ”文件。

1、补充:语音信号的采集Wavread 函数常用的语法为:[y,fs,bite]=wavread(‘filename.wav’); 这里fs 为采样频率,bite 为采样点数。

AWGN :在某一信号中加入高斯白噪声输入信号y = awgn(x,SNR) 在信号x 中加入高斯白噪声。

信噪比SNR 以dB 为单位。

用哈夫曼编码实现文件压缩实验报告【管理资料】

用哈夫曼编码实现文件压缩实验报告【管理资料】

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

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

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

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

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

三、实验设备与环境:微型计算机、Windows 系列操作系统、Visual C++四、实验内容:根据输入小写英文字母和输入的对应权值创建哈夫曼树,可以求出每个小写英文字母的哈夫曼编码,将文本中的字母对应的哈夫曼编码写入文本中,实现对文本的编码。

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

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

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

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

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

(3) 文本编码读取存放在文本中的字母,一对一的进行编译,将对应的编码存放到另一个文本中。

#include<>#include<>#include<>//树结点定义typedef struct{int weight;int parent;int lchild;int rchild;}HTNode,*HuffmanTree;static char N[100];//用于保存字符//赫夫曼编码,char型二级指针typedef char **HuffmanCode;//封装最小权结点和次小权结点typedef struct{int s1;int s2;}MinCode;//函数声明void Error();HuffmanCode HuffmanCoding(HuffmanTree &HT,HuffmanCode HC,int *w,int n);MinCode Select(HuffmanTree HT,int n);//当输入1个结点时的错误提示void Error(){printf("一个字符不进行编码!\n");exit(1);}//构造赫夫曼HT,编码存放在HC中,w为权值,n为结点个数HuffmanCode HuffmanCoding(HuffmanTree &HT,HuffmanCode HC,int *w,int n){int i,s1=0,s2=0;HuffmanTree p;char *cd;int f,c,start,m;MinCode min;if(n<=1){Error();//只有一个结点不进行编码,直接exit(1)退出}m=2*n-1;//赫夫曼码需要开辟的结点大小为2n-1HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//开辟赫夫曼树结点空间m+1//初始化n个叶子结点for(p=HT,i=0;i<=n;i++,p++,w++){p->weight=*w;p->parent=0;p->lchild=0;p->rchild=0;}//将n-1个非叶子结点的初始化for(;i<=m;i++,p++){p->weight=0;p->parent=0;p->lchild=0;p->rchild=0;}//构造赫夫曼树for(i=n+1;i<=m;i++){min=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;//赋权和}//打印赫夫曼树printf("HT List:\n");printf("Number\t\tweight\t\tparent\t\tlchild\t\trchild\n");for(i=1;i<=m;i++){printf("%d\t\t%d\t\t%d\t\t%d\t\t%d\t\n",i,HT[i].weight,HT[i].parent,HT[i].lchild,HT[i].rchild);}//从叶子结点到根节点求每个字符的赫夫曼编码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;//定义左子树为0,右子树为1/*从最下面的1号节点开始往顶部编码(逆序存放),然后编码2号节点,3号......*/for(c=i,f=HT[i].parent; f!=0; c=f,f=HT[f].parent){if(HT[f].lchild==c)cd[--start]='0';elsecd[--start]='1';}//为第i个字符分配编码空间HC[i]=(char *)malloc((n-start)*sizeof(char *));//将当前求出结点的赫夫曼编码复制到HCstrcpy(HC[i],&cd[start]);}free(cd);return HC;}MinCode Select(HuffmanTree HT,int n){int min,secmin;int temp = 0;int i,s1,s2,tempi = 0;MinCode code ;s1=1;s2=1;min = 999999;//足够大//找出权值weight最小的结点,下标保存在s1中for(i=1;i<=n;i++){if(HT[i].weight<min && HT[i].parent==0){min=HT[i].weight;s1=i;}}secmin = 999999;//足够大//找出权值weight次小的结点,下标保存在s2中for(i=1;i<=n;i++){if((HT[i].weight<secmin) && (i!=s1) && HT[i].parent==0){secmin=HT[i].weight;s2=i;}}//放进封装中=s1;=s2;return code;}void Compression(HuffmanCode HC) //翻译原文档字符为赫夫曼编码FILE *fp1,*fp2;char ch;if((fp1 = fopen("","r")) == NULL)exit(0);if((fp2 = fopen("","a")) == NULL)exit(0);ch = fgetc(fp1);while((int)ch!= -1){switch(ch){case 'a': fputs(HC[1],fp2); break;case 'b': fputs(HC[2],fp2); break;case 'c': fputs(HC[3],fp2); break;case 'd': fputs(HC[4],fp2); break;case 'e': fputs(HC[5],fp2); break;case 'f': fputs(HC[6],fp2); break;case 'g': fputs(HC[7],fp2); break;case 'h': fputs(HC[8],fp2); break;case 'i': fputs(HC[9],fp2); break;case 'j': fputs(HC[10],fp2); break;case 'k': fputs(HC[11],fp2); break;case 'l': fputs(HC[12],fp2); break;case 'm': fputs(HC[13],fp2); break;case 'n': fputs(HC[14],fp2); break;case 'o': fputs(HC[15],fp2); break;case 'p': fputs(HC[16],fp2); break;case 'q': fputs(HC[17],fp2); break;case 'r': fputs(HC[18],fp2); break;case 's': fputs(HC[19],fp2); break;case 't': fputs(HC[20],fp2); break;case 'u': fputs(HC[21],fp2); break;case 'v': fputs(HC[22],fp2); break;case 'w': fputs(HC[23],fp2); break;case 'x': fputs(HC[24],fp2); break;case 'y': fputs(HC[25],fp2); break;case 'z': fputs(HC[26],fp2); break;default: printf(" 没有编码!\n");}ch = fgetc(fp1);}fclose(fp1);fclose(fp2);void main(){HuffmanTree HT=NULL;HuffmanCode HC=NULL;int *w=NULL;int i,n;printf("输入字符:");gets(N);n = strlen(N);w=(int *)malloc((n+1)*sizeof(int *));//开辟n+1个长度的int指针空间w[0]=0;printf("输入结点权值:\n");//输入结点权值for(i=1;i<=n;i++){printf("w[%d]=",i);scanf("%d",&w[i]);}//构造赫夫曼树HT,编码存放在HC中,w为权值,n为结点个数HC=HuffmanCoding(HT,HC,w,n);//输出赫夫曼编码printf("赫夫曼:\n");printf("Number\t\tWeight\t\tCode\n");for(i=1;i<=n;i++){printf("%c\t\t%d\t\t%s\n",N[i-1],w[i],HC[i]);}Compression(HC);}选取权值最小的结点的算法:选取权值次小的结点的算法:哈夫曼树建立的算法:哈夫曼编码的算法:七、测试结果及分析:4.输出哈夫曼树:5.字符对应编码:6.要编码的文本:7.编译后的文本:价。

霍夫曼编码的实验报告(3篇)

霍夫曼编码的实验报告(3篇)

第1篇一、实验目的1. 理解霍夫曼编码的基本原理和实现方法。

2. 掌握霍夫曼编码在数据压缩中的应用。

3. 通过实验,加深对数据压缩技术的理解。

二、实验环境1. 操作系统:Windows 102. 编程语言:C++3. 开发环境:Visual Studio 20194. 数据源:文本文件三、实验原理霍夫曼编码是一种常用的数据压缩算法,适用于无损数据压缩。

它通过使用变长编码表对数据进行编码,频率高的数据项使用短编码,频率低的数据项使用长编码。

霍夫曼编码的核心是构建一棵霍夫曼树,该树是一种最优二叉树,用于表示编码规则。

霍夫曼编码的步骤如下:1. 统计数据源中每个字符的出现频率。

2. 根据字符频率构建一棵最优二叉树,频率高的字符位于树的上层,频率低的字符位于树下层。

3. 根据最优二叉树生成编码规则,频率高的字符分配较短的编码,频率低的字符分配较长的编码。

4. 使用编码规则对数据进行编码,生成压缩后的数据。

5. 在解码过程中,根据编码规则恢复原始数据。

四、实验步骤1. 读取文本文件,统计每个字符的出现频率。

2. 根据字符频率构建最优二叉树。

3. 根据最优二叉树生成编码规则。

4. 使用编码规则对数据进行编码,生成压缩后的数据。

5. 将压缩后的数据写入文件。

6. 读取压缩后的数据,根据编码规则进行解码,恢复原始数据。

7. 比较原始数据和恢复后的数据,验证压缩和解码的正确性。

五、实验结果与分析1. 实验数据实验中,我们使用了一个包含10000个字符的文本文件作为数据源。

在统计字符频率时,我们发现字符“e”的出现频率最高,为2621次,而字符“z”的出现频率最低,为4次。

2. 实验结果根据实验数据,我们构建了最优二叉树,并生成了编码规则。

使用编码规则对数据源进行编码,压缩后的数据长度为7800个字符。

将压缩后的数据写入文件,文件大小为78KB。

接下来,我们读取压缩后的数据,根据编码规则进行解码,恢复原始数据。

比较原始数据和恢复后的数据,发现两者完全一致,验证了压缩和解码的正确性。

基于哈夫曼编码实现文本文件的压缩和解压缩实验报告模板

基于哈夫曼编码实现文本文件的压缩和解压缩实验报告模板

本科学生设计性实验报告软件工程技能实践Ⅰ项目组长陈启学号_*******专业软件工程班级_15软件7 班成员陈启杨林昌邓志远万胜实验项目名称_指导教师及职称__讲师__开课学期2015 至2016 学年第二学期一、实验设计方案1、实验任务与目的(简单介绍实验内容,说明实验任务和目的)1.1实验内容根据ascii码文件中各ascii字符出现的频率情况创建Haffman树,再将各字符对应的哈夫曼编码写入文件中,实现文件压缩。

对于给定的一组字符,可以根据其权值进行哈夫曼编码,并能输出对应的哈夫曼树和哈夫曼编码;实现哈夫曼解码。

能够分析文件,统计文件中出现的字符,再对文件进行编码,实现文件的压缩和解压缩,能够对于文件的压缩,比例进行统计,能够打印文件。

分析与设计哈夫曼树的存储结构,实现哈夫曼算法以及编码与译码基本功能,并对任意文本文件利用哈夫曼编码进行压缩得到压缩文件,然后进行解压缩得到解压文件。

1.2实验任务和目的1.2.1了解文件的概念。

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

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

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

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

2、实验思路(详细描述解决问题的整体思路、涉及的算法思想及数据结构等)2.1整体思路2.2涉及的算法思想及数据结构:2.2.1输入要压缩的文件首先运行的时候,用户主界面上有菜单提示该如何使用软件,根据菜单提示选择所要执行的项,依次进行,因为各个环节之间有先后顺序。

第一步为输入压缩软件的名称,由键盘输入文件路径和文件名称,读入字符数组中,打开该文件,按照提示进行压缩。

若打不开,则继续输入。

2.2.2读文件并计算字符频率文件将信息存放在字符数组中;计算每个字符出现的次数,申请一个结构体数组空间,用读取的字符减去字符结束符作为下标记录字符的频率。

2.2.3根据字符的频率,利用Huffman编码思想创建Huffman树将所记录的字符的频率作为权值来创建Huffman树,依次选择权值最小的两个字符作为左右孩子,其和作为父结点的权值,依次进行下去,直到所有的字符结点都成为叶子结点。

无损压缩编码实验

无损压缩编码实验

无损压缩编码实验实验报告一、实验题目:无损压缩编码实验二、实验要求:任选一种无损编码式,通过C++编程实现。

(1)字符串的输入是手工输入的。

(2)通过程序实现编码,最终在屏幕上现实编码结果。

三,实验分析采用霍夫曼编码实现无损压缩编码,从键盘输入若干字符及每个字符出现的频率,将字符出现的频率作为结点的权值,建立哈夫曼树,然后对各个字符进行哈夫曼编码,最后打印输出字符及对应的哈夫曼编码,并算出平均码长。

四,主要编码原理五,源程序代码#include <iostream>using namespace std;class HuffmanTree//霍夫曼树结构{public:unsigned int Weight, Parent, lChild, rChild;};typedef char **HuffmanCode;void Select(HuffmanTree* HT,int Count,int *s2,int *s1)//从结点集合中选出权值最小的两个结点{unsigned int temp1=0;unsigned int temp2=0;unsigned int temp3;for(int i=1;i<=Count;i++){if(HT[i].Parent==0){if(temp1==0){temp1=HT[i].Weight;(*s1)=i;}else{ if(temp2==0){temp2=HT[i].Weight;(*s2)=i;if(temp2<temp1){temp3=temp2;temp2=temp1;temp1=temp3;temp3=(*s2);(*s2)=(*s1);(*s1)=temp3;}}else{if(HT[i].Weight<temp1){temp2=temp1;temp1=HT[i].Weight;(*s2)=(*s1);(*s1)=i;}if(HT[i].Weight>temp1&&HT[i].Weight<temp2){temp2=HT[i].Weight;(*s2)=i;}}}}}}void HuffmanCoding(HuffmanTree * HT, HuffmanCode * HC,int *Weight,int Count)//霍夫曼编码函数{int i;int s1,s2;int TotalLength;char* cd;unsigned int c;unsigned int f;int start;if(Count<=1) return;TotalLength=Count*2-1;HT = new HuffmanTree[(TotalLength+1)*sizeof(HuffmanTree)];for(i=1;i<=Count;i++){HT[i].Parent=0;//父节点HT[i].rChild=0;//左孩子HT[i].lChild=0;//右孩子HT[i].Weight=(*Weight);Weight++;}for(i=Count+1;i<=TotalLength;i++){HT[i].Weight=0;HT[i].Parent=0;HT[i].lChild=0;HT[i].rChild=0;}//建造霍夫曼树for(i=Count+1;i<=TotalLength;++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;}//输出霍夫曼编码(*HC)=(HuffmanCode)malloc((Count+1)*sizeof(char*));cd = new char[Count*sizeof(char)];cd[Count-1]='\0';for(i=1;i<=Count;++i){start=Count-1;for(c = i,f = HT[i].Parent; f != 0; c = f, f = HT[f].Parent){if(HT[f].lChild == c)cd[--start]='0';elsecd[--start]='1';(*HC)[i] = new char [(Count-start)*sizeof(char)];strcpy((*HC)[i], &cd[start]);}}delete [] HT;delete [] cd;}int LookFor(char *str, char letter, int count)//在字符串中查找某个字符,如果找到,则返回其位置{ int i;for(i=0;i<count;i++){if(str[i]==letter) return i;}return -1;}void Quanzhi(char *Data,int Length,char **WhatLetter,int **Weight,int *Count)//计算权值并输出{int i;char* Letter = new char[Length];int* LetterCount = new int[Length];int AllCount=0;int Index;int Sum=0;float Persent=0;for(i=0;i<Length;i++){if(i==0){Letter[0]=Data[i];LetterCount[0]=1;AllCount++;}else{Index=LookFor(Letter,Data[i],AllCount);if(Index==-1){Letter[AllCount]=Data[i];LetterCount[AllCount]=1;AllCount++;}else{LetterCount[Index]++;}}}for(i=0;i<AllCount;i++)//计算平均码长{Sum=Sum+LetterCount[i];}(*Weight) = new int[AllCount];(*WhatLetter) = new char[AllCount];for(i=0;i<AllCount;i++){Persent=(float)LetterCount[i]/(float)Sum;(*Weight)[i]=(int)(100*Persent);(*WhatLetter)[i]=Letter[i];}(*Count)=AllCount;delete [] Letter;delete [] LetterCount;}int main()//主函数调用{HuffmanTree * HT = NULL;HuffmanCode HC;char Data[100];//储存输入的字符串char *Letter;int *Weight;int Count;cout<<"**********欢迎使用霍夫曼编码器********"<<endl; cout<<"请输入一行字符串:"<<endl;cin>>Data;cout<<endl;Quanzhi(Data,strlen(Data),&Letter, &Weight,&Count); HuffmanCoding(HT, &HC, Weight, Count);cout<<"字符出现频率和编码结果"<<endl;double K=0;double L;char P[100];for(int i = 0; i<Count; i++){cout<<Letter[i]<<" ";//字符cout<<Weight[i]<<"%\t";//出现频率cout<<HC[i+1]<<endl;//霍夫曼码strcpy(P,HC[i+1]);L=strlen(P);K=K+L*Weight[i]/100;}cout<<"平均码长"<<K;cout<<endl;system("pause");return 0;}六,测试结果输入字符串“jjjdddeielsl”七,实验总结通过本次实验,尤其在自己对程序的调试过程中,感觉对树的存储结构,终结状态,还有编码,译码的过程都有了比较清晰的认识。

哈夫曼文件压缩实验报告

哈夫曼文件压缩实验报告

哈夫曼文件压缩实验报告摘要:哈夫曼编码是一种常用的文件压缩算法,在本实验中我们通过使用哈夫曼编码算法对文件进行压缩和解压缩,来评估该算法在文件压缩方面的效果。

通过实验结果分析,我们发现哈夫曼编码能够有效地减小文件的大小,同时保持压缩后文件的可还原性。

1. 引言文件压缩是计算机科学领域的一个重要研究方向,它能够有效地减小文件的大小,节省存储空间和传输带宽。

哈夫曼编码作为一种经典的文件压缩算法,已被广泛应用于实际的文件压缩和传输中。

本实验旨在通过对哈夫曼编码的实际应用进行实验,评估其在文件压缩方面的效果。

2. 实验设计本实验分为三个步骤:文件读取、哈夫曼编码和压缩、解压和文件写入。

首先,我们需要从硬盘上读取待压缩的文件,并将其转化为二进制数据流。

接下来,我们使用哈夫曼编码算法对二进制数据流进行编码,生成编码后的数据流。

最后,我们根据编码表对编码后的数据流进行解码,恢复原始的二进制数据流,并将其写入硬盘上。

3. 实验过程首先,我们通过在计算机上选择一个待压缩的文件作为实验对象,然后设计一个程序来读取该文件的内容,并将其转化为二进制数据流。

为了保证实验结果的准确性,我们选择了不同类型和不同大小的文件进行实验,包括文本文件、图像文件和音频文件等。

接下来,我们使用哈夫曼编码算法对二进制数据流进行编码。

哈夫曼编码算法的核心思想是:将出现频率较高的字符用较短的编码表示,而将出现频率较低的字符用较长的编码表示,以达到最小化编码长度的效果。

在编码过程中,我们需要构建哈夫曼树和哈夫曼编码表。

哈夫曼树通过合并出现频率最低的两个节点来构建,最终生成一棵以根节点为基础的哈夫曼树。

哈夫曼编码表则是根据哈夫曼树的结构和编码规则生成的,将每个字符与对应的编码一一对应。

哈夫曼编码压缩实验报告

哈夫曼编码压缩实验报告

Huffman编码压缩实验报告程序说明:压缩/解压程序;计算压缩比。

实验说明:根据字符的权值,运用哈夫曼算法,找出最小的两个替代合为一个新权值,再放入队列,排序。

如此循环重复,直至算法结束,即只剩一个根节点。

最后,根节点记为0,相对的,子树左节点记为0,右节点记为1,一次输出编码。

源代码:#include<iostream>#include<algorithm>#include<string>#include<cstring>using namespace std;#define N 1000char st[N],cnt[N];int l,n,m,sum,newsum;struct aaa{char cc;int val;int dep;int l,r;int index;};struct bbb{char zi[200];int l;}bianma[200];aaa a[2000],b[2000];bool cmp(aaa a1, aaa a2){if(a1.val==a2.val)return a1.dep<a2.dep;elsereturn a1.val<a2.val;}void preput(int index){cout<<a[index].cc<<'('<<a[index].val<<") ";if(a[index].l!=0) preput(a[index].l);if(a[index].r!=0) preput(a[index].r);}void search(char st[200],int ll,int index,char ch){int i,j;ll++; st[ll]=ch;if(a[index].l==0){cout<<"The "<<a[index].cc<<" will be ";if(ll==1){cout<<'0'; bianma[int(a[index].cc)].zi[1]='0'; bianma[int(a[index].cc)].l=1; } else{bianma[int(a[index].cc)].l=0;for(i=2;i<=ll;i++){bianma[int(a[index].cc)].l++;bianma[int(a[index].cc)].zi[bianma[int(a[index].cc)].l]=st[i];cout<<st[i];}}cout<<endl;}else{search(st,ll,a[index].l,'0');search(st,ll,a[index].r,'1');}}int maxx(int a,int b){if(a>b) return a; else return b;}int main(){int i,j;cout<<"***********************************************************"<<endl; cout<<"Please input your characters needed to compreSS,end with !"<<endl;cout<<"***********************************************************"<<endl; cout<<"Your string: ";while(cin.getline(st,sizeof(st))){l=strlen(st); n=1; sum=8*l;for(i=0;i<l;i++) cnt[i]=st[i];if(l==1 && st[0]=='!') break;sort(st,st+l);a[n].cc=st[0]; a[n].val=1; a[n].dep=0; a[n].l=0; a[n].r=0; a[n].index=1;for(i=1;i<l;i++)if(st[i]!=a[n].cc){n++;a[n].cc=st[i]; a[n].val=1; a[n].dep=0; a[n].l=0; a[n].r=0; a[n].index=n;}elsea[n].val++;for(i=1;i<=n;i++){b[i]=a[i];cout<<"The "<<b[i].cc<<" weighted "<<b[i].val<<endl;}cout<<endl;i=1;m=n;sort(b+i,b+i+n,cmp);while(i<m){n++;a[n].val=b[i].val+b[i+1].val; a[n].index=n;a[n].l=b[i].index; a[n].r=b[i+1].index; a[n].dep=maxx(b[i].dep,b[i+1].dep)+1; m=n;b[m]=a[n];i+=2;sort(b+i,b+1+n,cmp);}char st2[200];search(st2,0,m,'0');cout<<endl;cout<<"The final result: "; newsum=0;for(i=0;i<l;i++){for(j=1;j<=bianma[int(cnt[i])].l;j++){cout<<bianma[int(cnt[i])].zi[j];newsum++;}}cout<<endl;cout<<"compression ratio(压缩比):"<<newsum*1.0*100/sum<<"%"<<endl;cout<<endl;cout<<"Your string: "; }return 0;}实验结果截图:只输入数字只输入字母输入数字+字母。

哈夫曼编码 实验报告

哈夫曼编码 实验报告

哈夫曼编码实验报告哈夫曼编码实验报告一、引言哈夫曼编码是一种用于数据压缩的算法,由大卫·哈夫曼于1952年提出。

它通过将出现频率高的字符用较短的编码表示,从而实现对数据的高效压缩。

本实验旨在通过实际操作和数据分析,深入了解哈夫曼编码的原理和应用。

二、实验目的1. 掌握哈夫曼编码的基本原理和算法;2. 实现哈夫曼编码的压缩和解压缩功能;3. 分析不同数据集上的压缩效果,并对结果进行评估。

三、实验过程1. 数据集准备本实验选取了三个不同的数据集,分别是一篇英文文章、一段中文文本和一段二进制数据。

这三个数据集具有不同的特点,可以用来评估哈夫曼编码在不同类型数据上的压缩效果。

2. 哈夫曼编码实现在实验中,我们使用了Python编程语言来实现哈夫曼编码的压缩和解压缩功能。

首先,我们需要统计数据集中各个字符的出现频率,并构建哈夫曼树。

然后,根据哈夫曼树生成每个字符的编码表,将原始数据转换为对应的编码。

最后,将编码后的数据存储为二进制文件,并记录编码表和原始数据的长度。

3. 压缩效果评估对于每个数据集,我们比较了原始数据和压缩后数据的大小差异,并计算了压缩比和压缩率。

压缩比是指压缩后数据的大小与原始数据大小的比值,压缩率是指压缩比乘以100%。

通过对比不同数据集上的压缩效果,我们可以评估哈夫曼编码在不同类型数据上的性能。

四、实验结果与分析1. 英文文章数据集对于一篇英文文章,经过哈夫曼编码压缩后,我们发现压缩比为0.6,即压缩后的数据只有原始数据的60%大小。

这说明哈夫曼编码在英文文本上具有较好的压缩效果。

原因在于英文文章中存在大量的重复字符,而哈夫曼编码能够利用字符的出现频率进行编码,从而减少数据的存储空间。

2. 中文文本数据集对于一段中文文本,我们发现哈夫曼编码的压缩效果不如在英文文章上的效果明显。

压缩比为0.8,即压缩后的数据只有原始数据的80%大小。

这是因为中文文本中的字符种类较多,并且出现频率相对均匀,导致哈夫曼编码的优势减弱。

压缩技术实验编码

压缩技术实验编码

实验一统计编码一、实验目的1.熟悉统计编码的原理2.掌握元编码的方法;3.了解编码效率及冗余度的计算;二、实验原理霍夫曼编码, 又称最佳编码,根据字符出现概率来构造平均长度最短的变长编码。

编码步骤:()(,…)按出现概率的值由大到小的顺序排列;()对两个概率最小的符号分别分配以“”和“”,然后把这两个概率相加作为一个新的辅助符号的概率;()()()用线将符号连接起来,从而得到一个码树,树的个端点对应个信源符号;()从最后一个概率为的节点开始,沿着到达信源的每个符号,将一路遇到的二进制码“”或“”顺序排列起来,就是端点所对应的信源符号的码字。

以上是二元霍夫曼编码。

如果是元霍夫曼编码,则应该如何做呢?在编码方案中,为出现概率较小的信源输出分配较长的码字,而对那些出现可能性较大的信源输出分配较短的码字。

为此,首先将个最小可能的信源输出合并成为一个新的输出,该输出的概率就是上述的个输出的概率之和。

重复进行该过程直到只剩下一个输出为止。

信源符号的个数与必须满足如下的关系式:() 为整数如果不满足上述关系式,可通过添加概率为零的信源符号来满足。

这样就生成了一个树,从该树的根节点出发并将、……分别分配给任何个来自于相同节点的分支,生成编码。

可以证明用这种方法产生的编码在前向树类编码中具有最小的平均长度。

举例:对于取值为{}其相应的概率为{,,,,,}的信源,试设计一个元码,求出码子的平均长度与编码效率。

注:因为是元编码,所以每次个概率值相加。

码字的平均长度××××××信源的熵()(×() ×() ×() ×()0.×() ×()编码效率用实现该编码的方法可用下面的矩阵来说明:①②⑤⑤③①②⑥④④②③③⑤③③①②④①②①⑤④①②⑥③. ⑦⑦注:每次个数加完后,重新按序分配编号,在按概率值重新排序,再进行下次加数。

视频压缩编码算法研究及实现的开题报告

视频压缩编码算法研究及实现的开题报告

视频压缩编码算法研究及实现的开题报告一、研究背景和意义随着移动互联网和数字化技术的快速发展,视频成为数字媒体应用中最为重要的一环,但视频数据量巨大,需要占用大量存储空间和传输带宽,不利于实现快速传输和共享。

因此,视频压缩编码技术得到广泛关注和研究,是实现高效视频存储和传输的关键技术之一。

视频压缩编码技术主要包括两个方面:压缩和编码。

视频压缩是通过一系列算法将视频信号的冗余信息去除,减少数据量的过程,包括空间域压缩、频域压缩和时域压缩等;而视频编码是将压缩后的视频信号转换成数字信号,用于存储和传输,包括帧间编码、帧内编码和混合编码等。

因此,视频压缩编码技术的研究和发展对于数字媒体的应用具有十分重要的意义,有助于提高视频存储和传输的效率、降低成本、提升用户体验,并推动数字媒体行业的健康发展。

二、研究目标和内容本文旨在研究视频压缩编码技术,具体包括以下内容:1.深入研究视频压缩编码的基本原理和常用算法,如H.264/AVC、VP9、HEVC等;2.分析不同算法之间的差异和优缺点,比较不同算法的压缩效率、图像质量和计算复杂度等指标;3.基于研究成果,实现一个视频压缩编码算法,探索不同算法的应用场景和优化方法;4.在实现算法的基础上,进行实验验证和性能评估,包括压缩比率、视频质量、延迟、占用带宽等指标。

三、研究方法和技术路线本文主要采用文献综述、理论分析和实验验证等方法,具体技术路线如下:1.收集研究领域内的重要文献资料,系统梳理视频压缩编码技术的基本原理和常用算法;2.分析不同算法的核心思想、编码流程和优缺点,比较不同算法的性能指标和适用场景;3.实现一个视频压缩编码算法,基于C/C++等编程语言开发,研究编码器和解码器的逻辑实现;4.利用测试数据集进行实验验证,运用压缩比率、图像质量、延迟时间、占用带宽等指标对算法性能进行评估。

四、预期成果和意义本文研究视频压缩编码技术,预期达到以下成果:1.全面深入的掌握视频压缩编码的基本原理和常用算法;2.比较不同算法的性能指标和适用场景,为实际应用提供参考;3.实现一个视频压缩编码算法,并进行性能评估,验证算法的有效性和可行性;4.推动数字媒体行业的健康发展,为国家数字经济发展做出贡献。

压缩实验报告

压缩实验报告

压缩实验报告压缩实验报告引言:压缩技术是现代信息技术中不可或缺的一部分。

它可以将大量的数据压缩成较小的体积,从而节省存储空间和传输带宽。

本实验旨在探究不同压缩算法的效果,并比较它们的优缺点。

一、实验设备和方法本实验使用了一台配置较高的计算机,并安装了常用的压缩软件。

实验过程中,我们选择了两种常见的压缩算法:Huffman编码和Lempel-Ziv-Welch(LZW)算法。

二、实验过程1. Huffman编码:Huffman编码是一种基于字符出现频率的压缩算法。

它通过构建哈夫曼树,将出现频率较高的字符用较短的编码表示,而出现频率较低的字符用较长的编码表示。

我们首先选择了一个文本文件进行压缩实验。

通过对文件进行统计分析,我们得到了每个字符的出现频率。

然后,根据频率构建了一棵哈夫曼树,并生成了对应的编码表。

最后,我们将原始文本文件使用Huffman编码进行压缩,并记录了压缩后的文件大小。

2. LZW算法:LZW算法是一种基于字典的压缩算法。

它通过建立字典并将输入文本与字典中的条目进行匹配,从而实现压缩。

当输入文本中的字符序列在字典中不存在时,将其添加到字典中,并输出前一个匹配的条目的编码。

我们选择了一段音频文件进行LZW算法的压缩实验。

首先,我们将音频文件转化为二进制数据,并建立一个初始字典,包含所有可能的字符。

然后,按照LZW算法的步骤,将输入文本与字典中的条目进行匹配,并输出对应的编码。

最后,我们记录了压缩后的文件大小。

三、实验结果与分析通过对压缩后的文件大小进行比较,我们得出了以下结论:1. Huffman编码相对于LZW算法,在处理文本文件时具有更好的压缩效果。

这是因为文本文件中存在大量重复的字符,而Huffman编码可以根据字符的出现频率进行编码,从而实现较高的压缩比。

2. LZW算法在处理音频文件时表现更好。

音频文件中的数据通常具有较高的连续性,而LZW算法可以通过建立字典并匹配连续的字符序列,实现较好的压缩效果。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

压缩编码算法设计与实现实验报告
一、实验目的:用C语言或C++编写一个实现Huffman编码的程序,理解对数据进行无损压缩的原理。

二、实验内容:设计一个有n个叶节点的huffman树,从终端读入n个叶节
点的权值。

设计出huffman编码的压缩算法,完成对n个节点的编码,并写出程序予以实现。

三、实验步骤及原理:
1、原理:Huffman算法的描述
(1)初始化,根据符号权重的大小按由大到小顺序对符号进行排序。

(2)把权重最小的两个符号组成一个节点,
(3)重复步骤2,得到节点P2,P3,P4……,形成一棵树。

(4)从根节点开始顺着树枝到每个叶子分别写出每个符号的代码
2、实验步骤:
根据算法原理,设计程序流程,完成代码设计。

首先,用户先输入一个数n,以实现n个叶节点的Huffman 树;
之后,输入n个权值w[1]~w[n],注意是unsigned int型数值;
然后,建立Huffman 树;
最后,完成Huffman编码。

四、实验代码:#include <stdio.h>
#include <malloc.h>
#include <string.h>
#define MAX 0xFFFFFFFF
typedef struct / /*设计一个结构体,存放权值,左右孩子*//
{
unsigned int weight;
unsigned int parent,lchild,rchild;
}HTNode,*HuffmanTree;
typedef char** HuffmanCode;
int min(HuffmanTree t,int i)
{
int j,flag;
unsigned int k = MAX;
for(j=1;j<=i;j++)
if(t[j].parent==0&&t[j].weight<k)
{
k=t[j].weight;
flag = j;
}
t[flag].parent = 1;
return flag;
}
void select(HuffmanTree h,int i,int &s1,int &s2)
{
int tmp;
s1 = min(h,i);
s2 = min(h,i);
if(s1 > s2)
{
tmp = s1;
s1 = s2;
s2 = tmp;
} }
void HuffmanCoding(HuffmanTree &HT,HuffmanCode &HC,int *w,int n,int &wpl)
{
int m,i,s1,s2,start,j;
unsigned int c,f;
HuffmanTree p;
char *cd;
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,++w)
{
(*p).weight=*w;
(*p).parent=0;
(*p).lchild=0;
(*p).rchild=0;
}
for(;i<=m;++i,++p)
{
(*p).weight=0;
(*p).parent=0;
(*p).lchild=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;
}
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));
wpl=wpl+(n-start-1)*HT[i].weight;
strcpy(HC[i],&cd[start]);
}
free(cd);
}
int main()
{
HuffmanTree HT;
HuffmanCode HC;
int *w,n,i,wpl=0;
printf("请输入叶节点的个数[>1]:");
scanf("%d",&n);
w=(int*)malloc(n*sizeof(int));
printf("请依次输入%d个权值[整型]fd:\n",n);
for(i=0;i<=n-1;i++)
scanf("%d",w+i);
HuffmanCoding(HT,HC,w,n,wpl);
for(i=1;i<=n;i++)
printf("权值为%d的Huffman编码
为:%s\n",HT[i].weight,HC[i]);
printf("带权路径长度WPL=%d\n",wpl);
return 0;
}
五、实验结果截图:
六、实验心得:通过本次多媒体实验,我又一次认真地学习了哈弗曼编码的方法和优点,在本次实验课程之前,我已经在《信息论与编码》和《多媒体技术教程》等课程中学习了多种编码方法,了解到哈弗曼编码是一种变长编码,并且哈弗曼编码的平均码长最小,传输速率最大,编码速率最高;通过编程的研究和最后运行结果分析,我们可以很容易看出,码字的权值越大,对应的编码越短。

在这次实验编程中开始虽然明白哈弗码编码的数学计算过程,但是要转换成C 语言遇到了很大困难,但是通过同学之间的讨论,课本的进一步了解与网络的查询,困难都一一迎刃而解。

相关文档
最新文档