码迷,mamicode.com
首页 > 编程语言 > 详细

【后缀数组】关于后缀数组模板的注解续

时间:2015-04-06 12:56:23      阅读:212      评论:0      收藏:0      [点我收藏+]

标签:

int wa[N], wb[N], ws[N], wv[N]
int rank[N], height[N]

#此处N比输入的N要多1,为人工添加的一个字符,用于避免CMP时越界
void getSA(int *r, int *sa, int n, int m) 

    int i, j, p, *x = wa, *y = wb, *t

    # bucket清空
    for(i = 0; i < m; i++) ws[i] = 0

    #进行一次基数排序
    for(i = 0; i < n; i++) ws[x[i] = r[i]]++    
    for(i = 1; i < m; i++) ws[i] += ws[i - 1]
    for(i = n - 1; i >= 0; i--) sa[--ws[x[i]]] = i

    #倍增法
    for(j = 1, p = 1; p < n; j *= 2, m = p)

        #string[n - j .. n] 是没有偏移为j的后缀 故第二关键字默认为0 
        #所以按照第二关键字排序肯定在最前面 同时还需要保证稳定性
        for(p = 0, i = n - j; i < n; i++) y[p++] = i

        #SA定义为‘排第几的是谁‘ 根据第二关键字排序时
        #第二关键字的次序就是其关联的第一关键字未完成排序时的次序
        #所以SA[i] – j为按照第二关键字次序收集的未完成排序 的第一关键字序列 
        for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i] – j

        #这里的x是临时的RANK数组 y是等待排序的第一关键字下标数组(即第i后缀)
        #映射出第一关键字之间的相对大小
        for(i = 0; i < n; i++) wv[i] = x[y[i]]

        #bucket清空
        for(i = 0; i < m; i++) ws[i] = 0

        #进行一次基数排序
        for(i = 0; i < n; i++) ws[wv[i]]++
        for(i = 1; i < m; i++) ws[i] += ws[i - 1]
        for(i = n - 1; i >= 0; i--) sa[--ws[wv[i]]] = y[i]

        #交换x y重标号临时SA
        for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i++)
            x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++

void getHeight(int *r, int *sa, int n)

    int i, j, k = 0

    #根据SA求RANK 
    for(i = 1; i <= n; i++) rank[sa[i]] = i

    #利用性质 h[i] = height[rank[i]] 减少运算时间
    #h[i] => height[rank[i]] => 表示第i后缀的height值
    #第i后缀必然比第i-1后缀短 同时注意第i后缀 = 第i-1后缀剔除首字母
    #记符号S(i)为原字符串的第i后缀 
    #记符号P(i)为第i后缀的SA值-1对应的后缀
    #h[i]   = height[rank[i]]   => 第i后缀和第i后缀的SA值-1对应的后缀的LCP
    #h[i-1] = height[rank[i-1]] => 第i-1后缀和第i-1后缀的SA值-1对应的后缀的LCP
    #h[i] = LCP(S(i), P(i)) h[i - 1] = LCP(S(i - 1), P(i - 1))
    #容易看出S(i - 1)剔除首字母后变为S(i) 
    #若h[i - 1] >= 1 则S(i - 1)和P(i - 1)的LCP >= 1
    #P(i - 1)肯定是某个后缀 同时因为h[i - 1] >= 1 故strlen(P(i - 1)) >= 1  
    #所以P(i - 1)剔除首字母必然可以得到某个后缀 
    #同时由S(i - 1)剔除首字母可以得到S(i)和P(i)
    #如果下标从1开始 
    #那么P(i - 1)和P(i)必然满足P(i - 1)[1 .. h[i - 1]] == P(i)[0 .. h[i - 1]]
    #但P(i - 1)[h[i - 1] + 1 .. -1] 和 P(i)[h[i - 1] + 1 .. -1]不一定相等
    #所以h[i] >= h[i - 1] - 1 
    #反之从0求h[i] 必然正确
    #补充 height[i] = LCP(string[sa[i - 1] .. -1], string[sa[i] .. -1])
    for(i = 0; i < n; height[rank[i++]] = k)
        for(k ? k-- : 0, j = sa[rank[i] - 1]; r[i + k] == r[j + k]; k++)

char str[N]
int sa[N]

int main
    char str[N]
    scanf("%s", str)
    int n = strlen(str)
    str[n] = 0

    #注意区分此处为n+1,因为添加了一个结尾字符用于区别比较
    getSA(str, sa, n + 1, 128)
    getHeight(str, sa, n)

【后缀数组】关于后缀数组模板的注解续

标签:

原文地址:http://blog.csdn.net/gumingdilian/article/details/44900591

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!