KK的技术人生

技术改变世界
唯一可译码与即时码的判决

专业课上要求做的一个小程序,练练STL编程挺好的
该程序比上次增加了另外一个回溯算法,可以在当遇到非唯一可译码码字序列时
返回有歧义的序列,即一个序列可以有多种译法.

#include <iostream>
#include 
<vector>
#include 
<string>
#include 
<cassert>
using namespace std;

#define ISSAME        0    
#define ISPREFIX    1
#define NOTPREFIX    2

#define ISUDC        0    //唯一可译码
#define ISRTC        1    //即时码
#define NOTUDC        2    //非唯一可译码

typedef vector
<char*> pCharVector;
/**************************************************************************/
/* 判断chPrefix是否为chWord的前缀.*/
/**************************************************************************/
int IsPrefix(const char* chPrefix,const char* chWord);
/**************************************************************************/
/* 往后缀码集合中插入不重复的键,*/
/*************************************************************************/
bool PushBackUniqueValue(pCharVector& pCode,char* pValue);
/**************************************************************************/
/* 判断码字序列的类型,非回溯法*/
/**************************************************************************/
int IsUDC(const pCharVector& pCode);
/**************************************************************************/
/* 回溯计算,如果不是唯一可译码则可以得到一串有歧义的码字序列(即有多种译法的
/* 序列),该序列用参数中的pInvalidSeqBuf返回,调用者需记得释放内存
/* 该方法的缺点是没有检测码字序列中是否有重复码字
*/
/**************************************************************************/
int IsUDC_Backtrace(const pCharVector& pCode,char** pInvalidSeqBuf);
//#define TEST_BY_FILE
int main()
{
    #ifdef TEST_BY_FILE
        freopen(
"in","r",stdin);
    
#endif

    pCharVector VCode;
    
int nCodeNum;
    
int i;
    
char chContinue;
    
do 
    {    
        cout
<<"请输入信源编码个数:";
        cin
>>nCodeNum;
        cout
<<"请输入依次"<<nCodeNum<<"组码字(以回车表示码字的结束): ";
        
for (i = 0; i < nCodeNum; i++)
        {
            
//将输入读取到缓冲区
            string strBuffer;        
            cin
>>strBuffer;
            
//copy字符到动态数组中已进行比较
            char* pTemp = new char[strBuffer.size() + 1];
            memcpy(pTemp,strBuffer.c_str(),
sizeof(char* (strBuffer.size() + 1));
            VCode.push_back(pTemp);        
        }
        
char * pRetn = NULL;
        
int nRetn = IsUDC_Backtrace(VCode,&pRetn);
        
if (NOTUDC != nRetn)
        {
            cout
<<"该码字序列/集合是唯一可译码码组! ";
        }
        
else
        {            
            cout
<<"该码字序列/集合不是唯一可译码码组! ";
            cout
<<"有歧义序列为:"<<pRetn;
        }
        
if (ISRTC == nRetn)
        {
            cout
<<"该码字序列/集合是即时码! ";
        }
        
else
        {
            cout
<<"该码字序列/集合不是即时码! ";
        }
        
//清除内存
        delete[] pRetn;
        
for (i = 0; i < VCode.size(); i++)
        {
            delete[] VCode.at(i);
        }
        VCode.clear();
        
        cout
<<"继续吗?(Y/N):";    
        cin
>>chContinue;
    } 
while(toupper(chContinue) == 'Y');

    #ifdef TEST_BY_FILE
        fclose(stdin);
    
#endif
        
    
return 0;
}
int IsPrefix(const char* chPrefix,const char* chWord)
{
    assert(chPrefix 
!= NULL && chWord != NULL);
    
int nLenPrefix,nLenWord;
    nLenPrefix 
= strlen(chPrefix);
    nLenWord 
= strlen(chWord);
    
//前缀长度大于整个词的长度,返回false
    if (nLenPrefix > nLenWord)
    {
        
return NOTPREFIX;
    }
    
int nRetn = memcmp(chPrefix,chWord,sizeof(char* strlen(chPrefix));
    
if(0 == nRetn && nLenPrefix == nLenWord) return ISSAME;
    
if(0 == nRetn) return ISPREFIX;
    
return NOTPREFIX;
}
bool PushBackUniqueValue(pCharVector& pCode,char* pValue)
{
    assert(pValue 
!= NULL);
    
for (int i = 0; i < pCode.size(); i++)
    {
        
if (0 == strcmp(pValue,pCode[i]))    //有重复,直接返回
            return false;
    }
    pCode.push_back(pValue);
    
return true;
}
int IsUDC(const pCharVector& pCode)
{
    assert(pCode.size() 
!= 0);
    
//用于存放后缀码    
    pCharVector CodePostfix;
    
//第一轮比较,码字内部比较,得到第一个后缀码集合
    char *iter1,*iter2;
    
int i,j;
    
for (i = 0; i < pCode.size(); i++)
    {
        iter1 
= pCode.at(i);
        
for (j = 0; j < pCode.size(); j++)
        {
            
//不比较自身
            if(i == j) continue;
            iter2 
= pCode.at(j);
            
int nRetn = IsPrefix(iter1,iter2);
            
if(ISSAME == nRetn) return NOTUDC;
            
if (ISPREFIX == nRetn)
            {
                
//将iter2的后缀填入CodePostfix
                PushBackUniqueValue(CodePostfix,iter2+strlen(iter1));
            }
        }
    }
    
if(CodePostfix.size() == 0return ISRTC;
    
//第二轮比较,比较后缀码集合中是否含有码字集合中的元素
    
//有则返回NOTUDC,如果后缀码集合中没有再出现新元素了表明该码字是
    
//UDC

    
//指向当前集合在整个后缀码集合中的位置,也即是
    
//前面所有后缀码的个数
    int    nPointer = CodePostfix.size();    
    
//指向当前集合的大小
    int nNewAssembleSize = nPointer;
    
do 
    {
        nPointer 
= CodePostfix.size();
        
for (i = 0; i < pCode.size(); i++)
        {
            iter1 
= pCode.at(i);
            
for (j = nPointer - nNewAssembleSize; j < nPointer; j++)
            {
                iter2 
= CodePostfix.at(j);
                
int nRetn = IsPrefix(iter1,iter2);
                
if (nRetn == ISSAME)
                {
                    cout
<<"码字"<<iter1<<"无法解析! ";
                    
//两个码字相同,返回false
                    return NOTUDC;
                }
                
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();
    
return ISUDC;
}
/************************************************************************/
/* 该函数是用来对每个pPostfix和原码字序列进行比较, 如果重复了则在pRetnBuf中
/* 返回本身.并返回1.否则如果没有得到新的后缀码的话返回0表示无重复
*/
/* Stack用来存储递归中产生的后缀码集合,这样确保每次得到的后缀码不会重复
/* 防止进去死循环
/***********************************************************************
*/
int GetBacktraceSeq(const pCharVector& pCode,char* pPostfix,pCharVector& Stack,char** pRetnBuf)
{
    
char* iter1;
    
for (int i = 0; i < pCode.size(); i++)
    {
        iter1 
= pCode.at(i);            
        
int nRetn = IsPrefix(iter1,pPostfix);
        
if (nRetn == ISSAME)
        {
            
//第一次进来的话由于是码字序列内部的比较,所以
            
//肯定会遇到自己跟自己比较然后相等的情况,对该情况不允考虑
            if(Stack.size() == 0continue;        
            
*pRetnBuf = new char[strlen(pPostfix) + 1];
            strcpy(
*pRetnBuf,pPostfix);
            
return 1;            
        }
        
if (ISPREFIX == nRetn)
        {            
            
//新得到的后缀码已经重复了,跳过对他的处理
            if(PushBackUniqueValue(Stack,iter1) == falsecontinue;
            
char* pTemp = NULL;
            
//递归处理下一个后缀码
            if(GetBacktraceSeq(pCode,pPostfix+strlen(iter1),Stack,&pTemp) == 0
            {
                
*pRetnBuf = NULL;
                Stack.pop_back();
                
continue;
            }
            Stack.pop_back();
            
//递归过程中遇到重复码字,算法应立即返回.
            
//将自身和递归得到的后面的后缀码组合成一个歧义序列返回
            char* pNewTraceSeq = new char[strlen(iter1) + strlen(pTemp) + 1];
            pNewTraceSeq[
0= 0;
            strcat(pNewTraceSeq,iter1);
            strcat(pNewTraceSeq 
+ strlen(iter1),pTemp);
            delete[] pTemp;
            
*pRetnBuf = pNewTraceSeq;    
            
return 1;
        }
        
if (ISPREFIX == IsPrefix(pPostfix,iter1))
        {    
            
if(PushBackUniqueValue(Stack,pPostfix) == falsecontinue;
            
char* pTemp = NULL;
            
if(GetBacktraceSeq(pCode,iter1+strlen(pPostfix),Stack,&pTemp) == 0
            {
                
*pRetnBuf = NULL;
                Stack.pop_back();
                
continue;
            }
            Stack.pop_back();
            
char* pNewTraceSeq = new char[strlen(pPostfix) + strlen(pTemp) + 1];
            pNewTraceSeq[
0= 0;
            strcat(pNewTraceSeq,pPostfix);
            strcat(pNewTraceSeq 
+ strlen(pPostfix),pTemp);
            delete[] pTemp;
            
*pRetnBuf = pNewTraceSeq;    
            
return 1;
        }
    }
    
return 0;
}
/*************************************************************************/
/* 用递归的方法实现唯一可译码的判决,当码字序列不是唯一可译码时,输出有歧义的
/* 码字序列
/***********************************************************************
*/
int IsUDC_Backtrace(const pCharVector& pCode, char** pInvalidSeqBuf)
{
    assert(pCode.size() 
!= 0);
    
//用于存放后缀码    
    pCharVector CodePostfix;
    
//第一轮比较,码字内部比较,得到第一个后缀码集合
    char *iter1,*iter2;
    
int i,j;
    pCharVector Stack;
    
for (i = 0; i < pCode.size(); i++)
    {
        iter1 
= pCode.at(i);
        
char* pTemp = NULL;
        
int nRetn = GetBacktraceSeq(pCode,iter1,Stack,&pTemp);
        
if(nRetn == 1
        {            
            
*pInvalidSeqBuf = pTemp;
            
return NOTUDC;
        }
    }
    
*pInvalidSeqBuf = NULL;
    
return ISUDC;
}

posted on 2009-01-31 18:29  KK2038  阅读(4705)  评论(0编辑  收藏  举报