后缀树(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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值