Ukkonen’s Algorithm is an online method for constructing suffix trees in linear time. It relies on three core ideas:
- Suffix Links
- Four Optimisation Tricks
The algorithm incrementally builds an implicit suffix tree for each prefix of str[1...n], and then extends all suffixes with $ to produce the regular suffix tree.
The suffix links are introduced to speed up traversal, and the optimisation tricks to eliminate redundant computations. Without them, the algorithm can degrade to — worse than the naive approach.
Incremental Construction Of Implicit Suffix Trees
Given a string str[1...n], Ukkonen’s Algorithm proceeds over phases:
- In phase , the algorithm constructs the implicit suffix tree for the prefix
str[1...i]() - In phase , it constructs incrementally from via suffix extension
A suffix extensions involves extending each suffix str[j...i] () from the implicit suffix tree, to include the new character str[i+1]. Specifically, it:
- Locates the end of the path corresponding to the suffix
str[j...i]in , then - Extends this path by appending
str[i+1], modifying the tree structure based on a set of extension rules.
After phases, is converted to the regular suffix tree by appending the terminal symbol $ and running one final phase (). In practice, it’s simpler to append $ to str[1...n] at the start and run all phases directly.
Suffix Extension Rules
Suffix extension rules determine how each suffix str[j...i] is extended to incorporate the next character str[i+1].
Rule 1 — Leaf Extension

At suffix extension in phase , if the substring α = str[j...i] has not appeared prior to , then, as suffixes with common prefixes share the same path, its path must end at a leaf.
Thus, to accommodate the new character str[i+1], a simple leaf extension is employed
Rule 1 — Leaf Extension
At suffix extension in phase , if the path
str[j...i]in ends at a leaf, then extend that leaf by adjusting the label of the edge to account for the added characterstr[i+1].
Rule 2 Regular — Internal Split

At suffix extension in phase , if the substring α has appeared prior to , and the prior a’s were followed by the same character x, then contains a root-to-leaf path representing α followed by x (and any subsequent characters)
Thus, to accommodate the new character str[i+1], the path for α must split.
Rule 2 Regular — Internal Split
At suffix extension in phase , if:
- The path
str[j...i]in doesn’t end at a leaf and,- The next character in the path is some
x != str[i+1]Then split the edge after
str[j...i]by inserting a new internal nodeufollowed by a leaf numbered , and assigning the characterstr[i+1]as the edge label betweenuandj
Rule 2 Alternate — Internal Append

At suffix extension in phase , if the substring α has appeared prior to , and the prior a’s were followed by different characters x and y, then contains a root-to-leaf path representing α ending at an internal node, which branches out to both x and y (followed by any subsequent characters)
Thus, to accommodate the new character str[i+1], another branch is appended to the internal node after α
Rule 2 Alternate — Internal Append
At suffix extension in phase , if:
- The path
str[j...i]in doesn’t end at a leaf and,- The next characters in the path are some
x, y != str[i+1]and,- An internal node already exists at the end of
str[j...i]Then create a new leaf numbered branching from the internal node
u, and assign the characterstr[i+1]as the edge label betweenuandj
Rule 3 — Do Nothing

