L3-INFO Algorithmique Quick 2 – 25 novembre 2014 – durée 1 h Les documents et les téléphones (incluant smartphone, tablettes,... tout ce qui contient une interface réseau) interdits. Les calculettes sont autorisées Seuls les dictionnaires pour les personnes de langue étrangère sont autorisés. 1 Codage Soit un arbre de codage binaire A. Démontrer que si A n’est pas complet (si un de ses nœuds internes n’est pas binaire), alors A ne représente pas un codage optimal (c’est-à-dire qu’il existe un codage plus court). 2 Rotation dans un ABR On s’intéresse à l’opération de rotation autour d’un nœud, utilisée notamment pour rééquilibrer les ABRs. La figure ci-dessous décrit l’effet des opérations de rotation à gauche et à droite autour du nœud x : RotationGauche x y RotationDroite y α x γ β α γ β 1. Dessiner l’arbre ci-dessous après une rotation à gauche, puis une rotation à droite autour de sa racine. 12 5 20 7 6 15 12 22 Quick 2 2. On donne ci-dessous la définition en C d’un type Arbre, implémenté par une structure chaînée : typedef Noeud; typedef struct { int cle; Noeud * fgauche; Noeud * fdroit; Noeud * parent; } Noeud; typedef Noeud * Arbre; Dans cette structure chaque nœud comporte un pointeur sur le nœud parent (NULL pour la racine). Une structure de type Arbre doit donc vérifier, pour tout Noeud * N qui la compose : N->fgauche 6= NULL ⇒ N->fgauche->parent = N N->fdroit 6= NULL ⇒ N->fdroit->parent = N Donner une réalisation de la procédure RotationGauche, réalisant une rotation à gauche autour de la racine de l’arbre fourni en paramètre : void RotationGauche(Arbre * A); 3 Ancêtre commun On manipule dans tout cet exercice un arbre binaire tels que ceux vus en cours, muni des opérations usuelles du type abstrait Arbre : EstVide, Clé, FilsGauche et FilsDroit. On suppose que chaque nœud de cet arbre est muni d’une clé entière, et que les clés des nœuds sont toutes distinctes deux à deux. L’obectif de cet exercice est le suivant : étant donnés deux nœuds x et y (identifiés par leurs clés), trouver un ancêtre commun à x et y, autrement dit un nœud n qui est la racine d’un sous-arbre contenant x et y. En particulier, on s’intéressera au plus bas ancêtre commun (en abrégé PBAC) à x et y, autrement dit le seul nœud de l’arbre : — qui est un ancêtre commun à x et y — mais dont aucun fils n’est un ancêtre commun à x et y. Par exemple, dans l’arbre ci-contre : — 16 est un ancêtre commun à 8 et 7 ; — 2 n’est pas un de leurs ancêtres communs ; — 6 est leur PBAC. 11 4 16 6 15 9 5 2 8 19 1 7 On note n le nombre de nœuds de l’arbre et h sa hauteur, en particulier pour les calculs de complexité. Algorithmique 25/11/2014 2/ 3 Quick 2 3.1 Algorithme naïf 1. Écrire un algorithme de recherche du PBAC basé sur un parcours récursif de l’arbre. Vous préciserez notamment de quel parcours il s’agit et vous justifierez ce choix. Votre algorithme devra renvoyer un triplet bool × bool × noeud : — le premier booléen détermine si x est présent ou non dans le sous-arbre parcouru — le second booléen détermine si y est présent ou non dans le sous-arbre parcouru — la clé renvoyée est le PBAC de x et de y, si celui-ci a été trouvé, sinon une valeur spéciale ⊥. 2. Déterminer la complexité au pire de cet algorithme. 3.2 Cas particulier On suppose pour ce paragraphe que l’arbre considéré est un ABR. 1. Écrire un algorithme de recherche du PBAC qui profite de cette particularité pour rendre la recherche plus efficace. 2. Déterminer la complexité au pire de cet algorithme. 3.3 Bonus (uniquement si vous avez traité tout le reste) : précalcul L’idée pour améliorer cet algorithme est d’effectuer un prétraitement : on exécute une fois pour toutes un premier calcul (éventuellement coûteux) sur tout l’arbre, pour qu’ensuite chaque appel à l’opération PBAC soit efficace. Dans ce cas particulier, le prétraitement peut consister à calculer, pour chaque nœud de l’arbre, quel est son nœud père (et à stocker cette information sous une forme accessible en temps constant : tableau, pointeur...). 1. Écrire un algorithme permettant d’affecter à chaque nœud n l’information père(n). 2. Déterminer la complexité au pire de cet algorithme. 3. Écrire un algorithme de calcul du PBAC qui exploite cette nouvelle information, et déterminer sa complexité au pire. On suppose pour cette question que les nœuds x et y sont donnés, et qu’il n’y a donc pas besoin de parcourir l’arbre pour les retrouver. Algorithmique 25/11/2014 3/ 3