Informatique tronc commun TP 5

publicité
Informatique tronc commun TP 5
11 novembre 2014
1 Tri d'un tableau
Le tri de données est un problème fondamental en informatique.
On se propose d'écrire deux algorithmes de tris et de comparer leurs performances.
1.1 Deux opérations utiles sur les tableaux
Deux opérations pratiques sur les tableaux Python permettent :
1. D'ajouter un élément à la n :
>>> t = [11, 42, 33]
>>> t.append(17)
>>> t
[11, 42, 33, 17]
2. De récupérer le dernier élément du tableau et de le retirer :
>>> t
[11, 42, 33, 17]
>>> t.pop()
17
>>> t
[11, 42, 33]
1.2 Jeux de tests
On pourra s'intéresser notamment à la performance de ces tris sur des tableaux de
nombres à virgule ottante de trois types :
1. Des tableaux de nombres aléatoires. Pour générer un tableau de nombres aléatoires,
on pourra utiliser la fonction random du module random qui retourne un nombre
à virgule ottante tiré aléatoirement de façon uniforme dans l'intervalle [0, 1[. On
utilisera aussi la méthode append des tableaux Python qui permet de rajouter un
élément à la n d'un tableau existant :
1
from random import random
def tableau_aleatoire(n):
"""Retourne un tableau contenant n éléments tirés aléatoirement de
façon uniforme dans [0,1[."""
t = []
for i in range(n):
# t contient i éléments
t.append(random())
# t contient i+1 éléments
return t
2. Des tableaux déjà triés par ordre croissant. Pour modier le moins possible les
conditions du test, on utilisera comme précédemment des tableaux de nombres à
virgule ottante :
def tableau_trie(n):
"""Retourne un tableau trié de n nombres à virgule flottante
appartenant à [0, 1["""
k = 1. / n
return [ k * i for i in range(n) ]
3. Des tableaux déjà triés par ordre décroissant :
def tableau_trie_decr(n):
"""Retourne un tableau trié par ordre décroissant de n nombres à
virgule flottante appartenant à [0, 1["""
k = 1. / n
return [ k * i for i in range(n-1, -1, -1) ]
Pour mesurer le temps de calcul d'une fonction, on utilisera timeit :
import timeit
def duree(f, x):
"""Calcule le temps mis par Python pour calculer f(x)."""
t = timeit.Timer(stmt=lambda : f(x))
time = t.timeit(number=1)
return time
1.3 L'existant en Python
Il est possible de trier un tableau avec la fonction sorted(t), qui retourne une copie
triée du tableau t. En exécutant
d1 = duree(sorted, tableau_trie(1000000))
d2 = duree(sorted, tableau_trie_decr(1000000))
d3 = duree(sorted, tableau_aleatoire(1000000))
On obtient respectivement des temps 0.024s, 0.023s, 0.57s.
2
Le but du TP est de voir comment écrire nous-mêmes des algorithmes de tri aussi
performants que possible.
1.4 Tri par sélection
Une première possibilité est le tri par sélection. Il fonctionne de la façon suivante : on
garde un tableau des éléments à trier et des éléments triés. Initialement, le tableau des
éléments triés est vide. Autant de fois qu'il y a d'éléments initialement, on cherche le
plus petit élément du tableau à trier et on le met à la n du tableau trié.
1. Écrire une fonction imin(t)) retournant l'indice k de l'élément le plus petit du
tableau t.
2. Écrire une fonction enleve(t, i) qui retourne enlève t[i] du tableau t et retourne
sa valeur. Pour cela, il sut simplement d'échanger t[i] avec t[-1] et d'utiliser
pop.
3. Écrire une fonction tri_selection(t) retournant un nouveau tableau, trié par
ordre croissant, contenant les mêmes éléments que t en utilisant l'algorithme du
tri par sélection présenté ci-dessus.
Regardez quelles sont les performances de votre programme (on pourra regarder pour
100, 1000 et 10000 éléments). Attention, que devient le tableau passé à tri_selection ?
1.5 Tri par insertion
Une seconde méthode est le tri par insertion. Là encore, on garde un tableau des
éléments trié, initialement vide, et on insère un par un les éléments du tableau à trier,
en faisant en sorte que chaque insertion préserve l'ordre du tableau trié.
1. Écrire une fonction insere(t, v) qui insère v dans un tableau (supposé déjà trié)
t. Notons n − 1 la longueur de ce tableau t. Pour y insérer l'élément v, on l'ajoute
à la n du tableau t puis on regarde si t[n-1] et t[n] sont dans l'ordre. Si c'est le
cas, on a terminé, sinon, on échange ces deux éléments et on compare alors t[n-2]
et [n-1]. S'ils sont dans l'ordre, c'est terminé, sinon, on les échange, etc.
2. Écrire une fonction tri_insertion(t) retournant un nouveau tableau, trié par
ordre croissant, contenant les mêmes éléments que t en utilisant l'algorithme du
tri par insertion présenté ci-dessus.
Regardez quelles sont les performances de votre programme (on pourra regarder pour
100, 1000 et 10000 éléments).
1.6 Tris en place
Dans les deux tris que nous avons présenté, nous avons utilisé un deuxième tableau.
On préfère souvent implanter ces deux tris en place, c'est-à-dire sans utiliser de nouveau
tableau (ce qui réduit fortement la consommation mémoire de l'algorithme lorsque le
tableau est grand).
3
Pour cela, on travaille avec un unique tableau t de taille n (celui donné en argument)
qui, au fur et à mesure de l'exécution contiendra d'une part les éléments déjà triés dans
la partie du tableau d'indices appartenant à [[0, i[[ et d'autre part les éléments restant à
trier dans la partie du tableau d'indices appartenant à [[i, n[[).
1. Pour adapter le tri par sélection, il convient donc d'écrire une fonction imin2(t, i)
donnant l'indice d'un minimum de la portion de t d'indices appartenant à [[i, n[[.
Enlever alors l'élément minimum de cette portion du tableau pour l'ajouter à la
portion déjà triée revient donc juste à l'échanger avec t[i]. Écrire cette fonctions
min2(t,i) puis la procédure tri_selection2(t) triant en place le tableau t.
2. Pour adapter le tri par insertion, il convient d'écrire une procédure insere2(t, i)
qui insère l'élément t[i] dans le sous-tableau (trié) d'indices appartenant à [[0, i[[.
Écrire cette procédure puis la procédure tri_insertion2(t) triant en place le
tableau t.
4
Téléchargement