Skip to content
Back to skills

Algo Tries

ASecurity

Prefix tree for O(m) string insert/search and O(p+k) prefix queries; ideal for autocomplete and dictionary membership.

  • 4 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added May 27, 2026
data-aipythongonode

Security analysis

A100/100

Scanned May 27, 2026

npx -y skills add Pavel-Kravchenko/Bioinformatics --skill algo-tries --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Algo Tries?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Algo Tries
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/pavel-kravchenko-algo-tries/badge)](https://www.skillsdirectory.com/skills/pavel-kravchenko-algo-tries)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: algo-tries
description: "Prefix tree for O(m) string insert/search and O(p+k) prefix queries; ideal for autocomplete and dictionary membership."
tool_type: python
primary_tool: Python
---

# Trie (Prefix Tree)

Each node = one character. Path root→node = prefix. `is_end` marks word boundaries.

## Complexity

| Operation | Time | Notes |
|-----------|------|-------|
| Insert | O(m) | m = word length |
| Search (exact) | O(m) | |
| Prefix check | O(p) | p = prefix length |
| Prefix collect | O(p + k) | k = results |
| Delete | O(m) | |

**vs Hash Table**: trie has O(p + k) prefix search vs O(n × m) scan; hash is usually lower memory for exact lookup.

## Implementation

```python
class TrieNode:
    def __init__(self):
        self.children: dict[str, "TrieNode"] = {}
        self.is_end = False


class Trie:
    def __init__(self):
        self.root = TrieNode()

    def _find_node(self, prefix: str) -> TrieNode | None:
        node = self.root
        for ch in prefix:
            if ch not in node.children:
                return None
            node = node.children[ch]
        return node

    def insert(self, word: str) -> None:
        node = self.root
        for ch in word:
            node = node.children.setdefault(ch, TrieNode())
        node.is_end = True

    def search(self, word: str) -> bool:
        node = self._find_node(word)
        return node is not None and node.is_end

    def starts_with(self, prefix: str) -> bool:
        return self._find_node(prefix) is not None

    def get_all_with_prefix(self, prefix: str) -> list[str]:
        results: list[str] = []
        node = self._find_node(prefix)
        if node is None:
            return results
        self._collect(node, prefix, results)
        return results

    def _collect(self, node: TrieNode, word: str, results: list[str]) -> None:
        if node.is_end:
            results.append(word)
        for ch, child in sorted(node.children.items()):
            self._collect(child, word + ch, results)

    def delete(self, word: str) -> bool:
        def _del(node: TrieNode, depth: int) -> bool:
            if depth == len(word):
                if not node.is_end:
                    return False
                node.is_end = False
                return not node.children  # safe to prune if leaf
            ch = word[depth]
            if ch not in node.children:
                return False
            if _del(node.children[ch], depth + 1):
                del node.children[ch]
                return not node.children and not node.is_end
            return False
        return _del(self.root, 0)

    def get_all_words(self) -> list[str]:
        return self.get_all_with_prefix("")
```

## Common Pattern: Autocomplete

```python
def autocomplete(trie: Trie, prefix: str, max_results: int = 5) -> list[str]:
    return trie.get_all_with_prefix(prefix)[:max_results]
```

## Pitfalls

- **`search` vs `starts_with`**: "ca" returns `True` for `starts_with` even if only "cat" was inserted; `search` checks `is_end`.
- **Deleting a prefix of another word**: never remove nodes that have children; only clear `is_end`. The delete implementation above handles this — prune only when the node becomes a childless non-endpoint.
- **Memory vs hash map**: a trie node with a `dict` per node uses more memory than a flat hash map for large, sparse alphabets. Use an array of size |Σ| only when the alphabet is small and dense (e.g., DNA: 4 chars).
- **Case sensitivity**: trie is case-sensitive by default; normalize input before inserting/searching.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…