搜索引擎中长串匹配及聚类算法:后缀树算法

来源:互联网 发布:android启动优化 编辑:程序博客网 时间:2024/05/21 02:50

 上个月写了一个后缀树算法,但是生成树的效率极低,这次重新改写,效率接近线性了,c++实现的,下面面是核心算法:

    Node *pTmpNode;    Edge *pEdge, *pTmpEdge;    unsigned int i,edgeNum;    unsigned int matchedPos=0;//匹配到的位置        bool bMatched=false;    m_pOldNode=NULL;    #ifdef Debug        #ifdef add_node             printf("<<<<<<<<<<<<<< '%s' >>>>>>>>>>>>>>>>\n",subData(start,1).c_str());        #endif    #endif    //搜索节点是否包含待加入字符    while(!bMatched)    {                    //活动节点:隐含节点为激活节点,或者本身为激活节点        //注意活动节点是非叶节点        //1.匹配整个后缀,即结束节点        //如果是隐含节点        if(m_activeNode.m_bImplicit)        {            matchedPos=m_activeNode.getImplicitPosition();            if(isDataEqual(start,matchedPos))            {                bMatched=true;//退出,因为更短的后缀也肯定是匹配的            }        }        //显示节点        else        {                        edgeNum=m_activeNode.m_pNode->getChildNum();            for(i=0;i<edgeNum;i++)            {                matchedPos=m_activeNode.m_pNode->getChildEdge(i)->getStartPos();                if(isDataEqual(start,matchedPos))                {                    bMatched=true;                    break;                }                        }        }                if(bMatched)        {            //更新激活节点            m_activeNode.increaseImplicitNodeOffset(i);//可能显隐互变?        }        //最后字符不匹配        else        {            //2.隐式节点,拆分节点,并添加叶节点            if(m_activeNode.m_bImplicit)            {                //拆分:                                pEdge=m_activeNode.getEdge();//上面边                //添加1个节点                pTmpNode=new Node(pEdge);//中间节点                //拆分为2条边                pTmpEdge=new Edge(matchedPos,pEdge->getVirtualEndPos(),pTmpNode,this);//下面边                pEdge->updateEndPosition(matchedPos);//若是叶子节点时,从此摆脱叶子节点                pTmpEdge->setNextNode(pEdge->getNextNode());                pEdge->setNextNode(pTmpNode);                                pTmpNode->addEdge(pTmpEdge);                //隐式节点变显示节点,并作为激活节点(有点牵强?)                m_activeNode.setExplicitNode(pTmpNode);                //后缀链接                if(m_pOldNode!=NULL)                    m_pOldNode->setNextSuffixPointer(m_activeNode.m_pNode);                m_pOldNode=m_activeNode.m_pNode;                #ifdef Debug                    #ifdef add_node                         printf("\nsplit:\n %d,%d,%d [%s]\n %d,%d [%s--%s] \n",pEdge->getStartPos(),pEdge->getEndPos(),pTmpEdge->getEndPos(),                                subData(pEdge->getStartPos(),pTmpEdge->getEndPos()-pEdge->getStartPos()).c_str(),start,start+1,                                subData(pEdge->getStartPos(),pEdge->getEndPos()-pEdge->getStartPos()).c_str(),subData(start,1).c_str());                    #endif                #endif                        }            //3.显示节点,仅在显示节点下新增叶子节点            //显示节点下新增叶子节点(含上面隐式变显示的节点)                pTmpEdge=new Edge(start,0,m_activeNode.m_pNode,this);//end为0时表示叶子节点             m_activeNode.m_pNode->addEdge(pTmpEdge);                        #ifdef Debug                #ifdef add_node                     int endPos=0;                    if(m_activeNode.m_bImplicit)                        endPos=m_activeNode.getEdge()->getEndPos();                    else if(m_activeNode.m_pNode!=m_pRoot)                        endPos=m_activeNode.m_pNode->getFrontEdge()->getEndPos();                    printf("\nnew:\n %d-(%d,%d '%s'--'%s')\n\n",endPos,                        start,start+1,subData(endPos-1,1).c_str(),subData(pTmpEdge->getStartPos(),pTmpEdge->charSize()).c_str());                #endif            #endif            //匹配更短的后缀            //判断后缀指针是否存在            if(m_activeNode.m_pNode->hasNextSuffixPointer())            {                m_activeNode.setExplicitNode(m_activeNode.m_pNode->getNextSuffix());            }            //若不存在则手动搜索下一个更短后缀            else                {                    //4.当前后缀已经为根节点(非隐含),退出                if(m_activeNode.m_pNode==m_pRoot)//!!!                    bMatched=true;                else                {                    CharPosition pos;                    pTmpNode=m_activeNode.m_pNode;                    //要查找的更短后缀                    string str;                    /*无论如何此时m_activeNode为显示节点                    //(开始就是根节点下的)隐含节点                    if(m_activeNode.m_bImplicit)//pTmpEdge==NULL                    {                        pTmpEdge=m_activeNode.getEdge();                        str=subData(pTmpEdge->getStartPos(),m_activeNode.m_nImplicitNodeOffsetInEdge);                    }*/                    while( (pTmpEdge=pTmpNode->getFrontEdge()) != NULL )                    {                        str.insert(0,subData(pTmpEdge->getStartPos(),pTmpEdge->getEndPos()-pTmpEdge->getStartPos()));                        pTmpNode=pTmpEdge->getFrontNode();                        if(pTmpNode==m_pRoot)//找到根节点下面的边                        {                            break;                        }                    }                    str.erase(0,1);                    //不连续时会出问题!!!                    //str=this->subData(pTmpEdge->getStartPos()+1,matchedPos-(pTmpEdge->getStartPos()+1));                    if(str.length()==0)//表示没有更短的后缀了,将根节点作为激活节点                    {                        m_activeNode.setExplicitNode(m_pRoot);                    }                    else if(search(str,pTmpNode,pos))//必定能找到,查找到结果后,隐式节点返回值pTmpNode为父节点指针                    {                        m_activeNode.m_pNode=pTmpNode;                        m_activeNode.m_nImplicitNodeEdge=pos.edgeIndex;                        m_activeNode.m_bImplicit=(pos.charIndex!=0);                        m_activeNode.m_nImplicitNodeOffsetInEdge=pos.charIndex;                                        }                    else                    {                        printf("################# search error #############\n");                    }                }            }                }//end of else    }//end of while


 

原创粉丝点击