• 后缀数组代码详解


    说起来学了很久的后缀数组了

    思想还是很容易明白的

    最大的问题就是

    代码看不懂

    然后在不断模拟研究的过程中

    终于弄清楚了一点

    就决定写下来了

    不然又会忘的QAQ

    以下是代码

    ps:首先要弄懂基数排序

    定义:c[ ]数组 : 基数排序的桶

               x[ ]数组:类似于rank数组,保存当前排序到的以每个位置开始的一段字符串的排名

               sa[ ]数组:sa[i]保存第i个排名的字符串开头所在位置

               y[ ]数组:第二关键字排序,y[i]保存第i个排名的字符串开头所在位置

     1  void BuildSa(int m) { 
     2       int *x = t, *y = t2;       //这是对单个字符的排序
     3       for (int i = 0; i < m; i++)    c[i] = 0; // 清空c数组
     4       for (int i = 0; i < n; i++)    c[x[i] = s[i]]++; // 初始长度为1时, x[i] == s[i]
     5       for (int i = 1; i < m; i++)    c[i] += c[i - 1]; // 得到每个所在位置
     6       for (int i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i; // 排名为c[x[i]]的字符,是从i位置开始的,每记录一次排名就-1,到前一个位置,保证排名和对应位置不重复
     7       for (int k = 1; k <= n; k <<= 1) {
     8         int p = 0; // 计数用的
     9         for (int i = n - k; i < n; i++)    y[p++] = i;  // 0是最小的,先把后面需要补0的放在最前面
    10         for (int i = 0; i < n; i++)    if (sa[i] >= k)    y[p++] = sa[i] - k; // sa[i] < k时不是第二关键字, sa[i]的排名是依次递增的,所以直接读入y数组,减去前面不是第二关键字的部分
    11         for (int i = 0; i < m; i++) c[i] = 0; // 清空c数组
    12         for (int i = 0; i < n; i++)    c[x[y[i]]]++; // 此时在y中已经按第二关键字排好序,x中存的是第一关键字,再直接基数排序第一关键字即可
    13          for (int i = 1; i < m; i++)    c[i] += c[i - 1];
    14          for (int i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
    15          swap(x, y);
    16         // 离散化排名      
    17           p = 1; x[sa[0]] = 0;
    18           for (int i = 1; i < n; i++)
    19             x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++; // 两个关键字都相同则排名相同
    20          if (p >= n)    break; // p代表了不同排名数量,若数量已经达到n,则排序完毕,可直接退出
    21          m = p;
    22      }
    23  }

    这是得到sa数组的做法

    然而

    一个sa数组并没有什么用

    下面是得到height数组的算法

    具体证明可以参考

    https://wenku.baidu.com/view/ed1be61e10a6f524ccbf85fd.html

    这个论文

    写的很好啦

    就是没有注释...

    首先还是上代码

    定义:rank[ ]数组:与sa[ ]数组正好相反,rank[i] = j代表以i开始的后缀的排名

     1 void GetHeight() {
     2     int k = 0;
     3     for (int i = 0; i < n; i++)    rank[sa[i]] = i; 
     4     for (int i = 0; i < n; i++)    {
     5         if (k)    k--; // 因为h[i] >= h[i - 1] - 1(h[i]看论文的定义),所以k需要-1 
     6         int j = sa[rank[i] - 1]; //得到排名前一位后缀开始位置
     7         while (s[i + k] == s[j + k])    k++; //从后面k个开始比较,直到不相同为止
     8         height[rank[i]] = k;
     9     }
    10 }
  • 相关阅读:
    关于我的介绍
    关于这周的作业
    关于这周的学习
    每周学习
    关于这周程序设计
    关于这周的总结
    关于这周的学习
    随机抽签程序报告
    Mysql的主从复制原理及部署
    项目架构脚本
  • 原文地址:https://www.cnblogs.com/cminus/p/8445307.html
Copyright © 2020-2023  润新知