后缀数组的学习(二):如何用基数排序来快速构造出SA数组

    由于后缀的数组的构造过程比较精妙,代码也经过了很多的优化,一下子不怎么容易看懂,我就把它化整为零,一点一点来做!

    首先还是倍增算法的思想:

     综合许大牛与罗大牛的论文,应该是很容易懂的!倍增其实就是排序的一种策略、这种策略要求对基数排序的思想有所理解!如果不懂基数排序,我觉得不用急着去学习后缀数组了!先把基础搭起来再往下走!

     第一句话:倍增充分利用了后缀之间的联系!

    在许大牛的论文对这一点论述得很清楚:我们需要用到前缀。我们把问题具体化,如果需要对字符串abaas的后缀进行排序:该怎么做呢?

首先在字符串的后面加一个字符$,字符串就变成了:abaas$,它的后缀分别是

1、abaas$
2、baas$
3、aas$
4、as$
5、s$
6、$

    我们看一下下面这种思路:

    1、先比较上面6个字符串的第一个字符:a b a a s $,在只比较第一个字符的前提下,(注意:只比较第一个字符,不考虑后面的),我们很容易看出:第1、3、4三个字符串相等,而第2、5、6两个字符串不相等。这样我们就可以写出sa_1和rank_1的结果了:

     sa_1={index(abaas),index(aas),index(as),index(baas),index(s),index($)};

     rank_1={2,3,2,2,4,1};

这里:index(s)表示后缀s在原字符串中的起始位置。

      rand_1[i]表示第i个后缀在所有后缀中的排名:比如rank_1[5]=0,就表示字符串abaas$的第5个后缀,即字符串 $ 在这6个后缀中排名第一,是最小的! 

    2、对于第一次比较不相等的两个字符串,实际上我们已经比较出他们的大小了,可以剔到一边去了。我们现在需要做的是考虑相等的三个字符串:abaas$ aas$ as$。

按与上面相同的方法,我们比较字符串的第二个字符:b a a s $ 0。最后的那个后缀只有一个字符,所以我们补0,这个时候,我们对比一下第一次比较时提取出的字符:a b a a s $:

a b a a s $

  b a a s $ 0
这里我故意错位,就能发现,第一次的rank,即rank_1已经保存了我们这次比较的前5个排名
  3,2,2,4,1。     

对于最后的补0,我们完全可以接到最后!这样我们第二次比较的排名就可以这样表示:

  第一关键字:2,3,2,2,4,1   
  第二关键字:3,2,2,4,1,0 

综合起来就是这样的: 23,32,22,24,41,10 ,这个不直观,我们还是让排名从1开始:

                      3  5  2  4  6  1

所以rank_2就变成了:rank_2={3,5,2,4,6,1};里面的排名没有重复的了,而所对于一个字符串来说,任意两个后缀是不可能相等的。所以我们的排序就剩下最后一步了:

根据sa与rank的互逆关系:假如sa[i]=k,那么rank[k]=i我们很容易得到:

   sa={6,3,1,4,2,5}; 字符串下标从0开始,所以sa={5,2,0,3,1,4}

所以整个字符串排序的结果就出来了(从小到大排序):   

1、$
2、aas$
3、abaas$
4、as$
5、baas$
6、s$

 

你可能感兴趣的:(后缀数组,SA和RANK数组的计算过程)