后缀数组的实现

10 篇文章 0 订阅

后缀数组的实现

什么是后缀数组

后缀数组是处理字符串的有力工具。后缀数组是后缀树的一个非常精巧的替代品,它比后缀树容易编程实现,能够实现后缀树的很多功能而时间复杂度也并不逊色,而且它比后缀树所占用的内存空间小很多。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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值