Algorithmique: Les Arbres Binaires de Recherche

1. Arbres

Un arbre est un ensemble organisé de noeuds.

  • Chaque noeud a un père et un seul
  • Excepté un noeud, la racine qui n'a pas de père
  • Les fils d'un noeud p sont les noeuds dont le père est p
  • Les feuilles d'un arbre sont les noeuds qui n'ont pas de fils

2. Arbres : définition récursive

Les arbres sont des structures éminemment récursives.

Un arbre est constitué :

  • D'un noeud p sa racine
  • D'une suite de sous-arbres (a1, a2, ...., ak)
  • Les racines des arbres a1, a2, ...., ak sont les fils de p.

3. Arbres : vocabulaire

4. Arbres binaires

Une arbre binaire est un arbre dont chaque noeud a au plus deux fils : le fils gauche et le fils droit

 

5. Arbres : terminologie et définitions

Nous allons voir maintenant des opérations sur les arbres qui vont nous permettre de prendre diverses mesures afin de déterminer leur complexité.

 

La taille d'un arbre B correspond au nombre de noeuds. Elle est définie par:

T(B) = 0, si B est un arbre vide

T(B) = 1 + T(g(B)) + T(d(B)), sinon

6. Arbres : terminologie et définitions (2)

La hauteur ou profondeur est définie par :

H(x) = 0,  si x est la racine de B

H(x) = 1 + H(y),  si y est le père de x.

La hauteur ou profondeur d'un arbre B est définie par :

H(B) = max(H(x)),  avec x représentant les noeuds de B.

7. Arbres : terminologie et définitions (3)

La longueur de cheminement d'un arbre B est définie par :

 

LC(B) = ΣH(x) avec x représentant les noeuds de B

 

La profondeur moyenne d'un arbre B est définie par :

 

PM(B) = LC(B)/T(B)

 

Soit la longueur de cheminement divisée par la taille.

8. Arbres : terminologie et définitions (4)

Note : Des mesures comme la longueur de cheminement et la profondeur moyenne seront très utile pour déterminer la complexité des algorithmes appliqués aux arbres binaires.

 

 

9. Illustration avec un arbre exemple

Pour clarifier tout cela, nous allons prendre l'arbre de la figure ci-dessous et préciser ses caractéristiques et mesures.

Pour cela nous appellerons cet arbre B et conserverons la numérotation des nœuds de l'arbre, ce qui donne :

 

10. Illustration avec un arbre exemple (2)

- 1 est la racine de B, 2 est son fils gauche et 3 son fils droit
- les frères sont : (2,3), (4,5), (6,7), (9,10), (12,13)
- 1, 2, 3, 5 et 7 sont des points doubles de B
- 4 est un point simple à gauche de B
- 6, 8 et 9 est un point simple à droite de B
- 10, 11, 12, 13 et 14 et 15 sont des feuilles de B
- (1, 2, 4, 8) et (1, 3, 7, 13) sont les bords gauches et droits de B

11. Illustration avec un arbre exemple (3)

- Les hauteurs des noeuds de l'arbre B sont :
En 0 le noeud 1, en 1 les noeuds 2 et 3, en 2 les noeuds 4, 5, 6 et 7, en 3 les noeuds 8, 9, 10, 11, 12 et 13,
en 4 les noeuds 14 et 15
- la hauteur de l'arbre B est H(B)=4
- la taille de l'arbre B est T(B)=15
- Les longueurs de cheminement et profondeurs moyennes de l'arbre B sont :
LC(B)=36, PM(B)=36/15 = 2.4

12. Arbres binaires particulier

Leur spécificité permet de modifier les algorithmes sur les arbres, voire d’utiliser des algorithmes propres.

Les arbres complets voient tous leurs niveaux remplis.

Les arbres parfaits voient tous leurs niveaux remplis excepté le dernier qui est rempli de gauche à droite.

Les arbres dégénérés ne sont constitués que de points simples à gauche ou à droite.

13. Arbres binaires particulier (2)

Un arbre binaire complet :

  • A la profondeur p possède 2^p noeuds
  • A un nombre total de nœuds  :


Un arbre binaire de hauteur h contient donc au plus 2^h - 1 nœuds

14. Arbre binaire de recherche

Toute collection de n éléments dont les clés appartiennent à un ensemble ordonné peut être stockée et classée à l'intérieur d'un arbre binaire de recherche de  n noeuds.

Dans ce cas, les noeuds contiennent les éléments et les liens père-fils permettent de gérer l'ordre entre ces éléments.

 

Un Arbre Binaire de Recherche (ABR) est un arbre binaire étiqueté tel qu'en tout noeud v de l'arbre:

- les éléments du sous-arbre gauche de l'arbre de racine v sont inférieurs ou égaux à  v,

- les éléments du sous-arbre droit de l'arbre de racine v sont strictement supérieurs à v.

 

15. Arbre binaire de recherche

Il peut y avoir plusieurs ABRs représentant un même ensemble de données, comme le montre l'exemple suivant (cf. figure 1), pour l'ensemble d'entiers E = {6,8,10,11,14,16,18,30,33}.

 

16. ABR: Recherche d'un élément

- si B est un arbre vide, la recherche est négative
- si x est égal à l'élément de la racine de B, la recherche est positive
- si x est inférieur à l'élément de la racine de B, la recherche se poursuit sur le sous-arbre gauche de B
- si x est supérieur à l'élément de la racine de B, la recherche se poursuit sur le sous-arbre droit de B

 

