霍夫曼信源编码实验报告
优秀Huffman编码 实验报告

实验二:Huffman 编码的实现实验学时:3实验类型:(演示、验证、综合、√设计、研究)实验要求:(√必修、选修)一、 实验目的 理解和掌握huffman 编码的基本原理和方法,实现对信源符号的huffman 编码。
二、 实验内容1. 理解和掌握huffman 编码的基本原理和方法2. 通过MATLAB 编程实现对单信源符号的huffma 编码3. 计算信源的信息熵、平均码长以及编码效率三、 实验原理1.Huffman 编码按信源符号出现的概率而编码,其平均码长最短,所以是最优码。
2.无失真信源编码定理:对于熵为H (X )的离散无记忆的平稳信源,必存在一种无失真编码,使每符号的平均码长满足不等式:()()1log log H S H S L r r≤<+ 3.二元Huffman 编码:若将编码设计为长度不等的二进制编码,即让待传字符串中出现概率大的字符采用尽可能短的码字,而把长的码字分配给概率小的信源符号。
构造方法如下:(a ) 将信源概率分布按大小以递减次序排列;合并两概率最小者,得到新信源;并分配0/1符号。
(b ) 新信源若包含两个以上符号返回(a ),否则到(c )。
(c ) 从最后一级向前按顺序写出每信源符号所对应的码字。
四、 实验数据源1.12345[]:0.40.20.20.10.1s s s s s X P ⎧⋅⎨⎩:{0,1}X2.123456[]:0.240.200.180.160.140.08s s s s s s X P ⎧⋅⎨⎩:{0,1}X 五、实验组织运行要求以学生自主训练为主的开放模式组织教学六、实验条件(1)微机(2)MATLAB 编程工具七、实验原理七、实验代码clear% S=[0.4,0.2,0.2,0.1,0.1]; S=[0.24,0.20,0.18,0.16,0.14,0.08];% S=[0.20,0.19,0.18,0.17,0.15,0.10,0.01];S0=sort(S); %将序列进行升序排列S1=fliplr(S0); %将升序排列的概率进行左右翻转得到降序排列t=length(S1); %得到信源符号的个数coding_table=[S1']; %创建编码过程表,第一列for i=1:length(S1)-1s=coding_table(t,i)+coding_table(t-1,i); %最小两个值相加S1(t-1)=s;S1(t)=0;t=t-1;S1=fliplr(sort(S1)); %进行重新降序排列coding_table=[coding_table,S1']; %排序结果加入到编码过程表for j=1:length(S1)if s==S1(j)b(i)=j; %记录两个最小概率相加得到的值在新排序中的位置。
Huffman编码实验报告

图像Huffman编码实验报告
1 实验目的
(1)熟练掌握Huffman编码的方法;
(2)理解无失真信源编码和限失真编码方法在实际图像信源编码应用中的差异。
2 实验内容与步骤
(1)针对“image1.bmp”、“image2.bmp”和“image3.bmp”进行灰度频率统计(即计算图像灰度直方图),在此基础上添加函数代码构造Huffman码表,针对图像数据进行Huffman编码,观察和分析不同图像信源的平均码长、编码效率和压缩比。
(2)针对任意一幅图像,得到其差分图像,对差分图像统计灰度频率,进行Huffman编码,计算平均码长、编码效率和压缩比,并与(1)对比。
3 实验结果
(1)对图像数据进行Huffman 编码,得到不同图像信源的平均码长、编码效率和压缩比如下:
image1:5.960179 0.994678 1.342242
image2:4.443604 0.992368 1.800341
image3:6.733643 0.996281 1.188064
(2)对lenna.bmp 进行Huffman 编码,得到其平均码长、编码效率和压缩比分别是:
5.294220 0.994358 1.511082。
霍夫曼编码设计实验报告

