SPÉ MP, MP∗TD03
Année 2016/2017 Tas et files de priorité
On dit d’un arbre binaire qu’il est presque complet, lorsqu’il est rempli sur tous ses niveaux, sauf
éventuellement le plus profond, sur lequel les noeuds situés le plus à droite peuvent éventuellement être
vides. Un tas est un arbre binaire presque complet Tvérifiant la propriété suivante : pour tout noeud x
de T, les valeurs des fils de xsont inférieures ou égales à la valeur de x.
Pour simplifier, tous les arbres utilisés dans ce TD auront des noeuds dont les valeurs sont du type
int. Dans des situations plus concrètes, on stockerait dans chaque noeud un objet xainsi qu’une clé qui,
elle, serait un nombre entier.
On peut représenter un arbre binaire presque complet Tpar un tableau t:
— La racine de Test placée en t.(0).
— Le fils gauche et le fils droit de cette racine sont placés respectivement en t.(1) et t.(2).
— Les noeuds de profondeur 2 sont rangés aux emplacements t.(3) àt.(6).
— Les noeuds de profondeur 3 sont rangés aux emplacements t.(7) àt.(14).
— etc.
Question : étant donné un noeud de l’arbre T, placé dans le tableau tà l’indice i, quel est l’indice
dans le tableau tdu père de ce noeud (lorsque i > 0) ? de son fils gauche ? de son fils droit ?
Question : dans un tas, où se trouve le noeud de plus grande valeur ? de plus petite valeur ?
On représente la structure d’arbre binaire presque complet par le type Caml suivant :
type abpc = {
data : int array;
mutable taille : int
};;
Étant donné un arbre binaire presque complet t, le champ t.data est un tableau contenant les valeurs
des noeuds de t. Le champ t.taille est un entier compris (au sens large) entre 0 et Array.length
t.data : l’arbre correspondant au sous-tableau de t.data dont les indices sont compris entre 0 et
t.taille - 1 est organisé en tas. Ainsi, pour un arbre « désorganisé », le champ taille est égal à
0. Si, au contraire, tout l’arbre est organisé en tas, ce champ est mis à la valeur maximale. Dans la suite,
lorsque l’on parlera du tas t, on s’intéressera donc uniquement aux indices de t.data compris entre 0 et
t.taille-1.
1. Soit tun tas. À quels indices de t.data se trouvent les feuilles de t?
2. Soit xun noeud (d’indice idans le tableau t.data) de l’arbre t. On suppose que le sous-arbre
de tde racine xest organisé en tas, à cela près que le noeud xest (peut-être) inférieur à l’un
de ses fils, et risque de compromettre la structure de tas. On rétablit la structure de tas pour le
sous-arbre de racine xau moyen de l’algorithme suivant :
— Déterminer parmi les trois noeuds x, son fils gauche (s’il existe) et son fils droit (s’il existe), le
noeud yqui a la plus grande valeur. S’il y a violation de la structure de tas, alors :
— Échanger les valeurs des noeuds xet y.
— Recommencer l’opération sur le noeud y.
Écrire la fonction entasser : tas -> int -> unit réalisant les opérations décrites ci-dessus.
3. On désire maintenant construire, à partir d’un arbre binaire presque complet t, un arbre presque
complet ayant une structure de tas. Pour cela :
— On donne à t.taille la valeur maximale Array.length t.
— Pour ivariant de t.taille/2 - 1 à 0, on applique entasser t i.
Écrire la fonction construire_tas : tas -> unit.
4. L’algorithme suivant, appelé assez logiquement « tri par tas », trie un tableau vd’entiers :
— Créer un tas tdont les noeuds sont les éléments de v.
— Pour ivariant de Array.length t -1 à 0 :
— Échanger t.data.(0) et t.data.(i) :t.data.(0) est en effet le noeud maximal du tas.
— Diminuer t.taille de 1 : l’ex-élément d’indice 0 est maintenant hors du tas.