黄晨-信息论与编码课程设计报告 (2)
信息论与编码课程设计报告
设计题目:判断唯一可译码和香农编码
专业班级电信12-3班
学号 311208002013
学生姓名黄晨
指导教师成凌飞
教师评分
2015 年 3 月 18 日
目录
一、设计任务与要求 (3)
二、设计思路 (3)
三、设计流程图 (4)
四、程序运行及结果 (5)
五、心得体会 (9)
参考文献 (10)
附录:源程序 (10)
一.设计任务和要求
(一)判断唯一可译码
要求:利用尾随后缀法判断任意输入的码是否为唯一可译码。
(二)香农编码
要求:任意输入消息概率,利用香农编码方法进行编码,并计算信源熵和编码效率。
二.设计思路
(一)判断唯一可译码
1.1 题目分析
设计一个程序实现判断输入码组是否为唯一可译码这一功能。
在我们学习使用了克劳夫特不等式之后,知道唯一可译码必须满足克劳夫特不等式。但是克劳夫特不等式仅仅是存在性的判定定理,即该定理不能作为判断一种码是否为唯一可译码的依据。也就是说当码字长度和码符号数满足克劳夫特不等式时,则必可以构造出唯一可译码,否则不能构造出唯一可译码。因此我们必须找到一种能够判断一种码是否为唯一可译码的方法—尾随后缀法。
1.2 算法分析
尾随后缀法算法描述:
设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 中的元素就终止,这也是在本题的要求中需要注意的问题。
(二)香农编码 2.1 香农编码原理
香农编码的目的是为了优化通信系统。香农编码属于不等长编码,通常将经常出现的消息编成短码,不常出现的消息编成长码。从而提高通信效率。
香农第一定理指出了平均码长与信源之间的关系,同时也指出了可以通过编码使平均码长达到极限值,这是一个很重要的极限定理。
香农第一定理指出,选择每个码字的长度Ki 满足下式: -log2 p(xi)≤ Ki <1-log2 p(xi) 就可以得到这种码。这种编码方法称为香农编码 。
2.2 香农编码步骤
⑴将信源符号按概率从大到小的顺序排列, p(a1)≥ p(a2)≥…≥ p(an) ⑵确定满足下列不等式的整数Ki ,
-log2 p(ai)≤ Ki <1-log2 p(ai) ⑶令p(a1)=0,用Pi 表示第i 个码字的累加概率,
⑷将Pi 用二进制表示,并取小数点后Ki 位作为符号ai 的编码
三.设计流程图
3.1 判断唯一可译码
∑-==1
1)
(i k k i a p P 开始
输入码字个数和码字
进行尾随后缀编码 判断是否为唯一码 调用main ()函数
结束
3.2 香农编码
开始
输入符号概率
将信源符号概率
求前J个的累加和
求码长Ki
十进制小数转
输出函数
结束
四.程序运行及结果
4.1 判断唯一可译码
(一)程序设计运行
由于需要判断尾随后缀,所以我们需要反复的比较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)中所提到的。 (二)程序结果 判断唯一可译码程序结果 测试数据为0 10 1100 1110 1011 1101 测试数据为:1 01 00 香农编码程序结果 测试数据:4 3 2 05 05 五.心得体会 课程设计是培养学生综合运用所学知识,发现,提出,分析和解决实际问题,锻炼实践能力的重要环节,是对学生实际工作能力的具体训练和考察过程。在这个过程中,不仅锻炼了我们缜密的思维和坚持不解的毅力,更磨练了一个队伍的团结互助的精神,只有通过大家一起努力才能将课程设计的所有环节都顺利的完成,另外程序设计中我们遇到问题并解决问题的过程,使得我们独自探索并解决问题的能力了有了一个提高,这有利于我们以后的学习。 在此次课程设计中,我们主要是做了判断唯一可译码与香农编码这两个题目,初一看题目感觉应该很简单,但真正的去做的时候才发现并不是想象的那么简单,由于信息论与编码是年前学的,而课程设计是现在才做,所以经历一个寒假,整本书的知识点都忘得差不多了,所以不得不重新复习课本,以便于自己能好的完成这次的课程设计。另外就是对以前的大一学的C语言也是一个考验,虽然在平时也用一些相关方面的知识,但是相对完成此次的编程任务显然不太容易,所以这次课程设计不仅锻炼了我们做文档,做PPT的能力,也帮助我们对相关知识的做了一个整体复习。还有就是在此过程中,也遇到了一些自己不能解决的问题,就会请教其他组员,一起共同讨论,直到解决,这是的我们充分认识到了团队协作的重要性,也体验到了在问题得到解决的时候所独有的那份喜悦。也体会到了与队友的合作更是一件快乐的事情,只有彼此都付出,彼此都努力维护才能将作品做的更加完美。 我认为,在这学期的课程设计中,在收获知识的同时,还收获了阅历,收获了成熟,在此过程中,我们通过查找大量资料,请教老师,以及不懈的努力,不仅培养了独立思考,在各种其它能力上也都有了提高。更重要的是,在课程设计上,我们学会了很多学习的方法。而这是日后最实用的,真的是受益匪浅。要面对社会的挑战,只有不断的学习、实践,再学习、再实践。 参考文献 [1] 傅祖芸.信息论—基础理论与应用(第二版).北京:电子工业出版社,2007.5 [2] 傅祖芸.信息论基础.北京:电子工业出版社,1989 [3] R W汉明.朱雪龙译.编码和信息理论.北京:科学出版社,1984 [4] 王育民,梁传甲.信息与编码理论.西安:西安电子科技大学出版社,1986 [5] 周炯槃.信息理论基础.北京:人民邮电出版社,1983 [6] 钟义信.信息科学原理.北京:北京邮电大学出版社,1996 [7] 陈运. 信息论与编码 [M]. 北京:电子工业出版社,2011. [8] 姚领田.精通MFC程序设计 [M]. 北京:人民邮电出版社,2006. [9] 杨永国,张冬明.Visual C++6.0实用教程.北京:清华大学出版社,2007.附录:源程序 (一)判断唯一可译码源程序 #include #include #include struct strings { char *string; struct strings *next; }; struct strings Fstr, *Fh, *FP; //输出当前集合 void outputstr(strings *str) { do { cout< str = str->next; }while(str); cout< } inline int MIN(int a, int b) { return a>b?b:a; } inline int MAX(int a, int b) { return a>b?a:b; } #define length_a (strlen(CP)) #define length_b (strlen(tempPtr)) //判断一个码是否在一个码集合中,在则返回0,不在返回1 int comparing(strings *st_string,char *code) { while(st_string->next) { st_string=st_string->next; if(!strcmp(st_string->string,code)) return 0; } return 1; } //判断两个码字是否一个是另一个的前缀,如果是则生成后缀码void houzhui(char *CP,char *tempPtr) { if (!strcmp(CP,tempPtr)) { cout<<"集合C和集合F中有相同码字:"< < <<"不是唯一可译码码组!"< exit(1); } if (!strncmp(CP, tempPtr, MIN(length_a,length_b))) { struct strings *cp_temp; cp_temp=new (struct strings); cp_temp->next=NULL; cp_temp->string=new char[abs(length_a-length_b)+1]; char *longstr; longstr=(length_a>length_b ? CP : tempPtr);//将长度长的码赋给longstr //取出后缀 for (int k=MIN(length_a,length_b); k cp_temp->string[k - MIN(length_a,length_b)]=longstr[k]; cp_temp->string[abs(length_a-length_b)]=NULL; //判断新生成的后缀码是否已在集合F里,不在则加入F集合 if(comparing(Fh,cp_temp->string)) { FP->next=cp_temp; FP=FP->next; } } } void main() { //功能提示和程序初始化准备 cout<<"\t\t唯一可译码的判断!\n"< struct strings Cstr,*Ch, *CP,*tempPtr; Ch=&Cstr; CP=Ch; Fh=&Fstr; FP=Fh; char c[]="C :"; Ch->string=new char[strlen(c)]; strcpy(Ch->string, c); Ch->next=NULL; char f[]="F :"; Fh->string=new char[strlen(f)]; strcpy(Fh->string, f); Fh->next=NULL; //输入待检测码的个数 int Cnum; cout<<"输入待检测码的个数:"; cin>>Cnum; cout<<"输入待检测码"< for(int i=0; i { cout< char tempstr[10]; cin>>tempstr; CP->next=new (struct strings); CP=CP->next; CP->string=new char[strlen(tempstr)] ; strcpy(CP->string, tempstr); CP->next = NULL; } outputstr(Ch); CP=Ch; while(CP->next->next) { CP=CP->next; tempPtr=CP; do { tempPtr=tempPtr->next; houzhui(CP->string,tempPtr->string); }while(tempPtr->next); } outputstr(Fh); struct strings *Fbegin,*Fend; Fend=Fh; while(1) { if(Fend == FP) { cout<<"是唯一可译码码组!"< exit(1); } Fbegin=Fend; Fend=FP; CP=Ch; while(CP->next) { CP=CP->next; tempPtr=Fbegin; for(;;) { tempPtr=tempPtr->next; houzhui(CP->string,tempPtr->string); if(tempPtr == Fend) break; } } outputstr(Fh);//输出F集合中全部元素 } } (二)香农编码源程序 #include #include #include #include class T { public: T() {} ~T(); void Create(); void Coutpxj(); void Coutk(); void Coutz(); void Print(); protected: int n; double *p; double *pxj; int *k; double *mz; }; void T::Create() { cout<<"请输入信源符号个数:"; cin>>n; p=new double[n]; cout<<"请分别输入这"< cin>>p[i]; pxj=new double[n]; k=new int[n]; mz=new double[n]; double sum=0.0; for(i=0;i sum+=p[i]; if(sum!=1.0) throw 1; else { for(i=0;i { int k=i; for(int j=i+1;j if(p[k] double m=p[i]; p[i]=p[k]; p[k]=m; } } } T::~T() { delete p; delete pxj; delete k; delete mz; } void T::Coutpxj() { pxj[0]=0; for(int i=1;i { pxj[i]=0; for(int j=0;j pxj[i]+=p[j]; } } void T::Coutk() { for(int i=0;i { double d=(-1)*(log(p[i])/log(2)); if(d-(int)d>0) k[i]=(int)d+1; else k[i]=(int)d; } } void T::Print() { cout<<"Xi"< < < < < for(int i=0;i { cout<<"X"< < mz[i]=pxj[i]; for(int j=0;j { if(2*mz[i]-1>=0) { cout<<1; mz[i]=2*mz[i]-1; } else { cout<<0; mz[i]=2*mz[i]; } } cout< } double K=0.0,H=0.0,Y; for(i=0;i { K+=(double)p[i]*k[i]; H+=(-1)*p[i]*(log10(p[i])/log10(2.0)); } Y=H/K; cout<<"平均码长:"< cout<<"信源熵:"< cout<<"编码效率:"< } void main() { T t;int e; try { t.Create(); t.Coutpxj(); t.Coutk(); t.Print(); } catch(int e) {if(e==1) cout<<"输入错误,请重新运行";} }