查询后缀词

头文件

#include <iostream>
#include <map>
#include <vector>
using namespace std;
struct TrieNode
{
    bool bWord;
    map<wchar_t,TrieNode*> mapChild;
    TrieNode()
    {
        bWord = false;
    }
};

struct FeatureNode
{
    int iStart;                 //起始位置
    int iEnd;                   //结束位置
    wstring wstrFeature;        //特征词
    FeatureNode* pPre;          //前驱
    FeatureNode* pNext;         //后驱
    TrieNode* pNode;            //记录当前遍历到的字典节点
    bool bWord;

    FeatureNode()
    {
        iStart = iEnd = 0;
        wstrFeature = L"";
        pPre = NULL;
        pNext = NULL;
        pNode = NULL;
        bWord = false;
    }

    FeatureNode* Clone()
    {
        FeatureNode* pNew = new FeatureNode();
        pNew->iEnd = this->iEnd;
        pNew->iStart = this->iStart;
        pNew->wstrFeature = this->wstrFeature;
        return pNew;
    }
    
    
};
class TrieTree
{
private:
    TrieNode *pRoot;
    FeatureNode *pFeatureHead;
    FeatureNode *pfResult;
    wstring wstrData;
    bool bAnalyse;
    vector<FeatureNode*> vecFeature;
private:   
    void InsertWord(TrieNode* pNode,const wstring& wstrWord,int &index);
    bool AnalyseFeatureEx(const wstring& wstrData);
    bool IsEmptyTree();
    void Init();
    void AnalyseChar(int index);
    TrieNode* AnalyseCharByNode(TrieNode* pNode,const wchar_t& wch);
    void InsertFeatureAtLast(FeatureNode* pNewFeature);
    void DeletePreNode(FeatureNode* pCurr,FeatureNode* pSave);
    void DeleteLink(FeatureNode* pCurr);
public:
    TrieTree();
    //存入后缀词
    void InsertWords(const vector<wstring>& wstrWords);
    //解析名称
    bool AnalyseFeature(const wstring& wstrData);

    FeatureNode* GetFeature();
};


cpp文件


#include "TrieTree.h"
TrieTree::TrieTree()
{
    pRoot = new TrieNode();
    pFeatureHead = new FeatureNode();
    pfResult = NULL;
    Init();
}
FeatureNode* TrieTree::GetFeature()
{
    return pfResult;
}
void TrieTree::Init()
{   
    wstrData = L"";
    bAnalyse = false;
    if(NULL!=pfResult)
    {
        delete pfResult;
    }
    pfResult = NULL;

    int iSize = vecFeature.size();
    for(int i=0;i<iSize;i++)
    {
        if(NULL==vecFeature[i])
        {
            delete vecFeature[i];
            vecFeature[i] = NULL;
        }   
    }
    vecFeature.clear();
}
//将vector中的每个字符串都存入字典树中
void TrieTree::InsertWords(const vector<wstring>& wstrWords)
{
    int iSize = wstrWords.size();

    for(int i=0;i<iSize;i++)
    {
        const wstring& wstrWord = wstrWords[i];
        int index = wstrWord.length()-1;
        if(!wstrWords.empty())              //判断是否为空
        {   
            InsertWord(pRoot,wstrWord,index);
        }
    }
}

void TrieTree::InsertWord(TrieNode* pNode,const wstring& wstrWord,int &index)
{
    if(NULL==pNode || index == -1)
    {
        return ;
    }

    wchar_t wch = wstrWord.at(index);
    map<wchar_t,TrieNode*>::iterator iter = pNode->mapChild.begin();
    iter = pNode->mapChild.find(wch);

    if(iter==pNode->mapChild.end())                         //如果没有该节点,那么就建一个
    {
        TrieNode* pNewNode = new TrieNode();
        if(index==0)                      //如果是最后一个字,那么就设置bWord为true
        {
            pNewNode->bWord = true;
        }

        pNode->mapChild.insert(make_pair(wch,pNewNode));
        index--;
        InsertWord(pNewNode,wstrWord,index);              //继续向下遍历        
    }
    else
    {
        index--;
        InsertWord(iter->second,wstrWord,index);          //该节点存在,向下遍历
    }
}

