实验2 唯一可译码判决准则.docx
《实验2 唯一可译码判决准则.docx》由会员分享,可在线阅读,更多相关《实验2 唯一可译码判决准则.docx(14页珍藏版)》请在冰豆网上搜索。
实验2唯一可译码判决准则
实验二唯一可译码判决准则
一、实验目的
(1)进一步熟悉唯一可译码判决准则;
(2)掌握C语言字符串处理程序的设计和调试技术。
二、实验要求
(1)已知:
信源符号个数q、码字集合C。
(2)输入:
任意的一个码。
码字个数和每个具体的码字在运行时从键盘输入。
(3)输出:
判决(是唯一可译码/不是唯一可译码)。
三、算法
1.考察C中所有的字码,若
是
的前缀,则将相应的后缀作为一个尾随后缀码放入集合
中;
2.考察C和
两个集合,若
是
的前缀或
是
的前缀,则将相应的后缀作为尾随后码放入集合
3.
即为码C的尾随后缀集合;
4.若
中出现了
中的元素,则算法终止,返回假(
不是唯一可译码);否则,若
中没有出现新的元素,则返回真。
四、代码
#include
#include
#include
#include
usingnamespacestd;
#defineISSAME0
#defineISPREFIX1
#defineNOTPREFIX2
#defineISUDC0//唯一可译码
#defineISRTC1//即时码
#defineNOTUDC2//非唯一可译码
typedefvectorpCharVector;
/**//*判断chPrefix是否为chWord的前缀.*/
intIsPrefix(constchar*chPrefix,constchar*chWord);
/**//*往后缀码集合中插入不重复的键,*/
boolPushBackUniqueValue(pCharVector&pCode,char*pValue);
/**//*判断码字序列的类型,非回溯法*/
intIsUDC(constpCharVector&pCode);
/**//*回溯计算,如果不是唯一可译码则可以得到一串有歧义的码字序列(即有多种译法的
/*序列),该序列用参数中的pInvalidSeqBuf返回,调用者需记得释放内存
/*该方法的缺点是没有检测码字序列中是否有重复码字*/
intIsUDC_Backtrace(constpCharVector&pCode,char**pInvalidSeqBuf);
//#defineTEST_BY_FILE
intmain()
{
#ifdefTEST_BY_FILE
freopen("in","r",stdin);//文件重定向freopen函数,文本多行读入*freopen(char*filename,char*type,FILE*stream)
#endif
pCharVectorVCode;
intnCodeNum;
inti;
charchContinue;
do
{
cout<<"请输入信源编码个数:
";
cin>>nCodeNum;
cout<<"请输入依次"<";
for(i=0;i{
//将输入读取到缓冲区
stringstrBuffer;
cin>>strBuffer;
//copy字符到动态数组中已进行比较
char*pTemp=newchar[strBuffer.size()+1];
//*memcpy(void*dest,void*src,unsignedintcount),功能:
由src所指内存区域复制count个字节到dest所指内存区域
//src和dest所指内存区域不能重叠,函数返回指向dest的指针
memcpy(pTemp,strBuffer.c_str(),sizeof(char)*(strBuffer.size()+1));//c_str()是把string转化为char*型
VCode.push_back(pTemp);//push_back()函数会在vector对象VCode后面添加元素
}
char*pRetn=NULL;
intnRetn=IsUDC_Backtrace(VCode,&pRetn);
if(NOTUDC!
=nRetn)
{
cout<<"该码字序列/集合是唯一可译码!
"<}
else
{
cout<<"该码字序列/集合不是唯一可译码!
"<cout<<"有歧义序列为:
"<}
//清除内存
delete[]pRetn;
for(i=0;i{
delete[]VCode.at(i);//AT()函数:
返回一个字符表达式或备注字段在另一个字符表达或备注字段中首次出现的位置,
//从最左边开始计数。
}
VCode.clear();//清除VCode流
cout<<"继续吗?
(Y/N):
";
cin>>chContinue;
}while(toupper(chContinue)=='Y');//toupper(将小写字母转换成大写字母)
#ifdefTEST_BY_FILE
fclose(stdin);//fclose是关闭freopen()的指针
#endif
return0;
}
intIsPrefix(constchar*chPrefix,constchar*chWord)
{
assert(chPrefix!
=NULL&&chWord!
=NULL);
intnLenPrefix,nLenWord;
nLenPrefix=strlen(chPrefix);
nLenWord=strlen(chWord);
//前缀长度大于整个词的长度,返回false
if(nLenPrefix>nLenWord)
{
returnNOTPREFIX;
}
intnRetn=memcmp(chPrefix,chWord,sizeof(char)*strlen(chPrefix));
if(0==nRetn&&nLenPrefix==nLenWord)returnISSAME;
if(0==nRetn)returnISPREFIX;
returnNOTPREFIX;
}
boolPushBackUniqueValue(pCharVector&pCode,char*pValue)
{
assert(pValue!
=NULL);
for(inti=0;i{
if(0==strcmp(pValue,pCode[i]))//有重复,直接返回
returnfalse;
}
pCode.push_back(pValue);
returntrue;
}
intIsUDC(constpCharVector&pCode)
{
assert(pCode.size()!
=0);
//用于存放后缀码
pCharVectorCodePostfix;
//第一轮比较,码字内部比较,得到第一个后缀码集合
char*iter1,*iter2;
inti,j;
for(i=0;i{
iter1=pCode.at(i);
for(j=0;j{
//不比较自身
if(i==j)continue;
iter2=pCode.at(j);
intnRetn=IsPrefix(iter1,iter2);
if(ISSAME==nRetn)returnNOTUDC;
if(ISPREFIX==nRetn)
{
//将iter2的后缀填入CodePostfix
PushBackUniqueValue(CodePostfix,iter2+strlen(iter1));
}
}
}
if(CodePostfix.size()==0)returnISRTC;
//第二轮比较,比较后缀码集合中是否含有码字集合中的元素
//有则返回NOTUDC,如果后缀码集合中没有再出现新元素了表明该码字是
//UDC
//指向当前集合在整个后缀码集合中的位置,也即是
//前面所有后缀码的个数
intnPointer=CodePostfix.size();
//指向当前集合的大小
intnNewAssembleSize=nPointer;
do
{
nPointer=CodePostfix.size();
for(i=0;i{
iter1=pCode.at(i);
for(j=nPointer-nNewAssembleSize;j{
iter2=CodePostfix.at(j);
intnRetn=IsPrefix(iter1,iter2);
if(nRetn==ISSAME)
{
cout<<"码字"<";
//两个码字相同,返回false
returnNOTUDC;
}
if(ISPREFIX==nRetn)
{
//将iter2的后缀填入CodePostfixTemp
PushBackUniqueValue(CodePostfix,iter2+strlen(iter1));
}
if(ISPREFIX==IsPrefix(iter2,iter1))
{
//将iter1的后缀填入CodePostfixTemp
PushBackUniqueValue(CodePostfix,iter1+strlen(iter2));
}
}
}
nNewAssembleSize=CodePostfix.size()-nPointer;
}while(nNewAssembleSize!
=0);
CodePostfix.clear();
returnISUDC;
}
/**//*该函数是用来对每个pPostfix和原码字序列进行比较,如果重复了则在pRetnBuf中
/*返回本身.并返回1.否则如果没有得到新的后缀码的话返回0表示无重复*/
/**//*Stack用来存储递归中产生的后缀码集合,这样确保每次得到的后缀码不会重复
/*防止进去死循环*/
intGetBacktraceSeq(constpCharVector&pCode,char*pPostfix,pCharVector&Stack,char**pRetnBuf)
{
char*iter1;
for(inti=0;i{
iter1=pCode.at(i);
intnRetn=IsPrefix(iter1,pPostfix);
if(nRetn==ISSAME)
{
//第一次进来的话由于是码字序列内部的比较,所以
//肯定会遇到自己跟自己比较然后相等的情况,对该情况不允考虑
if(Stack.size()==0)continue;
*pRetnBuf=newchar[strlen(pPostfix)+1];
strcpy(*pRetnBuf,pPostfix);
return1;
}
if(ISPREFIX==nRetn)
{
//新得到的后缀码已经重复了,跳过对他的处理
if(PushBackUniqueValue(Stack,iter1)==false)continue;
char*pTemp=NULL;
//递归处理下一个后缀码
if(GetBacktraceSeq(pCode,pPostfix+strlen(iter1),Stack,&pTemp)==0)
{
*pRetnBuf=NULL;
Stack.pop_back();
continue;
}
Stack.pop_back();
//递归过程中遇到重复码字,算法应立即返回.
//将自身和递归得到的后面的后缀码组合成一个歧义序列返回
char*pNewTraceSeq=newchar[strlen(iter1)+strlen(pTemp)+1];
pNewTraceSeq[0]=0;
strcat(pNewTraceSeq,iter1);
strcat(pNewTraceSeq+strlen(iter1),pTemp);
delete[]pTemp;
*pRetnBuf=pNewTraceSeq;
return1;
}
if(ISPREFIX==IsPrefix(pPostfix,iter1))
{
if(PushBackUniqueValue(Stack,pPostfix)==false)continue;
char*pTemp=NULL;
if(GetBacktraceSeq(pCode,iter1+strlen(pPostfix),Stack,&pTemp)==0)
{
*pRetnBuf=NULL;
Stack.pop_back();
continue;
}
Stack.pop_back();
char*pNewTraceSeq=newchar[strlen(pPostfix)+strlen(pTemp)+1];
pNewTraceSeq[0]=0;
strcat(pNewTraceSeq,pPostfix);
strcat(pNewTraceSeq+strlen(pPostfix),pTemp);
delete[]pTemp;
*pRetnBuf=pNewTraceSeq;
return1;
}
}
return0;
}
/**//*用递归的方法实现唯一可译码的判决,当码字序列不是唯一可译码时,输出有歧义的
/*码字序列*/
intIsUDC_Backtrace(constpCharVector&pCode,char**pInvalidSeqBuf)
{
assert(pCode.size()!
=0);
//用于存放后缀码
pCharVectorCodePostfix;
//第一轮比较,码字内部比较,得到第一个后缀码集合
char*iter1;
inti,j;
pCharVectorStack;
for(i=0;i{
iter1=pCode.at(i);//AT()函数:
返回一个字符表达式或备注字段在另一个字符表达或备注字段中首次出现的位置,
//从最左边开始计数。
char*pTemp=NULL;
intnRetn=GetBacktraceSeq(pCode,iter1,Stack,&pTemp);
if(nRetn==1)
{
*pInvalidSeqBuf=pTemp;
returnNOTUDC;
}
}
*pInvalidSeqBuf=NULL;
returnISUDC;
}
五、运行结果
1、为唯一可译码时:
(1)已知:
信源符号个数6、码字集合{abaaedeacdbbsdnf}
(2)输入:
任意的一个码。
码字个数和每个具体的码字在运行时从键盘输入。
(3)输出:
判决(是唯一可译码)。
2、不是唯一可译码时:
(1)已知:
信源符号个数6、码字集合{acadabbbadad}
(2)输入:
任意的一个码。
码字个数和每个具体的码字在运行时从键盘输入。
(3)输出:
判决(不是是唯一可译码)。
歧义序列为:
adad
六、实验总结
本实验使用C++编写,使用了递归方法比较出了惟一可译码和不是唯一可译码,感觉这个实验比较复杂,对于信息论与编码也是一个很好的复习,也是对C++语言的一个回顾与熟悉,便于后面的实验。