TD⚓︎
Exercice 1 : Maximum
Que fait la fonction récursive ci-dessous:
def mystere(lst, i = 0, j = None):
if j is None:
j = len(lst) - 1
if i == j:
return lst[i]
else:
milieu = (i + j) // 2
return max(mystere(lst, i, milieu), mystere(lst, milieu + 1, j))
Exercice 2 : Mediane
- Réfléchir à l'utilisation da la méthode "diviser pour régner" pour déterminer la valeur médiane d'un tableau d'entier non trié.
-
Mise en place: pour réaliser cet algorithme, nous allons chercher la k-ième valeur dans une liste.
-
Réaliser une fonction
sous_listes(lst, pivot)ayant en entrée une listelstet une valeur de la listepivotet retournant 3 sous-listes:- la sous-liste
lst_gdes valeurs strictement inférieures au paramètre - la sous-liste
lst_ddes valeurs strictement supérieures au paramètre - la sous-liste
lst_mdes valeurs strictement égales au paramètre
- la sous-liste
On a alors trois cas possibles en fonction de la taille de ces trois sous-listes:
- Si
kest inférieur à la taille de la sous-liste de gauche, alors la k-ième valeur est dans la sous-liste de gauche - Sinon, si
kest inférieur à la somme de la taille de la sous-liste de gauche et la taille de la sous-liste du milieu, alors la k-ième valeur est le pivot. - Sinon, la k-ième valeur appartient à la sous liste de droite (mais elle n'est plus la k-ième valeur de cette liste)
- Réaliser une fonction récursive
rang(lst, k)implémentant cet algorithme.
-
-
Le code suivant permet de mesurer le temps d'exécution:
import timeit from random import randint lst = [randint(-100, 100) for i in range(1000)] l = (len(lst) + 1)//2 lst_trie = sorted(lst) def affiche_temps(): print(timeit.timeit("rang(lst, l)", number=1000, globals=globals())) print(timeit.timeit("rang(lst_trie, l)", number=1000, globals=globals()))il affiche:
>>> affiche_temps() 0.3120999999991909 0.06440000000293367Analyser les temps obtenus. Que pouvez vous en conclure ?
Exercice 3 : Type bac
Cet exercice porte sur la programmation Python (listes, dictionnaires) et la méthode "diviser pour régner".
Cet exercice est composé de trois parties indépendantes. Dans cet exercice, on s'intéresse à des algorithmes pour déterminer, s'il existe, l'élément absolument majoritaire d'une liste.
On dit qu'un élément est absolument majoritaire s'il apparaît dans strictement plus de la moitié des emplacements de la liste.
Par exemple, la liste [1, 4, 1, 6, 1, 7, 2, 1, 1] admet 1 comme élément absolument majoritaire, car il apparaît 5 fois sur 9 éléments. Par ailleurs, la liste [1, 4, 6, 1, 7, 2, 1, 1] n'admet pas d'élément absolument majoritaire, car celui qui est le plus fréquent est 1, mais il n'apparaît que 4 fois sur 8, ce qui ne fait pas plus que la moitié.
- Déterminer les effectifs possibles d'un élément absolument majoritaire dans une liste de taille 10.
Partie A : Calcul des effectifs de chaque élément sans dictionnaire⚓︎
On peut déterminer l'éventuel élément absolument majoritaire d'une liste en calculant l'effectif de chacun de ses éléments.
-
Écrire une fonction
effectifqui prend en paramètres une valeurvalet une listelstet qui renvoie le nombre d'apparitions devaldanslst. Il ne faut pas utiliser la méthodecount. -
Déterminer le nombre de comparaisons effectuées par l'appel
effectif(1, [1, 4, 1, 6, 1, 7, 2, 1, 1]). -
En utilisant la fonction
effectifprécédente, écrire une fonctionmajo_abs1qui prend en paramètre une listelst, et qui renvoie son élément absolument majoritaire s'il existe et renvoieNonesinon. -
Déterminer le nombre de comparaisons effectuées par l'appel à
majo_abs1([1, 4, 1, 6, 1, 7, 2, 1, 1]).
Partie B : Calcul des effectifs de chaque élément dans un dictionnaire⚓︎
Un autre algorithme consiste à déterminer l'élément absolument majoritaire éventuel d'une liste en calculant l'effectif de tous ses éléments en stockant l'effectif partiel de chaque élément déjà rencontré dans un dictionnaire.
- Recopier et compléter les lignes 3, 4, 5 et 7 de la fonction
eff_dicosuivante qui prend en paramètre une listelstet qui renvoie un dictionnaire dont les clés sont les éléments delstet les valeurs les effectifs de chacun de ces éléments danslst.
def eff_dico(lst):
dico_sortie = {}
for ......... :
if ... in dico_sortie:
.....
else:
...
return dico_sortie
- En utilisant la fonction
eff_dicoprécédente, écrire une fonctionmajo_abs2qui prend en paramètre une listelst, et qui renvoie son élément absolument majoritaire s'il existe et renvoieNonesinon.
Partie C : par la méthode "diviser pour régner"⚓︎
Un dernier algorithme consiste à partager la liste en deux listes. Ensuite, il s'agit de déterminer les éventuels éléments absolument majoritaires de chacune des deux listes. Il suffit ensuite de combiner les résultats sur les deux listes afin d'obtenir, s'il existe, l'élément majoritaire de la liste initiale.
Les questions suivantes vont permettre de concevoir précisément l'algorithme.
On considère lst une liste de taille n.
- Déterminer l'élément absolument majoritaire de
lstsin = 1. C'est le cas de base.
On suppose que l'on a partagé lst en deux listes :
lst1 = lst[:n//2](lst1contient lesn//2premiers éléments delst)lst2 = lst[n//2:](lst1contient les autres éléments delst)
-
Si, ni
lst1nilst2n'admet d'élément absolument majoritaire, expliquer pourquoilstn'admet pas d'élément absolument majoritaire. -
Si
lst1admet un élément absolument majoritairemaj1, donner un algorithme pour vérifier simaj1est l'élément absolument majoritaire delst. -
Recopier et compléter les lignes 4, 11, 13, 15 et 17 pour la fonction récursive
majo_abs3qui implémente l'algorithme précédent. Vous pourrez utiliser la fonctioneffectifde la question 2.def majo_abs3(lst): n = len(lst) if n == 1: return ... else: lst_g = lst[:n//2] lst_d = lst[n//2:] maj_g = majo_abs3(lst_g) maj_d = majo_abs3(lst_d) if maj_g is not None: eff = ...... if eff > n/2: return ... if maj_d is not None: eff = ...... if eff > n/2: return ...