一、实验目的1. 理解霍夫曼编码的基本原理和算法流程。
2. 掌握霍夫曼编码的构建过程和编码方法。
3. 通过实验验证霍夫曼编码在数据压缩方面的效果。
4. 提高编程能力和数据结构应用能力。
二、实验环境1. 操作系统:Windows 102. 编程语言:C++3. 开发工具:Visual Studio 2019三、实验原理霍夫曼编码是一种基于字符出现频率进行编码的数据压缩方法。
其基本原理如下:1. 对字符进行统计,得到每个字符出现的频率。
2. 根据频率对字符进行排序,频率高的字符排在前面。
3. 构建霍夫曼树,将频率高的字符放在树的左侧,频率低的字符放在树的右侧。
4. 从树根到叶子节点,为每个字符分配一个二进制编码,频率高的字符用较短的编码表示,频率低的字符用较长的编码表示。
四、实验步骤1. 定义一个结构体HuffmanNode,用于存储字符及其频率。
2. 实现一个函数用于统计字符频率。
3. 实现一个函数用于构建霍夫曼树。
4. 实现一个函数用于生成霍夫曼编码。
5. 实现一个函数用于解码霍夫曼编码。
6. 编写主函数,进行实验验证。
五、实验过程1. 定义结构体HuffmanNode,用于存储字符及其频率。
```cppstruct HuffmanNode {char ch;int weight;HuffmanNode lchild, rchild;};```2. 实现一个函数用于统计字符频率。
```cppvoid StatFrequency(char str, int freq) {int length = strlen(str);for (int i = 0; i < 256; ++i) {freq[i] = 0;}for (int i = 0; i < length; ++i) {freq[(int)str[i]]++;}}```3. 实现一个函数用于构建霍夫曼树。
```cppHuffmanNode CreateHuffmanTree(int freq, int length) {HuffmanNode nodes = new HuffmanNode[length + 1];for (int i = 0; i < length; ++i) {nodes[i].ch = 'a' + i;nodes[i].weight = freq[i];nodes[i].lchild = nullptr;nodes[i].rchild = nullptr;}for (int i = length; i < length + 1; ++i) {nodes[i].ch = '\0';nodes[i].weight = 0;nodes[i].lchild = nullptr;nodes[i].rchild = nullptr;}for (int i = 0; i < length - 1; ++i) {HuffmanNode minNode1 = &nodes[0];HuffmanNode minNode2 = &nodes[1];for (int j = 0; j < length + 1; ++j) {if (nodes[j].weight < minNode1->weight) {minNode2 = minNode1;minNode1 = &nodes[j];} else if (nodes[j].weight < minNode2->weight && nodes[j].weight > minNode1->weight) {minNode2 = &nodes[j];}}nodes[i].weight = minNode1->weight + minNode2->weight;nodes[i].lchild = minNode1;nodes[i].rchild = minNode2;minNode1->parent = &nodes[i];minNode2->parent = &nodes[i];}return &nodes[length - 1];}```4. 实现一个函数用于生成霍夫曼编码。
实验三 信源编码实验

实验三信源编码实验一、实验目的:1、掌握哈夫曼编码的Matlab实现方法。
2、掌握VC++读取信源数据的方法。
3、运行编译好的霍夫曼编码、算术编码、游程编码编码程序,比较霍夫曼编码、算术编码、游程编码编码的编码效果二、实验内容与步骤1、Huffman编码实验1)编写计算信息熵的M文件参考程序:function h=entropy(p)%H=ENTROPY(P)返回概率矢% 量P的熵函数if length (find(p<0))~=0error('Not a prob.vector,negative component(s)')endif abs (sum(p)-1)>10e-10error ('Not a prob.vector,components do not add up to 1') endh=sum(-p.*log2(p));求信源X=[x1,x2,…,x9],其相应的概率为p=[0.2,0.15,0.13,0.12,0.1,0.09,0.08,0.07,0.06];利用编写的程序计算信息熵,并记录数值。
2)编写程序实现Huffman编码编写实现Huffman编码的M文件,编译后运行,验证程序的正确性并记录编码结果。
参考程序:function [h,l]=huffman(p);%HUFFMAN 哈夫曼编码生成器% [h,l]=huffman(p),返回哈夫曼编码矩阵H及码字长度if length (find (p<0))~=0,erro('Not a prob.vector,negative component(s)')endif abs(sum(p)-1)>10e-10,error('Not a prob.vector,components do not add up to 1') endn=length(p);q=p;m=zeros(n-1,n);for i=1:n-1[q,l]=sort(q);m(i,:)=[l(1:n-i+1),zeros(1,i-1)];q=[q(1)+q(2),q(3:n),1];endfor i=1:n-1c(i,:)=blanks(n*n);endc(n-1,n)='0';c(n-1,2*n)='1';for i=2:n-1c(n-i,1:n-1)=c(n-i+1,n*(find(m(n-i+1,:)==1))-(n-2):n*(fi nd(m(n-i+1,:)==1)));c(n-i,n)='0';c(n-i,n+1:2*n-1)=c(n-i,1:n-1);c(n-i,2*n)='1';for j=1:i-1c(n-i,(j+1)*n+1:(j+2)*n)=c(n-i+1,n*(find(m(n-i+1,:)==j+1 )-1)+1:n*find(m(n-i+1,:)==j+1));endendfor i=1:nh(i,1:n)=c(1,n*(find(m(1,:)==i)-1)+1:find(m(1,:)==i)*n); ll(i)=length(find(abs(h(i,:))~=32));endl=sum(p.*ll);在命令行后输入》p=[0.1 0.3 0.05 0.09 0.21 0.25];》[H,l]=huffman(p)记录运行结果,并说明编码结果是否正确,计算编码效率。
信息论霍夫曼编码译码实验报告