At suffix extension in phase , if the substring α has appeared prior to , and the prior a’s were followed by same characters z = str[i+1], then already contains a root-to-leaf path representing α followed by str[i+1] = z.
In this case, no changes are required since the path str[j...i+1] is already present.
Rule 3 — Do Nothing
At suffix extension in phase , if:
- The path
str[j...i]in doesn’t end at a leaf and,- The next characters in the path is
str[i+1],Then
str[i+1]is already in the tree, and no further action is needed
Naive Implicit Suffix Tree Construction
The following presents a base implementation of Ukkonen’s algorithm, without any optimisation.
def implicit_suffix_tree(str):
n = len(str)
Construct I₁
for i from [1...n-1]:
# Begin PHASE i + 1
for j from [1...i+1]
# Begin EXTENSION j
Follow the path str[j...i] from the root in the current state of the implicit suffix tree
Extend this path by appending str[i+1] using the suffix extension rules
# str[j...i+1] is now in the tree
# end of phase i+1 (I_{i+1} computed)In each phase, the algorithm makes up to extensions, and finding the end of each path str[j...i] takes up to time. Summing all character traversals across phases gives a worst case time complexity of .
Although this implementation is inefficient, its structure mirrors Ukkonen’s algorithm, which is derived by refining this approach to achieve linear time.
Example Of Constructing An Implicit Suffix Tree
Given a string
str[1...7] = abaaba$, constructing an implicit suffix tree (using space-efficient representation) goes as follows:Phase | Prefix
εInitially at phase , the implicit suffix tree contains no edges or suffixes, only the root node.
Phase | Prefix
aAt phase , each suffix
str[j...i]is extended by characterstr[i+1] = str[1] = a.The first extension , extends the path
str[1...0] = ""bya. This can be considered a “base case”, as only contains the root, sostr[1]is never present in the tree.As the path ends at an internal node (the root), rule 2 alternate applies: a new leaf labelled is added directly to the root, with the edge label being
str[i+1] = a
Phase | Prefix
abAt phase , each suffix
str[j...i]is extended bystr[2] = b.Extension extends the path
str[1...1] = abyb, formingstr[j...i+1] = str[1...2] = ab. As the path ends at a leaf, rule 1 applies: the leaf is extended by adjusting the edge endpoint to .
Extension extends the path
str[2...1] = ""byb. As this path is non-existent in the tree, rule 2 alternate applies.
Phase | Prefix
abaAt phase , each suffix
str[j...i]is extended bystr[3] = a.Extension extends the path
str[1...2] = abbya, formingaba. As the path ends at a leaf, rule 1 applies.
Extension extends the path
str[2...2] = bbya, formingba. As this path, ends at a leaf, rule 1 applies.
Extension extends the path
str[3...2] = ""bya, forminga. As the pathstr[j...i+1] = str[3...3] = aalready exists in the tree, rule 3 applies: no changes are needed.Phase | Prefix
abaaAt phase , each suffix
str[j...i]is extended bystr[4] = a.Extension extends the path
str[1...3] = ababya, formingabaa. As the path ends at a leaf, rule 1 applies.
Extension extends the existing path
str[2...3] = babya, formingbaa. As this path, ends at a leaf, rule 1 applies.
Extension extends the path
str[3...3] = abya, formingaa. The pathaexists implicitly (ends in the middle of an edge, not at a leaf, nor an internal node), therefore rule 2 regular applies: an internal node is created aftera, and two edges are appended one for the previousbaa, and a new edge fora.
Extension extends the path
str[4...3] = ""bya, forminga. As the pathstr[4...4] = aalready exist, rule 3 applies.Phase | Prefix
abaabAt phase , each suffix
str[j...i]is extended bystr[5] = b.Extension extends the path
str[1...4] = abaabyb, formingabaab. As the path ends at a leaf, rule 1 applies.
Extension extends the path
str[2...4] = baabyb, formingbaab. As this path, ends at a leaf, rule 1 applies.
Extension extends the path
str[3...4] = aabyb, formingaab. As this path, ends at a leaf, rule 1 applies.
Extension extends the path
str[4...4] = abyb, formingab. As the pathabalready exists, rule 3 applies.Extension extends the path
str[5...4] = ""byb, formingb. As the pathbalready exists, rule 3 applies.Phase | Prefix
abaabaAt phase , each suffix
str[j...i]is extended bystr[6] = a.Extension extends the path
str[1...5] = abaabbya, formingabaaba. As the path ends at a leaf, rule 1 applies.
Extension extends the path
str[2...5] = baabbya, formingbaaba. As this path, ends at a leaf, rule 1 applies.
Extension extends the path
str[3...5] = aabbya, formingaaba. As this path, ends at a leaf, rule 1 applies.
Extension extends the path
str[4...5] = abbya, formingaba. As the pathabaalready exists, rule 3 applies.Extension extends the path
str[5...5] = bbya, formingba. As the pathbaalready exists, rule 3 applies.Extension extends the path
str[5...5] = ""bya, forminga. As the pathaalready exists, rule 3 applies.Phase | Prefix
abaaba$At phase , each suffix
str[j...i]is extended bystr[7] = $.Extension extends the path
str[1...6] = abaababy$, formingabaaba$. As the path ends at a leaf, rule 1 applies.
Extension extends the path
str[2...6] = baababy$, formingbaaba$. As this path, ends at a leaf, rule 1 applies.
Extension extends the path
str[3...6] = aababy$, formingaaba$. As this path, ends at a leaf, rule 1 applies.
Extension extends the path
str[4...6] = ababy$, formingaba$. As the path exists implicitly, rule 2 regular applies.
Extension extends the path
str[5...6] = baby$, formingba$. As the path exists implicitly, rule 2 regular applies.
Extension extends the path
str[5...6] = aby$, forminga$. As the path ends at an internal node, rule 2 alternate applies.
Extension extends the path
str[6...6] = ""by$, forming$. As the path ends at an internal node, rule 2 alternate applies.
The additional phase is no different to any other phase, and constructs the explicit suffix tree for
str[1...7 = abaaba$.

























