Menu
Coddy logo textTech

Trie (arbre préfixe)

Dernière mise à jour

Un trie (prononcé « traï »), ou arbre préfixe, stocke un ensemble de chaînes par leurs caractères : chaque arête est étiquetée par un caractère et un chemin depuis la racine épelle un préfixe. Les mots qui partagent un préfixe partagent les mêmes nœuds, si bien que « car », « card » et « care » réutilisent tous le chemin c-a-r. Appuyez sur lecture ci-dessus pour voir les mots insérés un caractère à la fois, ne se ramifiant que là où ils diffèrent.

Comme les recherches parcourent un nœud par caractère, chercher un mot de longueur m prend O(m) quel que soit le nombre de mots contenus dans le trie. Cela rend les tries idéaux pour l'autocomplétion, la correction orthographique et la recherche par préfixe.

Complexité en temps et en espace

OpérationComplexitéNotes
InsertionO(m)m = longueur du mot
RechercheO(m)Une étape par caractère
Requête de préfixeO(m)Parcourir jusqu'au nœud du préfixe
EspaceO(total chars)Les préfixes partagés sont stockés une seule fois

Étape par étape (insertion)

ÉtapeCe qui se passe
1Commencez au nœud racine.
2Pour chaque caractère du mot, cherchez une arête enfant correspondante.
3Si elle existe, suivez-la (en réutilisant le préfixe partagé).
4Sinon, créez un nouveau nœud enfant pour ce caractère.
5Après le dernier caractère, marquez ce nœud comme fin de mot.

Exemple résolu

Insertion de ["car", "card", "care"] dans un trie vide :

ÉtapeStructureAction
Insérer carroot → c → a → r✓Aucun enfant correspondant n'existe, donc créez c, a, r et marquez r comme fin de mot.
Insérer cardroot → c → a → r✓ → d✓Réutilisez le chemin existant c-a-r, puis créez un nouvel enfant d et marquez-le comme fin de mot.
Insérer careroot → c → a → r✓ → {d✓, e✓}Réutilisez c-a-r, ramifiez depuis r avec un nouvel enfant e, et marquez e comme fin de mot.
Rechercher careroot → c → a → r → e✓Parcourez c, a, r, e ; le nœud final est marqué comme fin de mot, donc care est présent.
Rechercher caroot → c → aLe chemin existe mais a n'est pas marqué comme fin de mot, donc ca est un préfixe mais pas un mot stocké.

Quand utiliser un trie

Utilisez-le quandÉvitez-le quand
Vous avez besoin de requêtes de préfixe ou d'autocomplétion sur un ensemble de chaînes.Vous n'avez besoin que de recherches de clés entières - une table de hachage est plus rapide et plus légère.
De nombreux mots stockés partagent des préfixes communs, donc les nœuds sont réutilisés.Les clés sont longues et se recoupent rarement, gaspillant un nœud par caractère.
Vous voulez que les clés soient renvoyées dans l'ordre via un parcours.La mémoire est limitée - les pointeurs enfants par nœud ajoutent une surcharge importante.
Le coût de recherche doit dépendre de la longueur de la clé, pas de la taille du jeu de données.L'alphabet est énorme (par ex. tout Unicode) et les enfants sont stockés de façon dense.

Code de Trie (Prefix Tree)

Une implémentation propre et exécutable de Trie (Prefix Tree) en Python, JavaScript, Java, C++, C. Choisissez un langage, copiez le code ou ouvrez-le préchargé dans le Playground Coddy.

Code de Trie (Prefix Tree) en Python

Python
1class TrieNode:2    def __init__(self):3        self.children = {}4        self.is_word = False5
6
7class Trie:8    def __init__(self):9        self.root = TrieNode()10
11    def insert(self, word):12        node = self.root13        for ch in word:14            node = node.children.setdefault(ch, TrieNode())15        node.is_word = True16
17    def search(self, word):18        node = self._walk(word)19        return node is not None and node.is_word20
21    def starts_with(self, prefix):22        return self._walk(prefix) is not None23
24    def _walk(self, s):25        node = self.root26        for ch in s:27            if ch not in node.children:28                return None29            node = node.children[ch]30        return node31
32
33trie = Trie()34for word in ["car", "card", "care", "dog"]:35    trie.insert(word)36
37print("search(card):     ", trie.search("card"))38print("search(ca):       ", trie.search("ca"))39print("starts_with(ca):  ", trie.starts_with("ca"))40print("starts_with(do):  ", trie.starts_with("do"))41print("starts_with(cat): ", trie.starts_with("cat"))
Exécutez ce code dans le Playground Python

FAQ sur les tries

À quoi sert un trie ?
Les tries alimentent les fonctionnalités basées sur les préfixes : autocomplétion et suggestions de recherche, correcteurs orthographiques, tables de routage IP et recherches dans un dictionnaire. Partout où vous devez répondre rapidement à « un mot stocké commence-t-il par ce préfixe ? », un trie excelle.
Quelle est la complexité temporelle d'un trie ?
L'insertion, la recherche et les requêtes de préfixe s'exécutent toutes en O(m), où m est la longueur du mot ou du préfixe - indépendamment du nombre de mots stockés. Le compromis est la mémoire : un trie peut utiliser beaucoup d'espace, bien que les préfixes partagés ne soient stockés qu'une seule fois.
Quelle est la différence entre un trie et une table de hachage ?
Une table de hachage offre une recherche moyenne en O(1) de clés entières mais ne peut pas répondre aux requêtes de préfixe. Un trie est légèrement plus lent par recherche mais prend naturellement en charge la recherche par préfixe, le parcours ordonné et l'autocomplétion - la raison pour laquelle il est préféré dans ces cas.
Quand devrais-je utiliser un trie plutôt qu'un arbre binaire de recherche ?
Utilisez un trie lorsque vos clés sont des chaînes et que vous avez besoin de recherches par préfixe : il s'exécute en O(m) par opération sur la longueur de la clé, alors qu'un ABR équilibré coûte O(m log n) car chaque comparaison parcourt la chaîne et il y en a log n. Un ABR est le meilleur choix quand les clés ne sont pas de type chaîne ou quand la surcharge mémoire compte plus que la vitesse des préfixes.
Comment gère-t-on la fin d'un mot dans un trie ?
Chaque nœud porte un indicateur de fin de mot qui n'est activé que lorsqu'un mot complet inséré s'y termine. Sans lui, vous ne pourriez pas distinguer un mot stocké d'un simple préfixe - par exemple, après avoir inséré card, le nœud pour car existe mais ne devrait être signalé comme un mot que si car a aussi été inséré.
Les tries économisent-ils toujours de la mémoire en partageant les préfixes ?
Pas toujours. Le partage n'aide que lorsque de nombreuses clés se recoupent ; avec des clés longues et distinctes, un trie peut utiliser bien plus de mémoire qu'un ensemble haché, puisque chaque caractère devient son propre nœud avec des pointeurs enfants. Si l'espace est le souci, un arbre radix compressé fusionne les chaînes à enfant unique pour réduire cette surcharge.
Coddy programming languages illustration

Maîtrisez les algorithmes avec Coddy

COMMENCER