4.1- TP - Tournoi des blobs
On vous a donné la tâche (très importante) d'organiser le tournois des blobs. Les blobs sont nombreux, et s'affrontent d'une manière mysterieuse que seuls eux maitrisent.
L'issue des affrontement est entièrement déterministe :
- Si le blob A gagne contre le blob B une fois, il gagnera toujours
- Si A gagne contre B, et que B gagne contre C, alors A gagnera nécéssairement contre C.
Votre objectif ? Établir le grand classement des blobs !

Implémentation python
Vous devez commencer par importer les éléments du module "blob", avec la ligne
from blob import *.Vous disposerez ensuite d'une liste de tous les blobs (ils sont 500), à laquelle vous pouvez accéder avec la fonction
get_blobs().Un blob peut en combattre un autre avec
blob1.combat(blob2). Cette fonction renvoie le vainqueur.Lorsque vous affichez un blob, il est identifié par son prénom (pris dans la liste officielle des prénoms en France depuis 2010, je n'ai rien inventé). Bien sûr, les blobs portent leur prénoms sans considération de genre, ce sont des blobs après tout.
Loading editor...
from blob import *
Loading editor...
blobs = get_blobs() N = len(blobs)
Question 1
Choisissez deux blobs de votre choix, et affichez-les.
Loading editor...
Loading editor...
Loading editor...
Question 2
Faite-les s'affronter. Qui gagne ?
Voir le combat
Pour voir le combat en animation, utilisez afficher_combat(blob1, blob2) : il renvoie aussi le vainqueur. Plus un blob est grand, plus il est fort...
Loading editor...
On va maintenant s'intéresser au tournois.
Vous avez peut-être remarqué une forte similarité entre ce problème, et celui du tri d'une liste ! Donc inspirez-vous librement du cours sur les tris.
I. Les tris quadratiques
Des classements en place
Dans tout ce TP, les classements se font en place : on ne crée pas de nouvelle liste, on modifie directement la liste blobs, en échangeant des blobs de place. À la fin, blobs[0] est le meilleur blob, blobs[1] le deuxième, etc.
Pour échanger les blobs d'indices i et j, on écrit : blobs[i], blobs[j] = blobs[j], blobs[i].
I.1. Première idée
On propose un premier moyen de réaliser le tournois :
- on place tous les blobs en ligne
- puis, chaque blob affronte son voisin de droite, et, si il perd, échange sa place avec lui.
- enfin, on répète cette opération suffisemment de fois pour avoir un classement fiable.

Question 3
Écrivez une fonction, qui prend en argument
- la liste des blobs
- un indice
i < len(blobs) - 1Et qui réalise l'affrontement entre le blob à l'emplacementi, et celui à l'emplacementi + 1. Si le blob d'indicei + 1gagne, votre fonction échange les deux blobs, afin que le gagnant soit le premier des deux dans la liste. La fonction ne renvoie rien : elle modifie la liste.
Loading editor...
Question 4
En déduire une fonction passe(blobs) qui applique cette procédure à chaque blob de la liste : pour i allant de 0 à len(blobs) - 2, le blob d'indice i affronte son voisin de droite. Remarquez qu'après une passe, le plus faible des blobs est forcément arrivé à la fin de la liste !
Loading editor...
Question 5
Combien de fois faudra-il répèter cette fonction pour que notre liste contienne le classement final ?
Écrivez ensuite une fonction classement_bulle qui réalise le classement en suivant ces étapes, puis affichez les 10 premiers blobs du classement.
Et non ! Ca ne suffit pas. Par exemple, que ce passe-il si les blobs sont en ordre inverse au départ ?
Oui ! Il faut bien le faire N fois.
Ca fait beaucoup quand même non ?
Loading editor...
Visualiser le classement
La fonction animer_classement(fonction, n) applique votre fonction de classement à une liste de n blobs, puis anime son déroulement : à chaque combat, les deux blobs se foncent dessus, et le vainqueur saute sur le perdant. Puis les blobs se déplacent à leur nouvelle place dans le classement.
Essayez-la avec chacun de vos classements !
Loading editor...
animer_classement(classement_bulle, 16)
Question 6
Quelle est alors la complexité de votre fonction ?
Non !
Oui !
En soi, c'est vrai. Mais en général, on évite d'utiliser des formules inutilement compliquées dans les
Vous l'aurez peut-être remarqué, mais on viens d'implémenter le tri à bulle !
Si vous ne voyez pas le lien, essayez de revoir la fonction du tri à bulle du cours.
Maitenant, on va faire la même chose avec les autres tris.
Récupérer à nouveau la liste des blobs non triés :
Loading editor...
blobs = get_blobs()
I.2. Tri par sélection
Cette fois, l'idée est d'abord de trouver le blob gagnant, puis le suivant, et ainsi de suite.
Question 7
Écrivez une fonction selection qui prend en argument
- une liste
blobs - un indice
0 <= k < len(L)
Et qui renvoie l'indice du blob le mieux classé de la liste blobs entre les indices k et len(blobs) - 1 (inclus). On pourra garder en mémoire l'indice du meilleur blob trouvé jusqu'ici, et le faire combattre avec chacun des blobs suivants.
Loading editor...
Question 8
En déduire une fonction classement_selection qui réalise le classement, en utilisant la fonction de la question précédente : pour k allant de 0 à len(blobs) - 2, on cherche le meilleur blob parmi ceux d'indices k à len(blobs) - 1, et on l'échange avec le blob d'indice k. Ainsi, après ce tour, les blobs d'indices 0 à k sont les k + 1 meilleurs, dans l'ordre.
Affichez les dix premiers blobs, et assurez-vous que le résultat est le même que pour le classement bulle !
Loading editor...
Loading editor...
animer_classement(classement_selection, 16)
Question 9
Quelle est alors la complexité de votre fonction ?
Non !
Oui !
En soi, c'est vrai. Mais en général, on évite d'utiliser des formules inutilement compliquées dans les
Loading editor...
blobs = get_blobs()
I.3. Tri par insertion
Oui, encore un tri... Mais bon, cette fois vous avez compris le principe, ça devrait aller vite !
Question 10
Écrivez une fonction insere(blobs, i) qui prend en argument la liste des blobs et un indice i. On suppose que les blobs d'indices 0 à i - 1 sont déjà classés entre eux. La fonction fait "reculer" le blob d'indice i jusqu'à sa place : tant qu'il bat son voisin de gauche, il échange sa place avec lui.
Après l'appel, les blobs d'indices 0 à i sont classés entre eux.
Loading editor...
Question 11
En déduire une fonction classement_insertion qui classe la liste des blobs (en place) : on insère successivement le blob d'indice 1, puis celui d'indice 2, etc. Au départ, le "classement partiel" ne contient que le blob d'indice 0.
Loading editor...
Loading editor...
animer_classement(classement_insertion, 16)
Question 12
Quelle est alors la complexité de votre fonction ?
Non !
Oui !
En soi, c'est vrai. Mais en général, on évite d'utiliser des formules inutilement compliquées dans les
II. Mais en vrai, qui fait un tournois comme ça ?
Les blobs, visiblement. Peut être qu'ils en ont marre de s'affronter pendant aussi longtemps, et qu'ils préfèreraient aller plus vite. Mais vous pouvez les aider à faire mieux !
On peut, par exemple, imaginer des mini tournois dans le grand tournois !
Question 13
En supposant qu'on ait deux classements de blobs distincts (par exemple, obtenus par deux mini tournois). Comment peut-on les combiner en un grand classement ?
Dans notre liste, les deux classements sont côte à côte : ce sont les blobs d'indices debut à milieu - 1, et ceux d'indices milieu à fin - 1. Écrivez une fonction fusion(blobs, debut, milieu, fin) qui les fusionne en un seul classement, des indices debut à fin - 1, en place (sans liste temporaire) :
- on garde deux indices :
i1, qui part dedebut, eti2, qui part demilieu. Ce sont les meilleurs blobs de chaque classement qui ne sont pas encore à leur place définitive ; - on fait combattre les blobs d'indices
i1eti2:- si le blob d'indice
i1gagne, il est à sa place : on avancei1; - sinon, le blob d'indice
i2doit passer devant tous les blobs restants du premier classement : on le fait reculer jusqu'à l'indicei1, en l'échangeant successivement avec son voisin de gauche. Les blobs restants du premier classement sont alors décalés d'une case vers la droite : on avancei1eti2;
- si le blob d'indice
- on s'arrête quand l'un des deux classements est épuisé (
i1 == i2oui2 == fin) : les blobs restants sont déjà à leur place.
Loading editor...
Question 14
Quelle est la complexité de votre fonction ? Avec
Pour les blobs, seuls les combats sont coûteux : se déplacer dans la liste ne leur coûte rien. Dans tout ce TP, on mesure donc la complexité en nombre de combats (on ne compte pas les échanges).
Pour les blobs, seuls les combats sont coûteux : se déplacer dans la liste ne leur coûte rien. Dans tout ce TP, on mesure donc la complexité en nombre de combats (on ne compte pas les échanges).
Non, on doit tout de même parcourir les listes !
Oui !
Non ! D'où sortirais le log dans ce cas ?
Si c'est la cas, vous pouvez faire mieux ! Réfléchissez à votre fonction.
Fonctions récursives
En python, (et en informatique en général), on peut faire des fonctions récursives, c'est-à-dire qui s'appellent elles-mêmes.
Attention, pour ne pas boucler à l'infini, l'idée est d'appeller notre fonction sur des entrées de plus en plus petites !
Par exemple, on peut imaginer une fonction du tri par insertion qui classe les n premiers blobs de la liste en faisant les opérations suivantes :
- si
nvaut 0 ou 1, il n'y a rien à faire ; - sinon, on classe les
n - 1premiers blobs (avec la même fonction !) ; - puis on insère le blob d'indice
n - 1, avec la fonctioninserede la question 10.
def tri_insertion_rec(blobs, n):
"""Classe (en place) les n premiers blobs, par insertion, récursivement."""
# cas de base : 0 ou 1 blob, déjà classé
if n <= 1:
return
# on classe les n - 1 premiers blobs (un problème plus petit)
tri_insertion_rec(blobs, n - 1)
# puis on insère le blob d'indice n - 1
insere(blobs, n - 1) Pour classer toute la liste, on appelle tri_insertion_rec(blobs, len(blobs)).
On propose alors une nouvelle procédure de classement, pour classer les blobs d'indices debut à fin - 1 :
- s'il y a 0 ou 1 blob, il n'y a rien à faire ;
- sinon, on coupe en deux au milieu,
milieu = (debut + fin) // 2; - on classe chaque moitié (de
debutàmilieu - 1, et demilieuàfin - 1) en utilisant la même procédure ; - enfin, on fusionne les deux moitiés avec la fonction de la question 13.
Question 15
Écrivez une fonction récursive classement_fusion_rec(blobs, debut, fin) qui réalise le classement de cette manière, puis une fonction classement_fusion(blobs) qui classe toute la liste (en appelant classement_fusion_rec avec les bons indices).
Loading editor...
Loading editor...
animer_classement(classement_fusion, 16)
III. Comparaison des classements
On aimerait maintenant comparer les manières de classer les blobs.
Compter les combats
On vous met à disposition deux fonctions :
reinit_compteur()remet à zéro le compteur de combatslire_compteur()compte le nombre de combats depuis la dernière réinitialisation.
Question 16
Comptez le nombre de combats dans chacuns de vos tris. Que remarquez-vous ?
Loading editor...
blobs = get_blobs() reinit_compteur() # à completer print(lire_compteur())
Loading editor...
Loading editor...
Loading editor...
Plus de blobs ?
Vous pouvez, optionellement, donner un argument à get_blobs pour dire combien de blobs vous voulez.
Courbes
Vous pouvez afficher des courbes :
- importez le module matplotlib.pyplot avec
import matplotlib.pyplot as plt - pour déclarer une courbe,
plt.plot(X, Y, "r+"), où X et Y sont des listes de mêmes tailles contenant les ordonnées et abscisses de chaque point, "r" est la couleur de votre courbe, et "+" la forme des points ("-" pour une ligne, "." pour un point, etc). - pour afficher le résultat,
plt.show(). Vous pouvez déclarer plusieurs courbes avant d'afficher le résultat, et elles seront alors sur le même graphique. - pour réinitialiser les courbes
plt.clf(). Je vous conseille d'appeler cette fonction au début de chaque cellule qui affiche une courbe.
Question 17
Tracez les courbes du nombre de comparaisons des différents tri en fonction du nombre de blobs. Que remarquez-vous ?
Loading editor...
Question 18
Tracez maintenant seulement la courbe du dernier tri (le tri fusion). Quelle forme a-elle ? À votre avis, quelle est la complexité de cette fonction ?
Loading editor...
Loading editor...
Entrez le code donné en cours pour accéder à la solution :