x - imagine

publicité
Renaud Marlet – ENPC MOPSI 2013-2014
1
ENPC – MOPSI
Petit arboretum
e
(1 partie)
Renaud Marlet
Laboratoire LIGM-IMAGINE
http://imagine.enpc.fr/~marletr
Renaud Marlet – ENPC MOPSI 2013-2014
Les arbres : en informatique et ailleurs...
Structure de donnée omniprésente
−
représentation d'une hiérarchie d'objets
■
−
décomposition organisationnelle
arbres de décision
■
simulation
−
recherche d'information
−
compression
−
routage
−
...
2
Renaud Marlet – ENPC MOPSI 2013-2014
3
Exemple : expression arithmétique
2
2
a +b +2ab cos ϕ
(2 × (­(3))) + (((4 × 5) + 6) / (9 ­ 7))
+
+
×
÷
a
2
­
+
^
+
2
­
b
×
3
4
6
5
×
^
9
2
×
2
7
texte d'une expression :
structure d'arbre implicite (conventionnelle)
×
a
b
cos
φ
Renaud Marlet – ENPC MOPSI 2013-2014
4
Exemple : programme
for
=
i
<
0
i
++
5
;
i
if
>
for (i = 0; i < 5; i++)
{
if (x < i)
x += i%2;
f(3*x+i);
}
x
call
+=
i
x
{}
f
i
%
x
i
+
*
3
i
i
2
i
3
i
x
-
x
Renaud Marlet – ENPC MOPSI 2013-2014
5
Structure, vocabulaire, représentation
Représentation tête en bas
racine
branche
nœud
feuille
sous-arbre
Renaud Marlet – ENPC MOPSI 2013-2014
6
Structure, vocabulaire, représentation
Représentation tête en bas
racine
branche
nœud
feuille
sous-arbre
Renaud Marlet – ENPC MOPSI 2013-2014
7
Orientation et identification des branches
Nœud père et nœuds fils
racine
variante : les fils connaissent
aussi leur père
branche
nœud père
branche 1
nœud fils 1
2
2
variante (plus rare) : les père ne
connaissent pas leurs fils
feuille
(nœud terminal)
sous-arbre
Renaud Marlet – ENPC MOPSI 2013-2014
8
Informations accrochées sur l'arbre
Sur les nœuds (parfois feuilles seules) et/ou branches
N.B. formulations équivalentes sauf à la racine
1
12
12
4
2
2
6
6
3
3
5
5
8
8
4
10
12
10 12
1
42
42
1
Renaud Marlet – ENPC MOPSI 2013-2014
9
Feuilles & nœuds (non-)terminaux
Opérateurs n-aires sans fils vs feuille terminale
()
()
8
4
()
()
3
nœud
terminal
()
()
42
()
1
nœud
non-terminal
sans fils
((8 (3)) 4 (((42) () 1)))
ou
[[8, [3]], 4, [[[42], [], 1]]]
Renaud Marlet – ENPC MOPSI 2013-2014
10
Exemple : (dé)composition géométrique
Géométrie de construction de solides (constructive solid geometry, CSG)
Sur un nœud non feuille :
une opération de composition
(union, intersection, différence...)
Sur une feuille :
un objet géométrique
élémentaire
(cube, sphère, cylindre...)
Renaud Marlet – ENPC MOPSI 2013-2014
Exemple : représentation compacte
d'une image Noir & Blanc
info N/B : seulement sur les feuilles, pas sur les nœuds intermédiaires
11
Renaud Marlet – ENPC MOPSI 2013-2014
12
Arbre explicite vs implicite
●
●
Arbre explicite (finalité)
−
créé intentionnellement
−
opérations :
■
modifications : ajouter, retirer, déplacer...
■
parcours : recherche d'info, énumération...
■
calcul : combinaisons des infos sur les nœuds...
Arbre implicite (support)
−
hébergement de données
−
modif. des données → modif. automatique de l'arbre
Renaud Marlet – ENPC MOPSI 2013-2014
13
Parcours d'un arbre
1
2
3
1
6
7
4
5
2
8
9
11
5
12
10
En profondeur d'abord (depth first)
[DFS = depth-first search]
3
4
6
8
7
9
10
11
12
En largeur d'abord (breadth first)
[BFS = breadth-first search]
Renaud Marlet – ENPC MOPSI 2013-2014
14
Parcours d'un arbre
1
2
3
1
6
7
4
5
2
8
9
11
5
12
3
4
6
8
10
7
9
10
11
12
En profondeur d'abord (depth first)
En largeur d'abord (breadth first)
Comment cela s'implémente-t-il ?
Renaud Marlet – ENPC MOPSI 2013-2014
15
Parcours en profondeur d'abord
Algorithme :
1
2
3
6
7
4
5
profDabord(nœud)
−
8
9
11
pour chaque nœud fils,
profDabord(nœud fils)
12
10
N.B. programme récursif !
Renaud Marlet – ENPC MOPSI 2013-2014
16
Parcours en largeur d'abord
Algorithme :
1
2
5
3
4
6
8
largeurDabord(noeud)
7
9
12
10
11
−
créer une file
−
mettre la racine en tête de file
−
tant que la file n'est pas vide
■
prendre le nœud en tête de file
■
mettre les fils du nœud dans la file
Renaud Marlet – ENPC MOPSI 2013-2014
17
Opérations en descendant vs en montant
En profondeur d'abord
1
2
3
12
6
7
4
5
4
8
9
11
1
12
5
11
3
2
10
7
8
9
10
6
Opération sur les nœuds
en descendant
Opération sur les nœuds
en montant
Renaud Marlet – ENPC MOPSI 2013-2014
18
Attributs hérités, attributs synthétisés
0
1
2
0
3
1
2
3
information héritée :
information sur un nœud fils
dépendant de
l'information sur le nœud père
information synthétisée :
information sur le nœud père
dépendant de
l'information sur les nœuds fils
infoi = fi(info0)
info0 = f (info1 , info2 , info3)
Renaud Marlet – ENPC MOPSI 2013-2014
19
Structure de données
cf. cours correspondant
●
Création
■
■
●
nœud / arbre
constructeur
−
−
avec info initiale
ou valeur par défaut
■
■
sous-arbre (recursive)
nœud
18
−
4
29
10
23
les fils d'un nœud
les nœuds d'un arbre
un fils (sous-arbre)
 nouvelle branche
