Algorithmique et Programmation Impérative 2 Maximier – Tri arbre

publicité
Algorithmique et Programmation
Impérative 2
Maximier – Tri arbre
N.E. Oussous
[email protected]
FIL – USTL
API2 - LST«A» – p.1/33
Maximier - Définition
➻ Un arbre vide est considéré comme un maximier.
API2 - LST«A» – p.2/33
Maximier - Définition
➻ Un arbre vide est considéré comme un maximier.
➻ Un arbre binaire non vide est un maximier si et
seulement si
API2 - LST«A» – p.2/33
Maximier - Définition
➻ Un arbre vide est considéré comme un maximier.
➻ Un arbre binaire non vide est un maximier si et
seulement si
➠ sa racine porte la valeur maximale.
API2 - LST«A» – p.2/33
Maximier - Définition
➻ Un arbre vide est considéré comme un maximier.
➻ Un arbre binaire non vide est un maximier si et
seulement si
➠ sa racine porte la valeur maximale.
➠ ses 2 sous-arbres principaux sont des maximiers.
API2 - LST«A» – p.2/33
Maximier - Définition
➻ Un arbre vide est considéré comme un maximier.
➻ Un arbre binaire non vide est un maximier si et
seulement si
➠ sa racine porte la valeur maximale.
➠ ses 2 sous-arbres principaux sont des maximiers.
➻ À la racine des 2 sous-arbres principaux on trouve
donc les 2ème et 3ème valeurs selon l’ordre
décroissant.
API2 - LST«A» – p.2/33
Maximier - Définition
➻ Un arbre vide est considéré comme un maximier.
➻ Un arbre binaire non vide est un maximier si et
seulement si
➠ sa racine porte la valeur maximale.
➠ ses 2 sous-arbres principaux sont des maximiers.
➻ À la racine des 2 sous-arbres principaux on trouve
donc les 2ème et 3ème valeurs selon l’ordre
décroissant.
➻ On a un ordre partiel :
API2 - LST«A» – p.2/33
Maximier - Définition
➻ Un arbre vide est considéré comme un maximier.
➻ Un arbre binaire non vide est un maximier si et
seulement si
➠ sa racine porte la valeur maximale.
➠ ses 2 sous-arbres principaux sont des maximiers.
➻ À la racine des 2 sous-arbres principaux on trouve
donc les 2ème et 3ème valeurs selon l’ordre
décroissant.
➻ On a un ordre partiel :
➠ Le père est plus grand que ses deux fils.
API2 - LST«A» – p.2/33
Maximier - Définition
➻ Un arbre vide est considéré comme un maximier.
➻ Un arbre binaire non vide est un maximier si et
seulement si
➠ sa racine porte la valeur maximale.
➠ ses 2 sous-arbres principaux sont des maximiers.
➻ À la racine des 2 sous-arbres principaux on trouve
donc les 2ème et 3ème valeurs selon l’ordre
décroissant.
➻ On a un ordre partiel :
➠ Le père est plus grand que ses deux fils.
➠ Pas d’ordre entre les frères.
API2 - LST«A» – p.2/33
Maximier - Exemple
9
7
8
6
2
3
3
2
7
1
5
6
API2 - LST«A» – p.3/33
Maximier - Utilité
➻ La structure de maximier n’est pas utilisée pour
implémenter les primitives usuelles (recherche,
insertion, suppression) sur les ensembles.
API2 - LST«A» – p.4/33
Maximier - Utilité
➻ La structure de maximier n’est pas utilisée pour
implémenter les primitives usuelles (recherche,
insertion, suppression) sur les ensembles.
➻ Par exemple, la recherche d’une valeur particulière
peut amener à parcourir tout l’arbre (donc être en
Θ(n)).
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.
API2 - LST«A» – p.4/33
Maximier - Utilité
➻ La structure de maximier n’est pas utilisée pour
implémenter les primitives usuelles (recherche,
insertion, suppression) sur les ensembles.
➻ Par exemple, la recherche d’une valeur particulière
peut amener à parcourir tout l’arbre (donc être en
Θ(n)).
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.
➻ Un maximier est par contre utilisé pour extraire le
maximum parmi un ensemble de valeurs.
API2 - LST«A» – p.4/33
Maximier - Cueillette
La suppression de l’élément maximal est, par contre, plus
efficace.
➻ On remplace cet élément par le plus grand de ses
successeurs.
API2 - LST«A» – p.5/33
Maximier - Cueillette
La suppression de l’élément maximal est, par contre, plus
efficace.
➻ On remplace cet élément par le plus grand de ses
successeurs.
➻ On recommence l’opération avec le successeur utilisé.
API2 - LST«A» – p.5/33
Maximier - Cueillette
La suppression de l’élément maximal est, par contre, plus
efficace.
➻ On remplace cet élément par le plus grand de ses
successeurs.
➻ On recommence l’opération avec le successeur utilisé.
➻ On supprime la feuille utilisée en dernier.
API2 - LST«A» – p.5/33
Cueillette - Exemple
9
7
8
6
2
3
3
2
7
1
5
6
API2 - LST«A» – p.6/33
Cueillette - Exemple
8
7
8
6
2
3
3
2
7
1
5
6
API2 - LST«A» – p.6/33
Cueillette - Exemple
8
7
8
6
2
3
3
2
7
1
5
6
API2 - LST«A» – p.6/33
Cueillette - Exemple
8
7
7
6
2
3
3
2
7
1
5
6
API2 - LST«A» – p.6/33
Cueillette - Exemple
8
7
7
6
2
3
3
2
7
1
5
6
API2 - LST«A» – p.6/33
Cueillette - Exemple
8
7
7
6
2
6
3
3
2
1
5
6
API2 - LST«A» – p.6/33
Cueillette - Exemple
8
7
7
6
2
6
3
3
2
1
5
6
API2 - LST«A» – p.6/33
Cueillette - Exemple
8
7
7
6
2
6
3
3
2
5
1
API2 - LST«A» – p.6/33
Cueillette - Code
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
API2 - LST«A» – p.7/33
Pré-Maximier
➻ Un Pré-Maximier est un arbre dont les 2 sous-arbres
principaux sont des maximiers.
API2 - LST«A» – p.8/33
Pré-Maximier
➻ Un Pré-Maximier est un arbre dont les 2 sous-arbres
principaux sont des maximiers.
➻ Un pré-maximier n’est pas nécessairement un
maximier, cela dépend de la valeur portée à la racine.
API2 - LST«A» – p.8/33
Pré-Maximier
➻ Un Pré-Maximier est un arbre dont les 2 sous-arbres
principaux sont des maximiers.
➻ Un pré-maximier n’est pas nécessairement un
maximier, cela dépend de la valeur portée à la racine.
➻ La transformation en maximier (Réorganisation)
se fait par une méthode analogue à celle utilisée pour
la suppression du maximum.
API2 - LST«A» – p.8/33
Pré-Maximier → Maximier
➻ Si le pré-maximier n’est pas un maximier, il faut
API2 - LST«A» – p.9/33
Pré-Maximier → Maximier
➻ Si le pré-maximier n’est pas un maximier, il faut
➠ Échanger la valeur portée à la racine avec la valeur
maximale de ses successeurs,
API2 - LST«A» – p.9/33
Pré-Maximier → Maximier
➻ Si le pré-maximier n’est pas un maximier, il faut
➠ É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.
API2 - LST«A» – p.9/33
Pré-Maximier → Maximier
➻ Si le pré-maximier n’est pas un maximier, il faut
➠ É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.
➻ La réorganisation nécessite le parcours d’une seule
branche, avec un traitement en Θ(1) à chaque nœud
parcouru.
API2 - LST«A» – p.9/33
Réorganisation - Exemple
2
8
9
3
7
6
3
2
7
1
5
6
API2 - LST«A» – p.10/33
Réorganisation - Exemple
2
8
9
3
7
6
3
2
7
1
5
6
API2 - LST«A» – p.10/33
Réorganisation - Exemple
9
8
2
3
7
6
3
2
7
1
5
6
API2 - LST«A» – p.10/33
Réorganisation - Exemple
9
8
2
3
7
6
3
2
7
1
5
6
API2 - LST«A» – p.10/33
Réorganisation - Exemple
9
8
7
3
2
6
3
2
7
1
5
6
API2 - LST«A» – p.10/33
Réorganisation - Exemple
9
8
7
3
2
6
3
2
7
1
5
6
API2 - LST«A» – p.10/33
Réorganisation - Exemple
9
7
8
3
6
2
3
2
7
1
5
6
API2 - LST«A» – p.10/33
Réorganisation - Code
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 ;
API2 - LST«A» – p.11/33
Fabrication d’un maximier
➻ Un arbre binaire quelconque contient des maximiers :
toutes ses feuilles.
API2 - LST«A» – p.12/33
Fabrication d’un maximier
➻ Un arbre binaire quelconque contient des maximiers :
toutes ses feuilles.
➻ Les sous-arbres de hauteur 2 sont donc des
pré-maximiers.
API2 - LST«A» – p.12/33
Fabrication d’un maximier
➻ Un arbre binaire quelconque contient des maximiers :
toutes ses feuilles.
➻ Les sous-arbres de hauteur 2 sont donc des
pré-maximiers.
➻ Par réorganisations successives, on peut transformer
tous les sous-arbres de hauteur 2 en maximiers, puis
ceux de hauteur 3, etc. . .
API2 - LST«A» – p.12/33
Fabrication d’un maximier
➻ Un arbre binaire quelconque contient des maximiers :
toutes ses feuilles.
➻ Les sous-arbres de hauteur 2 sont donc des
pré-maximiers.
➻ Par réorganisations successives, on peut transformer
tous les sous-arbres de hauteur 2 en maximiers, puis
ceux de hauteur 3, etc. . .
➻ Il faudra donc parcourir les sous-arbres par hauteurs
croissantes (les sous-arbres les plus profonds en
premier).
API2 - LST«A» – p.12/33
Fabrication - Exemple
2
9
6
6
7
7
1
3
2
3
5
8
API2 - LST«A» – p.13/33
Fabrication - Exemple
2
9
6
6
7
1
3
2
7
3
5
8
API2 - LST«A» – p.13/33
Fabrication - Exemple
2
9
6
7
6
3
3
2
8
1
5
7
API2 - LST«A» – p.13/33
Fabrication - Exemple
2
9
6
7
6
3
3
2
8
1
5
7
API2 - LST«A» – p.13/33
Fabrication - Exemple
2
9
8
7
6
3
3
2
7
1
5
6
API2 - LST«A» – p.13/33
Fabrication - Exemple
2
9
8
7
6
7
3
3
2
1
5
6
API2 - LST«A» – p.13/33
Fabrication - Exemple
9
7
8
6
2
7
3
3
2
1
5
6
API2 - LST«A» – p.13/33
Fabrication - Code récursif
Cet algorithme s’exprime facilement de façon récursive
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
API2 - LST«A» – p.14/33
Fabrication - Code itératif
Cet algorithme peut aussi s’exprimer (informellement) de
façon itérative par
for h := 2 to hauteur(arbre) do begin
Réorganiser tous les sous-arbres de hauteur h ;
end; // for
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.
API2 - LST«A» – p.15/33
Tri-Arbre : Heapsort
L’utilisation des maximiers peut amener à une méthode de
tri appelée Tri-arbre ou Heapsort.
Description informelle de l’algorithme :
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
En pratique, cette méthode de tri est employée dans le
cas d’une implémentation d’arbre bien particulière : le tas.
API2 - LST«A» – p.16/33
La structure de Tas
➻ 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.
API2 - LST«A» – p.17/33
La structure de Tas
➻ 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.
➻ Elle consiste à ranger les valeurs portées par les nœuds
API2 - LST«A» – p.17/33
La structure de Tas
➻ 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.
➻ Elle consiste à ranger les valeurs portées par les nœuds
➠ par profondeur croissante
API2 - LST«A» – p.17/33
La structure de Tas
➻ 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.
➻ Elle consiste à ranger les valeurs portées par les nœuds
➠ par profondeur croissante
➠ de gauche à droite (pour une profondeur donnée).
API2 - LST«A» – p.17/33
La structure de Tas
➻ 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.
➻ Elle consiste à ranger les valeurs portées par les nœuds
➠ par profondeur croissante
➠ de gauche à droite (pour une profondeur donnée).
un arbre = un tableau
un curseur = un indice du tableau
un nœud = une case du tableau
API2 - LST«A» – p.17/33
Tas - Exemple
9
7
8
6
3
2
1
9
3
2
7
1
5
6
2
3
4
5
6
7
8
9
10
11
12
7
8
6
3
7
5
2
3
2
1
6
API2 - LST«A» – p.18/33
Tas dans 1 tableau d’indices 1..n
T(1)
T(2)
T(4)
T(8)
T(3)
T(5)
T(6)
T(7)
T(9) T(10) T(11) T(12)
Racine
Successeur gauche
Successeur droite
Prédecesseur
Est_Feuille
Possède 2 successeurs
Possède 1 seul successeur
Dernier nœud interne
1
2i
2i + 1
i
2
2i > n
2i < n
2i = n
n
2
API2 - LST«A» – p.19/33
Tas - Cas général
T[low(T)]
T[low(T)+1]
T[low(T)+3]
...
...
T[low(T)+2]
T[low(T)+4]
...
...
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)+5]
T[low(T)+6]
T[high(T)]
low(T )
2i − low(T ) + 1
2i − low(T ) + 2
1
(i + low(T ) − 1)
2
2i − low(T ) + 1 > high(T )
2i − low(T ) + 1 < high(T )
2i − low(T ) + 1 = high(T )
1
(high(T ) + low(T ) − 1)
2
API2 - LST«A» – p.20/33
La structure de Tas
➻ Les moins
API2 - LST«A» – p.21/33
La structure de Tas
➻ Les moins
➠ Les arbres auront une taille maximale, celle du
tableau.
API2 - LST«A» – p.21/33
La structure de Tas
➻ Les moins
➠ Les arbres auront une taille maximale, celle du
tableau.
➠ Un nœud est associé à une case (fixée) du tableau.
la suppression d’un nœud ou l’insertion d’un
nouveau nœud sont impossibles.
API2 - LST«A» – p.21/33
La structure de Tas
➻ Les moins
➠ Les arbres auront une taille maximale, celle du
tableau.
➠ Un nœud est associé à une case (fixée) du tableau.
➻ Les plus
API2 - LST«A» – p.21/33
La structure de Tas
➻ Les moins
➠ Les arbres auront une taille maximale, celle du
tableau.
➠ Un nœud est associé à une case (fixée) du tableau.
➻ Les plus
➠ Pas besoin de pointeurs.
API2 - LST«A» – p.21/33
La structure de Tas
➻ Les moins
➠ Les arbres auront une taille maximale, celle du
tableau.
➠ Un nœud est associé à une case (fixée) du tableau.
➻ Les plus
➠ Pas besoin de pointeurs.
➠ Le passage d’un nœud à ses successeurs se fait par
adressage calculé.
API2 - LST«A» – p.21/33
La structure de Tas
➻ Les moins
➠ Les arbres auront une taille maximale, celle du
tableau.
➠ Un nœud est associé à une case (fixée) du tableau.
➻ 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.
API2 - LST«A» – p.21/33
La structure de Tas
➻ Les moins
➠ Les arbres auront une taille maximale, celle du
tableau.
➠ Un nœud est associé à une case (fixée) du tableau.
➻ 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.
API2 - LST«A» – p.21/33
Réorganiser un Tas : Itératif
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
API2 - LST«A» – p.22/33
Réorganiser un Tas : Récursif
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
API2 - LST«A» – p.23/33
Réorganiser Tas : Complexité
➻ Le temps d’exécution de Reorganiser sur un
sous-arbre de taille n enraciné en un nœud i est la
somme du temps Θ(1) nécessaire pour corriger la
relation entre les éléments T[C], T[sag(C)] et
T[sad(C)], et le temps d’exécution de
Reorganiser sur un sous-arbre enraciné sur l’un
des deux fils du nœud i.
API2 - LST«A» – p.24/33
Réorganiser Tas : Complexité
➻ Le temps d’exécution de Reorganiser sur un
sous-arbre de taille n enraciné en un nœud i est la
somme du temps Θ(1) et le temps d’exécution de
Reorganiser sur un sous-arbre enraciné sur l’un
des deux fils du nœud i.
➻ Les sous-arbres des fils ont chacun une taille au plus
égale à 2n
3 . Car c’est un arbre binaire presque
complet.
API2 - LST«A» – p.24/33
Réorganiser Tas : Complexité
➻ Le temps d’exécution de Reorganiser sur un
sous-arbre de taille n enraciné en un nœud i est la
somme du temps Θ(1) et le temps d’exécution de
Reorganiser sur un sous-arbre enraciné sur l’un
des deux fils du nœud i.
➻ Les sous-arbres des fils ont chacun une taille au plus
égale à 2n
3 .
➻ Le pire des cas est atteint lorsque le dernier niveau est
rempli exactement à moitié.
API2 - LST«A» – p.24/33
Réorganiser Tas : Complexité
➻ On aboutit à la relation de récurrence suivante :
2n
+ Θ(1)
T (n) 6 T
3
API2 - LST«A» – p.25/33
Réorganiser Tas : Complexité
➻ On aboutit à la relation de récurrence suivante :
2n
+ Θ(1)
T (n) 6 T
3
➻ On est dans le cas 2 du théorème général avec
3
a = 1 b =
2
f (n) = Θ(1)
Ainsi nlogb a = n0 = 1 et f (n) = Θ(nlogb a )
API2 - LST«A» – p.25/33
Réorganiser Tas : Complexité
➻ On aboutit à la relation de récurrence suivante :
2n
+ Θ(1)
T (n) 6 T
3
➻ On est dans le cas 2 du théorème général avec
3
a = 1 b =
2
f (n) = Θ(1)
Ainsi nlogb a = n0 = 1 et f (n) = Θ(nlogb a )
➻ La solution est donc
T (n) = O(log2 n)
API2 - LST«A» – p.25/33
Fabriquer un Tas
➻ Les feuilles sont
n situées dans les dernières cases du
tableau : T[( 2 +1)..n]. En supposant que le
tableau est indicé de 1 à n.
➻ On parcourt les sous-arbres par hauteurs croissantes
en parcourant les cases du tableau en ordre inverse.
API2 - LST«A» – p.26/33
Fabriquer un Tas
➻ Les feuilles sont
n situées dans les dernières cases du
tableau : T[( 2 +1)..n].
➻ On parcourt les sous-arbres par hauteurs croissantes
en parcourant les cases du tableau en ordre inverse.
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;
Racine ≡ 1 et Dernier_arbre_h2 ≡ n2 .
API2 - LST«A» – p.26/33
Fabriquer un Tas
➻ Les feuilles sont
n situées dans les dernières cases du
tableau : T[( 2 +1)..n].
➻ On parcourt les sous-arbres par hauteurs croissantes
en parcourant les cases du tableau en ordre inverse.
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;
➻ Le temps d’exécution de Fabriquer_tas : Chaque appel à
Reorganiser coûte O(log2 n). Il existe O(n) appels de ce
type. Donc, le temps d’exécution est au plus O(n log n).
API2 - LST«A» – p.26/33
Exemple
➻ Soit le tableau suivant :
1
2
3
4
5
6
7
8
9
10
4
1
3
2
16
9
10
14
8
7
API2 - LST«A» – p.27/33
Exemple
➻ Soit le tableau suivant :
1
2
3
4
5
6
7
8
9
10
4
1
3
2
16
9
10
14
8
7
➻ Il lui correspond l’arbre suivant :
1
4
2
3
1
3
4
5
6
7
2
16
9
10
8
9
10
14
8
7
API2 - LST«A» – p.27/33
Exemple
1
4
2
3
1
3
4
2
i
8
9
10
14
8
7
5
6
7
16
9
10
API2 - LST«A» – p.28/33
Exemple
1
4
i
2
3
1
3
4
5
6
7
2
16
9
10
8
9
10
14
8
7
API2 - LST«A» – p.28/33
Exemple
1
4
2
3
1
i
3
4
5
6
7
14
16
9
10
8
9
10
2
8
7
API2 - LST«A» – p.28/33
Exemple
1
4
i
2
3
1
10
4
5
6
7
14
16
9
3
8
9
10
2
8
7
API2 - LST«A» – p.28/33
Exemple
1
i
4
2
3
16
10
4
5
6
7
14
7
9
3
8
9
10
2
8
1
API2 - LST«A» – p.28/33
Exemple
1
16
2
3
14
10
4
5
6
7
8
7
9
3
8
9
10
2
4
1
API2 - LST«A» – p.28/33
Fabriquer Tas : Complexité
➻ Une analyse plus fine est basée sur les propriétés des
tas :
API2 - LST«A» – p.29/33
Fabriquer Tas : Complexité
➻ Une analyse plus fine est basée sur les propriétés des
tas :
➠ La hauteur d’un tas à n éléments est h = ⌊log2 n⌋.
API2 - LST«A» – p.29/33
Fabriquer Tas : Complexité
➻ Une analyse plus fine est basée sur les propriétés des
tas :
➠ La hauteur d’un tas à n éléments est h = ⌊log2 n⌋.
➠ 1 sous-arbre de hauteur h, 2 sous-arbres de
hauteur h − 1, 4 sous-arbres de hauteur h − 2
API2 - LST«A» – p.29/33
Fabriquer Tas : Complexité
➻ Une analyse plus fine est basée sur les propriétés des
tas :
➠ La hauteur d’un tas à n éléments est h = ⌊log2 n⌋.
➠ 2h−i sous-arbres de hauteur i.
➻ Le temps de calcul de Reorganiser sur un nœud de
hauteur h est O(h).
API2 - LST«A» – p.29/33
Fabriquer Tas : Complexité
➻ Une analyse plus fine est basée sur les propriétés des
tas :
➠ La hauteur d’un tas à n éléments est h = ⌊log2 n⌋.
➠ 2h−i sous-arbres de hauteur i.
➻ Le temps de calcul de Reorganiser sur un nœud de
hauteur h est O(h).
➻ Le coût total pour Fabriquer_tas sera
!
h
h
X
X
i
h−i
h
2 · O(i) = O 2
T (n) =
i
2
i=0
i=0
API2 - LST«A» – p.29/33
Fabriquer Tas : Complexité
➻ On a l’égalité :
∞
X
1/2
i
=
= 2
i
2
2
(1 − 1/2)
i=0
Obtenue en remplaçant x par 1/2 et k par i dans la
formule :
∞
X
k=0
kx
k
x
=
(1 − x)2
API2 - LST«A» – p.30/33
Fabriquer Tas : Complexité
➻ On a l’égalité :
∞
X
1/2
i
=
= 2
i
2
2
(1 − 1/2)
i=0
➻ Donc, le temps d’exécution de Fabriquer_tas
peut être borné par

