後綴數組的實現

後綴數組的實現

什麼是後綴數組

後綴數組是處理字符串的有力工具。後綴數組是後綴樹的一個非常精巧的替代品,它比後綴樹容易編程實現,能夠實現後綴樹的很多功能而時間複雜度也並不遜色,而且它比後綴樹所佔用的內存空間小很多。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
不知道是我不會用還是因爲CSDN的markdown編輯器本身就有問題呢,看着好醜LOL

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章