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

    #define SUFFIX_ARRAY_PFXDBL
    #ifdef SUFFIX_ARRAY_PFXDBL
    namespace SA{
        /*
         Suffix Array, Prefix Doubling Method
         
         <SUBSCRIPT_START_FROM,SIZE>
         MAXN   : Maximum length for string
         s      : String for building suffix array <0,MAXN>
         t,t2,c : [Auxiliary] buffers <0,MAXN>
         n      : Length of string
         
         sa     : Suffix Array, Lexicographically ith suffix starts from.  <0,MAXN>
         rank   : Suffix Rank, rank of the suffix starts from i <0,MAXN>
         height : LCP of suffix starts from sa[i] and sa[i-1] <1,MAXN>
         
         build_sa(int m) : m is the size of character set("character" being 0~m-1), should set s and n previously.
         getHeight() : Calculate height and rank array accordingly.
         
         #define REP(i,t) for(int i = 0;i < t; i++)
         #define REP_R(i,t) for(int i = t-1;i >= 0; i--)
         #define REP_1(i,t) for(int i = 1;i <= t; i++)
         #define REP_1R(i,t) for(int i = t;i >= 1; i--)
         
         Time   : O(nlogn)
         Space  : 7n
         */
        const int MAXN = 10005;
        char s[MAXN];
        int sa[MAXN],t[MAXN],t2[MAXN],c[MAXN],rank[MAXN],height[MAXN],n;
        void build_sa(int m){
            int *x = t,*y = t2;
            //第一次基数排序
            REP(i, m) c[i] = 0; //重置排序数组
            REP(i, n) c[x[i]=s[i]]++; //拷贝字符串内容到x缓冲区,并在基数排序数组中统计字符数量
            REP_1(i, m-1) c[i] += c[i-1]; //基数排序数组求前缀和以算出排名
            REP_R(i, n-1) sa[--c[x[i]]] = i; //从后往前顺次查询后缀的排名写入SA(字符相同的时候,长度小的靠前,长度大的靠后)
            //此时的x数组可以看成是保存了各个位置开始的后缀对应的第一基准
            for(int k = 1;k <= n; k <<= 1){
                //第k次基数排序,单组长度2^k
                int p = 0;
                //利用SA排序第二基准,y存储的是第二基准排序之后的后缀开始位置
                for(int i = n-k;i < n; i++) y[p++] = i; //长度没达到k,这种只能看第一基准,第二基准视为0
                REP(i, n) if(sa[i] >= k) y[p++] = sa[i]-k; //从前往后扫SA,即从字典序小的后缀开始扫,如果这个后缀的开始位置>=k的话,
                                                            //这个后缀在sa中的结果实际上是i-k的第二基准
                //排序第一基准
                REP(i, m) c[i] = 0; //重置排序数组
                REP(i, n) c[x[y[i]]]++; //按第二基准顺序读取第一基准进行统计
                REP(i, m) c[i] += c[i-1];//基数排序数组求前缀和以算出排名
                REP_R(i, n-1) sa[--c[x[y[i]]]] = y[i];//按第二基准从后往前顺次查询后缀的排名写入SA
                //准备下一次排序的第一基准序列x
                //第二基准排序结果y没有用了,上一次的第一基准序列x还有用,直接互换
                swap(x, y);
                //现在y是上一次的第一基准序列
                p = 1;
                x[sa[0]] = 0;//第一基准从0开始
                //现在的sa是排好序的,从小到大查询,如果两项无法分出先后,就令成统一基准,否则基准自增
                //如果两个后缀的第一关键字和第二关键字一样,说明他们的排名一样
                REP_1(i, n-1) 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; //如果基准数已达n,说明排序完成,所有后缀已经分出先后
                m = p; //下一轮排序的基准数是p
            }
        }
        void getHeight(){
            int i,j,k = 0;
            REP(i, n) rank[sa[i]] = i;
            for(i = 0;i < n; height[rank[i++]] = k)
                for(k?k--:0,j = sa[rank[i]-1];s[i+k]==s[j+k];k++);
            return;
        }
    }
    #endif
    

      

  • 相关阅读:
    黑盒测试和白盒测试的区别
    alpha测试和beta测试的区别
    selenium退出语句区别
    QTP8.2--安装流程
    Xshell无法连接Linux虚拟机问题
    Linux-----centos6.2---安装Linux的流程
    MySql错误处理--错误代码和消息
    基于Linux系统--web环境搭建
    前端底层-作用域 this 原型笔试题练习
    前端底层-冒泡与捕获
  • 原文地址:https://www.cnblogs.com/ZhaoxiCheung/p/5965281.html
Copyright © 2011-2022 走看看