⌊log2 n⌋

X i
 = O n
O n
i
2
i=0
∞
X
i=0
i
2i
!
= O(n · 2) = O(n)
API2 - LST«A» – p.30/33
Fabriquer Tas : Complexité
➻ On a l’égalité :
∞
X
1/2
i
=
= 2
i
2
2
(1 − 1/2)
i=0
➻ Donc, le temps d’exécution de Fabriquer_tas
peut être borné par

⌊log2 n⌋

X i
 = O n
O n
i
2
i=0
∞
X
i=0
i
2i
!
= O(n · 2) = O(n)
➻ Ainsi, on peut construire un tas à partir d’un tableau
non ordonné en un temps linéaire.
API2 - LST«A» – p.30/33
Le tri par tas : Heapsort
➻ On construit un tas par Fabriquer_Tas à partir de
T[1..n], n=length(T).
API2 - LST«A» – p.31/33
Le tri par tas : Heapsort
➻ On construit un tas par Fabriquer_Tas à partir de
T[1..n], n=length(T).
➻ L’élément maximum de T se trouve à la racine T[1].
API2 - LST«A» – p.31/33
Le tri par tas : Heapsort
➻ On construit un tas par Fabriquer_Tas à partir de
T[1..n], n=length(T).
➻ L’élément maximum de T se trouve à la racine T[1].
➻ On le place à sa position finale en l’échangeant avec
T[n].
API2 - LST«A» – p.31/33
Le tri par tas : Heapsort
➻ On construit un tas par Fabriquer_Tas à partir de
T[1..n], n=length(T).
➻ L’élément maximum de T se trouve à la racine T[1].
➻ On le place à sa position finale en l’échangeant avec
T[n].
➻ On décrémente la taille du tableau en ne considérant
que le sous-tableau T[1..(n-1)].
API2 - LST«A» – p.31/33
Le tri par tas : Heapsort
➻ On construit un tas par Fabriquer_Tas à partir de
T[1..n], n=length(T).
➻ L’élément maximum de T se trouve à la racine T[1].
➻ On le place à sa position finale en l’échangeant avec
T[n].
➻ On décrémente la taille du tableau en ne considérant
que le sous-tableau T[1..(n-1)].
➻ 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.
API2 - LST«A» – p.31/33
Exemple
1
16
2
3
14
10
4
5
6
7
8
7
9
3
8
9
10
2
4
1
API2 - LST«A» – p.32/33
Exemple
1
1
2
3
14
10
4
5
6
7
8
7
9
3
8
9
10
2
4
16
i
API2 - LST«A» – p.32/33
Exemple
1
14
2
3
8
10
4
5
6
7
4
7
9
3
8
9
10
2
1
16
i
API2 - LST«A» – p.32/33
Exemple
1
1
2
3
8
10
4
5
6
7
4
7
9
3
8
9
2
14
10
i
16
API2 - LST«A» – p.32/33
Exemple
1
10
2
3
8
9
4
5
6
7
4
7
1
3
8
9
2
14
10
i
16
API2 - LST«A» – p.32/33
Exemple
1
2
8
10
i
2
3
8
9
4
5
6
7
4
7
1
3
9
10
14
16
API2 - LST«A» – p.32/33
Exemple
1
9
8
10
i
2
3
8
3
4
5
6
7
4
7
1
2
9
10
14
16
API2 - LST«A» – p.32/33
Exemple
1
8
2
3
7
3
4
5
6
7
4
2
1
9
8
9
10
10
14
16
i
API2 - LST«A» – p.32/33
Exemple
1
7
2
3
4
3
4
5
6
1
2
8
8
9
10
10
14
16
7
i
9
API2 - LST«A» – p.32/33
Exemple
1
4
2
3
2
3
4
5
1
7
8
9
10
10
14
16
i
6
7
8
9
API2 - LST«A» – p.32/33
Exemple
1
3
2
3
2
1
4
4
i
8
9
10
10
14
16
5
6
7
7
8
9
API2 - LST«A» – p.32/33
Exemple
1
2
2
3
1
3
i
4
5
6
7
4
7
8
9
8
9
10
10
14
16
API2 - LST«A» – p.32/33
Exemple
1
1
2
2
3
i
3
4
5
6
7
4
7
8
9
8
9
10
10
14
16
API2 - LST«A» – p.32/33
Exemple
1
1
2
2
3
i
3
4
5
6
7
4
7
8
9
8
9
10
10
14
16
1
2
3
4
5
6
7
8
9
10
1
2
3
4
7
8
9
10
14
16
API2 - LST«A» – p.32/33
Tri Tas : Code
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 ;
API2 - LST«A» – p.33/33
Tri Tas : Code
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 ;
➻ L’appel à Fabriquer_Tas prend un temps en O(n).
API2 - LST«A» – p.33/33
Tri Tas : Code
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 ;
➻ L’appel à Fabriquer_Tas prend un temps en O(n).
➻ Chacun des n − 1 appels à Reorganiser prend un
temps en O(log n).
API2 - LST«A» – p.33/33
Tri Tas : Code
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 ;
➻ L’appel à Fabriquer_Tas prend un temps en O(n).
➻ Chacun des n − 1 appels à Reorganiser prend un
temps en O(log n).
➻ La complexité de Tri_Tas est donc en O(n log n).
API2 - LST«A» – p.33/33
Téléchargement