当前位置:文档之家› 信息论与编码课程设计..

信息论与编码课程设计..

吉林建筑大学电气与电子信息工程学院信息理论与编码课程设计报告设计题目:哈夫曼编码的分析与实现专业班级:电子信息工程101学生姓名:学号:指导教师:吕卅王超设计时间:2013.11.18-2013.11.29一、设计的作用、目的《信息论与编码》是一门理论与实践密切结合的课程,课程设计是其实践性教学环节之一,同时也是对课堂所学理论知识的巩固和补充。

其主要目的是加深对理论知识的理解,掌握查阅有关资料的技能,提高实践技能,培养独立分析问题、解决问题及实际应用的能力。

通过完成具体编码算法的程序设计和调试工作,提高编程能力,深刻理解信源编码、信道编译码的基本思想和目的,掌握编码的基本原理与编码过程,增强逻辑思维能力,培养和提高自学能力以及综合运用所学理论知识去分析解决实际问题的能力,逐步熟悉开展科学实践的程序和方法二、设计任务及要求通过课程设计各环节的实践,应使学生达到如下要求:1. 理解无失真信源编码的理论基础,掌握无失真信源编码的基本方法;2. 掌握哈夫曼编码/费诺编码方法的基本步骤及优缺点;3. 深刻理解信道编码的基本思想与目的,理解线性分组码的基本原理与编码过程;4. 能够使用MATLAB 或其他语言进行编程,编写的函数要有通用性。

三、设计内容一个有8个符号的信源X ,各个符号出现的概率为:编码方法:先将信源符号按其出现的概率大小依次排列,并取概率最小的字母分别配以0和1两个码元(先0后1或者先1后0,以后赋值固定),再将这两个概率相加作为一个新字母的概率,与未分配的二进制符号的字母重新排队。

并不断重复这一过程,直到最后两个符号配以0和1为止。

最后从最后一级开始,向前返回得到各个信源符号所对应的码元序列,即为对应的码字。

哈夫曼编码方式得到的码并非唯一的。

在对信源缩减时,两个概率最小的符号合并后的概率与其他信源符号的概率相同时,这两者在缩减中的排序将会导致不同码字,但不同的排序将会影响码字的长度,一般讲合并的概率放在上面,12345678,,,,,()0.40.180.10.10.070.060.050.04X x x x x x x x x P X ⎡⎤⎧⎫=⎨⎬⎢⎥⎣⎦⎩⎭这样可获得较小的码方差。

四、设计原理4.1哈夫曼编码步骤(1)将信源消息符号按照其出现的概率大小依次排列为≥Λ21≥pnpp≥(2)取两个概率最小的字母分别配以0和1两个码元,并将这两个概率相加作为一个新的概率,与未分配的二进制符号的字母重新排队。

(3)对重新排列后的两个最小符号重复步骤(2)的过程。

(4)不断重复上述过程,知道最后两个符号配以0和1为止。

(5)从最后一级开始,向前返回得到的各个信源符号所对应的码元序列,即为相应的码字。

4.2哈夫曼编码特点哈夫曼编码是用概率匹配的方法进行信源匹配方法进行信源。

它的特点是:(1)哈夫曼的编码方法保证了概率大的符号对应于短码,概率小的符号对应于长码,充分应用了短码。

(2)缩减信源的最后两个码字总是最后一位不同,从而保证了哈夫曼编码是即时码。

(3)哈夫曼编码所形成的码字不是唯一的,但编码效率是唯一的,在对最小的两个速率符号赋值时可以规定大的为“1”,小得为“0”,如果两个符号的出现概率相等时,排列时无论哪个在前都可以,所以哈夫曼所构造的码字不是唯一的,对于同一个信息源,无论上述的顺序如何排列,他的平均码长是不会改变的,所以编码效率是唯一的。

(4)只有当信息源各符号出现的概率很不平均的时候,哈夫曼编码的效果才明显。

(5)哈夫曼编码必须精确的统计出原始文件中每个符号出现频率,如果没有这些精确的统计将达不到预期效果。

哈夫曼编码通常要经过两遍操作,第一遍进行统计,第二遍产生编码,所以编码速度相对慢。

另外实现电路复杂,各种长度的编码的编译过程也是比较复杂的,因此解压缩的过程也比较慢。

(6)哈夫曼编码只能用整数来表示单个符号,而不能用小数,这很大程度上限制了压缩效果。

哈夫曼所有位都是合在一起的,如果改动其中一位就可以使其数据变得面目全非。

