信息论与编码课程设计报1.docx
- 文档编号:23483863
- 上传时间:2023-05-17
- 格式:DOCX
- 页数:23
- 大小:320.40KB
信息论与编码课程设计报1.docx
《信息论与编码课程设计报1.docx》由会员分享,可在线阅读,更多相关《信息论与编码课程设计报1.docx(23页珍藏版)》请在冰豆网上搜索。
信息论与编码课程设计报1
信息论与编码课程设计报告
姓名:
时旭东
专业:
电科10-01
学号:
311008002320
指导老师:
成凌飞
完成日期:
2013.03.20
目录
一.课程描术。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
1
二.设计原理。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
2
三.设计内容。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
3
四.总结。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
22
五.参考文献。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
。
23
一.课程设计教学目的
通过本次课程设计的练习,使学生进一步巩固信源熵、信源编码的基本原理,掌握具体的编码方法,熟悉编程软件的使用,培养学生自主设计、编程调试的开发能力,同时提高学生的实践创新能力。
二.题目一:
判断唯一可译码
一.设计要求:
利用尾随后缀法判断任意输入的码是否为唯一可译码。
二.题目分析:
设计一个程序实现判断输入码组是否为唯一可译码这一功能。
在我们学习使用了克劳夫特不等式之后,知道唯一可译码必须满足克劳夫特不等式。
但是克劳夫特不等式仅仅是存在性的判定定理,即该定理不能作为判断一种码是否为唯一可译码的依据。
也就是说当码字长度和码符号数满足克劳夫特不等式时,则必可以构造出唯一可译码,否则不能构造出唯一可译码。
因此我们必须找到一种能够判断一种码是否为唯一可译码的方法—尾随后缀法。
三.算法分析:
尾随后缀法算法描述:
设C为码字集合,按以下步骤构造此码的尾随后缀集合F:
(1)考查C中所有的码字,若Wi是Wj的前缀,则将相应的后缀作为一个尾随后缀放入集合F0中;
(2)考查C和Fi两个集合,若Wj∈C是Wi∈Fi的前缀或Wi∈Fi是Wj∈C的前缀,则将相应的后缀作为尾随后缀码放入集合Fi+1中;
(3)F=∪Fi即为码C的尾随后缀集合;
(4)若F中出现了C中的元素,则算法终止,返回假(C不是唯一可译码);否则若F中没有出现新的元素,则返回真。
在我们设计的算法中,需要注意的是我们需要的是先输出所有尾随后缀的集合,然后再判断该码是否是唯一可译码,即如F中出现了C中的元素,则C不是唯一可译码,否则若F中没有出现新的元素,则C为唯一可译码。
而不是F中出现C中的元素就终止,这也是在本题的要求中需要注意的问题。
简明流程图
开始
输入码字个数和码字
进行尾随后缀编码
判断是否为唯一码
调用main()函数
结束
四.概要设计:
由于需要判断尾随后缀,所以我们需要反复的比较C和F中的码字。
1)首先我们用一个b[40][40]的数组来存放所有的尾随后缀的集合;用Q记录所有尾随后缀的个数;
2)用数组a[40][40]来存放输入的码字,L[50]来存放码字的长度;
通过一个双重循环并调用Hz(a[i],a[j],L[i],L[j])函数来找到a[40][40]中的为随后缀,即:
for(i=0;i { for(j=0;j { if(i! =j&&L[i] Hz(a[i],a[j],L[i],L[j]); } } 3)通过判断Q是否大于0,如果不大于0,即b[40][40]中没有码字,也就是不存在尾随后缀,那么可判断a[40][40]是唯一可译码,否则进行如下操作; 4)计算b[40][40]中尾随后缀的长度,用k1表示;并调用Hz(b[i],a[j],k1,L[j])其中k1 for(i=0;i { k1=strlen(b[i]); for(j=0;j { if(k1 Hz(b[i],a[j],k1,L[j]); } } 5)寻找b[40][40]中的尾随后缀;用k2表示b[40][40]中码字的长度,并调用Hz(a[i],b[j],L[i],k2)来实现,其中k2>L[j];通过循环调用即可找到b[40][40]中的所有尾随后缀,最后再将他们分别存放在b[40][40]中;即通过 for(i=0;i { for(j=0;j { k2=strlen(b[j]); if(k2>L[i]) { Hz(a[i],b[j],L[i],k2); } } } 6)在反复调用Hz(a[i],a[j],L[i],L[j])函数中如果b[40][40]中有重复出现的,即尾随后缀相同的不用再次放入b[40][40]中。 7)在调用函数中所需要注意的问题就是一个比较的问题,也就是实现6)中所提到的。 五.测试结果 5.1、测试数据为0101100111010111101 5.2、测试数据为110111000010 五、源代码 #include #include charb[40][40]; intQ; voidHz(charc[],chard[],intL1,intL2) { inti,j,temp=0; charm[50]; for(i=0;i { if(c[i]==d[i])continue; elsebreak; } if(i==L1) { for(j=0;j m[j]=d[L1+j]; m[j]='\0'; for(i=0;i { if(strcmp(b[i],m)==0) { temp=1; break; } } if(temp! =1) { strcpy(b[Q],m); Q++; } } } voidmain() { inti,j,k,k1,k2,n; chara[40][40]; intL[50]; inttemp=1; intf=0; printf("请输入码字个数: "); scanf("%d",&n); printf("请分别输入码字: "); for(i=0;i { scanf("%s",&a[i]); L[i]=strlen(a[i]); } for(i=0;i { for(j=0;j { if(i! =j&&L[i] Hz(a[i],a[j],L[i],L[j]); } } if(Q>0) { for(i=0;i { k1=strlen(b[i]); for(j=0;j { if(k1 Hz(b[i],a[j],k1,L[j]); } for(k=0;k { for(j=0;j { k2=strlen(b[j]); if(k2>L[k]) { Hz(a[k],b[j],L[k],k2); } } } } printf("尾随后缀集合为: "); for(i=0;i printf("%s",b[i]); for(i=0;i =0;i++) { for(j=0;j { if(strcmp(a[i],b[j])==0) { temp=0; break; } elsecontinue; } } printf("\n"); if(temp==0)printf("该码不是唯一可译码! \n"); elseprintf("该码是唯一可译码! \n"); } elseprintf("该码组是唯一可译码! "); f++; printf("\n"); } 题目二: 哈夫曼编码 1课题描述 在这个信息量爆炸的时代,凡是能载荷一定信息量,且码字的平均长度最短,可分离的变长码的码字集合称为最佳变长码。 为此,必须将概率大的信息符号编以短的码字,概率小的符号编以长的码字,使得平均码字最短。 能获得最佳码的编码方法主要有: 香农(Shannon)、费诺(Fano)、哈夫曼(Huffman)编码等。 哈夫曼(Huffman)编码是一种常用的压缩编码方法,是Huffman于1952年为压缩文本文件建立的。 它的基本原理是频繁使用的数据用较短的代码代替,较少使用的数据用较长的代码代替,每个数据的代码各不相同。 哈夫曼压缩是个无损的压缩算法,一般用来压缩文本和程序文件。 哈夫曼压缩属于可变代码长度算法一族。 意思是个体符号用一个特定长度的位序列替代。 因此,在文件中出现频率高的符号,使用短的位序列,而那些很少出现的符号,则用较长的位序列。 哈夫曼编码是哈夫曼树的一个应用,是一种最优的前缀技术,然而其存在的不足却制约了它的直接应用。 首先,其解码时间为O(lavg),其中lavg为码字的平均长度;其次,更为重要的是,解码器需要知道哈夫曼编码树的结构,因而编码器必须为解码器保存或传输哈夫曼编码树。 对于小量数据的压缩而言,这是很大的开销。 因而,应用哈夫曼编码的关键是如何降低哈夫曼编码树的存储空间。 目前流行的很多压缩方法都是用了该技术,如GZIB、ZLIB、PNC等。 2设计原理 对于多进制哈夫曼编码,为了提高编码效率,就要是长码的符号数量尽量少、概率尽量小,所以信源符号数量最好满足n=(m-1)*k+r,其中m为进制数,k为缩减的次数。 设计步骤如下: [1]将信源符号按概率从大到小的顺序排列,令 p(x1)≥p(x2)≥…≥p(xn) [2]给两个概率最小的信源符号p(xn-1)和p(xn)各分配一个码位“0”和“1”,将这两个信源符号合并成一个新符号,并用这两个最小的概率之和作为新符号的概率,或者在新添加一个信源符号,令其概率为0,则个分配一个码位“0”、“1”和“2”,将其合并,结果得到一个只包含(n-1)个信源符号的新信源。 称为信源的第一次缩减信源,用S1表示。 [3]将缩减信源S1的符号仍按概率从大到小顺序排列,此后每次合并3个信源符号,得到只含(n-3)个符号的缩减信源S2。 [4]重复上述步骤,直至最后,此时所剩符号的概率之和必为1。 然后从最后一级缩减信源开始,依编码路径向前返回,就得到各信源符号所对应的码字。 3设计过程 3.1软件介绍 3.1.1VisualC++6.0简介 VisualC++6.0,简称VC或者VC6.0,是微软推出的一款C++编译器,将“高级语言”翻译为“机器语言(低级语言)”的程序。 VisualC++是一个功能强大的可视化软件开发工具。 自1993年Microsoft公司推出VisualC++1.0后,随着其新版本的不断问世,VisualC++已成为专业程序员进行软件开发的首选工具。 VisualC++6.0由Microsoft开发,它不仅是一个C++编译器,而且是一个基于Windows操作系统的可视化集成开发环境(integrateddevelopmentenvironment,IDE)。 VisualC++6.0由许多组件组成,包括编辑器、调试器以及程序向导AppWizard、类向导ClassWizard等开发工具。 这些组件通过一个名为DeveloperStudio的组件集成为和谐的开发环境。 Microsoft的主力软件产品。 VisualC++是一个功能强大的可视化软件开发工具。 VisualC++6.0以拥有“语法高亮”,自动编译功能以及高级除错功能而著称。 比如,它允许用户进行远程调试,单步执行等。 还有允许用户在调试期间重新编译被修改的代码,而不必重新启动正在调试的程序。 其编译及创建预编译头文件(stdafx.h)、最小重建功能及累加连结(link)著称。 这些特征明显缩短程序编辑、编译及连结的时间花费,在大型软件计划上尤其显著。 3.1.2主要部分 [1]DeveloperStudio 图1DeveloperStudio环境 这是一个集成开发环境,我们日常工作的99%都是在它上面完成的,再加上它的标题赫然写着“MicrosoftVisualC++”,所以很多人理所当然的认为,那就是VisualC++了。 其实不然,虽然DeveloperStudio提供了一个很好的编辑器和很多Wizard,但实际上它没有任何编译和链接程序的功能,真正完成这些工作的幕后英雄后面会介绍。 我们也知道,DeveloperStudio并不是专门用于VC的,它也同样用于VB,VJ,VID等VisualStudio家族的其他同胞兄弟。 所以不要把DeveloperStudio当成VisualC++,它充其量只是VisualC++的一个壳子而已。 这一点请切记! [2]MFC 从理论上来讲,MFC也不是专用于VisualC++,BorlandC++,C++Builder和SymantecC++同样可以处理MFC。 同时,用VisualC++编写代码也并不意味着一定要用MFC,只要愿意,用VisualC++来编写SDK程序,或者使用STL,ATL,一样没有限制。 不过,VisualC++本来就是为MFC打造的,VisualC++中的许多特征和语言扩展也是为MFC而设计的,所以用VisualC++而不用MFC就等于抛弃了VisualC++中很大的一部分功能。 但是,VisualC++也不等于MFC。 [3]PlatformSDK 这才是VisualC++和整个VisualStudio的精华和灵魂,虽然我们很少能直接接触到它。 大致说来,PlatformSDK是以MicrosoftC/C++编译器为核心(不是VisualC++,看清楚了),配合MASM,辅以其他一些工具和文档资料。 上面说到DeveloperStudio没有编译程序的功能,那么这项工作是由谁来完成的呢? 是CL,是NMAKE,和其他许许多多命令行程序,这些我们看不到的程序才是构成VisualStudio的基石。 3.2设计内容 例: 对如下单符号离散无记忆信源编三进制哈夫曼码。 这里: m=3,n=8 令k=3,m+k(m-1)=9,则s=9-n=9-8=1 所以第一次取m-s=2个符号进行编码。 由计算可得: 平均码长为: (3.1) 信息率为: (3.2) 编码效率为: (3.3) 可见: 哈夫曼的编码效率相当高,对编码器的要求也简单得多。 编码过程如下: 表1哈夫曼编码 信源 符号 概率 缩减信源 码字 码长 0.4 0.09 0 1 0 0.22 2 0 1 2 1 01.0 1 2 0 1 0.18 10 2 0.1 11 2 0.1 12 2 0.07 21 2 0.06 22 2 0.05 200 3 0.04 201 3 2 图2哈夫曼编码 4编码程序及其分析//**哈夫曼编码** #include"stdio.h" #include"iostream.h" #include"math.h" #defineMaxNo100 typedefcharElemType; typedefstruct { ElemTypedata[MaxNo]; doubleweight;/*信源概率*/ intparent,lchild,rchild;/*父亲和左右孩子节点*/ }HTNode; typedefstruct { charcd[MaxNo];/*存放编码用*/ intstart; }HCode; voidCreateHCode(HTNodeht[],HCodehcd[],intn)/*哈夫曼编码子程序*/ { inti,f,c; intchoose; HCodehc; printf("请输入0或1进行编码方式选择: ");/*方式选择*/ scanf("%d",&choose); for(i=0;i { hc.start=n;c=i; f=ht[i].parent; if(choose==0)/*若选择0,则哈夫曼编码以先标0开始*/ { while(f! =-1) { if(ht[f].lchild==c)hc.cd[hc.start--]='0'; elsehc.cd[hc.start--]='1'; c=f;f=ht[f].parent; } hc.start++; hcd[i]=hc; } else/*反之以先标1开始*/ { { while(f! =-1) { if(ht[f].lchild==c)hc.cd[hc.start--]='1'; elsehc.cd[hc.start--]='0'; c=f;f=ht[f].parent; } hc.start++; hcd[i]=hc; } } } } voidCreateHT(HTNodeht[],intn)/*构造哈夫曼树子程序*/ { inti,j,k; ints1,s2;/*节点*/ doublemin1,min2; for(i=0;i<2*n-1;i++)/*进行2*n-1次合并*/ ht[i].parent=ht[i].lchild=ht[i].rchild=-1; for(i=n;i<2*n-1;i++) { min1=min2=32767; s1=s2=-1; for(k=0;k<=i-1;k++)/*不断循环组合最终生成Huffman树*/ { if(ht[k].parent==-1) { if(ht[k].weight { min2=min1; s2=s1; min1=ht[k].weight; s1=k; } elseif(ht[k].weight { min2=ht[k].weight; s2=k; } } } ht[i].weight=ht[s1].weight+ht[s2].weight; /*组合树根节点权重为左右子之和*/ ht[i].lchild=s1; ht[i].rchild=s2;/*组合树左右子分别为s1,s2*/ ht[s1].parent=ht[s2].parent=i;/*新树加入数组*/ } } intmain() { inti,j,n; doubleaverage_length,sum=0; HTNodeht[MaxNo]; HCodehcd[MaxNo]; floatD[100];/*各概率的对数*/ floatH=0.00; floath[100];/*存放信息熵*/ floatR;/*编码效率*/ cout<<"姓名: 时旭东学号: 311008002320"< cout<<"请输入信源符号个数: "< while(scanf("%d",&n)) { cout<<"请输入各个信源符号及其概率,比如: A0.12: "< for(i=0;i { scanf("%s%lf",&ht[i].data,&ht[i].weight); sum=ht[i].weight+sum; } if(sum>1)/*避免总概率大于1*/ cout<<"概率大于1,请重新输入"< for(i=0;i { D[i]=3.322*(-log10(ht[i].weight)); h[i]=ht[i].weight*D[i];/*各信源的熵*/ H=H+h[i]; } CreateHT(ht,n);/*生成哈夫曼树*/ CreateHCode(ht,hcd,n);/*生成哈夫曼编码*/ cout<<"哈夫曼编码如下: "< for(i=0;i { printf("%s: ",ht[i].data); for(j=hcd[i].start;j<=n;j++) printf("%c",hcd[i].cd[j]); printf("\n"); } cout<<"下面将计算该码的平均码长、编码效率: "< average_length=0; for(i=0;i average_length+=ht[i].weight*(n-hcd[i].start+1); /*计算该信源的平均码长*/ cout<<"平均编码长度: K="< R=H/average_length;/*编码效率*/ cout<<"编码效率: R="< } return0; } 2.截图 图3程序运行结果 总结 在这次课程设计中,通过对程序的编写,调试和运行,使我更好的掌握了Huffman树等数据结构方面的基本知识和各类基本程序问题的解决方法,熟悉了各种调用的数据类型,在调试和运行过程中,加深我对程序运行的环境了解和熟悉的程度,同时也提高了我对程序调试分析的能力和对错误纠正的能力。 这次信息论与编码的程序设计,对于我来说是一个挑战。 我对数据结构的学习在程序的设计中也有所体现。 课程设计是培养学生综合运用所学知识,发现问题、提出问题、分析问题和解决问题的过程,锻炼学生的逻辑思维能力和实践能力,是对学生实际工作能力的具体训练和考察过程。 在整个课程程序中,我们充分应用和调用各个程序模块,从而部分实现了此次程序设计的所应该有的功能。 就是我在课程设计是比较成功的方面,而
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 信息论 编码 课程设计
![提示](https://static.bdocx.com/images/bang_tan.gif)