SPÉ MP, MP∗ TD03 Année 2016/2017 Tas et files de priorité On dit

SPÉ MP, MPTD03
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.
Entasser le noeud t.data.(0) : il viole en effet la structure de tas.
Écrire la fonction tri_tas : int array -> unit.
5. Quelle taille maximale de tableau votre fonction peut-elle trier en 10 secondes ?
6. Les tas permettent également d’implémenter ce que l’on appelle des files de priorité. Une file de
priorité est un ensemble Fd’objets munis chacun d’une priorité. On peut
Ajouter dans Fun objet xavec une priorité p(push).
Retirer de Fl’objet de priorité maximale (pop).
Rechercher sans le supprimer l’objet de Fde priorité maximale (top).
Les files de priorité sont utillisées dans de très nombreux algorithmes. Pour n’en citer qu’un,
l’algorithme de Dijkstra qui permet de trouver des plus courts chemins à l’intérieur d’un graphe.
Encore une fois, par souci de simplicité, nous supposerons que nos files de priorité contiennent
uniquement des entiers représentant des priorités (et pas les objets auxquels sont associées ces
priorités). Une file de priorité sera donc pour nous un tas.
(a) La fonction de recherche de la plus grande priorité est immédiate. Écrire top : abpc -> int.
(b) Pour supprimer de la file tl’objet de plus petite priorité, on échange les valeurs t.data.(0)
et t.data.(t.taille - 1). Après avoir décrémenté t.taille, on entasse depuis la racine.
Écrire la fonction pop : abpc -> int.
(c) La fonction d’insertion dans la file de priorité est la suivante :
let push x t =
t.data.(t.taille) <- x;
t.taille <- t.taille + 1;
detasser t (t.taille - 1)
Il reste à écrire detasser : soit xun noeud (d’indice idans le tableau t.data) de l’arbre t. On
suppose que test organisé en tas, à cela près que le noeud xa (peut-être) une valeur supérieure
à celle de son père, et risque de compromettre la structure de tas. On rétablit la structure de
tas en échangeant éventuellement xet son père, puis en réitérant s’il y a eu échange. Écrire la
fonction detasser: abpc -> int -> unit.
7. On part d’une file de priorité initialement vide, puis on effectue nentassements et ndétassements
de nombres aléatoires. Quelle valeur de nvotre algorithme peut-il traiter en 10 secondes ?
1 / 2 100%

SPÉ MP, MP∗ TD03 Année 2016/2017 Tas et files de priorité On dit

La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !