From 6a10707740d7537d7a22a478c1312acc8a7a6551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B9=E6=99=93=E8=88=AA?= <1210603696@qq.com> Date: Tue, 30 Dec 2014 11:46:53 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E8=AE=A1=E7=AE=97rank?= =?UTF-8?q?=E6=95=B0=E7=BB=84=E7=9A=84=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TinySTL/SuffixArray.h | 61 +++++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/TinySTL/SuffixArray.h b/TinySTL/SuffixArray.h index 58f5d13..8be5bd5 100644 --- a/TinySTL/SuffixArray.h +++ b/TinySTL/SuffixArray.h @@ -7,10 +7,12 @@ namespace TinySTL{ class suffix_array{ + public: + using array_type = std::vector < int > ; private: - //typedef std::unique_ptr> vecPtr; - private: - std::vector _array; + array_type _suffix_array; + array_type _height_array; + array_type _rank_array; public: template //arr - 源数组 @@ -18,9 +20,35 @@ namespace TinySTL{ //max_len - max_len代表字符串arr中字符的取值范围,是基数排序的一个参数, // 如果原序列都是字母可以直接取128,如果原序列本身都是整数的话,则m可以取比最大的整数大1的值。 suffix_array(InputIterator arr, size_t len, size_t max_len = 128){ + calSuffix(arr, len, max_len); + calRank(); + } + + array_type suffixArray(){ + return _suffix_array; + } + array_type heightArray(){ + //todo + } + array_type rankArray(){ + return _rank_array; + } + private: + template + bool cmp(InputIteraotr arr, size_t a, size_t b, size_t l){ + return arr[a] == arr[b] && arr[a + l] == arr[b + l]; + } + void calRank(){ + _rank_array.resize(_suffix_array.size()); + for (auto i = 0; i != _suffix_array.size(); ++i){ + _rank_array[_suffix_array[i]] = i; + } + } + template + void calSuffix(InputIterator arr, size_t len, size_t max_len){ //采用了罗穗骞论文中实现的倍增算法 //算法时间复杂度 = O(nlg(n)) - _array.resize(len); + _suffix_array.resize(len); int wa[1024], wb[1024], wv[1024], ws[1024]; int i, j, p, *x = wa, *y = wb, *t; @@ -30,7 +58,7 @@ namespace TinySTL{ for (i = 0; i < len; i++) ws[x[i] = arr[i]]++; for (i = 1; i < max_len; i++) ws[i] += ws[i - 1]; //i之所以从len-1开始循环,是为了保证在当字符串中有相等的字符串时,默认靠前的字符串更小一些。 - for (i = len - 1; i >= 0; i--) _array[--ws[x[i]]] = i; + for (i = len - 1; i >= 0; i--) _suffix_array[--ws[x[i]]] = i; //下面这层循环中p代表rank值不用的字符串的数量,如果p达到len,那么各个字符串的大小关系就已经明了了。 //j代表当前待合并的字符串的长度,每次将两个长度为j的字符串合并成一个长度为2*j的字符串,当然如果包含字符串末尾具体则数值应另当别论,但思想是一样的。 @@ -39,7 +67,7 @@ namespace TinySTL{ { //以下两行代码实现了对第二关键字的排序 for (p = 0, i = len - j; i < len; i++) y[p++] = i; - for (i = 0; i < len; i++) if (_array[i] >= j) y[p++] = _array[i] - j; + for (i = 0; i < len; i++) if (_suffix_array[i] >= j) y[p++] = _suffix_array[i] - j; //第二关键字基数排序完成后,y[]里存放的是按第二关键字排序的字符串下标 //这里相当于提取出每个字符串的第一关键字(前面说过了x[]是保存rank值的,也就是字符串的第一关键字),放到wv[]里面是方便后面的使用 //以下四行代码是按第一关键字进行的基数排序 @@ -47,21 +75,22 @@ namespace TinySTL{ for (i = 0; i < max_len; i++) ws[i] = 0; for (i = 0; i < len; i++) ws[wv[i]]++; for (i = 1; i < max_len; i++) ws[i] += ws[i - 1]; - for (i = len - 1; i >= 0; i--) _array[--ws[wv[i]]] = y[i]; + for (i = len - 1; i >= 0; i--) _suffix_array[--ws[wv[i]]] = y[i]; //下面两行就是计算合并之后的rank值了,而合并之后的rank值应该存在x[]里面,但我们计算的时候又必须用到上一层的rank值,也就是现在x[]里面放的东西,如果我既要从x[]里面拿,又要向x[]里面放,怎么办? //当然是先把x[]的东西放到另外一个数组里面,省得乱了。这里就是用交换指针的方式,高效实现了将x[]的东西“复制”到了y[]中。 - for (t = x, x = y, y = t, p = 1, x[_array[0]] = 0, i = 1; i < len; i++) - x[_array[i]] = cmp(y, _array[i - 1], _array[i], j) ? p - 1 : p++; + for (t = x, x = y, y = t, p = 1, x[_suffix_array[0]] = 0, i = 1; i < len; i++) + x[_suffix_array[i]] = cmp(y, _suffix_array[i - 1], _suffix_array[i], j) ? p - 1 : p++; } return; } - - const std::vector suffixArray()const{ - return _array; - } - private: - bool cmp(int *arr, int a, int b, int l){ - return arr[a] == arr[b] && arr[a + l] == arr[b + l]; + template + void calHeight(InputIteraotr arr, size_t len) + { + int i, j, k = 0; + for (i = 1; i <= n; i++) _rank_array[_suffix_array[i]] = i; + for (i = 0; i < n; _height_array[_rank_array[i++]] = k) + for (k ? k-- : 0, j = _suffix_array[_rank_array[i] - 1]; arr[i + k] == arr[j + k]; k++); + return; } }; }