黄晨-信息论与编码课程设计报告 (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<string<

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<<"输入错误,请重新运行";} }

相关文档
最新文档