bool TrieTree::AnalyseFeature(const wstring& wstrData)
{
    if(wstrData.empty() || IsEmptyTree())
    {
        return false;
    }
    if(0==this->wstrData.compare(wstrData))
    {
        return bAnalyse;
    }
    Init();    
    bAnalyse =  AnalyseFeatureEx(wstrData);
    return bAnalyse;
}
bool TrieTree::AnalyseFeatureEx(const wstring& wstrData)
{
    this->wstrData = wstrData;
    int iLen = wstrData.length();

    for(int i =iLen-1;i>=0;i--)
    {
        AnalyseChar(i);
        if(NULL!=pfResult)
        {
            break;
        }
    }

    //获取链表中的第一个后缀节点
    if(NULL==pfResult)
    {
        FeatureNode* pCurr = pFeatureHead->pNext;
        while(NULL!=pCurr)
        {
            if(pCurr->bWord)
            {
                pfResult = pCurr;
                pCurr->pPre->pNext = pCurr->pNext;
                pCurr->pNext->pPre = pCurr->pPre;
                break;
            }
        }
        DeleteLink(pFeatureHead->pNext);
    }
    return true;
}
//判断树是否为空
bool TrieTree::IsEmptyTree()
{
    if(pRoot->mapChild.empty())
    {
        return true;
    }
    return false;
}

void TrieTree::AnalyseChar(int index)
{
    wchar_t wch = wstrData.at(index);
    FeatureNode* pCurr = pFeatureHead->pNext;
    while(NULL!=pCurr)
    {
        /*
        如果当前节点已经是后缀词,那么要看现在分析的字符是不是紧挨着自己
        如果紧挨着自己,就需要进行分析,这样可以获取最大的后缀词
        如果不是紧挨着自己,就不需要分析,以免发生错误 例如 大风车酒店  酒店和大酒店都是后缀词
        如果不考虑相邻关系,就将后缀词错误的分析成大酒店
        */

        if(pCurr->bWord && pCurr->iStart-index>1)
        {
            pCurr = pCurr->pNext;       
            continue;                   
        }

        TrieNode* pTmp = AnalyseCharByNode(pCurr->pNode,wch);


        if(NULL==pTmp)
        {
            //如果此时 pCurr是一个后缀,且是第一个节点,那么就说明,已经获取到结尾处的第一个后缀
            if(pCurr->bWord && pCurr == pFeatureHead->pNext)
            {
                //获取到后缀词,做清理操作
                pfResult = pCurr;
                DeleteLink(pCurr->pNext);
                pFeatureHead->pNext = NULL;
                return ;
            }

            if(!pCurr->bWord)       //当前节点不是单词,且不能继续分析,删除该节点
            {
                pCurr->pPre->pNext = pCurr->pNext;
                if(NULL!=pCurr->pNext)
                {
                    pCurr->pNext->pPre = pCurr->pPre;
                }                
                FeatureNode* pTmp = pCurr->pPre;
                delete pCurr;
                pCurr = NULL;
                pCurr = pTmp;
            }
        }
        else
        {
            if(pCurr->bWord)        //当前节点已经是后缀,这说明可能存在更长的后缀
            {
                if(pTmp->bWord)     //修改当前节点
                {
                    pCurr->iStart = index;
                    pCurr->pNode = pTmp;
                    pCurr->wstrFeature.insert(pCurr->wstrFeature.begin(),1,wch);
                }
                else
                {
                    //创建新节点,放在当前节点的后面
                    FeatureNode* pNew = pCurr->Clone();
                    pNew->pNode = pTmp;
                    pNew->wstrFeature.insert(pNew->wstrFeature.begin(),1,wch);
                    pNew->pNext = pCurr->pNext;
                    pCurr->pNext = pNew;
                    pNew->pPre = pCurr;
                    if(NULL!=pNew->pNext)
                    {
                        pNew->pNext->pPre = pNew;
                    }                   
                    pCurr = pNew;
                }
            }
            else
            {
                if(pTmp->bWord)     //找到了后缀
                {
                    //找到后缀后,向前删除可能存在的被自己包含的更短的后缀,以及那些还没有形成后缀的节点
                    pCurr->wstrFeature.insert(pCurr->wstrFeature.begin(),1,wch);
                    pCurr->bWord = true;
                    pCurr->iStart = index;
                    pCurr->pNode = pTmp;

                    DeletePreNode(pCurr->pPre,pCurr);
                }
                else                //不是后缀,但可以继续分析
                {
                    pCurr->wstrFeature.insert(pCurr->wstrFeature.begin(),1,wch);
                    pCurr->pNode = pTmp;
                }
            }
        }

        pCurr = pCurr->pNext;
    }

    TrieNode* pTmp = AnalyseCharByNode(pRoot,wch);
    if(NULL!=pTmp)      //在链表的结尾处添加新节点
    {
        FeatureNode* pNewFeature = new FeatureNode();
        pNewFeature->iEnd = index;
        pNewFeature->pNode = pTmp;
        pNewFeature->wstrFeature.insert(pNewFeature->wstrFeature.begin(),1,wch);
        InsertFeatureAtLast(pNewFeature);
    }
}

