在前面的博文里面分析了SA数组和rank数组的实现过程,实际上也就是倍增算法的思想分析!虽然思想上面懂了,但是代码实现还是很难理解的!因为代码里面做了太多的优化。

  整个代码的实现可以分成两部分:1、对所有后缀的第一次排序!运用第一次排序的结果来推算后面的排序!

  一、对所有后缀的第一次排序:

   
   
   
   
  1. for (i = 0; i < m; i++) ws[i] = 0; 
  2. for (i = 0; i < n; i++) ws[x[i] = r[i]]++; 
  3. for (i = 1; i < m; i++) ws[i] += ws[i - 1]; 
  4. for (i = n - 1; i >= 0; i--) sa[--ws[x[i]]] = i; 

这里用到了x和ws两个辅助数组!一般而言,用一个辅助数组就很难理解了,作者竟然用了两个! 这主要是因为:我们通常用到的排序是value的排序,我们是不理会下标的。而这里是对value排序,但是输出的结果却是下标!所以,这里的排序又变得复杂了。我们不仅要考虑value,还要考虑index,我觉得这才是真正难以理解后缀数组的地方。

    这里的排序实际上是用的是,我觉得类似于Hash的方式。把字符串r数组的value映射到辅助数组ws的index。这样的话实际已经排序了,但是我们SA数组存储的是下标,这里才是难点!该怎么做呢?我们知道ws里面存储的其实是r字符串中各个字符的个数。这里我们转化一下,转化成每个字符的排名:比如 

假设:ws中是这样存储的:

index:  65 66 67 68 69
value:  1  2  1  1  2

其实就是:字符串中字符及个数分别是:

A:1 B:2 C:1 D:1 E:2

转化成排名:( for (i = 1; i < m; i++) ws[i] += ws[i - 1]; )

则ws变成:

index:  65 66 67 68 69
value:  1  3  4  5  7 

这样的话,我们存储下标的时候就可以这样:

for (i = n - 1; i >= 0; i--) sa[--ws[x[i]]] = i; 

由于下标从0开始,而且可能相同的字符不止一个,故需要--ws[x[i]]; 就用原字符串逆序的方式把排序后后缀下标存储到sa数组了!

   个人感觉计算过程真的是挺精巧的!里面包含的思想,真的值得我深入学习!大牛就是大牛!

    由于x数组已经类似于计算出排名了,所以我们不需要真正去计算了,如果需要计算的话:把里面的值减一个最小值然后加1就可以了!

    总的来说,只考虑后缀首字母的话,对后缀排序还是比较简单的!更难的在下面用倍增的思想对整个后缀排序的过程。这才是倍增算法的真正核心!上面充其量是预处理罢了!