Parcours d'arbres - Tournoi
La fédération de badminton souhaite gérer ses compétitions à l’aide d’un logiciel. Pour ce faire, une structure arbre de compétition a été définie récursivement de la façon suivante : un arbre de compétition est soit l’arbre vide, noté \(\emptyset\), soit un triplet composé d’une chaîne de caractères appelée étiquette, d’un arbre de compétition appelé sous-arbre gauche et d’un arbre de compétition appelé sous-arbre droit. On représente graphiquement un arbre de compétition de la façon suivante :
Cet arbre se lit de la façon suivante :
- 4 participants se sont affrontés : Joris, Kamel, Carine, et Abdou. Leurs noms apparaissent en bas de l'arbre, se sont les étiquettes des feuilles de l'arbre.
- Au premier tour, Kamel a battu Joris, et Carine a battu Abdou.
- En finale, Kamel a battu Carine.
- Le vainqueur de la compétition est Kamel.
Pour s'assurer que chaque finaliste ait joué le même nombre de matchs, un arbre de compétition a toutes ses feuilles à la même hauteur : il s'agit donc d'arbres parfaits. On suppose également que tous les joueurs de la compétition ont des noms différents.
On utilisera les fonctions usuelles pour représenter et manipuler les arbres : Arbre
, est_vide
, est_feuille
, etiquette
, gauche
, et droit
. L'arbre vide est représenté par la valeur None
.
Exécuter le bloc ci-dessous pour charger l'interface du TP.
class Noeud:bksl-nl def py-undpy-undinitpy-undpy-und(self, etiquette, gauche, droit):bksl-nl self.etiquette = etiquettebksl-nl self.gauche = gauchebksl-nl self.droit = droitbksl-nlbksl-nldef creerpy-undvide(): return Nonebksl-nldef estpy-undvide(a): return a is Nonebksl-nldef etiquette(a): return a.etiquettebksl-nldef etiquettepy-undstr(a): return "•" if estpy-undvide(a) else str(etiquette(a))bksl-nldef gauche(a): return a.gauchebksl-nldef droit(a): return a.droitbksl-nldef Arbre(e, a1, a2): return Noeud(e, a1, a2)bksl-nlbksl-nl
L'arbre de l'énoncé est alors :
1 2 3 4 5 6 7 |
|
Informations sur le tournoi¶
Nombre de joueurs du tournoi¶
Écrire une fonction nb_joueurs
qui étant donné un arbre de compétition a
renvoie le nombre de joueurs ayant participé à cette compétition.
def nbpy-undjoueurs(a):bksl-nl """ Arbre -> intbksl-nl Renvoie le nombre de joueurs ayant participé à la compétition d'arbre a """bksl-nl passbksl-nlbksl-nl
Nombre de rounds d'un tournoi¶
Écrire une fonction nb_rounds
qui étant donné un arbre de compétition a
renvoie le nombre de rounds dont a été composée la compétition.
Remarque. Un round correspond à un "niveau" de la compétition : la finale, les demi-finales, les quarts de finale, etc. sont des rounds.
def nbpy-undrounds(a):bksl-nl """ Arbre -> intbksl-nl Renvoie le nombre de rounds de la compétition a """bksl-nl passbksl-nlbksl-nl
Informations sur un joueur¶
Nombre d'occurrences du joueur dans l'arbre¶
Écrire une fonction occurrences
qui étant donné un arbre a
et le nom nom
d'un joueur renvoie le nombre d'occurences de l'étiquette nom
parmi les nœuds de l'arbre a
.
def occurrences(a, nom):bksl-nl """ Arbre, str -> intbksl-nl Renvoie le nombre d'occurrences de nom dans a """bksl-nl passbksl-nlbksl-nl
Nombre de matchs joués par le joueur¶
Déduire de la fonction occurrences
, une fonction nombre_matchs
qui étant donné un arbre de compétition a
et un nom nom
détermine le nombre de matchs joués par nom
pendant à la compétition.
Attention aux cas particuliers
def nombrepy-undmatchs(a, nom):bksl-nl """ Arbre, str -> intbksl-nl Renvoie le nombre de matchs joués par le joueur nom dans la compétition d'arbre a """bksl-nl passbksl-nlbksl-nl
Informations sur les joueurs¶
Liste des joueurs du tournoi¶
Compléter le code de la fonction liste_joueurs
qui étant donné un arbre de compétition a
renvoie la liste des noms de tous les joueurs ayant participé à la compétition. On remarquera qu'il s'agit des étiquettes des feuilles de l'arbre a
. Si jamais l'arbre de compétition est vide, on renverra la liste vide.
On rappelle que si l1
et l2
sont deux listes python, alors l1 + l2
renvoie la concaténation de l1
et de l2
: c'est la liste constituée de tous les éléments de l1
et de l2
mis bout à bout.
def listepy-undjoueurs(a):bksl-nl """ Arbre -> [str]bksl-nl Renvoie la liste des joueurs ayant participé à la compétition d'arbre a """bksl-nl # if estpy-undvide(a):bksl-nl # return ....................................bksl-nl # elif estpy-undfeuille(a):bksl-nl # return [..................................]bksl-nl # else:bksl-nl # return ....................................bksl-nlbksl-nl
Liste des joueurs par niveau¶
En vous inspirant de la fonction liste_joueurs
, écrire une fonction niveau
qui étant donné un entier i
et un arbre de compétition a
renvoie la liste des étiquettes des nœuds de profondeur i
de l'arbre a
.
On remarquera que :
- Si un arbre de compétition
a
est vide alors pour tout entieri
,niveau(i, a)
doit renvoyer la liste vide. - le niveau \(0\) correspond à la racine de l'arbre.
- le niveau
i
de l'arbrea
correspond au niveaui - 1
du sous-arbre gauche dea
et au niveaui - 1
du sous-arbre droit dea
.
def niveau(a, i):bksl-nl """ Arbre, int -> [str]bksl-nl Renvoie la liste des étiquettes des nœuds de profondeur i de l'arbre a """bksl-nl passbksl-nlbksl-nl
Liste des joueurs vaincus I¶
Écrire une fonction vaincus_gagnant
qui étant donné un arbre de compétition a
renvoie la liste des joueurs ayant été vaincus par le gagnant de la compétition.
def vaincuspy-undgagnant(a):bksl-nl """ Arbre -> [str]bksl-nl Renvoie la liste des joueurs ayant joué un match contre le gagnant de la compétition d'arbre a """bksl-nl passbksl-nlbksl-nl
Parcours en largeur¶
Algorithme de cours¶
En vous inspirant de l'algorithme vu en cours, écrire une fonction parcours_largeur
qui étant donné un arbre a
en renvoie la liste des étiquettes, telles qu'obtenues à l'aide d'un parcours en largeur de l'arbre.
On utilisera un objet file
de type list
pour représenter la file d'attente des éléments à traiter :
- la file est vide lorsque
file
est la liste[]
; - on enfile l'élément
a
à l'aide de l'instructionfile.append(a)
; - on défile le premier élément de la file à l'aide de l'instruction
file.pop(0)
- on accède sans défiler au premier élément de la file à l'aide de l'instruction
file_noeud[0]
On utilisera un objet liste_etiquettes
de type list
pour stocker la liste des étiquettes de l'arbre a
dans l'ordre du parcours. Initialement celle-ci sera vide. L'opération de traitement sur le nœud parcouru sera l'ajout de son étiquette à la liste liste_etiquettes
(lorsque cela est possible).
def parcourspy-undlargeur(a):bksl-nl """ Arbre -> [str]bksl-nl Renvoie la liste des étiquettes des nœuds de l'arbre a, telle qu'obtenue à l'aide d'un parcours en largeur """bksl-nl passbksl-nlbksl-nl
Liste des joueurs vaincus II¶
On souhaite établir la liste des joueurs ayant été vaincus par un joueur donné dans la compétition d'arbre a
. Pour cela, on utilise l'algorithme suivant :
- on détermine le nœud
n
de profondeur minimale de l'arbre de compétitiona
dont l'étiquette est égale au nom du joueur recherché ; - la liste des joueurs vaincus par
nom
dans la compétition d'arbrea
est la liste des joueurs vaincus par le gagnant de la compétition dont l'arbre est le sous-arbre dea
de racinen
.
Par exemple, dans l'arbre de compétition de l'énoncé, si on souhaite établir la liste des joueurs ayant été vaincus par Carine :
- le nœud de profondeur minimal
n
est alors le nœud à la profondeur 1 et d'étiquette"Carine"
; - le sous-arbre de racine
n
est constitué de trois éléments. Dans cette sous-compétition, Carine n'a vaincu qu'un seul joueur, Abdou.
Ainsi la liste des joueurs vaincus par Carine est donc ["Abdou"]
.
Recherche d'un nœud de profondeur minimale¶
Écrire une fonction recherche_noeud
qui étant donné un arbre a
et un nom
renvoie le nœud de profondeur minimal de a
dont l'étiquette est nom
. On utilisera pour cela un parcours en largeur d'abord et on s'arrêtera dès que l'étiquette du nœud courant est le nom
recherché.
Dans le cas où nom
n'est pas une étiquette de l'arbre a
, on renverra None
.
def recherchepy-undnoeud(a, nom):bksl-nl """ Arbre, str -> Arbrebksl-nl Renvoie le sous-arbre de a dont la racine a pour étiquette nom et est de profondeur minimale dans a """bksl-nl passbksl-nlbksl-nl
Liste des joueurs vaincus¶
Écrire une fonction joueurs_vaincus
qui étant donné un arbre de compétition a
et le nom d'un joueur nom
renvoie la liste des joueurs vaincus par nom
dans la compétition. On utilisera pour cela l'algorithme décrit en section 4.2 ainsi que les fonctions vaincus_gagnant
et recherche_noeud
précédemment écrites.
def joueurspy-undvaincus(a, nom):bksl-nl """ Arbre, str -> [str]bksl-nl Renvoie la liste des joueurs vaincus par nom dans la compétition d'arbre a """bksl-nl passbksl-nlbksl-nl