void TrieTree::DeleteLink(FeatureNode* pFeature)
{
    if(NULL==pFeature)
    {
        return ;
    }

    if(NULL==pFeature->pNext)
    {
        delete pFeature;
        pFeature = NULL;
    }
    else
    {
        DeleteLink(pFeature->pNext);
        if(NULL!=pFeature)
        {
            delete pFeature;
            pFeature = NULL;
        }
    }
}
void TrieTree::DeletePreNode(FeatureNode* pCurr,FeatureNode* pSave)
{
    if(NULL==pCurr || pCurr==pFeatureHead || NULL==pSave)
    {
        return ;
    }

    if(pSave->iEnd>=pCurr->iEnd)    //比较起始位置
    {
        pCurr->pPre->pNext = pSave;
        pSave->pPre = pCurr->pPre;
        delete pCurr;
        pCurr = NULL;

        pCurr = pSave->pPre;
        DeletePreNode(pCurr,pSave);
    }

}
void TrieTree::InsertFeatureAtLast(FeatureNode* pNewFeature)
{
    if(NULL==pNewFeature)
    {
        return;
    }

    FeatureNode* pCurr = pFeatureHead;
    while(NULL!=pCurr->pNext)
    {
        pCurr = pCurr->pNext;
    }

    pCurr->pNext = pNewFeature;
    pNewFeature->pPre = pCurr;


}
TrieNode* TrieTree::AnalyseCharByNode(TrieNode* pNode,const wchar_t& wch)
{
    if(NULL==pNode)
    {
        return NULL;
    }

    map<wchar_t,TrieNode*>::iterator iter = NULL;
    iter = pNode->mapChild.find(wch);
    if(iter==pNode->mapChild.end())
    {
        return NULL;
    }

    return iter->second;
}


mian


void testAnalyse()
{
    TrieTree test;
    vector<wstring> vecWstr;
    vecWstr.push_back(L"酒店");
    vecWstr.push_back(L"宾馆");
    vecWstr.push_back(L"酒店式宾馆");
    vecWstr.push_back(L"连锁式宾馆");
    test.InsertWords(vecWstr);
    test.AnalyseFeature(L"大地酒店式宾馆洗澡部");

    FeatureNode *pNode = test.GetFeature();
}
int main()
{
    testAnalyse();
    return 1;
}



资源下载链接为: https://pan.quark.cn/s/1bfadf00ae14 华为移动服务(Huawei Mobile Services,简称 HMS)是一个全面开放的移动服务生态系统,为企业和开发者提供了丰富的工具和 API,助力他们构建、运营和推广应用。其中,HMS Scankit 是华为推出的一款扫描服务 SDK,支持快速集成到安卓应用中,能够提供高效且稳定的二维码和条形码扫描功能,适用于商品扫码、支付验证、信息获取等多种场景。 集成 HMS Scankit SDK 主要包括以下步骤:首先,在项目的 build.gradle 文件中添加 HMS Core 库和 Scankit 依赖;其次,在 AndroidManifest.xml 文件中添加相机访问和互联网访问权限;然后,在应用程序的 onCreate 方法中调用 HmsClient 进行初始化;接着,可以选择自定义扫描界面或使用 Scankit 提供的默认扫描界面;最后,实现 ScanCallback 接口以处理扫描成功和失败的回调。 HMS Scankit 内部集成了开源的 Zxing(Zebra Crossing)库,这是一个功能强大的条码和二维码处理库,提供了解码、生成、解析等多种功能,既可以单独使用,也可以与其他扫描框架结合使用。在 HMS Scankit 中,Zxing 经过优化,以更好地适应华为设备,从而提升扫描性能。 通常,ScanKitDemoGuide 包含了集成 HMS Scankit 的示例代码,涵盖扫描界面的布局、扫描操作的启动和停止以及扫描结果的处理等内容。开发者可以参考这些代码,快速掌握在自己的应用中实现扫码功能的方法。例如,启动扫描的方法如下: 处理扫描结果的回调如下: HMS Scankit 支持所有安卓手机,但在华为设备上能够提供最佳性能和体验,因为它针对华为硬件进行了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

酷python

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值