后缀数组 java实现

首先,欢迎大牛点评或手下留情请绕过。

对于只会java而对c和c++不熟悉的同学,初学后缀数组,基本概念肯定是看了很多遍,但到自己编码肯定又调不通

这里先献上代码,没加注释请自行理解,后面大致分析下踩坑的点。

public class SuffixArray {

    private static final int SIZE = 256;

    private static int[] sa(String s) {
        char[] ch = s.toCharArray();
        int i, p, step, m = SIZE, len = ch.length;
        int[] sa = new int[len],x = new int[len+1],y = new int[len+1],wv = new int[len],ws = new int[SIZE],t;

        for (i = 0 ; i < m ; i ++) ws[i] = 0;
        for (i = 0; i < len; i++) ws[x[i] = ch[i]]++;
        for (i = 1; i < m; i++) ws[i] += ws[i-1];
        for (i = len-1; i >= 0; i--) sa[--ws[ch[i]]] = i;

        for (step = 1,p = 0; p < len && step <= len ; step *= 2,m = p) {
            for (p = 0,i = len - step; i < len; i++) y[p++] = i;
            for (i = 0; i < len; i++)
                if (sa[i] >= step) y[p++] = sa[i] - step;

            for (i = 0; i < len; i++) wv[i] = x[y[i]];
            for (i = 0 ; i < m ; i++) ws[i] = 0;
            for (i = 0; i < len; i++) ws[wv[i]]++;
            for (i = 1; i < m; i++) ws[i] += ws[i-1];
            for (i = len - 1; i >= 0; i--) sa[--ws[wv[i]]] = y[i];

            for (t = x,x = y,y = t,i = 1,y[len] = -1,x[sa[0]] = 0,p = 1; i < len; i++)
                x[sa[i]] = (y[sa[i]] == y[sa[i-1]] && y[sa[i]+step] == y[sa[i-1]+step]) ? p-1 : p++;
        }
        return sa;
    }
    
    public static void main(String[] args) {
        String s = "aabaaaab";
        System.out.println("sa: " + Arrays.toString(sa(s)));
    }
}

基数排序不多说,简单说下几个踩坑点:

y数组是基于上次基数排序结果结果对本次排序的第二关键字进行排序,后面的基数排序是对第一关键字基数排序。

后面的x和y数组交换,就是为了省内存,重复利用,此时y就是原来的x,x可以理解为以该下标开始 step长度的所有子字符串的排名,可能存在重复值,后面的for循环相当于重新计算x排名,这里p的值可以理解为不重复的子串的个数,p如果等于len,说明后缀数组已构建完。

y数组长度开大一位,计算本次排名时令y[len] = -1,是因为上次的排名的最小值从0开始,空串的排名应该比0小,所以设置成-1。

 

总结:

《后缀数组-字符串处理的有力工具》里面每一句描述都不是废话,尤其是强调的地方,初学者可多品味品味。

 

你可能感兴趣的:(后缀数组 java实现)