SA-IS
1개요
SA-IS는 O(n) 접미사 배열 구성 알고리즘이다.
2S/L형 분류
시작하기 전에 문자열 마지막에 다른 모든 문자보다 작은 특수 문자 $를 덧붙인다.
각 위치 i를 다음 규칙으로 S형 또는 L형으로 분류한다.
- Si < Si+1, 또는 Si = Si+1이고 i+1이 S형 ⇒ i는 S형(Small)
- Si > Si+1, 또는 Si = Si+1이고 i+1이 L형 ⇒ i는 L형(Large)
- $는 S형
오른쪽에서 왼쪽으로 스캔하면 O(n)에 분류할 수 있다. i가 S형이면 suf(i) < suf(i+1), L형이면 suf(i) > suf(i+1)이다.
3LMS 위치
바로 왼쪽이 L형인 S형 위치를 LMS(Left-Most S-type) 위치라 한다. $는 항상 LMS다.
LMS 위치 i의 LMS 부분 문자열은 i에서 시작해 다음 LMS 위치 j까지의 구간 Si⋯j이다. 두 LMS 위치 사이에 다른 LMS 위치, 즉 L→S 전환이 없으므로, 구간 내부는 S형 연속 뒤 L형 연속으로 이루어지고 j에서 S형으로 끝난다(S+L+S 패턴).
두 LMS 부분 문자열이 같으려면 길이가 같고 대응하는 각 위치의 문자와 S/L형이 모두 일치해야 한다.
4유도 정렬
문자 c로 시작하는 접미사들의 위치 집합 Bc = { i : Si = c }를 버킷이라 한다. SA에서 Bc는 연속 구간을 차지한다. SA를 정확히 몰라도 버킷은 쉽게 알 수 있다.
초기에 SA의 모든 위치가 비어 있다. lms(i)를 i의 오른쪽 첫 LMS 위치라 하자. LMS 위치들을 각 버킷 끝에 배치하고 유도 정렬을 실행하면 모든 위치 i가 비교 기준 (Si, Si+1, ⋯, Slms(i)−1, rlms(i))으로 정렬된다.
4.1알고리즘
L형 유도: 각 버킷의 맨 앞에 삽입 포인터 headc를 두고, i = 0, ⋯, n−1 순서로 스캔한다. SAi가 비어 있으면 건너뛰고, SAi = j이면 j−1이 L형일 때 j−1을 headSj−1에 삽입하고 headSj−1를 오른쪽으로 한 칸 이동한다.
S형 유도: 각 버킷의 맨 뒤에 삽입 포인터 tailc를 두고, i = n−1, ⋯, 0 순서로 스캔한다. SAi가 비어 있으면 건너뛰고, SAi = j이면 j−1이 S형일 때 j−1을 tailSj−1에 삽입하고 tailSj−1를 왼쪽으로 한 칸 이동한다. 이때 빈 칸에 삽입될 수도 있고, 이미 채워진 칸을 덮어쓸 수도 있다. LMS 위치는 S형이므로 초기에 배치한 LMS 항목들은 이 과정에서 S형 위치로서 재삽입된다.
4.2증명
4.2.1L형 유도
4.2.1.1모든 L형 위치가 SA에 배치됨
i < j인 모든 j에 대해 j가 L형 위치일 경우 SA에 배치됨을 가정하고 i가 L형 위치일 경우 언젠가 SA에 배치됨을 보이자.
- i+1이 LMS 위치: LMS 위치는 초기에 배치되어 있으므로 i도 배치된다.
- i+1이 L형 위치이고 Si+1 > Si+2: i+1은 i+2가 스캔될 때 배치되는데, i+1은 i+2보다 오른쪽 버킷에 배치되므로 언젠가 스캔되어 i가 배치된다.
- i+1이 L형 위치이고 Si+1 = Si+2: Si+1 = Si+2이므로 i+2도 L형이다. 가정에 의해 i+2가 SA에 배치된다. i+2가 배치될 때 headSi+1는 i+2의 위치를 지나 전진하며 이후 오른쪽으로만 이동한다. 따라서 i+2가 스캔될 때 i+1은 i+2보다 오른쪽에 배치되어 이후 스캔되고 i가 배치된다.
4.2.1.2같은 버킷 내 순서가 올바름
SA 위치 0, 1, ⋯, k−1 중 L형 위치가 모두 올바르게 정렬되어 있다고 가정하자.
i, j ≤ k, Si = Sj = c이고 suf(i) < suf(j)인 L형 위치 i, j를 생각하자. Si = Sj이므로 suf(i+1) < suf(j+1)이고, 가정에 의해 i+1이 j+1보다 왼쪽에 있다. 따라서 i가 j보다 먼저 배치되고, SA 위치 0, 1, ⋯, k 중 L형 위치가 모두 올바르게 정렬되어 있다. ■
4.2.2S형 유도
4.2.2.1모든 S형 위치가 SA에 배치됨
j > i인 모든 S형 위치 j가 SA에 배치됨을 가정하고 S형 위치 i가 SA에 배치됨을 보이자.
- i+1이 L형: L형 유도 후 i+1이 SA에 배치되어 있다. i+1이 스캔될 때 i가 배치된다.
- i+1이 S형이고 Si+1 < Si+2: i+1은 i+2가 스캔될 때 배치되는데, i+1은 i+2보다 왼쪽 버킷에 배치되므로 이후 스캔되어 i가 배치된다.
- i+1이 S형이고 Si+1 = Si+2: Si+1 = Si+2이므로 i+2도 S형이다. 가정에 의해 i+2가 SA에 배치된다. i+2가 배치될 때 tailSi+1는 i+2의 위치를 지나 후퇴하며 이후 왼쪽으로만 이동한다. 따라서 i+2가 스캔될 때 i+1은 i+2보다 왼쪽에 배치되어 이후 스캔되고 i가 배치된다.
4.2.2.2같은 버킷 내 순서가 올바름
SA 위치 n−1, n−2, ⋯, k+1 중 S형 위치가 모두 올바르게 정렬되어 있다고 가정하자.
i, j ≥ k, Si = Sj = c이고 suf(i) < suf(j)인 S형 위치 i, j를 생각하자. Si = Sj이므로 suf(i+1) < suf(j+1)이고, 가정에 의해 i+1이 j+1보다 왼쪽에 있다. 따라서 j가 i보다 먼저 배치되고, SA 위치 n−1, n−2, ⋯, k 중 S형 위치가 모두 올바르게 정렬되어 있다. ■
5알고리즘
- 모든 위치를 S/L형으로 분류하고 LMS 위치를 구한다.
- LMS 위치를 Si 순서로 배치하고 유도 정렬한다. SA에서 LMS 위치들의 상대 순서는 LMS 부분 문자열의 정렬 순서와 일치한다.
- LMS 부분 문자열에 순위를 부여한다. 모든 LMS 부분 문자열이 서로 다르면 LMS 접미사 순서가 확정된다.
- 같은 LMS 부분 문자열이 있으면 LMS 부분 문자열 순위로 축소 문자열 r을 구성하고 SA-IS를 재귀 호출해 LMS 접미사 순서를 구한다.
- LMS 위치를 LMS 접미사 순서로 배치하고 유도 정렬하면 올바른 SA가 된다.
LMS 위치 수는 ⌊n/2⌋ 이하이므로 |r| ≤ n/2. T(n) = T(n/2) + O(n) ⇒ T(n) = O(n).
6증명
축소 문자열의 SA가 LMS 부분 접미사 순서를 올바르게 구함을 보이자.
LMS 위치를 순서대로 p0 < p1 < ⋯ < pm-1이라 하고, rk를 pk의 LMS 부분 문자열에 부여한 rank라 한다. 축소 문자열 r = (r0, r1, ⋯, rm-1)의 k번째 접미사를 sufr(k)로 쓴다.
sufr(k) < sufr(j) ⇒ sufS(pk) < sufS(pj)임을 보이자.
rk+i < rj+i인 최소의 음이 아닌 정수 i를 잡는다. 순위가 같은 LMS 부분 문자열은 완전히 같으므로 sufS(pk)와 sufS(pj)의 비교는 결국 sufS(pk+i)와 sufS(pj+i)의 비교가 된다.
두 LMS 부분 문자열은 다음 성질을 만족한다.
- 접두사 관계는 불가능하다. LMS 부분 문자열은 정확히 다음 LMS 위치에서 끝난다. 짧은 쪽의 끝이 긴 쪽의 내부에 있으려면 그 위치가 LMS여야 하는데, LMS 사이에 LMS가 없으므로 모순이다.
- 문자 배열이 같으면 S/L형도 같다. LMS 부분 문자열의 S/L형은 문자 배열과 일대일 대응이다.
따라서 두 LMS 부분 문자열이 다르면 반드시 어떤 위치에서 문자가 다르다. 처음으로 문자가 다른 위치 q에서 Spk+i+q < Spj+i+q이므로 sufS(pk+i) < sufS(pj+i)이고, sufS(pk) < sufS(pj)이다.
따라서 r의 접미사 배열이 LMS 접미사의 순서를 정확히 결정한다. ■
7참고 문헌
- Nong, G., Zhang, S., & Chan, W. H. (2009). Linear suffix array construction by almost pure induced-sorting. 2009 Data Compression Conference, 193–202.