Algorithmie PC 3 : Arbres corrigé 1 Arbres Maximier

publicité
Algorithmie
PC 3 : Arbres
corrigé
1
Arbres Maximier
On a vu en cours la définition et les possibles utilitées des arbres maximier. Par
définition, un arbre maximier est un arbre binaire tel que les clefs des fils d’un
noeud soient plus petites que la clef du noeud.
Cette définition implique en particulier que la clef de la racine soit la plus
grande.
Nous allons nous intéresser ici à l’implémentation la plus concise possible
d’un arbre maximier.
1.1
Codage d’arbre
1.1.1
La figure 1 montre 3 arbres binaires. Lequel de ces arbres est plein
ou complet ?
(a)
(b)
(c)
Figure 1: Trois arbres binaires
1
L’arbre (a) est un arbre ni plein (le niveau 3, qui n’est pas le dernier niveau
n’est pas rempli), ni complet (puisqu’il n’est pas plein).
L’arbre (b) est plein, car tous les niveaux excepté le dernier sont remplis. Il
n’est par contre pas complet, car tous les nœuds du dernier niveau ne sont pas
à gauche.
L’arbre (c) est plein et complet.
1.1.2
Soit A un arbre binaire complet planté. Quel est le nombre de nœuds
par niveaux ?
Au niveau 1 de l’arbre se trouve la racine et au niveau 2 ses deux fils. Les
deux fils ayant chacuns 2 fils, il y en a au maximum 4, etc. Un arbre binaire
complet a donc 2i−1 éléments par niveau, à part pour le dernier niveau.
1.1.3
Si on numérote les éléments d’un arbre complet planté de gauche à
droite et de haut en bas (la racine aura ainsi le numéro 1, son fils
de gauche le numéro 2, son fils de droite le numéro 3, etc), quel est
l’indice du père du nœud i ?
1
2
3
4
8
5
9
10
6
7
11
Figure 2: Code d’un arbres binaires
La figure 2 montre un tel code en action. Il est alors facile de se convaincre
que si le numéro d’un nœud est i, son père est en i/2 (on prend la partie entière
si i est impair).
De là, on voit aussi que les fils du nœud i sont en 2i et en 2i + 1.
Ce code est particulier au arbres binaires complets. En effet, si les niveaux
intermédiaires ne sont pas remplis et si les nœuds du dernier niveau ne sont pas
à gauche, ça ne marchera pas. On pourra essayer sur les arbres (a) et (b) de la
figure 1 pour s’en convaincre.
1.1.4
Conclure de ce qui prédède une façon simple, élégante et prenant très
peu de mémoire de coder un arbre binaire complet.
2
Il suffit d’utiliser un tableau de taille N où N est le nombre de nœuds.
L’indice de la racine est 1, et pour tout nœud d’indice i , les indices de ses fils
sont 2i et 2i + 1.
1.1.5
À quel arbre binaire complet correspond le tableau [S,U,G,A,T,A,S,S,L,L,E,R]
en utilisant le code précédent ?
L’arbre est présenté en figure 3.
1
S
2
3
U
G
4
5
6
7
A
T
A
S
S
L
L
E
R
8
9
10
11
12
Figure 3: Arbre correspondant à [S,U,G,A,T,A,S,S,L,L,E,R]
1.2
Manipulations d’arbres binaires complets
1.2.1
Proposez un algorithme permettant d’insérer un élément dans un
arbre maximier codé comme dans la partie précédente.
On commence par ajouter un élément à l’arbre binaire complet à la fin du
tableau. Si son père est plus petit que lui, on échange. Si après l’échange le
nouveau père est plus petit on échange encore, et ainsi de suite jusqu’à la racine.
Ces échanges à répétitions assurent le fait qu’à la fin la structure maximier est
respectée. Il faut cependant faire attention à ne pas dépasser la racine (une
sentinelle est placée).
L’algorithme 1 explicite cette méthode.
1.2.2
Même question pour le codage du remplacement de la clef de la racine.
Cela se fait de la façon opposée à l’insertion. On commence par remplacer
la valeur de la racine par la nouvelle valeure. Si la valeur de la nouvelle racine
est plus petite que la plus grande valeur de ses fils, on échange les valeurs. Si le
problème presiste, on continue les échanges de la même manière. Ces échanges
successifs assurent le fait à la fin de la procédure, la structure maximier est
respectée.
3
Algorithme 1 Insertion d’un élément dans un arbre maximier
Données
tab (les indices vont de 0 à n-1)
n
obj (l’objet à rajouter)
Début
tab[n]=obj
n = n+1
k = n+1
Tant que k>1 et tab[k/2-1] < tab[k-1] faire (Attention : dèpart à l’indice 0)
tempo=tab[k-1], tab[k-1] = tab[k/2-1], tab[k/2-1] = tempo
k = k/2
rendre tab
Fin
Il faut cependant faire attention à la fin du tableau ainsi qu’au cas où un
père ne possède qu’un seul fils.
L’algorithme 2 explicite cette méthode.
1.2.3
Enfin, codez une façon de supprimer la racine d’un arbre maximier.
La suppression d’un élément peut se faire très simplement (comme vu en
cours). Il suffit remplacer (en utilisant l’algorithme 2) la valeur de la racine par
la valeur du dernier élément du tableau.
2
Méthodes de recherche
Cette partie va s’atteler à savoir si un élément particulier se trouve dans un
ensemble d’éléments. On verra que la performance de la recherche dépend de
la structure utilisée pour stocker les éléments.
2.1
Recherche séquentielle
Ici, la structure pour stocker les éléments est un tableau. Tout nouvel
élément est placé en queue de tableau.
Quelle est la complexité de recherche d’un élément dans une telle
structure ? Et en moyenne ?
Ici, pour trouver un élément, il faut parcourir le tableau élément après
élément. Ainsi, en cas de recherche infructueuse, il faut comparer tous les
éléments du tableau à l’élément recherché : on a donc besoin de N comparaisons.
4
Algorithme 2 de la racine dans un arbre maximier
Données
tab (les indices vont de 0 à n-1)
n
obj (l’objet à rajouter)
Début
tab[0]=obj
k=1
Tant que k<=n/2 faire
decalage=0
Si 2k < N et tab[2k-1] < tab[(2k+1)-1] alors
decalage=1
Si tab[k-1] < tab[2k-1+decalage]
tempo=tab[k-1], tab[k-1] = tab[2k-1+decalage], tab[2k-1+decalage] = tempo
k = 2k+decalage
Sinon
k =n (sortie de boucle)
rendre tab
Fin
Dans le cas d’une recherche fructueuse, l’élément recherché peut être de
façon équiprobable dans toutes les cases du tableau (il a 1/N chance d’être en
position i, pour tout 1 ≤ i ≤ N ).
Ainsi, s’il est en position i, il y P
aura juste i comparaisons à effectuer. L’espérance
du nombre d’opération est alors 1≤i≤N ( N1 i) = N2+1
2.2
Recherche dichotomique
Ici, notre structure est un tableau trié. À chaque nouvel élément, on re-trie le
tableau.
2.2.1
Quel est la complexité d’un ajout ou d’une suppression d’élément ?
Il faut retrier à chaque fois le tableau. Comme on ne rajoute ou on ne
supprime qu’un élément, ceci revient à trouver où l’élément doit être placé ou
supprimer, puis à décaler tous les autres éléments.
De là, le fait de décaler les éléments revient – au pire – à tous les décaler et
donc amène à une complexité de N. En moyenne, comme l’élément à déplacer
peut être de façon équiprobable à toutes les positions du tableau, et comme si
le premier élément à décaler
en décaler N − i, le nombre
P est en 1position i, il faut
N +1
moyen de décalage est :
1≤i≤N ( N (N − i)) =
2 .
5
2.2.2
Quel est le coup d’une recherche ?
De façon dichotomique, on coupe successivement le tableau en 2 et on choisit
où regarder (puisque le tableau est trié, on sait a priori dans quelle partie du
tableau est l’élément recherché s’il est présent).
On a donc besoin de log2 (N) opération. En effet, à chaque étape on coupe
le tableau en 2 jusqu’à trouver le bon élément.
En effet, s’il y a 2 éléments une étape suffit, s’il y a au plus 4 éléments, 2
étapes suffisent, et ainsi de suite. Par là, trouver un élément parmi 2k peut se
faire en k étapes.
2.3
Arbres binaires de recherche
On utilise ici des arbres binaires de recherche stocker nos données.
Un arbre binaire de recherche est un arbre tel que pour tout nœud,
son sous arbre gauche ne contienne que des valeurs strictement plus
petites que sa propre valeur, et que son sous-arbre droit ne contienne
que des valeurs plus grande ou égale à sa valeur.
La figure 4 montre un Arbre binaire de recherche.
5
1
20
9
3
15
14
19
12
Figure 4: Un arbre binaire de recherche
Nous ne détaillerons pas ici les algorithmes d’insertion et de suppression mais leur complexité est la même :
• complexité maximale O(n),
• complexité moyenne O(log(n)).
Effecuter une recherche se fait depuis la racine et on parcours les nœuds (à
gauche si la valeur à chercher est inférieure à la valeur du nœud, à droite sinon)
jusqu’à arriver à la solution. L’insertion peut se faire selon le même principe, on
parcours l’arbre pour rechercher la valeur et on rajoute la valeur à la dernière
6
feuille visitée. Ainsi, si on veut rajouter la valeur 8 à l’arbre de la figure 4, on
parcours l’arbre de la façon suivante 5 ← 20 ← 9 et on insère 8 à gauche de 9.
Pour la suppression, c’est un petit peu plus technique. Certains nœuds sont
faciles à supprimer : ceux qui n’ont qu’au plus 1 fils. Pour ceux qui ont deux fils
(comme la racine), il suffit de prendre la valeur qui lui est strictement supérieure
(ici 9). Ce nœud ne peut posséder qu’un seul fils à droite (car entre la racine et
sa valeur strictmeent supérieure il n’y a personne dans l’arbre). On peut alors
échanger la valeur de la racine avec le nœud trouvé (ici 9) et de le supprimer.
Le résultat est présenté en figure 5
9
1
20
3
15
14
19
12
Figure 5: Un arbre binaire de recherche
2.4
Quel est le coup maximal et moyen d’une recherche ?
La hauteur d’un arbre de recherche peut être égale au nombre de données si
l’arbre est mal construit (des données triées par exemple), ainsi, au maximum
la recherche, la suppression ou l’insertion d’une donnée peut prendre un temps
en O(n).
Le temps moyen est donc égal à 1/N fois la longeur totale interne (la somme
de tous les chemins des nœuds qui ne sont pas des feuilles à la racine) moyenne
d’un arbre binaire de recherche.
La longeur totale moyenne d’un arbre binaire de recherche peut être trouvée
à partir de la formule de récurrence suivante :
X
C(N ) = N − 1 + 1/N
(C(i − 1) + C(N − i))
1≤i≤N
Et C(1)=1.
Le premier terme tient compte du fait que la racine contribue de 1 à la
longueur des chemins des N-1 autres éléments, et le deuxième terme précise la
longeur des sous-arbres à gauche et à droite de la racine. La racine à en effet
7
1/N chance d’être la i ième plus petite valeures et donc que son arbre gauche
contienne i éléments et son arbre droit N-i éléments.
Cette récurrence est presque identique à celle trouvée en PC2 pour le tri
rapide et peut être résolue de la même manière. On a alors C(N) =O(n log(n)).
On peut prouver que, de même que pour l’insertion ou la suppression, ce temps
moyen est en O(log(n)). Cette méthode est don plus efficace que la recherche
dichotomique et séquencielle.
8
Téléchargement