Structures de Données et Complexité Maximier – T ri Arbre

publicité
➻ Par exemple, la recherche d’une valeur particulière peut amener à
parcourir tout l’arbre (donc être en
).
Elle nécessite de plus la gestion d’une pile dont la hauteur est celle
de l’arbre lui-même.
Cette recherche serait donc inefficace.
➻ La structure de maximier n’est pas utilisée pour implémenter les
primitives usuelles (recherche, insertion, suppression) sur les
ensembles.
Maximier - Utilité
FIL – USTL
[email protected]
SDC - Licence – p.1/32
SDC - Licence – p.4/32
➻ Un maximier est par contre utilisé pour extraire le maximum parmi
un ensemble de valeurs.
2
6
3
7
2
3
1
9
6
7
8
5
2
6
3
7
2
➻ On supprime la feuille utilisée en dernier.
3
1
8
6
➻ On recommence l’opération avec le successeur utilisé.
7
SDC - Licence – p.5/32
5
➻ On remplace cet élément par le plus grand de ses successeurs.
La suppression de l’élément maximal est, par contre, plus efficace.
Maximier - Cueillette
➻ On a un ordre partiel :
➠ Le père est plus grand que ses deux fils.
➠ Pas d’ordre entre les frères.
SDC - Licence – p.2/32
➻ À la racine des sous-arbres principaux on trouve donc les ème et
ème valeurs selon l’ordre décroissant.
Maximier – Tri Arbre
N.E. Oussous
➻ Un arbre binaire non vide est un maximier si et seulement si
➠ sa racine porte la valeur maximale.
➠ ses sous-arbres principaux sont des maximiers.
➻ Un arbre vide est considéré comme un maximier.
Maximier - Définition
Structures de Données
et Complexité
3
1
6
7
Cueillette - Code
2
3
8
SDC - Licence – p.3/32
5
SDC - Licence – p.6/32
procedure Supprimer_Max(var T : Maximier) ;
X : Curseur ;
Begin
X := Racine(T) ;
While not Est_Feuille(X) Do Begin
Determiner quel successeur possède
la valeur maximale ;
Recopier cette valeur;
Descendre X du coté où se trouvait
la valeur maximale ;
end ; // while
Supprimer(X);
End ; // Supprimer_Max
2
6
7
9
Maximier - Exemple
➻ Par réorganisations successives, on peut transformer tous les
sous-arbres de hauteur en maximiers, puis ceux de hauteur , etc
➻ Les sous-arbres de hauteur sont donc des pré-maximiers.
SDC - Licence – p.11/32
➻ Il faudra donc parcourir les sous-arbres par hauteurs croissantes (les
sous-arbres les plus profonds en premier).
SDC - Licence – p.10/32
Fabrication d’un maximier
➻ Un arbre binaire quelconque contient des maximiers : toutes ses
feuilles.
SDC - Licence – p.8/32
➻ La réorganisation nécessite le parcours d’une seule branche, avec un
à chaque nœud parcouru.
traitement en
➠ Échanger la valeur portée à la racine avec la valeur maximale de
ses successeurs,
➠ Réorganiser le successeur avec lequel a eu lieu l’échange.
Réorganisation - Code
Maximier
➻ Si le pré-maximier n’est pas un maximier, il faut
Pré-Maximier
procedure Reorganiser(var T : Maximier) ;
X : Curseur ;
Begin
X := Racine(T) ;
Repeat
if not Est_Vide(sag(X)) then begin
G := X; G := sag(G) ;
if not Est_Vide(sad(X)) then begin
D := X; D := sad(D) ;
if Valeur(D) > Valeur(G) and Valeur(D) > Valeur(X) then begin
Changer_Valeur(X, Valeur(D)); X := D;
end else
if Valeur(G) > Valeur(D) and Valeur(G) > Valeur(X) then begin
Changer_Valeur(X, Valeur(G)); X := G;
end else exit;
end else begin
Changer_Valeur(X, Valeur(G)); X := G;
end;
end else
if not Est_Vide(sad(X)) then begin
Changer_Valeur(X, Valeur(D)); X := D;
end else exit;
until false ; // Repeat
End ;
SDC - Licence – p.7/32
➻ La transformation en maximier (Réorganisation) se fait par
une méthode analogue à celle utilisée pour la suppression du
maximum.
➻ Un pré-maximier n’est pas nécessairement un maximier, cela
dépend de la valeur portée à la racine.
➻ Un Pré-Maximier est un arbre dont les sous-arbres principaux sont
des maximiers.
Pré-Maximier
7
6
6
7
3
3
9
9
2
2
1
3
3
1
2
2
5
2
6
3
7
2
3
1
6
8
7
6
5
2
6
3
7
2
3
1
9
6
Fabrication - Exemple
6
7
8
9
7
7
Réorganisation - Exemple
8
8
SDC - Licence – p.12/32
5
SDC - Licence – p.9/32
5
La structure de Tas
un arbre = un tableau
un curseur = un indice du tableau
un nœud = une case du tableau
➻ Elle consiste à ranger les valeurs portées par les nœuds
➠ par profondeur croissante
➠ de gauche à droite (pour une profondeur donnée).
SDC - Licence – p.16/32
➻ La structure de tas permet de représenter, dans un tableau, un arbre
quasi-équilibré, dont les feuilles à profondeur maximale sont situées
le plus à gauche possible.
SDC - Licence – p.13/32
procedure Fabriquer_maximier(C : Curseur)
Begin
if not Est_Vide(sag(X)) then begin
G := X; G := sag(G) ;
Fabriquer_maximier(G) ;
end; // if
if not Est_Vide(sad(X)) then begin
D := X; D := sad(D) ;
Fabriquer_maximier(D);
end; // if
// on a maintenant un pré-maximier
Reorganiser(C);
End ; // Fabriquer_maximier
Cet algorithme s’exprime facilement de façon récursive
Fabrication - Code récursif
7
9
2
8
3
9
2
10
1
11
6
12
SDC - Licence – p.17/32
T(7)
5
7
Racine
Successeur gauche
Successeur droite
Prédecesseur
Est_Feuille
Possède 2 successeurs
Possède 1 seul successeur
Dernier nœud interne
7
6
T(6)
T(9) T(10) T(11) T(12)
T(5)
3
5
6
T(8)
T(4)
T(3)
6
4
1
5
T(2)
T(1)
8
3
2
7
SDC - Licence – p.15/32
SDC - Licence – p.18/32
Tas dans 1 tableau d’indices 1..n
2
3
3
8
SDC - Licence – p.14/32
En pratique, cette méthode de tri est employée dans le
cas d’une implémentation d’arbre bien particulière : le tas.
Tri_Arbre(var T : Tableau)
Begin
Constituer un arbre contenant les valeurs de T;
Fabriquer un maximier à partir de cet arbre;
for i:=low(T) to high(T) do begin
Ranger le maximum dans T[i] ;
Retirer le maximum de l’arbre ;
end; // for
End ; // Tri_Arbre
Description informelle de l’algorithme :
L’utilisation des maximiers peut amener à une méthode de tri appelée
Tri-arbre ou Heapsort.
Tri-Arbre : Heapsort
1
2
6
7
9
Tas - Exemple
Mais l’interface d’arbre proposée jusqu’ici ne permet
pas d’implémenter aisément cette version itérative,
faute de moyen efficace pour parcourir tous les
sous-arbres d’une hauteur donnée.
for h := 2 to hauteur(arbre) do begin
Réorganiser tous les sous-arbres de hauteur h ;
end; // for
Cet algorithme peut aussi s’exprimer (informellement) de façon itérative
par
Fabrication - Code itératif
...
T[low(T)+1]
...
...
T[low(T)+4]
T[high(T)]
T[low(T)+5]
T[low(T)+2]
T[low(T)+6]
Reorganiser(T, C)
g : Curseur ;
d : Curseur ;
Begin
g := sag(C) ;
d := sad(C) ;
// on détermine max(T[C], T[g], T[d])
if g <= high(T) and T[g] > T[C] then
max := g
else
max := C ;
if d <= high(T) and T[d] > T[max] then max := d ;
if max <> C then begin // c’est un pré-maximier
Echanger(T[C], T[max]) ;
Reorganiser(T, max) ;
end; // if
End; // Reorganiser
SDC - Licence – p.22/32
SDC - Licence – p.19/32
Réorganiser un Tas : Récursif
Racine
Successeur gauche
Successeur droite
Prédecesseur
Est_Feuille
Possède 2 successeurs
Possède 1 seul successeur
Dernier nœud interne
...
T[low(T)+3]
T[low(T)]
Tas - Cas général
Réorganiser Tas : Complexité
! # $% &
"
( # $% &
' ➻ La solution est donc
et
"
Ainsi
SDC - Licence – p.23/32
➻ On est dans le cas 2 du théorème général avec
➻ Le pire des cas est atteint lorsque le dernier niveau est rempli
exactement à moitié.
➻ Les sous-arbres des fils ont chacun une taille au plus égale à
Réorganiser Tas : Complexité
➻ On aboutit à la relation de récurrence suivante :
SDC - Licence – p.24/32
SDC - Licence – p.21/32
procedure Reorganiser( C : Curseur ) ;
I : Curseur ;
begin
I := C ;
repeat
if Possede_2_Successeurs(I) then begin
if T[sag(I)] > T[sad(I)] and T[sag(I)] > T[I] then begin
Echanger(T[I],T[sag(I)]);
I := sag(I);
end else
if T[sad(I)] > T[sag(I)] and T[sad(I)] > T[I] then begin
Echanger(T[I],T[sad(I)]);
I := sad(I);
end else // T[I] est la plus grande des 3 valeurs
exit;
end else
if Possede_1_Seul_Successeur(I) and T[sag(I)]>T[I] then begin
Echanger(T[I],T[sag(I)]);
exit;
end else exit;
Until false ;
end; // Reorganiser
Réorganiser un Tas : Itératif
.
➻ Le temps d’exécution de Reorganiser sur un sous-arbre de taille
enraciné en un nœud i est la somme du temps
et le temps
d’exécution de Reorganiser sur un sous-arbre enraciné sur l’un
des deux fils du nœud i.
SDC - Licence – p.20/32
➻ Les plus
➠ Pas besoin de pointeurs.
➠ Le passage d’un nœud à ses successeurs se fait par adressage
calculé.
➠ Possibilité de calculer également l’emplacement du
prédécesseur.
➠ Possibilité de parcourir l’arbre de bas en haut.
➻ Les moins
➠ Les arbres auront une taille maximale, celle du tableau.
➠ Un nœud est associé à une case (fixée) du tableau.
La structure de Tas
'
, * +
)
Fabriquer un Tas
➻ Les feuilles sont situées dans les dernières cases du tableau :
T[(
+1)..n].
-
.
➻ Le temps d’exécution de Fabriquer_tas : Chaque appel à
Reorganiser coûte
. Il existe
appels de ce
type. Donc, le temps d’exécution est au plus
.
procedure Fabriquer_Tas(var T : Arbre) ;
begin
for i:=Dernier_arbre_h2 downto Racine do begin
Reorganiser(i); // Reorganiser(T,i)
end;
end Fabriquer_Tas;
➻ On parcourt les sous-arbres par hauteurs croissantes en parcourant
les cases du tableau en ordre inverse.
)
, * +
)
* +
)
➻ Une analyse plus fine est basée sur les propriétés des tas :
➠ La hauteur d’un tas à éléments est
.
➠
sous-arbres de hauteur .
Fabriquer Tas : Complexité
,
SDC - Licence – p.25/32
8
9
8
7
10
5
16
10
7
6
9
14
8
3
7
8
3
10
9
7
10
: 3
0
, /* +
1 2
(
5
SDC - Licence – p.26/32
➻ Donc, le temps d’exécution de Fabriquer_tas peut être borné
par
➻ On a l’égalité :
Fabriquer Tas : Complexité
14
4
2
2
1
4
)
9
SDC - Licence – p.28/32
9
16
1
6
5
➻ Le coût total pour Fabriquer_tas sera
2
est
3
4
➻ Le temps de calcul de Reorganiser sur un nœud de hauteur
.
1
4
3
➻ Il lui correspond l’arbre suivant :
2
1
➻ Soit le tableau suivant :
Exemple
;
;
)
)
9
8
A
1
3
1
143
6
: 3
B>C
? # $% @
3
<> =
)
(
8
5
)
)
76
1 2
(
5
(
5
)
(
5
SDC - Licence – p.29/32
➻ Ainsi, on peut construire un tas à partir d’un tableau non ordonné en
un temps linéaire.
8
10
6
7
7
10
10
1
9
4
8
2
5
7
4
8
6
9
Le tri par tas : Heapsort
9
3
10
2
14
7
SDC - Licence – p.27/32
3
SDC - Licence – p.30/32
➻ On transforme T[1..(n-1)] en tas puisque les fils de la racine
restent des tas. Il y aura éventuellement à descendre la nouvelle
racine à sa place.
➻ On décrémente la taille du tableau en ne considérant que le
sous-tableau T[1..(n-1)].
➻ On le place à sa position finale en l’échangeant avec T[n].
➻ L’élément maximum de T se trouve à la racine T[1].
➻ On construit un tas par Fabriquer_Tas à partir de T[1..n],
n=length(T).
9
8
14
5
16
3
2
3
1
1
16
4
2
4
Exemple
1
7
5
8
6
9
7
8
10
9
14
SDC - Licence – p.31/32
16
10
➻ La complexité de Tri_Tas est donc en
,
4
* +
)
4
.
.
SDC - Licence – p.32/32
appels à Reorganiser prend un temps en
3
3
2
➻ Chacun des
.
➻ L’appel à Fabriquer_Tas prend un temps en
2
9
1
16
8
7
Tri_Tas(T)
Begin
Fabriquer_Tas(T) ;
n := Length(T) ;
for i:=n downto 2 do begin
Echanger(T[1], T[i]) ;
Reorganiser(T[1..n-1], 1) ;
end;
End ;
Tri Tas : Code
)
1
14
10
10
7
9
4
8
6
3
5
i
2
4
3
2
1
1
Exemple
* +
,
)
Téléchargement