Skip to content

Ternary Search Tree Search

Search for a string key in a ternary search tree using character comparisons and three-way branching.

Ternary search tree search stores strings in a tree where each node contains one character and has three children.

The left child stores smaller characters, the middle child continues the current string, and the right child stores larger characters. This combines properties of binary search trees and tries.

Problem

Given a ternary search tree root root and a string key s, determine whether s is stored as a complete key.

Return true if present, otherwise false.

Structure

Each node stores:

fieldmeaning
charcharacter stored at this node
leftnext node for smaller character
midnext node for equal character and next string position
rightnext node for larger character
is_terminalmarks the end of a stored key

Algorithm

Compare the current query character with the node character.

ternary_search_tree_search(root, s):
    if s is empty:
        return false

    node = root
    i = 0

    while node != null:
        c = s[i]

        if c < node.char:
            node = node.left

        else if c > node.char:
            node = node.right

        else:
            if i == length(s) - 1:
                return node.is_terminal

            i = i + 1
            node = node.mid

    return false

Example

Stored keys:

key
“cat”
“car”
“dog”

One possible ternary search tree:

        c
        |
        a
       / \
      -   -
       \ 
        t*
       /
      r*

A clearer search path for "car" is:

stepquery charnode charaction
1ccequal, go middle
2aaequal, go middle
3rtr < t, go left
4rrequal, terminal true

The * marks a terminal node.

Correctness

At each node, the current query character is compared with the node character. If it is smaller, only the left subtree can contain a matching continuation. If it is larger, only the right subtree can contain it. If it is equal, the search advances to the next character through the middle child.

This exactly mirrors lexicographic search over strings. When the last character is matched, the terminal flag determines whether the full string, rather than only a prefix, is stored.

Therefore the algorithm returns true exactly when the key exists in the ternary search tree.

Complexity

Let LL be the string length and hch_c be the height of character comparison trees at each level.

casetime
balanced character branchesO(Llogσ)O(L \log \sigma)
typical sparse stringsclose to O(L)O(L)
worst caseO(L+n)O(L + n)

Here σ\sigma is the alphabet size.

Space complexity for iterative search is:

O(1) O(1)

When to Use

Ternary search trees are useful when:

  • keys are strings
  • memory use should be lower than a full array based trie
  • prefix search is needed
  • ordered traversal is useful

Compared to ordinary tries, ternary search trees avoid storing a large child array per node. Compared to hash tables, they preserve prefix and lexicographic operations.

Implementation

class TSTNode:
    def __init__(self, char):
        self.char = char
        self.left = None
        self.mid = None
        self.right = None
        self.is_terminal = False

def ternary_search_tree_search(root, s):
    if not s:
        return False

    node = root
    i = 0

    while node is not None:
        c = s[i]

        if c < node.char:
            node = node.left
        elif c > node.char:
            node = node.right
        else:
            if i == len(s) - 1:
                return node.is_terminal

            i += 1
            node = node.mid

    return False
type TSTNode struct {
	Char       rune
	Left       *TSTNode
	Mid        *TSTNode
	Right      *TSTNode
	IsTerminal bool
}

func TernarySearchTreeSearch(root *TSTNode, s string) bool {
	runes := []rune(s)
	if len(runes) == 0 {
		return false
	}

	node := root
	i := 0

	for node != nil {
		c := runes[i]

		if c < node.Char {
			node = node.Left
		} else if c > node.Char {
			node = node.Right
		} else {
			if i == len(runes)-1 {
				return node.IsTerminal
			}

			i++
			node = node.Mid
		}
	}

	return false
}