Algorithme d'Ukkonen

Cet article est une ébauche concernant l’informatique.

Vous pouvez partager vos connaissances en l’améliorant (comment ?) selon les recommandations des projets correspondants.

Algorithme d'Ukkonen
Construction de l'arbre des suffixes du mot b a o b a b {\displaystyle baobab}
Découvreur ou inventeur
Esko Ukkonen (en)Voir et modifier les données sur Wikidata
Date de découverte
1995
Problème lié
Recherche des suffixes dans une chaîne de caractères
Structure des données
arbre
Complexité en temps
Pire cas
O ( n log n ) {\displaystyle O(n\log n)}
Moyenne
O ( n ) {\displaystyle O(n)}

modifier - modifier le code - modifier WikidataDocumentation du modèle


En informatique, l'algorithme d'Ukkonen construit incrémentalement en temps linéaire l'arbre des suffixes d'un mot. Cet algorithme a été proposé par Esko Ukkonen (en) en 1995[1]. L'algorithme est essentiellement la linéarisation d'une version naïve quadratique d'un algorithme de construction de l’arbre des suffixes.

Principe

L'algorithme d'Ukkonen lit les caractères les l'un après l'autre, en faisant grossir la structure qu'il produit, de telle sorte que, à tout instant, l'arbre obtenu est l'arbre des suffixes du préfixe lu. Cette lecture des caractères du mot, qui progresse de gauche à droite, confère à l'algorithme d'Ukkonen son incrémentalité. Dans le premier algorithme de construction de l’arbre des suffixes, proposé par Peter Weiner, celui-ci lit le mot du dernier caractère au premier, produisant les arbres des suffixes, du plus petit suffixe du mot donné au plus grand suffixe du mot (c'est-à-dire le mot lui-même)[2]. Edward M. McCreight propose plus tard un algorithme plus simple, allant toujours de droite à gauche dans la lecture du mot[3]. Dans sa présentation, Esko Ukkonen propose d'abord sa version quadratique incrémentale de gauche à droite qu'il linéarise ensuite.

L'implémentation naïve de la construction d'un arbre de suffixes en lisant le mot du début à la fin requiert une complexité temporelle O (n2) voire O(n3) en notation de Landau, où n est la longueur de la chaîne. En exploitant un certain nombre de techniques algorithmiques, l'algorithme d'Ukkonen réduit ce temps à O(n) (linéaire), pour les alphabets de taille constante, et O(n log n) en général, correspondant aux performances d'exécution des deux précédents algorithmes.

Exemple

Explicitons l'exécution sur le mot b a o b a b {\displaystyle baobab} . L'algorithme part de l'arbre ne contenant qu'une racine. Lisons les lettres de b a o b a b {\displaystyle baobab} de gauche à droite.

Étape 1 : insertion de b {\displaystyle b} dans l'arbre.

Comme aucune arête partant de la racine n'est étiquetée par b {\displaystyle b} , on construit un nœud correspondant au suffixe b {\displaystyle b} . À ce stade, on a construit un arbre suffixe correspondant au mot b {\displaystyle b} dont le seul suffixe est b {\displaystyle b} .

Étape 2 : insertion de a {\displaystyle a} dans l'arbre.

À ce stade, le mot entier considéré est b a {\displaystyle ba} . Le suffixe b {\displaystyle b} devient b a {\displaystyle ba} et on ajoute le suffixe a {\displaystyle a} dans l'arbre.

À ce stade, le mot entier considéré est '"`UNIQ--postMath-00000010-QINU`"'. Le suffixe '"`UNIQ--postMath-00000011-QINU`"' devient '"`UNIQ--postMath-00000012-QINU`"' et on ajoute le suffixe '"`UNIQ--postMath-00000013-QINU`"' dans l'arbre.
À ce stade, le mot entier considéré est b a {\displaystyle ba} . Le suffixe b {\displaystyle b} devient b a {\displaystyle ba} et on ajoute le suffixe a {\displaystyle a} dans l'arbre.

Étape 3 : insertion de o {\displaystyle o} dans l'arbre.

À ce stade, le mot entier considéré est b a o {\displaystyle bao} . Comme précédemment, on met à jour les suffixes b a {\displaystyle ba} et a {\displaystyle a} qui deviennent respectivement b a o {\displaystyle bao} et a o {\displaystyle ao} puis on ajoute o {\displaystyle o} comme suffixe.

Étape 4 : insertion de b {\displaystyle b} dans l'arbre.

