Structures Arborescentes – Implémentations - Algo, la page

publicité
Structures Arborescentes – Implémentations
Nathalie Junior Bouquet
avril 2013
1
Arbres binaires
Définition
Un arbre binaire est soit vide, soit de la forme B = <o, B1 , B2 >, où B1 et B2 sont des arbres
binaires disjoints et ’o’ est un nœud appelé racine.
e
u
c
u
q
l
q
o
e
n
Figure 1 – Arbre binaire
1.1
Le type algébrique abstrait
sorte
ArbreBinaire
utilise
Nœud, Élément
opérations
arbre-vide
<–, –, –>
contenu
racine
g
d
:
:
:
:
:
:
→ ArbreBinaire
Nœud × ArbreBinaire × ArbreBinaire → ArbreBinaire
Nœud → Élément
ArbreBinaire → Nœud
ArbreBinaire → ArbreBinaire
ArbreBinaire → ArbreBinaire
préconditions
racine(B1 ) est-défini-ssi B1 ̸= arbre-vide
g(B1 ) est-défini-ssi B1 ̸= arbre-vide
d (B1 ) est-défini-ssi B1 ̸= arbre-vide
axiomes
racine(<o, B1 , B2 >) = o
g(<o, B1 , B2 >) = B1
d (<o, B1 , B2 >) = B2
avec
B1 , B2 : ArbreBinaire
o
: Nœud
1
Algorithmique
Types abstraits : Les arbres – avril 2013
Info-Sup
Epita
L’opération contenu permet d’associer à chaque Nœud de l’arbre une information de type Élément. Un
arbre dont les nœuds contiennent des éléments est dit arbre étiqueté.
On notera, abusivement, <r, G, D> l’arbre dont la racine contient l’élément r.
r
G
D
Figure 2 – Arbre binaire : une structure récursive
1.2
Représentation dynamique
La représentation la plus naturelle reproduit la structure récursive (voir figure 2).
On utilise les pointeurs pour chaîner entre eux les nœuds. A chaque nœud on associe deux pointeurs,
vers les deux sous-arbres gauche et droit. L’arbre non vide est représenté par un pointeur sur le nœud
racine. Il a la valeur nul s’il est vide.
Nous utiliserons la plupart du temps des arbres étiquetés. Un champ supplémentaire cle contiendra
l’information contenue dans le nœud.
1.2.1
Le type
types
/* déclaration du type t_element*/
t_arbreBinaire = ↑ t_noeudBinaire
t_noeudBinaire = enregistrement
t_element
cle
t_arbreBinaire fg, fd
fin enregistrement t_noeudBinaire
B
e
c
u
NUL
u
q
l
NUL
NUL
q
e
o
n
NUL NUL
NUL NUL
NUL NUL
NUL NUL
Figure 3 – Représentation dynamique de l’arbre de la figure 1
2
Algorithmique
Types abstraits : Les arbres – avril 2013
1.2.2
1.3
Info-Sup
Epita
Implémentation des opérations
Type abstrait : ArbreBinaire
Implémentation : type t_arbreBinaire
B : ArbreBinaire
B : t_arbreBinaire
arbre-vide
nul
contenu(racine(B))
B↑.cle
g(B)
B↑.fg
d(B)
B↑.fd
Représentation statique
On peut simuler la représentation précédente à l’aide de tableaux 1 : les pointeurs sont alors remplacés
par des entiers indiquant les positions des nœuds dans le tableau. L’arbre est représenté par le tableau,
ainsi qu’un entier indiquant la position de la racine.
1.3.1
La numérotation hiérarchique
On peut utiliser un simple vecteur pour représenter un arbre binaire. Il suffit de stocker chaque nœud
à la position correspondant à sa numérotation hiérarchique.
1
f
2
3
i
p
4
5
n
8
u
6
r
9
_
7
a
t
10
a
Figure 4 – Arbre binaire parfait + numérotation hiérarchique
constantes
nbMAxNoeuds = ...
types
/* déclaration du type t_element*/
t_AB_Hierarchique = nbMAxNoeuds
variables
t_AB_hierarchique
t_element
B
L’arbre de la figure 4 sera représenté par le tableau suivant :
1
f
2
p
3
i
4
n
5
r
6
a
1. Selon le même principe que pour les ”fausses listes chaînées“
3
7
t
8
u
9
_
10
a
Algorithmique
Types abstraits : Les arbres – avril 2013
Info-Sup
Epita
L’utilisation de cette représentation est intéressante sur un arbre parfait (ou complet, comme celui de
la figure 8), car on peut limiter la taille du vecteur à celle de l’arbre. Par contre, sur un arbre quelconque,
la place occupée n’est plus optimisée.
Représentation de l’arbre de la figure 1 :
1
e
2
c
3
u
4
u
5
l
6
q
7
8
9
q
10
e
11
12
o
13
n
La place occupée sera d’autant moins optimisée que la hauteur de l’arbre sera élevée. Dans le cas d’un
arbre dégénéré (ou filiforme) à n nœuds, l’espace occupé peut alors atteindre 2n − 1 !
f
i
l
i
f
e
Figure 6 – Peigne droit
Figure 5 – Arbre filiforme
Représentation de l’arbre filiforme de la figure 5 :
1
f
2
3
i
...
...
7
l
...
...
14
i
...
...
29
f
...
...
15
g
...
...
30
i
31
n
58
e
Représentation du peigne droit de la figure 6 :
1
p
1.3.2
2
d
3
e
...
...
6
r
7
i
...
...
14
o
...
...
62
t
63
e
Utilisation
◦ La racine est en position 1 dans le vecteur.
◦ Si i est la position du nœud actuel alors :
◃ son fils gauche se trouve à la position 2i
◃ son fils droit se trouve à la position 2i + 1
◃ son père (sauf pour la racine de l’arbre),
se trouve à la position i div 2.
En pratique, il faut avoir une valeur particulière (∅)
pour remplacer la racine de l’arbre vide. Sauf si
l’arbre est parfait : la taille de l’arbre suffit !
4
Algorithmique
Types abstraits : Les arbres – avril 2013
1.4
1.4.1
Info-Sup
Epita
Parcours d’un arbre binaire
Parcours en profondeur
Le parcours en profondeur main gauche consiste à
descendre dans l’arbre à gauche le plus loin possible.
Lorsque l’on ne peut plus aller à gauche, on descend à
droite. Lorsqu’on ne peut plus descendre, on remonte
d’un niveau : si on vient de la gauche, on descend à
droite, sinon on remonte encore. . .
La manière la plus simple d’envisager ce parcours est récursive. Il revient tout simplement à parcourir
le sous-arbre gauche, puis à parcourir le sous-arbre droit !
r
(1)
(3)
(2)
G
(1) : préfixe
D
(2) : infixe
(3) : suffixe
Figure 7 – Parcours en profondeur d’un arbre binaire
Lors du parcours en profondeur, chaque nœud est rencontré trois fois :
(1) avant de descendre sur le sous arbre-gauche : ordre préfixe,
(2) en remontant de la gauche, avant de descendre à droite : ordre infixe (ou symétrique),
(3) en remontant de la droite : ordre suffixe (ou postfixe).
Exemples : les trois ordres de traitement des nœuds d’un arbre induits lors d’un parcours en profondeur.
◦ L’ordre préfixe sur l’arbre de la figure 8 donnera : lui_est_complet
◦ L’ordre infixe sur l’arbre de la figure 4 donnera : un_parf ait
◦ L’ordre suffixe sur l’arbre de la figure 1 donnera : quelconque
l
u
c
s
i
_
e
t
o
_
m
l
p
e
Figure 8 – Arbre binaire complet
5
t
Algorithmique
Types abstraits : Les arbres – avril 2013
Info-Sup
Epita
L’algorithme :
Avec la représentation statique :
Avec la représentation dynamique :
↓
algorithme procedure parcours_prof
parametres locaux
t_arbreBinaire
B
debut
si B[i] = ∅ alors
/* ∅ = "vide" */
sinon
prof_rec (B, 2*i)
prof_rec (B, 2*i+1)
fin si
fin algorithme procedure prof_rec
debut
si B = nul alors
/* terminaison */
sinon
/* traitement préfixe */
parcours_prof (B↑.fg)
/* traitement infixe */
parcours_prof (B↑.fd)
/* traitement suffixe */
fin si
fin algorithme procedure parcours_prof
1.4.2
algorithme procedure prof_rec
parametres locaux
t_AB_hierarchique
B
entier
i
→
algorithme procedure parcours_prof
parametres locaux
t_AB_hierarchique
B
debut
prof_rec(B, 1)
fin algorithme parcours_prof
Parcours en largeur
Le parcours en largeur ou par niveaux consiste à visiter les nœuds niveaux par niveaux (en général
de gauche à droite) : c’est l’ordre hiérarchique.
L’algorithme classique utilise une file qui sera utilisée comme suit :
– on enfile la racine de l’arbre
– tant que la file n’est pas vide :
– on défile le premier élément de la file
– on enfile chacun de ses fils (s’ils ne sont pas vides), d’abord le gauche puis le droit.
L’algorithme : Avec la représentation dynamique
algorithme procedure parcours_largeur
parametres locaux
t_arbreBinaire
B
variables
t_file
f
debut
si B <> nul alors
f ← enfiler (B, file_vide())
faire
B ← defiler (f)
/* traitement B↑.cle */
si B↑.fg <> nul alors
f ← enfiler (B↑.fg, f)
fin si
si B↑.fd <> nul alors
f ← enfiler (B↑.fd, f)
fin si
tant que non est_vide (f)
fin si
fin algorithme procedure parcours_largeur
Pour la représentation statique, on peut envisager une implémentation sans file, en effectuant un
parcours séquentiel du vecteur (en passant les éventuelles valeurs ∅). Mais cela n’est réellement intéressant
que lorsque l’arbre est complet ! Sinon, il suffit d’utiliser une file d’entiers, qui contiendra les numéros en
ordre hiérarchique des nœuds.
6
Téléchargement