ds1-fevrier2018-cor
ds1-fevrier2018-cor
ds1-fevrier2018-cor
Note : lorsque, dans une question, est demandée la complexité, c’est une fonction de la taille de la
donnée qui est attendue. Lorsque c’est le comportement asymptotique, la réponse attendue est soit
une notation O, soit une notation Θ soit une notation Ω (le choix vous incombe).
Vous pourrez utiliser toute fonction vue en cours, TD, TP à la condition expresse de spécifier correc-
tement les entrées et les sorties.
Le barême est donné à titre indicatif.
Livres, calculatrices et objets de communication interdits.
Q 1.1 Si je prouve qu’un algorithme est en Θ(n2 ), peut-il être en Ω(n3 ) ? Répondre par oui ou non.
Corrigé
Q 1.2 Si je prouve qu’un algorithme est en Θ(n log n) dans le pire des cas, peut-il exister des cas en Ω(n2 ) ?
Répondre par oui ou non.
Corrigé
Non. Puisque l’algorithme s’exécute dans le pire des cas en Θ(nlogn), le meilleur des cas ne pourra pas
être en Ω(n2 ) puisque n log n < n2 .
Q 1.3 On peut résoudre l’équation de récurrence (qui compte les appels de f) de l’algorithme suivant en
utilisant le théorème général. Répondre par vrai ou faux.
def f ( t ):
if t == []:
return 0
else :
return 1 + 2 * f ( t [0: len ( t )//4])
Corrigé
Oui. L’algorithme divise la taille du problème à chaque appel. (on pourrait ajouter en un nombre constant
de sous-problèmes)
1
n = len ( t )
s1 = Element (0)
s2 = Element (0)
fini = False
i = 0
while i <= n // 2 and not fini :
s1 . add ( t [ i ]) # il fallait lire s1 = s1 . add ( t [ i ])
s2 . add ( t [n -1 - i ]) # il fallait lire s2 = s2 . add ( t [n -1 - i ])
if s1 . cmp ( s2 ) == 0:
fini = True
i = i + 1
Q 2.1 Décrire un meilleur des cas pour le nombre d’additions d’Element (le nombre d’appels à la méthode
add).
Corrigé
Si t est tel que t[0] = t[n − 1] : la boucle est exécutée un seule fois, la comparaison retourne vraie et le
booléen passe à vrai.
Q 2.2 Donner exactement le nombre cm (n) d’additions d’Element pour un tableau de taille n pour le
meilleur des cas.
Corrigé
cm (n) = 2
Q 2.3 Décrire un pire des cas pour le nombre d’additions d’Element. Puis donner un exemple pour
n = 10.
Corrigé
Pj Pj
Si t est tel que pour tout j ∈ [0, n//2], i=0 t[i] 6= i=0 t[n − 1 − i] : la boucle est exécutée n//2 fois. Par
exemple [0,1,1,1,1,1,1,1,1,1].
Q 2.4 Donner exactement le nombre cp (n) d’additions d’Element pour un tableau de taille n pour le pire
des cas. Justifier.
Corrigé
P n2
cp (n) = i=0 2 = 2 × ( n2 + 1)
Q 2.5 Donner le comportement asymptotique de cet algorithme pour le nombre d’additions d’Element.
Corrigé
Dans le meilleur des cas en Θ(1). Dans le pire des cas en Θ(n).
Q 2.6 Donner le comportement asymptotique de cet algorithme pour le nombre de comparaisons d’Element
(le nombre d’appels à la méthode cmp). Justifier.
Corrigé
On est en O(n) et Ω(1). Les pire et meilleur des cas sont les mêmes que pour le nombre d’additions.
2
Exercice 3 : Revisite du tri bulle [6.5 points]
Compétence évaluée : comprendre un nouvel algorithme, analyser des résultats expérimentaux.
L’algorithme du tri bulle est souvent présenté avec une double boucle pour aboutissant à une complexité
en nombre de comparaisons en Θ(n2 ) (comme vu en cours).
Voici une version un peu modifiée :
def bubbleSort ( t ):
"""
: param t : numpy array of Element
"""
fini = False
indices = range ( len ( t ) -1)
while not fini :
echange = False
for i in indices :
if cmp ( t [ i ] , t [ i +1]) > 0:
t [ i ] , t [ i +1] = t [ i +1] , t [ i ]
echange = True
if not echange :
fini = True
Q 3.1 Décrire un meilleur des cas en nombre de comparaisons (le nombre d’appels à la fonction cmp).
Corrigé
Si le tableau est trié en ordre croissant, aucun échange n’est réalisé, la boucle tant que ne fait qu’un tour.
La boucle pour est exécutée une fois, avec une comparaison à chaque fois.
Q 3.2 Quel est le nombre exact de comparaisons dans le meilleur des cas.
Corrigé
Pn−1
i=1 1=n−1
Si le tableau est trié en ordre décroissant, au moins un échange est réalisé pour chaque élément, la boucle
tant que est réalisée n fois.
Q 3.4 Quel est le nombre exact de comparaisons dans le pire des cas.
Corrigé
Pn Pn−1 Pn
i=1 j=1 1= i=1 n − 1 = n(n − 1)
3
On propose maintenant une amélioration 1 :
def cocktailSort ( t ):
fini = False
indices = range ( len ( t ) -1)
while not fini :
echange = False
for i in indices :
if cmp ( t [ i ] , t [ i +1]) > 0:
t [ i ] , t [ i +1] = t [ i +1] , t [ i ]
echange = True
if not echange :
fini = True
if not fini :
echange = False
for i in reversed ( indices ):
if cmp ( t [ i ] , t [ i +1]) > 0:
t [ i ] , t [ i +1] = t [ i +1] , t [ i ]
echange = True
if not echange :
fini = True
Ce n’est pas modifié. En effet, comme il n’y a pas d’échange à la première boucle pour, fini devient vrai
et la seconde boucle pour n’est pas exécutée.
Ce n’est pas modifié non plus. La première boucle pour place correctement l’élément le plus grand. La
seconde boucle pour place correctement l’élément le plus petit. Et ainsi de suite, à chaque tour de boucle
tant que, deux éléments sont bien placés.
La courbe ci-dessous montre le nombre moyen de comparaisons réalisé sur un tirage aléatoire de 100
tableaux pour chaque longueur entre 1 et 100, pour le bubbleSort et pour le coctailSort.
1. On trouve différentes dénominations de ce tri : cocktailSort ou shakerSort
4
Q 3.7 Qu’en conluez-vous sur l’efficacité du cocktailSort par rapport au bubbleSort ?
Corrigé
En moyenne le cocktailSort est plus rapide que le bubbleSort. La complexité en moyenne semble quadra-
tique.
Q 3.8 Donner un exemple d’un tableau de taille 5 où le coctailSort est plus efficace (vous déroulerez les
étapes de chacun des deux tris en affichant le contenu du tableau après chaque boucle pour).
Corrigé
Prenons le tableau [5 2 3 4 1], l’exécution des deux tris donne les résultats suivants :
bubbleSort coctailSort
[2 3 4 1 5] [2 3 4 1 5]
[2 3 1 4 5] [1 2 3 4 5]
[2 1 3 4 5] [1 2 3 4 5]
[1 2 3 4 5] nb cmp = 12
[1 2 3 4 5]
nb cmp = 20
: return : les deux couples correspondant aux points les plus proches
Corrigé
def p o i n t _ l e s _ p l u s _ p r o c h e s _ n a i f ( l ):
n = len ( l )
r1 , r2 = l [0] , l [1]
min = distance ( r1 , r2 )
i = 0
for p1 in l :
i += 1
for p2 in l [ i +1: n ]:
d = distance ( p1 , p2 )
if d < min :
r1 , r2 = p1 , p2
min = d
return r1 , r2
Q 4.2 Quel est le nombre de calculs de distances entre deux points réalisé par votre algorithme naı̈f donné
à la question précédente si l’ensemble des points est de taille n ?
Corrigé
Pn Pn Pn n(n−1)
1+ i=1 j=i+1 1=1+ i=1 n−i=1+ 2
On présente maintenant une autre stratégie. On ne vous demande pas de comprendre pourquoi cela
fonctionne dans le cadre de cet examen, car la preuve de l’algorithme n’est pas évidente.
On supposera que la liste des points ` est triée selon les abscisses des points (cela ne rentre pas en compte
dans la complexité de l’algorithme). Puis on applique l’algorithme suivant récursivement :
Etape 1 diviser ` en deux : `1 contient les bn/2c premiers points 2 , `2 contient les dn/2e derniers points
Etape 2 trouver récursivement les deux points les plus proches dans `1 et dans `2 , notons respectivement
d1 et d2 les distances de ces deux paires de points, on note d = min(d1 , d2 )
1 2
Etape 3 on considère l’abcisse xm = ` [−1][0]+`
2
[0][0]
, construire la liste s des points de ` dont les abscisses
sont au maximum à une distance d de l’abscisse xm
Etape 4 trier s selon l’axe des ordonnées
Etape 5 trouver les deux points les plus proches dans s (en utilisant l’algorithme naı̈f ). Soit ds la
distance entre ces points. Si s est vide, ds := d.
Etape 6 retourner le minimum entre d et ds
2. ceux d’abscisse la plus faible étant donné que ` a été triée selon les abscisses
6
dx dx
d1
ds
d2
xm
Q 4.3 Quel nom donne-t-on à la stratégie mise en place dans cet algorithme ?
Corrigé
Q 4.4 Quel tri choisir pour les tris de listes dans l’algorithme ? Justifier ce choix par des considérations
sur la complexité de votre algorithme.
Corrigé
Q 4.5 L’algorithme décrit n’indique pas quand la récursion s’arrête. Décrire en français le ou les cas de
base.
Corrigé
Q 4.6 Quel est le nombre d’appels à la fonction distance à l’étape 5 dans le pire des cas ? Justifier en
décrivant le pire des cas.
Corrigé
n(n−1)
Dans le pire des cas, tous les points sont dans s. 1 + 2
Q 4.7 Donner l’équation de récurrence de l’algorithme récursif dans le pire des cas ?
Corrigé
Dans le pire des cas, tous les points sont dans s. Donc l’équation de récurrence s’écrit :
1 si `est de longueur 2
c(n) = 2 si `est de longueur 3
n n(n−1)
2c( 2 ) + 1 + 2 sinon
Q 4.8 En déduire la complexité asymptotique de l’algorithme récursif dans le pire des cas. Justifier.
Corrigé
L’ensemble s ne peut pas toujours être vide sinon c’est qu’il n’y a pas de points.
import time
from functools import total_ordering
@total_ordering
class Element :