实验一一、实验背景*哈夫曼编码(Huffman Coding)是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。
Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般叫作Huffman编码。
二、实验要求*利用程序实现哈夫曼编码,以加深对哈夫曼编码的理解,并锻炼编程能力。
三、代码分析#include<stdio.h>#define n 3 //叶子数目#define m (2*n-1) //结点总数#define maxval 10000.0 //maxval是float类型的最大值#define maxsize 100 //哈夫曼编码的最大位数typedef struct //定义霍夫曼树结构体{char ch; //消息float weight; //所占权重int lchild,rchild,parent; //定义左孩子、右孩子}hufmtree;typedef struct //定义霍夫曼编码结构体{char bits[n]; //位串int start; //编码在位串中的起始位置char ch; //字符}codetype;void huffman(hufmtree tree[]); //建立哈夫曼树void huffmancode(codetype code[],hufmtree tree[]); //根据哈夫曼树求出哈夫曼编码void decode(hufmtree tree[]); //依次读入电文,根据哈夫曼树译码void main(){printf(" ——哈夫曼编码——\n");printf("信源共有%d个符号\n",n);hufmtree tree[m]; //m个结点,即有m个树形结构codetype code[n]; //信源有n个消息,则需要n个编码int i,j; //循环变量huffman(tree); //建立哈夫曼树huffmancode(code,tree); //根据哈夫曼树求出哈夫曼编码printf("【输出每个字符的哈夫曼编码】\n");for(i=0;i<n;i++){printf("%c: ",code[i].ch);for(j=code[i].start;j<n;j++)printf("%c ",code[i].bits[j]);//“消息:该消息的编码”printf("\n");}printf("【读入电文,并进行译码】\n");decode(tree); //依次读入电文,根据哈夫曼树译码}void huffman(hufmtree tree[]) //建立哈夫曼树{int i,j,p1,p2; //p1,p2分别记住每次合并时权值最小和次小的两个根结点的下标float small1,small2,f;char c;for(i=0;i<m;i++) //初始化{tree[i].parent=0;tree[i].lchild=-1;tree[i].rchild=-1;tree[i].weight=0.0;}printf("【依次读入前%d个结点的字符及权值(中间用空格隔开)】\n",n);for(i=0;i<n;i++) //读入前n个结点的字符及权值{printf("输入第%d个字符为和权值",i+1);scanf("%c %f",&c,&f);getchar(); //吸收回车符tree[i].ch=c;tree[i].weight=f; //将接收到的结点的字符及权值存入它对应的结构体数据中}for(i=n;i<m;i++) //进行n-1次合并,产生n-1个新结点{p1=0;p2=0;small1=maxval;small2=maxval; //maxval是float类型的最大值for(j=0;j<i;j++) //选出两个权值最小的根结点{if(tree[j].parent==0) //还未找到父结点的if(tree[j].weight<small1) //如果有比最小的还小的{small2=small1; //改变最小权、次小权及对应的位置small1=tree[j].weight;p2=p1;p1=j;}else if(tree[j].weight<small2) //如果有比最小的大,但比第二小的小的{small2=tree[j].weight; //改变次小权及位置p2=j;}}//找出的两个结点是新节点i的两个孩子tree[p1].parent=i;tree[p2].parent=i;tree[i].lchild=p1; //最小权根结点是新结点的左孩子tree[i].rchild=p2; //次小权根结点是新结点的右孩子tree[i].weight=tree[p1].weight+tree[p2].weight;}} //huffman//codetype code[]为求出的哈夫曼编码//hufmtree tree[]为已知的哈夫曼树void huffmancode(codetype code[],hufmtree tree[]) //根据哈夫曼树求出哈夫曼编码{int i,c,p;codetype cd; //缓冲变量for(i=0;i<n;i++){cd.start=n; //编码在位串中的起始位置cd.ch=tree[i].ch;c=i; //从叶结点出发向上回溯,第i个叶结点p=tree[i].parent; //tree[p]是tree[i]的父结点while(p!=0){cd.start--;if(tree[p].lchild==c)cd.bits[cd.start]='0'; //tree[i]是左子树,生成代码'0' elsecd.bits[cd.start]='1'; //tree[i]是右子树,生成代码'1' c=p; //c记录此时的父结点p=tree[p].parent; //p记录新的父结点,即原来的父结点的父结点,向上溯回}code[i]=cd; //第i+1个字符的编码存入code[i] }} //huffmancodevoid decode(hufmtree tree[])//依次读入电文,根据哈夫曼树译码{int i,j=0;char b[maxsize];i=m-1; //从根结点开始往下搜索printf("输入发送的编码:");gets(b);printf("译码后的字符为");while(b[j]!='\0'){if(b[j]=='0')i=tree[i].lchild; //走向左子树elsei=tree[i].rchild; //走向右子树if(tree[i].lchild==-1) //如果回到叶结点,则把该结点的消息符号输出{printf("%c",tree[i].ch);i=m-1; //回到根结点}j++;}printf("\n");if(tree[i].lchild!=-1&&b[j]=='\0') //电文读完,但尚未到叶子结点printf("\nERROR\n"); //输入电文有错}//decode四、实验补充说明解码时,以回车键结束输入电文。
Huffman编解码实验报告

