Algorithm Search⌘K

Proofs: DC3 (skew) algorithm

These are the human proofs of DC3 (skew) algorithm, at full length.

The DC3 algorithm sorts the suffixes in linear time full

This proof shows: correctness, termination, time.worst.

Notation. T=T[0…n−1]T = T[0 \ldots n-1] with symbols in {1,…,K}\{1, \ldots, K\}, and T[n]=T[n+1]=T[n+2]=0T[n] = T[n+1] = T[n+2] = 0. Positions are 0-based, Ti=T[i…n−1]T_i = T[i \ldots n-1], and the order is lexicographic with a proper prefix first. For i≥ni \ge n, TiT_i is the empty string. Because 0 is smaller than all symbols, comparing the padded strings T[i…n+2]T[i \ldots n+2] gives the same order as comparing the suffixes, and two different suffixes never compare equal. Let n0=⌈n/3⌉n_0 = \lceil n/3 \rceil, n1=⌊(n+1)/3⌋n_1 = \lfloor (n+1)/3 \rfloor, n2=⌊n/3⌋n_2 = \lfloor n/3 \rfloor: the numbers of positions i<ni < n with i mod 3=0,1,2i \bmod 3 = 0, 1, 2. The sample B12B_{12} is the set of positions i<n+(n0−n1)i < n + (n_0 - n_1) with i mod 3≠0i \bmod 3 \ne 0. When n mod 3=1n \bmod 3 = 1, it contains the dummy position nn, whose suffix is empty.

Lemma 1 (reduced string). Let name(i)name(i) be the rank of the triple T[i…i+2]T[i \ldots i+2] among the distinct triples of the sample, from 1. Let RR be the string name(1) name(4) name(7)⋯name(1)\,name(4)\,name(7) \cdots (all sample positions ≡1\equiv 1, n0n_0 of them) followed by name(2) name(5)⋯name(2)\,name(5) \cdots (all ≡2\equiv 2, n2n_2 of them). For sample positions ii and jj, Ti<TjT_i < T_j if and only if the suffix of RR that starts at the index of ii is smaller than the suffix that starts at the index of jj.

Proof. The suffix of RR at the index of i≡1i \equiv 1 is name(i) name(i+3)⋯name(i)\,name(i+3) \cdots up to the end of the first half, followed by the names of the second half. The run of names name(i) name(i+3)⋯name(i)\,name(i+3) \cdots spells TiT_i triple by triple, padded with zeros. The last triple of the first half contains a 0: if n mod 3≠1n \bmod 3 \ne 1, the last position ≡1\equiv 1 below nn is n−1n - 1 or n−2n - 2, whose triple reaches index nn; if n mod 3=1n \bmod 3 = 1, it is the dummy nn with triple (0,0,0)(0, 0, 0). A triple that contains a 0 can be equal to another triple only if the zeros are at the same offsets, which happens only for the triples that end at the same place in TT. So when two suffixes of RR are compared, they differ at the latest at the first triple that contains the end of TT, before the comparison reaches the second half of RR (except for two equal triples at the very same position, which means i=ji = j). For two positions ≡2\equiv 2 the same argument applies, since the last triple of the second half also contains a 0. Comparing names in order is comparing triples in order, and comparing triples is comparing the padded suffixes. □\square

Lemma 2 (sample ranks). After lines L4 to L7, rank(i)rank(i) for i∈B12i \in B_{12} is the rank of TiT_i among the sample suffixes, from 1, and rank(i)=0rank(i) = 0 for i≥n+(n0−n1)i \ge n + (n_0 - n_1) through the padding.

Proof. If all names are different (line L7), the triple order is the suffix order, because two suffixes that differ in the first triple compare as the triples. Otherwise line L6 sorts the suffixes of RR, which by Lemma 1 orders the sample suffixes; the recursion is correct by induction on nn, since ∣R∣=n0+n2<n|R| = n_0 + n_2 < n for n≥2n \ge 2. □\square

Lemma 3 (non-sample order). For i,j≡0i, j \equiv 0, Ti<TjT_i < T_j if and only if (T[i],rank(i+1))<(T[j],rank(j+1))(T[i], rank(i+1)) < (T[j], rank(j+1)).

Proof. Ti=T[i] Ti+1T_i = T[i]\,T_{i+1} and i+1∈B12i + 1 \in B_{12} or i+1≥ni + 1 \ge n. If T[i]≠T[j]T[i] \ne T[j] the first symbols decide. Otherwise Ti+1T_{i+1} and Tj+1T_{j+1} decide, and by Lemma 2 their ranks compare as they do. Line L8 takes the positions i+1≡1i + 1 \equiv 1 in the sorted sample order, which is sorted by rank(i+1)rank(i+1), and sorts them stably by T[i]T[i], so the result is sorted by the pair. □\square

Lemma 4 (merge). For i≡0i \equiv 0 and j∈B12j \in B_{12}:

  • if j≡1j \equiv 1: Ti<TjT_i < T_j if and only if (T[i],rank(i+1))<(T[j],rank(j+1))(T[i], rank(i+1)) < (T[j], rank(j+1)), because i+1≡1i + 1 \equiv 1 and j+1≡2j + 1 \equiv 2 are both in the sample or beyond the end;
  • if j≡2j \equiv 2: Ti<TjT_i < T_j if and only if (T[i],T[i+1],rank(i+2))<(T[j],T[j+1],rank(j+2))(T[i], T[i+1], rank(i+2)) < (T[j], T[j+1], rank(j+2)), because i+2≡2i + 2 \equiv 2 and j+2≡1j + 2 \equiv 1 are both in the sample or beyond the end.

Proof. As in Lemma 3, peel one or two symbols and compare the rest by the sample ranks. A rank of 0 belongs to an empty suffix and is smaller than all others. The pairs or triples are never equal for i≠ji \ne j, since the suffixes are different. □\square

Theorem 1 (correctness). DC3 returns the suffix array of TT.

Proof. The sample suffixes are sorted by Lemma 2, without the dummy, which is the smallest and is skipped at the start of the merge. The other suffixes are sorted by Lemma 3. Line L9 merges two sorted lists, and by Lemma 4 each comparison of the merge is correct. So the result lists all nn suffixes in order. For n≤1n \le 1 the result is trivial. □\square

Theorem 2 (time). DC3 runs in O(n)O(n) time when K=O(n)K = O(n).

Proof. Without the recursion, each line is a scan or a counting sort with O(K+n)O(K + n) buckets; in the recursive calls the alphabet is the names, at most the length of the string. The reduced string has length n0+n2≤⌈2n/3⌉+1n_0 + n_2 \le \lceil 2n/3 \rceil + 1, so the time satisfies t(n)≤t(⌈2n/3⌉+1)+O(n)t(n) \le t(\lceil 2n/3 \rceil + 1) + O(n), whose solution is O(n)O(n). The recursion depth is O(log⁡n)O(\log n), and the recursion stops, since the length drops for n≥2n \ge 2 and the case n≤1n \le 1 returns at once. ■\blacksquare

Back to DC3 (skew) algorithm