À ce stade, le mot entier considéré est b a o b {\displaystyle baob} . On met à jour les suffixes b a o {\displaystyle bao} , a o {\displaystyle ao} et o {\displaystyle o} qui deviennent respectivement b a o b {\displaystyle baob} , a o b {\displaystyle aob} et o b {\displaystyle ob} . En revanche, il n'est pas nécessaire d'insérer le suffixe b {\displaystyle b} qui est déjà présent dans l'arbre via l'arête b a o b {\displaystyle baob} . (on retient maintenant que les prochaines modifications vont avoir lieu sur l'arête b a o b {\displaystyle baob} , et que le plus long préfixe commun est b {\displaystyle b} . On garde ces informations).

Étape 5 : insertion de a {\displaystyle a} (mot considéré est b a o b a {\displaystyle baoba} ) :

L'arête courante est b a o b {\displaystyle baob} , dont b a {\displaystyle ba} est toujours le préfixe. Il suffit donc de mettre à jour les suffixes b a o b {\displaystyle baob} , a o b {\displaystyle aob} et o b {\displaystyle ob} qui deviennent b a o b a {\displaystyle baoba} , a o b a {\displaystyle aoba} et o b a {\displaystyle oba} . Le plus long préfixe commun devient b a {\displaystyle ba} .

Étape 6 insertion de b {\displaystyle b} (mot considéré est b a o b a b {\displaystyle baobab} ) :

Les suffixes b a o b a {\displaystyle baoba} , a o b a {\displaystyle aoba} et o b a {\displaystyle oba} deviennent b a o b a b {\displaystyle baobab} , a o b a b {\displaystyle aobab} et o b a b {\displaystyle obab} . En revanche, le suffixe b a b {\displaystyle bab} n'est plus préfixe de b a o b a b {\displaystyle baobab} . Il faut scinder l'arête b a o b a b {\displaystyle baobab} après b a {\displaystyle ba} qui est le plus long préfixe commun.

  • Étape 6.1 : on insère un nœud entre b a {\displaystyle ba} et o b a b {\displaystyle obab} , puis on rajoute une arête b {\displaystyle b} partant de ce nœud (on a introduit un branchement). On a ainsi ajouté les suffixes b a o b a b {\displaystyle baobab} et b a b {\displaystyle bab} dans l'arbre. Il reste à traiter les suffixes a b {\displaystyle ab} et b {\displaystyle b} .
  • Étape 6.2 : le suffixe a b {\displaystyle ab} a comme plus long préfixe commun a {\displaystyle a} avec l'arête a o b a b {\displaystyle aobab} . On sépare donc l'arête a o b a b {\displaystyle aobab} en insérant un nœud entre a {\displaystyle a} et o b a b {\displaystyle obab} . On ajoute également une arête b {\displaystyle b} partant de ce nœud
  • Étape 6.3 : le suffixe b {\displaystyle b} a comme plus long préfixe b {\displaystyle b} avec l'arête b a {\displaystyle ba} . On insère donc encore un nœud entre b {\displaystyle b} et a {\displaystyle a} sur l'arête b a {\displaystyle ba}

Articles connexes

  • Arbre des suffixes
  • Algorithme en ligne

Bibliographie

  1. (en) E. Ukkonen, « On-line construction of suffix trees », Algorithmica, vol. 14, no 3,‎ , p. 249–260 (DOI 10.1007/BF01206331, lire en ligne)
  2. (en) Peter Weiner, 14th Annual Symposium on Switching and Automata Theory (SWAT 1973), , 1–11 p. (DOI 10.1109/SWAT.1973.13), « Linear pattern matching algorithms »
  3. (en) Edward Meyers McCreight, « A Space-Economical Suffix Tree Construction Algorithm », Journal of the ACM, vol. 23, no 2,‎ , p. 262–272 (DOI 10.1145/321941.321946)

Liens externes

  • Explication détaillée en anglais
  • Recherche rapide de chaînes avec des arbres de suffixes Tutoriel de Mark Nelson. Présente un exemple d'implémentation écrit en C++.
  • Implémentation en C avec explication détaillée
  • Diapositives de la conférence de Guy Blelloch
  • Page d'accueil d'Ukkonen
  • Projet d'indexation de texte (construction en temps linéaire d'Ukkonen d'arbres de suffixes)
  • Implémentation en C Partie 1 Partie 2 Partie 3 Partie 4 Partie 5 Partie 6
  • icône décorative Portail de l'informatique théorique