Algorithmique et structure de données Cours de Robert Cori – 1ère Année ENSEIRB TD 2 1 Algorithmes récursifs simples 1. Écrire une version récursive de l’algorithme permettant de calculer rapidement la puissance n-ième d’un nombre entier. Correction 1 int puissance(int a, int n) // Version explicite { if (n == 1) { return a; } else if (n % 2 == 0) { return puissance(a, n / 2) * puissance(a, n / 2); } else { return puissance(a, n / 2) * puissance(a, n / 2) * a; } } int puissance(int a, int n) // Version optimisée { int p; if (n == 1) { p = a; } else { p = puissance(a, n / 2); p = p * p; if (n % 2 == 1) { p = p * a; } } return p; } 2. Sachant que le calcul du produit de deux entiers de 1000 chiffres prend 1/100 de seconde, calculer le temps mis pour calculer a1000000 , où a est un entier de 1000 chiffres, par cette méthode. Comparer ce temps à celui que prendrait un algorithme consistant à effecetuer 1000000 de multiplications (noter que log2 (1000000) ≈ 20). 3. Le plus grand commun diviseur, ou PGCD, de deux entiers non nuls est le plus grand nombre entier qui divise ces deux nombres. Par exemple, le PGCD de 1071 1 et 1029 est 21. Écrire un algorithme récursif calculant le PGCD de deux entiers, en s’inspirant de l’algorithme itératif donné en cours. Correction 2 On considère a > b. Il faut démontrer que tout nombre qui divise a et b divise aussi le reste de la division de a par b, ce qui se voit facilement avec a = bq + r. Réciproquement, tout nombre qui divise b et r divise ausi a. Donc pgcd(a, b) = pgcd(b, r). int pgcd(int a, int b) { if (b == 0) { return a; } else { return pgcd(b, a % b); } } 2 Figure de Sierpiński La figure de Sierpiński est une figure géométrique d’aire nulle et de périmètre infini. Elle se construit, à partir d’un triangle équilatéral, par subdivisions successives. On la définit de la façon suivante : – La figure de Sierpiński d’ordre 1 est un triangle équilatéral noir, – La figure de Sierpiński d’ordre n est obtenue à partir de celle d’ordre n − 1 en inscrivant un triangle équilatéral blanc à l’intérieur de tous les triangles noirs, formant ainsi trois nouveaux triangles noirs à l’intérieur de chacun de ces triangles. Voici par exemple les figures de Sierpiński d’ordre 1, 2, 3, 4 et 5 : 1. Écrire un algorithme récursif dessinant la figure de Sierpiński d’ordre n dont le sommet du sud-ouest du triangle a pour coordonnées (x, y) et dont la longueur du coté est a : void sierpinski(x, y, a, n) On utilisera pour cela la fonction tracer_ligne(x, y, a, b) qui trace un segment entre les points de coordonnées (x, y) et (a, b). On remarquera aussi que la figure de Sierpiński d’ordre n > 1 est formée de trois figures plus petites d’ordre n − 1. 2 Correction 3 → Préciser qu’on dessine les triangles noirs, pas les blancs ! void sierpinski(x, { if (n == 1) { tracer_ligne( tracer_ligne( tracer_ligne(x } else { sierpinski( sierpinski(x + sierpinski(x + } } 3 y, a, n) x, y, (x + a) / 2, y + a * sqrt(3) / 2); x, y, x + a, y); + a, y, (x + a) / 2, y + a * sqrt(3) / 2); x, y, a / 2, n - 1); a / 2, y, a / 2, n - 1); a / 4, y + a * sqrt(3) / 4, a / 2, n - 1); Tris 1. Le tri à bulles consiste à faire remonter le plus grand élément d’un tableau jusqu’à la fin de celui-ci (comme une bulle d’air remonte à la surface). Pour cela, on parcourt le tableau, en triant les éléments successifs deux à deux, autant de fois que nécessaire. Écrire un algorithme effectuant le tri à bulles. Correction 4 void tri_a_bulles(int tab[], int taille) { int fin = taille - 1; bool echange = true; while(echange) { echange = false; for (i = 0; i < fin; i++) { if (tab[i] > tab[i + 1]) { echanger(tab[i], tab[i + 1]); echange = true; } } fin--; } } 2. Le tri par insertion consiste à insérer successivement chaque élément dans une partie triée dont la taille augmente à chaque étape. Pour insérer un élément on décale les éléments du tableau pour insérer cet élément à sa place dans la partie déjà triée. Écrire un algorithme effectuant le tri par insertion. 3 Correction 5 void tri_insertion(int tab[], int taille) { for (i = 1; i < taille; i++) { int m = tab[i]; int k = i; while (k > 0 && tab[k - 1] > m) { tab[k] = tab[k - 1]; k--; } tab[k] = m; } } 4