TD 2 - LSV

publicité
Algorithmique TD2
L3 Informatique – ENS Cachan
Thomas Chatain
Exercice 1
Pour chacun des problèmes suivants, proposer un algorithme itératif et un algorithme récursif,
prouver leur correction et leur terminaison, et calculer leur complexité en temps et en espace.
1. Calcul de la factorielle d’un entier.
2. Calcul du n-ième terme de la suite de Fibonacci définie par :

 u0 = 0
u1 = 1

un = un−2 + un−1 , pour n > 1.
3. Calcul du PGCD de deux entiers par l’algorithme d’Euclide.
Exercice 2
On considère un tableau A[1..n] qui contient toutes les valeurs de {0, 1, . . . , n} sauf une. On
voudrait déterminer laquelle en temps linéaire.
Montrer comment résoudre ce problème si les éléments de A peuvent être lus et copiés en temps
constant.
On suppose maintenant qu’un accès élémentaire dans A est une lecture du i-ème bit de A[j].
Montrer comment résoudre ce problème en temps linéaire et en utilisant une mémoire en O(log(n)).
Exercice 3
Lorsque des données sont stockées sur des supports physiques ou transmises dans un réseau,
il peut arriver que des bits d’information changent de valeur malencontreusement. Pour détecter
ces erreurs, on ajoute aux données quelques bits, appellés bits de parité, dont la valeur est fixée
initialement en fonction des données. À l’aide des bits de parité, on peut vérifier que les données
n’ont pas été endommagées.
Les codes de Hamming sont construits en insérant des bits de parité aux positions 1, 2, 4, 8. . .
qui sont des puissances de 2. Les autres positions (3, 5, 6, 7, 9, 10. . .) restent disponibles pour les
données. Pour chaque k, on positionne le bit de parité en position 2k à 0 ou 1 de telle sorte qu’il
y ait un nombre pair de bits à 1 parmi les bits dans les positions n telles que b 2nk c est impair.
1. Construire le code de Hamming pour la donnée 11010001101.
2. Proposer un algorithme pour vérifier l’intégrité des données.
3. Adapter l’algorithme pour qu’il propose une correction dans le cas où les données ont été
altérées.
4. Que se passe-t-il si deux bits ont été modifiés ?
5. Montrer comment détecter jusqu’à trois erreurs en ajoutant un bit de parité supplémentaire.
1
Exercice 4
1. Donner la complexité en temps de l’algorithme vu à l’école primaire pour multiplier deux
entiers.
2. En observant que
(a × 10k + b)(c × 10k + d) = ac × 102k + (ac + bd − (a − b)(c − d)) × 10k + bd
proposer un algorithme de type diviser pour régner et calculer sa complexité en temps.
3. Adapter l’algorithme à la multiplication de deux polynômes.
Exercice 5
Une file est une structure de données permettant de stocker une suite d’éléments, où les insertions se font toutes d’un même côté et les suppressions toutes de l’autre côté (À l’inverse des piles
dans lesquelles insertions et suppressions sont faites du même côté).
Implémenter l’ajout et la suppression dans une file à l’aide de deux piles (avec du pseudocode,
ou bien un langage de votre choix).
Quel est le coût d’une opération dans le pire des cas ?
Calculer le coût amorti d’une opération.
Exercice 6
On souhaite implémenter une pile à l’aide d’un tableau. Si on fixe la taille du tableau a priori,
on perd en efficacité pour deux raisons : lorsqu’il y a trop peu de données, beaucoup de place est
perdue ; lorsqu’il y a trop de données, on ne peut pas tout rentrer dans le tableau. Pour résoudre
ce problème, on utilise des piles dynamiques dont la taille peut changer de telle sorte qu’au moins
la moitié du tableau est toujours remplie. L’opération qu’on veut implémenter est l’empilement :
elle consiste à insérer l’élément à la première place libre lorsque le tableau n’est pas plein ; sinon,
on crée un nouveau tableau de taille double du précédent, on copie dedans tous les éléments du
premier tableau puis on empile finalement l’élément dedans.
On néglige le coût de l’allocation d’un tableau. Le coût à mesurer est donc le nombre de copies
effectuées.
1. Implémenter la fonction empiler(x).
2. Quelle est la complexité de la fonction empiler dan le pire des cas ?
3. Calculer la complexité amortie de la fonction empiler(x) lorsqu’on commence par une pile
vide.
4. On considère une procédure différente empiler2(x) qui consiste à augmenter la taille du
tableau d’une constante k plutôt que de la doubler, lorsque le tableau est plein. Quelle est
la complexité amortie de cette procédure ?
5. Supposons qu’on veuille également une opération de dépilement depiler(), qui consiste à
effacer le dernier élément du tableau. Si la suppression du dernier élément résulte en un
tableau à moitié plein, on crée un tableau de taille divisée par deux et on copie les éléments
du tableau dedans. Quel est le coût amorti des opérations empiler(x) et depiler().
6. Montrer qu’un coût amorti linéaire peut être obtenu si on divise par deux la taille du tableau
quand le nombre d’éléments descend en dessous d’un quart.
2
Téléchargement