−
à une position ou
un rang donné
0
1
ajouter/supprimer
■
?
lecture, écriture
parcourir (ex. itérateur)
■
Destruction
■
accéder à l'info d'un nœud
■
−
x
●
Opérations :
2
36
51
12
17
24
8
9
Renaud Marlet – ENPC MOPSI 2013-2014
20
Exemple d'interface
// Node of a tree containing an integer at each node
class IntTree {
// Node information
int data;
// Node sons
??? quelle structure de données sous-jacente utiliser ??? sons;
public:
// Create a node with given information
IntTree(int d);
// Return node information
int getData();
// Set node information
void setData(int d);
// Return the number of sons of this node
int nbSons();
// Return the son at position pos (left-most at position 0)
IntTree* getSon(int pos);
// Set the son at position pos (left-most at position 0)
void setSon(int pos, IntTree* tree);
// Add argument as supplementary right-most son
void addAsLastSon(IntTree* tree);
// Remove right-most son
void removeLastSon();
};
pos = 0
15
42
1
6
2
8
Renaud Marlet – ENPC MOPSI 2013-2014
21
Exemple d'interface
// Node of a tree containing an integer at each node
class IntTree {
// Node information
int data;
// Node sons
vector<IntTree*> sons;
public:
// Create a node with given information
IntTree
IntTree(int d);
// Return node information
int getData();
// Set node information
15
data
void setData(int d);
sons
// Return the number of sons of this node
int nbSons();
// Return the son at position pos (left-most at position 0)
IntTree* getSon(int pos);
// Set the son at position pos (left-most at position 0)
void setSon(int pos, IntTree* tree);
// Add argument as supplementary right-most son
void addAsLastSon(IntTree* tree);
// Remove right-most son
void removeLastSon();
};
pos = 0
15
data
42
1
2
6
8
42
sons
data
sons
6
data
8
sons
opérations déjà
+/- disponibles dans
la classe vector <T>
Renaud Marlet – ENPC MOPSI 2013-2014
22
Exercice 1
1) Définissez les méthodes de IntTree (≈ 1 ligne par fonction)
2) Construisez l'arbre ci-contre dans une variable
root
IntTree* root = new IntTree(12);
root->addAsLastSon(new IntTree(8));
root->getSon(0)->addAsLastSon(new IntTree(4)); …
3) Ajoutez une méthode d'affichage récursive
void display(string prefix = "",
string indent = " ")
telle que root->display("* ") affiche :
* 12
*
8
*
4
*
9
*
23
*
17
*
15
prefix : au début de chaque
ligne (pour chaque nœud)
indent : ajouté pour chaque
niveau de profondeur
12
8
4
23
9
17
15
Renaud Marlet – ENPC MOPSI 2013-2014
23
Exercice 1 (suite)
4) Ajoutez dans IntTree les fonctions suivantes (≈ 1 ligne) :
void addSon(int pos, IntTree* tree);
void removeSon(int pos);
5) Rendez robustes les fonctions de IntTree :
− testez la validité des arguments et levez des exceptions
− utilisez pour ça les exceptions de #include <stdexcept>
6) Rendez IntTree générique pour le type des données :
− faites une classe Tree<T> qui prend le type en argument
7) Rendez un programme qui illustre chaque point précédent
avec des opérations (y compris erronées) sur l'arbre root
et des affichages correspondants via root->display()
Renaud Marlet – ENPC MOPSI 2013-2014
24
Exercice 2
1) Construisez un arbre et affichez sur une ligne la liste
des informations portées par chacun de ses nœuds,
avec les trois manières suivantes :
a) parcourez-le en profondeur d'abord en affichant
la donnée de chaque nœud en descendant
b)parcourez-le en profondeur d'abord en affichant
la donnée de chaque nœud en montant
c) parcourez-le en largeur d'abord en affichant
la donnée de chaque nœud
Renaud Marlet – ENPC MOPSI 2013-2014
25
Exercice 2 (suite)
2) Définissez une fonction int maxDepth()
− qui calcule rapidement la profondeur maximale d'un arbre
(= profondeur de la feuille la plus profonde)
− mieux vaut-il utilisez un parcours en profondeur d'abord
ou en largeur d'abord — pourquoi ?
3) Définissez une fonction int minDepth()
− qui calcule rapidement la profondeur minimale d'un arbre
(= profondeur de la feuille la moins profonde)
− mieux vaut-il utilisez un parcours en profondeur d'abord
ou en largeur d'abord — pourquoi ?
4) Rendez un programme qui illustre ces deux fontions
Renaud Marlet – ENPC MOPSI 2013-2014
26
Arbre binaire
●
Tout nœud a au plus deux fils :
−
●
●
fils gauche, fils droit
Variante : pour tout nœud
−
0 fils (feuille), ou bien
−
exactement 2 fils
Cas dégénéré : peigne
(gauche ou droit)
Renaud Marlet – ENPC MOPSI 2013-2014
27
Arbre binaire de recherche
●
Représente un ensemble ordonné
●
Info sur nœud nommé « clé »
●
Propriété (pour tout nœud) :
●
−
clés sur fils gauche ≤ clé du père
−
clés sur fils droit ≥ clé du père
12
8
4
23
9
6
17
15
20
Recherche ≈ par dichotomie
−
descente dans le sous-arbre qui contient la clé
−
O(log n) en moyenne pour n nœuds
−
O(n) dans le pire cas (peigne)
16
Renaud Marlet – ENPC MOPSI 2013-2014
28
Insertion dans un
arbre binaire de recherche
●
Comment faire ?
−
ex. insérer 10
−
ex. insérer 18
12
8
4
9
6
●
Quelle est la complexité ?
23
17
15
20
16
Renaud Marlet – ENPC MOPSI 2013-2014
29
Insertion dans un
arbre binaire de recherche
●
Comment faire ?
−
ex. insérer 10
−
ex. insérer 18
12
8
4
23
9
17
18
10
6
●
Quelle est la complexité ?
15
20
18
16
Renaud Marlet – ENPC MOPSI 2013-2014
30
Insertion dans un
arbre binaire de recherche
●
Pour insérer la clé x :
−
−
12
rechercher un nœud t tel que
■
x < clé(t) et t n'a pas de fils gauche ou
■
x > clé(t) et t n'a pas de fils droit
créer un nouveau fils (gauche ou droit)
de t avec x
8
4
23
9
10
6
●
Complexité
−
17
comme pour la recherche
■
O(log(n)) en moyenne, si arbre à peu près équilibré
■
O(n) dans le pire cas
15
20
18
16
Renaud Marlet – ENPC MOPSI 2013-2014
31
Suppression dans un
arbre binaire de recherche
●
●
Comment faire ?
−
ex. supprimer 6
−
ex. supprimer 4
−
ex. supprimer 8
−
ex. supprimer 12
Quelle est la complexité ?
12
8
4
23
9
6
17
15
20
16
Renaud Marlet – ENPC MOPSI 2013-2014
32
Suppression dans un
arbre binaire de recherche
●
Comment faire ?
−
12
ex. supprimer 6
8
4
9
6
●
Quelle est la complexité ?
23
17
15
20
16
Renaud Marlet – ENPC MOPSI 2013-2014
33
Suppression dans un
arbre binaire de recherche
●
Comment faire ?
−
12
8
ex. supprimer 4
4
9
6
●
Quelle est la complexité ?
23
17
15
20
16
Renaud Marlet – ENPC MOPSI 2013-2014
34
Suppression dans un
arbre binaire de recherche
●
Comment faire ?
12
8
−
ex. supprimer 8
4
9
6
●
Quelle est la complexité ?
23
17
15
20
16
Renaud Marlet – ENPC MOPSI 2013-2014
35
Suppression dans un
arbre binaire de recherche
●
Comment faire ?
12
8
4
−
●
ex. supprimer 12
Quelle est la complexité ?
23
9
6
17
15
20
16
Renaud Marlet – ENPC MOPSI 2013-2014
36
Suppression dans un
arbre binaire de recherche
●
Pour supprimer la clé x :
−
−
−
−
●
rechercher le nœud t avec la clé x
8
si t est une feuille, la supprimer
si t a un fils, supprimer t et
le remplacer par son fils
4
9
si t a deux fils,
■ chercher t' le nœud le plus à droite
6
du sous-arbre gauche, c.-à.d. prédécesseur
de x dans l'arbre [ou symétrique gauche/droite]
■ remplacer clé(t) par clé(t')
■ supprimer t' (qui n'a que 0 ou 1 fils), c.-à-d. attribuer
comme fils du père de t' l'éventuel fils gauche de t'
12
23
17
15
20
16
Complexité : O(log(n)) en moyenne si équil., O(n) dans le pire cas
Renaud Marlet – ENPC MOPSI 2013-2014
37
Exemple d'interface
Pointeur nul
class BinarySearchTree {
en C++11
int key; // Ici juste un entier pour simplifier
BinarySearchTree *left, *right; // nullptr ⇔ pas de fils
public:
BinarySearchTree(int k); // Construit un nœud k sans fils
bool contains(int k); // Teste si l'arbre contient k
void insert(int k);
// Insert k dans l'arbre (si absent)
void remove(int k);
// Supprime k dans l'arbre (si présent)
};
Renaud Marlet – ENPC MOPSI 2013-2014
38
Exercice 3
1) Rendez publics les champs left et right pour le debug
2) Construisez « à la main » l'arbre ci-dessous
dans une variable BinarySearchTree* bst;
à lire en penchant la tête
sur le côté gauche...
3) Ajouter une fonction récursive
void display(string prefix = "")
telle que bst.display() affiche :
/ 23
/ \ 17
/ \ \ 15
12
\ / 9
\ 8
\ \ 4
12
8
4
23
9
17
15
Renaud Marlet – ENPC MOPSI 2013-2014
39
Exercice 3 (suite)
4) Définissez et testez la fonction contains
5) Définissez et testez la fonction insert
− créez un arbre initial avec la valeur 12, insérez-y les valeurs
8, 4, 9, 23, 17, 15, et affichez-le
− faites des essais avec des ordres d'insertion différents
− dans quel cas (général) l'arbre résultant est-il déséquilibré ?
6) Définissez et testez la fonction remove
7) Quand c'est débogué, rendez à nouveau privés les champs
left et right: seuls insert/remove peuvent les modifier
8) Rendez un programme qui illustre successivement différents
cas d'insertion, de tests d'appartenance et de suppression
Renaud Marlet – ENPC MOPSI 2013-2014
40
Exercice 3 (fin)
à lire sur le côté...
9) Bonus : modifier la fonction display (< 10 lignes) pour
qu'elle affiche les arbres comme ceci :
/--23
| \--17
|
\--15
|
\--14
12
|
/--11
|
| \--10
| /--9
\--8
\--4
|
/--3
| /--2
\--1
\--0
12
8
4
23
9
17
1
0
11
2
10
3
15
14
Renaud Marlet – ENPC MOPSI 2013-2014
41
Pour les curieux : arbre équilibré
●
Arbre avec critère d'équilibre (ex. nb nœuds des fils...)
●
Arbre binaire équilibré :
−
−
●
critère d'équilibre
■
entre fils gauche et fils droit
■
total ou partiel
évite notamment les peignes
Avantages
−
recherche en O(log(n)) pire cas pour un arbre à n nœuds
−
insertion et suppression O(n) ou O(log(n)) suivant variantes
Renaud Marlet – ENPC MOPSI 2013-2014
42
Arbre AVL
●
Georgii Adelson-Velsky & Evguenii Landis (1962)
−
●
principe général toujours d'actualité
Arbre AVL
−
arbre binaire de recherche équilibré tq la hauteur de deux
sous-arbres d'un même nœud diffère au plus de 1
hauteur
au plus 1
Renaud Marlet – ENPC MOPSI 2013-2014
43
Arbre non AVL : exemple
arbre non AVL
12
7
4
2
15
10
Pourquoi ?
16
8
23
9
21
Renaud Marlet – ENPC MOPSI 2013-2014
44
Arbre AVL : exemple
arbre non AVL
arbre AVL (après rééquilibrage)
12
12
7
15
7
16
h(gauche) = 0 h(droite) = 3
4
2
10
16
8
4
23
9
21
2
9
8
15
10
21
23
Renaud Marlet – ENPC MOPSI 2013-2014
45
Arbre AVL
●
Propriété
−
●
Principe (transposable dans d'autres circonstances)
−
●
recherche, insertion, suppression en O(log(n))
insertion et suppression font du rééquilibrage
Voir : plein d'exemples sur le web...
(par ex. http://oopweb.com/Algorithms/Documents/AvlTrees/Volume/AvlTrees.htm)
Téléchargement