五、设计步骤5.1以框图形式画出哈夫曼编码过程(哈夫曼编码要求构建哈夫曼树)。

表1 哈夫曼编码哈夫曼树:给定n个实数w1,w2,......,wn(n≥2),求一个具有n个结点的二叉数,使其带权路径长度最小。

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

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

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

(1)根据与n个权值{w1,w2…wn}对应的n个结点构成具有n棵二叉树的森林F={T1,T2…Tn},其中第i棵二叉树Ti(1 ≤i ≤n)都只有一个权值为wi的根结点,其左、右子树均为空。

(2) 在森林F 中选出两棵根结点的权值最小的树作为一棵新树的左、右子树,且置新树的根结点的权值为其左、右子树上根结点权值之和。

(3)从F 中删除构成新树的那两棵,同时把新树加入F 中。

(4)重复第(2)和第(3)步,直到F 中只含有一棵为止,此树便为Huffman 树。

图1哈夫曼树5.2计算平均码长、编码效率、冗余度。

平均码长为:K =∑=81i )(Ki xi p =0.4×1+0.18×3+0.1×3+0.1×4+0.07×4+0.06×4+0.05×5+0.04×5=2.61(码元/符号)信源熵为:∑===ni xi p xi p X H 1)(log )()(-(0.4log0.4+0.18log0.18+0.1log0.1+0.1log0.1+0.07+log0.07+0.06log0.06+0.05log0.05+0.04log0.04) =2.55bit/符号信息传输速率为:R=KX H )(=61.255.2=0.977bit/码元 编码效率为: η=KX H )(=61.255.2=0.977 冗余度为:γ=1-η=1-0.977=0.023六、哈夫曼编码的实现6.1软件介绍Visual C++ 6.0,简称VC 或者VC6.0,是微软推出的一款C++编译器,将“高级语言”翻译为“机器语言(低级语言)”的程序。

Visual C++是一个功能强大的可视化软件开发工具。

自1993年Microsoft 公司推出Visual C++1.0后,随着其新版本的不断问世,Visual C++已成为专业程序员进行软件开发的首选工具。

Visual C++6.0由Microsoft 开发, 它不仅是一个C++ 编译器,而且是一个基于Windows 操作系统的可视化集成开发环境(integrated development environment ,IDE )。

Visual C++6.0由许多组件组成,包括编辑器、调试器以及程序向导AppWizard 、类向导Class Wizard 等开发工具。

这些组件通过一个名为Developer Studio 的组件集成为和谐的开发环境。

Microsoft 的主力软件产品。

Visual C++是一个功能强大的可视化软件开发工具。

Visual C++6.0以拥有“语法高亮”,自动编译功能以及高级除错功能而著称。

比如,它允许用户进行远程调试,单步执行等。

还有允许用户在调试期间重新编译被修改的代码,而不必重新启动正在调试的程序。

其编译及创建预编译头文件(stdafx.h)、最小重建功能及累加连结(link)著称。

这些特征明显缩短程序编辑、编译及连结的时间花费,在大型软件计划上尤其显著。

(1)Developer Studio 这是一个集成开发环境,我们日常工作的99%都是在它上面完成的,再加上它的标题赫然写着“Microsoft Visual C++”,所以很多人理所当然的认为,那就是Visual C++了。

其实不然,虽然Developer Studio 提供了一个很好的编辑器和很多Wizard ,但实际上它没有任何编译和链接程序的功能,真正完成这些工作的幕后英雄后面会介绍。

我们也知道,Developer Studio并不是专门用于VC的,它也同样用于VB,VJ,VID等Visual Studio家族的其他同胞兄弟。

所以不要把Developer Studio当成Visual C++,它充其量只是Visual C++的一个壳子而已。

这一点请切记!(2)MFC从理论上来讲,MFC也不是专用于Visual C++,Borland C++,C++Builder 和Symantec C++同样可以处理MFC。

同时,用Visual C++编写代码也并不意味着一定要用MFC,只要愿意,用Visual C++来编写SDK程序,或者使用STL,ATL,一样没有限制。

不过,Visual C++本来就是为MFC打造的,Visual C++中的许多特征和语言扩展也是为MFC而设计的,所以用Visual C++而不用MFC 就等于抛弃了Visual C++中很大的一部分功能。

但是,Visual C++也不等于MFC。

(3)Platform SDK这才是Visual C++和整个Visual Studio的精华和灵魂,虽然我们很少能直接接触到它。

大致说来,Platform SDK是以Microsoft C/C++编译器为核心(不是Visual C++,看清楚了),配合MASM,辅以其他一些工具和文档资料。

上面说到Developer Studio没有编译程序的功能,那么这项工作是由谁来完成的呢?是CL,是NMAKE,和其他许许多多命令行程序,这些我们看不到的程序才是构成Visual Studio的基石。

6.2 编程//**哈夫曼编码**#include <iostream.h>#include <math.h>#include <string.h>#include <stdio.h>#include <stdlib.h>#include <vector>using namespace std;struct Huffman_InformationSource{char InformationSign[10];double Probability;char Code[10];int CodeLength;;};struct HuffNode{char InformationSign[10];double Probability;HuffNode *LeftSubtree,*middleSubtree,*RightSubtree,*Next;char Code[10];int CodeLength;};class CHuffman_2{public:CHuffman_2(){ISNumber=0;AvageCodeLength=0.0;InformationRate=0.0;CodeEfficiency=0.0;Redundancy=0.0;}CHuffman_2(){DestroyBTree(HuffTree);}void Huffman_Input();void Huffman_Sort();void Huffman_Tree();void Huffman_Coding();void Huffman_CodeAnalyzing();void Huffman_Display();void DestroyBTree(HuffNode *TreePointer);private:vector<Huffman_InformationSource>ISarray;int ISNumber;double AvageCodeLength;double InformationRate;double CodeEfficiency;HuffNode * HuffTree;private:void Huffman_Code(HuffNode *TreePointer);};//输入信源信息void CHuffman_2::Huffman_Input(){Huffman_InformationSource temp1={"x1",0.40,"",0};ISarray.push_back(temp1);Huffman_InformationSource temp2={"x2",0.18,"",0};ISarray.push_back(temp2);Huffman_InformationSource temp3={"x3",0.10,"",0};ISarray.push_back(temp3);Huffman_InformationSource temp4={"x4",0.10,"",0};ISarray.push_back(temp4);Huffman_InformationSource temp5={"x5",0.07,"",0};ISarray.push_back(temp5);Huffman_InformationSource temp6={"x6",0.06,"",0};ISarray.push_back(temp6);Huffman_InformationSource temp7={"x7",0.05,"",0};ISarray.push_back(temp7);Huffman_InformationSource temp8={"x8",0.04,"",0};ISarray.push_back(temp8);ISNumber=ISarray.size();}//按概率“从大到小”排序void CHuffman_2::Huffman_Sort(){Huffman_InformationSource temp;int I,j;for(i=0;i<ISNumber-1;i++)for(j=i+1;j<ISNumber;j++)if(ISarray[i].Probability<ISarray[j].Probability){temp=ISarray[i];ISarray[i]=ISarray[j];ISarray[j]=temp;}}void CHuffman_2::Huffman_Tree(){int I;HuffNode *ptr1,*ptr2,*ptr3,*ptr4,*temp1,*temp2;ptr1=new HuffNode;strcpy(ptr1->InformationSign,ISarray[0].InformationSign);ptr1->Probability=ISarray[0].Probability;strcpy(ptr1->Code,ISarray[0].Code);ptr1->LeftSubtree=NULL;ptr1->middleSubtree =NULL;ptr1->RightSubtree=NULL;ptr1->Next=NULL;HuffTree=ptr1;for(i=1;i<ISNumber;i++){ptr2=new HuffNode;strcpy(ptr2->InformationSign,ISarray[i].InformationSign);ptr2->Probability=ISarray[i].Probability;strcpy(ptr2->Code,ISarray[i].Code);ptr2->LeftSubtree=NULL;ptr2->middleSubtree =NULL;ptr2->RightSubtree=NULL;ptr2->Next=ptr1;ptr1=ptr2;}HuffTree=ptr1;int k;int s;k=ceil((double)(ISNumber-3)/(3-1));s=3+k*(3-1)-ISNumber;if(s==1){ptr2=ptr1->Next;ptr4=new HuffNode;strcpy(ptr4->InformationSign,"*");ptr4->Probability=ptr1->Probability+ptr2->Probability;strcpy(ptr4->Code,"");ptr4->LeftSubtree =NULL;ptr4->middleSubtree=ptr1;ptr4->RightSubtree=ptr2;HuffTree=ptr2->Next;temp1=HuffTree;while(temp1&&(ptr4->Probability>temp1->Probability)) {temp2=temp1;temp1=temp1->Next;}ptr4->Next=temp1;if(temp1==HuffTree)HuffTree=ptr4;elsetemp2->Next=ptr4;ptr1=HuffTree;}while(ptr1->Next){//合并概率最小的结点ptr2=ptr1->Next;ptr3=ptr2->Next;ptr4=new HuffNode;strcpy(ptr4->InformationSign,"*");ptr4->Probability=ptr1->Probability+ptr2->Probability +ptr3->Probability;strcpy(ptr4->Code,"");ptr4->LeftSubtree=ptr1;ptr4->middleSubtree=ptr2;ptr4->RightSubtree=ptr3;HuffTree=ptr3->Next;temp1=HuffTree;while(temp1&&(ptr4->Probability>temp1->Probability)){temp2=temp1;temp1=temp1->Next;}ptr4->Next=temp1;if(temp1==HuffTree)HuffTree=ptr4;elsetemp2->Next=ptr4;ptr1=HuffTree;}//释放:ptr1=NULL;ptr2=NULL;ptr3=NULL;ptr4=NULL;temp1=NULL;temp2=NULL;strcpy(HuffTree->Code,"");HuffTree->CodeLength=0;}//生成哈夫曼码void CHuffman_2::Huffman_Code(HuffNode *TreePointer){if (TreePointer == NULL)return;char tempstr[10]="";if(!TreePointer->LeftSubtree&&!TreePointer->middleSubtree&&!TreePointer->RightSubtree){for(int i=0;i<ISNumber;i++)if(strcmp(ISarray[i].InformationSign,TreePointer->InformationSign)==0) {strcpy(ISarray[i].Code,TreePointer->Code);ISarray[i].CodeLength=TreePointer->CodeLength;return;}return;}if(TreePointer->LeftSubtree){strcpy(tempstr,TreePointer->Code);strcat(tempstr,"2");strcpy(TreePointer->LeftSubtree->Code,tempstr);TreePointer->LeftSubtree->CodeLength=TreePointer->CodeLength+1;Huffman_Code(TreePointer->LeftSubtree);}if(TreePointer->middleSubtree){strcpy(tempstr,TreePointer->Code);strcat(tempstr,"1");strcpy(TreePointer->middleSubtree->Code,tempstr);TreePointer->middleSubtree->CodeLength=TreePointer->CodeLength+1;Huffman_Code(TreePointer->middleSubtree);}if(TreePointer->RightSubtree){strcpy(tempstr,TreePointer->Code);strcat(tempstr,"0");strcpy(TreePointer->RightSubtree->Code,tempstr);TreePointer->RightSubtree->CodeLength=TreePointer->CodeLength+1;Huffman_Code(TreePointer->RightSubtree);}}void CHuffman_2::Huffman_Coding(){Huffman_Code(HuffTree);}//编码结果void CHuffman_2::Huffman_CodeAnalyzing(){for(int i=0;i<ISNumber;i++)AvageCodeLength+=ISarray[i].Probability*ISarray[i].CodeLength;int L=1;int m=2; /InformationRate=AvageCodeLength/L*(log(m)/log(2));double Hx=0;for(int j=0;j<ISNumber;j++)Hx+=-ISarray[j].Probability*log(ISarray[j].Probability)/log(2);CodeEfficiency=Hx/InformationRate;Redundancy=1- CodeEfficiency;}void CHuffman_2::Huffman_Display(){cout<<"码字:"<<endl;for(int i=0;i<ISNumber;i++){cout<<"\'"<<ISarray[i].InformationSign<<"\'"<<": "<<ISarray[i].Code<<endl;}cout<<endl;cout<<"平均码长:"<<AvageCodeLength<<endl<<endl;cout<<"编码效率:"<<CodeEfficiency<<endl<<endl;cout<<"冗余度:"<< Redundancy <<endl<<endl;}void CHuffman_2::DestroyBTree(HuffNode *TreePointer) {if (TreePointer!= NULL){DestroyBTree(TreePointer->LeftSubtree);DestroyBTree(TreePointer->middleSubtree);DestroyBTree(TreePointer->RightSubtree);delete TreePointer;TreePointer = NULL;}}void main(){CHuffman_3 YYY;YYY.Huffman_Input();YYY.Huffman_Sort();YYY.Huffman_Tree();YYY.Huffman_Coding();YYY.Huffman_CodeAnalyzing();YYY.Huffman_Display();}6.3 运行结果及分析图2 运行结果运行结果分析:从运行结果上可以看出,该结果与理论计算一致,并且可以看出哈夫曼编码的特点:(1)哈夫曼的编码方法保证了概率大的符号对应于短码,概率小的符号对应于长码,充分应用了短码。

相关主题