Huffman编解码实验报告⽂本⽂件的⼆进制预统计Huffman编解码⼀、实验⽬的(1) 熟悉Huffman编解码算法;(2) 理解Huffman编码的最佳性。
⼆、实验内容1、编程思想霍夫曼(Huffman)编码是1952年为⽂本⽂件⽽建⽴,是⼀种统计编码。
属于⽆损压缩编码。
霍夫曼编码的码长是变化的,对于出现频率⾼的信息,编码的长度较短;⽽对于出现频率低的信息,编码长度较长。
这样,处理全部信息的总码长⼀定⼩于实际信息的符号长度。
计算机编程实现时,⾸先统计带编码的⽂本⽂件中各个字符出现的概率,然后将概率作为节点的权值构建huffman树。
编码时从叶⼦节点出发,如果这个节点在左⼦树上,则编码0,否则编码1,直到根节点为⽌,所得到的01序列即为该叶⼦节点的编码。
所有叶⼦节点的编码构成⼀个码本。
有两种译码⽅法:(1)按位读⼊码字,从已建好的Huffman树的根节点开始,若码字为“0”,则跳到左⼦树,若为“1”则跳到右⼦树,直到叶⼦结点为⽌,输出叶⼦接点所表⽰的符号。
(2)由于Huffman编码是唯⼀码,还有另⼀种译码⽅法,每读⼊⼀位编码就去码本中去匹配相应的码字,若匹配不成功,则继续读⼊下⼀个编码,直到匹配成功为⽌。
显然前⼀种⽅法⽐较简便,本程序采⽤便是该⽅法。
2、程序流程图3、编程实现本实验采⽤⽤C 语⾔程序语⾔,VC++ 6.0编程环境。
(1)数据结构构造存放符号及其权值的存储结构如下 typedef struct {unsigned char symbol; //符号的ASCII 码值 int sweight; //权值}syml_weit;syml_weit *sw;构造huffman 树存储结构如下:typedef struct {int weit; //权值int lchd; //左孩⼦地址 int rchd; //右孩⼦地址 int part; //双亲地址 }hufmtree;hufmtree *htree;(2)函数本程序共包含5个函数:⼀个主函数:void main(), 4个⼦函数:void CountWeight(unsigned char *DataBuf,int FileLen); void BuildTree();void HufmCode(unsigned char *DataBuf,int FileLen); void HufmDCode(unsigned char *CDataBuf,int CDataLen); 其功能分别CountWeight----计算⽂本⽂件中各符号的权值; BuildTree-------构建Huffman 树,形成码本; HufmCode---------对⽂本⽂件进⾏编码; HufmDCode-------进⾏译码。
信源编码硬件实验报告

1. 了解信源编码的基本原理和重要性;2. 掌握霍夫曼编码和算术编码的硬件实现方法;3. 分析信源编码在实际应用中的性能和优势;4. 通过实验,提高动手能力和理论联系实际的能力。
二、实验原理信源编码是一种将信源信息进行压缩的过程,其目的是减小数据传输和存储过程中的数据量,提高传输效率。
信源编码主要有两种方法:霍夫曼编码和算术编码。
1. 霍夫曼编码:根据信源中各个符号出现的概率,构建一棵霍夫曼树,将出现概率高的符号赋予较短的码字,出现概率低的符号赋予较长的码字。
霍夫曼编码具有无失真编码的特点,编码效率较高。
2. 算术编码:将信源中的符号按照一定的概率进行编码,码字长度不固定。
算术编码具有无失真编码的特点,编码效率较高,但实现较为复杂。
三、实验环境1. 硬件环境:FPGA开发板、信号发生器、示波器、数字存储示波器等;2. 软件环境:Quartus II、MATLAB、Simulink等。
四、实验内容1. 霍夫曼编码硬件实现(1)设计霍夫曼编码器:根据信源概率分布构建霍夫曼树,生成码字映射表;(2)输入信源数据,通过霍夫曼编码器进行编码;(3)输出编码后的码字,并验证码字长度是否符合霍夫曼编码规则。
2. 算术编码硬件实现(1)设计算术编码器:根据信源概率分布,生成码字映射表;(2)输入信源数据,通过算术编码器进行编码;(3)输出编码后的码字,并验证码字长度是否符合算术编码规则。
1. 根据信源概率分布,设计霍夫曼编码器和算术编码器;2. 在FPGA开发板上进行硬件编程,实现信源编码算法;3. 使用信号发生器产生信源数据,通过示波器观察编码后的码字;4. 使用数字存储示波器记录编码后的码字,分析编码效率;5. 对比霍夫曼编码和算术编码的编码效率,分析两种编码方法的优缺点。
六、实验结果与分析1. 霍夫曼编码:通过实验,验证了霍夫曼编码器能够根据信源概率分布生成码字映射表,编码后的码字长度符合霍夫曼编码规则。
二元霍夫曼编码 - 信息论与编码实验报告

计算机与信息工程学院综合性实验报告一、实验目的根据霍夫曼编码的原理,用MATLAB设计进行霍夫曼编码的程序,并得出正确的结果。
二、实验仪器或设备1、一台计算机。
2、MATLAB r2013a。
三、二元霍夫曼编码原理1、将信源消息符号按其出现的概率大小依次排列,p1>p2>…>p q2、取两个概率最小的字母分别配以0和1两个码元,并将这两个概率相加作为一个新字母的概率,从而得到只包含q-1个符号的新信源S1。
3、对重排后的缩减信源S1重新以递减次序排序,两个概率最小符号重复步骤(2)的过程。
4、不断继续上述过程,直到最后两个符号配以0和1为止。
5、从最后一级开始,向前返回得到各个信源符号所对应的码元序列,即相应的码字。
四、霍夫曼编码实现程序function [outnum]=lml_huffman(a)%主程序,输入一组概率,输出此组概率的霍夫曼编码%a:一组概率值,如a=[0.2 0.3 0.1 0.4]等%outnum:输出的霍夫曼码,以cell中的字符数组表示if sum(a)~=1warning('输入概率之和不为“1”,但程序仍将继续运行')end[cho,sequ,i,l]=probality(a);global lmlcode %用于输出霍夫曼码,定义为cell型global cellnum %用于编码的累加计算cellnum=1;lmlcode=cell(l,1);j=1; %第一部分add_num=char;[l_add]=addnum(add_num,i,j,l);[output,m]=disgress(sequ,i,j,l,l_add);dealnum(output,m); %在全局变量中输出霍夫曼码j=2; %第二部分[l_add]=addnum(add_num,i,j,l);[output,n]=disgress(sequ,i,j,l,l_add);dealnum(output,n);[outnum]=comset(lmlcode,cho(1,:));%将概率和编码进行关联function [output]=addnum(input,i,j,l)%对概率矩阵中每一行最后两个不为0的数进行编码,即在某个编码后添加0,1或空%输出:% input:输入的某个未完成的编码% (i,j):当前检索目标在sequ矩阵中的位置% l:sequ矩阵的列数%PS: sequ矩阵在此函数中未用到%PS:此函数为编码第一步if j==(l-i)output=[input '0'];else if j==(l-i+1)output=[input '1'];elseoutput=input;endendfunction [ecode]=comset(code,pro)%将概率和编码进行关联%code:已编成的霍夫曼码%pro:输入的一组概率%ecode:最终完成的码l=length(code);ecode=cell(l,2);for i=1:llang(i)=length(code{i});end[a,b]=sort(lang);for i=1:lecode{i,1}=code{b(i)};ecode{i,2}=pro(i);endfunction [final,a]=dealnum(imput,m)%整理并在全局变量中输出已完成的霍夫曼码%输入: imput:程序运算后的生成cell型矩阵% m:标识数%输出: final:整理后的霍夫曼码% a:标识数global lmlcodeglobal cellnumif m==1lmlcode{cellnum}=imput;cellnum=cellnum+1;final='';a='';else if m==2[final1,a1]=dealnum(imput{1,1},imput{1,2});[final2,a2]=dealnum(imput{2,1},imput{2,2});[final3,a3]=dealnum(final1,a1);[final4,a4]=dealnum(final2,a2);final=[final3 final4];a=[a3 a4];elsefinal=imput;a=m;endendfunction [outnum,p]=findsumother(sequ,i,j,l,add_num)%当前检索目标在sequ(i,j)处为非1时的处理程序,即跳转到下一级进行整理%输入: sequ:概率转移矩阵% (i,j):当前检索目标在sequ矩阵中的位置% l:sequ矩阵的列数% add_num:当前进行的编码%输出:(与disgress类同)% outnum:进行霍夫曼编码,用cell型表示% p:标识数j=l-i+2-sequ(i,j);i=i-1;[add_num1]=addnum(add_num,i,j,l);[outnum,p]=disgress(sequ,i,j,l,add_num1);function [outnum1,outnum2,p,q]=findsumis1(sequ,i,j,l,add_num)%当前检索目标在sequ(i,j)处为1时的处理程序,%即对下一级的最小两概率进行求和移位编码整理%输入: sequ:概率转移% (i,j):当前检索目标在sequ矩阵中的位置% l:sequ矩阵的列数% add_num:当前进行的编码%输出:(与disgress类同)% outnum1&[outnum2:进行霍夫曼编码,用cell型表示% p&q:标识数i=i-1;j1=l-i;j2=l-i+1;[add_num1]=addnum(add_num,i,j1,l);[outnum1,p]=disgress(sequ,i,j1,l,add_num1);[add_num2]=addnum(add_num,i,j2,l);[outnum2,q]=disgress(sequ,i,j2,l,add_num2);function [output,m]=disgress(sequ,i,j,l,add_num)%当前检索目标,累加数,输出下一级霍夫曼码及其个数,此函数被调用次数最多%输入:sequ:概率转移矩阵% (i,j):当前检索目标在sequ矩阵中的位置% l:sequ矩阵的列数% add_num:当前进行的编码%输出:output:进行霍夫曼编码,用cell型表示% m:标识数%PS:此函数为编码第二步if i~=1if sequ(i,j)==1[output1,output2,p,q]=findsumis1(sequ,i,j,l,add_num);output=cell(2);output{1,1}=output1;output{1,2}=p;output{2,1}=output2;output{2,2}=q;m=2;else if sequ(i,j)~=1[output1,p]=findsumother(sequ,i,j,l,add_num);output=output1;m=p;endendelseoutput=add_num;m=1;end五、实验程序实现方法演示若在command window中输入的概率数组为p=[0.1 0.15 0.20 0.25 0.30]使用子函数[output,sequ,i,j]=probality(p)对此组概率进行预处理,处理结果如下图所示:图5.1 概率数据处理过程简图图5.2 对图1中数据的转移方式标示图图2标明了对图1中各数据的位置转移过程。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验1:霍夫曼信源编码综合设计
【实验目的】
通过本专题设计,掌握霍夫曼编码的原理和实现方法,并熟悉利用C语言进行程序设计,对典型的文本数据和图像数据进行霍夫曼编解码。
【预备知识】
1、熵的概念,霍夫曼编码原则
2、数据结构和算法设计
3、C(或C++)编程语言
【实验环境】
1、设备:计算机一台
2、软件:C程序编译器
【设计要求】
根据霍夫曼编码原则,利用C语言设计并实现霍夫曼编码和解码程序,要求能够对给出的典型文本数据和图像数据进行霍夫曼编解码,并计算相应的熵和压缩比。
【实验原理】
Huffman编码属于熵编码的方法之一,是根据信源符号出现概率的分布特性而进行的压缩编码。
Huffman编码的主要思想是:出现概率大的符号用长的码字表示;反之,出现概率小的符号用短的码字表示。
Huffman编码过程描述:
1. 初始化:
将信源符号按出现频率进行递增顺序排列,输入集合L;
2. 重复如下操作直至L中只有1个节点:
(a) 从L中取得两个具有最低频率的节点,为它们创建一个父节点;
(b) 将它们的频率和赋给父结点,并将其插入L;
3. 进行编码:
从根节点开始,左子节点赋予1,右节点赋予0,直到叶子节点。
【基本定义】
1. 熵和平均编码符号长度
熵是信息量的度量方法,它表示某一事件出现的概率越小,则该事件包含的信息就越多。
根据Shannon 理论,信源S 的熵定义为2()log (1/)i i i H s p p =∑,其中i p 是符号i S 在S 中出现的概率;2log (1/)i p 表示包含在i S 中的信息量,也就是编码i S 所需要的位数
假设符号i S 编码后长度为l i (i=1,…,n),则平均编码符号长度L 为:i i i L p l =∑ 2. 压缩比
设原始字符串的总长度为L orig 位,编码后的总长度为L coded 位,则压缩比R 为 R = (L orig - L coded )/ L orig
【例子】
有一幅40个象素组成的灰度图像,灰度共有5级,分别用符号A 、B 、C 、D 和E 表示,40个象素中出现灰度A 的象素数有15个,出现灰度B 的象素数有7个,出现灰度C 的象素数有7个等等,如表1所示。
如果用3个位表示5个等级的灰度值,也就是每个象素用3位表示,编码这幅图像总共需要120位。
根据Shannon 理论,这幅图像的熵为
H (S ) = (15/40)⨯2log (40/15)+(7/40)⨯2log (40/7)+ +(5/40)⨯2log (40/5)=2.196 平均编码符号长度L 为(15/40)*1+(7/40)*3+(7/40)*3+(6/40)*3+(5/40)*3 = 2.25
根据霍夫曼编码原则可以得到如下的霍夫曼编码表。
霍夫曼码的码长虽然是可变的,但却不需要另外附加同步代码。
例如,码串中的第1位为0,那末肯定是符号A ,因为表示其他符号的代码没有一个是以0开始的,因此下一位就表示下一个符号代码的第1位。
同样,如果出现“110”,那么它就代
表符号D。
如果事先编写出一本解释各种代码意义的“词典”,即码簿,那么就可以根据码簿一个码一个码地依次进行译码。
【实验步骤】(16学时)
根据提供的示例Huffman编译码器源程序,利用VC++6.0进行编译生成可执行文件,阅读并运行程序。
1、用Microsoft Office Vision分别画出Huffman编码和译码程序流程图,写出用
到的主要数据结构并加以说明。
2、在Huffman编码器合适位置加入4个函数:calcProbability,calcEntropy,
calcAvgSymbolLength,calcCompressionRatio,分别计算信源各符号出现的概率、信源的熵、平均编码符号长度以及压缩比。
(自定义函数的参数)
3、分析霍夫曼编译码码的计算复杂度,定量说明Huffman编码和译码哪种操作更
耗时?
4、设计中遇到的问题,怎样解决问题的。
在设计过程中的心得体会。
思考题:
1、霍夫曼编码是否具有唯一性?
2、个人对霍夫曼编码方式的不足之处的思考以及怎么样在进行压缩时避免这些
问题。
3、分析霍夫曼编码对文本数据以及图象数据的编码效率,观察与对应信源概率分
布的关系。
4、参考静止图像压缩编码国际标准JPEG,为了提高对图像编码的效率,通常要
在霍夫曼编码之前进行什么操作?
5、。
【实验结果】
一.译码与编码流程图如下所示:
1.译码流程图
2.编码流程图
二.四个部分的程序
1.计算每个个符号出现的概率
void calcProbability(int total, SymbolFrequencies *pSF) {
int i;
float prob[MAX_SYMBOLS];
memset(prob, 0, sizeof(prob));
for(i = 0; i < MAX_SYMBOLS; ++i)
{
if((*pSF)[i])
{
prob[i] = (float)(*pSF)[i]->count / total;
printf("%c, %f\n", (*pSF)[i]->symbol, prob[i]);
}
}
}
2.计算熵
void calcEntrop(SymbolFrequencies *pSF)
{
int i;
float prob[MAX_SYMBOLS];
double entropy;
double difference;
double difference1;
double difference2;
entropy = 0;
for(i = 0; i < MAX_SYMBOLS; ++i)
{
difference1 = log(prob[i]);
difference2 = log(2);
difference = difference1/difference2;
entropy = entropy - prob[i]*difference;
}
printf(" %f\n", entropy);
}
3.计算平均长度
void calcAvgSymbolLength(SymbolFrequencies *pSF, *bits[MAX_SYMBOLS]) {
int i;
double AvgSymbolLength;
AvgSymbolLength = 0;
for(i = 0; i < MAX_SYMBOLS; ++i)
{
AvgSymbolLength = AvgSymbolLength + prob[i]*numbytes[i];
}
printf(" %f\n", AvgSymbolLength);
}
4.计算压缩比
void calcCompressionRatio(int total, AvgSymbolLength)
{
doubule Ratio;
doubule CompressionRatio;
Ratio = total – AvgSymbolLength* MAX_SYMBOLS;
CompressionRatio = Ratio/total;
}
三.分析耗时
从Huffman编码和译码的代码相比较,可以看出译码的操作更加耗时。
四.遇到的问题
在这次实验中,由于以前并没有学过C++,所以在编程期间遇到很多基础性的问题,对于语言的运用不熟悉,所以导致在写出代码之后编译很久都不成功,但是在老师的辅导下,还是可以做出来一些成果,对于C++的运用有了一定的了解和运用。
虽然在这次实验中,并没有将老师所布置的任务全部完成,但是在经过了将近三个星期的反复调试,将最基础最简单的任务完成了。
其中或许有些错误,但是已经是尽了全力去完成的。
五.思考题
1.霍夫曼编码是否具有唯一性?
答:霍夫曼信源不具有唯一性,可将1与0交换。
2.参考静止图像压缩编码国际标准JPEG,为了提高对图像编码的效率,通常要在霍夫曼编码之前进行什么操作?
答:参考静止图像压缩编码国际标准JPEG,为了提高对图像编码的效率,通常要在霍夫曼编码之前进行数据压缩。
3.通过本综合设计,谈谈对“算法+数据结构=程序”的认识
答:程序是计算机指令的某种组合,控制计算机的工作流程,完成一定的逻辑功能,以实现某种任务;算法是程序的逻辑抽象,是解决某类客观问题的数学过程;在这里,数据结构具有两个层面上的涵义--逻辑结构和物理结构:客观事物自身所具有的结构特点,我们将其称之为逻辑结构。
算法的确定依赖于数据结构的选择,数据结构的选择制约于算法设计的复杂程度--算法+ 数据结构= 程序。