zoukankan      html  css  js  c++  java
  • 后缀数组

    
    
    在事先不知道查询的情况下支持多模板匹配。
    代码复杂度比后缀树低,且不易写错。

      利用倍增的思想,在O(N log N)的时间内构造出来。

      这里不提供思路,只提供代码的讲解。

      讲解在代码的注释里。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 using namespace std;
     6 const int MAXN=100001;
     7 
     8 /*  s[]: 文本串
     9    sa[]: 后缀数组,表示“第i名是谁 ”
    10       t[]: 即x[], 表示第一关键字下“i是第几名 ”
    11      t2[]: 即y[], 表示第二关键字下“第i名是谁 ”,对应sa[]
    12       c[]: 桶,用来进行基数排序
    13 */
    14  
    15 char s[MAXN];  
    16 int sa[MAXN], t[MAXN], t2[MAXN], c[MAXN], n;
    17 
    18 void build_sa(int m) {        //构造后缀数组 
    19     int i, *x=t, *y=t2;         //swap函数参数需为指针 
    20     //基数排序 
    21     for (i=1; i<m; i++) c[i]=0;          //清桶 
    22     for (i=0; i<n; i++) c[x[i]=s[i]]++;  //x[]=s[]:把k=0时的第一关键字排名即字符本身赋给x,c[q]++:入桶 
    23     for (i=1; i<m; i++) c[i]+=c[i-1];    //c[i]~c[i-1]为桶中的数所占的排名,如c[1]=2,c[2]=3执行完该语句变为c[1]=2,c[2]=5表示以1开头的关键字将分配的排名为1,0;以2开头的分配的排名为4,3,2 
    24     for (i=n; i>=0; i--) sa[--c[x[i]]]=i;//x[i]"i是第几名",由于桶的下标按名次来排,所以--c[x[i]]表示分配给i的排名.因为sa表示"第i名是谁",所以sa[i的名次]=i 
    25     
    26     for (int k=1; k<=n; k<<=1) {         //倍增
    27         int p=0;
    28         //用sa[]排序第二关键字y[],即把第一关键字“抄过来” 
    29         for (i=n-k; i<n; i++) y[p++]=i;    //第二关键字的前几名一定是x中最后k位等于0的,直接赋值 
    30         for (i=0; i<n; i++) if (sa[i]>=k) y[p++]=sa[i]-k;//把其他排名平移到上一位。因为前K个平移后消失(没有“上一个关键字”所以不被需要),所以不用存;其他的顺次平移K位 
    31         //基数排序第一关键字 
    32         for (i=1; i<m; i++) c[i]=0;
    33         for (i=0; i<n; i++) c[x[y[i]]]++;
    34         for (i=1; i<m; i++) c[i]+=c[i-1];
    35         for (i=n; i>=0; i--) sa[--c[x[y[i]]]]=y[i];
    36       // 根据sa[]和y[]计算新的x[]
    37          swap(x, y);
    38         p=1; x[sa[0]]=0;
    39         for (i=1; i<n; i++)
    40             x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
    41         if (p>=n) break;
    42         m=p;
    43     }
    44     return;
    45 }

    (无注释版)

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    using namespace std;
    const int MAXN=100001;
    
    char s[MAXN];  
    int sa[MAXN], t[MAXN], t2[MAXN], c[MAXN], n;
    
    void build_sa(int m) {        
        int i, *x=t, *y=t2;         
        
        for (i=1; i<m; i++) c[i]=0;           
        for (i=0; i<n; i++) c[x[i]=s[i]]++; 
        for (i=1; i<m; i++) c[i]+=c[i-1];    
        for (i=n; i>=0; i--) sa[--c[x[i]]]=i;
        
        for (int k=1; k<=n; k<<=1) {        
            int p=0;
            for (i=n-k; i<n; i++) y[p++]=i;    
            for (i=0; i<n; i++) if (sa[i]>=k) y[p++]=sa[i]-k;
             
            for (i=1; i<m; i++) c[i]=0;
            for (i=0; i<n; i++) c[x[y[i]]]++;
            for (i=1; i<m; i++) c[i]+=c[i-1];
            for (i=n; i>=0; i--) sa[--c[x[y[i]]]]=y[i];
          
             swap(x, y);
            p=1; x[sa[0]]=0;
            for (i=1; i<n; i++)
                x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
            if (p>=n) break;
            m=p;
        }
        return;
    }
    View Code
  • 相关阅读:
    poj 3669 Meteor Shower
    poj 3009 Curling 2.0
    poj 1979 Red and Black
    区间内素数的筛选
    九度oj 题目1347:孤岛连通工程
    poj 3723 Conscription
    poj 3255 Roadblocks
    Luogu P3975 [TJOI2015]弦论
    AT2165 Median Pyramid Hard 二分答案 脑洞题
    后缀自动机多图详解(代码实现)
  • 原文地址:https://www.cnblogs.com/zjzj/p/6991027.html
Copyright © 2011-2022 走看看