唯一可译码与即时码的判决

专业课上要求做的一个小程序,练练STL编程挺好的
该程序比上次增加了另外一个回溯算法,可以在当遇到非唯一可译码码字序列时
返回有歧义的序列,即一个序列可以有多种译法.
/************************************************************************/
/* 唯一可译码和即时码的判决
/* 完成时间    :2007-6-3
/* 作者        :杨基彬
/* E-Mail    :[email protected]
/* 欢迎交流
/***********************************************************************
*/

#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;
}

你可能感兴趣的:(C++,null,delete,iostream,string,file,vector)