17. ABR: Insertion d'un élément (1)

- Déterminer la place d'ajout en fonction de l'ordre
- Réaliser l'ajout de l'élément

 

18. ABR: Insertion d'un élément (2)

- Déterminer la place d'ajout en fonction de l'ordre
- Réaliser l'ajout de l'élément

 

19. ABR: Implémentation

On propose de modéliser en pseudo-code un arbre , comme une liste de nœuds, de la manière suivante :
Arbre = [

( etiquette 1, [ indice fils 1, indice fils 2, ..., indice fils n0 ] ),
( etiquette 2, [ indice fils 1, indice fils 2, ..., indice fils n1 ] ),
...
( etiquette n, [ indice fils 1, indice fils 2, ..., indice fils np ] )

]

Les nœuds d'arbres binaires n'ont que deux enfants. On pourra convenir d'un indice (par exemple -1) pour souligner l'absence de fils à gauche ou à droite.

 

20. ABR: Implémentation

Autrement dit :

  • Un nœud est représenté par un couple

 

  • Un arbre est représenté par une liste de couples contenant:

         - La valeur du noeud (étiquette ou clé)
         - La liste des indices des nœuds fils

 

 

21. ABR: Implémentation (exemple)

Par exemple, l'arbre suivant:

arbre_exemple = [(10, [1,2,3]),(20, [4,5,6]),(30, []),(40, []),(1, []),(2, []),(3,[7]),(4,[])]

On compte les indices à partir de 0. Puis on avance de 1 en 1 en progressant de haut en bas et à un même étage de gauche à droite.

Ainsi 10 est à l'indice 0, 20 à l'indice 1, 30 à l'indice 2 etc...

22. ABR: Implémentation Recherche

Voici un exemple d'implémentation de la fonction de recherche en pseudo-code. Nous allons le faire selon deux modes:

  • Iteratif
  • Récursif

 

Ces fonctions partent du principe que vous avez codé quatre fonctions:

gauche(Arbre, Noeud) -> Renvoie le fils gauche dans l'arbre nommé Arbre du nœud donné en paramètre.

droite(Arbre, Noeud) -> Renvoie le fils droit dans l'arbre Arbre du nœud donné en paramètre.

get_racine(Arbre) -> Renvoie la racine de l'arbre Arbre donné en paramètre.

cle(Noeud)-> Renvoie l'étiquette du nœud donné en paramètre.

Un noeud est représenté par un couple comme décrit précédemment.

23. ABR: Implémentation Recherche (2)

On utilise la représentation statique des arbres (à l'aide des tableaux), à ne pas confondre avec la représentation dynamique des arbres (à l'aide des classes).

 

Version récursive

fonction Rechercher(Arbre, noeud, x):
  si noeud == None ou x == cle(noeud):
  	retourner noeud
  sinon si x < cle(noeud):
  	retourner Rechercher(Arbre, gauche(Arbre, noeud), x)
  sinon
  	retourner Rechercher(Arbre, droite(Arbre, noeud), x)
  finsi
fin

24. ABR: Implémentation Recherche (2)

On utilise la représentation statique des arbres (à l'aide des tableaux), à ne pas confondre avec la représentation dynamique des arbres (à l'aide des classes).

 

Version itérative

fonction RechercherIteratif(Arbre, x):
  noeud = get_racine(Arbre)
  tantque noeud != None et x != cle(noeud):
    si x < cle(noeud)
    	noeud = gauche(Arbre, noeud)
    sinon
    	noeud = droite(Arbre, noeud)
    finsi
  fin tantque
  retourner noeud
fin

24. ABR: Implémentation Insérer (1)

La procédure Insérer prend deux paramètres : Arbre (l'arbre dans lequel on veut faire l'insertion) et e (l'élément à insérer).

La procédure décrite dans la page suivante est un algorithme qui illustre le fonctionnement de l'insertion dans un arbre binaire de recherche. Pour cela elle fait appel à deux valeurs.

  • L'une représente le nœud courant dont  la valeur va bifurquer à gauche ou à droite en fonction du résultat de la comparaison entre e et noeud.cle, jusqu'à ce qu'elle atteigne None.

 

  • L'autre qui représente le parent du nœud courant à chaque étape. Cet objet qui a un cran de retard sur le nœud courant s'appelle un pointeur de traîne.

 

 

24. ABR: Implémentation Inserer (2)

Version itérative

  procedure Inserer(Arbre, e):
	noeud_parent = None    # sky is the only limit
	noeud = get_racine(Arbre)
	tantque noeud != None:
		noeud_parent = noeud    # Le parent descend d'un "étage"
		si e < cle(noeud):
			noeud = gauche(noeud)    # L'enfant aussi
		sinon
			noeud = droite(noeud)    # L'enfant aussi
		finsi
	fintantque
    
	# Trouver le parent de e
	# C'est l'élément noeud_parent
	# Il faut lui dire qu'il a un nouvel enfant...
	# La question est... à gauche ou à droite ??
	# Tout dépend de la relation d'ordre de e vis-à-vis du noeud_parent !
    
	indice_parent = Arbre.index(noeud_parent)
	Arbre.ajouter( (e, []) )
	tok = Arbre[indice_parent][0]
 	si e < tok:
		Arbre[indice_parent] = (tok, [longueur(Arbre) - 1])
	sinon:
		Arbre[indice_parent] = (tok, [-1, longueur(Arbre) - 1])
	finsi
  finfonction
       
Made with Slides.com