後綴數組的實現
什麼是後綴數組
後綴數組是處理字符串的有力工具。後綴數組是後綴樹的一個非常精巧的替代品,它比後綴樹容易編程實現,能夠實現後綴樹的很多功能而時間複雜度也並不遜色,而且它比後綴樹所佔用的內存空間小很多。1
上邊參考的文章中,後綴數組原理講解的很清楚,但是代碼實現簡直就是一鍋粥,不知所云。因此我自己實現了一下,原理的話就請參考這篇文章了。
後綴數組的生成
在實現階段,我沒有過多的考慮算法的性能,也沒有參考該文章所說的2倍增算法,主要使用了c++容器的一些特性。
實現步驟如下:
- 生成後綴排序數組
- 生成後綴數組
- 生成高度數組(排名相鄰的兩個後綴的最長公共前綴)
代碼片段如下:
#include<iostream>
#include<string>
#include<Windows.h>
using namespace std;
//字典序比較兩個字符串,iter_1 > iter_2 ->return true
bool Cmp(string::iterator iter_1, string::iterator iter_2,string::iterator end)
{
string tmp_str_1(iter_1, end);
string tmp_str_2(iter_2, end);
//tmp_str_1 > tmp_str_2
if (tmp_str_1.compare(tmp_str_2) > 0)
{
return true;
}
else
{
return false;
}
}
//求出來某個後綴數組suf的排名
int Rank(string str, unsigned suf)
{
int rank = 0;
for (auto iter = str.begin(); iter != str.end(); iter++)
{
if (iter == (str.begin() + suf))
{
continue;
}
else if ( Cmp(str.begin() + suf, iter, str.end()) )
{
rank++;
}
}
return rank;
}
//創建一個排名數組
void set_suffix_rank_array(string str, int suff_rank[],unsigned len)
{
for(unsigned i = 0; i < len; i++)
{
suff_rank[i] = Rank(str, i);
}
}
//創建後綴數組
void set_suffix_array(int suff_rank[], int suff_array[], unsigned len)
{
for (unsigned i = 0; i < len; i++)
{
suff_array[suff_rank[i]] = i;
}
}
//依次將排名相近的兩個後綴數組從前向後計數(有相同前綴)
void set_height_array(string str,int suff_rank[], int suff_array[],int height[], unsigned len)
{
unsigned h(0),r(0);
for (unsigned i = 0; i < len; i++)
{
h = 0;
r = suff_rank[i];//只是爲了表達方便
//其中的i表示的是suff_array[suff_rank[i]],爲了書寫方便
while ((r+ 1<len) && (i + h < len) && (suff_array[r + 1] + h < len )
&& (str[i + h] == str[suff_array[r + 1] + h]))
{
h++;
}
height[suff_rank[i]] = h;
}
}
/*主要參考“後綴數組-處理字符串的有力工具”,論文作者是“羅穗騫”
主要要解決的問題:
1、最長重複出現子串;
2、最長公共子串;
*/
#include"MakeSuffixArray.h"
#include<Windows.h>
#include<string>
int main(void)
{
string str("aabca");
string str1("aab");
str = str + '0' + str1;
cout << str << endl;
auto len = str.size();
int *suff_rank = new int[len]();
int *suff_array = new int[len]();
int *height = new int[len]();
//創建一個排名數組suff[str.size()]
set_suffix_rank_array(str, suff_rank, len);
//創建後綴數組,排第幾的是誰
set_suffix_array(suff_rank, suff_array, len);
//創建高度數組
set_height_array(str, suff_rank, suff_array, height, len);
/*求一個字符串中最長重複子串,並輸出。
解題思路:只需求得height中的最大值,並根據height數組中的位置反推出字符串中的位置
*/
int pos(0), lengthest = height[0];
for (unsigned i = 1; i < len-1; i++)
{
if (height[i] > lengthest)
{
lengthest = height[i];
pos = i;
}
}
cout <<suff_array[pos]<< " "<<lengthest << endl;
for (unsigned j = 0; j < lengthest; j++)
{
cout << str[suff_array[pos] + j];
}
cout << endl;
/*求最長公共子串的問題
解題思路:先將兩個字符串前後相連,然後求最長子串,
要注意兩個子串不在同一字符串中
*/
system("pause");
return 0;
}
更詳細的代碼請轉:github