后缀树(O(N))

#include <iostream>
#include <cstring>
using namespace std;

struct Edge
{
    int l, r, len;
}edge[400000];

struct Node
{
    Node *node[28];
    Edge *edge[28];
    bool info;
    int activeLength;
    Node *suffixLink;
    Node *parent;
    int num;

}node[400000], *st;

char strTemp[200008], pattern[200008];

class SuffixTree
{
public:
    int nodeNum, edgeNum;
    Node roots;
    Node* activeNode;
    Node* addNode;
    int minDistance, lastBound;
    int n;
    char *str;
    int maping[128]; 

    SuffixTree()
    {
        nodeNum=edgeNum=minDistance=lastBound=0;
        memset(roots.node, NULL, sizeof(roots.node));

        roots.info=false;
        roots.suffixLink=&roots;
        roots.activeLength=0;
        roots.num=-1;
        roots.parent=NULL;
        activeNode=&roots;
        addNode=NULL;

        for(int i=0; i<128; i++)
            maping[i]=26;
        for(int i='a'; i<='z'; i++)
            maping[i]=i-'a';
        maping['#']=27;
    }

    void create(char *s, int l)
    {
        str=s;
        n=l;
        Node *help;   
        for(int i=0; i<n; i++)
        {
            activeNode=activeNode->suffixLink;
            int start=i + activeNode->activeLength;
            int minDistanceTemp=lastBound - activeNode->activeLength - i;
            if(minDistanceTemp<0)
                minDistanceTemp=0;

            int t=maping[str[start]];

            while(activeNode->node[t] != NULL && 
                minDistanceTemp >= activeNode->edge[t]->len)
            {
                start=start + activeNode->edge[t]->len;
                minDistanceTemp=minDistanceTemp - activeNode->edge[t]->len;
                activeNode=activeNode->node[t];
                t=maping[str[start]];
            }
            //沿边一个一个字符进行比较
            help=activeNode;
            bool flag=false;
            int minDis=minDistanceTemp;

            while(activeNode->node[t]!=NULL)
            {
                int record=maping[str[start]];
                start += minDis;
                int l=help->edge[record]->l;
                int r=help->edge[record]->r;

                for(int j=l+minDis; j<=r; j++, start++)
                {
                    minDis=0;
                    if(str[j]!=str[start])
                    {
                        memset(node[nodeNum].node, NULL, sizeof(node[nodeNum].node));

                        node[nodeNum].info=false;
                        node[nodeNum].activeLength = activeNode->activeLength + (j-l);
                        node[nodeNum].num = nodeNum;
                       
                        flag=true;
       
                        help->edge[t]->r = j-1;
                        help->edge[t]->len=j - help->edge[t]->l;

                        int tt=maping[str[j]];

                        node[nodeNum].edge[tt]=&edge[edgeNum];
                        edge[edgeNum].l=j;
                        edge[edgeNum].r=r;
                        edge[edgeNum].len=r-j+1;

                        node[nodeNum].node[tt]=help->node[t];
                        help->node[t]->parent=&node[nodeNum];

                        help->node[t]=&node[nodeNum];
                        node[nodeNum].parent = help;

                        help=&node[nodeNum];

                        ++edgeNum;
                        ++nodeNum;

                        goto ans;
                    }   
                }
                activeNode=activeNode->node[t];
                help=activeNode;
                t=maping[str[start]];
            }
            ans:;
            //增加新的信息节点
            lastBound=start;

            Node *stmp=help;
            if(addNode!=NULL)
            {
                while(stmp->activeLength != addNode->activeLength-1)
                    stmp=stmp->parent;
                addNode->suffixLink=stmp;
            }

            if(flag)
                addNode=help;
            else
                addNode=NULL;

            if(addNode!=NULL && addNode->activeLength == 1)
            {
                addNode->suffixLink=&roots;
                addNode=NULL;
               
            }

            t=maping[str[start]];
            memset(node[nodeNum].node, NULL, sizeof(node[nodeNum].node));
            help->node[t]=&node[nodeNum];
            help->edge[t]=&edge[edgeNum];
            edge[edgeNum].l=start;
            edge[edgeNum].r=n-1;
            edge[edgeNum].len=n-start;

            node[nodeNum].info=true;
            node[nodeNum].num=nodeNum;
            ++nodeNum;
            ++edgeNum;
        }
    }

    bool search(char *pattern)
    {
        int length=strlen(pattern), patLen=0;
        Node *root=&roots;
        while(true)
        {
            int temp=maping[pattern[patLen++]];
            if(root->node[temp]==NULL)
                return false;
            if(patLen==length)
                return true;
            int l=root->edge[temp]->l+1, r=root->edge[temp]->r;
            for(int i=l; i<=r; i++)
            {
                if(str[i]!=pattern[patLen++])
                    return false;
                if(patLen==length)
                    return true;
            }
            root=root->node[temp];
        }
    }


    void dfs(Node *st, int l)
    {
        if(st->info)
        {
            printf("/n");
            return;
        }
        printf("它的儿子节点如下:/n");
        l=l+4;
        for(int i=0; i<28; i++)
        {
            if(st->node[i])
            {
                for(int j=0; j<l; j++)
                    printf(" ");
                printf("%d  ", st->edge[i]->l+1);
                for(int j=st->edge[i]->l; j<=st->edge[i]->r; j++)
                    printf("%c", strTemp[j]);
                dfs(st->node[i], l+st->edge[i]->len);

            }
        }
    }

    ~SuffixTree()
    {
        nodeNum=edgeNum=minDistance=lastBound=0;
        memset(roots.node, NULL, sizeof(roots.node));
        roots.info=false;
        roots.suffixLink=&roots;
        roots.activeLength=0;
    }
}suffixTree;

int main()
{
    printf("请输入字符串(只支持小写字母):");
    scanf("%s", &strTemp);
    int l=strlen(strTemp);
    strTemp[l++]='#';
    strTemp[l]='/0';
    suffixTree.create(strTemp, l);
    st=&suffixTree.roots;
    suffixTree.dfs(st, 0);
    printf("请输入模式串(输入EOF结束):");
    while(scanf("%s", &pattern)!=EOF)
    {
        bool ret=suffixTree.search(pattern);
        if(ret)
            printf("%s 是其子串/n", pattern);
        else
            printf("%s 不是其子串/n", pattern);
        printf("请输入模式串(输入EOF结束):");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值