diff --git a/T1_Structures_de_donnees/1.3_Arbres/exercices/index.html b/T1_Structures_de_donnees/1.3_Arbres/exercices/index.html index 9de86190e..7c2b669f3 100644 --- a/T1_Structures_de_donnees/1.3_Arbres/exercices/index.html +++ b/T1_Structures_de_donnees/1.3_Arbres/exercices/index.html @@ -4051,9 +4051,22 @@
Q3.a. Écrire la liste de toutes les valeurs dans l'ordre où elles seront affichées.
Q3.b. Choisir le type de parcours d'arbres binaires de recherche réalisé parmi les propositions suivantes : Préfixe, Suffixe ou Infixe.
+On reconnait un parcours préfixe.
+Q4. En vous inspirant de l’algorithme précédent, écrire un algorithme Parcours2 permettant de parcourir et d'afficher les valeurs de l'arbre A dans l'ordre croissant.
+Pour afficher les valeurs d'un ABR dans un ordre croissant, il faut utiliser un parcours infixe. Un algorithme récursif de parcours infixe peut être celui-ci:
+Parcours2(A) # A est un arbre binaire de recherche
+ Parcours(A.fils_gauche)
+ Afficher(A.valeur)
+ Parcours(A.fils_droit)
+
Exercice 3 du sujet Centres Etrangers J2 - 2023
diff --git a/search/search_index.json b/search/search_index.json index 0e12d793c..53c819dd3 100644 --- a/search/search_index.json +++ b/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["fr"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Accueil","text":"Actualit\u00e9s
Th\u00e8me en cours d'\u00e9tude
Exercice 1
\u00c9nonc\u00e9Corr. Q1Corr. Q2Corr. Q3Corr. Q4Exercice 5 du sujet Centres \u00c9trangers 1 - 2021
def maximum(P):\n if est_vide(P):\n return None\n m = depile(P)\n while not est_vide(P):\n val = depile(P)\n if val > m:\n m = val\n return m\n
Avec le code ci-dessus, la pile p
est vide \u00e0 la fin de l'ex\u00e9cution. Pour \u00e9viter cela, on peut par exemple cr\u00e9er une pile q
temporaire qui recevra les \u00e9l\u00e9ments de p
, avant de retransf\u00e9rer \u00e0 la fin du programme les \u00e9l\u00e9ments de q
dans p
.
def maximum(P):\n Q = creer_pile()\n if est_vide(P):\n return None\n m = depile(P)\n empile(Q, m)\n while not est_vide(P):\n val = depile(P)\n empile(Q, val)\n if val > m:\n m = val\n while not est_vide(Q):\n empile(P, depile(Q))\n return m\n
Q4a. On va vider la pile p
dans une pile q
tout en comptant le nombre d'\u00e9l\u00e9ments d\u00e9pil\u00e9s dans une variable t
. On redonne ensuite \u00e0 p
son \u00e9tat initial en vidant q
dans p
.
Q4b
def taille(P):\n if est_vide(P):\n return 0\n Q = creer_pile()\n t = 0\n while not est_vide(P):\n empile(Q, depile(P))\n t += 1\n while not est_vide(Q):\n empile(P, depile(Q))\n return t\n
Exercice 2
\u00c9nonc\u00e9Corr. Q1Corr. Q2aCorr. Q2bCorr. Q3Corr. Q4Exercice 1 du sujet La R\u00e9union J2 - 2022
La variable temp
contient la valeur 25.
p1
est identique, elle contient toujours les valeurs 25, 3 et 7.
def addition(p):\n nb1 = depiler(p)\n nb2 = depiler(p)\n empiler(p, nb1 + nb2)\n
p = pile_vide()\nempiler(p, 3)\nempiler(p, 5)\naddition(p)\nempiler(p, 7)\nmultiplication(p)\n
Exercice 3
\u00c9nonc\u00e9Corr. Q1aCorr. Q1bCorr. Q2aCorr. Q2bCorr. Q3Corr. Q4Exercice 2 du sujet M\u00e9tropole Candidats Libres J1 - 2021
pile1 = Pile()\npile1.empiler(7)\npile1.empiler(5)\npile1.empiler(2)\n
L'affichage produit est 7, 5, 5, 2
.
3, 2
3, 2, 5, 7
3
\u00abpile vide\u00bb
La fonction mystere
permet d'obtenir la pile retourn\u00e9e jusqu'\u00e0 un \u00e9l\u00e9ment particulier (s'il existe).
def etendre(pile1, pile2):\n while not pile2.est_vide():\n val = pile2.depiler()\n pile1.empiler(val)\n
def supprime_toutes_occurences(pile, element):\n p_temp = Pile()\n while not pile.est_vide():\n val = pile.depiler()\n if val != element:\n p_temp.empiler(val)\n while not p_temp.est_vide():\n val = p_temp.depiler()\n pile.empiler(val)\n
Exercice 4
\u00c9nonc\u00e9Corr. Q1aCorr. Q1bCorr. Q2Corr. Q3Corr. Q4Exercice 5 du sujet Am\u00e9rique du Nord J1 - 2021
Le contenu de la pile P sera
| \"rouge\" |\n| \"vert\" |\n| \"jaune\" |\n| \"rouge\" |\n| \"jaune\" |\n _________\n
def taille_file(F):\n\"\"\"File -> Int\"\"\"\n F_temp = creer_file_vide()\n n = 0\n while not est_vide(F):\n enfiler(F_temp, defiler(F))\n n += 1\n while not est_vide(F_temp):\n enfiler(F, defiler(F_temp))\n return n\n
def former_pile(F):\n\"\"\"File -> Pile\"\"\"\n P_temp = creer_pile_vide()\n P = creer_pile_vide()\n while not est_vide(F):\n empiler(P_temp, defiler(F))\n while not est_vide(P_temp):\n empiler(P, depiler(P_temp))\n return P\n
def nb_elements(F, elt):\n\"\"\"File, Int -> Int\"\"\"\n F_temp = creer_file_vide()\n n = 0\n while not est_vide(F):\n val = defiler(F)\n if val == elt:\n n += 1\n enfiler(F_temp, val)\n while not est_vide(F_temp):\n enfiler(F, deFiler(F_temp))\n return n\n
def verifier_contenu(F, nb_rouge, nb_vert, nb_jaune):\n\"\"\"File, Int, Int, Int -> Bool\"\"\"\n return nb_elements(F, \"rouge\") <= nb_rouge and \\\n nb_elements(F, \"vert\") <= nb_vert and \\\n nb_elements(F, \"jaune\") <= nb_jaune\n
Exercice 5
\u00c9nonc\u00e9Corr. Q1Corr. Q2Corr. Q3Corr. Q4Exercice 2 du sujet Centres \u00c9trangers J1 - 2022
Il faut \u00e9crire l'instruction :
panier_1.enfile((31002, \"caf\u00e9 noir\", 1.50, 50525))\n
def remplir(self, panier_temp):\n while not panier_temp.est_vide():\n article = panier_temp.defile()\n self.enfile(article)\n
def prix_total(self):\n total = 0\n panier_temp = Panier()\n while not self.est_vide():\n article = self.defile()\n total += article[2]\n panier_temp.enfile(article)\n self.remplir(panier_temp)\n return total \n
def duree_passage_en_caisse(self):\n if self.est_vide():\n return None\n horaire_premier = self.defile()[3]\n while not self.est_vide():\n horaire_dernier = self.defile()[3]\n return horaire_dernier - horaire_premier \n
Exercice 6 Cet exercice est bas\u00e9 sur l'\u00e9nigme n\u00b05 d'Advent Of Code 2018.
Le but est de r\u00e9duire le plus possible une cha\u00eene de caract\u00e8res (comme dabAcCaCBAcCcaDA
) en ob\u00e9issant \u00e0 la r\u00e8gle suivante :
R\u00e8gle de simplification
D\u00e8s que deux lettres identiques mais de casse diff\u00e9rente (majuscule-minuscule ou minuscule-majuscule) sont c\u00f4te \u00e0 c\u00f4te dans la cha\u00eene, on les supprime de la cha\u00eene.
Exemple :
dabAcCaCBAcCcaDA On enl\u00e8ve le premier 'cC'.\ndabAaCBAcCcaDA Cela donne naissance \u00e0 un 'Aa', qu'on enl\u00e8ve.\ndabCBAcCcaDA On enl\u00e8ve alors 'cC' (ou 'Cc', cela revient au m\u00eame).\ndabCBAcaDA Plus aucune simplification n'est possible.\n
La cha\u00eene de caract\u00e8res qu'il va falloir simplifier contient ... 50000 caract\u00e8res.
Exercice 7
Exercice 3 du sujet Centres Etrangers J1 - 2023
Jeu du Simon
Correction Q1.def ajout(f):\n couleurs = (\"bleu\", \"rouge\", \"jaune\", \"vert\")\nindice = randint(0, 3)\nenfiler(f, couleur[indice])\nreturn f\n
Correction Q2. def vider(f):\n while not est_vide(f):\n defiler(f)\n
Correction Q3. def affich_seq(sequence):\n stock = creer_file_vide()\n ajout(sequence)\n while not est_vide(sequence):\nc = defiler(sequence)\naffichage(c)\ntime.sleep(0.5)\nenfiler(stock, c)\nwhile not est_vide(stock):\nenfiler(sequence, defiler(stock)) \n
Correction Q4.a. def tour_de_jeu(sequence):\naffich_seq(sequence)\nstock = creer_file_vide()\n while not est_vide(sequence):\n c_joueur = saisie_joueur()\nc_seq = defiler(sequence)\nif c_joueur == c_seq:\nenfiler(stock, c_seq)\nelse:\nvider(sequence)\nwhile not est_vide(stock):\nenfiler(sequence, defiler(stock))\n
Correction Q4.b. Question bizarre...
def tour_de_jeu_modifie(sequence):\n while True:\n affich_seq(sequence)\n stock = creer_file_vide()\n while not est_vide(sequence):\n c_joueur = saisie_joueur()\n c_seq = defiler(sequence)\n if c_joueur == c_seq:\n enfiler(stock, c_seq)\n else:\n vider(sequence)\n vider(stock)\n while not est_vide(stock):\n enfiler(sequence, defiler(stock))\n
ou bien
def tour_de_jeu_modifie(sequence):\n affich_seq(sequence)\n stock = creer_file_vide()\n while not est_vide(sequence):\n c_joueur = saisie_joueur()\n c_seq = defiler(sequence)\n if c_joueur == c_seq:\n enfiler(stock, c_seq)\n else:\n vider(sequence)\n print(\"Perdu ! On rejoue !\")\n tour_de_jeu_modifie(sequence)\n while not est_vide(stock):\n enfiler(sequence, defiler(stock))\n tour_de_jeu_modifie(sequence)\n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/Exercices/#1-elaboration-dune-fonction-utile","title":"1. \u00c9laboration d'une fonction utile","text":"On rappelle que la fonction ord
renvoie le code ASCII d'une lettre. En comparant les codes ASCII de deux lettres identiques mais de casse diff\u00e9rentes, en d\u00e9duire une fonction simplifiable
qui prend en param\u00e8tres deux lettres l1
et l2
et qui renvoie un bool\u00e9en indiquant si ces deux lettres sont simplifiables.
Exemples d'utilisation :
>>> simplifiable('c', 'C')\nTrue\n>>> simplifiable('C', 'c')\nTrue\n>>> simplifiable('C', 'C')\nFalse\n
Correction def simplifiable(l1, l2):\n return abs(ord(l1) - ord(l2)) == 32\n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/Exercices/#2-une-seule-simplification-de-la-chaine-de-caracteres","title":"2. Une seule simplification de la cha\u00eene de caract\u00e8res","text":"\u00c9crire une fonction simplifie
qui prend en param\u00e8tre une cha\u00eene de caract\u00e8re s
et qui renvoie cette m\u00eame cha\u00eene de caract\u00e8res, ayant \u00e9t\u00e9 simplifi\u00e9e une fois au maximum.
Principe : on parcourt la cha\u00eene et d\u00e8s qu'on trouve une simplification \u00e0 faire, on simplifie la cha\u00eene et on la renvoie imm\u00e9diatement.
Exemples d'utilisation :
>>> simplifie('dabAcCaCBAcCcaDA')\n'dabAaCBAcCcaDA'\n>>> simplifie('dabAaCBAcCcaDA')\n'dabCBAcCcaDA'\n>>> simplifie('dabCBAcCcaDA')\n'dabCBAcaDA'\n>>> simplifie('dabCBAcaDA')\n'dabCBAcaDA'\n
Pour information, on rappelle la technique de slicing de cha\u00eene de caract\u00e8res :
>>> ch = 'abcde'\n>>> ch[:2]\n'ab'\n>>> ch[2:]\n'cde'\n
Correction def simplifie(s):\n for i in range(len(s) - 1):\n if simplifiable(s[i+1], s[i]):\n return s[:i] + s[i+2:]\n return s\n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/Exercices/#3-resolution-du-probleme","title":"3. R\u00e9solution du probl\u00e8me","text":"Apr\u00e8s vous \u00eatre demand\u00e9 comment savoir facilement qu'une cha\u00eene n'\u00e9tait plus simplifiable, proposer une fonction reduction
qui prend en param\u00e8tre une cha\u00eene s
et qui renvoie cette cha\u00eene s
une fois effectu\u00e9es toutes les simplifications possibles.
Exemple d'utilisation :
>>> reduction('dabAcCaCBAcCcaDA')\n'dabCBAcaDA'\n
Correction def reduction(s):\n fini = False\n while not fini:\n s_temp = s\n s = simplifie(s)\n if len(s_temp) == len(s):\n fini = True\n return s\n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/Exercices/#4-le-vrai-enonce-dadvent-of-code","title":"4. Le vrai \u00e9nonc\u00e9 d'Advent of Code","text":"Dans cette \u00e9nigme n\u00b05, la r\u00e9ponse \u00e0 donner est le nombre de caract\u00e8res de la cha\u00eene une fois simplifi\u00e9e. Ce qui ne devrait pas nous poser de probl\u00e8me.
Par contre, la cha\u00eene 'dabAcCaCBAcCcaDA'
sur laquellle nous avons travaill\u00e9 n'est qu'un exemple... La vraie cha\u00eene contient 50000 caract\u00e8res :
Anecdotique ? Pas vraiment...
Effectuez la r\u00e9duction de cette cha\u00eene avec votre programme pr\u00e9c\u00e9dent. Que remarquez-vous ?
Corrections = 'YyLlXxYKkbNnQqBFfxXbyYWwBhHyYTCBbCjI...'\n\ndef simplifiable(l1, l2):\n return abs(ord(l1) - ord(l2)) == 32\n\ndef simplifie(s):\n for i in range(len(s) - 1):\n if simplifiable(s[i+1], s[i]):\n return s[:i] + s[i+2:]\n return s\n\ndef reduction(s):\n fini = False\n while not fini:\n s_temp = s\n s = simplifie(s)\n if len(s_temp) == len(s):\n fini = True\n return s\n\nprint(len(reduction(s)))\n
Le r\u00e9sultat (9370) est loooong \u00e0 nous parvenir ! (30 secondes sur ma machine)
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/Exercices/#5-sauve-par-une-pile","title":"5. Sauv\u00e9 par une pile","text":"Cet exercice peut \u00eatre r\u00e9solu beaucoup plus efficacement gr\u00e2ce \u00e0 l'utilisation d'une pile... mais comment ?
Vous pouvez utiliser l'impl\u00e9mentation de pile disponible ici.
Aide \u00e0 la construction de l'algorithmePour chaque lettre de la cha\u00eene :
s = 'YyLlXxYKkbNnQqBFfxXbyYWwBhHyYTCBbCjI...'\n\np = Pile() # ne pas oublier de r\u00e9cup\u00e9rer une impl\u00e9mentation de la classe Pile()...\n\ndef simplifiable(l1, l2):\n return abs(ord(l1) - ord(l2)) == 32\n\nfor lettre in s:\n if p.est_vide():\n p.empile(lettre)\n else:\n sommet = p.depile()\n if not simplifiable(sommet, lettre):\n p.empile(sommet)\n p.empile(lettre)\n\nprint(p.taille()) \n
Le r\u00e9sultat est cette fois imm\u00e9diat : 0.04 secondes sur ma machine, soit environ 1000 fois plus rapide que le code pr\u00e9c\u00e9dent.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/","title":"Listes, piles, files","text":"Exemples de structures de donn\u00e9es lin\u00e9aires.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#0-preambule-interface-implementation","title":"0. Pr\u00e9ambule : interface \u2260 impl\u00e9mentation","text":"
Les structures que nous allons voir peuvent s'envisager sous deux aspects :
Un exemple d'interface et d'impl\u00e9mentation
Nous avons d\u00e9j\u00e0 abord\u00e9 ces deux aspects lors de la d\u00e9couverte de la Programmation Orient\u00e9e Objet. Le principe d'encapsulation fait que l'utilisateur n'a qu'\u00e0 conna\u00eetre l'existence des m\u00e9thodes disponibles, et non pas le contenu technique de celle-ci. Cela permet notamment de modifier le contenu technique (l'impl\u00e9mentation) sans que les habitudes de l'utilisateur (l'interface) ne soient chang\u00e9es.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#1-structures-de-donnees-lineaires","title":"1. Structures de donn\u00e9es lin\u00e9aires","text":""},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#11-a-chaque-donnee-sa-structure","title":"1.1 \u00c0 chaque donn\u00e9e sa structure","text":"En informatique comme dans la vie courante, il est conseill\u00e9 d'adapter sa mani\u00e8re de stocker et de traiter des donn\u00e9es en fonction de la nature de celles-ci :
De m\u00eame en informatique, pour chaque type de donn\u00e9es, pour chaque utilisation pr\u00e9vue, une structure particuli\u00e8re de donn\u00e9es se rev\u00e8lera (peut-\u00eatre) plus adapt\u00e9e qu'une autre.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#111-donnees-lineaires","title":"1.1.1 Donn\u00e9es lin\u00e9aires","text":"Int\u00e9ressons nous par exemple aux donn\u00e9es lin\u00e9aires. Ce sont des donn\u00e9es qui ne comportent pas de hi\u00e9rarchie : toutes les donn\u00e9es sont de la m\u00eame nature et ont le m\u00eame r\u00f4le. Par exemple, un relev\u00e9 mensuel de temp\u00e9ratures, la liste des \u00e9l\u00e8ves d'une classe, un historique d'op\u00e9rations bancaires...
Ces donn\u00e9es sont \u00abplates\u00bb, n'ont pas de sous-domaines : la structure de liste para\u00eet parfaitement adapt\u00e9e.
Lorsque les donn\u00e9es de cette liste sont en fait des couples (comme dans le cas d'une liste de noms/num\u00e9ros de t\u00e9l\u00e9phone), alors la structure la plus adapt\u00e9e est sans doute celle du dictionnaire.
Les listes et les dictionnaires sont donc des exemples de structures de donn\u00e9es lin\u00e9aires.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#112-donnees-non-lineaires","title":"1.1.2 Donn\u00e9es non-lin\u00e9aires","text":"M\u00eame si ce n'est pas l'objet de ce cours, donnons des exemples de structures adapt\u00e9es aux donn\u00e9es non-lin\u00e9aires :
Si une liste de courses est subdivis\u00e9e en \"rayon frais / bricolage / papeterie\" et que le rayon frais est lui-m\u00eame s\u00e9par\u00e9 en \"laitages / viandes / fruits & l\u00e9gumes\", alors une structure d'arbre sera plus adapt\u00e9e pour la repr\u00e9senter. Les structures arborescentes seront vues plus tard en Terminale.
Enfin, si nos donn\u00e9es \u00e0 \u00e9tudier sont les relations sur les r\u00e9seaux sociaux des \u00e9l\u00e8ves d'une classe, alors la structure de graphe s'imposera d'elle-m\u00eame. Cette structure sera elle-aussi \u00e9tudi\u00e9e plus tard cette ann\u00e9e.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#12-comment-seront-traitees-ces-donnees-lineaires-introduction-des-listes-des-piles-et-des-files","title":"1.2 Comment seront trait\u00e9es ces donn\u00e9es lin\u00e9aires ? Introduction des listes, des piles et des files","text":"La nature des donn\u00e9es ne fait pas tout. Il faut aussi s'int\u00e9resser \u00e0 la mani\u00e8re dont on voudra les traiter :
Lorsque ces probl\u00e9matiques d'entr\u00e9e/sortie n'interviennent pas, la structure \u00abclassique\u00bb de liste est adapt\u00e9e. Mais lorsque celle-ci est importante, il convient de diff\u00e9rencier la structure de pile de celle de file.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#121-les-piles-stack","title":"1.2.1 Les piles (stack)","text":"Une structure de pile (penser \u00e0 une pile d'assiette) est associ\u00e9e \u00e0 la m\u00e9thode LIFO (Last In, First Out) : les \u00e9l\u00e9ments sont empil\u00e9s les uns au-dessus des autres, et on ne peut toujours d\u00e9piler que l'\u00e9l\u00e9ment du haut de la pile. Le dernier \u00e9l\u00e9ment \u00e0 \u00eatre arriv\u00e9 est donc le premier \u00e0 \u00eatre sorti.
Exemples de donn\u00e9es stock\u00e9es sous forme de pile
Une structure de file (penser \u00e0 une file d'attente) est associ\u00e9e \u00e0 la m\u00e9thode FIFO (First In, First Out) : les \u00e9l\u00e9ments sont enfil\u00e9s les uns \u00e0 la suite des autres, et on ne peut toujours d\u00e9filer que l'\u00e9l\u00e9ment du haut de la file. Le premier \u00e9l\u00e9ment \u00e0 \u00eatre arriv\u00e9 est donc le premier \u00e0 en sortir. Sinon \u00e7a r\u00e2le dans la file d'attente.
Exemples de donn\u00e9es stock\u00e9es sous forme de file :
Dans les entrep\u00f4ts de stockage, comme dans les rayons d'un supermarch\u00e9, la structure naturelle est celle de la pile : les gens attrapent l'\u00e9l\u00e9ment situ\u00e9 devant eux (\u00aben haut de la pile\u00bb). Si les employ\u00e9s du supermarch\u00e9 remettent en rayon les produits plus r\u00e9cents sur le dessus de la pile, les produits au bas de la pile ne seront jamais choisis et p\u00e9rimeront. Ils doivent donc transformer la pile en file : lors de la mise en rayon de nouveaux produits, ceux-ci seront plac\u00e9s derri\u00e8re (\u00abau bas de la file\u00bb) afin que partent en priorit\u00e9 les produits \u00e0 date de p\u00e9remption plus courte. On passe donc du LIFO au FIFO.
Certains dispositifs permettent de le faire naturellement : Ci-dessous, une file... de piles (\u00e9lectriques). Le chargement par le haut du distributeur fait que celle qui sera sortie (en bas) sera celle qui aura \u00e9t\u00e9 rentr\u00e9e en premier (par le haut). Ce FIFO est donc provoqu\u00e9 naturellement par la gravit\u00e9 (et un peu d'astuce). On notera que cette probl\u00e9matique est universelle : voir par exemple ce site.
Apr\u00e8s avoir pr\u00e9sent\u00e9 rapidement ces trois types de donn\u00e9es lin\u00e9aires, nous allons maintenant les \u00e9tudier plus en d\u00e9tail, et proposer pour chacune d'elles une interface et plusieurs impl\u00e9mentations.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#2-les-listes","title":"2. Les listes","text":""},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#21-definition-generale","title":"2.1 D\u00e9finition g\u00e9n\u00e9rale","text":"Une liste est un ensemble ordonn\u00e9 d'objets. G\u00e9n\u00e9ralement, ces donn\u00e9es seront de m\u00eame type, mais ce n'est pas structurellement obligatoire.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#22-les-listes-chainees-linked-lists","title":"2.2 Les listes cha\u00een\u00e9es (linked lists)","text":"Lorsque l'impl\u00e9mentation de la liste fait appara\u00eetre une cha\u00eene de valeurs, chacune pointant vers la suivante, on dit que la liste est une liste cha\u00een\u00e9e.
Impl\u00e9mentation choisie :
x
ou bien None
sur les sch\u00e9mas)Une cons\u00e9quence de cette impl\u00e9mentation sous forme de liste cha\u00een\u00e9e est la non-constance du temps d'acc\u00e8s \u00e0 un \u00e9l\u00e9ment de liste : pour acc\u00e9der au 3\u00e8me \u00e9l\u00e9ment, il faut obligatoirement passer par les deux pr\u00e9c\u00e9dents.
\u00c0 retenir : dans une liste cha\u00een\u00e9e, le temps d'acc\u00e8s aux \u00e9l\u00e9ments n'est pas constant.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#23-exemple-dimplementation-minimale-dune-liste-chainee","title":"2.3 Exemple d'impl\u00e9mentation minimale d'une liste cha\u00een\u00e9e","text":"Exemple fondateur : impl\u00e9mentation d'une liste chain\u00e9e en POO
class Cellule :\n def __init__(self, contenu, suivante):\n self.contenu = contenu\n self.suivante = suivante\n
Cette impl\u00e9mentation rudimentaire permet bien la cr\u00e9ation d'une liste :
>>> lst = Cellule(3, Cellule(5, Cellule(1,None)))\n
La liste cr\u00e9\u00e9e est donc :
Mais plus pr\u00e9cis\u00e9ment, on a :
Exercice 1
\u00c9nonc\u00e9CorrectionRetrouvez comment acc\u00e9der aux \u00e9l\u00e9ments 3, 5 et 1.
>>> lst.contenu\n3\n>>> lst.suivante.contenu\n5\n>>> lst.suivante.suivante.contenu\n1\n
On pourra remarquer que l'interface propos\u00e9e \u00e0 l'utilisateur n'est pas des plus pratiques...
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#24-et-les-listes-de-python","title":"2.4 Et les listes de Python ???","text":"Nous connaissons d\u00e9j\u00e0 les listes de Python :
>>> maliste = [3, 1, -1, 42]\n
Et nous connaissons aussi (un peu) l'interface de ce type list
, notamment avec les m\u00e9thodes append()
ou reverse()
. N\u00e9anmoins, l'impl\u00e9mentation qui a \u00e9t\u00e9 choisie par les concepteurs de Python de ce type list
fait que le celui-ci se rapproche plus d'un tableau dynamique.
Dans un tableau dynamique :
Dans une liste cha\u00een\u00e9e :
Nous nous servirons parfois du type list
de Python dans la suite de ce cours, mais il ne faut pas oublier qu'il n'est pas un \u00abvrai\u00bb type list
.
Imaginons que nous poss\u00e9dons une interface offrant les fonctionnalit\u00e9s suivantes :
Liste()
: cr\u00e9e une liste vide.est_vide
: indique si la liste est vide. (renvoie un bool\u00e9en)ajoute_tete
: ins\u00e8re un \u00e9l\u00e9ment (pass\u00e9 en param\u00e8tre) en t\u00eate de liste. (ne renvoie rien)renvoie_tete
: renvoie la valeur de l'\u00e9l\u00e9ment en t\u00eate de liste ET le supprime de la liste.Exercice 2
\u00c9nonc\u00e9CorrectionOn consid\u00e8re l'encha\u00eenement d'op\u00e9rations ci-dessous. \u00c9crire \u00e0 chaque \u00e9tape l'\u00e9tat de la liste lst
et la valeur \u00e9ventuellement renvoy\u00e9e.
1. lst = Liste() \n2. lst.ajoute_tete(3)\n3. lst.ajoute_tete(5) \n4. lst.ajoute_tete(1) \n5. lst.renvoie_tete() \n6. lst.est_vide() \n7. lst.ajoute_tete(2) \n8. lst.renvoie_tete() \n9. lst.renvoie_tete() \n10. lst.renvoie_tete()\n11. lst.est_vide() \n
1. lst = Liste() # lst = None\n2. lst.ajoute_tete(3) # lst = 3\n3. lst.ajoute_tete(5) # lst = 3 5 \n4. lst.ajoute_tete(1) # lst = 3 5 1\n5. lst.renvoie_tete() # lst = 3 5 valeur renvoy\u00e9e : 1\n6. lst.est_vide() # valeur renvoy\u00e9e : False\n7. lst.ajoute_tete(2) # lst = 3 5 2\n8. lst.renvoie_tete() # lst = 3 5 valeur renvoy\u00e9e : 2\n9. lst.renvoie_tete() # lst = 3 valeur renvoy\u00e9e : 5\n10. lst.renvoie_tete()# lst = None valeur renvoy\u00e9e : 3\n11. lst.est_vide() # valeur renvoy\u00e9e : True\n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#3-les-piles","title":"3. Les piles","text":"Comme expliqu\u00e9 pr\u00e9c\u00e9demment, une pile travaille en mode LIFO (Last In First Out). Pour \u00eatre utilis\u00e9e, l'interface d'une pile doit permettre a minima :
Exercice 3
\u00c9nonc\u00e9CorrectionOn consid\u00e8re l'encha\u00eenement d'op\u00e9rations ci-dessous. \u00c9crire \u00e0 chaque \u00e9tape l'\u00e9tat de la pile p
et la valeur \u00e9ventuellement renvoy\u00e9e.
Bien comprendre que la classe Pile()
et ses m\u00e9thodes n'existent pas vraiment. Nous jouons avec son interface.
On prendra pour convention que la t\u00eate de la pile est \u00e0 droite.
1. p = Pile() \n2. p.empile(3) \n3. p.empile(5) \n4. p.est_vide() \n4. p.empile(1) \n5. p.depile() \n6. p.depile() \n7. p.empile(9) \n8. p.depile() \n9. p.depile() \n10. p.est_vide() \n
1. p = Pile() # p = None\n2. p.empile(3) # p = 3\n3. p.empile(5) # p = 3 5 par convention\n4. p.est_vide() # False\n4. p.empile(1) # p = 3 5 1\n5. p.depile() # p = 3 5 valeur renvoy\u00e9e : 1\n6. p.depile() # p = 3 valeur renvoy\u00e9e : 5\n7. p.empile(9) # p = 3 9\n8. p.depile() # p = 3 valeur renvoy\u00e9e :9\n9. p.depile() # p est vide valeur renvoy\u00e9e : 3\n10. p.est_vide() # True\n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#32-implementations-dune-pile","title":"3.2 Impl\u00e9mentation(s) d'une pile","text":"L'objectif est de cr\u00e9er une classe Pile
. L'instruction Pile()
cr\u00e9era une pile vide. Chaque objet Pile
disposera des m\u00e9thodes suivantes :
est_vide
: indique si la pile est vide (renvoie un bool\u00e9en)empile
: ins\u00e8re un \u00e9l\u00e9ment (pass\u00e9 en param\u00e8tre) en haut de la pile. Ne renvoie rien.depile
: renvoie la valeur de l'\u00e9l\u00e9ment en haut de la pile ET le supprime de la pile.Ces 3 m\u00e9thodes sont essentielles et se retrouveront syst\u00e9matiquement dans chaque interface. Nous y ajouterons, uniquement par commodit\u00e9, la m\u00e9thode suivante :
__repr__
: permet d'afficher la pile sous forme agr\u00e9able (par ex : |3|6|2|5|
)list
de Python","text":"Exercice 4
\u00c9nonc\u00e9CorrectionCr\u00e9er la classe Pile
ci-dessus.
Le type list
de Python est parfaitement adapt\u00e9. Des renseignements int\u00e9ressants \u00e0 son sujet peuvent \u00eatre trouv\u00e9s ici.
Correction
class Pile:\n def __init__(self):\n self.data = []\n\n def est_vide(self):\n return len(self.data) == 0 \n\n def empile(self,x):\n self.data.append(x)\n\n def depile(self):\n if self.est_vide():\n print('Vous avez essay\u00e9 de d\u00e9piler une pile vide !')\n return None\n else :\n return self.data.pop() \n
class Pile:\n def __init__(self):\n self.data = []\n\n def est_vide(self):\n return len(self.data) == 0 \n\n\n def empile(self,x):\n self.data.append(x)\n\n def depile(self):\n if self.est_vide():\n print('Vous avez essay\u00e9 de d\u00e9piler une pile vide !')\n return None\n else :\n return self.data.pop() \n\n def __repr__(self): # Hors-Programme : pour afficher \n s = '|' # convenablement la pile avec p\n for k in self.data :\n s = s + str(k) + '|'\n return s \n
Test de l'impl\u00e9mentation : >>> p = Pile()\n>>> p.empile(5)\n>>> p.empile(3)\n>>> p.empile(7)\n>>> p\n|5|3|7|\n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#322-a-laide-dune-liste-chainee-et-de-la-classe-cellule-creee-au-23","title":"3.2.2 \u00c0 l'aide d'une liste cha\u00een\u00e9e et de la classe Cellule
cr\u00e9\u00e9e au 2.3","text":"Au 2.3 nous avons cr\u00e9\u00e9 la classe Cellule
:
class Cellule :\n def __init__(self, contenu, suivante):\n self.contenu = contenu\n self.suivante = suivante\n
Exercice 5
\u00c9nonc\u00e9Correction\u00c0 l'aide cette classe, re-cr\u00e9er une classe Pile
disposant exactement de la m\u00eame interface que dans l'exercice pr\u00e9c\u00e9dent.
class Cellule :\ndef __init__(self, contenu, suivante):\n self.contenu = contenu\n self.suivante = suivante\n\nclass Pile:\n def __init__(self):\n self.data = None\n\n def est_vide(self):\n return self.data == None\n\n def empile(self, val):\n self.data = Cellule(val, self.data)\n\n def depile(self):\n v = self.data.contenu #on r\u00e9cup\u00e8re la valeur \u00e0 renvoyer\n self.data = self.data.suivante # on supprime la 1\u00e8re cellule \n return v\n\n def __repr__(self):\n s = '|'\n c = self.data\n while c != None :\n s += str(c.contenu) + '|'\n c = c.suivante\n return s\n
Test de l'impl\u00e9mentation :
>>> p = Pile()\n>>> p.empile(5)\n>>> p.empile(3)\n>>> p.empile(7)\n>>> p\n|7|3|5|\n
\u00c0 retenir : pour l'utilisateur, les interfaces du 3.2.1 et 3.2.2 sont strictement identiques. Il ne peut pas savoir, en les utilisant, l'impl\u00e9mentation qui est derri\u00e8re.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#33-application-des-piles","title":"3.3 Application des piles","text":"Exercice 6
\u00c9nonc\u00e9CorrectionSimulez une gestion de l'historique de navigation internet, en cr\u00e9ant une classe Nav
qui utilisera une pile. Attention, il ne faut pas r\u00e9inventer la classe Pile
, mais uniquement s'en servir !
Exemple d'utilisation :
>>> n = Nav()\n>>> n.visite('lemonde.fr')\npage actuelle : lemonde.fr\n>>> n.visite('google.fr')\npage actuelle : google.fr\n>>> n.visite('lyceemauriac.fr')\npage actuelle : lyceemauriac.fr\n>>> n.back()\npage quitt\u00e9e : lyceemauriac.fr\n>>> n.back()\npage quitt\u00e9e : google.fr\n
class Nav:\n def __init__(self):\n self.pile = Pile()\n\n def visite(self, page):\n self.pile.empile(page)\n print('page actuelle :', page)\n\n def back(self):\n page_quittee = self.pile.depile()\n print('page quitt\u00e9e :', page_quittee)\n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#4-les-files","title":"4. Les files","text":"Comme expliqu\u00e9 pr\u00e9c\u00e9demment, une file travaille en mode FIFO (First In First Out). Pour \u00eatre utilis\u00e9e, une interface de file doit proposer a minima :
La repr\u00e9sentation la plus courante d'une file se fait horizontalement, en enfilant par la gauche et en d\u00e9filant par la droite :
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#41-utilisation-dune-interface-de-file","title":"4.1 Utilisation d'une interface de file","text":"Exercice 7
\u00c9nonc\u00e9CorrectionOn consid\u00e8re l'encha\u00eenement d'op\u00e9rations ci-dessous. \u00c9crire \u00e0 chaque \u00e9tape l'\u00e9tat de la file f
et la valeur \u00e9ventuellement renvoy\u00e9e. Par convention, on enfilera \u00e0 gauche et on d\u00e9filera \u00e0 droite.
1. f = File()\n2. f.enfile(3) \n3. f.enfile(5)\n4. f.est_vide()\n5. f.enfile(1) \n6. f.defile() \n7. f.defile()\n8. f.enfile(9) \n9. f.defile() \n10. f.defile()\n11. f.est_vide() \n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#42-implementation-dune-file","title":"4.2 Impl\u00e9mentation d'une file","text":"L'objectif est de cr\u00e9er une classe File
, disposant des m\u00e9thodes suivantes :
est_vide
: indique si la file est vide. (renvoie un bool\u00e9en)enfile
: ins\u00e8re un \u00e9l\u00e9ment (pass\u00e9 en param\u00e8tre) en queue de file. (ne renvoie rien)defile
: renvoie la valeur de l'\u00e9l\u00e9ment en t\u00eate de la file ET le supprime de la file.Nous y ajouterons comme pr\u00e9c\u00e9demment la m\u00e9thode facultative suivante :
__repr__
: permet d'afficher la file sous forme agr\u00e9able (par ex : |3|6|2|5|
)Exercice
\u00c9nonc\u00e9CorrectionCr\u00e9er la classe ci-dessus. L\u00e0 encore, le type list
de Python est peut \u00eatre utilis\u00e9.
Penser \u00e0 aller voir ici les m\u00e9thodes des objets de types list
, notamment la m\u00e9thode insert
.
class File:\n def __init__(self):\n self.data = []\n\n def est_vide(self):\n return len(self.data) == 0 \n\n def enfile(self, x):\n self.data.insert(0, x)\n\n def defile(self):\n if self.est_vide():\n print('Vous avez essay\u00e9 de d\u00e9filer une file vide !')\n return None\n else :\n return self.data.pop() \n\n def __repr__(self): # Hors-Programme : pour afficher \n s = '|' # convenablement la file\n for k in self.data:\n s = s + str(k) + '|'\n return s\n
>>> f = File()\n>>> f.enfile(5)\n>>> f.enfile(8)\n>>> f\n|8|5|\n>>> f.defile()\n5\n
Remarque : Notre impl\u00e9mentation r\u00e9pond parfaitement \u00e0 l'interface qui \u00e9tait demand\u00e9e. Mais si le \u00abcahier des charges\u00bb obligeait \u00e0 ce que les op\u00e9rations enfile()
et defile()
aient lieu en temps constant (en \\(O(1)\\)), notre impl\u00e9mentation ne conviendrait pas.
En cause : notre m\u00e9thode enfile()
agit en temps lin\u00e9aire (\\(O(n)\\)) et non pas en temps constant. L'utilisation de la structure de \u00abliste\u00bb de Python (les tableaux dynamiques) provoque, lors de l'instruction self.data.insert(0, x)
un redimensionnement de la liste. Le tableau doit \u00eatre agrandi et chaque \u00e9l\u00e9ment doit \u00eatre recopi\u00e9 dans la case suivante. Ceci nous co\u00fbte un temps lin\u00e9aire.
Comment cr\u00e9er une file avec 2 piles ? L'id\u00e9e est la suivante : on cr\u00e9e une pile d'entr\u00e9e et une pile de sortie.
# il est imp\u00e9ratif de comprendre qu'on peut choisir l'impl\u00e9mentation\n# de la classe Pile qu'on pr\u00e9f\u00e8re parmi les deux trait\u00e9es plus haut.\n# Comme elles ont la M\u00caME INTERFACE et qu'on ne va se servir que\n# de cette interface, leur m\u00e9canisme interne n'a aucune influence\n# sur le code de la classe File que nous ferons ensuite.\n\n# Par exemple, on choisit celle avec la liste cha\u00een\u00e9e :\n\nclass Cellule :\n def __init__(self, contenu, suivante):\n self.contenu = contenu\n self.suivante = suivante\n\n\nclass Pile:\n def __init__(self):\n self.data = None\n\n def est_vide(self):\n return self.data == None\n\n def empile(self, x):\n self.data = Cellule(x, self.data)\n\n def depile(self):\n v = self.data.contenu #on r\u00e9cup\u00e8re la valeur \u00e0 renvoyer\n self.data = self.data.suivante # on supprime la 1\u00e8re cellule \n return v\n\n def __str__(self):\n s = \"|\"\n c = self.data\n while c != None :\n s += str(c.contenu)+\"|\"\n c = c.suivante\n return s\n\n# ------------------------------------------------------- \n# Impl\u00e9mentation d'une file \u00e0 l'aide de deux piles \n\nclass File:\n def __init__(self):\n self.entree = Pile()\n self.sortie = Pile()\n\n def est_vide(self):\n return self.entree.est_vide() and self.sortie.est_vide()\n\n def enfile(self,x):\n self.entree.empile(x)\n\n def defile(self):\n if self.est_vide():\n print(\"File vide !\")\n return None\n\n if self.sortie.est_vide():\n while not self.entree.est_vide():\n self.sortie.empile(self.entree.depile())\n\n return self.sortie.depile()\n
>>> f = File()\n>>> f.enfile(5)\n>>> f.enfile(8)\n>>> f.defile()\n5\n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#bibliographie","title":"Bibliographie","text":"s = 'YyLlXxYKkbNnQqBFfxXbyYWwBhHyYTCBbCjIiqwtTWQJczeEauUAZDdFfmwWMccbBOojBbXxKnNkkKsSeEsxXmxlpPLXMuULlSJqnSsNQmMmMCYyXDdvVDdtTxYmBbsSNdDnyYaAOBbouUwWiIMyYzZyPptGDbpoOPBdnNtTapPeEAHhrXxRtSjJsTPpepPGgCcEfFenNEmMGUpPugCanNAnNcEzZTtQqZzRreMmpzPpzZZJbBjxXTtEcCemMPJjXxhHTtydDmIOolLiJQqHhkKMmjVeEsSWwnNQqsNgGnLkKlcCSvdVvcCDeWPpwEvVUuNnTGhHgVZEenNQqRrTtSspjJPHhcNnYyCwoOHhcFJjaAXxDdqQfTnbBNtSsyLlYCGgWEezZiufFUhHHSshkKTvVoOtIfFTbBtTyYeqQEZnNztDdNnxYytFflLTWwSgGsmsSMXzvIikeEfFpPKdDccCTtFfqlRrLQgGqxyYXQCpuUPkQqKTeEtSsXmMmMxVDdWweuUEyYtFfboOBbBbBTuBbrReEKfAaFkoeEtTYyRroOQqcCjYyYycCtTJOLVvkKWwYylukKqnFfilEeXxLgVvqQGINQZJjlnNLzVvKkpjkKJPsSBIibQmMqXQqHhrTtRayYAECczgGZeHhFfMCbBcVvfFZzRrNlLwQqZzWnjUukKxXkKFfJuUzZqQyYfPpiIOojJFNZzhHlLnVfFvwYHhyWMmOUuqtTARWwrZNnzasSzYLlyCBbcLlKkoOZZzIiKkQiqQIRiIkKrgFfpPnexXEPpNTtOobgGBEeCDdcoOQqGQCUuhoOSnNsbBWwfFwiIFfEeZzWQEIieSmMaAsFfEeSsHKkhjOoJmvVMlLGtvVTTWwtgXSsxpPIZziKHhXXCLlcxyaeEcCAYxkLlCcEefOoFLlWweEyOnNojJZzYcXxmMWwXxydXxDFfgGYGGgxOpPoUuXRrgplLPWwqLlQEQYylLqgSsjJDsSIidIVviGnNaAFfelLVvdDHsShmCcroOOoJjSsQqqQHVFfvhiqQeEWmnNzZjJJbtTBsSjGgoOMKDdfqxXQFjJmMitTIcCkcCwrRxnNFfvVXIRDdJAXxahHZzJjzZBbjjbBJhuUAaxXHMwpPfFmMcCfuUyAfFauZUuuUzRrUjJuPZzfKlLdDhsSSsAatyYaAHhTbnNBbBQqmmiFfIxOZzoXAaAaWwMWwzZaAMhrRHHsNnSBboEeXCcxOrAaZzsSRkLqzZQPplFaIiAhHZzwWMmEeWwnplLmMQXDdYsSyWwxHhRrWwoOKhoOltTLHAaDdkgGLkKlquUPpXxdnNrRpXxPbNnbVviIGgBBzFfZIiwWDCcGggJjiIGxXxQGgqQqteENwWnTiIAAaaSsNnTVPpbBFfvtXCcDuUdDdBdhHKOokiWSCcswIcCcCKkoPSspOWwUkKuAaKkoOwhAawWaALlHCcWcJYyKkMmMmhHzZjvVtThHCDYyALlNnrRGcCVvpPgvCcMmVLhwWuUmMHUupPladDHhNnpPMTtmazZvVAakUuxXKDmMZzdGgLlABbNnMmWqQRrvVeEjSsJwJMmjTwAEQqeFfRrQqQqaqQdaADWGgtFfacCaBboVvZzDdOZzTtgGOFfGgoqBWwbxXZzsBVVvDnNhHXxdvZwWzOrRosSEeyYVvUuEebWwoOXxUuQqTqQtBbiIEXxeBHQqtTiIxXRZCtTchHQqzBktTKIitTNvVnYZzysEeSMBbKAjJpPFfavxLlXVQqKkDEMmYyenNXxtTlYbFfByLIiQqKkGPhHpFaxXAfglLYySsBpPvVbyYdnNyyYYKkXzZeEeEWwRxXreEgGUusHCPpczJjZOohsSpWtTwgGPKkvVFpPVvfSsOMmnPpNoOozezNnZksMmSIiaAEeGgoOpPuUWwDYcsYySPXCcYyoUNnCcuOZzLbBlAGguxnNwWvHhVXsPaApSPpQOoKtTVvExXekOmMoOooZzOOoIihQqHCcqmzIiZMQHhqTsSQqfFtxzwWrReETtmwNsOxXovVAeJjEaSnWMSNtTnsWsSwaAvVZJrRjfFnaANDdYzlLOoQqZysrRtTwvVWSRdAkXxKarvqQVgpPGOomkPpKMHhpPlkKDdpPLSszLlZyYBbxgGUuCdDeEcaACcXCclLRLllLIigGmMrRXxBbCcOoeELnNbBKxDdXHhkmMlTtpeEPQqzZDnNIiDBhqApPaQnNcpPCiSsqQIHiqQTsLnNlWKkNnwtWwAaThHFfGuUgSLsRrSliItFfDduQqSstTwcCKkWUhHLlSoGrbBOoRgWCcwgVvGtKkhPpBbHSsKkTFfUZEekKfcCWwHhYyFbBaAzuFrRAHvrReEVlLFfhaisVvSHvVXxlLjEeJJjgGjdDcCJhWwKkmMSXPpxsKzZwAaWkttTTaSapPXKkkrRhkgzZGCcKxXHuUKZWwzZzSsxdbBDXKkxfTtIiAaFhHmxXMnNJjUuxeEXuGgUuUzuUZjJvbBVtTpUuYykKPnNfFGGKkgoOxXggFfGrJjRoOaAOodHhxnNXcPtQqAaTmMZbBzpXeEdmzZmMkTtpPKFeEedDdDEhHqubBUQYQqykKcrRCfMSsAnPzZTtpuUNWwIiuURrdDaeECgGcyYzMIimXQqqaAQnJjwWaAeEKqQBCDdeEfeEGgaPpbBAhHKKkbmMBkOouCcrlcCdDsSLRmYyNnSRgGiFfIrcOHhUugGzZTdDtVPGgpvGgXxouLlNnlLUGgwZzHWwhPptTWfiFWwfoOsSIvsZzSVsSuSsUFGgETTkKzZtteJdIiDlLlLugjTiItFfJNnwWGiIlLKkTtnNDsSdpPUeEeEJjgGPSspzZbcjJCBAaeVPpLfSsFTXxtlBbhkFkKfuUQqKNnHkKMSshQqVvOpPrRXxZzSzZsZzHhNnWWwwqQUuBLlyYrRgGfTtFrxXUuEeYyUuKvVdDkqURFfFlLfxfFXmkKMCZAaYyTgGAatzcrNOoIntTNisSnrJjUuRHTthwWwByYmMDhHqQWzOjJoZwdhHFfboOdVvNdFDdOjJoeEOoIihHfqCcQaAmMcoJjZsDAadSeEzOSsCGeEUAcCaFaAtTnNYvVUuyZzLoiIcCOlhHfVvUuIicCeEDsSdDdrREeESsejWNnWwGgOdDuUfFcClLMEHhZzemtTEvVeXxGpPgSOUudDNfFPpnyrROoYEMmeyiIYoqVvuUJNnDdjQGgofFAaOuXKklfFdDmMLAauUSwWrXxRhHBWQqwbseEeExXbnNCcBEgGVCXQqxcwWvPPHhpraARICcQqwQPpqsStTWAaDdQxDdBbXlZzLbBdtsCcOoSOoaAEeHTthlcdDCLuUTDksSKktTqQvWOowhHCkKbxVvwWXCOoDdYycPpcPpNnCIIiiulIieELCcPrRCUujJGNMmngfFTcCvVdUuDtjJtTfNniwmMmMVvNnosSVvLlOWmMHXxWpPwXxgGhaAJjvpPlLigGBbCMmHhcIkKDuUdDeOoqaAQEJKkjrRyYzZIifFkKKRruVvNneTtpPuUEkKYIiyqCpPfFpPLlFfTtnahjJHANUuhNnIidoOpPycZHhznSsYytTUujJhHNCqzZBwKkWEejJCcHDdSshRrOwWohHbCcmabBAmMMXdDcJjCtlLTUuZztBNnbxXTuUSxwWjJXsYyLlHhMmhyYKsSkBjCcJHhMZzUuvSVvZzCcehHEFEeftnIiRrNTqVvmIiugGUTSstSsVNnDdhVkKveEHwWzZvAagGXxipPaAIvVhHhDjJBbdtTWbBFfwdDQqVHhtTtkvrptTrRPRzWgGwrRjJxtbYyqQhHBePpFfELVXxeEvNnlXjJgGxGKkgoDYypPpNnPdlwCcWzNnsSZLwcCoOrvVKkJjdDdTtDiyYyYItqQTyYmMwWSYHhrDdufkJjhHWvVwpwWylPMmzZpLESsmjJMeBbaAWwJjuQqMJjXeEaAaFffFFhnNCcZdDYyzeGgESTtoKkBbmhHedDFfHhcCdDWAawlEVvXDdxlVvioOIOYyogKkbBGLHWwhWwpPWwxRrXflLPWCciTtCcNnNmMNnnSsYyqyYlpPIiBbLrfFRmMVvQIFfZzduwtJjyMmbCNnsScCmMmptSOoEeoXuUxOsKkEWuVyYuUPpQpcCPtRrcCtFfKcCfZRrzdDFkSFYyfMmsftTlEeLECMRrmcTtQGKkgqCMNnLlxYyXaPuUcCaAqQtTAEeaMmpZznvWwVTtUkKuRrIiUuJjtTwfFjJWsSjJttTTNjJqQtIiTkMKIikmyxwWXYPLgGRccCCrPpTEetNniINnpPBzZbFFffBBbaAbOFrRfXxpRZzrFfPxyWwYUVjJvuMmPpXxxXBODdoPpGmMbSIisBgejJEwWbgGXXxxoOtTJjcHsShgGxXCzFAafsSAaZUuxTBiOooOuULlUDduDdFQqfIbdjJuUrWzZiIPFVvDdiIfpwGfFsBnBtTbvVsSNJYyXFfxbyYCPtTpKHkKzxXCcZUuuUKECcyYCcZzeIoiIMOpkKPfFdDYywWouUAjJaFtTfxXjZbBzJvFfyYjJOoMmCceBbKkEkKLlxmxXMCcCcMryYRGDdOogzQFfqHEbBtOoNOCcstTNnSoDSGgseUuLlExbdDBXkKLlJuSbBbcrRCdDBaAsWaAwtTBbVZzvqiIMmuUHtTwWfFFFfKkqQxYRWwYyeEfbBVviGzZQqCRrsSXDdxXxcvTtHOotThkKPptTpZzPCcVfFnNzIiZyIMmiVvUuYwHhuUjJdDWfQXkKxMmCtTcFfhiIDdHdsSDFEefqZzKkQROorqyZVvzRtKHWwmMjbBJUuKkRPprLlfgnNpKoOMmTtaALlbBHWdDGgwhQqOqxXiIIiYyDdzZrGcaAFfhHxEeNnpqqQQTMmqmMrlLTIeGgEmGgMZzWwATtavnNsaPpGgASZzVhHOLLbBlwWkKYyiVlFfLoOtlLTFfCOoVvjJcYkKXxpJjPHhmMZzyUaAuNNnvVtTzSsbpaAPBDwWGgbBFarzZRAfBwSRrkaACcrRizZIKkiuUQqWwIXxKQqpPzzfFZZnNnNyDdVvCmbpPYkKAZzaDuUdXQdDqzJuUTVvoOteERrdDoQqcCcbBwGgdDvcCKkVEZkKzeRrdhHCcDHhkYyATtagGVvbBFBqQBbQSsUuAjTjJvGzZpGgPCbTXnNwWJjbBhtjJmMPpQqqQuUBbEWweYKkyTXxxJIivRrvhHXxRriIIqQijJVlLIOfZzlsSLQqdyYvVJIijHTBBbbmIimMlLNnMxgGXYypPTwWteUvFGgfpPVHhoOOjJohCKkcAawPpWsSeBfFJjyYbAYyKdDbJjBPJjZzUjJTtuzLeEgjJIsSiGiIbBRrMJjCcbgGJjxRrXmMgGinNfgGFxuUkKCceEMPpmXIdDBuBbUKoOkuUXgGxEexrRxQqXXodDdDWeebBEPpxXxoOXboOqQDdBhHJRPpuUQqrjJiIXxsSjaALlSsuyYUXhHHJhbBzZPplLdFfyYDwWbauYySSssUaAASBbsJjUtTulRgVvGJjeEmFYypPZzPpqTtzSuxXBbUmMVKkvRroOwVUuiIfpPVvXxbBYAaHhGIMmjJdQqqQDisVSsvUugGSyYsSPiIpsWwhHSHhciICujJUJBbyQEhHeafFWwooOOFIimMXrRxyWFfBbQqqQwNnZaAzRrwmHYmMyxXhzAaZvVbBTEetMQGgqXxWZmMZzzRrNnXzZOoxfFJjgGgGTPpgddDYyDSsIixDdXSGgsguUMiImGymMCcyYoOPCcwNnWpiIYyjEerXxAadDKkNuUQqnQuUOoqSswDdEeXeExWoOjIGCcOolqbBQEeMmmMLFHhAJjWwvVcCnNqQaqQunNrRUXxrRQOIiuBbkEecCLREenNrjDdRrDnNwWTtzlLMmuaAIqeLKcmHCsSBbFfchQqfTtFMIijDdCKXxHPvVRrWweMmLlrREqvxXVQSsSprRPPpsyYjKdkKDNzFfZnkwWlRrLnNYBbyeEjJmMvITtiAaVuUUuJFfjMePpECcepXxPGaARrdyYDiIMmgnSsIAnbBZIioODdSszNEeFBbYaAyfFiIvVvmMfjaeEcCAhHsSQqFfJFVFAaQqfCuUPpPMmBbbnNGgjfFJqTgcCqIWMmVvoOliVvIFeEzZBqkKQbQqcCfxszZpPMmYyvIiVWwSsYkKHgGGFfLlgZzKkvVOoLgGiIRrgBsSbqqZjbBXxvVaGgAJoMPpsSmOjJaAOJjIIiizuUZYylLdKxXkgrXbBLlgGKkxnNBbWwldmMuFfULlGgFfmKkQqfLlJjFuMmPpUIiHYyIcCTtYyigGdDhnNRroOkKgGMJiIMmzfFsfbBFSXdDwACJEejcnpNniIIjJicuUCnNmMWwpPPsSRrLlPpFlMmqizsSZQqiIqQRTzZtTUuRrdDJIcCcCnVJmMjvzZAagGjoMmxXSaAsiIiIOeELlNnoPpUlVvLkKuYyOoOeQeEuaANRrxXnDDiIddUXxqWXFfuSsOoUIixzSsZYyYyYaAXxNLlXxnZzKkupPfFaEeCzZABboOaQqjkKfFJvMmVvUuVPpZzMSyYPpsOoNBySsYbktTOKGgzMKksSmMacTtCSsrRAxXPwPVUuWwlvbBBbxUkKaNngiIkBbFfJIiGgjChHcMmIiXxxXKkHKlLkeMmEkOoKdDAoOoOahKBbhSfAahJhHjJwjSsJjJmbBYenNEqQUxXykKNnXxbBrRwGgWXBbjJnRhHnNOyYoOCeEmTtFfMJjeEcsSFfeEvVnNEVlrRLjmNXWPpsSeEwtTKkbmRkKsSHhrRrRgGrUMMmmzZyvVYocCOSWwVvsfFdrdCcgGDRQAaqbfrRFBwpPMmWGgdNnJjvVDKYyPpxGKkgzDmMdZPnNpWVTtvFmKkELqQtTleTtwWclLcwWUuCTtCOnNaDdMmRrAiIgdLlDaAYyGBcOZzolaEeaZmqQbpPUuBgGdDcCgGhfVvvVFGgoOsSrRxoKkOXYXxMmCpPhHlLVvcIiEefFOodDlUVuUGgQMQqHPphmOMmolLCuUASssUuVUuvdwWDaAEeTaDdVmMvCcDdjBbZnNznNMyYRrmcCnNJVvrxXtTiXxiVSsvIvVBbxDPpdPpoVvSqDdQZkKzsOXffaAYmMGgZzguUpaTxxvVWzZWwwBRhHrSoOFhHEeyYTtfoOIEeisSsZoiGPrLIimpqQzZPMhEtTeqJjGQqyFfYgEejJvGlLbBgqQVxDXxwWdVjJlaALjJjnoONmdUfFVvuTtDmMNnmMPluULSszrRLXtTOoxSNCbBCccngnNrRbBGYhHyqQibFfJSvVsTMmtzmMZZsNXxnSzugGjXxJWwjJlVvnNAIrRAavViiIUytOCXxcnNCEeckKTtjJonXxNnYyJjMmhHqQMmFmBxGWkJszMPrkSspPJrRkzZKjQnBbWQqjGTtgoOTsLlSHhDzNnJhHPpQYygkccCCPpKGjJMmDvVCGcxXTtEUwFfkKWlLurRRrESKJreVvZrMeyYNnEDdDgGnGgNdDokKOnNiCVvxXcIzEoOemvVMOoXKkbNnvVBcYvVbBgGWwmMtTNKkGiIgOoOooOHhCqQsMmSnNJsSfQWCCcGlLeEuUgZztIiTqzZQIxZzXkMThybBEAaOgnNUDdiIilLgLlGjJIuUPArJEcCoKLlkOuUbBBTrYyEeiImMSNnlBuUbwWAueEgbBZhHgdDlLOoGocCwWfEXCcAKQqkSzZegGKktTlLCCdDIiPpcuuvsSVUXxfflDdLtmuUMqQTpYyPdDVMmvXVvxJjuUxXuUmMOClYyFuRvVcpPqBPpboJjaVvADbBdfFFilWaOoAwPpLfKkvGBbKZzcCHhwBbFfmMWUbBuKkrbAaSsCclDqbBAaYDCIiEwXxWejNYEXudCcCUudalWwgGLpWwPVvWjICcZzidDxXhHzZJTtYyeEoyUurjJRYdDTtyPhkKnNHOPpJTtjELlNdxEerRHhgGiIXMmJjDJLlDqQHFrRrRmMqQotTOEevVrRWwCkGgKJRrAkqQyJPXkKxEhTtfgGFHEDdcCcCzZYNDqQdsiIMGkKvaAsCcWwSrNnPXxwqbBQHhWrsBXxgPQqpDdUGIUuwpPcCFptTtJKkNqQnolLZcCkKRsSpvVGaKkAnpPLPKkKkoJjOxXRrUukKxbBefgGAYylRrtTLbBaxXniNFbVvBeOoPpEEdDYynMOXxopjJPuUeEoOpPLlemMYEeGEegeEQqXTtDxXcCdMmnrCcRqQhEefFHiIZHBxXbdOoDuVvUpPuYwUtdDTluUxTtXRrLLzcCZAUnMmNWZzbBnNAGgbBxXpXFRrZlLeGgXxEeJQqxOGgKkMSsyxXTVvtwWAaHhyYHhsSAoOOofFfChHsScinNcCIFupPCYTtyceEprRPewWbGJjgcMBCcCBbZzcbmGjYyhTtzUuxXZHcCMUumAaYyRjUaQqAuJrLlPpKkuODdWwoGgcCUUDduzTtZwWKYyQqQqGggsIXxiSOmdDMognUuxgGHNndDwWtTOHhoLllrRrRfvVbIvVXDdooFWwfFfOnrcCUXxBbuRQqHxLWmUuxXJjxTtzZVfFXtTwWoSDdcCshzZHPpVvTtDkjYkKrWwRUukKwWyUuOzZopPQqRqvlLVQbTtqQiIYVpPEWjjJJmbBjJMEnNelLgzCcJDdAaOoJjdDdDjyYTtRwdDAaaNMmOoGCkKcWpVvPXkKqQeExwgnHhVtkdDKCcTGYlLNnRrRETlIiNdDzrGgOonpPOlLJjsGvVgtLlLlaAzaAaAZiIYZzyVvTmuUGEeizZIDLlRrtDTtdfFcCowWOdUuyYEeDgSuUKAfkKNvdDVnGaAgFaAauonNOUQqwDdHhbTtBWgGBJjtTwqQpBbFfwWPKkZBbzyiHCchRrDdWLlwEePpZzleEJjpPgGLsStHhiIiIWwPpWwTLqNpsSPQqHyYhbBVHMXxmzXJjwWRUuZzkKJAajgGNxXYsOoSAayiiOCcouUtTlLIiyAaDdXxGgYoOTtjJgGlTNnXhHBbxVvnnNpsSPNjJIyduUwnNWWwJjKkWwYFIiRPVMmHGgNrmMJZzEeHJWMqDdQeEFfySPpklLKIvVDeztTfSFfsuUFrRTwWuOHhVvoeEVvbBkKDAwWJrRwWWfFUukWORWbBEewaAnlLLSslIJXxjUuUzeEeEZwWOoujSsHpHtThOoTtlLHJOdDSJjQIigFxqHhQYyOoYNnyXWkXZzUxBznOoNnWwlgGgsSTtocPpAaEXbBGMCcmcFftTrhHunyYlzmMnzZsSNekKEsZzuUeiIpPsSlLJjRUumMrbcCVdIiHLldDtTqKkAziIZHhEOoMmCXxcVvSswWAaCMmlGTtgpPLQOQFfqzAaVvEHhzEevVnNnQqNqTtnNpPTNpfFGnNzZZpXamoODdygDqQmMdDdyIkKiSiXxSsIiRgDdGhNnHgGlTdnNDYWwyeEvVCcXxJeEpPqQoCcOPEEelLjJoOEJjeDdqQWwyIIiLEelUuyYfFQqcshHheEHSCvVOonEeNnAaAALIilpxGnOoNOjJoDoMmruURKklLOKigGuUBnNbGgbBgGFsDYydIXkKHhNnhHToOhKkeNnEzJmMhHjmpmMPdDaAEeRZTFYyyMmeEtTMXxmUuBuUbQqQnNTeEtqCcvLlVQSMBZzYyAlbFzZdDTtRZzgEeaxXAgGLcpPHhUuCghyYKkckoFuUfOKyYOoCrdDegGpcwQqJjCcVvMmPpjeENnJfZzdDozZiIALqQlAbgGGvVgfNnMmZzFoOfiIHOvINpQSvdeECtWwbBrDdQqGgRfiXxKkYyBIibIphHUoOurYQUuqyLlTjuZSszDPpULludVFQPjJlLBbIGgiCGguhIiRDdqLlQuUsSPcCpnZzNsEefoOlLoOFDdqQzmMZSsqQhHSGgTNNgGnnZejkfFbBhrRHRrniOoIrRNeEQQqqUNnitBbTfwbgGBWwkLlOmnNgGCcDdhOhHZJjzxXodDvMjJmCcrCcgcCGRashiIHSubcCiPQqrRiIimbEHhtTlLeBaAeEjJMQqcCJqQApPENeEBvVuKSskjrTtvVRTyYCcjJxcCXGYMPpmowpPjJIaAjeLlEJSqQPUSnakKlWUnNuNNpPLlnnBbhGoOCcErPIipgGcCoOQAqQGgflnNVvFjJfLfFolLVvsSiozNnPpZjkKkBkkKKbKJQqcssSxBbuUEeOobBdXxRaArCFfMbkQqCcAaNbLdQqqQDlLvRKRisSInNnjJvMmYhurrrRtTxOHaAhorJwWWwBIBoODgGMGbBgmyNaZDfFwWJjCcuUpZMEeFfRRrhHmFfsKkDdSMdDmuUFfjJWBbwrRurRXEFUuRYyroSsOiHXSyVEeeEoOqQTtkCcVHSKWwlAxzPKoOzQWCyNnYcwKruQgGuUeEcCqUuURVvkKvVuwWGVKchvoOzZyZzJRrjYjJjJVHMmOoeELlCJjoErRPsbbFyYYDdpPdDKkZGgzhnNOnNWeGgEMmWLltwWyxXGwWganNjZZzUgGCzZyYqQZgGMmzhHaAkqQKdSsIiDfFuUIiwWRrDdlljURrVviLwWNmYyMfFKkMWsSwnNEeQDjJggGmEeWJGksSlLxbBAxxeolXxLOdDEHhyyrRYYRrZvaAVzSsSsospcCYPpyCcPLlkKxjJfFkKkEKkBXxbeKCbBDdcSvfrMmFfbBNNKgGknxXyiIYaQqAnLGgEezJTtNnlLVbWwbnlLNGAEfNndDFiITgMmEegEeGMswWAaUuBOgGBboQdYOdjJJrRbBfFIieEGgwWjCcbxXnZhEepmMXQqxgGPAanoOPmOoGhHZOrCeNmMnBiKkRghHHhGfKGgIaAiPkZHhzkKiQIiFfqIKpPpdvVOoDrzpPZjJFfNSFuaASjJNkKGKkxXKPpSskKkaABaKkyYFfAwuUWREebJjnjYyInRrNdUuDUhHuMgoOGcjJCQRLlkUuKYyxTtXQqrlLqQpPLxXsSUbFSqkKNnQTtsfmSRruRWwriJjKkKkJBbdDAtbBTagWwjZzVmMSRrsHDABbXxuBbUCJjcpSsXxMTtQqmPbBqQWofUuFZOozOTpwWnygHgGOfFSsTRrtLGTBbtcCTtvsEcCiIoOeBbJjfjJFLKkrRYjJzElEeLwWhHnNYyCrTwWtWpNCcNnNnpPFfyJjKWwlJCVDdvcOojWwLEkOoIiKEeQyYCcmwWMfpWEaaaAaAAJjAsOStNybBYsZzSAaVvmIipPMmpPcCCcAtJxaAxXXOojdDyOoYqQrWSMZQqYydDzsSmpSsiSuUsIRrjkKJhtTZzMmZzIicJjQxGgbBsZWwzSUiIbQqUlbBtRraAzZTVLpaAkyhHbOohNnHrRaAizywWIsTiIteyYtTESzsDbBERakJjKArCPdEeKkhbBYyHIsSqqQVvjfFJjJezmoBDrRfFdbvVVRrRrBbGgxAaGgjJXSKSrRpwWBbPDdhHidDQqIwAanRFfgGliDdtTzZvbRwWrGlneENLgaAvqgvCWwcVqzZBJAaEuEJjNgGneUlLzZzlqkMmjPpJaIilqHhWwXxEOogGGIPJjCoOJByYYydSsVUuxslmMLKkWwQqwzZHPphTtPLlhuHhMqQdcSEYcCrRyVvVUuvgOoGLYosSORdmMWivmMyYGgEEymMYZzezZiIBzZFXWwmEVvsSYyeBbEbpPBVvEaeVvIinNEYcFnoOFfkzpPZnNKvYySsRrpsSSLlMbBqtTdDQtTYYJjkGgKLlhJjUVZELLlUnXGgxjdDgEiNNnnSFdDdDZAasSzuYyWwhsQSsXUYFflLEGZzFfnBcaZzUbGgNvlCcMmuUBTtbLVeEUhmvVCfFcoFfcCOMHuiIXbBxHQtOWDNndwDNQcXQqKlpItsXxjJcCSzyWRtTrwOwWeEJjlLIWwKBnNrxXkKVNWCcwcCNnnbBvgGbBeECcxEeNJjTTtlLtrjmMJEekKafNnxfFLQqTmMxXNnaexhHbjJPpKkwGgLmtTMiIYdDgGygrRxXGxqQXKcCLHhlAODdoaAfgPOlNpPPXrnLqQlzynWHhSJZzWLgQqjZzvVJchHNnNbNQsSuaAtTWJDdtMRbBMSLlomMZetSsSaNnCcAaptTkKSTcPpbBCcCOkKotIiwWAiILgxAaXlLWtTuwciOWwhBQuhrRuUHwWijIiTtvoOVNNnnDaouUEnNDuUnuPYSlVvHhLhRriIYgGyHmMUrRusoUaXaACgGDXxAjckKQwWKkwWzZBGvVWwhHcCWCcwWgPxgGhEeTVvRrgGKDdkBbLMmDOUuNcbBcCMmqQVZpOoxXVBbnvVgGMmCcxuGgUVviIBMeSscCEkKeWwEpmswnNcCYydQqDkKWkKjEeJijwWVvJCngGOorgyKUuktdLagGzZFfnAakKtsYfFHhXxsSIiNdDiQnNOohCvPpVoOHZFWwUumMPetTXuRrCcUNneEGgdeDBbdYyiqQIlLlLNtTpHsSttTTBbgGcADdfdDFLlSuUeBbDAadRwWvSYysZzrcMmnNCVGgFYgqibBhZzHYyIQNUhbhcvVlLCAknXceEaYyafSzZseQqEEheeMnNStTNhDdHnCceiNKkMmbOoHhYXjJJjYFOWwIiofBbZzoOpzZXxgbpfwndDVvgieESsqPhQBcCVdNnJYyAahHjPYPpyEhtHhBLjJrXxZhHfFIiQthHqQSdcbEepEeNnPRryWwhHYvVphHHyYysSdYyYyhHDgJjcNnxRrgGNndDgGXWwTnArRaQqFfVvPpLlNeEofXxiGgIRYyrSiIGgdDwDDdKlLtTyXcCnNaqBbpTtMFbvjJQhHlLEckKZzYyiIbBZUuTtIQeEqhHAtTHBbhxXnNpPcwlLgGYeAaSNZILufFbljJiILBSCPpcAabxIiLWNKUuQqHbPpAaYQqOopPwWGtKkSsTnIhqPpQuUsuUAaSHRmMrQqhPxXSsvBtAqQZxXsRrSEDdqfFPpLTtQGgjJqfAnYRYAxokKFIfFDdPpqsNLdDBHhJPpMmjSgGsYoOQqyusSUhaSNEhgGWmXXxhHdDxMhdDeESsTtYYANpSsPTfKkTGgtjRhHrJAnNasSTtaAsSdGrRrfFXxCmMIDBbDlVKkvyrRtToOzZOXkJjHGAagfFhPogLEvhZYyxXzdQhHgGTqQgjmpPMJtTRMmPVvbPyYnbBNFBbzXxhoOHoMeEUuwWtTmzGwARoIIiaXDdKkVdDeIiEdBbZAYywWIvVJjiBgGbQpwbQMgGTtmqFfBTADdqbckKCRSsHhrIzZJaOptMmTPRRrFYySssinBUubxXYNnIDdbFfTUdDqQyzClbXxTISsgXpPXwTtWAaxGlvEuUwCcPmjuUQbBqaRulLFsSVyYHIIkKihDpPxKwIibBjDdJeyGitQqQqFgGzZQqyYQqAlyMAdDabBMnNhkHPphWwkTIEeHzZhRrZZzkKZclwzZUuDVyoWwzZQqzxupPsSUWSswXxgeEuUvVsSzuUDcCVvdQqayYASxXNBbDtCcgYyJjEmMYypJjJToOtcCndDQqKkNZzOdDlLKNJpPtOeIiefFEUtTZzyYoOXhHxchSokKOsqQHCrOsSfGgFSsCRrcTaAbBtxXuYybLgoupPUSsVvojJOUdDuOQzgGDdcCZTcjjJJaWwfFmMFnNzZqZzmUuLeWlSUTfHaCUuiRriIlaAScCBaFDQFZzrRhHAjJQQCEecoOjeEkKJiDAadTttIiSwciCcIKEArUiWKBbkKXhkPpIyYrRDkjfFwWfnNFfaAehEgGeHKDeEHtTzYyiYXxMuUNvkfFXKZzkvVxMvVRkKrCibSErRLlYtFfMmKkvpPVWwmMZGgEKkJjKFfkxXBboOcjJfGgFkTtmEOUsSIVFGQqIDdTttlLTTWzZgpPrqJxXYyPnLlNpjaASwWPqwyYfagOYAhMOcBxYdDrsSRSsRrJjOLloPpmCvVUuDdrROoRrgFFflHvVxtkKTusuUYyXmMaAxSeNYyCvVcnEYcjJPuiamMgfyzQcCPpmpTxDdZatTVLeXBbAnMzqGkWKtfFfFBRUnNuLlAMmaQMkYMmPpyanADHlFfAZzGWwVMmvDxXJAajKPpkUuPoiIOmMhIEeeNKkyEGlKEekAaxXuAGXxnGgNBrVvUlzZAaFXQqBBbbDcCdsSxbBjzdDDOxQqdkKQqQqxnxiFfHrMmlWUNnuHhnWfFgGoOepHhNnaAuUtasGRIiyYAixaAXVvSsbMEemAaaFNhHvViIiZzIIipEQqcCTtNmMGRrgNiVvIgmyYoOxGNExmCcMXtKbHlrGKxXkeLlulLYbBLsSlBbCcSyYIiwmaGGEVvZzkKStTXxsZvZZmMyJjqnwYyxFAafEllGfFNngmMscCnjJbaAVnVqQvNnfRrzGIbBiQqpPThuyYUuUhHxXjJcCOoNVvEenBZzNEqQemMpuUuPpQqrmMxXhlLSMIbbBpkKPTtpPBKjjJIqQqIYyIKsScAaAabBJoKmknNerLlGpovxXhPpHzofhdpgNnxsSsYNnBbHdDhaGwWIBRrbEeixXzJjZfRrFaAAajNnjjJowWWuIiTXIJGgjWWwfLhHlFIiwJcCCcjAqjJIkKIigAaXxJhLQqUQqrREJjRrFfeHIEePpkKiplLsPphHUwaAIpPwaaAAEQgGRruHFfmpPwWsSfKswTtWVvRrkBsSXxNnuaAfdsSgLhUuHlGtTtIiTyYKWwTiIUureTlLtEmKKBboOsgCTQrZyYtiIeEUfcCcQEeRTVvkGglOttTxoKwWksCgZzYyJjXVlLsTtgGXUxQdPoOHhMVmmhHknmMkYyaHxSsXnNhtTeqwWQPpnRXuZEezEeWJjpeEEPpVvnNtOoTtKkNrReAaAlLaFfJXxSfFCciIfkVGUuvVHnqIizOlarqnNTfFtQnNuRrLEelURkBSYysbOoEeVYyvLRrXxNnxXnzeEkxuzZbBCYSoJOqBPXxpUugttTTVSyxAWhITRViIvhHeEPfpiFSsRYytDdXNiiIqQLMtTNnEeaqlUuhHHvrnNtTSVMmhHTKkzZtRNmMcCPHcQqChqVHgovVrgGRHMBbwWHZzLliIhNmMncCNnwWPpoBAabplAaUuLiiIIhhHHeEjUuTmoyfiIFYoTtvVxUuXqVPpyYJjwWlLvbBTtaAUKmMSLlskHEpmMjYXPiyJjLboNURrwYyfFgkKGldDpPLGoOKNnfFDAadGgNpPWwHCxTtOqNQqnQeEQqzepOojFUluXxUCVvgJrRjKoWJjFfwWGgGgwEVWRrwsCcMrppPNJlLQGgzNncCqTcsSCwDdvgOIiaAbPplLBKJTtEhEVvamJjpPcCLLTJgGjtYWauUAXxdDgiBbIGBcTPMwYXPMrCmepTtZbBNEeXAIibpPSFfHwWoOOoYnNMEeQKkdDYCaAcygcnBKkDoOcMmCrBnArzGldMxanlzNuUZSsHhclLgVTgdDkEAeGIBrRVvuyYdoZVvEeqQfFbBfxXeEXjJxExtzHMpcCPMLBAaUuUlwWVqQaAYaAyVvIuunNUUPptTQwBxXBbQsuUXOoxuonNOUqQEzfJdDUeEjJBbuYyjUxZTtHFfbjJCcAaKjJUuAakBesSzZScKkwWCcCsRrrVvhHUmMMoJjLlqQTVvTvexXdWIARBbGbBcBbMzogXxGOCUkPoAotTOktyYMqnNQbNqxXZzLmLNaVvhlLEeGgIwWPpAEmyYUNnqQTtuNXBbxNBbMmsSdDnFpPNnFvVcCncqQSsYykKCUsLlxxRNItGgRUurTqpwWPumwWwFTtqUctTVPpzZHVvInAadDNojJrZzRDUQqxXTtlLGlLkKRrghqQHzaASsJNvjaAoORrTjJaObBHhMmMmgQTUwWKNnoOkvVoqXeEyYaftTFlhHGrobeEdDvVvVsfrRFcAPpXtxXTxVujJvZzIielLESaKhxEtyYCcTLlQqGgeEecVvEeIRXbJjKHhpXsYUuVvRWQjrRJqfSsFNhHqQnHRRlLCcIkKooDiqCrRDbhDdsgGGJjKDgGdkRHGgXxPMmQNnwWlaHhAlRrLhHftTyDQnLbBJwWjMmoFpdDPXuUEWQjFfCcyYYzZvRWuUfFwrPpUOoufFbBAahHMMoVbFUYyCWoOLZjJXxZGqQwWypbsSwWcoMmOCnnVvNQnbahsSUKkAaJQfkvVOoiIrRvOKkpPCVbYyAkKecaACtTnGEAJaRHhjJOeEoaSvkKVxXYpPvMNniINnztTkZzMhjPpaAqQkiuvVSwWHsACckZzualLVWwoGPpgOxIigGRrlCYUtTuxmMcCXtkAFmuUBuXQqQqAUrkqQpAjWzZliCJtHhArdDRQqGOoZdBziIyfFYGhtTEeHVvflCrRqPrRkKZiDpPyYhHKkCcduJTtxPpYyTMeEnTtGgkKNixbjJIPpSGfMiImBbFbBnysSYnLDqQjJdXxlLwWrROjJVKxoOaJjBbADKkUuRmMrnPpKTfFityYyaxJtTkuMHzJHhtTFKkBiWiIqNcoYhHUutXXjJBYysSbKkFfoORTtuAaPFYyfpidyYDsSFGaAmMgSjJiaAdCkKjvVHdDhjJDJuUjdOofBbFjlkSpPsGYeEEeuNOHKknCOdcCPpUuTtDeEEegGTrlAnTtYkMhpPHqVXxNnIiMpniLhHpPYRPpMoOLJcpPeMJjDQqAomMOaEetWTmJkrDaAVvdCcSsqUOjJouQgkKGNnllGMmRNJjfTtAErsVJUulLxXEBYyIibExXqdDiuUjZxXzvVRlcCLgCctTCINmMLlmQDdSsEeRGgrRsSlbDZIiXtuUzZTeESnNxKkXsJjxzpPWRrYqSiPpfIgAOpHwWPlLpswwWWwDvVdVvLzFKkNXxwlLWnzmJjQqqhNnMWxXGmMgwnNdXLlHOgGZziUuWFfXLlIHhGcCqQgcBbbqQGaATtgBKkEJjHuUeyYVXQDdxshaAdDWsSfFQAqIbBRddDVGgqgGQclRrjnCcNLmLlNlGDdHhZcCmVZAazvtwnbBdXKkzsSlznfiZETdDMdDlKkJjLMGgmZcTjtTgGJEkKeWyYwPpxXtTjqQJWwvSsWtTwGgiLvEeVZznNlIPFfpcBbbBCAPRTcCsEehHqMxRQqNnaAaALbysaQOGOoaAOoZxXdYydDpPdpjmMPBgGbEYzZhHGFfKkDpPHhdEetuUhHYWKjOImPnAaeEITpPFffFZztNEgTetNfgHhHhGTFfPTtlLDChnZzNFdQUYqKFfZiITIfiTCInNjyrRDNWhHDriIKkyYsXXbBOoWjJrfyYUuFIeEXxhkKHiSsgGRwdcCKkXOoNnXaEeuOIiogGSNfpRUkKFVhouUOQCNnIuUXrTQNnnRrRcCWdRyFfkjpPJRMfYyKkvBcCJWcCwjsAasSwmMmVOoviFfUuoFfqQlLLgMTPzQGgqAaiIZkANWUvVwtqQYyTWEkYnRUGXWFfIijlaArRoYUHhzZGSsSLlsZaADbBfFzMmZKbBkgrRGwWVUSeEYsaWwOKkHdFfoTflvVEeyYxXoOMzQHsIYLDdZWSsVvXxgGQUkKcCEHExATBukAaKkNaeffFFcMiIYSWEewdqQqXRrnmDIxPplLJEUqQmhAVTcmMRIhARrpXyuWQdDnNwWqzZdzWEirRydVILocnNWoOtJjnCczyYlYuCNnFqQCxXJsSTvjagJgdvVtTyYcSAaeDvnNVKkQquUsAaRfgJjGFrkGFqQfmMoLFMmMAahwIIiJjnNitTfFUucRWOvVvrRpgGPreERcIiCGIiiIKOGggFfFfxqwNTjJHFosqipJqQMoSsOmfGgFIihcUuyaOoXFfKknNxhHIVoORWIYCULbKqjNjJnyYnNWwHhZzkrzQqZewXgGEeiVvImsmvVmJjjokKMuUpbuqoOQUTtdDvVyqjwWBCccCULlsSuMAyOAajJdlHSsyEwWykgGKwWNnssqnoOOlnDiIhxZzVrRvGtewxyYjJZRbLkKmqIAavTuUAMmxOoXaCWwWwcCctTPVvpwqfoOFQWPogGvVSBhEpPXxjyYbVvRrdMmNnWcxlFkKfLHzDdZqXWSsLXxlYwVCQLlyOQrRqaAuLUufFluirLmVyVvhHKwqqQQtrRZvKkNFfKeEGnOhWzXxZwWmChHEeIbOohHBQjJkKqsRrSZzYOQCcqwBTpZzxgGXrSzZsNeEaJrRYyxppKVvkOJjoqbEeNKBbvVwqZzdgGnSiIscCUvhYyUutXHaFsEuKSsHhheMAaGgsSzZhBbJMmNxCqdgGgGHfSlLsGgYysSRrYsVFftTtVvoiPpbzRpFYyezHmMwYjrdSyYfGlqRrncxihHIEeIqTQqycokyiYxZvNnxjJGgMmXeECchpXxPzZQzxNWvlLSnNKksVwjJqhHQnGpgTtGZVUjJuvzPnFEGgXxVRrNbOyYoBCwvxCONrRnNImMinoRZtTAhzQqQOoPkibBVxPpXaAadBcCbGBZzcCWdiILPuUTdYyubTSNRkhbXxBPTNntXKvApPatTMamVvMAUWGEvVWLAaiAfFUupEKZrRYRrRrdDyJCcoOLVvdjJDlLlRrmMjJjrRxNnioPCcWwRrpNnHETadDbpxTyasBoOVqECcMaiImzZSBcjPAapSsODiKiZnAKkwNncWhHPImTtVSAayYsdrnVPpZvWIioOzZfCcqNfPeorROoOOIiXuUustWpvxXUuUmxLlAaGbyteExDdQmMqIiIBGkdxfBHukiVvbQMutIiTbEeMzxXLUulMfFmQqfTtFcAtxbypPDPpdZBZzXxwpPBbqLBbaAjJfzZKkrWiNnIwRplbtXAEtSXxVOctmuoGgOHdDhlZXunQRWOIlYDSrRyYOobJiwWLliIZzIWqowriCnxXuMmUyEnCEzZyYNGysQqbBIiAEeXGPpAvVaGzZCSMMhZzHAPDdqlCcLpjnNUnMKynNJnNjvVepPaAEJjOtFfDdkKEYlLBHhbsSgaAgDdGUCvVcuPBKkVTtajJcCAznlLCSsSntTXkOaHoIAqQeEHNZFSBbMbhmcItTmMphOuxbzjJZhlIiRsfCuUHiwpPQqWAtTerEVsSvVRrYzZnvNqtFfmMTPptNKUutrHFfhjJlaACnnNBbYGgQqypgbEeZgHhwWyYZFFBubBUuUrRNQzZJtTuUDLqFJFOoqwfFJjWuUBbfbBOEGgDdvVXxeoFQRgGohDdHkKBAabMyTtjDdfxXwBbmSsDqntxXTlUDArRtgAOuiLPVBqFLuzZEeUEesKiXtdVvxXGOxlJwWBQqJjOPnNBIODdoURrtYyLUuNnTtdyYMjoOIXyYJRMmevVBYddkqQEewFnHhSvVqQMqQeEgGFfESsYmcsSCkEMfsSFzZmsOaRTtqpPQrtTMIeMdfpzUSsHFBbfhBbBbZzUnNxvAaVXFMVvhTtUXAaxnmkWwgBxzVHRrAaUCFgGpiUSORHQXYtHEfFbXRIBPgHhRrVvAEeEHUuheDdqQStzZxJVlLYOoYyLsrRXtTxwqPpHiaFlLsSsgIiVGgvyTehzyYTsjJJhLsMRrqQmkSsXnNMmfRqsSHhcgRLlVvnNIiYLOkcuUCKXIXbuwWUAKkaftucQmZMmzMIIUWwuHhiiqPpPamgCcGACQAGjbkKZzZpcEfeGbbBwtTCcnNCcBbWLXOrDhgGBahjYymuhHQJjdWnNxXmuUJcAXxamMXiIkbhXaSToOonJNnFfPOHhnNEfdutRjOHhlHhLAUuYqoQCUuWwhHxcPXxAMBQyYGgqilDplpwgGFKFQqfTtEBNqRXWbfONnoFnNMIyLxUINexRrXPiwvVmDdksrRTtaAFGjUOEyAzEJbtuYyQDdvVqTroOrgGRNmsSOovryWwYGejJEcsuUtTsLmIgGtMLlRVvXwWxAaQqddnJjZnaANwgUusqCOvMNnnNAGgaAcvjnnNnOAaUHZzwxwwktZzdDAaTKGgyYTZDcCdjGgJoOEenkimCHldkCcSDmMgmMWRXtTxQqxGpYzZVOovCpJnUufiIlgcrqQfvTDaJjUAfFaQAkQnwWcCUMSiwSJAuLloFfQUfPpZapSFdDgmfFHHfdrJcIYFfGHhUQqzPplLeHCczrcBzZjZhuDmEBqlLBfCeGgQqMqJognNVvMPpNnPGgNYyDdIiRqHhhHurRUmDjYypPBeWuUmqxahHCcAgANrRWmMoiIdaLlAiIlLsGuUgGnNgSWiILNHhnTxXmMtoqmoMlXghIlLOolYKkjvVGbBwWZzAgGdDOaKkAMmQkDHGxLlPSRrvVsHBoOEeaMmAsSctaUNuUGgxxpPaNSwIiIcCsSgYdDyVgLlXKyhYCcLOoIiKgnNhHYuCCLGVnkgGLbAaEcCfSAHhahZelYyTzPpZAatLUJdDdWwOyYoDrrsBiIbwYyroOqQlHMmhBEUqQKMtTmlArkByYyYoOiJPmMQOoqYyYwWnUugFfNcVVyfFjNXNnxRrRrMmMAZSszKYytYwAYQhJqQoOlDEemewxLtTKFfbyYsbBJjCcLJpMmjJrVYyWqBDFfdOoEeGcvGKkFfLKyYkewNnfFZCnsjJSBiIbYMboEEcCeyYAadDXhHUKIikbFUoWwqQOuvdgDmMeUoOOouvVdDtkXTsSACocOoGhHgGjYysSuQGUuGQqgGGzWwKTlLtSdvVuUoOgGfRLDtUdDVtTvuYxXuCIsSYyCKkyaMbBmuTdDnWvrDCbBYDqxSseEpcTiKyYkyFMHhDlfjJlTHnzNnZNIihjMBbguBbfwvNnOoVlKvdptTwWlLjJAwUKkzeEKStTtJKGxeyYXNJOonNWtBbXxxjTqsSKkrGjvVBbBqQGrqQmVvfiCckxiIXYAVjaeMmTLHhsIiIJRdDskKxXxYykKEqjWqQEeZTtxxWwlpPDdLXQduFzVvZyYltTfFsGOhcCHogSbBjbBobBOJaEbqvfllAUsSuZlLuUzGopPOgGgpPAKkFOcCzZBUubEeNnWwTBuUzvVBXpByobmJjGgsMmMmpDEhHAaQAEeayYPNELlIghjJHJLWcMmCIigllsSyuwHALsSlpPJxvTDdSstVbBQqGfFNnrnAaNogYyyYGDwogGdmMQqFAoncCNgoOXaaAAXkKMBMmbhEePpBnNlLffYoTNJjXVvKkPhCUurcyLVvlzrGgIgNdvwJeEjWVSsYGgqjnsShHxPpXueEwlZzHhHhLWRrmNnRrrzEsSeNHhhfdLfOoRluUwWmDazZAJvLlVeERrgGNVKtmbBMZzHuUMmbBVMmJuHYycChUjRrDbzlLguUYvzixMmxXFfFfXFmiIMWwKhGChHZehxqwWIWwYHXalVRrPpcZTqgGJzZjjQztTZBsKkRrSjNBBbPptTsSbncGgCyYTmhkaUKknNXxuAOtFRDnNzZlUKXNfKSjcvJlLmuUJjOZzBptTPCszZQqxXjYyJkYyKoAYyYvVzfFIvrRxXJZTPpUmbBXxKkFfEewqlfFgvVGtjsSEezZBbjxXeDyfFUuDrqINIieEWwAaEtOxxOSsAazrXxownNWoRPAQIiMmJdJLTtnPScCspexmMXqtOehkkeEefLlAauNnuULlNBHhjGoziIrIRrHscPpCbTtmMUPpeEtPIfFZzVvGgVIiFfNbVUubRApLWqnlaAWwMaeiRDAMmeGgEaIidumDHhKVVgGiIizDdZIvrRXxKkCcvCiIckMhHmsVvACrtjpWwfqQUgKqQyJHlmxXMAaTnNtvVbdAgLlzZrjTewyxXYGjUxXqMQeEgXHhwWxGjGgxnLYZzyWHhcBbWkKBNnbnWfvfyYnNdVIeEiWwOLzKeLlWwgdtTDGVvdYXxAMqQqbeEFHVblxoACcJLibuyYSQAxrOoVJRbBZQEetbZzBTJIdgxXGDrKXTAYyZzrRaAHhgKFarRkmMvmAWyYwrRWPAyYSDKyYfNPYyfmMXGgxudDeEGgWRkZzGghKvVYuVxYjHhXxJYKucaQBsSLYIYyEWwLEerRlLVoSsmacksSKqTZhHuUDMZODdNYHpWRGMzZgbBgYDdzcCjFsSUyDxhKYcgHhGzaaUSpPfVvqQzZbrRcCEeEuJjULFfGIypPyYPIimkMfFIRBbQLxhGAXzamyfFdDWUQwWwWPnNpDcCdvXhieEoAaOnTtRzSGCtTNaAHpdxXDyKkVQsbAaOXZCnrbGsSyyYodDyYQjgnNYyiHsXIiJvVrRuouwWKdmZPpUwNnzjJPWpPwPuUQMmquMeETtXBbBMahpPHgGCWJjFSMmBAjJPyYpavVWOMImuUMosUzqQZrRMmuiISCqQDEedKJoJEkhvVvVXMzGsiXLZhnEeNHzSYyHhWrvEeEeTKzZNzwykHdDMPpmhMSmwWoJdIUdZezZbohLlgVqZPJmYSMLlPCYXfAoVIPpCciNBbnIyPpRrNHhAXxOoTLltPhYycgqppTtKkQqJOvVoPdAHhaUvXvwLlJlLLlzLIilZzWwpaDHIitRxXkEFfZnNdHhioHeiPhwcebnNCxMmAerIiIoOezqQWHTthodDPCcXBUuTYyQXSseExqauUoOiEeIMcCmmMkKGxFJhijJIJsBwWfFRYyfmrHPyRQCcdTtJExXiPDjEfZNiAHNUuYHnXhWwTvaAHhOGgoCZzccfstbLlYfFyzmqjqQFXKKkXWIiyPPpkocFhhuveCczBRaJRpzFfZmzZgRrWyYwDdETtJvWCDdmiRKkgGtTqUuNnKkwWkKUkKecWGjaAyYyYqFxSsXfbBQieeEdDECFfSxXWwExUuEtTjJUuYETtMYlYWwrRzxGDSJjwomQqaChHbBvVSZOonYmMjJYyHzJmpdsSDuMvVmCXTvsKfPVvKlzKYyoRKTtpdRrPPamMeEcnGbLisSTtgEJjfgzZNnbBMmXxtTXgkiSlLsiIjnFhgNnVkKseEtaoOYyoTKmfFcpKPBDcLDdBVOoCFDNMmtbSwqiIlyYfFZZVCcTSpPwWhHNndDdwWiaYZgDrRHhZPEYTtXOomMrxXQaAMMfziIKMgLlpPkaAcCqhHKyYvGgXbBxKuuUaAvuUtFKkjIDXFHpBbuUmFfMPipKbshYeEyYzeWBbwjvVJYxXpmMBbqcCSCGgRmOgvSsyjQotyYHwjRPuDItNTtnkPEepfTtFkKsSkKPpkBuMkKmjJFfVTSSZzsyRxZFNfNniRrFjJJlLQwJjXxzzjUgObHfFFpxXWwPMnKkVjQqjrbHUfPpIdXJHkCrRDdsSczZKZzwuUqQfufosBbWWgGwwSOIilmzZifsLbjJKXcVvuUyYDafnyYfFNFHvBbbusEeuUSUhGZzgTPurWjMxraUGHgGqyhhyRowJtkFfeEfmMcCYFFfIvRVPBbjGgxXXxJpaNJXxaLlxhopRvqhgFPgJgKCTtBAabnMmkKbTVvOZBCQqTxDwccCCvamMQMmuMmoOUzZjdflEzyCGgRcfFCCcsSTWeEQMmuYnjFyYHgukoOUiwWWeEmtqVvtThwWkKtkKTFdDfwMmQmXxMMeEyAatTUIalXSsxbSsIbvVMSSsYRrsxQXxTSwWyYKTtvCtTTPkdIHhlLnVvlGghdSXxCTjscnmMqcCmMsSFfPHFoOgTKwCdeiHotQqgELMHgkeNKkmMnzZhHNnddGgDDUSCoCySssuUSYcOFWwfpPJrSsKPkKkKkKNOonmeEYOTtoAahGeEgHdYZzBkKkaAKwRUurAEPpueEVvVqndEHhKkinVvaAKkIsdJiInNyXMaAmxqQtaASVqTUMoSsRnfFIZyYMmqQXbBSlxVvRIPjUSTxXvVnfFJjDdOoDKkdeENJVvqYLPprRWdqUyYueEnoOuUEeNEFlXbBxPfhtTCWweEnGgokqQkKGgKBlSsdzCtTcOSmiqxFpWuLXxBRSsHuEEemLwYyGdTJjtDIiDhTtFfHdhHGGRTfFGgCeEcgCetsVxTUiiHNvXxVJgJXjJZZNBNnVounXicRrCIRnoLDjXxEcCwWMmeJmmMyHRPpqdOoRzUZzTxRpzZhUZzuFdUEsHLRUVgVvVRrCzBbcyYaNwiIaBdWwLXlqQLEexrhmhlDZUPoAFfXOUoOakKUuiEFxkZzvVHhkAaYMmSqQUpsymBbwLlqOuWKRJjXDdMmFfxUumMaArHhnlnkvmujJRrwWUDcIsSodVvvJoOjBbebBoROorKkFfMmRkoDvRDANnkKpPdQqExLzZlBbxiIQqaPphowxyJMmWeqzgGZFfystTSgRrSzzZCcRXpPRJjGgyYlsZqQuIoOWIilxYyYHgZJuTtUjTtjJbtDmgCmMcgGgydXkKJxBvYltQDdAHQqDOEYvkivVxjjuNxXBbEbBtSUlScNdNiKeECckoOoEgRAYcCmMyswWaASbqWpPRrakBtvpMwAXMdZotAsXpPAaxXEhDdHwafqQjpNniZkKzLcjkkIeQCPKtJseFDFYyNIEqEeQIiVjtYpPDfpYPOKktTEVYpPhkNwtTdNpPawXVvttUIiuZsdONtaytVvrVYyqFeeQgrRZRcCrAtkKAZdTbBtvbXlRrcXxAfrmzBbJjZrwIQqtTUuiOoWsckbKvVkBKbbXxBBuUCbRDZKREkoOJFjeKUqQKIiOoFvsBSRrGBbbvVAHdRVQcCatVvVbzpfXXVYmJmTVaCckWwKspPZHhySTjICwgGmCcMaFhHSUmSsVtTRrKoOkMEexEACdDXxsoKbBoSCrROMSsmeEyCInAaOeoOovVZZPlLBJnLlTNWvMmmuqExXebmkuIXxReDNGwssSSYUMNvsJjSKCNaUuAWUpPuqqQzqMmLlBeEkDXffpfXEdDFGHZDTTBbeGgAfmxXxHfImMdGUtTbhHBGpLlPlLgugDiFhXxcCHhwZzSsWXMFaEtkKtdzhgGgfexFEiIePFFxdKNnbMmSsQZQxXwFfnckVnpPmuyWgoOFfndErFfiUKMBaAQUMVwntyYNjbpzzOrNqQnRkKEoNiFfcSQkKqsYoWwcsOkOkKEeScaUueXSsmqQmMRrvMusNnIifAnNNnWGgciJtsYzSAvtMjMyZzqemgGMEQvGgxaAxFwaTtzZAWPZBvTAqAaQqvrDhaBgsbSVfbBkuSskETtJfjKGgerRrkzNndrBcCiIxXSRSsYyMTrEeRtRFajJCLZzxBVgMmGDoOzaTaYyzAaGqEEfQvRvVUuTYFfATnoDSzTTxWAnDuUWnKHuUyveyYtToMmpyPFrYyRXxdEbaABeyTTtUuJveiQqnrMmRfdfEswmMWSWwkKSjTkpfFcqEiJjKKJClIUuPyYXTtxJFbCcBAKkWeiIxSiIaTOLlzholLOHZzDmxaWmPVTbKAImMiwQBartTGeHnNhOoOInDxXnCsMmLusTaAexXnUJJXcCIvVKVoVJXxjvOyFhHfeodhVXxvaBIibqUvVueEJjTLSszZyHhVbXjxXoOxDYRcCtgGTrGGMdTBYyKkdbBDzGhyXLwoOiUzSdDLzZrxrZsGYMfFmQqQqQEwjYXWOnNBbHAFhHfXXeDiIaAadaArVBbdOKrOPpEMmVDODdiCLldMVKNLMmWwXxNkwUoQGgWMaAYSPusyYKkyKvVKXfeIAPpuoxiDdIaOpuzdLHMTQTtTtqBbtPpHRlxXDbAWFsSfnEpHhPeAowWdDOMmCZcvGvurlhSeuDfHiIPrXtuZoOrDQOorhMmbBbBYMRPpbBDdKkuUrdlOHhmMNrxNUOUuvbnzzdDxiIjGjNndDnSshIIsSutXgGlvVLvSEeTEcGOoQFfyYqtrggIiGggWlMeUhHhrblWwUwPfXQIMsoZNJvVjWwnDLbONEecvVtTHFprRLfeOoQDxXwlyQmMqQAajtsBbRruJpicCrXLsuUxZzziNrHhOmuKAapPkWwtQvsTYkKodDOjpPDSiYyNjJMmJxXjIBbeDNQvEyYDdeUeaWbyZzQpPqbPcCpWwBDoOeEOVvyYoyMWQqwpkRjcsuEKoeEOGhmtUuTleGTOhHhxXIEDcWlLktGfrRhpQqAapPQNNnCSJqQtcsDHLNiDKptcVkstqXSysmBimMxXBLGkKCcCcgAiLluVvYmqiImMWuUWwHQZtTzeETMwIWwuKUGhfIiDdTtJNyhHUqwtzXxSYyAasZKkhHuUcCrcYUuZeLFDJzZafFAkhSsHKqAaorRpPOAViINnnNWBbpPdXtcbzooHhOkKtDdBkKNckGnNjGpfGkKyYyYHQVrPOHXAjnLlAvQqPprVZziyYoOfAayYytTPHhpFlLKTjWOrYHHYQhgWwuARpPgGXmJyYwRUptGvVguUHBVFTLBbltfhWcCwveEVAdtTCxkBlSFIMvVLUuFUFUuWAaiqQiIIhjxNnDiFuhBRJJOovNNnmfhBoGuJZZWqjfIFnfzXrBbYstvmMUbKwWBbQqBbeEOonNKBbePpSshHETidUprzZJWEepPkKhTOqkKZyYzJYrXxRVGoMrcsLlQPydDEZycCIiYymMjJHSBkPIhfCcmMtTKkxdiJfTVqQupPUUhHkMmSDdsVkQPpKJjWwTtBbGmkPpZFmHhXxiImfFqRxHhyeHzZhMOPpojJMmHvVhmMmNGgnXxpyYwGrRYygWzZzdGzyAIrRDVvqNnQstzZvzzNnlLLcCQWsBrOoRTyYrRkKfFLlnBbdfMmhHcvxeEXblCdbgDdGpkYyYyPwWCaAMkdaADtOYCcyATSvGyYHRrfoONJvVbBiIIxXKGzZxGFBbeEesSGBbICclBgNHhCApRrPppDPkeErOkZLkdDpFkaASVtxcUrRsSPMjZheMmElLyNzscAnNMOWsdUuhHgXZySQaAqsLymCccCeybBeXekKgGscIJgwCQqECNncupPjJQrcCIbBMsScwJjVjeGvVMPrjArbqQKkZEVDaAdUHHfCOKpWwYwxkxfbPSspfFBJQMoOZBTSFhFfHCTiMmQqHhITttVtHxNhSsdDynhrRaItTnBbzFeJIiPpdpAaIHhejDqHhQqrYRPpIirphRsSFfMmMFrDdbSnNEFfeDdlLjHjfXgaRrSsJjAAtbxpTtOwTtZEiRGgEalLlrRjJHaAhaApPbBzZLhHufvVaAFCcUXcRiIgGrBECfFWHIipIEhOTtFfIaAKkEeuoOUDzeKyYrCcQqsSThdAPZjNnWwWGgVZzvVxVuDpjeEaAPPQGCHpaAanfFYivOaFxycJjvVpmEesyMoOgTtGjpzQvGHOBZYLlUJjuyzEnNzDuWwiDjOThwWwWHtJQqjMsmKYaIiAWZnktEeEeVRwslxoOiIIPpWwSgZmxwWfFHKeQqjOHhjkUuaKkAgGqVuUvQcOmYcCyMJjimmMowbsfNsSnwhHcAmbxGgqiIXxQzZmMmGgUZmMzqQppTtZvVLlWrxXpPRukKzMhHkKIiBbDkUOUWTtDdwjxqQSXxhIGJqQqOYgBnNRGgNcoEeOFfzxyYoWwBSqOovYfhHqQFyYAaPhsSncgsZrvVGgNwWWRrwQqqQIHxVkKcQqCeEquwYMALlZxaKBbkgzZSCkSsKLuUlcyYCcsHIiwWXlqrimKMpjJYigzZDdlecCBqQGoOgFsuAAZKkgGCykHvVXuUdYufJZvVMmyaAGzZlLmMVvGmgrwOoPhynoHhhHzqHhQdqzZQeEDmdoOOWwonNztQCAMUuOtTXxvleiylbqACLEeTtKklUkWaAoOcCwUuyyXvUycmMCUuXxvVkHKrwFfWwUFpnFmhHMkhlLHdsMmapXxwKkaMVDdKXxSsGghHAfkGatxkHhKkRiVvjqzrjvRXaWwqsBbPpUBIljaOXyYLBvhfBQmaGdDgyIiDtTLlEkZlTtorUuRvFVFwNsLlSuUwZzCCcTtwlNndDVvNwWXJqmQuIiJgMmaAAXxaxXWEtJRGXIixaDBXxLeESshjYqQkGQquFPJVvTRcaSYFfyuDnNdqAcCyYjJaQUFFUuffQqdDdMUDdrFkKfIVvEAmTTttZhlLHzbBWwXxekKBbELNNnQwlpVaUuAvPPUuarBvBnvwWfFipDdTuCcgGKPpkKkBHhxXSsSZcCzHhaAhijdyYDJRrRaAZOgJbnRrUFEKKHEoTQEyYNljDjMOomUuqFfaxXNnprbBOcCQqORZoXXoTeniRrNnQaARdBbYdEJPpJiITBbLQTtkKWTcCFfOoVvtJjMupPsStzjtTViZyaYyOScdDknNKboMjVCJsXxkIcCiFnxkufFLcCdrfToKHIiXxMtLlJbqJQtdDzCvLVvApPwWxSYyEeshmMyOoiBbaAQXHEzcgHkfIZVbBYNnyyDdGZzZBdRrvhTkvRrnyYLKklFfWwsSjdMLyYrFlDFVvHIikKnZRfFMnNkKUNCZzcqFfQqQJQyXxvVDduUDnGlLiNnRSZzsZYCRKkcHwWpxXxntOMmyFFbHmOoCcxlLxGOafDdnNnNJYyjolLODBbIiOWdOrRAaRguqqQGgQUXjQPpfQqFqahzZWUYLYyLGAawMjJmljlIWwiLGienpbBquUedPSxXNnPpMBOYbgGkKPNnXxxbqQZbqQtMmBbBRjJrVeEveNnEbofatTGSsgaLLFVQBeAnNsSLRrfmMpPUNnTtDHhUucCuUqXzwiIJMmMmQBbeWwXSrjiSltEAJvayKSsIgGFOomMMRgbYIZziyyYJgRQtJXUuTwjnxEXgkjTskZrRunNWajJPDdSrRsDVkLGgWFMmUiIGmqQJVZzfFvtGgLsyYoOSFLrRdmfYItCnNYygGPNnXyYQdycdKkRVMiImwNGgFfdDpvVPtUsSngGNcCnNYyHFfhAYcicUyaATdBblrFDsTtkZggDdgCcqUJgCOxXcatxQqWwKWwYyTEdGDkKVLlfBXxRGgruxXLKklOoxeOBFfmysSNcYyVvzWmMWHfFhwLlElRrglLVCiSsIgbQwvzZRPVvjSslPpkKNyYWwnSBOoklXWpPaAEMdtTLjHqyYyhHaWPpyTkLljdDJamnJYTmMtBbvvCRrhHXxndDLYylYymMGUTtuNymMVvxXrRpjIZzFfbKRaLRgGbKkBrkuHhebEUueZzmUuMLRWAaSOoWwRRjuVmMvEzHsFeBlWwqQOoKNvgMCcmlcbSsBcUydDqQGklyHYTtkxGvtTzZGidDWshHnAXpNnPXGgGgnuSmMsArRMmTCSjKkYyJjJsjJbhVvQqpXZzghdfFIiKCcqQfFOoqoagZzJyTmMtLiHGIBrRbivVxLmOEeQqMQOlLlyYwpPjJDOwiIJjnIiaGXQMwEeWwXxxXkKEFfbJcCrRdMAaNSsvEeVnvpPVQXKkxaAroOnAWwapPpmqQGOjQfFmpPUyYxXuEcFbVvUuUuQbeMdrRUuXxUHzJYyBwTtqQuUWbbCRZhEZuFfHhCcgyiCWwjRDFhhMGPpfAasPAzOoFuqOpPUaRrjswWWITtsmmMuNBbKkfFMmqKdDaquxXAdtVtTFRMmnNCGjJUuLFUUuuNjPiIcUuybBPgXsSrwGdeEsjJKvVYyDLwuUWhcMIuUKpPNpPqQsNnSztIiJfFgGQqjWILliWGgXyYLlWhwWuoSsiaAIcSsCNvVNCcJVoOCqQrRcCxXwWaXxYyTtGOogmVocQKkhHRYyrSRrGWzGgJjNDDfFrmTiMlSqQSCgIirRDqwWQdygGvGgVXxwWwWgGwJxXjWYutTURVMaAnRVtTvtUTBeLlEjeuUZeEaYqEeQeEeLlgGDdouJlLNnFfgVvfGgSKMbBWwWbxXBIpEniuXlYmMimOoBwxrdDZzQnbekXxfWOoPLlLlLPdZzDddDLIbmapCXcpPqyYOQyCVvcaPpoJrHhfnNFTNnUDFPpoKknBbNONEenQqeopHyYtbBThjyYNUuOtsAMmxHeEBHhKQqxGgZzEeCjuUMwDaAqLlUMJTtHRrUukKAbrvVRHdRoxlBpPgEFeCPpdDPMmHhzlLBJgDyYdaqcaMApCUTFBxiiIxmMolJjyrGuuUUCABbacCjJQrFmMxOhHoKiOoISHhlHNnjStUurRZHmMEtYpgGPGKkpPSfVvAIhfFQWNnKkKkSlyVXxvmMvjPpXTsaHhGpbirxAaBehQqkKKkTyxqhrostToOufFIVvVEevPiYyItTfcuOoxXJjhvZXbMmGKMNufFHtTmfuuZUaRrAuPFogGnNODyYmEiIAakPpKiejJOoEmhHhHAoSRreEeqQgGKMHhBbyYcCOKkoyemsazZAwRuUrWhHNeEfWKlLIiDkKDAmMagRrGybhHEroOjxifFJmrRDsSlTufFWwibpobjLiIXogIlLiDTxIsSAaIikOyWWwwYoSlfyYQbvplIUosSDdaGTitfFTEeYGgySsIadfFRrCcCcuLaAlLNQZzLlFfdAaSsFfsSMXxMmBbWVvFJoOjJwWYmdDOWtTPpwbBrfjjJLlmVvMfdceECDQldjkZzKqnbqQffhHzGzPpBGPNtwWTfFcbBLRTknTQIiOoaAnNkXaABbxKnugdDZTtnNzGUVNnNZzyveREaZzzZIhcFHeEhSrLHtTBgGzZXUoHRrPnNUuiCJjMHgGmMBJjuUmsfzmuUMnVvhMmHhRraixXOhAoKxsiIfFSNjcCJqQVvsclLNZUvVjJulLWwuCcUNQIiqnvwWCcSsbRroOpAaGyMmeToIiYwWkmNrRuJEePQpapPkKmmscgSHhskKgxaSYSsgnecNeYYyNcdDlLIRiIWOUuQwjBsdSsAayLiQqowrqNUxzLUMGgmMrRlLTCQqovzZsTeaxuUTBSssSLPatTuUAuUFlAaQxXWbHhzYBXDnNdWwTiRrIXxaCLdZzfFDCcdDlZmBUmMmqBKkIiIKXtTxUhbpPFXDKwWgdDbhHiXTeEYBrRVbBvpPgXMuVnNPwTSIiUxIioELlpnNBbFSslLSsNQqnnQeEkKFdDwVzvdDiINvVRDSsEevTtMiTMmZztpwCWaNiIzIkIdRroTySsYtJTOonNtCZzbsMAmEyYedDenNQvbwWSAYtXPBAtehOIrJjRXGgqQzrvVaqRrQAhBbHbBexXvVERhHcCVvkezZPfHhFGgaIljJwegwumAarRVkbBxpHKrnNnstOoBUDJjtwWpBblDwxQBbdDQBbqTDdtqXbAasSgEsSYyeDAJjxXvIuUKxwWXpqZHazrnNcXVfZzFWcoOnvefvVNgXZqHVzXxXyIqQYKOCYZzsStQiXCUfFgGuOodDNWUuwLlQLgtTNnFsDRJyQqWyYhUuWwZEfPrZBbBIOTvSyRKkrRrSsFhDQcXEjJxXenXxMmjHQqwCcWmEHovVnNOJjkAbBqQAaaUDdtTeSdDIifqQAVFfvhKWIiwkxTHuNfsSSsLYzZylFiIDRrpPPpQWknBrRQPPXjAnRPtboOaAZcCzmMrRWTtoLlkKylLiLlLlcMDdlLwHohTtmJjMHiINCcgknrRSslLFfVmMzUuTqQWpPkYvMlRfFIUUoYOcGgCoqvJjNnVnNcSsvWTtymTtMwxQAahXCwHhDYyBJeXxnNHbsXuUxOptViQMlBrzMjOgxXGoJmXphHoOgGPWEmMTgpPXHdxXkKNbBLgGtToNQUunNoOSSYSseYhLfVvFxXDoYaYbOoBXxymbJRrYyQYBPmpPDdqcCQEeOJxdVvDGgXpXxxXPpooOOPoOMPpMSMseEbBQqSrNnYyCcRxWERKicCIcCJQkdDBgGlTtucyiwPpWXxwIAadDirviAqQYCdDwWzZHBqNnbBeEQbNnjPIQSOcCfhtnWKkQXRrGJBbjokganFfNrRcCAxXMVvmVowrKxXkCnNQqWHmflDdEXxeOgKSvVaAGgdEsClLDGjOoGAJVlVvLtjcokSmMgGVvaAsKqqQQOfcUyLSsnUoOuNZNTwhHGdDgmMsSCOalDdLqQDzZdADdliFtTfvDaAYRrkKxXIeMmwZEeDwUYxPzZaHaAirCtvxXxKkXayYHMmMuejXidMdDNxQqQDcCsEeymCEAAaraRrARnhcCHKUbLlJjaAtabBXehcCeoOuqwDdEeXxzlQqyilLSDdbBhqZmUuwWLFtxLlcuUCXOqQDhoASyshHuvdpPzmpPMgGguKkkKkKyOhHdDLJyYbBwxgsSurNyXxKesJjOonRrNSXxuwnagGtTtMmTKptmbBGlOWwIcCIieEoOMOoWSscCSJjFfbmMVFPpmFfrzZKYlLrDwrNdDNnjJqtRRUurxwWicWwqHvwWfurOoPFnsnfFEejoOJNZzVvUAtvVTxlLxDBbxqQxSUuSsSeCciIEFfBbsRZEeBbzdwsQJjqSjQqWyYwJniIdRbBrYuUJiEeoOctIGqQGggFivVtGgzQqCHnNhfhHQqFdDcWwkQyuqDGgWfFwfTtHcKkSssSdAapLlElLetFnTEtGeLlTtGCceEeEgnicCNpMioJkAaXxwyvlDdLVTgyeBbpJNIinPdDDDwGgxsEegGSXKkFjJeEvnNVjJOofWzgXxoirRISsqAHhSbBYBlrXkKGgmLlUuQStrplLazZVdDTWwttCzmvVtKkeNnzIFNZJkKjDdqSdDsQxXBbuiUuIULlZzLZxDNkKWTcCNnlSsLlLuUMlIiLzgLnMlJLCnNwQqWoOvDzSkWwdDybBYKsEeZrHhiQaqaCtTcAwdWwDYKkyHSXDTtdJjqxvEhefFeElLbbBBHhClTDdtLiqsStTQxwISsohxDFfCcmXxHQMWwLlkKZfQcCuUqZlsSWShPofFBREexXSsrbaGiFIsQQqVNnvydDwBbdBEepPNnLVMmvHhsSrqMnVvicAEeaGrJsSuUIQOoeehHjTtJjNKkdDnsSrRmMvhHDOmModSReaFnrgLaAGgNnLGgQqDdRKjMtmMwTzZdmEpPYoOkKylLwWCjNnlQqmTtvRkKEeDdMmrVeErylINPZzecCEmvQpPmKyeENaUuMmuUoOLqQGgRtSsUuUXxuocNhDdonUNnxXWwdzZeyYiIEDygyYKDnNdVvLJJYycDjJIsaAbBsSeZzEfIUrxBbtTxSsTUuyOFfCFfnAnNaCxXCcHhcTtQQqQMmqpPwIbfeRrtcCrRTEjrRMmZhbfFQJQqrRXxjNgGnqBmUKsSsSjXwMmtTZzDdWApPdDLlPuUpYWwTItEekMmEKkkKeNHhoOpPdaBbVvPpYhHyAXaAkqQvolNtTdDNqQHyYhtTgWwsEeiBXRrImtXjntTNUIzpKkQqQcvVBbLFdDjJgZbDzgaTjckKILwBbJQqaKkPoOKYyRuNnaxUbMfaKJjnNDduUTrRycCcLXvQqcCAUKaShwWsUMmInNKJuxXUHmKRrhlLHZsoIiOSUTtuRrrRmVykpPMmKsAwWIiyYWwrAjEeaeXxgNMmEQZzqNnaBvyYcBboObBoVBTmGgMtbjJCcJjAaKFqjuHABNqNjTtJtHhBbTlLwWgYyGBfFtTbBPYgzzNnlbBwcujaAJFffFQqfBgjJGvOmmPpcCVJjyJJjqwLMmlextTfOlNgGqdYuUFnNJjRrbBeEjJLqxXpeRrEETtrRelLeEhrYygSHBdcbeEBQIdOOirrheEwryfFSKkKkxMmPkJiIzLlZjUiIuBAaxriCtTqQXrRHlLkAXxsmMflCcLHSshFVqCcQULWwlvyNnRrSsNnoOQFfqkKYMmaCSBZzvNnVORgLAqQxMmUAauQOWwutGHhgqxHKkFfhXGKkoAtmpPHDdhlFvVfLMJeEuUVnjZQqueETtdanLlNoUuiIzZOAOCLlcUuiiKkIHVvhhvCdDCcfBbnEeNTtCcUuSswWbBFAaupPQfWIiMUQinrIiXXeESuNfVvfJjnMeaiHcCAnynNYlMltTuUIiQntFfTBmTuURdUuDrUufFGggGQqKaOpKucZuUKkDdPpmCgrNnaiKkWwwXxDuUxXEVaMmAtBbtOmuTtRtTdDEhzKkXuJjDdFZeriOoIRuZzUoOgGHhWVvwSqiIbWqiMBbIimRrvkXxAaKhHsGgjJSsSEeLubyYYfFylzZmjJwoOWmXqQBbLlxhZRrTXxXCcewKkyYCcWFzODHhyYxXSsUbigEaeKGtvGCANnalLkQqKzKknrRPpZLuUNAXmDLckKCxXgZWwROoaNtTMmbQqRdbNPpCGwaAlLWqmgGyJjhWwsBaACcavVxnzPEMcRmFfQMmqHhckKCpxrbBdDtTrRVvkKRyWmSsptCHhbwyBbTtlAaLllgGMAeHeoOjkBbIioGDdVWDDddKDdkVvJjtQNnkKZJjnNqjsYySPdDXxhHpzZnPtTRmSxXveFfOkGcLnNufJPEZoXvZzVchnkKxXkOogWulnNLnOBlzyYZYIpxvVBbyPpJkKoOPehaAoOuQlLOdDEeORrMXxtJpoOPmMiInNfFuUTtPTtObBLlsiIFfSCcyYltTLmjJhOoOGhvQpnrIiTtNnVvcCvsAaRVhtTLQUIiuAlLmlItTnjOoJPpLljJxTraAHhLluUrRfIPFppBbPNFfnWgGwDQGgRrqzZhHdDdrlLtbBcCEeiHUuwcCaDdXYsvGDcCdbGvVfFvVMmgIiwWeHhEQLlotSbBsTkKjHhOsjJycnTtNTtUuQjJqUXKZNryYRXWwxiIlVzZvDFfpPdKrRrRANneEKkVdDvLoZNZzVvnxXtTQNhBbgGgvKMmFIcCiIiTtXxTTttsJjjoaAORrHhEnTePyYwZwWiIzlJjLpPxXcCUxcCxXrNEAKWwNSsKMMvEGgejJmGgVvpDqXcCuxlLUUuOXxoWwvVuSvxTtpMmPGcSOXYyZgMmGpPzuedDEUToLKtIiuUrqCFuwWTIiXxVfdDFvzZrRXxzRrRjUuSsJqtxXJBbGgaAjcGBPYypbSkkGgiIMhHRtkDFUbqQKSkFMhUBbqesSgGyhHYWieEWQqXxuSPhulHjGiuUpxXPQGgaAaPpTtoONEenUuixtUwOJJyFfYrRiIgrRAKCcRrkySXGPDIivFftSsTMmjJWwXxWwVEeDdAaHFOlLZVOtcWwCTPgcCREGgKMOorRbBGDdgkAarRvVOuMmUjeECpPVlLvkiiQiKkCcJkimsHoORQqUMRDvVdrmYyOhHoPFfKlLrRkiIyYzZnTtbPpHrRtgcCgAlLaGZRrPpcCFvVHhNLlXxXYyxXKuUkxvBNSLLeXWkKNRrQYzzVTWwtzepHhPgeEuUhHgAMWWhHwsybBULlEgRxXLhBkYyTengXMGnbBGgmMvVKknejgGJGgJjyYPnhGgfFHoOfjJFfEeQqfFXxAfBbFBKkIaXwBJjbgGWxuUAargNPpnSAAvVgGaTPGgEoOnNEewGgNtOoYyTwshHSrUuRzwWdDZUuqQfFDdoOsmMSQqLRhIPoeEOAapPoXBbEetTxOpXhHNXDXEeoIidDdrtTRQAaqbBZJfLuRbXxgaUIiLgeBbYqQnEiHjvxXVJbBkTtKpdBbgaeEGMmmMgLhtTdiIaoSsoOONaAGgAKmqrbsSmDdMfFdDTkwfFKlLaAgQcCZmNQqnNaxEVvlBbvvSsVjJAzXtPMqZYVvFGAifDdFIAaRrIUpGgNnCAayUqQXdDgGhpYyPLfHRGgKAakrhGnKkbBNcMObBPpopPvkbgGsSBjJKdDGgVKkyhHXbComgGHaUuyjJoFfGAFUuWryYbIiQqBRQpcCsQRGdDTtIiGgwAaNnNntigfpMmPDdviMmZfFzMmjJKkupDVvdcXxZzkKCPooOePpMKjJCzYyZHhfFQqeWwzTyMmlAaLOoeMmsUIigGMmuLlBIaAoOcCcmiIKYyVnDdmEeyeEqQIuUCcMmZgRrGhdkEMmnNXxFJKdiHFfNnhKHxTtkwWwIZzuJJjjRaeQqxuUXktTRrCWsTAaIBbqqoOafZNnzqdtTwWSsfAaAzZbsZzFKeEkfLuUIcpPAJjhFtchHCJjwmMgGxXFfWusQFfqDLXsSxwFfZzfFWwElPpMQCccCjJnNfAOoCtqGlBzZUwWIHhwWiuUCGgcsSRroRuEoTjnkMmhaAuUHlLokKTtKkjPRrOoXxSspNwWXxniIPRrPpeBbOoGTlXxLdvVUDduZznsnNlPRrbqQBSsPplLpLgGZzZmMliEeILquAajJEnNeWwUZzdDVvGgQGunPpNUwWCvVcUgGuXZOSsNTtnYvdDdWLuUFfCzMmoOaAzZvVzeHWwhEiiICctKMDdmpPHhKHmIimcCYLBbvXxVafqQjJTCcIrRgnNbBtWwZFnNjNnBbqQJfzTYEWkXdHihRnNiIrCOocXxvfUrrRAftTtTFDdaAsSPpwWJYyVoORrvbBNnMJjpmMWlsSOBboLiIeVzZAaLLwWlzZSsgxGNnitBiCcILqQccfFCZYsShyXxYIwWiHutBiyMuUOocCJIijwWmyYNIfnNOoFSLlfrpPrRQqVvoFfAgGuUjiBPpqQQawWtceEcCBbCcbBCPpqyYQlvVLWPYCcyBkgLlGFfKbziIZqLlRrYyeELlcCaiIaAzDbBvwWxAzZRrNiInOoiOraWgZwWOZBqQbNnfwWpBprNnpTtPIiGtyYqDMlLmQqHVWwqrFfRQelCcDdGNnOpXxdDKDdcVvCxopPYLdfrRFuUpHhCcPjJjJiIeEdijhVvHJcRODdogGDdgcLUnNSslLulCDXxTXxtFdDtnbVvByYaykKyHwHensAFfpvVPHBbQqRrbvrRZoOyYzTtfwWFUuVlcChHnSQpPrRifOaAXayryNEeaFYylQfFeQqukKUzaiIOoTbVpGgHiNUugyGPpgBgeEGUuhknwlnMmKkNLlvpcCPXbBxVXIiBsUlizFXxfnlLoOtTsEyWCIiGgkKhUbBuHaDdeHhEizNXxnCDdeqVBfjJYyFiaAIfsSofFOmPQAxYkdjJWsFHhOMmIitpPRrqQRrJjxXfFCNnOowOocCWGkiIKYhaAPBoOCDsTqzRlbhHTHepGgPpKkJjnNpPDviBbIrRbqHpdDQgbBJjfFrGgRGrRrRIGNvVWFpPPRrBGkKGgUupjJPkKPyCcEgGeRrCcOdDoxyBCAacTtWwHhnIqZzQLlwuUWEsmEEHeicCIFMIimlLAFfAnNCxNCcsSyYTtkKKaoPpOHPpfFfFBHuvVnGyzZkeEKtTfvRVoOrXxERrRrDdiIsDdfFaGgKkzvVQgGJjhHqZCjJhPnoOEDTtuifFhHIURrxpPxXEsSbBpsloOLeESgGfzvVhkKoOcHhXxfFHDdiIqAaISsnrRyZzSTyYyYKwWkNFGOogRrVvfsSAXxlgGDbBTqQzTtNwWnZsSIiPwWpYEeGRNcIxnNOOeMmEpPPpooXSMiIWwdDgUueEGyTtYjJvwWtTmMRnoONrTtVfFiwWnNLlIuUPBeDoOdEpPbmbXXxxXwmMWXxNvPzlLvyYkKCmeEMtTZxSGgskKwbQbBqBFkKXxmhHMpPfWXBbpPEezzZnJjLRrlmMtTXxodlOxXTZztoUKkutJjRrHlLXpbBGJjwDhHdgbyYjzZPRrpJvVqFrRjJvVfjJCJaYyddxXDcpPsSxXxAKkuHhOdDzZIIiypMuUmUNGgGgdegGOAdeENnaAWwJcCIYyUqYycCbCcHooOICkKfFQIiqsSWUwlJjLGZzYyEelGLMmlgEeaKkTUuZzbxXWwBfFtlvVMmLlLKzZkaqCcvVvqQVQMtTrRmvVFfuULlOohHAzZsPAsLlTELlzOsyYmrmkMmJjKTjZzwpPUSsDfaAsSFdUtOoTuqMmnBnpPCnNGlHhwjsAjJHInNihawNHhYZaAdDNRdXxYyDxpndKkDQqLsSaOowWMmtTAyYKkiIKkooOUupUBYyVgGvUplLPfFAaubuGFxXaFfDdLlkmMbBlWIojJOiaAJjltTLBXSsSsEGgbsTtStTliILrRBpCfFJjMmULlbnNBucPAtlXFoOLlALlRdKkCcAaDUuFfFfnvVaAXVlLvRbmMNnklLqQUuigGIiorRYZUuThvVXFfxHiPLkQvVqxaAnNqQCqkmMKgBbGnkKVUuvdBHhboTqEJjehgYyhHGOonBZzoOgGkKuKkQqACMmFiIfbIijJyAaCcEeyYYmHhMpPNgIieyeEuxsSqSHUfsIeGJNmHhMsSuleFnNfMmhHzyrcCRYvuUsSzZuYyvjaAjJJVYyFfHyqvdDVlLIiQytMmXxTmsPeEVNfgnNGCYyyAPpeFfeiOoZzJjIDdMJjxrRtTfbezmXgGxGVvgqQMZXxGgVIwDrylNnesCDmFYyfwWUHzZaAwWpgGHOohPpWqBGgbqBbQipCchHnNPIQhHSGgyHhYUuXvDSsyYbHSwWsKmMkhqQjcuUpiIiJmMDqQCcuUjJdjoOgenMbBmEevVfFxXNnNQVvLATiItKGyYgGgbmMNVvoOCMmcnBpBbPpWwPPYypQLZCczZaAqQejbQGQbBVBXxVDdIHhsSsSLgGrNeEtTjJXAaXuUFfxpSsPJMXxmjJjxWsfmMFksIivOTtpPMofFNlLnAaZzOPrHhRWwpZEapPxXAQIiiDpceaAdSiIOoeQqEhHiICcJjYyZiYZIBGgdXqQxPpDgGEeYqQWQXxqbBwgVvGgGZoOXxEezZjJkKuDdAasbBSUsSzNnKPSsTtOofFIilvjJLuBuwoOWSlLHhsEeXqCvgGlLVbuUpDdPAcCAaajJBmMHgGeELjJOolTtPswRbBAdDaTaMnTgGszZoXxSaeRrEeiIEAeEuUewWwPFiItkKTqmZzMfFeljJEeQqIElLeiLaDPpdAoOAIiaLlkYeEGguUvVKjMmJlLwvVIiWYyknPhHwRceKkPpDQqdeEjJZMIimyvVmOKkPiIpoMuKkUpPlSVcCglohGYNjJPtWwwhHwWadhxXCoOcqQzLlQDmMdqZvmSsMZzrRJrRGjzZyYIEeURruUTtBbsMpPVrRvsSBulqmyYiJNBrPAeGgEaxXpYysSNxXGgnbsSIikNnKgnsUUutTfMmsnRIikFQqXxlLrhHInNbEEecRoYyeEzcCgeEjJzZdDBSoOsbMEerRpqPphHQSsNHYyzNBDiIOooyDqeXxEGgbTtSHSshxXmGaAtipPIecCpPahHgBOoBvjvVZJRrjjJBbCclMyxXYmRUugqQGFeEVAaLlkKCcskKXSlkKqQWwVvLObGgNrRnLlzZwWdoODBHhXwWXaqQaAoyYhHzZOXKgdRruUDjwWwyYMmMGdqmOoZzmMnlQqIuJRrLLcLlSshHuBbkKzvVmMZzVvnNJxXAdyYDDdLlWIiwYfFzZTwmMOowoHUuZgGzXxYBboOyyyUjJuueElbBLSsUYfWwSsNnCcmMBBoOSpeOkvgoPpOUTWwtbBkqQErRejJdDWCcwmBbmMMQqkKqZrROokpZXaLkJjshvJXxvVjKCcvYsKkxbhHBhZzkKBbeEIeEnIUuBbiNVvOofeEexUFwWDdfMrqQmzeEPmfFMdbNnBMjJzZvVtCtTuUcEeTNnpGgMnNeEkKmPmPpxXGgzmTtGgoOMJjJjmVvpPMmMAnuUNnZAazYeEdaWwAbibjRoODdXYyRpPRIiEeUgGIVvijJHypPVqQNZzrYyxXkbBrmWwyYYyRrbBMSswWMmVQyKkDdYqLllBnDSsdpYyTtDuUvVdDdiIPfFhHSyYsKsSBpPBbmcRrDtPlHhBbLaApOoTXKkSaLljeDdGgEJrRACjJDBbdOIOFMmaqRaAlpPhHXxLeXxCcixXOoRrYybBIgHTHhtwjJLAUuNsupsiWGgqQOGgxXyQJjqgFfeEtTPptJCcsSUbneaikKIwWOojuUIpIBOoXxTtcCVvUArRtTVHFfJjMooHhOKWFmMIYyuKJQqEzUuZDdbqQBztrxXHHpPhAaUYQqnNDdpPylxXoPpOdDFdDfIiMmLcIipqfvUJHhtBeETQqtNnbEXUuLlxsSeeERPFsSTcmPEepMnXxNbWwmMPpvVBDvVGgVsjJyYqPRruUTtSsFfMmZgGzDdniVSsoPpDdhBbZznrRNFBAaaaOaAFcAaCWtThHCPjGgEeJtTvwWVURruiIERHnNGlGrfYyWGgtTwPLVvMmlpBLFfHhCcsadDAScCtTabMmbBmMmOobBXxNnskKyYXhHBbHhoOxqYfLlbBDdyYRrkKtzrVvMIimMZHMmlLHiIhtBbZzMmxnPpNzZpPiSWwfndDNVvIkHhPpbBdEegNnlxXLXPJuUjoOaUCcuoOaNZWwzJVvjYyjJXxQoOINvVnNnimMdDzZqyYiYWwegFfFfGpjtLrIBbsYnNGYMAxZUuqQzPzwWgPnLltEeDdQZeZOoOooqceuUbqQLlBaWwJjWwQhXkKiITtxDvBywWYPpESnNZKkLdeEhHDNURtTCJjiIgxVvzZRrzZuUPAapeCQpPqIigxXGOoOGLBxXbNWwrRaAZpMuUmPbXuxDdiIasSEejJAKCDdvVcwqQqpsSPNnKkaAIiQpPhHfGqskmZzMKoWHbBhwtTjDzZdhrRwWPfFhJiNeEroyYBbwKRsSRrXxroOLlxXPpwjvVaoOdUVWwvStTbBstZCcEOovVdTtirRsSsCcYjnNJgrRgGjJGpeETtPmwjNnXxmMUuJjGghjtwWYyTRJjnvVhSslLvprrwWRfQqrRykKCGgTfFXxpPtcxXDOtToYnNPMmpizAauUGlLgZATtaeEtLINndDInfFrAaQqRXxruUxZhvlLmIiDGgdMUunQlMPpmKkaUuAiwWxXIZzxXfnNFeEDdIXxYWVWwvIibksGHhgeqQEGqQGDdVvgeEXzmTtMSoOhHsZxdZwxXWzxXDTtiIHhTiOoIdsSEPXxpejJgMSorIilLpPRWUuwExXeCckKNSszZRYSsyfFZnmMcCgGiILqQyYtkKenNFmxXMrRsSRrQSsROorqzZfHhrvJjMmvVVrRygvACcWruIiwWIiiIUZGwevMKyYkmYkKaACQqceEaAyCcpXxPVvymMkKBpPNnrubBUJuUiIKBYybdOoEenNDkKVvJgGjdoOCcOxvXvHhVMFxXflXxpPLeIiJjEUzZVvFfuLoOaGgFfFlLfAjJhHlwxXyYNnlQqUuBbXiIhdDPpYEevVyNSsFfKknNOfFxiBFLZxXzsShXPcpMmPCRrpNnhHNGGkaAiIKGgkKMuUvzZVzZmNnkJYHhJjyfFfFgCBTtJjgGEDdUarRhhHEeMcmMCmGgHYmuNmgGMqQnnNuUUPpPdDpddDDodDXjdGgAaDlLxXOoaFfAEzfxPbHhCcBAuUwWLeElmMaVUuvyYEeawdDueeWwEEatTljTtJaAWwMmaAuWcCyYyGgpPMmPpuUzZCcUhtTQqUuzNtTxfFyEvVmbBEexXnRrwWNNXZzCeETtcmMKksSwWRruVvUyrRYDSsdpluUNgeElLZzBbPvVrzOlLDdLlcCRrjfFIiFfmMTdDPfTtWibBguyDdYxXdDAaGxXQoObBqbtTZzSdDRzZpRrRVIDditOoKcCkTgUumSnyzZeeDmMaAdphLlHyYjYKuuUfqQFUgGSsaxXDTtdqQjrRJjtTcDdBbfOoFfhdjzZnuUxXjJejJoTtjJTtpSslzZLYkwRrWVvSsKEeVvGgOSsoOKkfFKkwyYAuyYMmUDEexqQXgGDdeEtnNTCoOccOoDUbBjJTtiIKddDDsSZzkxqQrRZzepPynoJjPpytTIinNhHasRrmMSAOloOfFLoqQYOHEEbBeehBbmMxiIXXhKkYYyyHzeyYEZYLlvVyxmMrRJFNlEeLsSlLagGAnKkgLaAlGfghHGhkKHUDduTtcdyNFfnhHQddDaALSWwsrRBxXgGRkgiIVDwWdFIPptTfIigGOQCrJjUfLQqcyYqQoOxXwWoNnTtITtrRiDYZzydzZvVHfkKFhOSsoDdFHsSeELmMQmMqHUuhcyYCuTtUuUTtiIqpPdDQldDipPIhqQFnNVwWjJvJjvVMcLBblFfZzfHhFQqCCsScmkJGgYyAuUajKUMmFfhHcHRrhTtECcgGsaSsxeAaQyYgkAaKuUjhHJbBXxQqQqTtIyYiGqjJFOXxZzzGcCuUcCUBbBbgGXeExJjTtKiIUukMmaBbLsNnjJXxMKkEemnNBlLbRtxXGgsSbWwHBbhejRwWCcabBpZzURrmMzZuqQuGWNnaAtTzZwTtEeodlLDvVdDwWeYHtpeEPeEmidsSpPDzoOZrROMWwmoUutoOTITtmMDdKickKuKkUQeEGgqwKkqFrRjcCkKcMmeMmElLnyZaBbAzCxVwWnNvOocCgGuUOooOLlnIicCZzdpPDeENhHLlZGgIiZmMzdfFHjJgGaAhjJmRHiIrRhzgGVvECcQqvVIiHhFfLlYOqQaAoyRRrjIisSksfFlLCcKrRkqQqQehHeCjBbiPpmMIJgRrtTqQtTnNcwwWWdiSsIuUoOfMmFqgGIsSaxXFfFfUsSIiHdDhuAijrIiWhHwWGgZzSsWwkKtTMmwBbPpRZNnzZFeEaAfgGVvzZIixXdpPGqQgbBtzwWlLZeEIirRfFJvzZPpVwNiIqcCKKkRJjpmZzrRlLZHhSbBAajKqQNnwVvCcgXupPULlhHrRDdMmbMGgPZzpfeLlXxEqQNFfOnNKkvVoTYulLaLUOoHhjBCmMcIrqQoOKkRCcslZMESsegGmMmZzzZpXxaAqSsQKVvkkKZzhHCcMhbBuUHIiujJrxXRWwUgyYGJvXlLjpPQqJHhdDMcCaAIimXxbBZzKksSQnNsSqQbBRrlOoIiLHAaxXBblQdDqsfFSRUuctTCpAajgGJgSsXgkKGxINjJnBhHbrRlLMmoOOzbowWOhHxXXXnKkNtAQqPmMJjGUStTsLlQqEeEeuyFLlFjJZzIFfRAtAaJeqQEwWMmjSaVvnNoOoOGgcNndyYbBFfDaAqjJsSjJvIiEehDdHcCuLsSFfYyXxXVeEvTtuUxXxNnytwWTevcCTtVEHeyYEMzejJEAxXaKkWwAAPpLVvbBCboMPpfXxSUuswFxHhXKkSsjJfvLlCcKzZkVXwEMmnNexXWkQPplLgGXxiIgPpGqQMmahHAqDliILxXdDUuKCclpPLkPbBvVuXzZNnxhHdDUpVcCrRvuSSstTZhHzjJjfOouUVvvVwWrRFRTtrJsMQqZzIisSfFBxnMbMmVvBJhKksSaAGgHDdvKktTrCcReiAafFIhHzrRZeEHhosSrNxYuDdYySYyaAsZzySssStuUTOaAoMcCWgMmGhBZzSseLyYlrREKkbHgGDdQrRUuMmqtTjYyHuAaYjXxJyUAaFCccCBbsmMrRHYykrRDiIdgGvRrVWWbBwPpwqQeqQEkzZwWKYyJUujDlCcgGOovwWVLWwdhHpPFfKGAnNZzusSXhHoOvVGFfgVuIiOZzoZPpWwzOKkoULYTtYyVxJjXHhyGgVvUuvTtpCcsSWmMpVQqvmCcZkWwSsFfoXxKnXIixmlLLwzZLlHhLlVvIiWZzlbBeEKkYlLWwLlhHfFMmycAUpPnHhnNNeRTtrEEeFfygGwdkKDtTSMmsEBsSbNnJNijsSuUtruURAWwarIQNnTtqQPpTpPCctRrAaLxBbaAiIXfNoOwLlWZzaWOFfbBAatTBbozZxZKKGgkhHdDgGkxJjXuxXUBbVuUvtTjKwWyVcCvPkKprRYqQkCcfFJjDlLLRGZzDEIienmMcCRrNGDcCWwdgiIuUKsSkozJjtTQQsSFfXxQPpVvqGlzXxZhUueEMmMpXrxXRxGgPIibBwWOUaAuomsSSsyOdNSsnQqDoKzTxXtfFZkiISXxkKavVmMAXZzyYvvVCcMmVLmMwiQGVhHpvVvUuVPLKklUuvHhtIiqvVQzZQKkRrBEQqevVpcTtGEMmMHhmrRegkGgKWwpaBbAPiTtIfxXFNnxXDdeEfadDGgaAihHSYyzZsbZbhHBZzzBNJjUupPEsDcCRrdSJjmZzvVpPJMmyYGvVgnVvUuNpftEeTFUuhqQBbSsrRkZzVkKvcJnNjJPphYyHCkzYGgDdyuUZdCcdDgGDxsSXBblEQiqQqQUlLKkZdnNOcCMmopPEeTHhtJBbllLAanoONpPKcCeOonnNNEBbSsAaUIcCiotTqUJjuAaCcflrRLBbgiJkKPOoYypRJYGOosDhHMHhnNmdeEsRrSNnbwHhWkKlsSLBFfScGfFPpgCtAvuUVaXNnxLJHhyYjlYEefuUAqJFfvVjQqOoUuWwmMoOYabBAjxrRXBiIbgyFQPpucCUqvlLWFfsKkZQkKkYTtaAycqXxQCYOoSsxXdDpPytTKMmfMrLBxoOEeXgJLljGNnHcCmMsSjAIiaXxPpaADbBMmZzRryYJeEjdKcCkhHhiIxEwzZAaOjJodsSDjbQMmqpPBQqJOmmBbMhHlaAjcCWvVwJqQZUyYTtWKkwPptyYiITsSHnNcQqCjJhxXuHhwWpmMyYdDkmMIaAiaMpPqQmMeEmvVhHGgBbBrRBbibgGBIbEkKFlLFfPpHhyYmMfgGLlWwHuEthDFSntTfLlFNWwsoiVFfbBEevVIxXXAarRylLYjJxMlLNnPpmoOPpijXIigGjJqQCkKOopPCVvmMhYyYiIfFyeEHcctLlTHNnMmNnAapBbPNnMmxtmMmnfFNjJbBMAaYykKEeBqyYQcguUUuFwWfhHmSsSngGNsMkKVhHtjJJKkChHcaqsSIiwWAabfqyYQKWLlxXxXCOkkKfFKEtUuTejZxyLNnQqoOcCleEBfFNnlLGgMcYEeTtshIiHWtTBbbFfEedZumlLMUnXxvEeIUKnNkuyYUuloiFfiiIfFIAXCcPtTpxXvmMKkVwWxwMmWaAaADdQquCzXxZTtyYidDfFIcSsUapPFfxXbBhHfFqQWtToOIiwnNjYylLgGcCOoHhCcJeEAaKkRrtQqPpRiIjJfAaFOoMmQtPiIPNnwWVvuUpXCgRQdoOCcDYFfyEeuUeEuhHmcVUuvCMmMUobBvbBcCqVvQVGYygDaAdkMZzmOoPGIiMmpPkKFaAUuhkTWwoZzPSsAxXapUBAabudDOYyfFgGSsIiGgWwreeWwEEAzZgGaYoOLCgkKGtTQqKkGgVvclwgDdGWyYpPiRrZjJzaAfFeEmMneVvbBrVvREKkRrlFfLqAaQjJaANSsSXxsoBbOLrRlsgGSYpPyPpLzsSZZzlICcJjmMFgSrRsdDvVFfJuUOojIGgFrMoOmSsCYNnbByeEccTtIilXxLUuqQKkCGgIiSJrRjxXshHkKIicCIPpifFxXyXfIiyZzGgYBKRrkmXxRrMdDgvpPVIxXiDdGgwWqLlQDdbrRBGTnNrRtbPpIihQGgZaAcCzfFvVeEvVCzZcmmMMUjDrRqtTeERrUuQddnTeaAhCcSsPpQRrqGglfKkFLZmXVqQNnmOpPSsSsiOohHJjCcXCcxkXxJjxXzZhVvkcBjXxXxbSgGpPgSsxBbdDeEpcGgCPXRRrCbjeEtTJBAaccdDfFtbQqBTAabBCHCchZzXVRraAIiLlvwWYyUupPxDiIOoxXtCcIiQqXXbBMmaArpPRogGSseRrzZcCFfEcCkKkAaBDdoOhHKkbIiyYrRLIilKOosDUudSlQqDdyYpvMmVLxXlAaiWwIWwKoOAmceTtFkKTWwcvVCTRrhHqsSPpvUgGsSwvVeTAaPMRrRdDriISUuoOsVvjJyIiYMmJjcFRrfJxXPpjdDBbKkyYBlLYaxXTjJhHtaVvAALeElgtTcCGqiIQzZMBIibIimaAcCTWbBUvVDVLlvEeWwCcTAIiJHhjKlLkatgTtxqQXQqGKkwJMWwaAmwWjIipDdmMHhpCcufFoOUwWPqQiIPuUzZpiITttTPpXxNjdDEeAaQqJDFfdQqnaAduUZzDFOdDHNnhoeLHhrmMnNDdRcTNntHTtYyPpeEWwjOoqQJhCKmMkzbBZENzZnuBbUFfcCMwWOaIiTQqNntpPTtAeEiILIirRbKyYkzZBZvhHVzsSduUxXxXzmeEwWMZPJjQqpTtXxTtpvVuUPfFHDEedhDWwIilZvVXxzcCLlsHCeEcLlGgVvgvVGsSfAxBeEbtTmUTtUuXxeEnNmMYbfQqFBlTtLuOoOoUhHghHGdDPVvKFlLURoJjOZzZzyTteEsZzOLllLoRUubBVKkvvKkJjVrRPpVDdnNvYyzZuUrRekKEWvUuLlVOTkPpPpKXNnkKyZuUzYwWZOoxXVKHLlTtWwhXxqcYyUuCaAFfBAabQbBpReyAaYEzZrQqPgGToOxXCkXHhqQxkRrKKcbAaBTtdAaNnDvHjJdDQdDUuqnNkQqlLKNnWwMVcCmMIdDigvVGwSsTtWvfPpgGFDdKkwMmzZxZzTbaASszZvhHVBmMUutDdXsUGgygGMmYuHhSWQCfBbFcRrmMNnhoOHsSAaskKGgfFAaFlLffhHFbBVXxRrhHvuUVxXDwWTtdlLDOKkoneElLNANnhdDNKknuUNeEnJjjJDuUdRrPpHadDWwDdSsFsSfdDVvTTtTxXtbnNBgGqQtdmKkPpbeEZzAscCSaHsSxPpdaADDdoIiOqQHhYyQDdYDWwvwwgGWLnNlkiKpPkIiIKOoLlWyYVMmTWwthHEerVvRsJjSrRfZzFHGgMmzfFHhZAauURMJjmrkKcXzsrRSnVvNZxiIKcCkQekKlLEHOoLlhdDCcUkwWkKdGLlaAgJYykKjVxyYXIJjBbFaAccioOMmICpTtqPpIiaAZzQqlKkLIiYGgylLQjJssSNnSCDlLdcCcUTtBcbBVUuJwWjZAhHKkaXxBbzeEKZzWwAGPpffFUTFftuFWKkwSlLsOogjJauUvVEbBefFrRFffFnKknNNqzZcCzZRrvVAaipeEekKiIEuCuUyYcUexyYZTtzcCfhHFIiDddDeEUzxXZAfFfIiFrxXRatTYyIiaAvAavVVhHMmlLWwhHIiEvGgtTcCVTtesdgXtTRWwrJjGgxuUhyYHMmqWcfzZFEeCeOosSEVvQqwgPpGnNvSUusVjJEeQXxGOoVvgGAaeMUumESEegGTtstTYyFfDotTbBAaKbBkiIwJbBuUpPZaALlvFfEedzvVZDtTmMVtFFffyFfJjmJjMYgGTzgGhHxqQXfIiFuOogDnDWLlwWdDTFftzZBbBbJHhjOocCsjOLloJSuMmNHhnsShHQNnBhHbRQwWqEePpXprRHiIVviIAMmaEefFhQqnNAaPlLRrxbjJgGaSsAtTjROzZouUKkSgGWDdwNGgnSssQqBbdDdHMJjAOoamhKkiIDBbrfFOoPpJPjJxXsSZzGgVzZvOolLpbBxXNOoHhMmnBfFbLlHDdyYhIiNbeEBXxhRrHhHnsSoEeoORrnqQNXxcvVcCCRlLrQmMYyqHpPgNnkKgGOfFiImMoGIiMWwZtTzKuUkFfmmcCvcXxCEbKkBXxuUgGjdDCwkKWeEuUuUTtVjJVvDdvnNCcPplLqQsGXxaArRZSszuYytTUsSkKHhgEkKeJOoxXeEiIxGcCgXGgFfcCGgjMaApPQqZzBfkKKkFDdgGonNrRDdEeOMmRrLlYyqQacCuUJjAePpEuUbGgBuUdDWwUfFReErSsubGgBbtTGgcCUFfFcbjUurRJrRkMMiIZzmZzmOoNSCcKkRrsRrxZmUEeDduMbBmMoBiIsMmSOoWwMmDdyYxWkfZzFoOKwxXXbAaCXVvxcsSsStBbTRzZKkzZCrsSTjJtRcekKkKErrIiRzmFfMCzZcCcZfFtTOsUuSDRrtTxXeExEeCTcCtsSGlkKVvLkcCKgIiDKZzdDkDdQqXxXmMPqQpxnNAgGGFfrRsSeEAagUrRRhHrMmuhHkKdCcNUuKknYkAaKGhHgaAyzZslLSDMmCcLCchHhHlsQYykKqAICcNnuUffFuUMGgbBbBdDVvjJmyYOsCndLlwWDNciIhHvVlDdKlLkXhHaAMmKkFfKkkMmLlKxwgGWvVLlLIbdLlFfxXmVvBbFyYfRrAiIaMrRrCoOcrOoIinNEuUiIyYhHeRUuxXrYwWRrjJbBAakVvJjKpHOohPuUyEedDKwWMOlLoFfKknNsSBbmeEAdDakhXxeEHRXUaaPHKGgreKkEReEWwzZkhpAvyUuYDdeEVxppPCqQdDULVvtGgmMeETlPpGoeEWdDyYcCmMwTtNnxQqXEeOzZwGgWTtqQKkgUAaiVyYvuUwWIrRuuTrRtyUOouxYyXIidKkNnKnoONCoOcvVnNrbBRNVvxTYytXnRroOsSFfyYwWAayUMmeXxEueUuEKknNYEZSkuaAeExXUKoOxEHhekmOQqWrRwojjYTtTjJgGPptOoGgzZlLBbywWYyvVJJjJjJgGWwsAFfaSMGgNneEehHkKEmVvbqQrZmFfSsMVvzHhkKoOIaABbCnNefFMmEcAaiZzhqQdDbJjrRYytvVLlTCKkcLleEwQqWqQmMSrRTtEeQuURrxXQxaPpAyYAaXkKTtqIHEehmMlLqQrLlROoNoJjEJjeXxOGgnfFIxXimMKkLliXBwQqWKkpYBbyPfGgFUuzpPZjNWwnJiIOoDdbdDNnKZzkmMpvoOVbBbBPlbBLxQSsqAbjJBZxlLCcjVIiaAvJXEeCcSBfFbszAFfbrFVvfNnRGgjdDImpPMfFiuZzUJvQqSsluBbUkKCJjcpPLrRiIVcCveEVlLUulZzLOowWgxXZzGqOoQWVveEIiKkwnNnNhHoOCcAoaAOEeaLlnNcCCsScFlLkaAKEMmNnaAvPiFfIpVnExXetqQTKkNlFftTXxuUUuLLlefDzZdSsqQlLTxXSstmMYCcPpeEyPaALXxRrTMmtrXpgGPvVxcCNnQqDBbdRlNJcCjFfRrIiCcOojJRrzZutpjJRwWAaZzrlLiGgKkIeEPTUgGprrouUORYySsGgRBbVvUYsAaSJqQjdDjJrRPgGxXpCZzcFtxXTzZFDUudKXxkHhftTKkxXTVvwWtWenNEIiemZzMZxXzEDdbBuUqZzuUQvVsLwiIWlSeVvwWEktTabBAKqTtjJQaLDdlAVRruIBbTtiURrvdDCbBTcCTtSbBsEeLlRrtOpPYypPohNeEnZfFzHvmMViIMmOoQqmMqmMDJjdjPpIiRrCpPcJHznNZcIiDWwdlLpPzfFZFfNulLUpdDPpPeEsSxXgGniIHhoOmMoObBKLlkAajJlFokKOfOoLGxXIiDdgqkyYuUKxXYywWooxXpGYygwWPOtTWzZwXxLNzZOonlpEeOoGgPDdlLZzmTtCfFcZwWFfUuDnNdbNnBRqeECcEenNQrKkNnzVaABbaALhFfHDdwWlvxCcXBOouUbvTtggGGVHhrRxUudCcDUgVnNqQaAvhzZHjBbywWYIirRJhXxHLuUJjlZzUuwWrRlEQqeLQqqQlTtWwveEVLaeEAmMfbGgBFWwHhzbGgBWHhwxfxXFXZNWwdDnuUvVmMGOoTDdRrBrRbNnteGRrgcCgGWwEiIZZsSzRrCvVDdcaewWEAiIBfFbzwWjuUJUvtTLlBYybBbTQqPptTtGNnQqgMUumSstsSnNtTCcfFvBbWwXxVVvGWweUuEKkCdFfTtiIDcHhcCCcOPpAaogoOJjJoOjcCRaAIiNLTtlnpPInNircCHhloOLuUvvVVqQYxiIXyMtTsSWsSJjHhWoJjUovEeVZzOuPNjJgGnIipcCkwWKOUNUunxXvVMmRyoRrOjJYrOZzmvVrRXxMPdHhbBoOxXDEeOoKknNpHyYhcCHKkrRUlLOoupPvVuUyYhAaxXoMXxgGmuTxXtGgxXsSGgdDwyYQPpKkqwXsSxmMIiRryYFfYycCJjCcOoYyzZYQGIiPpaAGggqyYgUjRrGgJbBuPpLly'\n
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/","title":"Dictionnaires","text":"Pr\u00e9ambule : retour sur le cours de Premi\u00e8re.
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/#0-notion-de-tableau-associatif","title":"0. Notion de tableau associatif","text":"Un tableau associatif est un type abstrait de donn\u00e9es (au m\u00eame titre que les listes, piles, files, vues pr\u00e9c\u00e9demment). Ce type abstrait de donn\u00e9es a la particularit\u00e9 de ne pas \u00eatre totalement lin\u00e9aire (ou \u00abplat\u00bb) puisqu'il associe des valeurs \u00e0 des cl\u00e9s.
Il est habituellement muni des op\u00e9rations suivantes :
Un r\u00e9pertoire t\u00e9l\u00e9phonique est un exemple de tableau associatif :
En Python, le dictionnaire est une structure native de tableau associatif.
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/#1-dictionnaire-et-temps-dacces-aux-donnees","title":"1. Dictionnaire et temps d'acc\u00e8s aux donn\u00e9es","text":""},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/#11-protocole-de-mesure","title":"1.1 Protocole de mesure","text":"Observons le code suivant :
import time\n\ndef fabrique_liste(nb):\n lst = [k for k in range(nb)]\n return lst\n\ndef fabrique_dict(nb):\n dct = {}\n for k in fabrique_liste(nb):\n dct[k] = k\n return dct\n\ndef mesures(nb):\n lst = fabrique_liste(nb)\n d = fabrique_dict(nb)\n\n tps_total = 0\n for _ in range(10):\n t0 = time.time()\n test = 'a' in lst # on cherche une donn\u00e9e inexistante\n delta_t = time.time() - t0\n tps_total += delta_t\n tps_moyen_lst = tps_total / 10\n\n tps_total = 0\n for _ in range(10):\n t0 = time.time()\n test = 'a' in d # on cherche une donn\u00e9e inexistante\n delta_t = time.time() - t0\n tps_total += delta_t\n tps_moyen_d = tps_total / 10\n\n print(f\"temps pour une liste de taille {nb} : {tps_moyen_lst}\")\n print(f\"temps pour un dictionnaire de taille {nb} : {tps_moyen_d}\")\n
La fonction mesures
prend en param\u00e8tre un nombre nb
qui sera la taille de la liste ou du dictionnaire. Dans le corps de cette fonction, la liste lst
et le dictionnaire d
sont fabriqu\u00e9s avant le commencement de la mesure du temps. La liste lst
contient des nombres (de 1
\u00e0 nb
), et le dictionnaire d
associe \u00e0 un nombre (de 1
\u00e0 nb
) sa propre valeur.
Dans ces deux structures, nous allons partir \u00e0 la recherche d'une valeur qui n'a aucune chance de s'y trouver : la chaine de caract\u00e8res 'a'
.
10 fois de suite (pour avoir un temps moyen le plus juste possible), on va donc mesurer le temps mis pour chercher la chaine 'a'
, qui n'est pr\u00e9sente ni dans la liste lst
ni dans le dictionnaire d
. On mesure donc une recherche dans le pire des cas.
Nous allons effectuer 3 mesures, avec une taille de liste et de dictionnaire augmentant d'un facteur 10 \u00e0 chaque fois.
>>> mesures(10**4)\ntemps pour une liste de taille 10000 : 0.00023534297943115235\ntemps pour un dictionnaire de taille 10000 : 1.6689300537109374e-07\n>>> mesures(10**5)\ntemps pour une liste de taille 100000 : 0.0012505292892456056\ntemps pour un dictionnaire de taille 100000 : 4.5299530029296873e-07\n>>> mesures(10**6)\ntemps pour une liste de taille 1000000 : 0.012522673606872559\ntemps pour un dictionnaire de taille 1000000 : 2.384185791015625e-07\n
On remarque donc que le temps moyen de recherche dans un dictionnaire est remarquablement constant. Il ne d\u00e9pend pas du nombre d'\u00e9l\u00e9ments du dictionnaire dans lequel on cherche. On dit qu'il est en \\(O(1)\\).
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/#13-conclusion","title":"1.3 Conclusion","text":"Temps de recherche
Il y a donc une diff\u00e9rence fondamentale \u00e0 conna\u00eetre entre les temps de recherche d'un \u00e9l\u00e9ment \u00e0 l'int\u00e9rieur :
Attention : en ce qui concerne les temps d'acc\u00e8s \u00e0 un \u00e9l\u00e9ment, la structure de tableau dynamique des listes de Python fait que ce temps d'acc\u00e8s est aussi en temps constant (comme pour les dictionnaires). On voit alors que les listes Python ne sont pas des listes cha\u00een\u00e9es, o\u00f9 le temps d'acc\u00e8s \u00e0 un \u00e9l\u00e9ment est directement proportionnel \u00e0 la position de cet \u00e9l\u00e9ment dans la liste.
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/#14-one-more-thing","title":"1.4 One more thing...","text":"Int\u00e9ressons-nous maintenant \u00e0 ce qui semble \u00eatre un peu trop miraculeux : une recherche en temps constant, quelque soit la taille du dictionnaire ? Mesurons cette fois non pas la recherche dans le dictionnaire, mais la cr\u00e9ation de celui-ci :
def mesures(nb):\n tps_total = 0\n for _ in range(10):\n t0 = time.time()\n lst = fabrique_liste(nb)\n delta_t = time.time() - t0\n tps_total += delta_t\n tps_moyen_lst = tps_total / 10\n\n tps_total = 0\n for _ in range(10):\n t0 = time.time()\n d = fabrique_dict(nb)\n delta_t = time.time() - t0\n tps_total += delta_t\n tps_moyen_d = tps_total / 10\n\n print(f\"temps pour liste de taille {nb} : {tps_moyen_lst}\")\n print(f\"temps pour un dictionnaire de taille {nb} : {tps_moyen_d}\")\n
>>> mesures(10**5)\ntemps pour liste de taille 100000 : 0.004771041870117188\ntemps pour un dictionnaire de taille 100000 : 0.012260651588439942\n>>> mesures(10**6)\ntemps pour liste de taille 1000000 : 0.04549875259399414\ntemps pour un dictionnaire de taille 1000000 : 0.14215753078460694\n>>> mesures(10**7)\ntemps pour liste de taille 10000000 : 0.4727184295654297\ntemps pour un dictionnaire de taille 10000000 : 1.302360200881958\n
La cr\u00e9ation des deux structures semble de complexit\u00e9 lin\u00e9aire, mais elle est surtout bien plus grande pour un dictionnaire que pour une liste... Pourquoi ?
Parce que pour b\u00e9n\u00e9ficier plus tard d'une recherche en temps constant, la cr\u00e9ation du dictionnaire demande beaucoup de calculs...
Petit d\u00e9tour par les fonctions de hachage :
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/#2-fonctions-de-hachage-hors-programme","title":"2. Fonctions de hachage (hors-programme)","text":"Tout ce qui suit est hors-programme de Terminale, mais permet de comprendre comment Python arrive \u00e0 faire de la recherche en temps constant quelle que soit la taille du dictionnaire.
Il est important de se rappeler qu'un dictionnaire n'est pas ordonn\u00e9 (contrairement \u00e0 l'objet \u00abdictionnaire\u00bb de la vie courante, o\u00f9 chaque mot est class\u00e9 suivant l'ordre alphab\u00e9tique).
On n'acc\u00e8de pas \u00e0 une valeur suivant sa position, mais suivant sa cl\u00e9.
Dans une liste, lorsqu'on veut savoir si un \u00e9l\u00e9ment appartient \u00e0 une liste (probl\u00e8me de la recherche d'\u00e9l\u00e9ment), il n'y a pas (dans le cas g\u00e9n\u00e9ral) de meilleure m\u00e9thode que le parcours exhaustif de tous les \u00e9l\u00e9ments de la liste jusqu'\u00e0 (\u00e9ventuellement) trouver la valeur cherch\u00e9e.
Dans un dictionnaire, on pourrait s'imaginer qu'il va falloir parcourir toutes les cl\u00e9s et regarder les valeurs correspondantes. Il n'en est rien. Pour comprendre cela nous allons faire un petit d\u00e9tour par les fonctions de hachage.
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/#21-verification-de-lintegrite","title":"2.1 V\u00e9rification de l'int\u00e9grit\u00e9","text":"Lorsque vous t\u00e9l\u00e9chargez un fichier important et que vous souhaitez v\u00e9rifier qu'il n'a pas \u00e9t\u00e9 corrompu lors du t\u00e9l\u00e9chargement (ou avant), vous avez parfois la possibilit\u00e9 de v\u00e9rifier l'int\u00e9grit\u00e9 de votre fichier t\u00e9l\u00e9charg\u00e9, en calculant une \u00abempreinte\u00bb de votre fichier et en la comparant avec celle que vous \u00eates cens\u00e9e obtenir :
Voil\u00e0 par exemple ce qui appara\u00eet sur la page de t\u00e9l\u00e9chargement d'une iso d'ubuntu 18.04 :
La cl\u00e9 MD5 propos\u00e9e pour chaque fichier est le r\u00e9sultat ce que doit donner le fichier (ici une iso d'environ 1,9 Go) lorsqu'il est \u00abhach\u00e9\u00bb par la fonction MD5. Dans notre cas, si nous t\u00e9l\u00e9chargeons ubuntu-18.04.3-desktop-amd64.iso
, nous devons calculer l'empreinte du fichier t\u00e9l\u00e9charg\u00e9 et v\u00e9rifier que nous obtenons bien 72491db7ef6f3cd4b085b9fe1f232345
:
Essayons :
La cl\u00e9 calcul\u00e9e sur l'ordinateur correspond bien \u00e0 celle indiqu\u00e9e sur le site de t\u00e9l\u00e9chargement : le fichier est int\u00e8gre.
Exemple
T\u00e9l\u00e9chargez le fichier banniere.png et dans un Terminal, calculez son empreinte MD5 :
eleve@linux:~/ md5sum banniere.png\n2895bae45eb0ab36a2a8324c0208ad95 banniere.png\n
Si votre fichier banniere.png
a \u00e9t\u00e9 convenablement t\u00e9l\u00e9charg\u00e9, votre empreinte devra \u00eatre \u00e9gale \u00e0 2895bae45eb0ab36a2a8324c0208ad95
.
Quelle que soit la taille du fichier donn\u00e9 en entr\u00e9e, la fonction MD5 va le r\u00e9duire \u00e0 un mot de 128 bits. Ce mot binaire de 128 bits est repr\u00e9sent\u00e9 par une cha\u00eene de 32 caract\u00e8res (en hexad\u00e9cimal, de 0 \u00e0 f). Il y a donc \\(2^{128}\\) (de l'ordre de \\(10^{39}\\)) empreintes MD5 diff\u00e9rentes, ce qui rend quasiment impossible le fait d'avoir un mauvais fichier qui donnerait (par un tr\u00e8s tr\u00e8s mauvais hasard) la bonne empreinte.
Le m\u00e9canisme effectif de calcul de la fonction MD5 est tr\u00e8s complexe : une explication en est donn\u00e9e ici.
Il est \u00e9videmment impossible de revenir en arri\u00e8re et de recr\u00e9er le fichier original \u00e0 partir de l'empreinte MD5. Dans le cas contraire, cela voudrait dire qu'on est capable de compresser sans perte un fichier de 1,9 Go en une cha\u00eene de 128 bits. Cette impossibilit\u00e9 de trouver une fonction r\u00e9ciproque \u00e0 la fonction de hachage est tr\u00e8s importante en cryptographie.
En effet, les simples cha\u00eenes de caract\u00e8res peuvent aussi \u00eatre transform\u00e9es par une fonction de hachage :
Quel est l'int\u00e9r\u00eat de hacher une cha\u00eene de caract\u00e8re ? La conservation des mots de passe !!!
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/#23-le-stockage-des-mots-de-passe","title":"2.3 Le stockage des mots de passe","text":"Les sites qui n\u00e9cessitent une authentification par login / mot de passe ne conservent pas en clair les mots de passe sur leur serveur. La moindre compromission de leur serveur serait en effet dramatique. Ce qui est conserv\u00e9 est l'empreinte du mot de passe apr\u00e8s son passage par une fonction de hachage. Par exemple, un site o\u00f9 notre mot de passe serait vive la NSI
conserverait dans ses bases de donn\u00e9es l'empreinte e74fb2f94c052bbf16cea4a795145e35
. \u00c0 chaque saisie du mot de passe c\u00f4t\u00e9 client, l'empreinte est recalcul\u00e9e (c\u00f4t\u00e9 serveur), puis compar\u00e9e avec l'empreinte stock\u00e9e. Lors du transit du mot de passe, le chiffrement effectu\u00e9 par le protocole https
assure la protection en cas d'interception. De cette fa\u00e7on, si le serveur est compromis, la non-r\u00e9versibilit\u00e9 de la fonction de hachage assure que le mot de passe ne peut pas \u00eatre retrouv\u00e9 par les attaquants.
Prenons l'empreinte MD5 bdc87b9c894da5168059e00ebffb9077
et allons fureter du c\u00f4t\u00e9 de (par exemple) https://md5.gromweb.com/
Notre empreinte ne r\u00e9siste pas bien longtemps... Re-essayons alors avec l'empreinte e74fb2f94c052bbf16cea4a795145e35
.
Les empreintes des mots de passe les plus fr\u00e9quents sont stock\u00e9es dans des tables (qu'on appelle rainbow tables ou tables arc-en-ciel) qui rendent possibles le d\u00e9chiffrage de ces empreintes.
Pour contrer cela, les cryptographes rajoutent des caract\u00e8res avant hachage (le sel), et choisissent surtout des bonnes fonctions de hachage. MD5 et SHA-1 ne sont plus utilis\u00e9es, on pr\u00e9f\u00e8re maintenant SHA-256 (voir ici).
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/#3-retour-aux-dictionnaires","title":"3. Retour aux dictionnaires","text":"Quel est le lien entre les fonctions de hachage et les dictionnaires ???
L'id\u00e9e essentielle est que chaque cl\u00e9 est hach\u00e9e pour donner une empreinte unique, qui est ensuite transform\u00e9e en un indice de positionnement dans un tableau.
Le dictionnaire :
d = {\"pommes\":3, \"poires\":0, \"bananes\":5}\n
serait donc par exemple impl\u00e9ment\u00e9 dans un tableau comme celui-ci :
On peut remarquer que ce tableau laisse beaucoup de cases vides.
Si je souhaite ensuite acc\u00e9der \u00e0 l'\u00e9l\u00e9ment d[\"kiwis\"]
:
\"kiwis\"
est calcul\u00e9. Par exemple, 4512d2202
.\"kiwis\"
dans mon dictionnaire est calcul\u00e9 \u00e0 partir de ce hash 4512d2202
. Dans notre exemple, cela pourrait donner l'indice 3.\"kiwis\"
n'est pas une cl\u00e9 existante du tableau. C'est notre cas ici car il n'y a rien \u00e0 la ligne 3.\"kiwis\"
, la valeur correspondante est renvoy\u00e9e.En r\u00e9sum\u00e9, Python sait toujours o\u00f9 aller chercher un \u00e9l\u00e9ment de son dictionnaire : soit il le trouve \u00e0 l'endroit calcul\u00e9, soit il n'y a rien \u00e0 cet endroit calcul\u00e9, ce qui veut dire que l'\u00e9l\u00e9ment ne fait pas partie du dictionnaire.
Par ce m\u00e9canisme, l'acc\u00e8s \u00e0 un \u00e9l\u00e9ment du dictionnaire se fait toujours en temps constant.
Il existe une mani\u00e8re de \u00abvoir\u00bb que Python utilise une fonction de hachage pour impl\u00e9menter un dictionnaire :
mondico = {}\n\n# un nombre peut-il \u00eatre une cl\u00e9?\nmondico[4] = \"foo\"\n\n# une cha\u00eene de caract\u00e8res peut-elle \u00eatre une cl\u00e9 ?\nmondico[\"riri\"] = \"fifi\"\n\n# une liste peut-elle \u00eatre une cl\u00e9 ?\nmondico[[2,5]] = \"loulou\"\n
---------------------------------------------------------------------------\n\nTypeError Traceback (most recent call last)\n\n<ipython-input-1-585560b5c422> in <module>\n 8 \n 9 # une liste peut-elle \u00eatre une cl\u00e9 ?\n- 10 mondico[[2,5]] = \"loulou\"\n\n\nTypeError: unhashable type: 'list'\n
Le message d'erreur est explicite : le type list
que nous avons voulu utiliser comme cl\u00e9 n'est pas hachable, car c'est un type d'objet pouvant \u00eatre modifi\u00e9 a posteriori tout en gardant la m\u00eame r\u00e9f\u00e9rence (on dit que c'est un objet mutable):
a = [3, 6, 8]\nprint(id(a))\na.append(12)\nprint(id(a))\n
139646950377032\n139646950377032\n
Ce changement de valeur tout en gardant la m\u00eame r\u00e9f\u00e9rence d\u00e9truirait le principe associant \u00e0 une cl\u00e9 unique une position unique dans le tableau impl\u00e9mentant le dictionnaire.
Ce probl\u00e8me ne se pose pas si la variable d\u00e9signe une cha\u00eene de caract\u00e8res, ou un nombre :
a = 2020\nprint(id(a))\na += 1\nprint(id(a))\n
139646916523440\n139646916523504\n
Un variable contenant un entier est donc un objet immuable car si on modifie la valeur de l'entier, la r\u00e9f\u00e9rence de la variable changera aussi. Comme un dictionnaire a besoin d'avoir des cl\u00e9s dont les r\u00e9f\u00e9rences soient d\u00e9finitives, seuls les objets immuables peuvent donc servir de cl\u00e9s dans les dictionnaires.
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/exercices/","title":"Exercices sur les dictionnaires","text":""},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/exercices/#exercice-1-creation-dune-rainbow-table","title":"Exercice 1 : cr\u00e9ation d'une rainbow table","text":"Objectif :
Cr\u00e9er une fonction inverse_md5()
qui va chercher dans un dictionnaire (construit pr\u00e9alablement) le mot correspondant au hash donn\u00e9 en param\u00e8tre.
Exemple :
>>> inverse_md5('0571749e2ac330a7455809c6b0e7af90')\n>>> 'sunshine'\n
Aide :
string
: lst = open(\"monfichier.txt\").read().splitlines()\n
import hashlib\nresult = hashlib.md5('azerty'.encode())\nprint(result.hexdigest())\n
Exercice 2 du sujet Centres Etrangers J1 2021
Correction Q1.a.flotte[26]
renvoie {\"type : \"classique\", \"etat\" : 1, \"station\" : \"Coliseum\"}
flotte[80][\"etat\"]
renvoie la valeur 0
.
flotte[99][\"etat\"]
renverra une erreur car la cl\u00e9 99 n'existe pas.
Les valeurs possibles pour choix
sont electrique
ou classique
.
En fonction du choix (electrique
ou classique
), cette fonction va renvoyer le nom de la premi\u00e8re station o\u00f9 un v\u00e9lo est disponible (\u00e0 l'etat
1). Seule la premi\u00e8re station sera renvoy\u00e9e, \u00e0 cause du return
. Si aucun v\u00e9lo n'est disponible, la fonction ne renverra rien.
for id_velo in flotte:\n if flotte[id_velo][\"station\"] == \"Citadelle\" and flotte[id_velo][\"etat\"] == 1:\n print(id_velo)\n
Correction Q3.b. for id_velo in flotte:\n if flotte[id_velo][\"type\"] == \"electrique\" and flotte[id_velo][\"etat\"] != -1:\n print(id_velo, flotte[id_velo][\"station\"])\n
Correction Q4. def velo_finder(coordonnees):\n velo_dispo = []\n for id_velo in flotte:\n d = distance(coordonnees, stations[flotte[id_velo][\"station\"]])\n if d < 800 and flotte[id_velo][\"etat\"] == 1:\n velo_dispo.append((flotte[id_velo][\"station\"], d, id_velo))\n return velo_dispo\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/","title":"Arbres","text":""},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#1-terminologie","title":"1. Terminologie","text":""},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#11-vocabulaire","title":"1.1 Vocabulaire","text":"Un arbre est une structure hi\u00e9rarchique de donn\u00e9es, compos\u00e9e de n\u0153uds. Si on adopte le vocabulaire des graphes, un arbre est un graphe non orient\u00e9, connexe, sans cycle, et dans lequel un n\u0153ud joue le r\u00f4le de racine.
Chaque n\u0153ud a exactement un seul n\u0153ud p\u00e8re, \u00e0 l'exception du n\u0153ud racine qui est le seul n\u0153ud \u00e0 ne pas avoir de p\u00e8re. (oui, la racine d'une arbre est en haut)
Chaque n\u0153ud peut avoir un nombre quelconque de fils, dont il est le p\u00e8re.
Exemples : dans l'arbre ci-dessus,
Redessinez de mani\u00e8re plus sch\u00e9matique cet arbre. Pour quelle raison cet arbre a-t-il \u00e9t\u00e9 modifi\u00e9 par rapport \u00e0 sa version orginale (voir ici ), qui laissait appara\u00eetre les parents de chaque enfant ?
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#122-le-dom-dune-page-web","title":"1.2.2 Le DOM d'une page web","text":"DOM : Document Object Model
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#123-larborescence-dun-disque-dur","title":"1.2.3 L'arborescence d'un disque dur","text":"Les syst\u00e8mes Unix (MacOS ou GNU/Linux) organisent leur disque dur suivant l'arborescence ci-dessous :
Exercice 1
Quelque part \u00e0 l'int\u00e9rieur des dossiers contenus dans l'archive dossiers.zip se trouve un fichier tresor.txt
. Quel secret renferme-t-il ?
Attention, cette recherche est \u00e0 faire uniquement en ligne de commande :
ls
: pour lister les dossiers et fichiers d'un r\u00e9pertoirecd Dossier
: pour se rendre dans le rep\u00e9rtoire Dossier
cd ..
: pour remonter d'un niveau dans l'arborescenceunzip monarchive.zip
: pour d\u00e9compresser une archivetree
: pour afficher l'arborescence du r\u00e9pertoire courantsudo apt install monprog
: pour installer le programme monprog
si celui-ci est manquant.D\u00e9finitions
la taille d'un arbre est son nombre total de n\u0153uds. Ici, elle vaut 8.
l'arit\u00e9 d'un n\u0153ud est son nombre de fils. Ici, l'arit\u00e9 de B vaut 2, celle de F vaut 1, celle de Z vaut 0.
la profondeur d'un n\u0153ud est le nombre de n\u0153uds de son chemin le plus court vers la racine. Ici, la profondeur de G est 3 (G-K-C), la profondeur de B est 2 (B-C), la profondeur de Z est 4 (Z-F-B-C), la profondeur de C est 1.
la hauteur d'un arbre est la profondeur de son n\u0153ud le plus profond. Ici, la hauteur de l'arbre est 4. Nous prendrons comme convention que :
Cette convention est celle adopt\u00e9e dans le sujet 0 publi\u00e9 le 15/12/2020. Attention, dans certains ouvrages, l'arbre vide a pour hauteur -1, et donc l'arbre r\u00e9duit \u00e0 un seul n\u0153ud a pour hauteur 0, donc notre arbre aurait avec cette convention une hauteur 3.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#14-arbres-binaires","title":"1.4 Arbres binaires","text":"D\u00e9finition
Un arbre binaire est un arbre dont chaque n\u0153ud poss\u00e8de au plus deux fils.
L'arbre g\u00e9n\u00e9alogique de la famille royale britannique n'est pas un arbre binaire.
L'arbre ci-dessous est lui un arbre binaire.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#141-sous-arbres-dun-arbre-binaire","title":"1.4.1 Sous-arbres d'un arbre binaire","text":"Chaque n\u0153ud d'un arbre binaire ne pouvant pas avoir plus de 2 fils, il est possible de s\u00e9parer le \u00abdessous\u00bb de chaque n\u0153ud en deux sous-arbres (\u00e9ventuellement vides) : le sous-arbre gauche et le sous-arbre droit.
On rencontre tr\u00e8s souvent des arbres binaires dits complets parce qu'aucun des fils gauche ou droit n'est manquant.
Taille d'un arbre complet de hauteur \\(h\\) : \\(1 + 2 + 2^2 + 2^3 + \\dots + 2^{h-1} = 2^{h} - 1\\)
preuve : ceci est la somme \\(S\\) des \\(h\\) premiers termes d'une suite g\u00e9om\u00e9trique de raison 2 et de premier terme 1, d'o\u00f9 \\(S= \\frac{1-2^{h}}{1-2} = 2^{h} -1\\).
Un arbre complet de hauteur \\(h\\) (en prenant la convention que l'arbre vide a pour hauteur 0) a donc une taille \u00e9gale \u00e0 \\(2^{h}-1\\).
Remarque : On en d\u00e9duit une in\u00e9galit\u00e9 classique sur l'encadrement de la taille \\(t\\) d'un arbre binaire (non n\u00e9cessairement complet) de hauteur \\(h\\) :
\\[h \\leqslant t \\leqslant 2^{h}-1\\]"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#2-parcours-darbres","title":"2. Parcours d'arbres","text":"Les arbres \u00e9tant une structure hi\u00e9rarchique, leur utilisation implique la n\u00e9cessit\u00e9 d'un parcours des valeurs stock\u00e9es. Par exemple pour toutes les r\u00e9cup\u00e9rer dans un certain ordre, ou bien pour en chercher une en particulier.
Il existe plusieurs mani\u00e8res de parcourir un arbre.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#21-parcours-en-largeur-dabord-bfs","title":"2.1 Parcours en largeur d'abord (BFS)","text":"BFS : Breadth First Search
M\u00e9thode du parcours en largeur (BFS)
Le parcours en largeur d'abord est un parcours \u00e9tage par \u00e9tage (de haut en bas) et de gauche \u00e0 droite.
L'ordre des lettres parcourues est donc T-Y-O-P-H-N.
Les trois parcours que nous allons voir maintenant sont des parcours en profondeur d'abord, ou DFS (Depth First Search). Ce qui signifie qu'un des deux sous-arbres sera totalement parcouru avant que l'exploration du deuxi\u00e8me ne commence.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#22-parcours-prefixe","title":"2.2 Parcours pr\u00e9fixe","text":"Le parcours pr\u00e9fixe est un parcours en profondeur d'abord.
M\u00e9thode du parcours pr\u00e9fixe
(parfois aussi appel\u00e9 pr\u00e9ordre)
L'ordre des lettres parcourues est donc T-Y-P-O-H-N.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#23-parcours-infixe","title":"2.3 Parcours infixe","text":"Le parcours infixe est aussi un parcours en profondeur d'abord.
M\u00e9thode du parcours infixe
(parfois aussi appel\u00e9 en ordre)
L'ordre des lettres parcourues est donc P-Y-T-H-O-N.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#24-parcours-postfixe","title":"2.4 Parcours postfixe","text":"Le parcours postfixe est aussi un parcours en profondeur d'abord.
M\u00e9thode du parcours postfixe
(parfois aussi appel\u00e9 post-ordre ou encore suffixe)
L'ordre des lettres parcourues est donc P-Y-H-N-O-T.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#25-comment-ne-pas-se-melanger-entre-le-pre-in-post-fixe","title":"2.5 Comment ne pas se m\u00e9langer entre le pr\u00e9 / in / post fixe ?","text":"Ces trois mots-cl\u00e9s parlent de la place du p\u00e8re par rapport \u00e0 ses fils. Ensuite, il faut toujours se souvenir qu'on traite le fils gauche avant le fils droit.
Un parcours pr\u00e9fixe commencera toujours par la racine, alors qu'un parcours postfixe finira toujours par la racine. Dans un parcours infixe, la racine sera \u00abau milieu\u00bb (pas n\u00e9cessairement parfaitement).
Exercice 2
\u00c9nonc\u00e9Corr. largeurCorr. pr\u00e9fixeCorr. infixeCorr. postfixeDonner le rendu de chaque parcours :
largeur : 1 2 3 4 5 6 7 8 9
pr\u00e9fixe : 1 2 4 5 7 8 3 6 9
infixe : 4 2 7 5 8 1 3 9 6
postfixe : 4 7 8 5 2 9 6 3 1
Exercice 3
\u00c9nonc\u00e9Corr. largeurCorr. pr\u00e9fixeCorr. infixeCorr. postfixeDonner le rendu de chaque parcours :
largeur : 9 8 7 6 2 5 1 4 3
pr\u00e9fixe : 9 8 6 2 1 7 5 4 3
infixe : 6 8 1 2 9 7 4 5 3
postfixe : 6 1 2 8 4 3 5 7 9
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#3-implementations-dun-arbre-binaire","title":"3. Impl\u00e9mentations d'un arbre binaire","text":""},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#31-en-utilisant-la-programmation-orientee-objet","title":"3.1 En utilisant la Programmation Orient\u00e9e Objet","text":"Le but est d'obtenir l'interface ci-dessous.
Il est \u00e0 remarquer que ce que nous allons appeler \u00abArbre\u00bb est en fait un n\u0153ud et ses deux fils gauche et droit.
interface souhait\u00e9e
>>> a = Arbre(4) # pour cr\u00e9er l'arbre dont le n\u0153ud a pour valeur 4,\n # et dont les sous-arbres gauche et droit sont None\n>>> a.left = Arbre(3) # pour donner la valeur 3 au n\u0153ud du sous-arbre gauche de a\n>>> a.right = Arbre(1) # pour donner la valeur 1 au n\u0153ud du sous-arbre droit de a\n>>> a.right.data # pour acc\u00e9der \u00e0 la valeur du fils droit de a\n
Exercice 4
\u00c9nonc\u00e9CorrectionDessinez l'arbre cr\u00e9\u00e9 par les instructions suivantes :
>>> a = Arbre(4)\n>>> a.left = Arbre(3)\n>>> a.right = Arbre(1)\n>>> a.right.left = Arbre(2)\n>>> a.right.right = Arbre(7)\n>>> a.left.left = Arbre(6)\n>>> a.right.right.left = Arbre(9)\n
Impl\u00e9mentation
\u2bc8 Principe : nous allons cr\u00e9er une classe Arbre
, qui contiendra 3 attributs :
data
: la valeur du n\u0153ud (de type Int
)left
: le sous-arbre gauche (de type Arbre
)right
: le sous-arbre droit (de type Arbre
).Par d\u00e9faut, les attributs left
et right
seront \u00e0 None
, qui repr\u00e9sentera l'arbre vide (ce qui n'est pas tr\u00e8s rigoureux, car None
n'est pas de type Arbre
...).
\u2bc8 Encapsulation ou pas ??? :
Afin de respecter le paradigme de la Programmation Orient\u00e9e Objet, nous devrions jouer totalement le jeu de l'encapsulation en nous refusant d'acc\u00e9der directement aux attributs.
Pour cela il faut construire des m\u00e9thodes permettant d'acc\u00e9der \u00e0 ces attributs (avec des getters, ou accesseurs en fran\u00e7ais) ou de les modifier (avec des setters, ou mutateurs en fran\u00e7ais) .
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#311-implementation-avec-encapsulation","title":"3.1.1 Impl\u00e9mentation avec encapsulation","text":"Classe Arbre
avec encapsulation
class Arbre:\n def __init__(self, data):\n self.data = data\n self.left = None\n self.right = None\n\n def set_left(self, sousarbre): # mutateur\n self.left = sousarbre\n\n def set_right(self, sousarbre): # mutateur\n self.right = sousarbre \n\n def get_left(self): # accesseur\n return self.left\n\n def get_right(self): # accesseur\n return self.right\n\n def get_data(self): # accesseur\n return self.data\n
L'impl\u00e9mentation pr\u00e9c\u00e9dente permet d'utiliser les instructions de l'exercice pr\u00e9c\u00e9dent et de v\u00e9rifier que l'arbre a bien \u00e9t\u00e9 cr\u00e9\u00e9.
>>> a = Arbre(4)\n>>> a.set_left(Arbre(3))\n>>> a.set_right(Arbre(1))\n>>> a.get_right().set_left(Arbre(2))\n>>> a.get_right().set_right(Arbre(7))\n>>> a.get_left().set_left(Arbre(6))\n>>> a.get_right().get_right().set_left(Arbre(9))\n
>>> a\n <__main__.Arbre at 0x7f0100361f40>\n
>>> a.get_right().get_left().get_data()\n 2\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#311-implementation-sans-encapsulation","title":"3.1.1 Impl\u00e9mentation sans encapsulation","text":"Classe Arbre
sans encapsulation
class Arbre:\n def __init__(self, data):\n self.data = data\n self.left = None\n self.right = None\n
C'est d\u00e9j\u00e0 fini !
a = Arbre(4)\na.left = Arbre(3)\na.right = Arbre(1)\na.right.left = Arbre(2)\na.right.right = Arbre(7)\na.left.left = Arbre(6)\na.right.right.left = Arbre(9)\n
>>> a\n <__main__.Arbre at 0x7f0100361f40>\n
>>> a.right.left.data\n 2\n
On voit que l'impl\u00e9mentation avec acc\u00e8s direct aux attributs est beaucoup plus simple et rapide. N\u00e9anmoins, elle peut \u00eatre consid\u00e9r\u00e9e comme incorrecte dans certains langages qui obligent \u00e0 passer par des accesseurs ou mutateurs pour lire ou modifier les attributs.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#312-representation-graphique-en-console","title":"3.1.2 Repr\u00e9sentation graphique en console","text":"La m\u00e9thode affiche
suivante (qui n'est pas \u00e0 conna\u00eetre) permet d'avoir un semblant de repr\u00e9sentation graphique de l'arbre en console :
def affiche(self, indent = 0):\n val = self.data\n s = ' '*2*indent + '|' + '_' + str(val) + '\\n'\n if self.left is not None:\n s += self.left.affiche(indent + 1)\n if self.left is None and self.right is not None:\n s += ' '*(2*indent+2) + '|' + '_' + 'None' + '\\n' \n\n if self.right is not None:\n s += self.right.affiche(indent + 1)\n if self.right is None and self.left is not None:\n s += ' '*(2*indent+2) + '|' + '_' + 'None' + '\\n' \n return s\n
La repr\u00e9sentation de cet arbre : donnera alors :
>>> print(a.affiche())\n|_4\n |_3\n |_6\n |_None\n |_1\n |_2\n |_7\n |_9\n |_None\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#32-implementation-a-partir-de-tuples-imbriques","title":"3.2 Impl\u00e9mentation \u00e0 partir de tuples imbriqu\u00e9s","text":"Arbre
sous forme de tuples imbriqu\u00e9s
Un arbre peut se repr\u00e9senter par le tuple (valeur, sous-arbre gauche, sous-arbre droit)
. L'arbre ci-dessous : est repr\u00e9sent\u00e9 par le tuple :
>>> a = (2, (8, (6,(),()), (9,(),())), (1, (7, (),()), ()))\n
Le sous-arbre gauche est alors a[1]
et le sous-arbre droit est a[2]
.
>>> a[1]\n(8, (6, (), ()), (9, (), ()))\n>>> a[2]\n(1, (7, (), ()), ())\n
Exercice 5
\u00c9nonc\u00e9Correction\u00c9crire le tuple repr\u00e9sentant l'arbre ci-dessous.
a = (T,(Y,(P,(),()),()),(O,(H,(),()),(N,(),())))\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#33-implementation-a-partir-dune-simple-liste","title":"3.3 Impl\u00e9mentation \u00e0 partir d'une \u00absimple\u00bb liste","text":"De mani\u00e8re plus surprenante, il existe une m\u00e9thode pour impl\u00e9menter un arbre binaire (qui est une structure hi\u00e9rarchique) avec une liste (qui est une structure lin\u00e9aire). Ceci peut se faire par le biais d'une astuce sur les indices :
Les fils du n\u0153ud d'indice i sont plac\u00e9s aux indice 2i+1 et 2i+2.
Cette m\u00e9thode est connue sous le nom de \u00abm\u00e9thode d'Eytzinger\u00bb, et utilis\u00e9e notamment en g\u00e9n\u00e9alogie pour num\u00e9roter facilement les individus d'un arbre g\u00e9n\u00e9alogique.
Exemple :
Pour comprendre facilement la num\u00e9rotation, il suffit de s'imaginer l'arbre complet (en rajoutant les fils vides) et de faire une num\u00e9rotation en largeur, niveau par niveau :
Exercice 6
\u00c9nonc\u00e9CorrectionSi on note \u0394 le sous-arbre vide, dessiner l'arbre repr\u00e9sent\u00e9 par la liste :
a = [3, 4, \u0394, 7, 5]\n
Remarque : parfois (comme dans le sujet 0...) la racine de l'arbre est plac\u00e9e \u00e0 l'indice 1. Dans ce cas, les fils du n\u0153ud d'indice i sont plac\u00e9s aux indice 2i et 2i+1.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#4-utilisation-de-limplementation-parcours-taille","title":"4. Utilisation de l'impl\u00e9mentation : parcours, taille...","text":"Dans toute la suite, sauf mention contraire, on utilisera l'impl\u00e9mentation en Programmation Orient\u00e9e Objet, en version sans encapsulation (la plus simple). Nous allons cr\u00e9er des fonctions renvoyant les diff\u00e9rents parcours d'un arbre, ou encore sa taille, sa hauteur, son nombre de feuilles... Toutes ses fonctions exploiteront la structure r\u00e9cursive d'un arbre.
Rappel de l'impl\u00e9mentation :
class Arbre:\n def __init__(self, data):\n self.data = data\n self.left = None\n self.right = None\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#41-parcours-prefixe-infixe-postfixe","title":"4.1 Parcours pr\u00e9fixe, infixe, postfixe","text":""},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#411-parcours-prefixe","title":"4.1.1 Parcours pr\u00e9fixe","text":"Parcours pr\u00e9fixe
def prefixe(arbre):\n if arbre is None :\n return None\n print(arbre.data, end = '-')\n prefixe(arbre.left)\n prefixe(arbre.right)\n
Exemple avec l'arbre
a = Arbre(9)\na.left = Arbre(8)\na.right = Arbre(7)\na.left.left = Arbre(6)\na.left.right = Arbre(2)\na.right.right = Arbre(5)\na.left.right.left = Arbre(1)\na.right.right.left = Arbre(4)\na.right.right.right = Arbre(3)\n
>>> prefixe(a)\n9-8-6-2-1-7-5-4-3-\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#412-parcours-infixe","title":"4.1.2 Parcours infixe","text":"Parcours infixe
def infixe(arbre):\n if arbre is None :\n return None\n infixe(arbre.left)\n print(arbre.data, end = '-')\n infixe(arbre.right)\n
>>> infixe(a)\n6-8-1-2-9-7-4-5-3-\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#413-parcours-postfixe","title":"4.1.3 Parcours postfixe","text":"Parcours postfixe
def postfixe(arbre):\n if arbre is None :\n return None\n postfixe(arbre.left)\n postfixe(arbre.right)\n print(arbre.data, end = '-')\n
>>> postfixe(a)\n6-1-2-8-4-3-5-7-9-\n
Pause vid\u00e9o
def infixe(arbre):\n parcours = []\n pile = []\n\n current = arbre\n\n while pile != [] or current is not None:\n if current is not None:\n pile.append(current)\n current = current.left\n else:\n current = pile.pop()\n parcours.append(current.data)\n current = current.right\n\n return parcours\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#42-calcul-de-la-taille-dun-arbre","title":"4.2 Calcul de la taille d'un arbre","text":"Rappel : la taille d'un arbre est le nombre de ses n\u0153uds.
Taille d'un arbre
def taille(arbre):\n if arbre is None:\n return 0\n else:\n return 1 + taille(arbre.left) + taille(arbre.right)\n
Exemple avec l'arbre
a = Arbre(9)\na.left = Arbre(8)\na.right = Arbre(7)\na.left.left = Arbre(6)\na.left.right = Arbre(2)\na.right.right = Arbre(5)\na.left.right.left = Arbre(1)\na.right.right.left = Arbre(4)\na.right.right.right = Arbre(3)\n
>>> taille(a)\n9\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#43-calcul-de-la-hauteur-dun-arbre","title":"4.3 Calcul de la hauteur d'un arbre","text":"Rappel : on prendra comme convention que l'arbre vide a pour hauteur 0.
Hauteur d'un arbre
def hauteur(arbre):\n if arbre is None:\n return 0\n else:\n return 1 + max(hauteur(arbre.left), hauteur(arbre.right))\n
>>> hauteur(a)\n4\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#44-calcul-du-nombre-de-feuilles-dun-arbre","title":"4.4 Calcul du nombre de feuilles d'un arbre","text":"Rappel : une feuille est un n\u0153ud d'arit\u00e9 0, autrement dit sans fils gauche ni fils droit.
Nombre de feuilles d'un arbre
def nb_feuilles(arbre):\n if arbre is None:\n return 0\n if (arbre.left is None) and (arbre.right is None):\n return 1\n return nb_feuilles(arbre.left) + nb_feuilles(arbre.right)\n
>>> nb_feuilles(a)\n4\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#45-recherche-dune-valeur-dans-un-arbre","title":"4.5 Recherche d'une valeur dans un arbre","text":"On renverra True
ou False
en fonction de la pr\u00e9sence ou non de la valeur dans l'arbre.
Recherche d'une valeur dans un arbre
def recherche(arbre, valeur):\n if arbre is None:\n return False\n if arbre.data == valeur:\n return True\n return recherche(arbre.left, valeur) or recherche(arbre.right, valeur)\n
>>> recherche(a, 2)\nTrue\n>>> recherche(a, 45)\nFalse\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#46-parcours-en-largeur","title":"4.6 Parcours en largeur","text":"Le parcours en largeur (BFS) est le plus simple \u00e0 faire visuellement : mais il est plus difficile \u00e0 coder que les parcours pr\u00e9fixe, infixe, postfixe. Il est n\u00e9cessaire d'utiliser une file :
On importera l'objet Queue()
du module queue
de Python, qui permet de :
file = Queue()
file.get()
a
par file.put(a)
file.empty()
# arbre-test\n# ne pas oublier de remonter plus haut dans le document pour relancer la classe Arbre\na = Arbre(8)\na.left = Arbre(4)\na.right = Arbre(5)\na.left.left = Arbre(2)\na.left.right = Arbre(1)\na.right.right = Arbre(3)\n
Parcours en largeur (BFS)
from queue import Queue\n\ndef BFS(arbre): \n file = Queue()\n file.put(arbre)\n sol = []\n while not file.empty():\n a = file.get()\n if a is not None :\n sol.append(a.data)\n file.put(a.left)\n file.put(a.right)\n return sol\n
>>> BFS(a)\n[8, 4, 5, 2, 1, 3]\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#5-arbres-binaires-de-recherche-abr","title":"5. Arbres binaires de recherche (ABR)","text":"D\u00e9finition d'un ABR
Un arbre binaire de recherche est un arbre binaire dont les valeurs des n\u0153uds (valeurs qu'on appelle \u00e9tiquettes, ou cl\u00e9s) v\u00e9rifient la propri\u00e9t\u00e9 suivante :
\u00c0 noter que l'arbre 3 (qui est bien un ABR) est appel\u00e9 arbre filiforme.
L'arbre 5 n'est pas un ABR \u00e0 cause de la feuille 9, qui fait partie du sous-arbre gauche de 3 sans lui \u00eatre inf\u00e9rieure.
Remarque : on pourrait aussi d\u00e9finir un ABR comme un arbre dont le parcours infixe est une suite croissante.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#51-determiner-si-un-arbre-est-un-abr","title":"5.1 D\u00e9terminer si un arbre est un ABR","text":"Employer une m\u00e9thode r\u00e9cursive imposerait de garder en m\u00e9moire dans l'exploration des sous-arbres la valeur maximale ou minimale. Nous allons plut\u00f4t utiliser la remarque pr\u00e9c\u00e9dente, et nous servir du parcours infixe.
M\u00e9thode : r\u00e9cup\u00e9rer le parcours infixe dans une liste, et faire un test sur cette liste.
\u00catre ou ne pas \u00eatre un ABR
def infixe(arbre, s = None):\n if s is None:\n s = []\n if arbre is None :\n return None\n infixe(arbre.left, s)\n s.append(arbre.data)\n infixe(arbre.right, s)\n return s\n\n\ndef est_ABR(arbre):\n'''renvoie un bool\u00e9en indiquant si arbre est un ABR'''\n parcours = infixe(arbre)\n return parcours == sorted(parcours) # on regarde si le parcours est \u00e9gal au parcours tri\u00e9 \n
# arbres-tests \n\n#arbre n\u00b04\na = Arbre(5)\na.left = Arbre(2)\na.right = Arbre(7)\na.left.left = Arbre(0)\na.left.right = Arbre(3)\na.right.left = Arbre(6)\na.right.right = Arbre(8)\n\n#arbre n\u00b05\nb = Arbre(3)\nb.left = Arbre(2)\nb.right = Arbre(5)\nb.left.left = Arbre(1)\nb.left.right = Arbre(9)\nb.right.left = Arbre(4)\nb.right.right = Arbre(6)\n
>>> est_ABR(a)\nTrue\n>>> est_ABR(b)\nFalse\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#52-rechercher-une-cle-dans-un-abr","title":"5.2 Rechercher une cl\u00e9 dans un ABR","text":"Un arbre binaire de taille \\(n\\) contient \\(n\\) cl\u00e9s (pas forc\u00e9ment diff\u00e9rentes). Pour savoir si une valeur particuli\u00e8re fait partie des cl\u00e9s, on peut parcourir tous les n\u0153uds de l'arbre, jusqu'\u00e0 trouver (ou pas) cette valeur dans l'arbre. Dans le pire des cas, il faut donc faire \\(n\\) comparaisons.
Mais si l'arbre est un ABR, le fait que les valeurs soient \u00abrang\u00e9es\u00bb va consid\u00e9rablement am\u00e9liorer la vitesse de recherche de cette cl\u00e9, puisque la moiti\u00e9 de l'arbre restant sera \u00e9cart\u00e9e apr\u00e8s chaque comparaison.
Recherche d'une cl\u00e9 dans un ABR
Exemple
L'arbre a
contient la valeur 8, mais l'arbre b
ne la contient pas :
>>> contient_valeur(a,8)\nTrue\n>>> contient_valeur(b,8)\nFalse\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#53-cout-de-la-recherche-dans-un-abr-equilibre","title":"5.3 Co\u00fbt de la recherche dans un ABR \u00e9quilibr\u00e9","text":"Imaginons un arbre \u00e9quilibr\u00e9 de taille \\(n\\). Combien d'\u00e9tapes faudra-t-il, dans le pire des cas, pour trouver (ou pas) une cl\u00e9 particuli\u00e8re dans cet arbre ?
Apr\u00e8s chaque n\u0153ud, le nombre de n\u0153uds restant \u00e0 explorer est divis\u00e9 par 2. On retrouve l\u00e0 le principe de recherche dichotomique, vu en classe de Premi\u00e8re (voir ici).
S'il faut parcourir tous les \u00e9tages de l'arbre avant de trouver (ou pas) la cl\u00e9 recherch\u00e9e, le nombre de n\u0153uds parcourus est donc \u00e9gal \u00e0 la hauteur \\(h\\) de l'arbre.
Pour un arbre complet, cette hauteur v\u00e9rifie la relation \\(2^h -1= n\\). et donc \\(2^h = n+1\\).
\\(h\\) est donc le \u00abnombre de puissance de 2\u00bb que l'on peut mettre dans \\(n+1\\). Cette notion s'appelle le logarithme de base 2 et se note \\(\\log_2\\).
Par exemple, \\(\\log_2(64)=6\\) car \\(2^6=64\\).
Le nombre maximal de n\u0153uds \u00e0 parcourir pour rechercher une cl\u00e9 dans un ABR \u00e9quilibr\u00e9 de taille \\(n\\) est donc de l'ordre de \\(\\log_2(n)\\), ce qui est tr\u00e8s performant !
Pour arbre contenant 1000 valeurs, 10 \u00e9tapes suffisent.
Cette complexit\u00e9 logarithmique est un atout essentiel de la structure d'arbre binaire de recherche.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#54-insertion-dans-un-abr","title":"5.4 Insertion dans un ABR","text":"L'insertion d'une cl\u00e9 va se faire au niveau d'une feuille, donc au bas de l'arbre. Dans la version r\u00e9cursive de l'algorithme d'insertion, que nous allons impl\u00e9menter, il n'est pourtant pas n\u00e9cessaire de descendre manuellement dans l'arbre jusqu'au bon endroit : il suffit de distinguer dans lequel des deux sous-arbres gauche et droit doit se trouver la future cl\u00e9, et d'appeler r\u00e9cursivement la fonction d'insertion dans le sous-arbre en question.
Algorithme :
Insertion dans un ABR
def insertion(arbre, valeur):\n if arbre is None :\n return Arbre(valeur)\n else :\n v = arbre.data\n if valeur <= v :\n arbre.left = insertion(arbre.left, valeur)\n else:\n arbre.right = insertion(arbre.right, valeur)\n return arbre\n
Exemple : Nous allons ins\u00e9rer la valeur 4 dans l'arbre a
et v\u00e9rifier par un parcours infixe (avant et apr\u00e8s l'insertion) que la valeur 4 a bien \u00e9t\u00e9 ins\u00e9r\u00e9e au bon endroit.
a = Arbre(5)\na.left = Arbre(2)\na.right = Arbre(7)\na.left.left = Arbre(0)\na.left.right = Arbre(3)\na.right.left = Arbre(6)\na.right.right = Arbre(8)\n
>>> infixe(a)\n0-2-3-5-6-7-8-\n>>> insertion(a,4)\n<__main__.Arbre at 0x7f46f0507e80>\n>>> infixe(a)\n0-2-3-4-5-6-7-8-\n
La valeur 4 a donc bien \u00e9t\u00e9 ins\u00e9r\u00e9e au bon endroit.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#bibliographie","title":"Bibliographie","text":"Exercice 1
Exercice 2 du sujet Nouvelle-Cal\u00e9donie J2 2022
Correction 1.C'est un arbre binaire car chaque n\u0153ud poss\u00e8de au maximum deux fils.
Correction 2.aV
est un dictionnaire.
V['J']\n
Correction 2.c def somme(W):\n s = 0\n for cle in W:\n s += W[cle]\n return s\n
Correction 2.d def VMax(W):\n val_max = 0\n for cle in W:\n if W[cle] > val_max:\n val_max = W[cle]\n cle_max = cle\n return cle_max\n
Correction 3. Cet algorithme calcule le nombre total de n\u0153uds de l'arbre, donc la taille de l'arbre. C'est un algorithme r\u00e9cursif qui va renvoyer, si on n'est pas positionn\u00e9 sur un arbre vide, la valeur 1 (correspond au n\u0153ud racine sur lequel on est positionn\u00e9), plus la taille des deux sous-arbres gauche et droits.
Correction 4.aLe parcours est A-B-C-E-D-F-G-I-H-J
C'est un parcours pr\u00e9fixe.
Exercice 2
2020, sujet 0
Question 1
D\u00e9terminer la taille et la hauteur de l\u2019arbre binaire suivant :
Question 2
On d\u00e9cide de num\u00e9roter en binaire les n\u0153uds d\u2019un arbre binaire de la fa\u00e7on suivante :
Par exemple, dans l\u2019arbre ci-dessous, on a utilis\u00e9 ce proc\u00e9d\u00e9 pour num\u00e9roter les n\u0153uds A, B, C, E et F .
Question 3 Un arbre binaire est dit complet si tous les niveaux de l\u2019arbre sont remplis.
On d\u00e9cide de repr\u00e9senter un arbre binaire complet par un tableau de taille n + 1, o\u00f9 n est la taille de l\u2019arbre, de la fa\u00e7on suivante :
R\u00e9pondre aux questions suivantes :
Question 4
On se place dans le cas particulier d\u2019un arbre binaire de recherche complet o\u00f9 les n\u0153uds contiennent des entiers et pour lequel la valeur de chaque noeud est sup\u00e9rieure \u00e0 celles des noeuds de son fils gauche, et inf\u00e9rieure \u00e0 celles des noeuds de son fils droit.
\u00c9crire une fonction recherche
ayant pour param\u00e8tres un arbre arbre
et un \u00e9l\u00e9ment element
. Cette fonction renvoie True
si element
est dans l\u2019arbre et False
sinon. L\u2019arbre sera repr\u00e9sent\u00e9 par un tableau comme dans la question pr\u00e9c\u00e9dente.
Q1 La taille est 9, la hauteur est 4. Q2 1. G est associ\u00e9 \u00e0 1010. Q2 2. 13 s'\u00e9crit 1101 en binaire, c'est donc le n\u0153ud I. Q2 3. Les n\u0153uds les plus en bas sont not\u00e9s sur \\(h\\) bits. Q2 4. L'arbre de hauteur \\(h\\) de taille minimale est l'arbre filiforme, qui est de taille \\(h\\). L'arbre de hauteur \\(h\\) de taille maximale est l'arbre complet, qui est de taille \\(2^h-1\\). Si \\(n\\) est la taille d'un arbre quelconque de taille \\(h\\), on a donc bien
\\(h \\leqslant n \\leqslant 2^h-1\\).
Q3 1. Tableau : [15, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O]
. Q3 2. Le p\u00e8re du n\u0153ud d'indice i
a pour indice i//2
.
Q4 :
def recherche(arbre, element):\n i = 1\n while i < len(arbre):\n if arbre[i] == element:\n return True\n if element < arbre[i]:\n i = 2*i # on se place sur le fils gauche\n else:\n i = 2*i + 1 # on se place sur le fils droit\n return False\n
Exercice 3
2021, M\u00e9tropole sujet 1
Dans cet exercice, les arbres binaires de recherche ne peuvent pas comporter plusieurs fois la m\u00eame cl\u00e9. De plus, un arbre binaire de recherche limit\u00e9 \u00e0 un n\u0153ud a une hauteur de 1. On consid\u00e8re l\u2019arbre binaire de recherche repr\u00e9sent\u00e9 ci-dessous (figure 1), o\u00f9 val
repr\u00e9sente un entier :
1.a Donner le nombre de feuilles de cet arbre et pr\u00e9ciser leur valeur (\u00e9tiquette).
1.b Donner le sous arbre-gauche du n\u0153ud 23.
1.c Donner la hauteur et la taille de l\u2019arbre.
1.d Donner les valeurs enti\u00e8res possibles de val
pour cet arbre binaire de recherche.
On suppose, pour la suite de cet exercice, que val
est \u00e9gal \u00e0 16.
2. On rappelle qu\u2019un parcours infixe depuis un n\u0153ud consiste, dans l\u2019ordre, \u00e0 faire un parcours infixe sur le sous arbre-gauche, afficher le n\u0153ud puis faire un parcours infixe sur le sous-arbre droit. Dans le cas d\u2019un parcours suffixe, on fait un parcours suffixe sur le sous-arbre gauche puis un parcours suffixe sur le sous-arbre droit, avant d\u2019afficher le n\u0153ud.
a. Donner les valeurs d\u2019affichage des n\u0153uds dans le cas du parcours infixe de l\u2019arbre. b. Donner les valeurs d\u2019affichage des n\u0153uds dans le cas du parcours suffixe de l\u2019arbre.
3. On consid\u00e8re la classe Noeud
d\u00e9finie de la fa\u00e7on suivante en Python :
a. Repr\u00e9senter l\u2019arbre construit suite \u00e0 l\u2019ex\u00e9cution de l\u2019instruction suivante :
racine = Noeud(18)\nracine.insere_tout([12, 13, 15, 16, 19, 21, 32, 23])\n
b. \u00c9crire les deux instructions permettant de construire l\u2019arbre de la figure 1. On rappelle que le nombre val
est \u00e9gal \u00e0 16. c. On consid\u00e8re l\u2019arbre tel qu\u2019il est pr\u00e9sent\u00e9 sur la figure 1. D\u00e9terminer l\u2019ordre d\u2019ex\u00e9cution des blocs (rep\u00e9r\u00e9s de 1 \u00e0 3) suite \u00e0 l\u2019application de la m\u00e9thode insere(19)
au n\u0153ud racine de cet arbre.
4. \u00c9crire une m\u00e9thode recherche(self, v)
qui prend en argument un entier v
et renvoie la valeur True
si cet entier est une \u00e9tiquette de l\u2019arbre, False
sinon.
1.a. Il y a 4 feuilles, d'\u00e9tiquette 12, val
, 21 et 32. 1.b. Le sous-arbre gauche du n\u0153ud 23 est 19-21. 1.c. La hauteur de l'arbre est 4. Sa taille est 9. 1.d. Les valeurs possibles de val
sont 16 et 17.
2.a. Parcours infixe : 12-13-15-16-18-19-21-23-32 2.b. Parcours suffixe : 12-13-16-15-21-19-32-23-18
3.a.
3.b.
racine = Noeud(18)\nracine.insere([15, 13, 12, 16, 23, 32, 19, 21])\n
(d'autres solutions sont possibles) 3.c. Bloc 3 - Bloc 2 - Bloc 1
4.
class Noeud():\n def __init__(self, v):\n self.ag = None\n self.ad = None\n self.v = v\n\n def insere(self, v):\n n = self\n est_insere = False\n while not est_insere:\n if v == n.v:\n est_insere = True\n elif v < n.v:\n if n.ag != None:\n n = n.ag\n else:\n n.ag = Noeud(v)\n est_insere = True\n else:\n if n.ad != None:\n n = n.ad\n else:\n n.ad = Noeud(v)\n est_insere = True\n\n def insere_tout(self, vals):\n for v in vals:\n self.insere(v)\n\n def recherche(self, v):\n arbre = self\n while not arbre is None:\n if arbre.v == v:\n return True\n if v < arbre.v:\n arbre = arbre.ag\n else:\n arbre = arbre.ad\n return False\n\n\nracine = Noeud(18)\nracine.insere_tout([12, 13, 15, 14, 19, 21, 32, 23])\nprint(racine.recherche(149))\nprint(racine.recherche(12))\n
Exercice 4
2021, M\u00e9tropole Candidats Libres 2
On rappelle qu\u2019un arbre binaire est compos\u00e9 de n\u0153uds, chacun des n\u0153uds poss\u00e9dant \u00e9ventuellement un sous-arbre gauche et \u00e9ventuellement un sous-arbre droit. Un n\u0153ud sans sous-arbre est appel\u00e9 feuille. La taille d\u2019un arbre est le nombre de n\u0153uds qu\u2019il contient ; sa hauteur est le nombre de n\u0153uds du plus long chemin qui joint le n\u0153ud racine \u00e0 l\u2019une des feuilles. Ainsi la hauteur d\u2019un arbre r\u00e9duit \u00e0 un n\u0153ud, c\u2019est-\u00e0-dire la racine, est 1.
Dans un arbre binaire de recherche, chaque n\u0153ud contient une cl\u00e9, ici un nombre entier, qui est :
Un arbre binaire de recherche est dit \u00ab bien construit \u00bb s\u2019il n\u2019existe pas d\u2019arbre de hauteur inf\u00e9rieure qui pourrait contenir tous ses n\u0153uds.
On consid\u00e8re l\u2019arbre binaire de recherche ci-dessous.
1.a. Quelle est la taille de l\u2019arbre ci-dessus ?
1.b. Quelle est la hauteur de l\u2019arbre ci-dessus ?
corrig\u00e91.a. La taille de l'arbre est 7. 1.b. La hauteur de l'arbre est 4.
2. Cet arbre binaire de recherche n\u2019est pas \u00ab bien construit \u00bb. Proposer un arbre binaire de recherche contenant les m\u00eames cl\u00e9s et dont la hauteur est plus petite que celle de l\u2019arbre initial.
corrig\u00e92.
3. Les classes Noeud et Arbre ci-dessous permettent de mettre en \u0153uvre en Python la structure d\u2019arbre binaire de recherche. La m\u00e9thode insere
permet d\u2019ins\u00e9rer r\u00e9cursivement une nouvelle cl\u00e9.
class Noeud :\n\n def __init__(self, cle):\n self.cle = cle\n self.gauche = None\n self.droit = None\n\n def insere(self, cle):\n if cle < self.cle :\n if self.gauche == None :\n self.gauche = Noeud(cle)\n else :\n self.gauche.insere(cle)\n elif cle > self.cle :\n if self.droit == None :\n self.droit = Noeud(cle)\n else :\n self.droit.insere(cle)\n\nclass Arbre :\n\n def __init__(self, cle):\n self.racine = Noeud(cle)\n\n def insere(self, cle):\n self.racine.insere(cle)\n
Donner la repr\u00e9sentation de l\u2019arbre cod\u00e9 par les instructions ci-dessous.
a = Arbre(10)\na.insere(20)\na.insere(15)\na.insere(12)\na.insere(8)\na.insere(4)\na.insere(5)\n
corrig\u00e9 3.
4. Pour calculer la hauteur d\u2019un arbre non vide, on a \u00e9crit la m\u00e9thode ci-dessous dans la classe Noeud.
def hauteur(self):\n if self.gauche == None and self.droit == None:\n return 1\n if self.gauche == None:\n return 1 + self.droit.hauteur()\n elif self.droit == None:\n return 1 + self.gauche.hauteur()\n else:\n hg = self.gauche.hauteur()\n hd = self.droit.hauteur()\n if hg > hd:\n return hg + 1\n else:\n return hd + 1\n
\u00c9crire la m\u00e9thode hauteur
de la classe Arbre
qui renvoie la hauteur de l\u2019arbre. corrig\u00e9 4.
def hauteur(self):\n return self.racine.hauteur()\n
5. \u00c9crire les m\u00e9thodes taille
des classes Noeud
et Arbre
permettant de calculer la taille d\u2019un arbre.
5. M\u00e9thode taille
de la classe Noeud
:
def taille(self):\n if self.gauche is None and self.droit is None:\n return 1\n elif self.gauche is None:\n return 1 + self.droit.taille()\n elif self.droit is None:\n return 1 + self.gauche.taille()\n else:\n return 1 + self.gauche.taille() + self.droit.taille()\n
M\u00e9thode taille
de la classe Arbre
: def taille(self):\n return self.racine.taille()\n
6. On souhaite \u00e9crire une m\u00e9thode bien_construit
de la classe Arbre
qui renvoie la valeur True
si l\u2019arbre est \u00ab bien construit \u00bb et False
sinon.
On rappelle que la taille maximale d\u2019un arbre binaire de recherche de hauteur \\(\u210e\\) est \\(2^h - 1\\).
6.a Quelle est la taille minimale, not\u00e9e min
d\u2019un arbre binaire de recherche \u00ab bien construit \u00bb de hauteur \\(\u210e\\) ?
6.a. La configuration minimale d'un arbre bien construit de hauteur \\(h\\) peut \u00eatre :
La taille minimale min
est donc \u00e9gale \u00e0 \\(2^{h-1}\\).
6.b \u00c9crire la m\u00e9thode bien_construit
demand\u00e9e.
6.b. Intuitivement, un arbre est mal construit si sa hauteur est trop grande par rapport \u00e0 sa taille (trop \u00e9tir\u00e9).
Donc un arbre est mal construit si sa taille est trop petite par rapport \u00e0 sa hauteur.
Donc un arbre de taille \\(t\\) et de hauteur \\(h\\) est mal construit si \\(t < 2^{h-1}\\), puisqu'on a d\u00e9montr\u00e9 que \\(2^{h-1}\\) \u00e9tait la taille minimale.
Pour tester si un arbre est bien construit, on va donc juste v\u00e9rifier que \\(t \\geqslant 2^{h-1}\\) :
def bien_construit(self):\n h = self.taille()\n return self.taille() >= 2**(h-1)\n
Exercice 5
2021, Polyn\u00e9sie
Cet exercice traite principalement du th\u00e8me \u00ab algorithmique, langages et programmation \u00bb et en particulier les arbres binaires de recherche. La premi\u00e8re partie aborde les arbres en mode d\u00e9branch\u00e9 via l'application d'un algorithme sur un exemple. La suivante porte sur la programmation orient\u00e9e objet. La derni\u00e8re partie fait le lien avec les algorithmes de tri.
Partie A : \u00c9tude d'un exemple
Consid\u00e9rons l'arbre binaire de recherche ci-dessous :
Q1. Indiquer quelle valeur a le n\u0153ud racine et quels sont les fils de ce n\u0153ud.
corrig\u00e9Le n\u0153ud racine est 5 et ses fils sont 2 et 7.
Q2. Indiquer quels sont les n\u0153uds de la branche qui se termine par la feuille qui a pour valeur 3.
corrig\u00e9La branche qui se termine par la feuille 3 a pour n\u0153uds 5, 2 et 3.
Q3. Dessiner l\u2019arbre obtenu apr\u00e8s l\u2019ajout de la valeur 6.
corrig\u00e9Partie B : Impl\u00e9mentation en Python
Voici un extrait d\u2019une impl\u00e9mentation en Python d'une classe mod\u00e9lisant un arbre binaire de recherche.
class ABR:\n\"\"\"Impl\u00e9mentation d\u2019un arbre binaire de recherche (ABR)\"\"\"\n def __init__(self, valeur=None):\n self.valeur = valeur\n self.fg = None\n self.fd = None\n\n def estVide(self):\n return self.valeur == None\n\n def insererElement(self, e):\n if self.estVide():\n self.valeur = e\n else:\n if e < self.valeur:\n if self.fg:\n self.fg.insererElement(e)\n else:\n self.fg = ABR(e)\n if e > self.valeur:\n if self.fd:\n self.fd.insererElement(e)\n else:\n self.fd = ABR(e)\n
Q1. Expliquer le r\u00f4le de la fonction __init__
.
La fonction __init__
est appel\u00e9e \u00abm\u00e9thode constructeur\u00bb, c'est elle qui cr\u00e9e l'objet et le dote de tous les attributs n\u00e9cessaires.
Q2. Dans cette impl\u00e9mentation, expliquer ce qui se passe si on ajoute un \u00e9l\u00e9ment d\u00e9j\u00e0 pr\u00e9sent dans l\u2019arbre.
corrig\u00e9Si on ajoute un \u00e9l\u00e9ment d\u00e9j\u00e0 pr\u00e9sent dans l'arbre, la valeur e
sera \u00e9gale \u00e0 self.valeur
(\u00e9ventuellement apr\u00e8s quelques appels r\u00e9cursifs). Or ce cas d'\u00e9galit\u00e9 n'est pas pr\u00e9vu par les tests : il ne se passera donc RIEN. Ceci est le comportement souhait\u00e9 puisqu'on ne veut pas avoir deux valeurs identiques dans notre ABR, ainsi qu'il est rappel\u00e9 au d\u00e9but de l'\u00e9nonc\u00e9.
Q3. Recopier et compl\u00e9ter les pointill\u00e9s ci-dessous permettant de cr\u00e9er l\u2019arbre de la partie A.
arbre = ABR(.......... )\narbre.insererElement(2)\narbre.insererElement(.......... )\narbre.insererElement(7)\narbre.insererElement(.......... )\n
corrig\u00e9 arbre = ABR(5)\narbre.insererElement(2)\narbre.insererElement(3)\narbre.insererElement(7)\narbre.insererElement(8)\n
Partie C : Tri par arbre binaire de recherche
On souhaite trier un ensemble de valeurs enti\u00e8res distinctes gr\u00e2ce \u00e0 un arbre binaire de recherche. Pour cela, on ajoute un \u00e0 un les \u00e9l\u00e9ments de l\u2019ensemble dans un arbre initialement vide. Il ne reste plus qu\u2019\u00e0 parcourir l\u2019arbre afin de lire et de stocker dans un tableau r\u00e9sultat les valeurs dans l\u2019ordre croissant.
Q1. Donner le nom du parcours qui permet de visiter les valeurs d\u2019un arbre binaire de recherche dans l\u2019ordre croissant.
corrig\u00e9Le parcours qui permet de visiter les valeurs d'un ABR dans l'ordre croissant est le parcours infixe.
Q2. Comparer la complexit\u00e9 de cette m\u00e9thode de tri avec celle du tri par insertion ou du tri par s\u00e9lection.
corrig\u00e9question difficile Pour cr\u00e9er l'ABR, il faut d'abord ins\u00e9rer chacune des valeurs. La fonction insertion
reposant sur une division par 2 \u00e0 chaque \u00e9tape de la taille de l'espace de recherche, on peut dire qu'elle a une complexit\u00e9 logarithmique. Mais cette op\u00e9ration est \u00e0 effectuer autant de fois qu'il y a d'\u00e9l\u00e9ments \u00e0 ins\u00e9rer : il faut donc multiplier la complexit\u00e9 logarithmique par n
, ce qui fera donc une complexit\u00e9 en \\(n \\log(n)\\). L'algorithme de parcours infixe est lui aussi lin\u00e9raire, ce qui ne change pas la complexit\u00e9 totale. Cette complexit\u00e9 est meilleure que le tris par insertion ou s\u00e9lection, qui sont de complexit\u00e9 quadratique.
Exercice 6
2021, Centres \u00c9trangers, sujet 1
Un arbre binaire est soit vide, soit un n\u0153ud qui a une valeur et au plus deux fils (le sous-arbre gauche et le sous-arbre droit).
Un arbre binaire de recherche est ordonn\u00e9 de la mani\u00e8re suivante :
Pour chaque n\u0153ud X,
Ainsi, par exemple, toutes les valeurs des n\u0153uds G1, G2 et G3 sont strictement inf\u00e9rieures \u00e0 la valeur du n\u0153ud X et toutes les valeurs des n\u0153uds D1, D2 et D3 sont sup\u00e9rieures ou \u00e9gales \u00e0 la valeur du n\u0153ud X.
Voici un exemple d'arbre binaire de recherche dans lequel on a stock\u00e9 dans cet ordre les valeurs : [26, 3, 42, 15, 29, 19, 13, 1, 32, 37, 30]
L'\u00e9tiquette d'un n\u0153ud indique la valeur du n\u0153ud suivie du nom du n\u0153ud. Les n\u0153uds ont \u00e9t\u00e9 nomm\u00e9s dans l'ordre de leur insertion dans l'arbre ci-dessous.
'29, noeud04'
signifie que le n\u0153ud nomm\u00e9 noeud04
poss\u00e8de la valeur 29.
Q1. On ins\u00e8re la valeur 25 dans l'arbre, dans un nouveau n\u0153ud nomm\u00e9 n\u0153ud11.
Recopier l'arbre binaire de recherche \u00e9tudi\u00e9 et placer la valeur 25 sur cet arbre en coloriant en rouge le chemin parcouru.
Pr\u00e9ciser sous quel n\u0153ud la valeur 25 sera ins\u00e9r\u00e9e et si elle est ins\u00e9r\u00e9e en fils gauche ou en fils droit, et expliquer toutes les \u00e9tapes de la d\u00e9cision.
Correction25 \u00e9tant plus petit que 26, on part dans son sous-arbre gauche. 25 \u00e9tant plus grand que 3, on part dans son sous-arbre droit. 25 \u00e9tant plus grand que 15, on part dans son sous-arbre droit. 25 \u00e9tant plus grand que 19, on ins\u00e8re 25 en tant que fils droit de 19.
Q2. Pr\u00e9ciser toutes les valeurs enti\u00e8res que l\u2019on peut stocker dans le n\u0153ud fils gauche du n\u0153ud04 (vide pour l'instant), en respectant les r\u00e8gles sur les arbres binaires de recherche.
CorrectionLes valeurs acceptables doivent \u00eatre strictement inf\u00e9rieures \u00e0 29, et sup\u00e9rieures ou \u00e9gales \u00e0 26. Ces valeurs sont donc : 26, 27 et 28.
Q3. Voici un algorithme r\u00e9cursif permettant de parcourir et d'afficher les valeurs de l'arbre :
Parcours(A) # A est un arbre binaire de recherche\n Afficher(A.valeur)\n Parcours(A.fils_gauche)\n Parcours(A.fils_droit)\n
Q3.a. \u00c9crire la liste de toutes les valeurs dans l'ordre o\u00f9 elles seront affich\u00e9es.
Q3.b. Choisir le type de parcours d'arbres binaires de recherche r\u00e9alis\u00e9 parmi les propositions suivantes : Pr\u00e9fixe, Suffixe ou Infixe.
Q4. En vous inspirant de l\u2019algorithme pr\u00e9c\u00e9dent, \u00e9crire un algorithme Parcours2 permettant de parcourir et d'afficher les valeurs de l'arbre A dans l'ordre croissant.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/exercices/#exercice","title":"Exercice","text":"Exercice 3 du sujet Centres Etrangers J2 - 2023
Correction Q1.a.'Bonjour Alan !'
Ce sont des bool\u00e9ens. x
vaut False
, y
vaut True
.
def occurences_lettre(une_chaine, une_lettre):\n nb = 0\n for lettre in une_chaine:\n if lettre == une_lettre:\n nb += 1\n return nb\n
Correction Q3.b.. def hauteur(un_abr):\n if un_abr.est_vide():\n return 0\n else:\n return 1 + max(hauteur(un_abr.sous_arbre_gauche, hauteur(un_abr.sous_arbre_droit)\n
Fichier des mots fran\u00e7ais : gutemberg.txt
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/TP_Labyrinthe/","title":"R\u00e9solution d'un labyrinthe","text":""},{"location":"T1_Structures_de_donnees/1.4_Graphes/TP_Labyrinthe/#1-presentation-du-probleme","title":"1. Pr\u00e9sentation du probl\u00e8me","text":"Consid\u00e9rons le labyrinthe suivant :
Affectons une lettre \u00e0 chaque case de ce labyrinthe.
Notre objectif est de trouver comment aller de A en P.
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/TP_Labyrinthe/#2-modelisation-par-un-graphe","title":"2. Mod\u00e9lisation par un graphe","text":"Dessiner le graphe (dont les noeuds seront des lettres) qui mod\u00e9lise ce labyrinthe.
Proposer deux \u00abformes\u00bb possibles pour ce graphe.
Correction "},{"location":"T1_Structures_de_donnees/1.4_Graphes/TP_Labyrinthe/#3-implementation-du-graphe-en-python","title":"3. Impl\u00e9mentation du graphe en Python","text":"En utilisant la classe Graphe
cr\u00e9\u00e9e en cours, impl\u00e9menter le graphe de ce labyrinthe.
class Graphe:\n def __init__(self, liste_sommets):\n self.liste_sommets = liste_sommets\n self.adjacents = {sommet : [] for sommet in liste_sommets}\n\n def ajoute_arete(self, sommetA, sommetB):\n self.adjacents[sommetA].append(sommetB)\n self.adjacents[sommetB].append(sommetA)\n\n def voisins(self, sommet):\n return self.adjacents[sommet]\n\n def sont_voisins(self, sommetA, sommetB):\n return sommetB in self.adjacents[sommetA]\n\ng = Graphe(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P'])\ng.ajoute_arete('A', 'E')\ng.ajoute_arete('E', 'F')\ng.ajoute_arete('F', 'B')\ng.ajoute_arete('B', 'C')\ng.ajoute_arete('C', 'G')\ng.ajoute_arete('G', 'H')\ng.ajoute_arete('H', 'D')\ng.ajoute_arete('G', 'K')\ng.ajoute_arete('F', 'J')\ng.ajoute_arete('J', 'I')\ng.ajoute_arete('I', 'M')\ng.ajoute_arete('M', 'N')\ng.ajoute_arete('N', 'O')\ng.ajoute_arete('O', 'K')\ng.ajoute_arete('K', 'L')\ng.ajoute_arete('L', 'P')\n
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/TP_Labyrinthe/#4-recherche-du-plus-court-chemin","title":"4. Recherche du plus court chemin","text":"En utilisant la fonction recherche_chemin
du cours, \u00e9tablir le plus court chemin pour aller de A vers P dans ce labyrinthe.
def recherche_chemin(g, depart, arrivee):\n'''\n Parcours en largeur du graphe g en partant du sommet depart,\n qui s'arr\u00eate d\u00e8s que le sommet arrivee est atteint.\n Renvoie alors le chemin du depart vers arrivee.\n '''\n traites = []\n decouverts = [depart]\n en_attente = [depart]\n parent = {}\n while en_attente != [] :\n sommet = en_attente.pop(0)\n voisins = g.voisins(sommet)\n for voisin in voisins:\n if voisin not in decouverts:\n decouverts.append(voisin)\n en_attente.append(voisin)\n parent[voisin] = sommet\n if voisin == arrivee:\n return remonte_chemin(depart, arrivee, parent)\n traites.append(sommet)\n return \"non trouv\u00e9\" \n\n\ndef remonte_chemin(depart, arrivee, parent):\n sommet = arrivee\n chemin = arrivee\n while sommet != depart:\n sommet = parent[sommet]\n chemin = sommet + chemin\n return chemin\n
>>> recherche_chemin(g, 'A', 'P')\n'AEFBCGKLP'\n
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/TP_Labyrinthe/#5-conclusion","title":"5. Conclusion","text":"Sur un labyrinthe un peu plus imposant, voici l'illustration de notre m\u00e9thode de r\u00e9solution :
parent
, et ainsi le chemin de sortie du labyrinthe est g\u00e9n\u00e9r\u00e9. Code de cette animation (en Pygame)
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/TP_Labyrinthe/#6-annexe-et-pourquoi-pas-en-dfs","title":"6. Annexe : et pourquoi pas en DFS ?","text":"Les parcours BFS et DFS ont tous deux la propri\u00e9t\u00e9 de parcourir la totalit\u00e9 du graphe (ils sont m\u00eame con\u00e7us pour cela). Cela a permis au parcours BFS de nous fournir une solution au labyrinthe (dont on a d\u00e9montr\u00e9 qu'elle \u00e9tait la plus courte).
Que penser de solution qui sera donn\u00e9e par le DFS ?
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/TP_Labyrinthe/#61-dans-un-labyrinthe-parfait","title":"6.1 Dans un labyrinthe parfait","text":"Voici un code o\u00f9 la solution est d'abord recherch\u00e9e par BFS (cases explor\u00e9es en bleu clair, chemin trouv\u00e9 marqu\u00e9 en bleu), puis en DFS (cases explor\u00e9es en rose, chemin trouv\u00e9 marqu\u00e9 en rouge).
anim_laby_DFSvsBFS_laby_parfait.py
Que remarquez-vous ???
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/TP_Labyrinthe/#62-dans-un-labyrinthe-non-parfait","title":"6.2 Dans un labyrinthe non parfait","text":"Changeons de code pour un labyrinthe d\u00e9g\u00e9n\u00e9r\u00e9 :
anim_laby_DFSvsBFS_laby_degenere.py
Que remarquez-vous ???
ExplicationsNotre labyrinthe con\u00e7u de mani\u00e8re al\u00e9atoire poss\u00e8de une propri\u00e9t\u00e9 remarquable (d\u00fb son algorithme de construction) : chaque case peut \u00eatre reli\u00e9e \u00e0 une autre par un chemin unique. On dit de ces labyrinthes qu'ils sont parfaits.
Donc, dans notre code du 6.1 (labyrinthe parfait), le DFS va lui aussi trouver le chemin le plus court... puisqu'il y en a qu'un seul ! De plus, la m\u00e9thode d'exploration en profondeur va de plus rendre le DFS plus rapide que le BFS, quasiment tout le temps. Ce qui fait que pour un labyrinthe parfait, le DFS est plus int\u00e9ressant que le BFS.
Mais si le labyrinthe n'est plus parfait (code du 6.2), le DFS va trouver une solution qui ne sera pas obligatoirement la meilleure... S'il y a plusieurs solutions possibles, absolument rien ne garantit que la premi\u00e8re solution trouv\u00e9e par le DFS (sur laquelle il s'arr\u00eatera) sera la meilleure !
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/","title":"Graphes","text":"Ce cours est int\u00e9gralement inspir\u00e9 du cours de C\u00e9dric Gouygou , du lyc\u00e9e Marguerite de Valois d'Angoul\u00eame (16)
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#1-notion-de-graphe-et-vocabulaire","title":"1. Notion de graphe et vocabulaire","text":"Le concept de graphe permet de r\u00e9soudre de nombreux probl\u00e8mes en math\u00e9matiques comme en informatique. C'est un outil de repr\u00e9sentation tr\u00e8s courant, et nous l'avons d\u00e9j\u00e0 rencontr\u00e9 \u00e0 plusieurs reprises, en particulier lors de l'\u00e9tude de r\u00e9seaux.
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#11-exemples-de-situations","title":"1.1 Exemples de situations","text":""},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#111-reseau-informatique","title":"1.1.1 R\u00e9seau informatique","text":""},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#112-reseau-de-transport","title":"1.1.2 R\u00e9seau de transport","text":""},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#113-reseau-social","title":"1.1.3 R\u00e9seau social","text":""},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#114-generalisation","title":"1.1.4 G\u00e9n\u00e9ralisation","text":"Une multitude de probl\u00e8mes concrets d'origines tr\u00e8s diverses peuvent donner lieu \u00e0 des mod\u00e9lisations par des graphes : c'est donc une structure essentielle en sciences, qui requiert un formalisme math\u00e9matique particulier que nous allons d\u00e9couvrir.
L'\u00e9tude de la th\u00e9orie des graphes est un champ tr\u00e8s vaste des math\u00e9matiques : nous allons surtout nous int\u00e9resser \u00e0 l'impl\u00e9mentation en Python d'un graphe et \u00e0 diff\u00e9rents probl\u00e8mes algorithmiques qui se posent dans les graphes.
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#12-vocabulaire","title":"1.2 Vocabulaire","text":"En g\u00e9n\u00e9ral, un graphe est un ensemble d'objets, appel\u00e9s sommets ou parfois n\u0153uds (vertex or nodes en anglais) reli\u00e9s par des ar\u00eates ou arcs ((edges en anglais)). Ce graphe peut \u00eatre non-orient\u00e9 ou orient\u00e9 .
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#121-graphe-non-oriente","title":"1.2.1 Graphe non-orient\u00e9","text":"Dans un graphe non-orient\u00e9, les ar\u00eates peuvent \u00eatre emprunt\u00e9es dans les deux sens, et une cha\u00eene est une suite de sommets reli\u00e9s par des ar\u00eates, comme C - B - A - E par exemple. La longueur de cette cha\u00eene est alors 3, soit le nombre d'ar\u00eates.
Les sommets B et E sont adjacents au sommet A, ce sont les voisins de A.
Exemple de graphe non-orient\u00e9 : le graphe des relations d'un individu sur Facebook est non-orient\u00e9, car si on est \u00abami\u00bb avec quelqu'un la r\u00e9ciproque est vraie.
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#122-graphe-oriente","title":"1.2.2 Graphe orient\u00e9","text":"Dans un graphe orient\u00e9, les arcs ne peuvent \u00eatre emprunt\u00e9s que dans le sens de la fl\u00e8che, et un chemin est une suite de sommets reli\u00e9s par des arcs, comme B \u2192 C \u2192 D \u2192 E par exemple.
Les sommets C et D sont adjacents au sommet B (mais pas A !), ce sont les voisins de B.
Exemple de graphe orient\u00e9 : le graphe des relations d'un individu sur Twitter est orient\u00e9, car on peut \u00absuivre\u00bb quelqu'un sans que cela soit r\u00e9ciproque.
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#123-graphe-pondere","title":"1.2.3 Graphe pond\u00e9r\u00e9","text":"Un graphe est pond\u00e9r\u00e9 (ou valu\u00e9) si on attribue \u00e0 chaque ar\u00eate une valeur num\u00e9rique (la plupart du temps positive), qu'on appelle mesure, poids, co\u00fbt ou valuation.
Par exemple:
Un graphe est connexe s'il est d'un seul tenant: c'est-\u00e0-dire si n'importe quelle paire de sommets peut toujours \u00eatre reli\u00e9e par une cha\u00eene. Autrement un graphe est connexe s'il est \u00aben un seul morceau\u00bb.
Par exemple, le graphe pr\u00e9c\u00e9dent est connexe. Mais le suivant ne l'est pas: il n'existe pas de cha\u00eene entre les sommets A et F par exemple.
Il poss\u00e8de cependant deux composantes connexes : le sous-graphe compos\u00e9 des sommets A, B, C, D et E d'une part et le sous-graphe compos\u00e9 des sommets F, G et H.
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#2-modelisations-dun-graphe","title":"2. Mod\u00e9lisations d'un graphe","text":"Pour mod\u00e9liser un graphe, il faut \u00e9tablir par convention une mani\u00e8re de donner les renseignements suivants :
Principe
i
et colonne j
si les sommets de rang i
et de rang j
sont voisins (dits aussi adjacents).Ce tableau s'appelle une matrice d'adjacence (on aurait tr\u00e8s bien pu l'appeler aussi matrice de voisinage).
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#211-graphe-non-oriente","title":"2.1.1 Graphe non orient\u00e9","text":"Dans ce graphe non orient\u00e9, comme B est voisin de C, C est aussi voisin de B, ce qui signifie que l'ar\u00eate qui relie B et C va donner lieu \u00e0 deux \"1\" dans la matrice, situ\u00e9 de part et d'autre de la diagonale descendante (un math\u00e9maticien parlera de matrice sym\u00e9trique).
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#212-graphe-oriente","title":"2.1.2 Graphe orient\u00e9","text":""},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#213-graphe-pondere","title":"2.1.3 Graphe pond\u00e9r\u00e9","text":""},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#214-exercices","title":"2.1.4 Exercices","text":"Exercice 1
Soit un ensemble d'amis connect\u00e9s sur un r\u00e9seau social quelconque. Voici les interactions qu'on a recens\u00e9es\u00a0:
Q1. Repr\u00e9senter le graphe des relations dans ce r\u00e9seau social (on d\u00e9signera chaque individu par l'initiale de son pr\u00e9nom). Il est possible de faire en sorte que les ar\u00eates ne se croisent pas !
Correction Q1Q2. Donner la matrice d'adjacence de ce graphe.
Correction Q2\\(\\pmatrix{ 0 & 1 & 1 & 0 & 1 & 1 & 0 & 0 \\\\ 1 & 0 & 1 & 1 & 0 & 0 & 0 & 1 \\\\ 1 & 1 & 0 & 1 & 1 & 1 & 1 & 0 \\\\ 0 & 1 & 1 & 0 & 1 & 0 & 0 & 0 \\\\ 1 & 0 & 1 & 1 & 0 & 0 & 0 & 0 \\\\ 1 & 0 & 1 & 0 & 0 & 0 & 1 & 0 \\\\ 0 & 0 & 1 & 0 & 0 & 1 & 0 & 0 \\\\ 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\\\ }\\)
Exercice 2
Construire les graphes correspondants aux matrices d'adjacence suivantes:
Q1. \\(M_1 =\\pmatrix{ 0&1&1&1&1\\\\ 1&0&1&0&0\\\\ 1&1&0&1&0\\\\ 1&0&1&0&1\\\\ 1&0&0&1&0\\\\ }\\)
CorrectionQ2. \\(M_2=\\pmatrix{ 0&1&1&0&1\\\\ 0&0&1&0&0\\\\ 0&0&0&1&0\\\\ 1&0&0&0&1\\\\ 0&0&0&0&0\\\\ }\\)
CorrectionQ3. \\(M_3=\\pmatrix{ 0&5&10&50&12\\\\ 5&0&10&0&0\\\\ 10&10&0&8&0\\\\ 50&0&8&0&100\\\\ 12&0&0&100&0\\\\ }\\)
Correction "},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#215-implementation-python-des-matrices-dadjacence","title":"2.1.5 Impl\u00e9mentation Python des matrices d'adjacence","text":"Matrices d'adjacence en Python
Une matrice se repr\u00e9sente naturellement par une liste de listes.
Exemple: La matrice \\(M_1 =\\pmatrix{ 0&1&1&1&1\\\\ 1&0&1&0&0\\\\ 1&1&0&1&0\\\\ 1&0&1&0&1\\\\ 1&0&0&1&0\\\\ }\\), associ\u00e9e au graphe
sera repr\u00e9sent\u00e9e par la variable G
suivante :
G = [[0, 1, 1, 1, 1],\n [1, 0, 1, 0, 0],\n [1, 1, 0, 1, 0],\n [1, 0, 1, 0, 1],\n [1, 0, 0, 1, 0]]\n
Complexit\u00e9 en m\u00e9moire et temps d'acc\u00e8s :
Pour un graphe \u00e0 \\(n\\) sommets, la complexit\u00e9 en m\u00e9moire (appel\u00e9e aussi complexit\u00e9 spatiale) de la repr\u00e9sentation matricielle est en \\(O(n^2)\\).
Tester si un sommet est isol\u00e9 (ou conna\u00eetre ses voisins) est en \\(O(n)\\) puisqu'il faut parcourir une ligne, mais tester si deux sommets sont adjacents (voisins) est en \\(O(1)\\), c'est un simple acc\u00e8s au tableau.
La mod\u00e9lisation d'un graphe par sa matrice d'adjacence est loin d'\u00eatre la seule mani\u00e8re de repr\u00e9senter un graphe : nous allons voir une autre mod\u00e9lisation, par liste d'adjacence.
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#22-representation-par-listes-dadjacence","title":"2.2 Repr\u00e9sentation par listes d'adjacence","text":"Principe
On associe \u00e0 chaque sommet sa liste des voisins (c'est-\u00e0-dire les sommets adjacents). On utilise pour cela un dictionnaire dont les cl\u00e9s sont les sommets et les valeurs les listes des voisins.
Dans le cas d'un graphe orient\u00e9 on associe \u00e0 chaque sommet la liste des successeurs (ou bien des pr\u00e9d\u00e9cesseurs, au choix).
Par exemple, le graphe sera repr\u00e9sent\u00e9 par le dictionnaire :
G = {'A': ['B', 'C', 'D', 'E'],\n 'B': ['A', 'C'],\n 'C': ['A', 'B', 'D'],\n 'D': ['A', 'C', 'E'],\n 'E': ['A', 'D']\n }\n
Complexit\u00e9 en m\u00e9moire et temps d'acc\u00e8s :
Pour un graphe \u00e0 \\(n\\) sommets et \\(m\\) ar\u00eates, la complexit\u00e9 spatiale de la repr\u00e9sentation en liste d'adjacence est en \\(O(n+m)\\). C'est beaucoup mieux qu'une matrice d'adjacence lorsque le graphe comporte peu d'ar\u00eates (i.e. beaucoup de 0 dans la matrice, non stock\u00e9s avec des listes).
Tester si un sommet est isol\u00e9 (ou conna\u00eetre ses voisins) est en \\(O(1)\\) puisqu'on y acc\u00e8de imm\u00e9diatement, mais tester si deux sommets sont adjacents (voisins) est en \\(O(n)\\) car il faut parcourir la liste.
Exercice 3
Construire les graphes correspondants aux listes d'adjacence suivantes.
Q1.
G1 = {\n'A': ['B', 'C'],\n'B': ['A', 'C', 'E', 'F'],\n'C': ['A', 'B', 'D'],\n'D': ['C', 'E'],\n'E': ['B', 'D', 'F'],\n'F': ['B', 'E']\n }\n
Correction Q1 Q2.
G2 = {\n'A': ['B'],\n'B': ['C', 'E'],\n'C': ['B', 'D'],\n'D': [],\n'E': ['A']\n }\n
Correction Q2 "},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#3-creation-dune-classe-graphe","title":"3. Cr\u00e9ation d'une classe Graphe
","text":"Dans cette partie, nous ne traiterons que des graphes non-orient\u00e9s.
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#31-interface-souhaitee","title":"3.1 Interface souhait\u00e9e","text":"Nous voulons que le graphe puisse \u00eatre cr\u00e9\u00e9 gr\u00e2ce aux instructions suivantes :
g = Graphe(['A', 'B', 'C', 'D', 'E'])\ng.ajoute_arete('A', 'B')\ng.ajoute_arete('A', 'C')\ng.ajoute_arete('A', 'D')\ng.ajoute_arete('A', 'E')\ng.ajoute_arete('B', 'C')\ng.ajoute_arete('C', 'D')\ng.ajoute_arete('D', 'E')\n
Nous souhaitons aussi pouvoir tester si deux sommets sont voisins avec la m\u00e9thode sont_voisins
:
>>> g.sont_voisins('E', 'A')\nTrue\n>>> g.sont_voisins('E', 'B')\nFalse\n
Enfin, nous voulons pouvoir obtenir facilement la liste de tous les voisins d'un sommet avec la m\u00e9thode voisins
:
>>> g.voisins('C')\n['A', 'B', 'D']\n
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#32-conseils-dimplementation","title":"3.2 Conseils d'impl\u00e9mentation","text":"L'objet de type Graphe
aura comme attributs :
liste_sommets
(donn\u00e9e en param\u00e8tre dans la liste liste_sommets
) adjacents
, o\u00f9 chaque sommet se verra attribuer une liste vide []
.Impl\u00e9mentation d'une classe Graphe
class Graphe:\n def __init__(self, liste_sommets):\n self.liste_sommets = liste_sommets\n self.adjacents = {sommet : [] for sommet in liste_sommets}\n\n def ajoute_arete(self, sommetA, sommetB):\n self.adjacents[sommetA].append(sommetB)\n self.adjacents[sommetB].append(sommetA)\n\n def voisins(self, sommet):\n return self.adjacents[sommet]\n\n def sont_voisins(self, sommetA, sommetB):\n return sommetB in self.adjacents[sommetA]\n
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#4-parcours-de-graphes","title":"4. Parcours de graphes","text":"Algorithme de parcours
Un parcours de graphe est un algorithme consistant \u00e0 explorer tous les sommets d'un graphe de proche en proche \u00e0 partir d'un sommet initial. Ces parcours sont notamment utilis\u00e9s pour rechercher un plus court chemin (et donc dans les GPS) ou pour trouver la sortie d'un labyrinthe...
Parcourir simplement le dictionnaire ou la matrice d\u2019un graphe n\u2019est pas consid\u00e9r\u00e9 comme un parcours de graphe.
Tous les parcours suivent plus ou moins le m\u00eame algorithme de base :
On visite un sommet A
. On cr\u00e9e une structure S
qui contiendra au d\u00e9part l\u2019ensemble des voisins de A
.
Tant que S
n\u2019est pas vide :
s
de S
s
S
tous les voisins de s
pas encore visit\u00e9sSommets visit\u00e9s
Contrairement \u00e0 un parcours d'arbre, o\u00f9 les fils d'un n\u0153ud ne peuvent pas avoir \u00e9t\u00e9 visit\u00e9s avant le n\u0153ud, un voisin d'un sommet peut avoir d\u00e9j\u00e0 \u00e9t\u00e9 visit\u00e9 en tant que voisin d'un sommet pr\u00e9c\u00e9dent...
Il est donc n\u00e9cessaire de m\u00e9moriser les sommets d\u00e9ja visit\u00e9s ou d\u00e9couverts (on dira qu'un sommet est d\u00e9couvert lorsqu'on l'ajoute \u00e0 S
).
Le choix de la structure de l'ensemble S
est pr\u00e9pond\u00e9rant:
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#41-le-parcours-en-largeur-bfs-breadth-first-search","title":"4.1 Le parcours en largeur (BFS, Breadth First Search)","text":""},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#411-principe","title":"4.1.1 Principe","text":"
Exemple de parcours en largeur, avec B comme sommet de d\u00e9part:
Codes couleur :
On utilise :
traites
qui recueille les sommets visit\u00e9s (c'est-\u00e0-dire qu'on a fini de traiter, apr\u00e8s avoir ajout\u00e9 ses voisins dans la file d'attente) et qui sera renvoy\u00e9e \u00e0 la fin de l'algorithme;decouverts
qui contient les sommets d\u00e9couverts au fur et \u00e0 mesure du parcours;en_attente
qui contient les sommets d\u00e9couverts mais non encore visit\u00e9s. On utilisera au choix une classe File
\u00e9crite plus t\u00f4t dans l'ann\u00e9e ou tout simplement une list
en utilisant pop(0)
(pour d\u00e9filer) et append()
(pour enfiler).En d\u00e9but d'algorithme, seul le sommet de d\u00e9part depart
donn\u00e9 en param\u00e8tre est d\u00e9couvert. La fonction BFS
renvoie la liste des sommets dans l'ordre de visite lors du parcours en largeur.
Parcours en largeur - BFS
def BFS(g, depart):\n'''\n Effectue un parcours en largeur du graphe g en partant du sommet depart,\n et renvoie la liste des sommets visit\u00e9s dans l'ordre du parcours.\n '''\n traites = []\n decouverts = [depart]\n en_attente = [depart]\n while en_attente != [] :\n sommet = en_attente.pop(0)\n voisins = g.voisins(sommet)\n for voisin in voisins:\n if voisin not in decouverts:\n decouverts.append(voisin)\n en_attente.append(voisin)\n traites.append(sommet)\n return traites\n
Int\u00e9r\u00eat de la liste decouverts
La liste decouverts
contient tous les sommets qui ont \u00e9t\u00e9 :
traites
)en_attente
)Le test de la ligne 13 if voisin not in decouverts:
permet donc de ne pas mettre en file d'attente un voisin qui est (ou a \u00e9t\u00e9) d\u00e9j\u00e0 en file d'attente.
Que contient la file en_attente
?
\u00c0 chaque instant, la file en_attente
contient des sommets \u00e0 la distance k+1
et \u00e0 la distance k
du point de d\u00e9part :
Exercice 4
Gr\u00e2ce \u00e0 la classe Graphe
du 3.3, ce graphe s'impl\u00e9mente par :
g = Graphe(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'])\ng.ajoute_arete('A', 'B')\ng.ajoute_arete('A', 'C')\ng.ajoute_arete('B', 'D')\ng.ajoute_arete('D', 'C')\ng.ajoute_arete('B', 'E')\ng.ajoute_arete('D', 'E')\ng.ajoute_arete('E', 'F')\ng.ajoute_arete('E', 'G')\ng.ajoute_arete('F', 'G')\ng.ajoute_arete('G', 'H')\n
Q1. Donner le parcours en largeur de g
gr\u00e2ce \u00e0 l'algorithme BFS, si le sommet de d\u00e9part est B. Cela correspond au parcours pr\u00e9sent\u00e9 par le gif de d\u00e9but de paragraphe.
>>> BFS(g, 'B')\n['B', 'A', 'D', 'E', 'C', 'F', 'G', 'H']\n
Q2. Deviner le parcours en largeur de d\u00e9part D, puis de d\u00e9part G. V\u00e9rifier gr\u00e2ce \u00e0 votre algorithme.
Correction Q2>>> BFS(g, 'D')\n['D', 'B', 'C', 'E', 'A', 'F', 'G', 'H']\n>>> BFS(g, 'G')\n['G', 'E', 'F', 'H', 'B', 'D', 'A', 'C']\n
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#413-application-du-bfs-recherche-du-plus-court-chemin","title":"4.1.3 Application du BFS : recherche du plus court chemin","text":"L'algorithme BFS d\u00e9couvre les sommets \u00abpar cercles concentriques\u00bb autour du point de d\u00e9part (ainsi que le montre la structure de la file d'attente). On d\u00e9couvre d'abord tous les sommets \u00e0 la distance 1 du point de d\u00e9part, puis \u00e0 la distance 2, puis 3, etc.
Un sommet situ\u00e9 \u00e0 la distance 5 sera d\u00e9couvert en tant que voisin d'un sommet \u00e0 la distance 4, qui lui-m\u00eame aura \u00e9t\u00e9 d\u00e9couvert gr\u00e2ce \u00e0 un sommet \u00e0 la distance 3, qui lui-m\u00eame...
On comprend donc que si on arrive \u00e0 se souvenir du sommet \u00abparent\u00bb de chaque sommet (celui qui lui a permis d'\u00eatre d\u00e9couvert), on pourra alors reconstituer un chemin permettant de remonter au point de d\u00e9part.
Nous allons pour cela nous servir d'une structure de dictionnaire pour associer \u00e0 chaque sommet son sommet-parent.
Il faudra ensuite une fonction pour recr\u00e9er le chemin.
Pourquoi le plus court chemin ?
Si le graphe est connexe, tout parcours BFS au d\u00e9part de A va parcourir l'int\u00e9gralit\u00e9 du graphe, et donc passera par B \u00e0 un moment. Un chemin sera donc forc\u00e9ment trouv\u00e9 entre A et B.
La d\u00e9couverte des sommets par cercles concentriques entre A et B nous assure qu'on ne peut pas rater le point B : s'il est \u00e0 la distance k
de A, il sera forc\u00e9ment visit\u00e9 puisque tous les sommets \u00e0 la distance k
vont passer par la liste d'attente, apr\u00e8s les sommets de distance k-1
et avant les sommets de distance k+1
.
Lorsqu'on remontera de B vers A en passant par les sommets parents successifs, il ne peut y avoir qu'un seul sommet par \u00abcouche\u00bb : le chemin sera donc exactement de longueur k
, il sera donc minimal.
Recherche du plus court chemin
def recherche_chemin(g, depart, arrivee):\n'''\n Parcours en largeur du graphe g en partant du sommet depart,\n qui s'arr\u00eate d\u00e8s que le sommet arrivee est atteint.\n Renvoie alors le chemin du depart vers arrivee.\n '''\n traites = []\n decouverts = [depart]\n en_attente = [depart]\n parent = {}\n while en_attente != [] :\n sommet = en_attente.pop(0)\n voisins = g.voisins(sommet)\n for voisin in voisins:\n if voisin not in decouverts:\n decouverts.append(voisin)\n en_attente.append(voisin)\n parent[voisin] = sommet\n if voisin == arrivee:\n return remonte_chemin(depart, arrivee, parent)\n traites.append(sommet)\n return \"non trouv\u00e9\" \n\n\ndef remonte_chemin(depart, arrivee, parent):\n sommet = arrivee\n chemin = arrivee\n while sommet != depart:\n sommet = parent[sommet]\n chemin = sommet + chemin\n return chemin\n
Exercice 5
Tester le code pr\u00e9c\u00e9dent pour trouver le plus court chemin entre A et G, entre H et C, entre B et G...
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#42-le-parcours-en-profondeur-dfs-depth-first-search","title":"4.2 Le parcours en profondeur (DFS, Depth First Search)","text":""},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#421-parcours-dfs-recursif","title":"4.2.1 Parcours DFS r\u00e9cursif","text":"Le parcours en profondeur est un parcours o\u00f9 on va aller \u00able plus loin possible\u00bb sans se pr\u00e9occuper des autres voisins non visit\u00e9s : on va visiter le premier de ses voisins non trait\u00e9s, qui va faire de m\u00eame, etc. Lorsqu'il n'y a plus de voisin, on revient en arri\u00e8re pour aller voir le dernier voisin non visit\u00e9.
Dans un labyrinthe, ce parcours s'explique tr\u00e8s bien : on prend tous les chemins sur la droite jusqu'\u00e0 rencontrer un mur, auquel cas on revient au dernier embranchement et on prend un autre chemin, puis on repart \u00e0 droite, etc.
C'est un parcours qui s'\u00e9crit naturellement de mani\u00e8re r\u00e9cursive :
Parcours en profondeur - DFS
def DFSrec(g, traites, actuel):\n traites.append(actuel)\n for voisin in g.voisins(actuel):\n if voisin not in traites:\n DFSrec(g, traites, voisin)\n return traites\n
Exercice 6
Q1. Donner (de t\u00eate) le parcours DFS de ce graphe en partant de A. Rappel : les voisins sont donn\u00e9s par ordre alphab\u00e9tique. Le premier voisin de A est donc B.
Q2. V\u00e9rifier avec le code pr\u00e9c\u00e9dent.
Correction Q2class Graphe:\n def __init__(self, liste_sommets):\n self.liste_sommets = liste_sommets\n self.adjacents = {sommet : [] for sommet in liste_sommets}\n\n def ajoute_arete(self, sommetA, sommetB):\n self.adjacents[sommetA].append(sommetB)\n self.adjacents[sommetB].append(sommetA)\n\n def voisins(self, sommet):\n return self.adjacents[sommet]\n\n def sont_voisins(self, sommetA, sommetB):\n return sommetB in self.adjacents[sommetA]\n\n\ng = Graphe(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'])\ng.ajoute_arete('A', 'B')\ng.ajoute_arete('A', 'C')\ng.ajoute_arete('B', 'D')\ng.ajoute_arete('D', 'C')\ng.ajoute_arete('B', 'E')\ng.ajoute_arete('D', 'E')\ng.ajoute_arete('E', 'F')\ng.ajoute_arete('E', 'G')\ng.ajoute_arete('F', 'G')\ng.ajoute_arete('G', 'H')\n\n\ndef DFSrec(g, traites, actuel):\n traites.append(actuel)\n for voisin in g.voisins(actuel):\n if voisin not in traites:\n DFSrec(g, traites, voisin)\n return traites\n
>>> DFSrec(g, [], 'A')\n['A', 'B', 'D', 'C', 'E', 'F', 'G', 'H']\n
Q3. Reprendre les questions pr\u00e9c\u00e9dentes en changeant le sommet de d\u00e9part.
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#422-parcours-dfs-iteratif","title":"4.2.2 Parcours DFS it\u00e9ratif","text":"Il \u00absuffit\u00bb de remplacer la file du parcours BFS par une pile. Ainsi, on partira visiter le voisin tout juste ajout\u00e9 \u00e0 la file d'attente (qui porte maintenant mal son nom, puisque c'est devenu une pile).
Parcours en profondeur it\u00e9ratif - DFS
def DFS_iteratif(graphe, start):\n traites = []\n en_attente = [start]\n while en_attente != []:\n actuel = en_attente.pop()\n if actuel not in traites:\n voisins = g.voisins(actuel)[::-1]\n for voisin in voisins:\n if voisin not in traites:\n en_attente.append(voisin)\n traites.append(actuel)\n return traites\n
Remarques :
\u00c0 la ligne 7, on inverse l'ordre des voisins pour que ce code renvoie le m\u00eame parcours quele parcours r\u00e9cursif (sinon c'est le dernier voisin ajout\u00e9 qui sera d\u00e9pil\u00e9). Cela n'est pas obligatoire : il n'y a pas \u00abun seul\u00bb parcours DFS (tout comme il n'y a pas qu'un seul BFS). Ce qui les caract\u00e9rise est la m\u00e9thode de d\u00e9couverte, plus que l'impl\u00e9mentation proprement dite.
Contrairement au BFS, il est possible d'empiler un sommet d\u00e9j\u00e0 d\u00e9couvert (on v\u00e9rifie juste qu'il n'ait pas d\u00e9j\u00e0 \u00e9t\u00e9 trait\u00e9). Vous pouvez vous en apercevoir en \u00e9crivant l'\u00e9tat de la pile lors du parcours DFS it\u00e9ratif du graphe de l'exercice 6.
import pygame, sys\nimport time\nfrom pygame.locals import *\n\nLARGEUR = 640\nHAUTEUR = 480\nRAYON = 20\n\npygame.display.init()\nfenetre = pygame.display.set_mode((LARGEUR, HAUTEUR))\nfenetre.fill([0,0,0])\n\nx = 300\ny = 200\ndx = 4\ndy = -3\ncouleur = (45, 170, 250)\n\nwhile True:\n fenetre.fill([0, 0, 0])\n pygame.draw.circle(fenetre, couleur, (x, y), RAYON)\n\n x += dx\n y += dy\n\n pygame.display.update()\n\n # routine pour pouvoir fermer \u00abproprement\u00bb la fen\u00eatre Pygame\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n\n time.sleep(0.1)\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/TP/#11-rajout-dun-rebond-sur-les-parois","title":"1.1 Rajout d'un rebond sur les parois","text":"Modifiez le code pr\u00e9c\u00e9dent afin que la balle rebondisse sur chaque paroi (il suffit de modifier intelligemment les variables de vitesse dx
et dy
).
import pygame, sys\nimport time\nfrom pygame.locals import *\n\nLARGEUR = 640\nHAUTEUR = 480\nRAYON = 20\n\npygame.display.init()\nfenetre = pygame.display.set_mode((LARGEUR, HAUTEUR))\nfenetre.fill([0, 0, 0])\n\nx = 300\ny = 200\ndx = 4\ndy = -3\ncouleur = (45, 170, 250)\n\nwhile True:\n fenetre.fill([0, 0, 0])\n pygame.draw.circle(fenetre, couleur, (x, y), RAYON)\n\n x += dx\n y += dy\n\n if (y <= RAYON) or (y >= HAUTEUR - RAYON):\n dy = -dy\n if (x <= RAYON) or (x >= LARGEUR - RAYON):\n dx = -dx\n\n pygame.display.update()\n\n # routine pour pouvoir fermer \u00abproprement\u00bb la fen\u00eatre Pygame\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n\n time.sleep(0.02)\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/TP/#12-rajout-dune-deuxieme-balle","title":"1.2 Rajout d'une deuxi\u00e8me balle","text":"Attention au nommage des variables...
Correctionimport pygame, sys\nimport time\nfrom pygame.locals import *\n\nLARGEUR = 640\nHAUTEUR = 480\nRAYON = 20\n\npygame.display.init()\nfenetre = pygame.display.set_mode((LARGEUR, HAUTEUR))\nfenetre.fill([0, 0, 0])\n\n\ndxA = 7\ndyA = 4\ndxB = -5\ndyB = 3\n\n\nxA = LARGEUR // 3\nyA = HAUTEUR // 2\nxB = LARGEUR // 2\nyB = HAUTEUR // 2\n\n\ncouleurA = (45, 170, 250)\ncouleurB = (155, 17, 250)\n\nwhile True:\n fenetre.fill([0, 0, 0])\n pygame.draw.circle(fenetre, couleurA, (xA, yA), RAYON)\n pygame.draw.circle(fenetre, couleurB, (xB, yB), RAYON)\n\n xA += dxA\n yA += dyA\n\n xB += dxB\n yB += dyB\n\n # rebond en haut ou en bas\n if (yA < RAYON) or (yA > HAUTEUR - RAYON):\n dyA = -dyA\n\n # rebond \u00e0 gauche ou \u00e0 droite\n if (xA < RAYON) or (xA > LARGEUR - RAYON):\n dxA = -dxA\n\n # rebond en haut ou en bas\n if (yB < RAYON) or (yB > HAUTEUR - RAYON):\n dyB = -dyB\n\n # rebond \u00e0 gauche ou \u00e0 droite\n if (xB < RAYON) or (xB > LARGEUR - RAYON):\n dxB = -dxB\n\n pygame.display.update()\n\n # routine pour pouvoir fermer \u00abproprement\u00bb la fen\u00eatre Pygame\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n\n time.sleep(0.03)\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/TP/#13-gestion-de-la-collision-entre-les-deux-balles","title":"1.3 Gestion de la collision entre les deux balles","text":"Q1. \u00c0 l'aide d'un sch\u00e9ma (papier-crayon !), mettez en \u00e9vidence le test devant \u00eatre r\u00e9alis\u00e9 pour d\u00e9tecter une collision.
indiceQ2. Impl\u00e9mentez ce test (en cr\u00e9ant pour cela une fonction distance
) et affichez \"collision\" en console lorsque les deux balles se touchent.
import pygame, sys\nimport time\nfrom pygame.locals import *\n\nLARGEUR = 640\nHAUTEUR = 480\nRAYON = 20\n\npygame.display.init()\nfenetre = pygame.display.set_mode((LARGEUR, HAUTEUR))\nfenetre.fill([0, 0, 0])\n\n\ndxA = 7\ndyA = 4\ndxB = -5\ndyB = 3\n\n\nxA = LARGEUR // 3\nyA = HAUTEUR // 2\nxB = LARGEUR // 2\nyB = HAUTEUR // 2\n\n\ncouleurA = (45, 170, 250)\ncouleurB = (155, 17, 250)\n\n\ndef distanceAB(xA, yA, xB, yB):\n return ((xA-xB)**2 + (yA-yB)**2)**0.5\n\n\nwhile True:\n fenetre.fill([0, 0, 0])\n pygame.draw.circle(fenetre, couleurA, (xA, yA), RAYON)\n pygame.draw.circle(fenetre, couleurB, (xB, yB), RAYON)\n\n xA += dxA\n yA += dyA\n\n xB += dxB\n yB += dyB\n\n # rebond en haut ou en bas\n if (yA < RAYON) or (yA > HAUTEUR - RAYON):\n dyA = -dyA\n\n # rebond \u00e0 gauche ou \u00e0 droite\n if (xA < RAYON) or (xA > LARGEUR - RAYON):\n dxA = -dxA\n\n # rebond en haut ou en bas\n if (yB < RAYON) or (yB > HAUTEUR - RAYON):\n dyB = -dyB\n\n # rebond \u00e0 gauche ou \u00e0 droite\n if (xB < RAYON) or (xB > LARGEUR - RAYON):\n dxB = -dxB\n\n if distanceAB(xA, yA, xB, yB) < 2 * RAYON:\n print(\"collision\")\n\n pygame.display.update()\n\n # routine pour pouvoir fermer \u00abproprement\u00bb la fen\u00eatre Pygame\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n\n time.sleep(0.03)\n
Q3. Pour donner l'illusion physique du rebond, \u00e9changez les valeurs respectives de dx
et dy
pour les deux balles.
import pygame, sys\nimport time\nfrom pygame.locals import *\n\nLARGEUR = 640\nHAUTEUR = 480\nRAYON = 20\n\npygame.display.init()\nfenetre = pygame.display.set_mode((LARGEUR, HAUTEUR))\nfenetre.fill([0, 0, 0])\n\n\ndxA = 7\ndyA = 4\ndxB = -5\ndyB = 3\n\n\nxA = LARGEUR // 3\nyA = HAUTEUR // 2\nxB = LARGEUR // 2\nyB = HAUTEUR // 2\n\n\ncouleurA = (45, 170, 250)\ncouleurB = (155, 17, 250)\n\n\ndef distanceAB(xA, yA, xB, yB):\n return ((xA-xB)**2 + (yA-yB)**2)**0.5\n\n\nwhile True:\n fenetre.fill([0, 0, 0])\n pygame.draw.circle(fenetre, couleurA, (xA, yA), RAYON)\n pygame.draw.circle(fenetre, couleurB, (xB, yB), RAYON)\n\n xA += dxA\n yA += dyA\n\n xB += dxB\n yB += dyB\n\n # rebond en haut ou en bas\n if (yA < RAYON) or (yA > HAUTEUR - RAYON):\n dyA = -dyA\n\n # rebond \u00e0 gauche ou \u00e0 droite\n if (xA < RAYON) or (xA > LARGEUR - RAYON):\n dxA = -dxA\n\n # rebond en haut ou en bas\n if (yB < RAYON) or (yB > HAUTEUR - RAYON):\n dyB = -dyB\n\n # rebond \u00e0 gauche ou \u00e0 droite\n if (xB < RAYON) or (xB > LARGEUR - RAYON):\n dxB = -dxB\n\n if distanceAB(xA, yA, xB, yB) < 2 * RAYON:\n dxA, dxB = dxB, dxA\n dyA, dyB = dyB, dyA\n\n pygame.display.update()\n\n # routine pour pouvoir fermer \u00abproprement\u00bb la fen\u00eatre Pygame\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n\n time.sleep(0.03)\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/TP/#14-rajout-dune-troisieme-balle-et-gestion-du-rebond-avec-les-deux-autres","title":"1.4 Rajout d'une troisi\u00e8me balle et gestion du rebond avec les deux autres.","text":"... vraiment ? Peut-on continuer comme pr\u00e9c\u00e9demment ?
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/TP/#2-la-poo-a-la-rescousse-creation-dune-classe-balle","title":"2. La POO \u00e0 la rescousse : cr\u00e9ation d'une classe Balle","text":""},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/TP/#21-la-classe-balle","title":"2.1 la classe Balle","text":"L'objectif est que la m\u00e9thode constructeur dote chaque nouvelle balle de valeurs al\u00e9atoires : abscisse, ordonn\u00e9e, vitesse, couleur...
Pour l'al\u00e9atoire, on pourra utiliser randint(a, b)
qui renvoie un nombre pseudo-al\u00e9atoire entre a
et b
. Il faut pour cela importer la fonction, par from random import randint
Vous pouvez aussi doter votre classe Balle
d'une m\u00e9thode dessine
(qui affiche la balle), ainsi qu'une m\u00e9thode bouge
qui la fait bouger.
Cr\u00e9ez cette classe et instanciez une balle.
Correctionimport pygame, sys\nimport time\nfrom pygame.locals import *\nfrom random import randint\n\n# randint(0,10) -> nb al\u00e9atoire entre 0 et 10\n\nLARGEUR = 640\nHAUTEUR = 480\nRAYON = 20\n\npygame.display.init()\nfenetre = pygame.display.set_mode((LARGEUR, HAUTEUR))\nfenetre.fill([0, 0, 0])\n\n\nclass Balle:\n def __init__(self):\n self.x = randint(0, LARGEUR)\n self.y = randint(0, HAUTEUR)\n self.dx = randint(2, 5)\n self.dy = randint(2, 5)\n self.couleur = (randint(0, 255), randint(0, 255), randint(0, 255))\n self.taille = RAYON\n\n def dessine(self):\n pygame.draw.circle(fenetre, self.couleur, (self.x, self.y), self.taille)\n\n def bouge(self):\n self.x += self.dx\n self.y += self.dy\n\n if self.y < self.taille or self.y > HAUTEUR - self.taille:\n self.dy = -self.dy\n if self.x < self.taille or self.x > LARGEUR - self.taille:\n self.dx = -self.dx\n\n\nma_balle = Balle()\n\nwhile True:\n fenetre.fill([0, 0, 0])\n\n ma_balle.dessine()\n ma_balle.bouge()\n\n pygame.display.update()\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n\n time.sleep(0.05)\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/TP/#22-plusieurs-balles","title":"2.2 Plusieurs balles","text":"L'id\u00e9e est de stocker dans une liste sac_a_balles
un nombre d\u00e9termin\u00e9 de balles...
import pygame, sys\nimport time\nfrom pygame.locals import *\nfrom random import randint\n\n# randint(0,10) -> nb al\u00e9atoire entre 0 et 10\n\nLARGEUR = 640\nHAUTEUR = 480\nRAYON = 20\nNB_BALLES = 10\n\npygame.display.init()\nfenetre = pygame.display.set_mode((LARGEUR, HAUTEUR))\nfenetre.fill([0, 0, 0])\n\n\nclass Balle:\n def __init__(self):\n self.x = randint(0, LARGEUR)\n self.y = randint(0, HAUTEUR)\n self.dx = randint(2, 5)\n self.dy = randint(2, 5)\n self.couleur = (randint(0, 255), randint(0, 255), randint(0, 255))\n self.taille = RAYON\n\n def dessine(self):\n pygame.draw.circle(fenetre, self.couleur, (self.x, self.y), self.taille)\n\n def bouge(self):\n self.x += self.dx\n self.y += self.dy\n\n if self.y < self.taille or self.y > HAUTEUR - self.taille:\n self.dy = -self.dy\n if self.x < self.taille or self.x > LARGEUR - self.taille:\n self.dx = -self.dx\n\n\nmon_sac_a_balles = [Balle() for _ in range(NB_BALLES)]\n\nwhile True:\n fenetre.fill([0, 0, 0])\n\n for balle in mon_sac_a_balles:\n balle.dessine()\n balle.bouge()\n\n pygame.display.update()\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n\n time.sleep(0.05)\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/TP/#23-collision-de-toutes-les-balles","title":"2.3 Collision de toutes les balles","text":"Il \u00absuffit\u00bb , dans la m\u00e9thode constructeur, de tester la collision de la balle self
avec chacune des balles de notre sac_a_balles
.
import pygame, sys\nimport time\nfrom pygame.locals import *\nfrom random import randint\n\n# randint(0,10) -> nb al\u00e9atoire entre 0 et 10\n\nLARGEUR = 640\nHAUTEUR = 480\nRAYON = 20\nNB_BALLES = 10\n\npygame.display.init()\nfenetre = pygame.display.set_mode((LARGEUR, HAUTEUR))\nfenetre.fill([0, 0, 0])\n\n\nclass Balle:\n def __init__(self):\n self.x = randint(0, LARGEUR)\n self.y = randint(0, HAUTEUR)\n self.dx = randint(2, 5)\n self.dy = randint(2, 5)\n self.couleur = (randint(0, 255), randint(0, 255), randint(0, 255))\n self.taille = RAYON\n\n def dessine(self):\n pygame.draw.circle(fenetre, self.couleur, (self.x, self.y), self.taille)\n\n def bouge(self):\n self.x += self.dx\n self.y += self.dy\n\n if self.y < self.taille or self.y > HAUTEUR - self.taille:\n self.dy = -self.dy\n if self.x < self.taille or self.x > LARGEUR - self.taille:\n self.dx = -self.dx\n\n for balle in mon_sac_a_balles:\n if (\n (self.x - balle.x) ** 2 + (self.y - balle.y) ** 2\n ) ** 0.5 < self.taille + balle.taille:\n self.dx, balle.dx = balle.dx, self.dx\n self.dy, balle.dy = balle.dy, self.dy\n\n\nmon_sac_a_balles = []\nfor _ in range(NB_BALLES):\n new_ball = Balle()\n mon_sac_a_balles.append(new_ball)\n\n# ces 4 derni\u00e8re lignes peuvent s'\u00e9crire par une seule ligne en compr\u00e9hension :\n# mon_sac_a_balles = [Balle() for _ in range(NB_BALLES)]\n\nwhile True:\n fenetre.fill([0, 0, 0])\n\n for balle in mon_sac_a_balles:\n balle.dessine()\n balle.bouge()\n\n pygame.display.update()\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n\n time.sleep(0.05)\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/","title":"Programmation orient\u00e9e objet","text":"abr\u00e9g\u00e9e par POO en fran\u00e7ais, OOP en anglais (ne pas confondre)
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#0-introduction","title":"0. Introduction","text":"La POO est un paradigme de programmation, au m\u00eame titre que la programmation imp\u00e9rative (que nous pratiquons d\u00e9j\u00e0) ou la programmation fonctionnelle (qui sera \u00e9tudi\u00e9e cette ann\u00e9e en Terminale), ou encore d'autres paradigmes (la liste est longue). Un paradigme de programmation pourrait se d\u00e9finir comme une philosophie dans la mani\u00e8re de programmer : c'est un parti-pris revendiqu\u00e9 dans la mani\u00e8re d'aborder le probl\u00e8me \u00e0 r\u00e9soudre. Une fois cette d\u00e9cision prise, des outils sp\u00e9cifiques au paradigme choisi sont utilis\u00e9s.
M\u00e9taphore
Imaginons 3 menuisiers qui ont pour mission de fabriquer chacun un meuble.
Pour la r\u00e9alisation de sa mission, chaque menuisier utilise un paradigme diff\u00e9rent. Qui utilise la meilleure m\u00e9thode ? Cette question n'a pas vraiment de r\u00e9ponse : certaines m\u00e9thodes sont plus rapides que d'autres, d'autres plus robustes, d'autres plus esth\u00e9tiques... Et pourquoi ne pas m\u00e9langer les paradigmes ? Rien n'interdit d'utiliser des pointes ET des vis dans la fabrication d'un meuble.
La Programmation Orient\u00e9e Objet sera (surtout \u00e0 notre niveau) m\u00e9lang\u00e9e avec de la programmation imp\u00e9rative, de la programmation fonctionnelle... d'ailleurs vous avez d\u00e9j\u00e0 manipul\u00e9 des objets sans le savoir :
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#1-des-objets-deja-autour-de-nous","title":"1. Des objets d\u00e9j\u00e0 autour de nous","text":">>> m = [4,5,2]\n>>> type(m)\nlist\n
m
est une liste, ou plus pr\u00e9cis\u00e9ment un objet de type list
. Et en tant qu'objet de type list
, il est possible de lui appliquer certaines fonctions pr\u00e9d\u00e9finies (qu'on appelera m\u00e9thodes) :
>>> m.reverse()\n
La syntaxe utilis\u00e9e (le . apr\u00e8s le nom de l'objet) est sp\u00e9cifique \u00e0 la POO. Chaque fois que vous voyez cela, c'est que vous \u00eates en train de manipuler des objets. Mais qu'a donc fait cette m\u00e9thode reverse()
?
>>> m\n[2, 5, 4]\n
Nous ne sommes pas surpris par ce r\u00e9sultat car la personne qui a programm\u00e9 la m\u00e9thode reverse()
lui a donn\u00e9 un nom explicite. Comment a-t-elle programm\u00e9 cette inversion des valeurs de la liste ? Nous n'en savons rien et cela ne nous int\u00e9resse pas. Nous sommes juste utilisateurs de cette m\u00e9thode. L'objet de type list
nous a \u00e9t\u00e9 livr\u00e9 avec sa m\u00e9thode reverse()
(et bien d'autres choses) et nous n'avons pas \u00e0 d\u00e9monter la bo\u00eete pour en observer les engrenages : on parle de principe d'encapsulation.
On peut obtenir la liste de toutes les fonctions disponibles pour un objet de type list
, par la fonction dir
:
>>> dir(m)\n['__add__',\n'__class__',\n'__contains__',\n'__delattr__',\n...\n'clear',\n'copy',\n'count',\n'extend',\n'index',\n'insert',\n'pop',\n'remove',\n'reverse',\n'sort']\n
Les m\u00e9thodes encadr\u00e9es par un double underscore __ sont des m\u00e9thodes priv\u00e9es, a priori non destin\u00e9es \u00e0 l'utilisateur. Les m\u00e9thodes publiques, utilisables pour chaque objet de type list
, sont donc append
, clear
, ...
Comment savoir ce que font les m\u00e9thodes ? Si elles ont \u00e9t\u00e9 correctement cod\u00e9es (et elles l'ont \u00e9t\u00e9), elles poss\u00e8dent une docstring, accessible par :
>>> m.append.__doc__\n'Append object to the end of the list.'\n>>> m.reverse.__doc__\n'Reverse *IN PLACE*.'\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#2-creer-son-propre-objet-sa-propre-classe","title":"2. Cr\u00e9er son propre objet sa propre classe","text":""},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#21-vocabulaire-classe-objet-instance-de-classe","title":"2.1 Vocabulaire : classe, objet, instance de classe","text":"Jusqu'ici nous avons employ\u00e9 uniquement le mot \u00abobjet\u00bb. Il convient maintenant d'\u00eatre plus pr\u00e9cis.
attrape_souris()
. Par exemple, l'objet Larry est une instance de la classe chat .
D'apr\u00e8s Wikipedia,
larry.pelage = \"blanc et tabby\"\nlarry.surnom = \"Chief Mouser to the Cabinet Office\"\n
Toujours d'apr\u00e8s Wikipedia, la m\u00e9thode larry.attrape_souris()
est plut\u00f4t efficace.
Cr\u00e9ons une classe \u00abvoiture\u00bb. Il suffit d'\u00e9crire :
class Voiture :\n pass #pass, car pour l'instant il n'y a rien dans la d\u00e9claration de la classe (et c'est mal)\n
La classe Voiture
est cr\u00e9\u00e9e. Notez que par convention, le nom d'une classe commence toujours par une majuscule. Pour cr\u00e9er une instance de cette classe, on \u00e9crit :
>>> titine = Voiture()\n
titine
est un objet, instance de la classe Voiture
.
>>> type(titine)\n__main__.Voiture\n
On peut alors donner des attributs \u00e0 cette instance :
>>> titine.annee = 2018\n>>> titine.couleur = \"verte\"\n>>> titine.vitesse_max = 162\n
Mais arr\u00eatons-l\u00e0 cette mauvaise m\u00e9thode. Si on d\u00e9sire cr\u00e9er une classe \u00abvoiture\u00bb, c'est pour cr\u00e9er un concept g\u00e9n\u00e9rique de voiture et d'en sp\u00e9cifier des caract\u00e9ristiques communes : l'ann\u00e9e, la couleur, la vitesse maximale...
L'id\u00e9e est donc qu'\u00e0 la cr\u00e9ation (on dira plut\u00f4t \u00e0 la construction) de chaque objet voiture, on va lui sp\u00e9cifier directement ses attributs :
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#222-bonne-maniere-la-methode-constructeur","title":"2.2.2 (bonne) mani\u00e8re : la m\u00e9thode constructeur","text":"La m\u00e9thode constructeur, toujours appel\u00e9e __init__()
, est une m\u00e9thode (une \u00abdef\u00bb) qui sera automatiquement appel\u00e9e \u00e0 la cr\u00e9ation de l'objet. Elle va donc le doter de tous les attributs de sa classe.
class Voiture :\n def __init__(self, annee, coul, vmax) :\n self.annee = annee\n self.couleur = coul\n self.vitesse_max = vmax\n self.age = 2023 - self.annee\n
self
, omnipr\u00e9sent en POO (d'autres langages utilisent this
), fait r\u00e9f\u00e9rence \u00e0 l'objet lui-m\u00eame, qui est en train d'\u00eatre construit.annee
, coul
et vmax
. Ils donneront respectivement leur valeur aux attributs annee
, couleur
et vitesse_max
.coul
et vmax
ont \u00e9t\u00e9 utilis\u00e9s pour abr\u00e9ger couleur
et vitesse_max
, mais il est recommand\u00e9 de garder les m\u00eames noms, m\u00eame si ce n'est pas du tout obligatoire.Construisons donc notre premi\u00e8re voiture !
>>> mon_bolide = Voiture(2012, \"rouge\", 190)\n
>>> type(mon_bolide)\n__main__.Voiture\n
mon_bolide
poss\u00e8de 4 attributs :
annee
, couleur
et vitesse_max
ont \u00e9t\u00e9 donn\u00e9s par l'utilisateur lors de la cr\u00e9ation.age
s'est cr\u00e9\u00e9 \u00abtout seul\u00bb par l'instruction self.age = 2021 - self.annee
.>>> mon_bolide.annee\n2012\n>>> mon_bolide.couleur\n'rouge'\n>>> mon_bolide.vitesse_max\n190\n>>> mon_bolide.age\n11\n
Observons les diff\u00e9rentes \u00e9tapes gr\u00e2ce \u00e0 PythonTutor :
Bien s\u00fbr, on peut cr\u00e9er une autre voiture en suivant le m\u00eame principe :
>>> batmobile = Voiture(2036, \"noire\", 325)\n>>> batmobile.couleur\n'noire'\n
Exercice 1
\u00c9nonc\u00e9CorrectionCr\u00e9er une classe Point
permettant de cr\u00e9er un objet A
, dont on r\u00e9cup\u00e8rera l'abscisse par la variable A.x
et l'ordonn\u00e9e par A.y
.
Exemple d'utilisation de la classe
>>> A = Point(3,5)\n>>> A.x\n3\n>>> A.y\n5\n
class Point :\n def __init__(self,x,y):\n self.x = x\n self.y = y\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#224-creer-une-methode-pour-notre-objet","title":"2.2.4 Cr\u00e9er une m\u00e9thode pour notre objet","text":"class Voiture :\n def __init__(self, annee, coul, vmax) :\n self.annee = annee\n self.couleur = coul\n self.vitesse_max = vmax\n self.age = 2023 - self.annee\n\n def petite_annonce(self) :\n print(\"\u00c0 vendre voiture\", self.couleur, \"de\", self.annee,\\\n \", vitesse maximale\", self.vitesse_max, \"km/h.\")\n
Remarque : le symbole \\
est utilis\u00e9 ici pour couper une ligne trop longue.
>>> batmobile = Voiture(2036, \"noire\", 325)\n>>> batmobile.petite_annonce()\n\u00c0 vendre voiture noire de 2036 , vitesse maximale 325 km/h.\n
Nous aurions pu (ou d\u00fb) en profiter pour \u00e9crire une docstring pour notre m\u00e9thode petite_annonce()
:
class Voiture :\n def __init__(self, annee, coul, vmax) :\n self.annee = annee\n self.couleur = coul\n self.vitesse_max = vmax\n self.age = 2023 - self.annee\n\n def petite_annonce(self) :\n\"\"\" R\u00e9dige automatiquement une petite annonce concernant le v\u00e9hicule\"\"\"\n print(\"\u00c0 vendre voiture\", self.couleur, \"de\", self.annee,\\\n \", vitesse maximale\", self.vitesse_max, \"km/h.\")\n
>>> batmobile = Voiture(2036, \"noire\", 325)\n>>> batmobile.petite_annonce.__doc__\n ' R\u00e9dige automatiquement une petite annonce concernant le v\u00e9hicule'\n
Que donne la commande dir
pour notre objet ?
dir(batmobile)\n
['__class__',\n '__delattr__',\n '__dict__',\n '__dir__',\n '__doc__',\n '__eq__',\n '__format__',\n '__ge__',\n '__getattribute__',\n '__gt__',\n '__hash__',\n '__init__',\n '__init_subclass__',\n '__le__',\n '__lt__',\n '__module__',\n '__ne__',\n '__new__',\n '__reduce__',\n '__reduce_ex__',\n '__repr__',\n '__setattr__',\n '__sizeof__',\n '__str__',\n '__subclasshook__',\n '__weakref__',\n 'age',\n 'annee',\n 'couleur',\n 'petite_annonce',\n 'vitesse_max']\n
On y retrouve donc \u00e0 la fois les 4 attributs et l'unique m\u00e9thode que nous avons cr\u00e9\u00e9s pour notre objet.
Exercice 2
\u00c9nonc\u00e9CorrectionReprendre la classe de l'exercice pr\u00e9c\u00e9dent et rajouter une m\u00e9thode distance()
qui renvoie la distance du point par rapport \u00e0 l'origine du rep\u00e8re (dans un rep\u00e8re orthonorm\u00e9).
Exemple d'utilisation de la classe
>>> A = Point(3,5)\n>>> A.distance()\n5.830951894845301\n
class Point:\n def __init__(self,x,y):\n self.x = x\n self.y = y\n\n def distance(self) :\n return (self.x**2+self.y**2)**0.5\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#3-complements","title":"3. Compl\u00e9ments","text":""},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#31-hors-programme-la-methode-__repr__","title":"3.1 Hors-Programme : la m\u00e9thode __repr__()
","text":"La m\u00e9thode __repr__()
(les doubles underscores traduisent le fait que la m\u00e9thode est priv\u00e9e) peut red\u00e9finir la mani\u00e8re dont l'objet doit s'afficher lors qu'on le passe en param\u00e8tre \u00e0 la fonction print()
, ou simplement lorsqu'on demande sa valeur en console.
Observons comment s'affiche un objet de type Fraction
lorsque rien n'a \u00e9t\u00e9 sp\u00e9cifi\u00e9 sur son affichage.
class Fraction:\n def __init__(self, num, den):\n self.numerateur = num\n self.denominateur = den\n
>>> a = Fraction(3,4)\n>>> print(a)\n <__main__.Fraction object at 0x7f470445c828>\n
C'est un peu d\u00e9cevant. Rajoutons donc une m\u00e9thode __repr__()
.
class Fraction:\n def __init__(self, num, den):\n self.numerateur = num\n self.denominateur = den\n\n def __repr__(self):\n return str(self.numerateur) + \"/\" + str(self.denominateur)\n
>>> a = Fraction(3,4)\n>>> print(a)\n 3/4\n>>> a\n 3/4\n
Ce qui est nettement plus agr\u00e9able ! Exercice 3
\u00c9nonc\u00e9CorrectionModifier la m\u00e9thode __repr__
afin de n'afficher que le num\u00e9rateur dans le cas o\u00f9 le d\u00e9nominateur vaut 1.
class Fraction:\n def __init__(self, num, den):\n self.numerateur = num\n self.denominateur = den\n\n def __repr__(self):\n if self.denominateur == 1:\n return str(self.numerateur)\n return str(self.numerateur) + \"/\" + str(self.denominateur)\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#32-lencapsulation-poussee-a-bout-les-getters-et-les-setters","title":"3.2 L'encapsulation pouss\u00e9e \u00e0 bout : les getters
et les setters
","text":"Imaginons la classe suivante :
class Joueur :\n def __init__(self, nom, club, age):\n self.nom = nom\n self.club = club\n self.age = age\n
Instancions le joueur Nans Ducuing
>>> nducuing = Joueur(\"Nans DUCUING\", \"UBB\", 31)\n
notre cobaye
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#321-les-setters","title":"3.2.1 Lessetters
","text":"Supposons maintenant que ce joueur change de club, pour aller de l'UBB \u00e0 Perpignan.
Il serait naturel de faire ceci :
>>> nducuing.club = \"Perpignan\"\n
Cela marche bien, mais... C'est contraire \u00e0 l'esprit de la Programmation Orient\u00e9e Objet. Ce paradigme milite pour une encapsulation des objets, qui interdisent le plus possible l'acc\u00e8s direct \u00e0 leurs attributs.
Comment faire alors ? En proposant une m\u00e9thode dont l'unique travail est d'aller effectuer une modification sur l'attribut :
class Joueur :\n def __init__(self, nom, club, age):\n self.nom = nom\n self.club = club\n self.age = age\n\n def mutation(self, nouveau_club):\n self.club = nouveau_club\n
Le changement de club se fera maintenant par l'appel :
>>> nducuing.mutation(\"Perpignan\")\n
Ce type de m\u00e9thode s'appelle un setter
.
getters
","text":"Nous avons vu qu'aller modifier directement un attribut \u00e9tait d\u00e9fendu... mais peut-on simplement aller le consulter ?
L\u00e0 encore, le concept d'encapsulation -pouss\u00e9 \u00e0 l'extr\u00eame- peut nous l'interdire.
Mais si nducuing.club
est interdit, comment savoir dans quel club joue notre joueur pr\u00e9f\u00e9r\u00e9 ?
Une fois de plus, en construisant une m\u00e9thode qui va nous renvoyer l'\u00e9tat actuel de son attribut club
:
class Joueur :\n def __init__(self, nom, club, age):\n self.nom = nom\n self.club = club\n self.age = age\n\n def mutation(self, nouveau_club):\n self.club = nouveau_club\n\n def get_club(self):\n return self.club\n
L'acc\u00e8s \u00e0 l'attribut club
de notre instance se fera donc maintenant par :
>>> nducuing.get_club()\n
Ce type de m\u00e9thode s'appelle un getter
.
Exercice 1
\u00c9nonc\u00e9CorrectionEleve
qui contiendra les attributs nom
, classe
et note
.compare(eleve1, eleve2)
qui renvoie le nom de l'\u00e9l\u00e8ve ayant la meilleure note (on ne traitera pas \u00e0 part le cas d'\u00e9galit\u00e9).Exemple d'utilisation de la classe
>>> riri = Eleve(\"Henri\", \"TG2\", 12)\n>>> fifi = Eleve(\"Philippe\", \"TG6\", 15)\n>>> loulou = Eleve(\"Louis\", \"TG1\", 8)\n>>> compare(riri, fifi)\n'Philippe'\n
class Eleve:\n def __init__(self, nom, classe, note):\n self.nom = nom\n self.classe = classe\n self.note = note\n\ndef compare(eleve1, eleve2):\n if eleve1.note > eleve2.note:\n return eleve1.nom\n else:\n return eleve2.nom\n
Exercice 2
\u00c9nonc\u00e9Correction\u00c9crire une classe TriangleRect
qui contiendra les attributs cote1
, cote2
et hypotenuse
.
La m\u00e9thode constructeur ne prendra en param\u00e8tres que cote1
et cote2
, l'attribut hypotenuse
se calculera automatiquement.
Exemple d'utilisation de la classe
>>> mon_triangle = TriangleRect(3,4)\n>>> mon_triangle.cote1\n3\n>>> mon_triangle.cote2\n4\n>>> mon_triangle.hypotenuse\n5.0\n
class TriangleRect:\n def __init__(self, c1, c2):\n self.cote1 = c1\n self.cote2 = c2\n self.hypotenuse = (self.cote1**2 + self.cote2**2)**0.5\n
Exercice 3
\u00c9nonc\u00e9CorrectionChrono
qui contiendra les attributs heures
, minutes
et secondes
.affiche()
qui fera affichera le temps t
.avance(s)
qui fera avancer le temps t
de s
secondes.Exemple d'utilisation de la classe
>>> t = Chrono(17,25,38)\n>>> t.heures\n17\n>>> t.minutes\n25\n>>> t.secondes\n38\n>>> t.affiche()\n'Il est 17 heures, 25 minutes et 38 secondes'\n>>> t.avance(27)\n>>> t.affiche()\n'Il est 17 heures, 26 minutes et 5 secondes'\n
Aide On pourra utiliser les op\u00e9rateurs :
%
, qui calcule le reste d'une division euclidienne.//
, qui calcule le quotient d'une division euclidienne.class Chrono:\n def __init__(self, h, m, s):\n self.heures = h\n self.minutes = m\n self.secondes = s\n\n def affiche(self):\n print(\"Il est {} heures, {} minutes \\\n et {} secondes\".format(self.heures, self.minutes, self.secondes))\n\n def avance(self, s):\n self.secondes += s\n\n # il faut ajouter les minutes suppl\u00e9mentaires si les secondes\n # d\u00e9passent 60\n self.minutes += self.secondes // 60\n\n # il ne faut garder des secondes que ce qui n'a pas servi\n # \u00e0 fabriquer des minutes suppl\u00e9mentaires\n self.secondes = self.secondes % 60\n\n # il faut ajouter les heures suppl\u00e9mentaires si les minutes\n # d\u00e9passent 60\n self.heures += self.minutes // 60\n\n # il ne faut garder des minutes que ce qui n'a pas servi\n # \u00e0 fabriquer des heures suppl\u00e9mentaires\n self.minutes = self.minutes % 60\n
Exercice 4
\u00c9nonc\u00e9Correction\u00c9crire une classe Player
qui :
energie
valant 3 par d\u00e9faut. alive
valant True
par d\u00e9faut.blessure()
qui diminue l'attribut energie
de 1.soin()
qui augmente l'attribut energie
de 1.energie
passe \u00e0 0, l'attribut alive
doit passer \u00e0 False
et ne doit plus pouvoir \u00e9voluer.Exemple d'utilisation de la classe
>>> mario = Player()\n>>> mario.energie\n3\n>>> mario.soin()\n>>> mario.energie\n4\n>>> mario.blessure()\n>>> mario.blessure()\n>>> mario.blessure()\n>>> mario.alive\nTrue\n>>> mario.blessure()\n>>> mario.alive\nFalse\n>>> mario.soin()\n>>> mario.alive\nFalse\n>>> mario.energie\n0\n
class Player:\n def __init__(self):\n self.energie = 3\n self.alive = True\n\n def blessure(self):\n self.energie -= 1\n if self.energie == 0:\n self.alive = False\n\n def soin(self):\n if self.energie > 0:\n self.energie += 1\n
\u00c0 faire sur Capytale : activit\u00e9 2ef0-54279
Exercice 5
\u00c9nonc\u00e9CorrectionCr\u00e9er une classe CompteBancaire
dont la m\u00e9thode constructeur recevra en param\u00e8tres :
titulaire
stockant le nom du propri\u00e9taire.solde
contenant le solde disponible sur le compte. Cette classe contiendra deux m\u00e9thodes retrait()
et depot()
qui permettront de retirer ou de d\u00e9poser de l'argent sur le compte.
Exemple d'utilisation de la classe
>>> compteGL = CompteBancaire(\"G.Lassus\", 1000)\n>>> compteGL.retrait(50)\nVous avez retir\u00e9 50 euros\nSolde actuel du compte : 950 euros\n>>> compteGL.retrait(40000)\nRetrait impossible\n>>> compteGL.depot(10000000)\nVous avez d\u00e9pos\u00e9 10000000 euros\nSolde actuel du compte : 10000950 euros\n
class CompteBancaire:\n def __init__(self, titulaire, solde):\n self.titulaire = titulaire\n self.solde = solde\n\n def retrait(self, somme):\n if somme > self.solde:\n print(\"Retrait impossible\")\n else :\n self.solde -= somme\n print(\"Vous avez retir\u00e9 {} euros\".format(somme))\n print(\"Solde actuel du compte : {} euros\".format(self.solde))\n\n def depot(self, somme):\n self.solde += somme\n print(\"Vous avez d\u00e9pos\u00e9 {} euros\".format(somme))\n print(\"Solde actuel du compte : {} euros\".format(self.solde))\n
Exercice 6
Exercice 32.2 de la BNS 2023.
Exercice 7
Exercice 2 Partie A du sujet M\u00e9tropole Septembre 2022
Correction Q1.aLa liste v
contient 5 \u00e9l\u00e9ments.
v[1].nom()
renvoie Les go\u00e9lands
.
la classe Villa
poss\u00e8de un attribut nom
ET une m\u00e9thode nom()
. Ceci est affreux et provoquerait une erreur lors de l'appel \u00e0 la m\u00e9thode nom()
.
def surface(self):\n return self.sejour.sup + self.ch1.sup + self.ch2.sup\n
Correction Q2 for villa in v:\n if villa.eqCuis == \"eq\":\n print(villa.nom)\n
ou bien
for villa in v:\n if villa.equip() == \"eq\":\n print(villa.nom)\n
Exercice 8
Exercice 5 du sujet M\u00e9tropole J1 2022
Correction Q1Instruction 3 : joueur1 = Joueur(\"Sniper\", 319, \"A\")
def redevenir_actif(self):\n if self.est_actif == False:\n self.est_actif = True\n
ou mieux : def redevenir_actif(self):\n if not self.est_actif:\n self.est_actif = True\n
Correction Q2.b def nb_tirs_recus(self):\n return len(self.liste_id_tirs_recus)\n
Correction Q3.a Le test est le test 1.
Correction Q3.bSi un joueur a \u00e9t\u00e9 touch\u00e9 par un tir alli\u00e9, son score diminue de 20 points.
Correction Q4if participant.est_determine() == True:\n self.incremente_score(40)\n
ou mieux : if participant.est_determine():\n self.incremente_score(40)\n
Exercice 9
Exercice 2 du sujet La R\u00e9union J1 2022
Correction Q1.ai = 0\nwhile i < len(Mousse) and Mousse[i] != None:\n i += 1\nreturn i\n
Correction Q1.b def placeBulle(B):\n i = donnePremierIndiceLibre(Mousse)\n if i != 6:\n Mousse[i] = B \n
Correction Q2 def bullesEnContact(B1,B2):\n return distanceEntreBulles(B1, B2) <= B1.rayon + B2.rayon\n
Correction Q3 def collision(indPetite, indGrosse, Mousse) :\n\"\"\"\n Absorption de la plus petite bulle d\u2019indice indPetite\n par la plus grosse bulle d\u2019indice indGrosse. Aucun test\n n\u2019est r\u00e9alis\u00e9 sur les positions.\n \"\"\"\n # calcul du nouveau rayon de la grosse bulle\n surfPetite = pi * Mousse[indPetite].rayon**2\n surfGrosse = pi * Mousse[indGrosse].rayon**2\nsurfGrosseApresCollision = surfPetite + surfGrosse = pi\nrayonGrosseApresCollision = sqrt(surfGrosseApresCollision/pi)\n\n #r\u00e9duction de 50% de la vitesse de la grosse bulle\nMousse[indGrosse].dirx = 0.5 * Mousse[indGrosse].dirx\nMousse[indGrosse].diry = 0.5 * Mousse [indGrosse].diry\n#suppression de la petite bulle dans Mousse\nMousse[indPetite] = None\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite/","title":"Exercices","text":"Exercice 1
\u00c9nonc\u00e9Correction\u00c9crire une fonction r\u00e9cursive puissance(x, n)
qui calcule le nombre \\(x^n\\).
def puissance(x, n):\n if n == 0:\n return 1\n else:\n return x * puissance(x, n-1)\n
Exercice 2
\u00c9nonc\u00e9CorrectionOn rappelle que le PGCD (plus grand diviseur commun de deux nombres) v\u00e9rifie la propri\u00e9t\u00e9 suivante : si la division euclidienne de \\(a\\) par \\(b\\) s'\u00e9crit \\(a = b \\times q + r\\), alors \\(pgcd(a,b)=pgcd(b,r)\\).
Cette propri\u00e9t\u00e9 est \u00e0 la base de l'algorithme d'Euclide
Exemple : \\(pgcd(24,18)=pgcd(18,6)=pgcd(6,0)\\), donc \\(pgcd(24,18)=6\\)
\u00c9crire un algorithme r\u00e9cursif pgcd(a,b)
.
def pgcd(a, b):\n if a%b == 0:\n return b\n else:\n return pgcd(b, a%b)\n
Exercice 3
\u00c9nonc\u00e9CorrectionLa conjecture de Syracuse (ou de Collatz) postule ceci :
Prenons un nombre \\(n\\) : si \\(n\\) est pair, on le divise par 2, sinon on le multiplie par 3 puis on ajoute 1. On recommence cette op\u00e9ration tant que possible. Au bout d'un certain temps, on finira toujours par tomber sur le nombre 1.
syracuse(n)
\u00e9crivant tous les termes de la suite de Syracuse, s'arr\u00eatant (on l'esp\u00e8re) \u00e0 la valeur 1.n
.1.
def syracuse(n):\n print(n)\n if n == 1:\n return None\n if n % 2 == 0:\n return syracuse(n // 2)\n else:\n return syracuse(3*n + 1)\n
Remarque : comme notre fonction syracuse
ne renvoie pas de valeur num\u00e9rique (elle ne fait qu'afficher une valeur), le return
du test de parit\u00e9 est en fait inutile.
Mais le return
du cas de base est lui primordial pour que le code s'arr\u00eate !
def syracuse(n):\n print(n)\n if n == 1:\n return None\n if n % 2 == 0:\n syracuse(n // 2)\n else:\n syracuse(3*n + 1)\n
2. def syracuse(n, t=0):\n print(n)\n t += 1\n if n == 1:\n print('temps de vol :', t)\n return None\n if n % 2 == 0:\n syracuse(n // 2, t)\n else:\n syracuse(3*n + 1, t)\n
Exercice 4
\u00c9nonc\u00e9CorrectionReproduire le dessin suivant, \u00e0 l'aide du module turtle
.
turtle
est un hommage au langage LOGO invent\u00e9 par Seymour Papert au MIT \u00e0 la fin des ann\u00e9es 60.
from turtle import *\ndef carre(c):\n for k in range(4):\n forward(c)\n right(90)\n\ndef base(c):\n carre(c)\n forward(c/2)\n right(45)\n\ndef trace(c, n):\n if n == 0 :\n return None\n else :\n base(c)\n c = c/(2**0.5)\n trace(c, n-1)\n\ntrace(200, 5)\n
Exercice 5
\u00c9nonc\u00e9CorrectionProposer une nouvelle fonction r\u00e9cursive puissance_mod(x, n)
qui calcule le nombre \\(x^n\\). Pour optimiser la fonction d\u00e9j\u00e0 construite \u00e0 l'exercice 1, utiliser le fait que :
def puissance_mod(x, n):\n if n == 0 :\n return 1\n else :\n if n % 2 == 0:\n return puissance_mod(x*x, n//2)\n else :\n return x * puissance_mod(x*x, (n-1)//2)\n
Exercice 6
\u00c9nonc\u00e9Correction\u00c9crire un algorithme r\u00e9cursif recherche(lst, val)
qui recherche la pr\u00e9sence de la valeur val
dans une liste tri\u00e9e (par ordre croissant) lst
.
Cette fonction doit renvoyer un bool\u00e9en.
Exemple d'utilisation :
>>> lst = [2,4,5,5,7,9,11,15,16,18,19]\n>>> recherche(lst, 16)\n[2, 4, 5, 5, 7, 9, 11, 15, 16, 18, 19]\n[9, 11, 15, 16, 18, 19]\n[16, 18, 19]\n[16]\nTrue\n>>> recherche(lst, 6)\n[2, 4, 5, 5, 7, 9, 11, 15, 16, 18, 19]\n[2, 4, 5, 5, 7]\n[5, 5, 7]\n[5, 7]\n[5]\nFalse\n
Aide :
Les techniques de slicing (hors-programme) permettent de couper une liste en deux :
>>> lst = [10, 12, 15, 17, 18, 20, 22]\n>>> lst[:3]\n[10, 12, 15]\n>>> lst[3:]\n[17, 18, 20, 22]\n
def recherche(lst, val):\n print(lst) # pour voir la taille de la liste diminuer\n if len(lst) == 1: #cas de base\n if lst[0] == val:\n return True\n else:\n return False\n else : #cas r\u00e9cursif\n ind_milieu = len(lst)//2\n if lst[ind_milieu] > val:\n return recherche(lst[:ind_milieu], val)\n else:\n return recherche(lst[ind_milieu:], val)\n
Exercice 7
\u00c9nonc\u00e9CorrectionOn consid\u00e8re le jeu des Tours de Hano\u00ef. Le but est de faire passer toutes les assiettes de A vers C, sachant qu'une assiette ne peut \u00eatre d\u00e9pos\u00e9e que sur une assiette de diam\u00e8tre inf\u00e9rieur.
Une version jouable en ligne peut \u00eatre trouv\u00e9e ici.
\u00c9crire une fonction r\u00e9cursive hanoi(n, depart, inter, arrivee)
qui donnera la suite d'instructions (sous la forme \" A vers C\") pour faire passer une pile de taille n de depart
vers arrivee
en prenant inter
comme interm\u00e9diaire.
def hanoi(n, depart, inter, arrivee):\n\"\"\" n : nombre d'assiettes dans la pile\n # depart : la pile de d\u00e9part(\"A\", \"B\" ou \"C\")\n # inter : la pile interm\u00e9daire(\"A\", \"B\" ou \"C\")\n # arrivee : la pile d'arriv\u00e9e (\"A\", \"B\" ou \"C\") \"\"\"\n\n if n == 1 :\n print(depart + \" vers \" + arrivee)\n else :\n hanoi(n-1, depart, arrivee, inter) \n print(depart + \" vers \" + arrivee)\n hanoi(n-1, inter, depart, arrivee)\n\nhanoi(5, \"A\", \"B\", \"C\")\n
Exercice 8
\u00c9nonc\u00e9CorrectionCet exercice a pour objectif le trac\u00e9 du flocon de Von Koch.
L'id\u00e9e est de r\u00e9p\u00e9ter de mani\u00e8re r\u00e9cursive la transformation ci-dessous : chaque segment de longueur l
donne naissance \u00e0 4 segments de longueur l/3
, en construisant une pointe de triangle \u00e9quilat\u00e9ral sur le deuxi\u00e8me tiers du segment.
1) Cr\u00e9er une fonction r\u00e9cursive floc(n, l)
qui trace \u00e0 une \u00abprofondeur\u00bb n
un segment de longueur l
. Indications
n
vaut 0.n
fait 4 appels successifs \u00e0 l'\u00e9tape n-1
.2) Cr\u00e9er une fonction triangle(n, l)
qui trace le flocon complet.
from turtle import *\n\ndef floc(n, l):\n if n == 0:\n forward(l)\n else:\n floc(n-1,l/3)\n left(60)\n floc(n-1,l/3)\n right(120)\n floc(n-1,l/3)\n left(60)\n floc(n-1,l/3)\n\n\nspeed(0)\n\ndef triangle(n,l):\n for _ in range(3):\n floc(n,l)\n right(120)\n\ntriangle(5,400)\n
Exercice 9
\u00c9nonc\u00e9CorrectionExercice 10
Exercice 4 du sujet Am\u00e9rique du Nord J1
correction Q1.a.Proposition 3
correction Q1.b.txt[0]
vaut 'b' txt[taille-1]
vaut 'r' interieur
vaut 'onjou'
def test_palindrome():\n assert palindrome(\"kayak\") == True\n assert palindrome(\"canoe\") == False \n
On teste les deux cas possibles. correction Q3. def palindrome_imperatif(txt):\n if len(txt) < 2:\n return True\n i = 0\n j = len(txt)-1\n while i<j:\n if txt[i] != txt[j]:\n return False\n i += 1\n j -= 1\n return True\n
correction Q4.a. def complementaire(txt):\n comp = {\"A\":\"T\", \"T\":\"A\", \"G\":\"C\", \"C\":\"G\"}\n sol = \"\"\n for c in txt:\n sol += comp[c]\n return sol\n
correction Q4.b \"GATCGTCTAGCA\" n'est pas un palindrome donc \"GATCGT\" n'est pas palindromique.
correction Q4.cdef est_palindromique(txt):\n txt_total = txt + complementaire(txt)\n return palindrome(txt_total)\n
Exercice 11
Exercice 1 du sujet Centres \u00c9trangers J2 2022
correction Q1.a.f(5)
affichera : `5 4 3 2 1 Partez!
On dit que cette fonction est r\u00e9cursive car elle s'appelle elle-m\u00eame \u00e0 l'int\u00e9rieur de sa propre d\u00e9finition.
Correction Q2.a.def ajouter(s, liste):\n res = []\n for m in liste:\n res.append(s + m)\n return res\n
Correction Q2.b. La commande renvoie :
['ba', 'bb', 'bc']\n
Correction Q2.c. La commande renvoie :
['a']\n
Correction Q3.a. Comme n
vaut 0, on est dans le cas de base et donc la commande renvoie [\"\"]
.
[\"\"]
n'est pas une liste vide, car elle contient un \u00e9l\u00e9ment (une chaine de caract\u00e8res vide). La liste vide est []
.
produit(\"ab\", 1)
renvoie ['a', 'b']
.
produit(\"ab\", 2)
renvoie ['aa', 'ab', 'ba', 'bb']
.
\u00c9crire une fonction r\u00e9cursive puissance(x,n)
qui calcule le nombre \\(x^n\\).
def puissance(x,n):\n if n == 0 :\n return 1\n else :\n return x*puissance(x,n-1)\n
puissance(2,10)\n
1024\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite_corr/#exercice-2","title":"Exercice 2","text":"\u00c9crire une fonction r\u00e9cursive boucle(i,k)
qui affiche les entiers entre i
et k
. Par exemple, boucle(2,5)
doit afficher 2 3 4 5
def boucle(i,k):\n if i == k :\n print(i)\n else :\n print(i)\n boucle(i+1,k)\n
boucle(2,5)\n
2\n3\n4\n5\n
\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite_corr/#exercice-3","title":"Exercice 3","text":"On rappelle que le PGCD (plus grand diviseur commun de deux nombres) v\u00e9rifie la propri\u00e9t\u00e9 suivante : si la division euclidienne de \\(a\\) par \\(b\\) s'\u00e9crit \\(a = b \\times q + r\\), alors \\(pgcd(a,b)=pgcd(b,r)\\).
Cette propri\u00e9t\u00e9 est \u00e0 la base de l'algorithme d'Euclide
Exemple : \\(pgcd(24,18)=pgcd(18,6)=pgcd(6,0)\\), donc \\(pgcd(24,18)=6\\)
\u00c9crire un algorithme r\u00e9cursif pgcd(a,b)
.
def pgcd(a,b):\n if b == 0 :\n return a\n else :\n return pgcd(b,a%b)\n\ndef pgcd2(a,b):\n return a if b == 0 else pgcd2(b,a%b)\n\n\nprint(pgcd(18,12))\nprint(pgcd2(18,12))\n
6\n6\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite_corr/#exercice-4","title":"Exercice 4","text":"La conjecture de Syracuse (ou de Collatz) postule ceci :
Prenons un nombre \\(n\\) : si \\(n\\) est pair, on le divise par 2, sinon on le multiplie par 3 puis on ajoute 1. On recommence cette op\u00e9ration tant que possible. Au bout d'un certain temps, on finira toujours par tomber sur le nombre 1.
Proposer un programme r\u00e9cursif syracuse(n)
\u00e9crivant tous les termes de la suite de Syracuse, s'arr\u00eatant (on l'esp\u00e8re) \u00e0 la valeur 1.
def syracuse(n):\n print(n)\n if n == 1 :\n return None\n else :\n if n % 2 == 0 :\n return syracuse(n//2)\n else :\n return syracuse(3*n+1)\n
syracuse(14)\n
14\n7\n22\n11\n34\n17\n52\n26\n13\n40\n20\n10\n5\n16\n8\n4\n2\n1\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite_corr/#exercice-5","title":"Exercice 5","text":"Reproduire le dessin suivant, \u00e0 l'aide du module turtle
.
turtle
est un hommage au langage LOGO invent\u00e9 par Seymour Papert au MIT \u00e0 la fin des ann\u00e9es 60.
from turtle import *\n\n\ndef carre(c):\n for k in range(4):\n forward(c)\n right(90)\n\ndef base(c):\n carre(c)\n forward(c/2)\n right(45)\n\ndef trace(c):\n if c < 5 :\n return None\n else :\n base(c)\n return trace(c/(2**0.5))\n\ntrace(200)\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite_corr/#exercice-6","title":"Exercice 6","text":"Proposer une nouvelle fonction r\u00e9cursive puissance(x,n)
qui calcule le nombre \\(x^n\\). Pour optimiser la fonction d\u00e9j\u00e0 construite \u00e0 l'exercice 1, utiliser le fait que : - si \\(n\\) est pair, \\(a^n=(a \\times a)^{n/2}\\) - sinon \\(a^n=a \\times (a \\times a)^{(n-1)/2}\\)
def puissance(x,n):\n if n == 0 :\n return 1\n else :\n if n % 2 == 0:\n return puissance(x*x,n//2)\n else :\n return x*puissance(x*x,(n-1)//2)\n
puissance(10,3)\n
1000\n
puissance(10,6)\n
1000000\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite_corr/#exercice-7","title":"Exercice 7","text":"\u00c9crire un algorithme r\u00e9cursif recherche(lst,m)
qui recherche la pr\u00e9sence de la valeur m
dans une liste tri\u00e9e lst
. Cette fonction doit renvoyer un bool\u00e9en.
lst=[5,6,9,12,17]\n
lst[:3]\n
[5, 6, 9]\n
lst[3:]\n
[12, 17]\n
def recherche(lst,m):\n print(lst) # pour voir la taille de la liste diminuer\n if len(lst) == 1 : #cas de base\n if lst[0] == m :\n return True\n else :\n return False\n else : #cas r\u00e9cursif\n mid = len(lst)//2\n if lst[mid] > m :\n return recherche(lst[:mid],m)\n else :\n return recherche(lst[mid:],m)\nlst=[5,6,9,12,17]\n\nrecherche(lst,18)\n
[5, 6, 9, 12, 17]\n[9, 12, 17]\n[12, 17]\n[17]\n\n\n\n\n\nFalse\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite_corr/#exercice-8","title":"Exercice 8","text":"On consid\u00e8re le jeu des Tours de Hano\u00ef. Le but est de faire passer toutes les assiettes de A vers C, sachant qu'une assiette ne peut \u00eatre d\u00e9pos\u00e9e que sur une assiette de diam\u00e8tre inf\u00e9rieur.
Une version jouable en ligne peut \u00eatre trouv\u00e9e ici.
\u00c9crire une fonction r\u00e9cursive hanoi(n, A, B, C)
qui donnera la suite d'instructions (sous la forme \" A vers C\") pour faire passer une pile de taille n de A vers C en prenant B comme interm\u00e9diaire.
def hanoi(n,A,B,C):\n\"\"\" n : nombre d'assiettes dans la pile\n # A : la pile de d\u00e9part(\"A\", \"B\" ou \"C\")\n # B : la pile interm\u00e9daire(\"A\", \"B\" ou \"C\")\n # C : la pile d'arriv\u00e9e (\"A\", \"B\" ou \"C\") \"\"\"\n\n if n == 1 :\n print(A + \" vers \" + C)\n else :\n hanoi(n-1,A,C,B) #de A vers B en passant par C\n print(A + \" vers \" + C)\n hanoi(n-1,B,A,C)\n\nhanoi(5,\"Tower1\",\"Tower2\",\"Tower3\")\n
Tower1 vers Tower3\nTower1 vers Tower2\nTower3 vers Tower2\nTower1 vers Tower3\nTower2 vers Tower1\nTower2 vers Tower3\nTower1 vers Tower3\nTower1 vers Tower2\nTower3 vers Tower2\nTower3 vers Tower1\nTower2 vers Tower1\nTower3 vers Tower2\nTower1 vers Tower3\nTower1 vers Tower2\nTower3 vers Tower2\nTower1 vers Tower3\nTower2 vers Tower1\nTower2 vers Tower3\nTower1 vers Tower3\nTower2 vers Tower1\nTower3 vers Tower2\nTower3 vers Tower1\nTower2 vers Tower1\nTower2 vers Tower3\nTower1 vers Tower3\nTower1 vers Tower2\nTower3 vers Tower2\nTower1 vers Tower3\nTower2 vers Tower1\nTower2 vers Tower3\nTower1 vers Tower3\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite_corr/#exercice-9","title":"Exercice 9","text":"Cet exercice a pour objectif le trac\u00e9 du flocon de Von Koch.
L'id\u00e9e est de r\u00e9p\u00e9ter de mani\u00e8re r\u00e9cursive la transformation ci-dessous : chaque segment de longueur l
donne naissance \u00e0 4 segments de longueur l/3
, en construisant une pointe de triangle \u00e9quilat\u00e9ral sur le deuxi\u00e8me tiers du segment.
1) Cr\u00e9er une fonction r\u00e9cursive floc(n,l)
qui trace \u00e0 une \u00abprofondeur\u00bb n
un segment de longueur l
.
Indications - l'instruction de trac\u00e9 n'a lieu que quand n
vaut 0. - l'\u00e9tape n
fait 4 appels sucessifs \u00e0 l'\u00e9tape n-1
.
2) Cr\u00e9er une fonction triangle(n,l)
qui trace le flocon complet.
from turtle import *\n\ndef floc(n,l):\n if n == 0 :\n forward(l)\n else :\n floc(n-1,l/3)\n left(60)\n floc(n-1,l/3)\n right(120)\n floc(n-1,l/3)\n left(60)\n floc(n-1,l/3)\n\ndef triangle(n,l):\n for _ in range(3):\n floc(n,l)\n right(120)\n\nspeed(0)\ntriangle(4,150)\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite_corr/#bibliographie","title":"Bibliographie","text":"G.Lassus, Lyc\u00e9e Fran\u00e7ois Mauriac -- Bordeaux
"},{"location":"T2_Programmation/2.2_Recursivite/cours/","title":"R\u00e9cursivit\u00e9","text":""},{"location":"T2_Programmation/2.2_Recursivite/cours/#1-premiere-approche","title":"1. Premi\u00e8re approche","text":""},{"location":"T2_Programmation/2.2_Recursivite/cours/#11-definition","title":"1.1. D\u00e9finition","text":"Fonction r\u00e9cursive
Une fonction est dite r\u00e9cursive lorsqu'elle fait appel \u00e0 elle-m\u00eame dans sa propre d\u00e9finition.
"},{"location":"T2_Programmation/2.2_Recursivite/cours/#12-un-tres-mauvais-exemple","title":"1.2 Un tr\u00e8s mauvais exemple","text":"C'est d\u00e9j\u00e0 une premi\u00e8re chose \u00e0 comprendre : un programme peut \u00eatre appel\u00e9 par lui-m\u00eame, \u00e0 l'int\u00e9rieur de sa propre d\u00e9finition.
def prems():\n print(\"un tr\u00e8s mauvais exemple\")\n prems()\n
Si on appelle cette fonction, par la commande :
>>> prems()\n
La sortie en console sera celle-ci : un tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\n...\n
\u00c9videmment, comme pr\u00e9vu, ce programme ne s'arr\u00eate pas. Nous sommes oblig\u00e9s de l'arr\u00eater manuellement. Nous sommes (volontairement) tomb\u00e9s dans un pi\u00e8ge qui sera syst\u00e9matiquement pr\u00e9sent lors d'une programmation r\u00e9cursive : le pi\u00e8ge de la boucle infinie.
"},{"location":"T2_Programmation/2.2_Recursivite/cours/#13-la-mauvaise-reputation","title":"1.3 La mauvaise r\u00e9putation","text":"Dans la culture informatique, la r\u00e9cursivit\u00e9 est (trop) souvent abord\u00e9e par le biais de l'auto-r\u00e9f\u00e9rence, le puits sans fin de la boucle infinie.
On trouve d'ailleurs fr\u00e9quemment cette d\u00e9finition de la r\u00e9cursivit\u00e9 :
Fonction r\u00e9cursive : fonction qui fait appel \u00e0 la r\u00e9cursivit\u00e9. Voir fonction r\u00e9cursive.
Google fait aussi (dans toutes les langues) la m\u00eame blague lors d'une recherche sur le terme \u00abr\u00e9cursivit\u00e9\u00bb :
Les acronymes r\u00e9cursifs sont aussi tr\u00e8s fr\u00e9quents... et v\u00e9hiculent avec eux le m\u00eame pi\u00e8ge : une fonction r\u00e9cursive ne serait jamais vraiment d\u00e9finie (c'est faux, nous le verrons)
Par exemple :
Disons-le clairement : au-del\u00e0 de la blague pour initi\u00e9s (dont vous faites partie maintenant) la r\u00e9cursivit\u00e9 ne DOIT PAS \u00eatre associ\u00e9e \u00e0 une auto-r\u00e9f\u00e9rence vertigineuse : c'est en algorithmique une m\u00e9thode (parfois) tr\u00e8s efficace, \u00e0 condition de respecter une r\u00e8gle cruciale : l'existence d'un CAS DE BASE .
Ce \u00abcas de base\u00bb sera aussi appel\u00e9 \u00abcondition d'arr\u00eat\u00bb, puisque la tr\u00e8s grande majorit\u00e9 des algorithmes r\u00e9cursifs peuvent \u00eatre per\u00e7us comme des escaliers qu'on descend marche par marche, jusqu'au sol qui assure notre arr\u00eat.
"},{"location":"T2_Programmation/2.2_Recursivite/cours/#21-la-recursivite-en-bd","title":"2.1 La r\u00e9cursivit\u00e9 en BD :","text":"Observez bien la descente puis la remont\u00e9e de notre vendeur de livre. Le cas de base est ici l'\u00e9tage 0. Il emp\u00eache une descente infinie.
Nous coderons bient\u00f4t la fonction donnant le prix du livre en fonction de l'\u00e9tage.
Pour l'instant, d\u00e9couvrons enfin \u00e0 quoi ressemble une fonction r\u00e9cursive \u00abbien \u00e9crite\u00bb :
"},{"location":"T2_Programmation/2.2_Recursivite/cours/#22-enfin-un-bon-exemple","title":"2.2 Enfin un bon exemple","text":"Exemple fondateur n\u00b01
def mystere(n):\n if n == 0 :\n return 0\n else : \n return n + mystere(n-1)\n
Trois choses sont essentielles et doivent se retrouver dans tout programme r\u00e9cursif :
lignes 2 et 3
: le cas de base (si n
vaut 0 on renvoie vraiment une valeur, en l'occurence 0)ligne 5
: l'appel r\u00e9cursifligne 5
: la d\u00e9cr\u00e9mentation du param\u00e8tre d'appelUtilisation de la fonction mystere
>>> mystere(0)\n0\n>>> mystere(4)\n10\n
Analyse gr\u00e2ce \u00e0 PythonTutor
Que se passe-t-il lorsqu'on appelle mystere(4)
?
On voit que l'existence du cas de base pour \\(n=0\\) est primordiale pour \u00e9viter la r\u00e9cursion infinie.
Cette fonction mystere(n)
calcule donc la somme des entiers positifs inf\u00e9rieurs ou \u00e9gaux \u00e0 \\(n\\).
mystere(100)
est \u00e9gal \u00e0 5050. Une anecdote raconte que Carl Friedrich Gauss trouva cette valeur de 5050 en quelques secondes, devant son instituteur \u00e9bahi. Il venait pour cela d'inventer la formule : \\(1+2+3+\\dots+n=\\frac{n(n+1)}{2}\\)
Ici, \\(1+2+3+\\dots+100=\\frac{100\\times 101)}{2}=50 \\times 101=5050\\)
Exercice 1
\u00c9nonc\u00e9CorrectionCoder la fonction prix(etage)
de la BD pr\u00e9sent\u00e9e plus haut.
def prix(etage):\n if etage == 0:\n return 3\n else:\n return 2 * prix(etage - 1)\n
Exercice 2
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la fonction factorielle(n)
(not\u00e9e \\(n!\\) en math\u00e9matiques), qui calcule le produit d'un entier \\(n\\) par les entiers positifs qui lui sont inf\u00e9rieurs:
Exemple : \\(5!=5\\times4\\times3\\times2\\times1=120\\)
Par convention, \\(1!=1\\)
fact_imp
. fact_rec
.Quelle paradigme de programmation vous a sembl\u00e9 le plus naturel ?
def fact_imp(n):\n p = 1\n for k in range(1, n + 1):\n p = p * k\n return p\n\ndef fact_rec(n):\n if n == 1:\n return 1\n else:\n return n * fact_rec(n - 1)\n
"},{"location":"T2_Programmation/2.2_Recursivite/cours/#3-le-mecanisme-interne-de-la-recursivite","title":"3. Le m\u00e9canisme interne de la r\u00e9cursivit\u00e9","text":""},{"location":"T2_Programmation/2.2_Recursivite/cours/#31-notion-de-pile","title":"3.1 Notion de pile","text":"Lors d'un appel \u00e0 une fonction r\u00e9cursive, le processeur utilise une structure de pile pour stocker les contextes d'ex\u00e9cution de chaque appel. Dans la notion de pile (voir ici), seule l'instruction \u00aben haut de la pile\u00bb peut \u00eatre trait\u00e9e et enlev\u00e9e (on dit \u00abd\u00e9pil\u00e9e\u00bb).
La pile d'appels de notre fonction mystere(5)
peut donc \u00eatre sch\u00e9matis\u00e9e comme ceci :
"},{"location":"T2_Programmation/2.2_Recursivite/cours/#32-limitation-de-la-taille-de-la-pile","title":"3.2 Limitation de la taille de la pile","text":"
Nous venons de voir que notre appel \u00e0 mystere(5)
g\u00e9n\u00e9rait une pile de hauteur 6 (on parlera plut\u00f4t de profondeur 6). Cette profondeur est-elle limit\u00e9e ?
mystere(2962)\n
---------------------------------------------------------------------------\n\nRecursionError Traceback (most recent call last)\n\n<ipython-input-32-a97c4dde4ef8> in <module>\n----> 1 mystere(2962)\n\n\n<ipython-input-1-386660a434f2> in mystere(n)\n 3 return 0\n 4 else :\n----> 5 return n + mystere(n-1)\n\n\n... last 1 frames repeated, from the frame below ...\n\n\n<ipython-input-1-386660a434f2> in mystere(n)\n 3 return 0\n 4 else :\n----> 5 return n + mystere(n-1)\n\n\nRecursionError: maximum recursion depth exceeded in comparison\n
Vous venons de provoquer un \u00abd\u00e9bordement de pile\u00bb, le c\u00e9l\u00e8bre stack overflow.
De mani\u00e8re g\u00e9n\u00e9rale, les programmes r\u00e9cursifs sont souvent susceptibles de g\u00e9n\u00e9rer un trop grand nombre d'appels \u00e0 eux-m\u00eames. Il est parfois possible de les optimiser, comme nous le verrons dans le cours concernant la programmation dynamique.
Nous reparlerons aussi de r\u00e9cursivit\u00e9 lorsque nous l'inscrirons dans un paradigme plus global de programmation, qui est \u00ab diviser pour r\u00e9gner \u00bb (en anglais divide and conquer).
"},{"location":"T2_Programmation/2.2_Recursivite/cours/#4-exemples-de-recursivite-double","title":"4. Exemples de r\u00e9cursivit\u00e9 double","text":""},{"location":"T2_Programmation/2.2_Recursivite/cours/#41-la-suite-de-fibonacci","title":"4.1 La suite de Fibonacci","text":"Consid\u00e9rons la suite num\u00e9rique ainsi d\u00e9finie :
On a donc \\(F_2=0+1=1, F_3=F_2+F_1=1+1=2, F_4=F_3+F_2=2+1=3, F_5=F_4+F_3=3+2=5\\) ...
Exercice 3
\u00c9nonc\u00e9CorrectionImpl\u00e9menter de fa\u00e7on r\u00e9cursive la suite de Fibonacci.
def fibo(n):\n if n == 0 :\n return 0 \n elif n == 1 :\n return 1\n else :\n return fibo(n-1) + fibo(n-2)\n
Observation de la pile d'ex\u00e9cution
Appelons F(n)
la fonction calculant de mani\u00e8re r\u00e9cursive le n-i\u00e8me terme de la suite. Observons en d\u00e9tail la pile d'ex\u00e9cution lors du calcul de F(4)
.
Analyse gr\u00e2ce \u00e0 PythonTutor
On s'aper\u00e7oit notamment que :
Le module rcviz
permet d'observer l'arbre des appels r\u00e9cursifs : voir cette activit\u00e9 Capytale
On peut y construire par exemple l'arbre d'appel de fibo(6)
:
On y remarque (par exemple) que fibo(2)
est calcul\u00e9 5 fois...
Exercice 4
\u00c9nonc\u00e9Correction\u00c9crire une fonction fibo_imperatif(n)
qui calcule de fa\u00e7on directe (imp\u00e9rative) le n-i\u00e8me terme de la suite de Fibonacci. On pourra par exemple utiliser un dictionnaire.
Construisons une fonction comparaison
qui affichera le temps de calcul pour chacune des deux fonctions fibo_imperatif
et fibo_recursif
:
import time\n\ndef fibo_imperatif(n):\n f = {}\n f[0] = 0\n f[1] = 1\n for k in range(2, n+1):\n f[k] = f[k-1] + f[k-2]\n return f[n]\n\ndef fibo_recursif(n):\n if n == 0 :\n return 0 \n elif n == 1 :\n return 1\n else :\n return fibo_recursif(n-1) + fibo_recursif(n-2)\n\n\ndef comparaison(n):\n t0 = time.time()\n fibo_imperatif(n)\n print(\"algo imp\u00e9ratif : \", time.time() - t0)\n t0 = time.time()\n fibo_recursif(n)\n print(\"algo r\u00e9cursif : \", time.time() - t0)\n
R\u00e9sultats
>>> comparaison(10)\nalgo imp\u00e9ratif : 6.9141387939453125e-06\nalgo r\u00e9cursif : 1.7642974853515625e-05\n>>> comparaison(20)\nalgo imp\u00e9ratif : 7.62939453125e-06\nalgo r\u00e9cursif : 0.0021445751190185547\n>>> comparaison(30)\nalgo imp\u00e9ratif : 1.8596649169921875e-05\nalgo r\u00e9cursif : 0.25478553771972656\n>>> comparaison(40)\nalgo imp\u00e9ratif : 1.1920928955078125e-05\nalgo r\u00e9cursif : 31.332343339920044\n
La fonction r\u00e9cursive apparait donc beaucoup, beaucoup plus lente que l'imp\u00e9rative (ici d'un facteur 100 pour toute augmentation de 10 du param\u00e8tre n
.)
Attention : cette comparaison des vitesses d'\u00e9x\u00e9cution peut \u00eatre critiqu\u00e9e car les deux programmes n'ont pas la m\u00eame complexit\u00e9. Nous \u00e9tudierons la complexit\u00e9 au moment des algorithmes de tri. La complexit\u00e9 des fonctions r\u00e9cursives n'est pas au programme de NSI.
Peut-on r\u00e9sumer la r\u00e9cursivit\u00e9 \u00e0 une m\u00e9thode \u00e9l\u00e9gante mais inefficace ? Ce serait r\u00e9ducteur : l'efficacit\u00e9 c'est aussi avoir un code lisible et intuitif. Nous en reparlerons lors du parcours des arbres et des graphes. (cf aussi l'exercice sur les Tours de Hano\u00ef)
"},{"location":"T2_Programmation/2.2_Recursivite/cours/#5-annexe-dessins-recursifs-grace-au-module-turtle","title":"5. Annexe : dessins r\u00e9cursifs gr\u00e2ce au moduleturtle
","text":"Le module turtle
permet de faire des trac\u00e9s basiques. Mais d\u00e8s l'instant o\u00f9 on met de la r\u00e9cursivit\u00e9 dans le code, les r\u00e9sultats peuvent devenir tr\u00e8s surprenants, et aboutir \u00e0 des structures fractales.
from turtle import *\n\nang = 40\n\ndef trace(n,l):\n if n == 0 :\n return None\n else :\n forward(l)\n left(ang)\n trace(n-1, 0.7*l)\n right(2*ang)\n trace(n-1, 0.7*l)\n left(ang)\n forward(-l)\n\n\npenup() \ngoto(0,-80)\npendown()\nleft(90)\nspeed(0)\n\ntrace(5,100)\n
"},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/","title":"D\u00e9cidabilit\u00e9, calculabilit\u00e9","text":""},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/#1-un-programme-comme-parametre-dun-programme","title":"1. Un programme comme param\u00e8tre d'un programme","text":"
Les codes que nous manipulons ressemblent souvent \u00e0 cela :
def accueil(n):\n for k in range(n):\n print(\"bonjour\")\n
Le programme s'appelle accueil
, et pour fonctionner il a besoin d'un param\u00e8tre, qui sera ici un nombre entier n
.
Voici comment nous pouvons repr\u00e9senter notre machine accueil
, son param\u00e8tre d'entr\u00e9e (5) et sa sortie (les 5 \u00abbonjour\u00bb)
Maintenant, enregistrons le code suivant dans un fichier test.py
:
def accueil(n):\n for k in range(n):\n print(\"bonjour\")\n\naccueil(5)\n
Pour ex\u00e9cuter ce code, nous devons taper dans un terminal l'instruction suivante : python3 test.py
, ce qui donnera
Le programme utilis\u00e9 est alors python3
, qui prend comme param\u00e8tre le programme test.py
. Ce param\u00e8tre test.py
est un ensemble de caract\u00e8res qui contient les instructions que le programme python3
va interpr\u00e9ter.
L'illustration correspondante sera donc :
Mais nous pouvons aller encore plus loin : l'instruction python3 test.py
est tap\u00e9e dans mon Terminal Linux, qui lui-m\u00eame est un programme appel\u00e9 Terminal
.
Et donc :
Conclusion :
Il n'y a donc aucun obstacle \u00e0 consid\u00e9rer un programme comme une simple donn\u00e9e, pouvant \u00eatre re\u00e7ue en param\u00e8tre par un autre programme. (voire par lui-m\u00eame !)
\u00c0 titre anecdotique, on pourra ex\u00e9cuter avec int\u00e9r\u00eat cette instruction Python : a='a=%r;print(a%%a)';print(a%a)
Ce type de code (magique !) existe dans tous les langages et s'appelle un quine.
Consid\u00e9rons le programme suivant :
def countdown(n):\n while n != 0:\n print(n)\n n = n - 1\n print(\"fini\")\n
En l'observant attentivement, je peux pr\u00e9voir que countdown(10)
affichera les nombres de 10 \u00e0 1 avant d'\u00e9crire \"fini\". Puis le programme s'arr\u00eatera.
Mais que va provoquer countdown(10.8)
?
Comme la variable n
ne sera jamais \u00e9gale \u00e0 0, le programme va rentrer dans une boucle infinie, il ne s'arr\u00eatera jamais. Mauvaise nouvelle. J'ai pu pr\u00e9voir ceci en regardant attentivement le code de mon programme. J'ai \u00abremarqu\u00e9\u00bb qu'une variable n
non enti\u00e8re provoquerait une boucle infinie.
Question : Est-ce qu'un programme d'analyse de programmes aurait pu faire cela \u00e0 ma place ?
"},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/#22-une-machine-pour-predire-larret-ou-non-dun-programme","title":"2.2 Une machine pour pr\u00e9dire l'arr\u00eat ou non d'un programme.","text":"Apr\u00e8s tout, un programme est une suite d'instructions (le code-source), et peut donc \u00eatre, comme on l'a vu, le param\u00e8tre d'entr\u00e9e d'un autre programme qui l'analyserait. Un tel programme (appelons-le halt
) prendrait en entr\u00e9es :
prog
(le code-source du programme)x
, qui serait le param\u00e8tre d'entr\u00e9e de prog
.L'instruction halt(prog, x)
renverrait True
si prog(x)
s'arr\u00eate, et False
si prog(x)
ne s'arr\u00eate pas.
Exemple :
halt(countdown, 10)
renverrait True
.halt(countdown, 10.8)
renverrait False
. Tentative d'\u00e9criture de halt
en Python :
def halt(prog, x):\n if \"prog(x) s'arr\u00eate\": # mes excuses, je n'ai pas eu le temps de finir totalement ce code\n return True\n else :\n return False\n
Nous en resterons l\u00e0 pour l'instant dans l'\u00e9criture de ce programme. Nous allons nous en servir pour construire d'autres programmes.
"},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/#23-amusons-nous-avec-ce-programme-halt","title":"2.3 Amusons-nous avec ce programmehalt
.","text":"Consid\u00e9rons le programme :
def sym(prog):\n if halt(prog, prog) == True:\n while True:\n print(\"vers l'infini et au-del\u00e0 !\")\n else:\n return 1\n
On peut remarquer que le programme halt
est appel\u00e9 avec comme param\u00e8tres prog, prog
, ce qui signifie que prog
se prend lui-m\u00eame en param\u00e8tre. On rappelle que ce n'est pas choquant, un code-source \u00e9tant une donn\u00e9e comme une autre.
Ce programme sym
re\u00e7oit donc en param\u00e8tre un programme prog
, et :
prog(prog)
s'arr\u00eate.prog(prog)
ne s'arr\u00eate pas.Puisqu'un programme peut prendre en param\u00e8tre son propre code-source, que donnerait l'appel \u00e0 sym(sym)
?
Deux cas peuvent se pr\u00e9senter, suivant si halt(sym, sym)
renvoie True
ou False
.
cas n\u00b01 : halt(sym, sym)
renvoie True
, ce qui signifie que sym(sym)
devrait s'arr\u00eater. Mais dans ce cas-l\u00e0, l'ex\u00e9cution de sym(sym)
rentre dans une boucle infinie. C'est une contradiction.
cas n\u00b02 : halt(sym, sym)
renvoie False
, ce qui signifie que sym(sym)
rentre dans une boucle infinie. Mais dans ce cas-l\u00e0, l'ex\u00e9cution de sym(sym)
se termine correctement et renvoie la valeur 1. C'est une contradiction.
Nous venons de prouver que notre programme halt
, cens\u00e9 pr\u00e9dire si un programme prog
peut s'arr\u00eater sur une entr\u00e9e x
, NE PEUT PAS EXISTER.
Ce r\u00e9sultat th\u00e9orique, d'une importance cruciale, s'appelle le probl\u00e8me de l'arr\u00eat.
Probl\u00e8me de l'arr\u00eat
Il ne peut pas exister de programme universel qui prendrait en entr\u00e9es :
et qui d\u00e9terminerait si ce programme P, lanc\u00e9 avec l'entr\u00e9e E, va s'arr\u00eater ou non.
Ce r\u00e9sultat a \u00e9t\u00e9 d\u00e9montr\u00e9 par Alan Turing en 1936, dans un article intitul\u00e9 \u00abOn computable numbers, with an application to the Entscheidungsproblem\u00bb.
Pour sa d\u00e9monstration, il pr\u00e9sente un mod\u00e8le th\u00e9orique de machine capable d'ex\u00e9cuter des instructions basiques sur un ruban infini, les machines de Turing.
\u00c0 la m\u00eame \u00e9poque, le math\u00e9maticien Alonzo Church d\u00e9montre lui aussi ce th\u00e9or\u00e8me de l'arr\u00eat, mais par un moyen totalement diff\u00e9rent, en inventant le lambda-calcul.
Tous deux mettent ainsi un terme au r\u00eave du math\u00e9maticien allemand David Hilbert, qui avait en 1928 pos\u00e9 la question de l'existence d'un algorithme capable de r\u00e9pondre \u00aboui\u00bb ou \u00abnon\u00bb \u00e0 n'importe quel \u00e9nonc\u00e9 math\u00e9matique pos\u00e9 sous forme d\u00e9cisionnelle (\u00abun triangle rectangle peut-il \u00eatre isoc\u00e8le ?\u00bb, \u00abexiste-t-il un nombre premier pair ?\u00bb)
Cette question, appel\u00e9e \u00abprobl\u00e8me de la d\u00e9cision\u00bb, ou Entscheidungsproblem en allemand, est d\u00e9finitivement tranch\u00e9e par le probl\u00e8me de l'arr\u00eat : un tel th\u00e9or\u00e8me ne peut pas exister, puisque par exemple, aucun algorithme ne peut r\u00e9pondre \u00aboui\u00bb ou \u00abnon\u00bb \u00e0 la question \u00abce programme va-t-il s'arr\u00eater ?\u00bb.
Le th\u00e9or\u00e8me de l'arr\u00eat sera \u00e9tendu plus tard par le th\u00e9or\u00e8me de Rice.
Ce r\u00e9sultat d\u00e9montre que toutes les questions s\u00e9mantiques (non \u00e9videntes) au sujet d'un programme sont ind\u00e9cidables :
Rice d\u00e9montre que toutes ces questions peuvent \u00eatre ramen\u00e9es (on dit r\u00e9duites) au th\u00e9or\u00e8me de l'arr\u00eat, qui est ind\u00e9cidable.
"},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/#2-calculabilite","title":"2. Calculabilit\u00e9","text":"D\u00e9cidabilit\u00e9 et calculabilit\u00e9
Le probl\u00e8me de l'arr\u00eat est dit ind\u00e9cidable car la fonction qui le r\u00e9sout (notre brave programme halt
) n'est pas calculable.
Qu'y a-t-il derri\u00e8re cette notion de calculabilit\u00e9 ? Cette notion, qui jette un pont entre les math\u00e9matiques (la vision de Church, pour sch\u00e9matiser) et l'informatique (la vision de Turing) n'est pas simple \u00e0 d\u00e9finir !
Le calcul math\u00e9matique peut se r\u00e9duire \u00e0 une succession d'op\u00e9rations \u00e9l\u00e9mentaires (songez \u00e0 la multiplication enti\u00e8re comme une s\u00e9rie d'additions). Les nombres calculables sont les nombres qui sont g\u00e9n\u00e9rables en un nombre fini d'op\u00e9rations \u00e9l\u00e9mentaires. De la m\u00eame mani\u00e8re, une fonction math\u00e9matique sera dite calculable s'il existe une suite finie d'op\u00e9rations \u00e9l\u00e9mentaires permettant de passer d'un nombre x \u00e0 son image f(x).
On retrouve cette notion d'op\u00e9rations \u00e9l\u00e9mentaires dans les machines de Turing. Cette machine (th\u00e9orique) permet de simuler tout ce qu'un programme informatique (une suite d'instructions) est capable d'ex\u00e9cuter. Un algorithme peut se r\u00e9duire \u00e0 une suite d'op\u00e9rations \u00e9lementaires, comme une fonction math\u00e9matique peut se r\u00e9duire \u00e0 une suite de calculs. D\u00e8s lors, on pourra consid\u00e9rer un algorithme comme une fonction.
Turing a d\u00e9montr\u00e9 que l'ensemble des fonctions calculables, au sens de Church, \u00e9tait \u00e9quivalent \u00e0 l'ensemble des fonctions programmables sur sa machine. Certaines fonctions peuvent \u00eatre calculables, ou ne pas l'\u00eatre : c'est notamment le cas de notre fonction du probl\u00e8me de l'arr\u00eat.
"},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/#22-langages-turing-complets","title":"2.2 Langages Turing-complets","text":"Ce r\u00e9sultat ne d\u00e9pend pas du langage utilis\u00e9 : le fait que nous ayons utilis\u00e9 Python au paragraphe pr\u00e9c\u00e9dent n'a pas d'influence sur notre d\u00e9monstration. Nous savons depuis les machines de Turing que tous nos langages de programmation sont Turing-complets : ils sont tous capables de faire la m\u00eame chose (avec plus ou moins de facilit\u00e9 !). Scratch, C, Python, Java, Basic, Haskell, Brainfuck... tous ces langages sont th\u00e9oriquement \u00e9quivalents : la calculabilit\u00e9 ne d\u00e9pend pas du langage utilis\u00e9.
"},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/#23-hp-calculable-oui-mais-facilement-1-million-de-a-gagner-ci-dessous","title":"2.3 (HP) Calculable, oui, mais facilement ? -> 1 million de $ \u00e0 gagner ci-dessous.","text":"L'\u00e9tude de la calculabilit\u00e9 d'une fonction (\u00e0 prendre au sens le plus large, c'est-\u00e0-dire un algorithme) ne se limite pas \u00e0 un choix binaire : \u00abcalculable\u00bb vs \u00abnon calculable\u00bb. Parmi les fonctions calculables, certaines peuvent l'\u00eatre rapidement, et d'autre beaucoup moins.
On retrouve alors la notion bien connue de complexit\u00e9 algorithmique, qui permet de classifier les algorithmes suivant leur d\u00e9pendance \u00e0 la taille de leurs donn\u00e9es d'entr\u00e9e (voir le cours de Premi\u00e8re).
On peut regrouper les probl\u00e8mes suivant la complexit\u00e9 de l'algorithme qui permet de les r\u00e9soudre.
"},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/#231-la-classe-p","title":"2.3.1 la classe P","text":"D\u00e9finition de la classe P
On dira que sont de \u00abclasse P\u00bb tous les probl\u00e8mes dont l'algorithme de recherche de solution est de complexit\u00e9 polynomiale.
Que retrouve-t-on dans la classe P ? Tous les probl\u00e8mes dont la solution est un algorithme de complexit\u00e9 lin\u00e9raire, quadratique, logarithmique... Tout mais surtout pas un algorithme de complexit\u00e9 exponentielle.
Pour le r\u00e9sumer tr\u00e8s grossi\u00e8rement, un probl\u00e8me de classe P est un probl\u00e8me que l'on sait r\u00e9soudre en temps raisonnable (m\u00eame grand).
D\u00e9finition de la classe NP
On dira que sont de \u00abclasse NP\u00bb tous les probl\u00e8mes dont l'algorithme de recherche de solution est Non-d\u00e9terministe Polynomial.
Warning : NP ne signifie pas Non-Polynomial !!!
Que veut dire la formulation \u00abnon-d\u00e9terministe polynomial\u00bb ? Cela fait r\u00e9f\u00e9rence \u00e0 ce que serait capable de faire une machine de Turing (donc, n'importe quel ordinateur) travaillant de mani\u00e8re non-d\u00e9terministe, donc capable d'explorer simultan\u00e9ment plusieurs solutions possibles. On peut imaginer un arbre dont le parcours se ferait simultan\u00e9ment dans toutes les branches, et non en largeur ou profondeur comme nous l'avons vu.
Sur une machine non-d\u00e9terministe, si la solution \u00e0 un probl\u00e8me se trouve en temps polynomial, alors ce probl\u00e8me appartient \u00e0 la classe NP.
Tr\u00e8s bien, mais les machines non-d\u00e9terministes... cela n'existe pas r\u00e9ellement. Comment caract\u00e9riser concr\u00e8tement cette classe de probl\u00e8me ?
Si la solution peut \u00eatre trouv\u00e9e de mani\u00e8re polynomiale par une machine non-d\u00e9terministe, une machine d\u00e9terministe qui aurait de la chance en partant directement vers la bonne solution la trouverait elle aussi de mani\u00e8re polynomiale. On simplifie souvent cela en disant \u00abla v\u00e9rification de la solution est polynomiale\u00bb. Cela nous donnne cette d\u00e9finition plus accessible de la classe NP :
D\u00e9finition (plus simple) de la classe NP
On dira que sont de \u00abclasse NP\u00bb tous les probl\u00e8mes dont l'algorithme de v\u00e9rification de solution est polynomial.
Pour le r\u00e9sumer tr\u00e8s grossi\u00e8rement, un probl\u00e8me de classe NP est un probl\u00e8me dont on sait v\u00e9rifier facilement si une solution propos\u00e9e marche ou pas :
Malheureusement, aucun de ces probl\u00e8mes cit\u00e9s n'a (\u00e0 ce jour) d'algorithme de r\u00e9solution meilleur qu'exponentiel...
"},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/#223-p-np-ou-pas","title":"2.2.3 P = NP, ou pas ?","text":"Tous les probl\u00e8mes de P ont une solution qui peut \u00eatre trouv\u00e9e de mani\u00e8re polynomiale. Donc \u00e9videmment, la v\u00e9rification de cette solution est aussi polynomiale. Donc tous les probl\u00e8mes de P sont dans NP. On dit que P est inclus dans NP, que l'on \u00e9crit P \u2282 NP.
Voici une capture d'\u00e9cran de l'excellente vid\u00e9o Nos algorithmes pourraient-ils \u00eatre BEAUCOUP plus rapides ? (P=NP ?) de l'excellent David Louapre :
On y retrouve (en vert) la classe P, qui contient les algorithmes de tri. En blanc, la classe NP, qui contient les probl\u00e8mes de factorisation, du sudoku, du sac-\u00e0-dos...
Si quelqu'un trouve un jour un algorithme de polynomial de factorisation, alors le probl\u00e8me de factorisation viendra se ranger dans P. (accessoirement, le RSA sera sans doute d\u00e9truit par cette d\u00e9couverte, sauf si l'ordre de complexit\u00e9 est tr\u00e8s grand)
Mais certains de ces probl\u00e8mes dans NP ont une propri\u00e9t\u00e9 remarquable : la r\u00e9solution polynomiale d'un seul d'entre eux ferait ramener la totalit\u00e9 des probl\u00e8mes NP dans P. On dit que ces probl\u00e8mes sont NP-complets (marqu\u00e9s en rouge ci-dessus) Concr\u00e8tement, si vous trouvez une solution polynomiale de r\u00e9solution du sudoku, vous entrainez avec lui dans P tous les autres probl\u00e8mes NP, et vous aurez ainsi prouv\u00e9 que P = NP. Accessoirement, vous gagnerez aussi le prix d'un million de dollars promis par la fondation Clay \u00e0 qui tranchera cette question... (prix que vous partagerez bien \u00e9videmment avec votre professeur de NSI)
Actuellement, \u00e0 part le grand Donald Knuth, la plupart des chercheurs qui travaillent \u00e0 ce probl\u00e8me sont plut\u00f4t pessimistes, et pensent que P \u2260 NP. Cela signifie qu'ils pensent que certains probl\u00e8mes ne pourront jamais avoir une solution polynomiale.
Alors, P = NP ou P \u2260 NP ? R\u00e9ponse peut-\u00eatre un jour...
"},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/#bibliographie","title":"Bibliographie","text":"extrait du site https://realpython.com/python-pep8/
"},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#1-conventions-syntaxiques","title":"1. Conventions syntaxiques","text":"La programmation est un art d\u00e9licat : un simple caract\u00e8re en trop peut provoquer une erreur pour le code tout entier (penser \u00e0 un innocent caract\u00e8re d'espace en d\u00e9but de ligne dans un code Python).
Mais m\u00eame lorsqu'un code s'ex\u00e9cute sans erreur, il ne faut pas n\u00e9gliger l'aspect purement \u00abesth\u00e9tique\u00bb de celui-ci : il est n\u00e9cessaire de respecter autant que possible des conventions typographiques, qui vont standardiser le code et le rendre ainsi plus lisible.
Ainsi pour chaque langage, il existe une \u00abbible\u00bb de bonnes pratiques de pr\u00e9sentation du code, qui visent \u00e0 l'uniformiser. Pour Python, cette r\u00e9f\u00e9rence s'appelle la Python Enhancement Proposal 8, plus connue sous le nom de PEP8.
En voici quelques extraits :
"},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#les-espaces","title":"Les espaces","text":"\u25b6 Il faut mettre une espace (oui, en typographie, on dit \u00abune\u00bb espace et non pas \u00abun\u00bb espace) avant et apr\u00e8s chaque op\u00e9rateur de comparaison, d'affectation, ou math\u00e9matique (=, ==, >, +, *, ...
)
# PAS BIEN \na=3\n\n# BIEN \na = 3\n
# PAS BIEN\nif x>3:\n print(\"ok\")\n\n# BIEN\nif x > 3:\n print(\"ok\")\n
\u25b6 Pour les op\u00e9rateurs math\u00e9matiques, on essaie de reconstituer les groupes de priorit\u00e9 (lorsqu'il y en a) :
# PAS BIEN\nx = 3*2\n\n# BIEN\nx = 3 * 2\n
mais
# PAS BIEN\nx = 3 * 2 + 5\n\n# BIEN\nx = 3*2 + 5\n
\u25b6 On ne met pas d'espace \u00e0 int\u00e9rieur des parenth\u00e8ses, des crochets ou des accolades :
# PAS BIEN\nfor x in range( 5 ):\n print( 'bonjour' )\n\n# BIEN\nfor x in range(5):\n print('bonjour')\n
\u25b6 Pour les virgules, et les deux points : pas d'espace avant mais une espace apr\u00e8s.
# PAS BIEN\nif color == (0,255,0) :\n print('vert')\n\n# BIEN\nif color == (0, 255, 0):\n print('vert')\n
On peut contr\u00f4ler si son code v\u00e9rifie les standards de la PEP8 sur ce site http://pep8online.com/
"},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#les-conventions-de-nommage","title":"Les conventions de nommage","text":"\u25b6 Les variables \u00e0 une lettre (comme i
, j
, k
) sont r\u00e9serv\u00e9es aux indices (notamment dans les boucles).
\u25b6 Les autres variables doivent avoir des noms explicites, \u00e9ventuellement \u00e9crits en snake_case
si plusieurs mots doivent \u00eatre reli\u00e9s.
# PAS BIEN\nif d == 1:\n cep += vm\n\n# BIEN\nif date == 1:\n compte_epargne += versement_mensuel\n
Rappel des diff\u00e9rents types de casse :
snake_case
: les mots sont s\u00e9par\u00e9s par des underscores. Conseill\u00e9 en Python.camelCase
: les mots sont s\u00e9par\u00e9s par des majuscules mais la 1\u00e8re lettre est minuscule. Conseill\u00e9 en Javascript.PascalCase
: les mots sont s\u00e9par\u00e9s par des majuscules et la 1\u00e8re lettre est majuscule. Conseill\u00e9 en C.kebab-case
: les mots sont s\u00e9par\u00e9s par des tirets courts. Conseill\u00e9 en HTML - CSS.\u25b6 Cas particulier des classes en Programmation Orient\u00e9e Objet : leur nom doit commencer par une majuscule.
# PAS BIEN\nclass voiture:\n def __init__(self, annee, marque, modele):\n #pass\n\n# BIEN\nclass Voiture:\n def __init__(self, annee, marque, modele):\n #pass\n
"},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#2-commentaires-et-docstrings","title":"2. Commentaires et docstrings","text":""},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#21-commenter-son-code-ou-pas","title":"2.1 Commenter son code ? (ou pas)","text":"La n\u00e9cessit\u00e9 de commenter son code est assez controvers\u00e9e. Il est d'usage de dire qu'un code doit \u00eatre assez explicite pour que le lecteur puisse le comprendre sans avoir \u00e0 lire un commentaire.
De fait, les commentaires sont parfois (souvent) superflus :
Et s'ils sont r\u00e9ellement n\u00e9cessaires, il faut se poser la question : est-ce que ce code n'aurait pas pu \u00eatre plus simple ? (attention, la r\u00e9ponse n'est pas toujours oui)
Exemple :
Consid\u00e9rons la fonction suivante.
def f(c, t, n):\n # c est le capital de d\u00e9part, t le taux annuel et n le nombre d'ann\u00e9es\n return c * (1 + t)**n #renvoie le capital apr\u00e8s n ann\u00e9es\n
Elle est bien comment\u00e9e. Mais si on croise la fonction f()
ailleurs dans le code, se souviendra-t-on de son r\u00f4le ? Il aurait mieux valu \u00e9crire :
def capital_apres_n_annees(capital, taux, nombre_annees) :\n return capital * (1 + taux)**nombre_annees\n
Ce code est plus long, mais assez explicite pour se passer de commentaires."},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#22-le-cas-particulier-des-docstrings","title":"2.2 Le cas particulier des docstrings
","text":""},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#221-que-sont-les-docstrings","title":"2.2.1 Que sont les docstrings
?","text":"Les docstrings
sont des commentaires normalis\u00e9s pour les fonctions, qui peuvent \u00eatre consult\u00e9s en console.
Exemples :
Nous connaissons la fonction len()
qui permet par exemple de conna\u00eetre la longueur d'une liste pass\u00e9e en param\u00e8tre.
Si nous tapons en console la commande print(len.__doc__)
, nous aurons la description de cette fonction.
>>> len.__doc__\n'Return the number of items in a container.'\n
Il est aussi possible d'acc\u00e9der \u00e0 la docstring d'une fonction f
par la commande help(f)
: >>> help(len)\nHelp on built-in function len in module builtins:\n\nlen(obj, /)\n Return the number of items in a container.\n
De m\u00eame pour la fonction range
:
>>> print(range.__doc__)\nrange(stop) -> range object\nrange(start, stop[, step]) -> range object\n\nReturn an object that produces a sequence of integers from start (inclusive)\nto stop (exclusive) by step. range(i, j) produces i, i+1, i+2, ..., j-1.\nstart defaults to 0, and stop is omitted! range(4) produces 0, 1, 2, 3.\nThese are exactly the valid indices for a list of 4 elements.\nWhen step is given, it specifies the increment (or decrement).\n
Le r\u00e9sultat de la commande help(range)
est trop long pour \u00eatre repris ici, mais on y retrouve bien la docstring de la fonction range
.
Il suffit pour cela de commencer la fonction \u00e0 documenter par une ou plusieurs phrases entre triples quotes :
def capital_apres_n_annees(capital, taux, nombre_annees) :\n\"\"\"\n Renvoie le capital apr\u00e8s n ann\u00e9es.\n capital : valeur initiale\n taux : taux d'int\u00e9r\u00eat exprim\u00e9 en nombre d\u00e9cimal (ex: 0.02 pour un taux de 2 %)\n nombre_annees : nombre d'ann\u00e9es de placement du capital\n \"\"\"\n return capital * (1 + taux)**nombre_annees\n
Ainsi, un utilisateur pourra trouver en console le mode d'emploi de notre fonction : >>> help(capital_apres_n_annees)\nHelp on function capital_apres_n_annees in module __main__:\n\ncapital_apres_n_annees(capital, taux, nombre_annees)\n Renvoie le capital apr\u00e8s n ann\u00e9es.\n capital : valeur initiale\n taux : taux d'int\u00e9r\u00eat exprim\u00e9 en nombre d\u00e9cimal (ex: 0.02 pour un taux de 2 %)\n nombre_annees : nombre d'ann\u00e9es de placement du capital\n
Comme on le voit, tout cela est tr\u00e8s \u00abverbeux\u00bb. Cela peut nous para\u00eetre largement superflu puisque nos codes d\u00e9passent rarement quelques dizaines de lignes et sont lus par rarement plus de 2 personnes. Mais dans la vraie vie des d\u00e9veloppeurs, il est primordial qu'un code soit clair et document\u00e9.
"},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#3-la-programmation-defensive-des-assert-pour-securiser-le-code","title":"3. La programmation d\u00e9fensive : desassert
pour s\u00e9curiser le code","text":"La programmation d\u00e9fensive est l'art de pr\u00e9voir le pire et d'essayer de le d\u00e9tecter avant qu'il ne soit trop tard. De mani\u00e8re bien plus concr\u00e8te, il est d'usage d'essayer de r\u00e9p\u00e9rer si des donn\u00e9es (souvent des param\u00e8tres d'une fonction) sont susceptibles de cr\u00e9er des probl\u00e8mes, ou sont hors sp\u00e9cification.
Un exemple :
La fonction :
def racine_carree(x):\n assert x >= 0, 'un nombre positif ou nul est requis'\n return x ** 0.5\n
donnera, lors de l'appel \u00e0 racine_carree(-2)
, le message suivant : >>> racine_carree(-2)\nTraceback (most recent call last):\n File \"<pyshell>\", line 1, in <module>\n File \"/home/gilles/Bureau/exemples_assert.py\", line 2, in racine_carree\n assert x >= 0, 'un nombre positif ou nul est requis'\nAssertionError: un nombre positif ou nul est requis\n
Un autre exemple :
def moyenne_trimestrielle(liste_notes):\n\"\"\"\n calcule la moyenne des nombres de la liste liste_notes\n \"\"\"\n assert liste_notes != [] , 'liste vide'\n assert max(liste_notes) <= 20, 'au moins une note d\u00e9passe 20'\n assert min(liste_notes) >=0, 'au moins une note est en dessous de 0'\n\n return sum(liste_notes) / len(liste_notes)\n
\u00c0 ce stade, les assert
sont donc pour nous juste un moyen rapide de remplacer un test if ... then ... else
pour d\u00e9tecter des erreurs potentielles. Ils sont en r\u00e9alit\u00e9 plus utiles que cela : lors de la conception d'un programme, des assert
sont pos\u00e9s pour v\u00e9rifier l'int\u00e9grit\u00e9 du code, mais peuvent \u00eatre d\u00e9sactiv\u00e9s \u00e0 tout moment pour en faire un code optimis\u00e9 (par la commande -O
\u00e0 l'ex\u00e9cution). Tout ceci d\u00e9passe largement le cadre de notre cours.
Il est \u00e0 noter aussi que les erreurs peuvent \u00eatre g\u00e9r\u00e9es par le m\u00e9canisme try ... except
, qui permet de \u00ablever des exceptions\u00bb. Pour les curieux, plus de renseignements ici.
Tester une fonction est la premi\u00e8re chose que l'on fait (normalement...) lorsqu'on vient de finir de l'\u00e9crire.
Par exemple, si on vient de construire la fonction valeur_absolue(n)
, il est fort probable qu'on aille taper ceci dans la console :
>>> valeur_absolue(-3)\n3\n>>> valeur_absolue(0)\n0\n>>> valeur_absolue(7)\n7\n
test_valeur_absolue()
.test_valeur_absolue()
avant m\u00eame de commencer \u00e0 \u00e9crire la fonction valeur_absolue(n)
.Remarque : la m\u00e9thode de d\u00e9veloppement logiciel TDD (Test Driven Developement) est bas\u00e9e en partie sur ce principe :
Revenons \u00e0 nos tests sur la fonction valeur_absolue(n)
def test_valeur_absolue():\n if valeur_absolue(-3) == 3 :\n print(\"ok\")\n else:\n print(\"erreur\")\n\n if valeur_absolue(0) == 0 :\n print(\"ok\")\n else:\n print(\"erreur\")\n\n if valeur_absolue(7) == 7 :\n print(\"ok\")\n else:\n print(\"erreur\")\n
En console, il suffit maintenant d'appeler la fonction test_valeur_absolue()
:
>>> test_valeur_absolue()\nok\nok\nok\n
"},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#42-revoila-les-assert","title":"4.2 Revoil\u00e0 les assert
","text":"Utiliser des assert
permet d'\u00e9crire tr\u00e8s simplement les tests pr\u00e9c\u00e9dents.
Reprenons notre fonction valeur_absolue()
. Sa fonction test test_valeur_absolue()
peut s'\u00e9crire :
def test_valeur_absolue():\n assert valeur_absolue(-3) == 3\n assert valeur_absolue(0) == 0\n assert valeur_absolue(7) == 7\n
Exercice : \u00c9crire une fonction maxi(liste)
qui renvoie le plus grand \u00e9l\u00e9ment de la liste liste
pass\u00e9e en param\u00e8tre (de pr\u00e9f\u00e9rence sans utiliser la fonction max()
...). Vous \u00e9crirez d'abord une fonction test_maxi()
avant d'\u00e9crire la fonction maxi(liste)
doctest
","text":"Le module doctest
permet d'\u00e9crire les tests \u00e0 l'int\u00e9rieur de la docstring d'une fonction.
Consid\u00e9rons une fonction dont le but est de compter les voyelles du mot pass\u00e9 en param\u00e8tre.
def compte_voyelles(mot):\n\"\"\"\n renvoie le nombre de voyelles du mot donn\u00e9 en param\u00e8tre.\n >>> compte_voyelles(\"python\")\n 2\n >>> compte_voyelles(\"HTTP\")\n 0\n >>> compte_voyelles(\"eau\")\n 3\n \"\"\"\n voyelles = \"aeiou\"\n total = 0\n for lettre in mot:\n if lettre in voyelles:\n total += 1\n return total\n
Observez bien la docstring : elle contient explicitement ce qu'on veut que renvoie le terminal lorsqu'on appellera la fonction. On \u00e9crit donc les trois chevrons >>>
suivi de l'appel \u00e0 la fonction, et \u00e0 la ligne en dessous ce que nous esp\u00e9rons que la fonction nous renvoie. On peut \u00e9crire autant de tests que l'on veut.
Ensuite, en console :
>>> import doctest\n>>> doctest.testmod()\n
Dans notre cas, le retour sera celui-ci : >>> import doctest\n>>> doctest.testmod()\n**********************************************************************\nFile \"voyelles.py\", line 4, in __main__.compte_voyelles\nFailed example:\n compte_voyelles(\"python\")\nExpected:\n 2\nGot:\n 1\n**********************************************************************\n1 items had failures:\n 1 of 3 in __main__.compte_voyelles\n***Test Failed*** 1 failures.\nTestResults(failed=1, attempted=3)\n
On voit que le test compte_voyelles(\"python\")
a renvoy\u00e9 la valeur 1 alors qu'on attendait 2. En regardant notre fonction, on s'aper\u00e7oit donc qu'on avait oubli\u00e9 le y
dans la liste des voyelles.
En corrigeant ceci, le test devient :
>>> import doctest\n>>> doctest.testmod()\nTestResults(failed=0, attempted=3)\n
Ce qui est beaucoup plus satisfaisant."},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#43-a-propos-des-tests","title":"4.3 \u00c0 propos des tests","text":"Le comportement face aux tests en programmation doit \u00eatre le m\u00eame qu'en math\u00e9matiques : un test qui ne marche pas est plus riche d'enseignements qu'un test qui marche.
En math\u00e9matiques, seule la notion de contre-exemple est fertile : si quelqu'un vous affirme que \u00abtous les nombres impairs sont premiers\u00bb, il vous suffit d'exhiber le nombre 9 pour lui prouver qu'il a tort et achever la discussion.
Par contre, il aurait pu essayer de vous convaincre avec les nombres 3, 5 et 13, qui sont bien impairs et premiers.
De la m\u00eame mani\u00e8re, voir qu'une fonction passe les tests que vous avez \u00e9crits ne vous assurera pas que cette fonction aura toujours le bon comportement souhait\u00e9. Elle l'aura pour les valeurs de test, mais pas forc\u00e9ment pour les autres.
En revanche, si une fonction ne passe pas un des tests, vous avez la certitude qu'il y a un probl\u00e8me \u00e0 r\u00e9gler quelque part.
Tout ceci en admettant, bien s\u00fbr, que vos tests eux-m\u00eames ne comportent pas d'erreurs...
"},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#bibliographie","title":"Bibliographie","text":"Nous avons vu en classe de Premi\u00e8re l'algorithme de dichotomie (du grec dikhotomia, \u00ab division en deux parties \u00bb).
Notre but ici est la recherche de la pr\u00e9sence (ou non) d'un \u00e9l\u00e9ment dans une liste tri\u00e9e. Notre fonction renverra donc un bool\u00e9en.
La recherche na\u00efve (\u00e9l\u00e9ment par \u00e9l\u00e9ment) est naturellement de complexit\u00e9 lin\u00e9aire. Nous allons voir que la m\u00e9thode dichotomique est plus efficace.
Activit\u00e9 d'introduction
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#11-version-imperative","title":"1.1 Version imp\u00e9rative","text":"Dichotomie version imp\u00e9rative
def recherche_dichotomique(tab, val) :\n'''\n renvoie True ou False suivant la pr\u00e9sence de la valeur val dans le tableau tri\u00e9 tab.\n '''\n i_debut = 0\n i_fin = len(tab) - 1\n while i_debut <= i_fin :\n i_centre = (i_debut + i_fin) // 2 # (1)\n val_centrale = tab[i_centre] # (2) \n if val_centrale == val: # (3) \n return True\n if val_centrale < val: # (4) \n i_debut = i_centre + 1 # (5) \n else :\n i_fin = i_centre - 1\n return False\n
Exemple d'utilisation :
>>> tab = [1, 5, 7, 9, 12, 13]\n>>> recherche_dichotomique(tab, 12)\nTrue\n>>> recherche_dichotomique(tab, 17)\nFalse\n
\u00c0 chaque tour de la boucle while
, la taille de la liste est divis\u00e9e par 2. Ceci conf\u00e8re \u00e0 cet algorithme une complexit\u00e9 logarithmique (bien meilleure qu'une complexit\u00e9 lin\u00e9aire).
Pour \u00e9crire simplement la version r\u00e9cursive de cet algorithme, nous allons avoir besoin de faire du slicing (d\u00e9coupage) de listes. Cette manipulation n'est pas au programme de NSI (m\u00eame si elle est tr\u00e8s simple). Attention, elle a un co\u00fbt algorithmique important, qui peut fausser notre analyse de complexit\u00e9.
Exemples de slicing :
>>> lst = ['a', 'b', 'c', 'd', 'e']\n>>> lst[:2]\n['a', 'b']\n>>> lst[2:]\n['c', 'd', 'e']\n
On comprend que :
lst[:k]
va renvoyer la sous-liste compos\u00e9e du premier \u00e9l\u00e9ment jusqu'\u00e0 celui d'indice k
non inclus.lst[k:]
va renvoyer la sous-liste compos\u00e9e du k
-i\u00e8me \u00e9l\u00e9ment (inclus) jusqu'au dernier.lst[k:p]
va renvoyer la sous-liste compos\u00e9e du k
-i\u00e8me \u00e9l\u00e9ment (inclus) jusqu'au p
-i\u00e8me (non inclus).Dichotomie version r\u00e9cursive avec slicing
def dichotomie_rec(tab, val):\n if len(tab) == 0:\n return False\n i_centre = len(tab) // 2\n if tab[i_centre] == val:\n return True\n if tab[i_centre] < val:\n return dichotomie_rec(tab[i_centre + 1:], val) # (1)\n else:\n return dichotomie_rec(tab[:i_centre], val) # (2)\n
Exemple d'utilisation :
>>> tab = [1, 5, 7, 9, 12, 13]\n>>> dichotomie_rec(tab, 12)\nTrue\n>>> dichotomie_rec(tab, 17)\nFalse\n
Visualisation gr\u00e2ce \u00e0 PythonTutor: "},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#123-dichotomie-recursive-sans-slicing","title":"1.2.3 Dichotomie r\u00e9cursive sans slicing","text":"
Il est possible de programmer de mani\u00e8re r\u00e9cursive la recherche dichotomique sans toucher \u00e0 la liste, et donc en jouant uniquement sur les indices :
Dichotomie version r\u00e9cursive sans slicing
def dicho_rec_2(tab, val, i=0, j=None): # (1)\n if j is None: # (2)\n j = len(tab)-1\n if i > j :\n return False\n m = (i + j) // 2\n if tab[m] < val :\n return dicho_rec_2(tab, val, m + 1, j)\n elif tab[m] > val :\n return dicho_rec_2(tab, val, i, m - 1 )\n else :\n return True\n
j=len(tab)-1
par d\u00e9faut (car tab
est aussi un param\u00e8tre). On passe donc par une autre valeur (ici None
) qu'on va ici intercepter.Exemple d'utilisation :
>>> tab = [1, 5, 7, 9, 12, 13]\n>>> dicho_rec_2(tab, 12)\nTrue\n>>> dicho_rec_2(tab, 17)\nFalse\n
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#2-diviser-pour-regner","title":"2. Diviser pour r\u00e9gner","text":"Les algorithmes de dichotomie pr\u00e9sent\u00e9s ci-dessous ont tous en commun de diviser par deux la taille des donn\u00e9es de travail \u00e0 chaque \u00e9tape. Cette m\u00e9thode de r\u00e9solution d'un probl\u00e8me est connue sous le nom de diviser pour r\u00e9gner, ou divide and conquer en anglais.
Une d\u00e9finition pourrait \u00eatre :
D\u00e9finition
Un probl\u00e8me peut se r\u00e9soudre en employant le paradigme diviser pour r\u00e9gner lorsque :
Remarques :
Consid\u00e9rons de l'\u00e9criture r\u00e9cursive de la fonction factorielle
ci-dessous :
def factorielle(n):\n if n == 0:\n return 1\n else:\n return n * factorielle(n-1)\n
On ne peut pas parler ici de diviser pour r\u00e9gner car la taille des donn\u00e9es \u00e0 traiter est pass\u00e9e de n \u00e0 n-1. C'est bien une diminution (qui fait que l'algorithme fonctionne) mais il n'y a pas de division de la taille des donn\u00e9es. C'est cette division (par 2 dans le cas de la dichotomie) qui donne son efficacit\u00e9 \u00e0 ce paradigme. Le paradigme diviser pour r\u00e9gner va naturellement amener \u00e0 r\u00e9diger des programmes r\u00e9cursifs.
On appelle exponentiation le fait de mettre en puissance un nombre. On va donc coder, de deux mani\u00e8res diff\u00e9rentes, la puissance d'un nombre.
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#31-algorithme-classique","title":"3.1 Algorithme classique","text":"Exponentiation classique
def puissance(a, n):\n if n == 0:\n return 1\n else:\n return a * puissance(a, n-1)\n
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#32-algorithme-utilisant-diviser-pour-regner","title":"3.2 Algorithme utilisant diviser pour r\u00e9gner","text":"Nous allons nous appuyer sur la remarque math\u00e9matique suivante : Pour tout nombre \\(a\\),
si \\(n\\) est pair, \\(a^n = (a^2)^{\\frac{n}{2}}\\)
si \\(n\\) est impair, \\(a^n = a \\times a^{n-1} = a \\times (a^2)^{\\frac{n-1}{2}}\\)
Ainsi, dans le cas o\u00f9 \\(n\\) est pair, il suffit d'\u00e9lever \\(a\\) au carr\u00e9 (une seule op\u00e9ration) pour que l'exposant diminue de moiti\u00e9. On peut donc programmer la fonction puissance
en utilisant le paradigme diviser pour r\u00e9gner :
Exponentiation rapide
def puissance_mod(a, n):\n if n == 0:\n return 1\n if n % 2 == 0:\n return puissance_mod(a*a, n//2)\n else:\n return a * puissance_mod(a*a, (n-1)//2)\n
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#33-comparaison-de-la-vitesse-dexecution-des-deux-algorithmes","title":"3.3 Comparaison de la vitesse d'ex\u00e9cution des deux algorithmes","text":"Exercice
\u00c9nonc\u00e9CorrectionRecr\u00e9er le graphique ci-dessus, qui compare les temps d'ex\u00e9cution des deux fonctions puissance
et puissance_mod
.
Aide pour Matplotlib : le code ci-dessous
import matplotlib.pyplot as plt\n\ndef carre(x):\n return x*x\n\nx = list(range(10))\ny = [carre(k) for k in x]\nplt.plot(x, y)\nplt.show()\n
donne le graphique suivant :
import matplotlib.pyplot as plt\nimport time\n\ndef puissance(a, n):\n if n == 0:\n return 1\n else:\n return a * puissance(a, n-1)\n\n\ndef puissance_mod(a, n):\n if n == 0:\n return 1\n if n % 2 == 0:\n return puissance_mod(a*a, n//2)\n else:\n return a * puissance_mod(a*a, (n-1)//2)\n\n\ndef mesure_puissance(n):\n t0 = time.time()\n p = puissance(3,n)\n return time.time()-t0\n\ndef mesure_puissance_mod(n):\n t0 = time.time()\n p = puissance_mod(3,n)\n return time.time()-t0\n
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#4-le-tri-fusion","title":"4. Le tri-fusion","text":"En anglais le merge sort.
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#41-preambule-linterclassement","title":"4.1 Preambule : l'interclassement","text":"Le m\u00e9canisme principal du tri fusion est la fusion de deux listes tri\u00e9es en une nouvelle liste elle aussi tri\u00e9e.
On appelera ce m\u00e9canisme l'interclassement.
Principe de l'interclassement de deux listes lst1
et lst2
.
lst_totale
lst1
et lst2
. Il faut pour cela g\u00e9rer s\u00e9par\u00e9ment un indice i1
pour la liste lst1
et un indice i2
pour la liste i2
.Exercice
\u00c9nonc\u00e9CorrectionCoder la fonction interclassement
.
def interclassement(lst1, lst2):\n i1 = 0\n i2 = 0\n lst_totale = []\n while i1 != len(lst1) and i2 != len(lst2):\n if lst1[i1] < lst2[i2]:\n lst_totale.append(lst1[i1])\n i1 += 1\n else:\n lst_totale.append(lst2[i2])\n i2 += 1\n return lst_totale + lst1[i1:] + lst2[i2:]\n
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#42-la-fusion","title":"4.2 La fusion","text":""},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#421-principe","title":"4.2.1 Principe","text":"L'id\u00e9e du tri fusion est le d\u00e9coupage de la liste originale en une multitude de listes ne contenant qu'un seul \u00e9l\u00e9ment. Ces listes \u00e9l\u00e9mentaires seront ensuite interclass\u00e9es avec la fonction pr\u00e9c\u00e9dente.
Principe de l'algorithme du tri fusion :
La grande force de ce tri va \u00eatre qu'il se programme simplement de mani\u00e8re r\u00e9cursive, en appelant \u00e0 chaque \u00e9tape la m\u00eame fonction mais avec une taille de liste divis\u00e9e par deux, ce qui justifie son classement parmi les algorithmes utilisants \u00abdiviser pour r\u00e9gner\u00bb.
Algorithme de tri fusion (merge sort)
def interclassement(lst1, lst2):\n lst_totale = []\n n1, n2 = len(lst1), len(lst2)\n i1, i2 = 0, 0\n while i1 < n1 and i2 < n2:\n if lst1[i1] < lst2[i2]:\n lst_totale.append(lst1[i1])\n i1 += 1\n else:\n lst_totale.append(lst2[i2])\n i2 += 1\n return lst_totale + lst1[i1:] + lst2[i2:]\n\ndef tri_fusion(lst):\n if len(lst) <= 1:\n return lst\n else:\n m = len(lst) // 2\n return interclassement(tri_fusion(lst[:m]), tri_fusion(lst[m:]))\n
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#423-visualisation","title":"4.2.3 Visualisation","text":"Une erreur classique avec les fonctions r\u00e9cursives est de consid\u00e9rer que les appels r\u00e9cursifs sont simultan\u00e9s. Ceci est faux ! L'animation suivante montre la progression du tri :
Il est aussi conseill\u00e9 d'observer l'\u00e9volution de l'algorithme gr\u00e2ce \u00e0 PythonTutor :
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#43-complexite","title":"4.3 Complexit\u00e9","text":"La division par 2 de la taille de la liste pourrait nous amener \u00e0 penser que le tri fusion est de complexit\u00e9 logarithmique, comme l'algorithme de dichotomie. Il n'en est rien.
En effet, l'instruction finale interclassement(tri_fusion(lst[:m]), tri_fusion(lst[m:]))
lance deux appels \u00e0 la fonction tri_fusion
(avec certe des donn\u00e9es d'entr\u00e9e deux fois plus petites).
On peut montrer que :
Complexit\u00e9 du tri fusion
L'algorithme de tri fusion est en \\(O(n \\log n)\\).
On dit qu'il est quasi-lin\u00e9aire. (ou lin\u00e9arithmique)
Une complexit\u00e9 quasi-lin\u00e9aire (en \\(O(n \\log n)\\)) se situe \u00abentre\u00bb une complexit\u00e9 lin\u00e9aire (en \\(O(n)\\)) et une complexit\u00e9 quadratique (en \\(O(n^2)\\)). Mais elle est plus proche de la complexit\u00e9 lin\u00e9aire.
Une jolie animation permettant de comparer les tris :
Issue de ce site
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/intro_dichotomie/","title":"Vers l'algorithme de dichotomie","text":"Exemple d'utilisation :
>>> tab = [1, 5, 7, 9, 12, 13]\n>>> recherche_dichotomique(tab, 12)\nTrue\n>>> recherche_dichotomique(tab, 17)\nFalse\n
Code \u00e0 trous, newbie version def recherche_dichotomique(tab, val) :\n'''\n renvoie True ou False suivant la pr\u00e9sence de la valeur val dans le tableau tri\u00e9 tab.\n '''\n i_debut = ...\n i_fin = ...\n while ... <= ... :\n i_centre = (... + ...) // 2 \n val_centrale = tab[...] \n if val_centrale == val: \n return ...\n if val_centrale < val: \n i_debut = ... + 1 \n else :\n i_fin = ... - 1\n return False\n
Code \u00e0 trous, regular version def recherche_dichotomique(tab, val) :\n'''\n renvoie True ou False suivant la pr\u00e9sence de la valeur val dans le tableau tri\u00e9 tab.\n '''\n i_debut = ...\n i_fin = ...\n while ... <= ... :\n i_centre = ... \n val_centrale = ... \n if ... == ... : \n return ...\n if ... < ...: \n i_debut = ... \n else :\n i_fin = ...\n return False\n
Code \u00e0 trous, expert version def recherche_dichotomique(tab, val) :\n'''\n renvoie True ou False suivant la pr\u00e9sence de la valeur val dans le tableau tri\u00e9 tab.\n '''\n ... = ...\n ... = ...\n while ... <= ... :\n ... = ... \n ... = ... \n if ... == ... : \n return ...\n if ... < ...: \n ... = ... \n else :\n ... = ...\n return False\n
Code \u00e0 trous, God version def recherche_dichotomique(tab, val) :\n ...\n
Pour tester :
>>> tab = [1, 5, 7, 9, 12, 13]\n>>> recherche_dichotomique(tab, 12)\nTrue\n>>> recherche_dichotomique(tab, 17)\nFalse\n
"},{"location":"T3_Algorithmique/3.2_Programmation_dynamique/cours/","title":"Programmation dynamique","text":""},{"location":"T3_Algorithmique/3.2_Programmation_dynamique/exercices/","title":"Exercices de programmation dynamique","text":""},{"location":"T3_Algorithmique/3.2_Programmation_dynamique/exercices/#exercice-1","title":"Exercice 1","text":"Exercice 5 du sujet M\u00e9tropole J2 2022
Correction Q1.cellule = Cellule(True, False, True, True)\n
Correction Q2. class Labyrinthe:\n def __init__(self, hauteur, longueur):\n self.grille = self.construire_grille(hauteur, longueur)\n\n def construire_grille(self, hauteur, longueur):\n grille = []\nfor i in range(hauteur):\nligne = []\nfor j in range(longueur):\ncellule = Cellule(True, True, True, True)\nligne.append(cellule)\ngrille.append(ligne)\n return grille\n
Correction Q3. cellule2.murs['S'] = False\n
Correction Q4. elif c1_lig == c2_lig and c1_col - c2_col == 1:\n cellule1.murs['O'] = False\n cellule2.murs['E'] = False\n
Correction Q5. def creer_labyrinthe(self, ligne, colonne, haut, long):\n if haut == 1 : # Cas de base\nfor k in range(colonne, colonne + long - 1):\nself.creer_passage(ligne, k, ligne, k + 1)\n elif long == 1: # Cas de base\nfor k in range(ligne, ligne + haut - 1):\nself.creer_passage(k, colonne, k + 1, colonne)\nelse: # Appels r\u00e9cursifs\n # Code non \u00e9tudi\u00e9 (Ne pas compl\u00e9ter)\n
Correction Q6. "},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/","title":"Recherche textuelle","text":""},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/#1-recherche-naive","title":"1. Recherche na\u00efve","text":"Illustration de l'algorithme Vous pouvez contr\u00f4ler le d\u00e9roulement de l'animation en la survolant avec la souris.
"},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/#11-premier-algorithme","title":"1.1 Premier algorithme","text":"Algorithme de recherche na\u00efve
def recherche_naive(texte, motif):\n'''\n renvoie la liste des indices (\u00e9ventuellement vide) des occurrences de\n de la cha\u00eene motif dans la cha\u00eene texte.\n '''\n indices = []\n i = 0\n while i <= len(texte) - len(motif):\n k = 0\n while k < len(motif) and texte[i+k] == motif[k]:\n k += 1\n if k == len(motif):\n indices.append(i)\n i += 1\n\n return indices\n
Exemple d'utilisation :
>>> recherche_naive(\"une magnifique maison bleue\", \"maison\")\n[15]\n>>> recherche_naive(\"une magnifique maison bleue\", \"nsi\")\n[]\n>>> recherche_naive(\"une magnifique maison bleue\", \"ma\")\n[4, 15]\n
"},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/#12-modification-de-lalgorithme","title":"1.2 Modification de l'algorithme","text":"Exercice 1
\u00c9nonc\u00e9CorrectionRe-\u00e9crire l'algorithme pr\u00e9c\u00e9dent en s'arr\u00eatant d\u00e8s qu'une occurrence de motif
est trouv\u00e9e dans texte
.
La fonction renverra uniquement un bool\u00e9en.
def recherche_naive_bool(texte, motif):\n'''\n renvoie un bool\u00e9en indiquant la pr\u00e9sence ou non de\n la cha\u00eene motif dans la cha\u00eene texte.\n '''\n trouve = False\n i = 0\n while i <= len(texte) - len(motif) and not trouve:\n k = 0\n while k < len(motif) and texte[i+k] == motif[k]:\n k += 1\n if k == len(motif):\n trouve = True\n i += 1\n\n return trouve\n
"},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/#13-application-a-la-recherche-dun-motif-dans-un-roman","title":"1.3 Application \u00e0 la recherche d'un motif dans un roman","text":"Le Projet Gutenberg permet de t\u00e9l\u00e9charger l\u00e9galement des ouvrages libres de droits dans diff\u00e9rents formats.
Nous allons travailler avec le Tome 1 du roman Les Mis\u00e9rables de Victor Hugo, \u00e0 t\u00e9l\u00e9charger ici au format txt
.
with open(\"Les_Miserables.txt\") as f:\n roman = f.read().replace('\\n', ' ')\n
"},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/#132-verification-et-mesure-du-temps-de-recherche","title":"1.3.2 V\u00e9rification et mesure du temps de recherche","text":"Exercice 2
\u00c9nonc\u00e9Correction\u00c0 l'aide du module time
, mesurer le temps de recherche dans Les Mis\u00e9rables d'un mot court, d'une longue phrase (pr\u00e9sente dans le texte), d'un mot qui n'existe pas. Que remarquez-vous ?
t0 = time.time()\nmotif = \"maison\"\nprint(recherche_naive(roman, motif))\nprint(time.time()-t0)\n\nt0 = time.time()\nmotif = \"La chandelle \u00e9tait sur la chemin\u00e9e et ne donnait que peu de clart\u00e9.\"\nprint(recherche_naive(roman, motif))\nprint(time.time()-t0)\n\nt0 = time.time()\nmotif = \"parcoursup\"\nprint(recherche_naive(roman, motif))\nprint(time.time()-t0)\n
retour console :
[7264, 9090, 9547, 9745, 10936, 17820, 23978, 38192, 41639, 41651, 41840, 42493, 48028, 48393, 51448, 53353, 70867, 72692, 72768, 75608, 77855, 108489, 115739, 130629, 132983, 138870, 143681, 144600, 153114, 155973, 158709, 160700, 163649, 169164, 169181, 171761, 171967, 182642, 186413, 190534, 219378, 220314, 224518, 225098, 227579, 296302, 345108, 345893, 346740, 349677, 359727, 362025, 389945, 395690, 434118, 438068, 457795, 457886, 464696, 469403, 501768, 514980, 520667, 520878, 520926, 520968, 522707, 529329, 598128, 601390, 645915]\n0.21963715553283691\n[651731]\n0.21761441230773926\n[]\n0.22150230407714844\n
On remarque que le temps de recherche est semblable, quel que soit le motif cherch\u00e9.
"},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/#2-vers-lalgorithme-de-boyer-moore-et-si-on-partait-a-lenvers","title":"2. Vers l'algorithme de Boyer-Moore : et si on partait \u00e0 l'envers ?","text":"Exercice 3
\u00c9nonc\u00e9CorrectionRe-\u00e9crire l'algorithme de recherche na\u00efve mais en d\u00e9marrant de la fin du motif et non du d\u00e9but. Certes, c'est pour l'instant tr\u00e8s artificiel, mais :
def presqueBMH(texte, motif):\n indices = []\n i = len(motif) -1\n while i < len(texte):\n k = 0\n while k < len(motif) and motif[len(motif)-1-k] == texte[i-k]:\n k += 1\n if k == len(motif):\n indices.append(i-len(motif)+1)\n i += 1\n return indices\n
"},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/#3-algorithme-de-boyer-moore-horspool","title":"3. Algorithme de Boyer-Moore-Horspool","text":""},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/#21-principe","title":"2.1 Principe","text":"L'id\u00e9e est d'am\u00e9liorer le code pr\u00e9c\u00e9dent (celui on parcourt le motif \u00e0 l'envers) en sautant directement au prochain endroit potentiellement valide.
Pour cela on regarde le caract\u00e8re X
du texte sur lequel on s'est arr\u00eat\u00e9 (car X
n'\u00e9tait pas \u00e9gal au caract\u00e8re de rang \u00e9quivalent dans le motif):
X
n'est pas dans le motif, il est inutile de se d\u00e9placer \"de 1\" : on retomberait tout de suite sur X
, c'est du temps perdu. On se d\u00e9cale donc juste assez pour d\u00e9passer X
, donc de la longueur du motif cherch\u00e9.X
est dans le motif (sauf \u00e0 la derni\u00e8re place du motif !), on va regarder la place de la derni\u00e8re occurence de X
dans le motif et de d\u00e9placer de ce nombre, afin de faire co\u00efncider le X
du motif et le X
du texte.Vous pouvez contr\u00f4ler le d\u00e9roulement de l'animation en la survolant avec la souris.
"},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/#22-implementation","title":"2.2 Impl\u00e9mentation","text":"On va d'abord coder une fonction dico_lettres
qui renvoie un dictionnaire associant \u00e0 chaque lettre de mot
(param\u00e8tre d'entr\u00e9e) son dernier rang dans le mot
. On exclut la derni\u00e8re lettre, qui poserait un probl\u00e8me lors du d\u00e9calage (on d\u00e9calerait de 0...)
Algorithme de Boyer-Moore-Horspool
def dico_lettres(mot):\n d = {}\n for i in range(len(mot)-1):\n d[mot[i]] = i\n return d\n\ndef BMH(texte, motif):\n dico = dico_lettres(motif)\n indices = []\n i = len(motif) -1\n while i < len(texte):\n k = 0\n while k < len(motif) and motif[len(motif)-1-k] == texte[i-k]: #(1)\n k += 1\n if k == len(motif): #(2)\n indices.append(i-len(motif)+1)\n i += 1 #(3)\n else:\n if texte[i-k] in dico: (#4)\n i = max(i - k + len(motif) - dico[texte[i-k]] - 1, i+1) #(5)\n else:\n i = i - k + len(motif) #(6)\n\n return indices\n
Exemple d'utilisation :
>>> BMH(\"une magnifique maison bleue\", \"maison\")\n[15]\n>>> BMH(\"une magnifique maison bleue\", \"nsi\")\n[]\n>>> BMH(\"une magnifique maison bleue\", \"ma\")\n[4, 15]\n
Exercice 4
\u00c9nonc\u00e9CorrectionReprendre les mesures effectu\u00e9es sur Les Mis\u00e9rables, mais cette fois avec l'algorithme BMH. Que remarquez-vous ?
t0 = time.time()\nmotif = \"maison\"\nprint(BMH(roman, motif))\nprint(time.time()-t0)\n\nt0 = time.time()\nmotif = \"La chandelle \u00e9tait sur la chemin\u00e9e et ne donnait que peu de clart\u00e9.\"\nprint(BMH(roman, motif))\nprint(time.time()-t0)\n\nt0 = time.time()\nmotif = \"parcoursup\"\nprint(BMH(roman, motif))\nprint(time.time()-t0)\n
retour console :
[7264, 9090, 9547, 9745, 10936, 17820, 23978, 38192, 41639, 41651, 41840, 42493, 48028, 48393, 51448, 53353, 70867, 72692, 72768, 75608, 77855, 108489, 115739, 130629, 132983, 138870, 143681, 144600, 153114, 155973, 158709, 160700, 163649, 169164, 169181, 171761, 171967, 182642, 186413, 190534, 219378, 220314, 224518, 225098, 227579, 296302, 345108, 345893, 346740, 349677, 359727, 362025, 389945, 395690, 434118, 438068, 457795, 457886, 464696, 469403, 501768, 514980, 520667, 520878, 520926, 520968, 522707, 529329, 598128, 601390, 645915]\n0.06359553337097168\n[651731]\n0.01853322982788086\n[]\n0.037064313888549805\n
On constate quelque chose de remarquable (et qui peut \u00eatre \u00e0 premi\u00e8re vue contre-intuitif) :
Plus le motif recherch\u00e9 est long, plus la recherche est rapide.
"},{"location":"T4_Bases_de_donnees/sommaire/","title":"Sommaire","text":"Lorsqu'une grande quantit\u00e9 de donn\u00e9es doit \u00eatre g\u00e9r\u00e9e, il faut savoir distinguer deux choses :
Par exemple, si je souhaite stocker toutes les temp\u00e9ratures relev\u00e9es dans mon jardin tous les matins \u00e0 07h00, je sais que mes donn\u00e9es seront des couples (date, temperature)
. \u00c9ventuellement ces dates seront regroup\u00e9es par mois, ou par saison... mais la structure des donn\u00e9es sera quand m\u00eame simple et lin\u00e9aire. Pour g\u00e9rer ces donn\u00e9es, je peux : les \u00e9crire \u00e0 la main dans mon agenda, cr\u00e9er un feuille de tableur avec Excel ou LibreOffice, utiliser une liste dans un IDE Python,... Chaque m\u00e9thode aura ses avantages et ses inconv\u00e9nients.
Si le nombre de donn\u00e9es \u00e0 stocker devient tr\u00e8s grand, est-ce que ma solution choisie pourra les g\u00e9rer ? (on peut par exemple m\u00e9diter sur le cas du Royaume-Uni dont le comptage des patients positifs au Covid est devenu faux car il a d\u00e9pass\u00e9 les limites de leur feuille Excel)
Est-ce que d'autres personnes que moi sont susceptibles de consulter ou modifier ces donn\u00e9es, \u00e9ventuellement en m\u00eame temps que moi ?
Si une donn\u00e9e se retrouve \u00e0 plusieurs endroits dans mes donn\u00e9es, devrais-je aller modifier cette donn\u00e9e partout o\u00f9 elle se trouve ou bien une seule fois ?
L'\u00e9tude des Bases de Donn\u00e9es tente d'apporter des r\u00e9ponses \u00e0 toutes ces questions.
"},{"location":"T4_Bases_de_donnees/4.1_Modele_relationnel/cours/#1-le-modele-relationnel","title":"1. Le mod\u00e8le relationnel","text":"Le programme de Terminale NSI pr\u00e9voit uniquement l'\u00e9tude du mod\u00e8le relationnel.
Th\u00e9oris\u00e9 en 1970 par le Britannique Edgard J. Codd, le mod\u00e8le relationnel est \u00e0 ce jour le mod\u00e8le de base de donn\u00e9es le plus utilis\u00e9, m\u00eame si l'\u00e8re actuelle du Big Data tend \u00e0 mettre en avant d'autres mod\u00e8les non relationnels (nous en reparlerons).
Les principes de base du mod\u00e8le relationnel
Un mod\u00e8le relationnel est donc bas\u00e9 sur des... relations.
"},{"location":"T4_Bases_de_donnees/4.1_Modele_relationnel/cours/#2-premiere-relation","title":"2. Premi\u00e8re relation","text":"Prenons l'exemple d'une biblioth\u00e8que dont la base de donn\u00e9es poss\u00e8de une relation \u00ablivres\u00bb :
Vocabulaire
Int
, Float
, String
). L'attribut \u00ab\u00c9diteur\u00bb est une cha\u00eene de caract\u00e8res, son domaine est donc String
. Par contre l'attribut \u00abISBN\u00bb est un nombre de 13 chiffres, commen\u00e7ant manifestement par 978. Son domaine est donc Int
.((Code, Entier), (Titre, Cha\u00eene de caract\u00e8res), (Auteur, Cha\u00eene de caract\u00e8res), (\u00c9diteur, Cha\u00eene de caract\u00e8res), (ISBN, Entier))
Cl\u00e9 primaire
Une cl\u00e9 primaire est un attribut (ou une r\u00e9union d'attributs) dont la connaissance suffit \u00e0 identifier avec certitude un unique enregistrement.
Par exemple, la cl\u00e9 primaire de la relation des personnes n\u00e9es en France pourrait \u00eatre leur num\u00e9ro de S\u00e9curit\u00e9 Sociale.
Observons, dans notre relation pr\u00e9c\u00e9dente, ce qui peut \u00eatre une cl\u00e9 primaire et ce qui ne peut pas l'\u00eatre.
Alors, quelle cl\u00e9 primaire choisir ? Il faut pour cela r\u00e9fl\u00e9chir \u00e0 ce que deviendrait notre relation si elle contenait 1000 livres au lieu de 10. Il est fort probable que deux livres aient alors le m\u00eame auteur : l'attribut \u00abAuteur\u00bb ne serait donc plus une cl\u00e9 primaire. Il peut arriver aussi que deux livres aient le m\u00eame titre : l'attribut \u00abTitre\u00bb n'est donc pas une bonne cl\u00e9 primaire.
Par d\u00e9finition, l'attribut \u00abISBN\u00bb pourrait jouer le r\u00f4le de cl\u00e9 primaire.
Quant \u00e0 l'attribut \u00abCode\u00bb, il s'agit sans doute d'une nomenclature \u00abmaison\u00bb correspondant \u00e0 une \u00e9tiquette coll\u00e9e sur la tranche des livres : c'est donc une cl\u00e9 primaire qu'on qualifiera d'\u00abartificielle\u00bb.
Attention Il ne peut pas y avoir deux cl\u00e9s primaires dans une table. La cl\u00e9 primaire choisie ici serait sans aucun doute l'attribut \u00abCode\u00bb.
"},{"location":"T4_Bases_de_donnees/4.1_Modele_relationnel/cours/#4-dautres-relations","title":"4. D'autres relations","text":"Ajoutons maintenant les relations ci-dessous :
Relation \u00abEmprunts\u00bb
id_emprunteur date Nom Pr\u00e9nom titre auteur code 845 12/10/2020 DURAND Michel Au revoir l\u00e0-haut Pierre LEMAITRE 942 125 13/10/2020 MARTIN Jean Pas pleurer Lydie SALVAYRE 1023 125 13/10/2020 MARTIN Jean Boussole Mathias ENARD 486Relation \u00abEmprunteurs\u00bb
id_emprunteur Nom Pr\u00e9nom 129 DULAC Marcel 845 DURAND Michel 125 MARTIN JeanL'attribut \u00abid_emprunteur\u00bb est une cl\u00e9 primaire de la relation \u00abEmprunteurs\u00bb.
Notion de cl\u00e9 \u00e9trang\u00e8re
Y-a-t-il une cl\u00e9 primaire dans la relation \u00abEmprunts\u00bb ?
\u00abid_emprunteur\u00bb est bien une cl\u00e9 primaire (d'\u00abEmprunteurs\u00bb) mais ne peut pas \u00eatre une cl\u00e9 primaire d'\u00abEmprunts\u00bb, car une personne peut prendre plusieurs livres \u00e0 la fois : on dit que c'est une cl\u00e9 \u00e9trang\u00e8re.
Cl\u00e9 \u00e9trang\u00e8re
Une cl\u00e9 \u00e9trang\u00e8re est une cl\u00e9 primaire d'une autre relation.
\u00abcode\u00bb est aussi une cl\u00e9 \u00e9trang\u00e8re : c'est une cl\u00e9 primaire (de la relation \u00ablivres\u00bb) mais elle ne peut pas jouer le r\u00f4le de cl\u00e9 primaire pour la relation emprunt, car un m\u00eame livre pourra \u00eatre pris \u00e0 diff\u00e9rentes dates.
Une cl\u00e9 primaire pourrait alors \u00eatre la combinaison (\u00abdate\u00bb, \u00abcode\u00bb). En effet, aucun livre ne pouvant \u00eatre emprunt\u00e9 deux fois le m\u00eame jour, la connaissance de \u00abdate\u00bb et \u00abcode\u00bb suffit \u00e0 identifier n'importe quel enregistrement.
"},{"location":"T4_Bases_de_donnees/4.1_Modele_relationnel/cours/#5-redondance-des-donnees","title":"5. Redondance des donn\u00e9es","text":"La relation \u00abEmprunts\u00bb contient des informations qui sont d\u00e9j\u00e0 disponibles dans d'autres relations : on dit qu'elle est redondante, et c'est quelque chose qu'il faut \u00e9viter. \u00c0 la fois pour des raisons d'espace de stockage mais aussi de coh\u00e9rence : si une modification doit \u00eatre faite (un emprunteur change de pr\u00e9nom), cette modification ne doit \u00eatre faite qu'\u00e0 un seul endroit de notre base de donn\u00e9es.
Une version non-redondante de la relation \u00abEmprunteurs\u00bb serait donc celle-ci :
Relation \u00abEmprunts\u00bb
id_emprunteur date code 845 12/10/2020 942 125 13/10/2020 1023 125 13/10/2020 486"},{"location":"T4_Bases_de_donnees/4.1_Modele_relationnel/cours/#6-les-3-contraintes-dintegrite","title":"6. Les 3 contraintes d'int\u00e9grit\u00e9","text":"Contrainte de domaine
Tout attribut d'un enregistrement doit respecter le domaine indiqu\u00e9 dans le sch\u00e9ma relationnel.
Attention, certains domaines sont subtils. Par exemple, si une relation poss\u00e8de un attribut \"Code Postal\", le domaine de cet attribut devra \u00eatre String
plut\u00f4t que Entier
. Dans le cas contraire, un enregistrement poss\u00e9dant le code postal 03150
serait converti en 3150
(car pour les entiers, 03150 = 3150). Or le code postal 3150
n'existe pas.
Contrainte de relation
Tout enregistrement est unique. Cette contrainte est assur\u00e9e par l'existence obligatoire d'une cl\u00e9 primaire.
Cette cl\u00e9 primaire est souvent cr\u00e9\u00e9e de mani\u00e8re artificielle (voir id_emprunteurs
dans la table ci-dessus par exemple).
Contrainte de r\u00e9f\u00e9rence
La coh\u00e9rence entre les diff\u00e9rentes tables d'une base de donn\u00e9es est assur\u00e9e par les cl\u00e9s \u00e9trang\u00e8res : dans une table, la valeur d'un attribut qui est cl\u00e9 \u00e9trang\u00e8re doit obligatoirement pouvoir \u00eatre retrouv\u00e9e dans la table dont cet attribut est cl\u00e9 primaire.
Par exemple, la relation \u00abEmprunts_v2\u00bb ci-dessous n'est pas valable :
Relation \u00abEmprunts_v2\u00bb
id_emprunteur date code 845 12/10/2020 942 125 13/10/2020 1023 125 13/10/2020 511En effet, le code 511 (cl\u00e9 \u00e9trang\u00e8re de ma table \u00abEmprunts_v2\u00bb) ne correspond \u00e0 aucun enregistrement dans la table dont il est cl\u00e9 primaire (la table \u00abLivres\u00bb) :
Il n'y a pas de code 511, donc ma relation \u00abEmprunts_v2\u00bb ne respecte pas la contrainte de r\u00e9f\u00e9rence, et provoquerait une erreur du SGBD.
"},{"location":"T4_Bases_de_donnees/4.1_Modele_relationnel/cours/#7-representation-usuelles-des-bases-de-donnees-en-modele-relationnel","title":"7. Repr\u00e9sentation usuelles des bases de donn\u00e9es en mod\u00e8le relationnel","text":"Consid\u00e9rons la base de donn\u00e9es Tour de France 2020, contenant les relations suivantes : (d'apr\u00e8s une id\u00e9e de Didier Boulle)
relation \u00c9quipes
codeEquipe nomEquipe ALM AG2R La Mondiale AST Astana Pro Team TBM Bahrain - McLaren BOH BORA - hansgrohe CCC CCC Team COF Cofidis, Solutions Cr\u00e9dits DQT Deceuninck - Quick Step EF1 EF Pro Cycling GFC Groupama - FDJ LTS Lotto Soudal ... ...\u00c9criture classique d'un sch\u00e9ma relationnel
Le sch\u00e9ma relationnel de cette table sera fr\u00e9quemment donn\u00e9 sous cette forme : Equipes ( codeEquipe String
, nomEquipe String
)
Notez le soulignement sous le mot \u00abcodeEquipe\u00bb, qui signifie que cet attribut est une cl\u00e9 primaire. Les cl\u00e9s \u00e9trang\u00e8res, lorsqu'elles existent, peuvent \u00eatre signal\u00e9es par une ast\u00e9risque * ou un di\u00e8se #.
relation Coureurs
dossard nomCoureur pr\u00e9nomCoureur codeEquipe 141 L\u00d3PEZ Miguel \u00c1ngel AST 142 FRAILE Omar AST 143 HOULE Hugo AST 11 ROGLI\u010c Primo\u017e TJV 12 BENNETT George TJV 41 ALAPHILIPPE Julian DQT 44 CAVAGNA R\u00e9mi DQT 45 DECLERCQ Tim DQT 121 MARTIN Guillaume COF 122 CONSONNI Simone COF 123 EDET Nicolas COF \u2026 \u2026 \u2026 \u2026Sch\u00e9ma : Equipes ( dossard Int
, nomCoureur String
, pr\u00e9nomCoureur String
, codeEquipe* String
)
relation \u00c9tapes
num\u00e9roEtape villeD\u00e9part villeArriv\u00e9e km 1 Nice Nice 156 2 Nice Nice 185 3 Nice Sisteron 198 4 Sisteron Orci\u00e8res-Merlette 160 5 Gap Privas 198 ... ... ... ...Sch\u00e9ma : \u00c9tapes ( num\u00e9roEtape Int
, villeD\u00e9part String
, villeArriv\u00e9e String
, km Int
)
relation Temps
dossard num\u00e9roEtape tempsR\u00e9alis\u00e9 41 2 04:55:27 121 4 04:07:47 11 5 04:21:22 122 5 04:21:22 41 4 04:08:24 ... ... ...Sch\u00e9ma : Temps ( dossard* Int
, num\u00e9roEtape * Int
, tempsR\u00e9alis\u00e9 String
)
Remarquez que la cl\u00e9 primaire de cette relation est le couple dossard-num\u00e9roEtape.
Diagramme relationnel
Fr\u00e9quemment, on pr\u00e9sentera l'ensemble des renseignements d'un mod\u00e8le relationnel sous forme d'un diagramme qui synth\u00e9tise la composition des diff\u00e9rentes tables et les relations entre elles.
"},{"location":"T4_Bases_de_donnees/4.1_Modele_relationnel/cours/#bibliographie","title":"Bibliographie","text":"(d'apr\u00e8s Pr\u00e9pabac NSI, Terminale, G.CONNAN, V.PETROV, G.ROZSAVOLGYI, L.SIGNAC, \u00e9ditions HATIER.)
Deux relations mod\u00e9lisent la flotte de voitures d'un r\u00e9seau de location de voitures.
Agences
id_agence ville d\u00e9partement 1 Paris 75 2 Lyon 69 3 Marseille 13 4 Aubagne 13Voitures
id_voiture marque mod\u00e8le kilom\u00e9trage couleur id_agence 1 Renault Clio 12000 Rouge 2 2 Peugeot 205 22000 Noir 3 3 Toyota Yaris 33000 Noir 3Questions
\u00c9nonc\u00e9CorrectionVoitures
comporte-t-elle d'attributs ?id_agence
dans la relation Voitures
?Agences
?Agences
?Voitures
?Voitures
?Int
)id_agence
id_voiture
id_agence
Reprenons la base Tour de France 2020 vue en cours :
relation \u00c9quipes
codeEquipe nomEquipe ALM AG2R La Mondiale AST Astana Pro Team TBM Bahrain - McLaren BOH BORA - hansgrohe CCC CCC Team COF Cofidis, Solutions Cr\u00e9dits DQT Deceuninck - Quick Step EF1 EF Pro Cycling GFC Groupama - FDJ LTS Lotto Soudal ... ...relation Coureurs
dossard nomCoureur pr\u00e9nomCoureur codeEquipe 141 L\u00d3PEZ Miguel \u00c1ngel AST 142 FRAILE Omar AST 143 HOULE Hugo AST 11 ROGLI\u010c Primo\u017e TJV 12 BENNETT George TJV 41 ALAPHILIPPE Julian DQT 44 CAVAGNA R\u00e9mi DQT 45 DECLERCQ Tim DQT 121 MARTIN Guillaume COF 122 CONSONNI Simone COF 123 EDET Nicolas COF \u2026 \u2026 \u2026 \u2026relation \u00c9tapes
num\u00e9roEtape villeD\u00e9part villeArriv\u00e9e km 1 Nice Nice 156 2 Nice Nice 185 3 Nice Sisteron 198 4 Sisteron Orci\u00e8res-Merlette 160 5 Gap Privas 198 ... ... ... ...relation Temps
dossard num\u00e9roEtape tempsR\u00e9alis\u00e9 41 2 04:55:27 121 4 04:07:47 11 5 04:21:22 122 5 04:21:22 ... ... ...Questions
\u00c9nonc\u00e9CorrectionExercice 1
(d'apr\u00e8s Pr\u00e9pabac NSI, Terminale, G.CONNAN, V.PETROV, G.ROZSAVOLGYI, L.SIGNAC, \u00e9ditions HATIER.)
On veut cr\u00e9er une base de donn\u00e9es baseHopital.db
qui contiendra les trois tables suivantes :
Int
nom Text
prenom Text
genre Text
annee_naissance Int
Ordonnances code Int
id_patient Int
matricule_medecin Int
date_ord Text
medicaments Text
Medecins matricule Int
nom_prenom Text
specialite Text
telephone Text
On suppose que les dates sont donn\u00e9es sous la forme jj-mm-aaaa
.
On donne le diagramme relationnel de cette base :
Q0. \u00c9crire le sch\u00e9ma relationnel de la table Ordonnances. On soulignera les cl\u00e9s primaires et marquera d'un # les cl\u00e9s \u00e9trang\u00e8res.
CorrectionOrdonnances ((code, Int), (id_patient#, Int), (matricule_medecin#, Int), (date_ord, Text), (medicaments, Text))
Q1. (HP) Donner les commandes SQL permettant de cr\u00e9er ces tables.
CorrectionCREATE TABLE Patients(\nid INTEGER PRIMARY KEY,\nnom TEXT,\nprenom TEXT,\ngenre TEXT,\nannee_naissance INTEGER\n);\n\nCREATE TABLE Ordonnances(\ncode INTEGER PRIMARY KEY,\nid_patient INTEGER,\nmatricule_medecin INTEGER,\ndate_ord TEXT,\nmedicaments TEXT,\nFOREIGN KEY(id_patient) REFERENCES Patients(Id),\nFOREIGN KEY(matricule_medecin) REFERENCES Medecins(matricule)\n);\n\nCREATE TABLE Medecins(\nmatricule INTEGER PRIMARY KEY,\nnom_prenom TEXT,\nspecialite TEXT,\ntelephone TEXT\n);\n
Q2. Mme Anne Wizeunid, n\u00e9e en 2000 et demeurant 3 rue des Pignons Verts 12345 Avonelit doit \u00eatre enregistr\u00e9e comme patiente num\u00e9ro 1. Donner la commande SQLite correspondante.
CorrectionINSERT INTO Patients\nVALUES (1, \"Wizeunit\", \"Anne\", \"F\", 2000);\n
Q3. Le patient num\u00e9ro 100 a chang\u00e9 de pr\u00e9nom et s'appelle maintenant \"Alice\". Donner la commande SQLite modifiant en cons\u00e9quence ses donn\u00e9es.
CorrectionUPDATE Patients\nSET prenom = 'Alice' WHERE id = 100 ;\n
Q4. Par souci d'\u00e9conomie, la direction d\u00e9cide de se passer des m\u00e9decins sp\u00e9cialis\u00e9s en \u00e9pid\u00e9miologie. Donner la commande permettant de supprimer leurs fiches.
CorrectionDELETE FROM Medecins WHERE specialite = \"\u00e9pid\u00e9miologie\";\n
Q5. Donner la liste des patient(e)s ayant \u00e9t\u00e9 examin\u00e9(e)s par un(e) psychiatre en avril 2020.
CorrectionSELECT p.nom, p.prenom\nFROM Patients AS p\nJOIN Ordonnances AS o ON p.id = o.id_patient\nJOIN Medecins AS m ON o.matricule_medecin = m.matricule\nWHERE m.specialite = \"psychiatrie\"\nAND o.date_ord LIKE \"%-04-2020\"\n
Exercice 2
bas\u00e9 sur le travail de G.Viateau (Bayonne)
On consid\u00e8re ci-dessous le sch\u00e9ma de la base de donn\u00e9es du stock d'un supermarch\u00e9 :
Q1. Quelle requ\u00eate SQL donne le prix d'achat du produit dont le nom_court
est \u00abLiq_Vaiss_1L\u00bb ?
SELECT prix_achat FROM Produits WHERE nom_court = 'Liq_Vaiss_1L'
Q2. Quelle requ\u00eate donne l'adresse, le code postal et la ville du fournisseur dont le nom est \u00abAvenir_confiseur\u00bb ?
CorrectionSELECT adresse, cp, ville FROM Fournisseurs WHERE nom = 'Avenir_confiseur';\n
Q3. Quelle requ\u00eate donne les produits \u00e9tant en rupture de stock ?
CorrectionSELECT Produits.nom FROM Produits\nJOIN Stocks ON Produits.id = Stocks.produit\nWHERE Stocks.quantite = 0;\n
Q4. Quelle requ\u00eate donne la liste de toutes les ampoules vendues en magasin ? On pourra faire l'hypoth\u00e8se que le nom du produit contient le mot \u00abampoule\u00bb
CorrectionSELECT nom FROM Produits WHERE nom LIKE \"%ampoule%\";\n
Q5. Quelle requ\u00eate permet d'avoir le prix moyen de ces ampoules ?
CorrectionSELECT AVG(prix_vente) FROM Produits WHERE nom LIKE \"%ampoule%\";\n
Q6. Quelle requ\u00eate permet d'identifier le produit le plus cher du magasin ?
CorrectionSELECT nom_court FROM Produits ORDER BY prix_vente DESC LIMIT 1;\n
ou SELECT nom FROM Produits WHERE prix_vente = (SELECT MAX(prix_vente) FROM Produits);\n
Q7. Quelle requ\u00eate renvoie les noms des produits dont la date de p\u00e9remption est d\u00e9pass\u00e9e ? (on pourra utiliser la fonction SQL NOW()
qui renvoie la date actuelle )
SELECT p.nom FROM Produits AS p\nJOIN Stocks AS s ON s.produits = p.id\nWHERE s.date_peremption < NOW();\n
Exercice 3
Exercice 1 du sujet Am\u00e9rique du Nord J1 2022
Correction Correction Q1.a.La relation Sport a pour cl\u00e9 primaire le couple NomSport et nomStation, et pour cl\u00e9 \u00e9trang\u00e8re l'attribut nomStation, cl\u00e9 primaire de la relation Station.
Correction Q1.b.Contrainte d'int\u00e9grit\u00e9 de domaine : l'attribut Prix doit \u00eatre un nombre entier.
Contrainte d'int\u00e9grit\u00e9 de relation : le couple (nomSport, nomStation) ne peut pas se retrouver deux fois dans la table (car il forme une cl\u00e9 primaire)
Contrainte d'int\u00e9grit\u00e9 de r\u00e9f\u00e9rence : l'attribut nomStation ne peut pas \u00eatre un nom n'apparaissant pas dans la relation Station.
La commande INSERT ne sert que pour ins\u00e9rer de nouveaux enregistrements, or le couple (\"planche \u00e0 voile\" , \"La tramontane catalane\") existe d\u00e9j\u00e0 dans la relation (et c'est une cl\u00e9 primaire donc on ne peut pas la retrouver deux fois). Il faut donc utiliser :
UPDATE Sports SET prix = 1350 WHERE nomSport = \"planche \u00e0 voile\" AND nomStation = \"La tramontane catalane\"
Correction Q2.b. INSERT INTO Station VALUES (\"Soleil Rouge\", \"Bastia\", \"Corse\") INSERT INTO Sport VALUES (\"plong\u00e9e\", \"Soleil Rouge\", 900)
Correction Q3.a. SELECT mail FROM Client
Correction Q3.b. SELECT nomStation FROM Sport\nWHERE nomSport = \"plongee\"
Correction Q4.a. SELECT Station.ville, Station.nomStation FROM Station\nJOIN Sport ON Sport.nomStation = Station.nomStation\nWHERE Sport.nomSport = \"plongee\"
Correction Q4.b. SELECT COUNT(*) FROM Sejour\nJOIN Station ON Station.nomStation = Sejour.nomStation\nWHERE Sejour.annee = 2020 AND Station.region = \"Corse\"\n
Exercice 4
Exercice 4 du sujet Centres \u00c9trangers J1 2022
Correction Correction Q1.a.L'attribut id_mesure
semble une cl\u00e9 primaire acceptable car elle semble sp\u00e9cifique \u00e0 chaque enregistrement.
L'attribut id_centres
semble \u00eatre une cl\u00e9 primaire de la relation Centres
. On le retrouve aussi (sous le m\u00eame nom) dans la relation Mesures
. C'est donc un attribut qui permettra de faire une jointure entre les deux relations.
Cette requ\u00eate va afficher tous les renseignements disponibles sur les centres dont l'altitude est strictement sup\u00e9rieure \u00e0 500m.
Correction Q2.b.SELECT nom_ville FROM Centres WHERE altitude >= 700 AND altitude <= 1200;\n
Correction Q2.c. SELECT longitude, nom_ville FROM Centres\nWHERE longitude > 5\nORDER BY nom_ville;\n
Correction Q3.a. Cette requ\u00eate va afficher tous les renseignements sur les mesures dat\u00e9es du 30 octobre 2021.
Correction Q3.b.INSERT INTO Mesures VALUES (3650, 138, 2021-11-08, 11, 1013, 0);\n
Correction Q4.a. Cette requ\u00eate va renvoyer tous les renseignements sur les centres dont la latitude est la latitude minimum de tous les centres.
Correction Q4.b.SELECT DISTINCT Centres.nom_ville FROM Centres\nJOIN Mesures ON Mesures.id_centre = Centres.id_centre\nWHERE Mesures.temperature < 10\nAND Mesures.date <= 2021-10-31\nAND Mesures.date >= 2021-10-01;\n
Exercice 5
Exercice 4 du sujet M\u00e9tropole J2 2022
Correction Correction Q1.a.Hey Jude\nI Want To Hold Your Hand\n
Correction Q1.b. SELECT nom FROM interpretes\nWHERE pays = 'Angleterre';\n
Correction Q1.c. I Want To Hold Your Hand, 1963\nLike a Rolling Stone, 1965\nRespect, 1967\nHey Jude, 1968\nImagine, 1970\nSmells Like Teen Spirit, 1991\n
Correction Q1.d. SELECT COUNT(*) FROM morceaux;\n
Correction Q1.e. SELECT titre FROM morceaux\nORDER BY titre;\n
Correction Q2.a. La cl\u00e9 \u00e9trang\u00e8re de la table morceaux
est l'attribut id_interprete
qui fait r\u00e9f\u00e9rence \u00e0 la cl\u00e9 primaire id_interprete
de la table interpretes
.
morceaux
: ((id_morceau, Int), (titre, Text), (annee, Int), (id_interprete#, Int)) interpretes
: ((id_interprete, Int), (nom, Text), (pays, Text))
La requ\u00eate va renvoyer une erreur car la cl\u00e9 primaire 1 est d\u00e9j\u00e0 pr\u00e9sente dans la table : il s'agit d'une violation de la contrainte de relation.
Correction Q3.a.UPDATE morceaux\nSET annee = 1971\nWHERE titre = 'Imagine'\n
Correction Q3.b. INSERT INTO interpretes\nVALUES (6, \"The Who\", \"Angleterre\")\n
Correction Q3.c. INSERT INTO morceaux\nVALUES (7, \"My Generation\", 1965, 6)\n
Correction Q4. SELECT morceaux.titre\nFROM morceaux\nJOIN interpretes ON interpretes.id_interprete = morceaux.id_interprete\nWHERE interpretes.pays = \"\u00c9tats-Unis\"\n
Exercice 6
Exercice 2 du sujet La R\u00e9union J2 2022
Correction Correction Q1.Le couple (NumClient, NumChambre)
ne pouvait pas \u00eatre une cl\u00e9 primaire car un m\u00eame client peut revenir dans l'h\u00f4tel et avoir la m\u00eame chambre qu'\u00e0 un pr\u00e9c\u00e9dent s\u00e9jour. Le couple (NumClient, NumChambre)
ne serait donc pas unique et ne peut donc pas servir de cl\u00e9 primaire pour la relation Reservations
.
SELECT Nom, Prenom FROM Clients
Correction Q2.b. SELECT Telephone FROM Clients\nWHERE Prenom = \"Grace\" AND Nom = \"Hopper\"\n
Correction Q3. SELECT NumChambre FROM Reservations\nWHERE date(DateArr) <= date('2024-12-28')\nAND date(DateDep) > date('2024-12-28')\n
Correction Q4.a. UPDATE Chambres\nSET prix = 75\nWHERE NumChambre = 404\n
Correction Q4.b SELECT Reservations.NumChambre FROM Reservations\nJOIN Clients ON Clients.NumClient = Reservations.NumClient\nWHERE Clients.Nom = 'Codd' AND Clients.Prenom = 'Edgar'\n
"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/02_exercices_inter/","title":"Exercices SQL interactifs","text":"Exercice 1
Questions interactives \u00e0 r\u00e9aliser sur le site sqlzoo.net.
Q1. Travail sur SELECT, (base de donn\u00e9es Nobel) ici.
CorrectionCorrections extraites du d\u00e9p\u00f4t https://github.com/jisaw/sqlzoo-solutions.
/*\nThird section of sqlzoo, SELECT from Nobel\n*/\n\n--#1\n/*\nChange the query shown so that it displays Nobel prizes for 1950.\n*/\nSELECT yr, subject, winner\nFROM nobel\nWHERE yr = 1950\n\n--#2\n/*\nShow who won the 1962 prize for Literature.\n*/\nSELECT winner\nFROM nobel\nWHERE yr = 1962 AND subject = 'Literature'\n\n--#3\n/*\nShow the year and subject that won 'Albert Einstein' his prize.\n*/\nSELECT yr, subject\nFROM nobel\nWHERE winner = 'Albert Einstein'\n\n--#4\n/*\nGive the name of the 'Peace' winners since the year 2000, including 2000.\n*/\nSELECT winner\nFROM nobel\nWHERE subject = 'Peace' AND yr >= 2000\n\n--#5\n/*\nShow all details (yr, subject, winner) of the Literature prize winners for 1980 to 1989 inclusive\n*/\nSELECT yr, subject, winner\nFROM nobel\nWHERE (yr >=1980 AND yr <=1989) AND subject = 'Literature'\n\n--#6\n/*\nShow all details of the presidential winners:\n\nTheodore Roosevelt\nWoodrow Wilson\nJimmy Carter\n*/\nSELECT *\nFROM nobel\nWHERE winner IN ('Theodore Roosevelt', 'Woodrow Wilson', 'Jimmy Carter')\n\n--#7\n/*\nShow the winners with first name John\n*/\nSELECT winner\nFROM nobel\nWHERE winner LIKE 'john%'\n\n--#8\n/*\nShow the Physics winners for 1980 together with the Chemistry winners for 1984.\n*/\nSELECT *\nFROM nobel\nWHERE (subject = \"Physics\" AND yr = '1980') OR (subject = 'Chemistry' AND yr = 1984)\n\n--#9\n/*\nShow the winners for 1980 excluding the Chemistry and Medicine\n*/\nSELECT *\nFROM nobel\nWHERE yr = 1980 AND subject NOT IN ('Chemistry', 'Medicine')\n\n--#10\n/*\nShow who won a 'Medicine' prize in an early year (before 1910, not including 1910) together with winners of a 'Literature' prize in a later year (after 2004, including 2004)\n*/\nSELECT *\nFROM nobel\nWHERE (subject = 'Medicine' AND yr < 1910) OR (subject = 'Literature' AND yr >= 2004)\n\n--#11\n/*\nFind all details of the prize won by PETER GR\u00dcNBERG\n*/\nSELECT *\nFROM nobel\nWHERE winner LIKE 'peter gr%nberg'\n\n--#12\n/*\nFind all details of the prize won by EUGENE O'NEILL\n*/\nSELECT *\nFROM nobel\nWHERE winner = 'Eugene O''Neill'\n\n--#13\n/*\nKnights in order\n\nList the winners, year and subject where the winner starts with Sir. Show the the most recent first, then by name order.\n*/\nSELECT winner, yr, subject\nFROM nobel\nWHERE winner LIKE 'sir%'\nORDER BY yr DESC, winner\n\n--#14\n/*\nThe expression subject IN ('Chemistry','Physics') can be used as a value - it will be 0 or 1.\n\nShow the 1984 winners ordered by subject and winner name; but list Chemistry and Physics last.\n*/\nSELECT winner, subject, subject IN ('Physics','Chemistry')\nFROM nobel\nWHERE yr=1984\nORDER BY subject IN ('Physics','Chemistry'),subject,winner\n
Q2. Travail sur SUM et COUNT, (base de donn\u00e9es World) ici. (jusqu'\u00e0 la question 5.)
CorrectionCorrections extraites du d\u00e9p\u00f4t https://github.com/jisaw/sqlzoo-solutions.
/*\nFifth section of sqlzoo, SUM and COUNT\n*/\n\n\n--#1\n/*\nShow the total population of the world.\n*/\nSELECT SUM(population)\nFROM world\n\n--#2\n/*\nList all the continents - just once each.\n*/\nSELECT DISTINCT(continent)\nFROM world\n\n--#3\n/*\nGive the total GDP of Africa\n*/\nSELECT SUM(gdp)\nFROM world\nWHERE continent = 'Africa'\n\n--#4\n/*\nHow many countries have an area of at least 1000000\n*/\nSELECT COUNT(name)\nFROM world\nWHERE area >= 1000000\n\n--#5\n/*\nWhat is the total population of ('France','Germany','Spain')\n*/\nSELECT SUM(population)\nFROM world\nWHERE name IN ('France', 'Germany', 'Spain')\n\n--#6\n/*\nFor each continent show the continent and number of countries.\n*/\nSELECT continent, COUNT(name)\nFROM world\nGROUP BY continent\n\n\n--#7\n/*\nFor each continent show the continent and number of countries with populations of at least 10 million.\n*/\nSELECT continent, COUNT(name)\nFROM world\nWHERE population >= 10000000\nGROUP BY continent\n\n--#8\n/*\nList the continents that have a total population of at least 100 million.\n*/\nSELECT continent\nFROM world\nGROUP BY continent\nHAVING SUM(population) > 100000000\n
Q3. Travail sur JOIN, (base de donn\u00e9es Euro2012) ici.
correction/*\nSixth section of sqlzoo, Join\n*/\n\n\n--#1\n/*\nThe first example shows the goal scored by 'Bender'.\n\nShow matchid and player name for all goals scored by Germany.\n*/\nSELECT matchid, player FROM goal\nWHERE teamid = 'GER'\n\n--#2\n/*\nFrom the previous query you can see that Lars Bender's goal was scored in game 1012. Notice that the column matchid in the goal table corresponds to the id column in the game table.\n\nShow id, stadium, team1, team2 for game 1012\n*/\nSELECT id,stadium,team1,team2\nFROM game\nWHERE id = 1012\n\n--#3\n/*\nYou can combine the two steps into a single query with a JOIN. You will get all the game details and all the goal details if you use\n\nSELECT *\n FROM game JOIN goal ON (id=matchid)\nShow the player, teamid and mdate and for every German goal. teamid='GER'\n*/\nSELECT player, teamid, mdate\nFROM game\nJOIN goal ON (id=matchid AND teamid='GER')\n\n--#4\n/*\nUse the same JOIN as in the previous question.\n\nShow the team1, team2 and player for every goal scored by a player called Mario player LIKE 'Mario%'\n*/\nSELECT team1, team2, player\nFROM game\nJOIN goal ON (id=matchid AND player LIKE 'Mario%')\n\n--#5\n/*\nThe table eteam gives details of every national team including the coach. You can JOIN goal to eteam using the phrase goal JOIN eteam on teamid=id\n\nShow player, teamid, coach, gtime for all goals scored in the first 10 minutes gtime<=10\n*/\nSELECT player, teamid, coach, gtime\nFROM goal\nJOIN eteam ON (teamid=id AND gtime<=10)\n\n--#6\n/*\nTo JOIN game with eteam you could use either\ngame JOIN eteam ON (team1=eteam.id) or game JOIN eteam ON (team2=eteam.id)\n\nNotice that because id is a column name in both game and eteam you must specify eteam.id instead of just id\n\nList the the dates of the matches and the name of the team in which 'Fernando Santos' was the team1 coach.\n*/\nSELECT mdate, teamname\nFROM game\nJOIN eteam ON (team1=eteam.id AND coach LIKE '%Santos')\n\n--#7\n/*\nList the player for every goal scored in a game where the stadium was 'National Stadium, Warsaw'\n*/\nSELECT player\nFROM goal\nJOIN game ON (id=matchid AND stadium = 'National Stadium, Warsaw')\n\n--#8\n/*\nThe example query shows all goals scored in the Germany-Greece quarterfinal.\nInstead show the name of all players who scored a goal against Germany.\n*/\nSELECT DISTINCT(player)\nFROM game\nJOIN goal ON matchid = id\nWHERE ((team1='GER' OR team2='GER') AND teamid != 'GER')\n\n--#9\n/*\nShow teamname and the total number of goals scored.\n*/\nSELECT teamname, COUNT(player)\nFROM eteam\nJOIN goal ON id=teamid\nGROUP BY teamname\n\n--#10\n/*\nShow the stadium and the number of goals scored in each stadium.\n*/\nSELECT stadium, COUNT(player) AS goals\nFROM game\nJOIN goal ON (id=matchid)\nGROUP BY stadium\n\n--#11\n/*\nFor every match involving 'POL', show the matchid, date and the number of goals scored.\n*/\nSELECT matchid, mdate, COUNT(player) AS goals\nFROM game\nJOIN goal ON (matchid=id AND (team1 = 'POL' OR team2 = 'POL'))\nGROUP BY matchid, mdate\n\n--#12\n/*\nFor every match where 'GER' scored, show matchid, match date and the number of goals scored by 'GER'\n*/\nSELECT id, mdate, COUNT(player)\nFROM game\nJOIN goal ON (id=matchid AND (team1 = 'GER' OR team2 = 'GER') AND teamid='GER')\nGROUP BY id, mdate\n\n--#13\n/*\nList every match with the goals scored by each team as shown. This will use \"CASE WHEN\" which has not been explained in any previous exercises.\nmdate team1 score1 team2 score2\n1 July 2012 ESP 4 ITA 0\n10 June 2012 ESP 1 ITA 1\n10 June 2012 IRL 1 CRO 3\n...\nNotice in the query given every goal is listed. If it was a team1 goal then a 1 appears in score1, otherwise there is a 0.\nYou could SUM this column to get a count of the goals scored by team1. Sort your result by mdate, matchid, team1 and team2.\n*/\nSELECT mdate,\nteam1,\nSUM(CASE WHEN teamid = team1 THEN 1 ELSE 0 END) AS score1,\nteam2,\nSUM(CASE WHEN teamid = team2 THEN 1 ELSE 0 END) AS score2 FROM\ngame LEFT JOIN goal ON (id = matchid)\nGROUP BY mdate,team1,team2\nORDER BY mdate, matchid, team1, team2\n
Exercice 2
Gestion d'un r\u00e9seau d'agences de location de voitures. D'apr\u00e8s le travail de J. Le Coupanec (Acad\u00e9mie de Rennes)
La base de donn\u00e9es locations.db contient les tables Agences
,Locations
, Vehicules
.
Agences
Q1. Visualisez toute la relation Agences
SELECT * FROM Agences\n
Q2. Listez uniquement les noms des agences et de leur ville.
CorrectionSELECT nom, ville FROM Agences\n
Q3. Listez les noms des agences de la ville de Lorient
CorrectionSELECT nom FROM Agences\nWHERE ville = 'Lorient'\n
Q4. Listez les noms des agences du d\u00e9partement du Morbihan (code postal 56***) ainsi que les codes postaux en utilisant par exemple un WHERE LIKE
.
SELECT nom FROM Agences\nWHERE code LIKE '56%'\n
Questions sur la relation Vehicules
Q5. D\u00e9terminez le nombre de voitures que vous poss\u00e9dez.
CorrectionSELECT COUNT(*) FROM Vehicules\n
Q6. D\u00e9terminez l'\u00e2ge minimum et maximum de vos v\u00e9hicules.
CorrectionSELECT MAX(age), MIN(age) FROM Vehicules\n
Q7. Quels sont la marque et le mod\u00e8le de votre derni\u00e8re acquisition qui date de trois mois ?
CorrectionSELECT nom FROM Vehicules\nWHERE age = 3\n
Q8. Quel est le kilom\u00e9trage maximum des v\u00e9hicules ?
CorrectionSELECT MAX(kilometrage) FROM Vehicules\n
Q9. Quel est le kilom\u00e9trage moyen des v\u00e9hicules ?
CorrectionSELECT AVG(kilometrage) FROM Vehicules\n
Q10. Afficher toute la flotte de v\u00e9hicules par ordre d\u00e9croissant de kilom\u00e9trage.
CorrectionSELECT * FROM Vehicules\nORDER BY kilometrage DESC\n
Questions sur la relation Locations
Q11. Visualisez toute la relation Locations.
CorrectionSELECT * FROM Locations\n
Q12. D\u00e9terminez le nombre de locations effectu\u00e9es avec changement d'agence
CorrectionSELECT COUNT(*) FROM Locations\nWHERE depart != retour\n
Q13. D\u00e9terminez le nombre total de kilom\u00e8tres effectu\u00e9s durant les locations
CorrectionSELECT SUM(distance) FROM Locations\n
Q14. Listez toutes les locations en y associant les caract\u00e9ristiques du v\u00e9hicule
CorrectionSELECT * FROM Locations\nJOIN Vehicules ON Locations.vehicule = Vehicules.immatriculation\n
Q15. Affichez le nom et l'immatriculation du v\u00e9hicule ainsi que la date de la location et le kilom\u00e9trage r\u00e9alis\u00e9 pour chacune des locations
CorrectionSELECT Vehicules.nom, Vehicules.immatriculation, Locations.date, Locations.kilometrage FROM Locations\nJOIN Vehicules ON Locations.vehicule = Vehicules.immatriculation\n
Q16. Affichez une seule fois le nom et l'immatriculation des v\u00e9hicules ayant d\u00e9j\u00e0 \u00e9t\u00e9 lou\u00e9s.
CorrectionSELECT DISTINCT nom, immatriculation FROM Locations\nJOIN Vehicules ON Locations.vehicule = Vehicules.immatriculation\n
Q17. Affichez les locations du v\u00e9hicule immatricul\u00e9 AB-224-BA en pr\u00e9cisant le nom de l'agence de d\u00e9part ainsi que la ville de d\u00e9part dans l'ordre chronologique des locations.
CorrectionSELECT Agences.nom, Agences.ville, Locations.* FROM Locations\nJOIN Agences ON Locations.depart = Agences.id\nWHERE vehicule = 'AB-224-BA'\nORDER BY Locations.date\n
Exercice 3
Championnat de France de Football 2015-2016
D'apr\u00e8s le travail de J. Le Coupanec (Acad\u00e9mie de Rennes)
La base de donn\u00e9es soccer.db contient les tables Team
,Match
, Event
, Player
.
Q1. Combien d'\u00e9quipes ont particip\u00e9 \u00e0 ce championnat ?
CorrectionSELECT COUNT(*) FROM Team\n
Q2. Listez les noms des clubs ainsi que leur date de cr\u00e9ation dans l'ordre chronologique de leur cr\u00e9ation.
CorrectionSELECT name, birthday FROM Team\nORDER BY birthday\n
Q3. Combien de p\u00e9naltys ont \u00e9t\u00e9 marqu\u00e9s ?
CorrectionSELECT COUNT(*) FROM Event\nWHERE type='penalty'\n
Q4. Combien de p\u00e9naltys ont \u00e9t\u00e9 siffl\u00e9s ?
CorrectionSELECT COUNT(*) FROM Event\nWHERE type IN ('penalty','miss')\n
Q5. Combien de cartons ont \u00e9t\u00e9 distribu\u00e9s ?
CorrectionSELECT COUNT(*) FROM Event\nWHERE type IN ('red','yellow2','yellow')\n
Q6. Combien de buts ont \u00e9t\u00e9 marqu\u00e9s ?
CorrectionSELECT COUNT(*) FROM Event\nWHERE type IN ('goal','own','penalty')\n
Q7. Affichez tous les renseignements sur les 10 cartons rouges obtenus le plus rapidement pendant un match.
CorrectionSELECT * FROM Event\nWHERE type = 'red'\nORDER BY time\nLIMIT 10\n
Q8. Donnez le nom du joueur qui a obtenu le carton rouge le plus rapidement.
CorrectionSELECT name from Player\nWHERE id=392\n
Exercice 4
Cet exercice en ligne est propos\u00e9 le Knight Lab de l'universit\u00e9 am\u00e9ricaine Northwerstern University.
Le point de d\u00e9part de l'histoire : un meurtre a \u00e9t\u00e9 commis dans la ville de SQL City le 15 janvier 2018.
\u00c0 partir de ce point de d\u00e9part et d'une base de donn\u00e9es dont le diagramme est donn\u00e9 ci-dessous, il s'agit de trouver le meurtrier.
Zone d'enqu\u00eate (\u00e0 coups de requ\u00eates)Il est conseill\u00e9 de travailler avec un Bloc-Notes ouvert \u00e0 c\u00f4t\u00e9 afin d'y coller les renseignements obtenus.
Tapez votre requ\u00eate ci-dessous Ex\u00e9cuter Vous pensez avoir trouv\u00e9 le meurtrier ?Copiez la requ\u00eate
INSERT INTO solution VALUES (1, 'nom du meurtrier');\nSELECT value FROM solution;\n
dans le champ ci-dessous : Ex\u00e9cuter Sur la page officielle, vous pouvez \u00eatre guid\u00e9s \u00e9tape par \u00e9tape jusqu'\u00e0 la recherche du meurtrier (qui n'est pas la fin de l'\u00e9nigme !)
Vous pouvez si vous le souhaitez t\u00e9l\u00e9charger la base sql-murder-mystery.db.
Vous pouvez trouver des \u00e9l\u00e9ments de correction ici...
Nous allons cr\u00e9er et interroger une base de donn\u00e9es sqlite
avec le module sqlite3
de Python.
import sqlite3\n\n#Connexion\nconnexion = sqlite3.connect('mynewbase.db')\n\n#R\u00e9cup\u00e9ration d'un curseur\nc = connexion.cursor()\n\n# ---- d\u00e9but des instructions SQL\n\n#Cr\u00e9ation de la table\nc.execute(\"\"\"\n CREATE TABLE IF NOT EXISTS bulletin(\n Nom TEXT,\n Pr\u00e9nom TEXT,\n Note INT);\n \"\"\")\n\n# ---- fin des instructions SQL\n\n#Validation\nconnexion.commit()\n\n\n#D\u00e9connexion\nconnexion.close()\n
mynewbase.db
sera cr\u00e9\u00e9 dans le m\u00eame r\u00e9pertoire que le fichier source Python. Si fichier existe d\u00e9j\u00e0, il est ouvert et peut \u00eatre modifi\u00e9.IF NOT EXISTS
assure de ne pas \u00e9craser une table existante qui porterait le m\u00eame nom. Si une telle table existe, elle n'est alors pas modifi\u00e9e.DB Browser
pour v\u00e9rifier sa structure et ses donn\u00e9es.Les morceaux de code ci-dessous sont \u00e0 positionner entre les balises # ---- d\u00e9but des instructions SQL
et # ---- fin des instructions SQL
.
c.execute('''INSERT INTO bulletin VALUES ('Simpson', 'Bart', 17)''')\n
Pensez \u00e0 v\u00e9rifier avec DB Browser
si les modifications sont effectives.
data = ('Simpson', 'Maggie', 2)\nc.execute('''INSERT INTO bulletin VALUES (?,?,?)''', data)\n
"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/03_python_et_SQL/#123-insertion-de-multiples-enregistrements","title":"1.2.3 Insertion de multiples enregistrements","text":"lst_notes = [ ('Simpson', 'Lisa', 19), ('Muntz', 'Nelson', 4), ('Van Houten', 'Milhouse', 12) ]\n\nc.executemany('''INSERT INTO bulletin VALUES (?, ?, ?)''', lst_notes)\n
Les diff\u00e9rentes valeurs sont stock\u00e9es au pr\u00e9alable dans une liste de tuples."},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/03_python_et_SQL/#13-mini-projet-1","title":"1.3 Mini-projet 1","text":"Cr\u00e9er un programme qui demande \u00e0 l'utilisateur un nom et une note, en boucle. Les r\u00e9sultats sont stock\u00e9s au fur et \u00e0 mesure dans une base de donn\u00e9es. Si le nom est \u00e9gal \u00e0 \u00abQ\u00bb ou \u00abq\u00bb, le programme s'arr\u00eate.
"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/03_python_et_SQL/#14-exemple-dinjection-sql","title":"1.4 \u2620 Exemple d'injection SQL","text":"L'injection SQL est une technique consistant \u00e0 \u00e9crire du code SQL \u00e0 un endroit qui n'est pas cens\u00e9 en recevoir.
https://xkcd.com/327/
Cr\u00e9ez un fichier contenant le code suivant :
import sqlite3\n\n#Connexion\nconnexion = sqlite3.connect('mabasecobaye.db')\n\n#R\u00e9cup\u00e9ration d'un curseur\nc = connexion.cursor()\n\nc.execute(\"\"\"\n CREATE TABLE IF NOT EXISTS notes(\n Nom TEXT,\n Note INT);\n \"\"\")\n\n\nwhile True :\n nom = input('Nom ? ')\n if nom in ['Q','q'] :\n break\n note = input('Note ? ')\n data = (nom, note)\n p = \"INSERT INTO notes VALUES ('\" + nom + \"','\" + note + \"')\"\n\n c.executescript(p)\n\n\n#Validation\nconnexion.commit()\n\n\n#D\u00e9connexion\nconnexion.close()\n
Ex\u00e9cutez ce fichier, rentrez quelques valeurs, quittez, et ouvrez dans DB Browser
la table notes
pour bien v\u00e9rifier que vos valeurs ont bien \u00e9t\u00e9 stock\u00e9es.
g','3'); DROP TABLE notes;--
notes
n'existe plus !Explication : La requ\u00eate qui a \u00e9t\u00e9 formul\u00e9e est INSERT INTO notes VALUES ('g','3'); DROP TABLE notes;--','12')
Dans un premier temps, le couple ('g','3')
a \u00e9t\u00e9 ins\u00e9r\u00e9. Puis l'ordre a \u00e9t\u00e9 donn\u00e9 de d\u00e9truire la table notes
. Le reste du code (qui n'est pas correct) est ignor\u00e9 car --
est le symbole du commentaire en SQL (l'\u00e9quivalent du # de Python).
Remarques : \u00c9videmment, ce code a \u00e9t\u00e9 fait sp\u00e9cifiquement pour \u00eatre vuln\u00e9rable \u00e0 l'injection SQL. Il suffit d'ailleurs de remplacer le c.executescript(p)
par c.execute(p)
pour que le code reste fonctionnel mais refuse l'injection SQL. Ceci dit, de nombreux serveurs sont encore attaqu\u00e9s par cette technique, au prix de manipulations bien s\u00fbr plus complexes que celles que nous venons de voir (vous pouvez par exemple regarder ici).
Rappelons enfin que ce genre de pratiques est interdit sur un serveur qui ne vous appartient pas.
"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/03_python_et_SQL/#2-lecture-des-enregistrements","title":"2. Lecture des enregistrements","text":"import sqlite3\n\n#Connexion\nconnexion = sqlite3.connect('mynewbase.db')\n\n#R\u00e9cup\u00e9ration d'un curseur\nc = connexion.cursor()\n\ndata = ('Simpson', )\n\nc.execute(\"SELECT Pr\u00e9nom FROM Bulletin WHERE Nom = ?\", data)\nprint(c.fetchall()) \n\n\n#D\u00e9connexion\nconnexion.close()\n
Ce code renvoie [('Homer',), ('Lisa',), ('Maggie',)]
, ou une liste vide s'il n'y a pas de r\u00e9sultat \u00e0 la requ\u00eate.
Reprendre le mini-projet pr\u00e9c\u00e9dent, en rendant possible \u00e0 l'utilisateur de rentrer des notes ou bien de les consulter.
Exemple :
"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/03_python_et_SQL/#23-mini-projet-3","title":"2.3 Mini-projet 3","text":"Cr\u00e9er un syst\u00e8me d'authenfication par login / mot de passe, dans le but de conserver une phrase secr\u00e8te.
Id\u00e9alement le mot de passe ne sera pas conserv\u00e9 en clair mais hach\u00e9.
Exemple :
lien vers une correction
"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/cours/","title":"Langage SQL","text":""},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/cours/#0-du-modele-relationnel-au-sgbd","title":"0. Du mod\u00e8le relationnel au SGBD","text":"Les consid\u00e9rations sur le mod\u00e8le relationnel du cours pr\u00e9c\u00e9dent traitaient plut\u00f4t de la structure math\u00e9matique des donn\u00e9es.
Il s'agissait de d\u00e9terminer la meilleure structure pour repr\u00e9senter les donn\u00e9es et les relations qui les lient.
Il convient maintenant d'aborder la partie logicielle : les SGBD (Syst\u00e8mes de Gestion de Bases de Donn\u00e9es).
Les SGBD jouent le r\u00f4le d'interface entre l'\u00eatre humain et la base de donn\u00e9es. Par l'interm\u00e9diaire de requ\u00eates, l'utilisateur va consulter ou modifier la base de donn\u00e9es. Le SGBD est garant de l'int\u00e9grit\u00e9 de cette base, et pr\u00e9vient notamment que les modifications (souvent appel\u00e9es transactions) ne soient pas pr\u00e9judiciables \u00e0 la base de donn\u00e9es.
Le langage utilis\u00e9 pour communiquer avec le SGBD est le langage SQL, pour Structured Query Langage (pour langage de requ\u00eates structur\u00e9es).
Les SGBD les plus utilis\u00e9s sont bas\u00e9s sur le mod\u00e8le relationnel. Parmi eux, citons Oracle, MySQL, Microsoft SQL Server, PostgreSQL, Microsoft Access, SQLite, MariaDB...
Mais de plus en plus de SGBD non-relationnels sont utilis\u00e9s, sp\u00e9cialement adapt\u00e9s \u00e0 des donn\u00e9es plus diverses et moins structur\u00e9es. On les retrouve sous l'appelation NoSQL (pour Not only SQL). Citons parmi eux MongoDB, Cassandra (Facebook), BigTable (Google)...
La quasi-totalit\u00e9 de ces SGBD fonctionnent avec un mod\u00e8le client-serveur.
Nous allons travailler principalement avec le langage SQLite peut lui s'utiliser directement sans d\u00e9marrer un serveur : la base de donn\u00e9es est enti\u00e8rement repr\u00e9sent\u00e9e dans le logiciel utilisant SQLite (dans notre cas, DB Browser for SQLite). Sa simplicit\u00e9 d'utilisation en fera notre choix pour illustrer cette pr\u00e9sentation du langage SQL.
"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/cours/#1-introduction-au-langage-sql","title":"1. Introduction au langage SQL","text":"Dans toute la suite, nous allons travailler avec la base de donn\u00e9es livres.db
qui provient de l'ouvrage paru chez Ellipses, cit\u00e9 en bibliographie.
Pr\u00e9-requis : t\u00e9l\u00e9chargez la base de donn\u00e9es livres.db.
1. En ligne avecsqliteonline.com
livres.db
pr\u00e9c\u00e9demment t\u00e9l\u00e9charg\u00e9.2. Avec un logiciel externe : DB Browser for SQLite
DB Browser for SQLite
, t\u00e9l\u00e9chargeable \u00e0 l'adresse https://sqlitebrowser.org/livres.db
. Dans toute la suite, les manipulations sont \u00e0 faire en interrogeant la base de donn\u00e9es livres.db
, avec l'une des m\u00e9thodes indiqu\u00e9es ci-dessus.
Voici le diagramme relationnel de cette base :
Requ\u00eate basique : SELECT, FROM
SELECT titre\nFROM livre ;\n
On veut tous les titres de la table \u00ablivre\u00bb.
Remarques
Les mots-cl\u00e9s SQL sont traditionnellement \u00e9crits en MAJUSCULES.
Le ;
signale la fin de l'instruction. Il peut donc \u00eatre omis s'il n'y a pas d'instructions encha\u00een\u00e9es (ce qui sera toujours notre cas).
L'indentation n'est pas syntaxique (pas comme en Python). On peut faire des retours \u00e0 la ligne et des indentations pour rendre le code plus lisible.
Requ\u00eate filtr\u00e9e : SELECT, FROM, WHERE
SELECT titre FROM livre WHERE annee >= 1990;\n
On veut les titres de la table \u00ablivre\u00bb qui sont parus apr\u00e8s (ou en ) 1990;
Le mot-cl\u00e9 WHERE doit \u00eatre suivi d'un bool\u00e9en. Les op\u00e9rateurs classiques =
, !=
, >
, >=
, <
, <=
peuvent \u00eatre utilis\u00e9s, mais aussi le mot-cl\u00e9 IN :
Requ\u00eate avec plusieurs possibilit\u00e9s : WHERE ... IN...
SELECT titre FROM livre WHERE annee IN (1990, 1991, 1992);\n
On veut les titres de la table \u00ablivre\u00bb qui sont parus en 1990, 1991 ou 1992.
Requ\u00eate avec bool\u00e9ens : AND - OR
SELECT titre FROM livre WHERE annee >= 1970\nAND annee <= 1980\nAND editeur = 'Dargaud';\n
On veut les titres de la table \u00ablivre\u00bb qui sont parus entre 1970 et 1980 chez l'\u00e9diteur Dargaud;
Requ\u00eate approch\u00e9e : LIKE
SELECT titre FROM livre WHERE titre LIKE '%Ast\u00e9rix%';\n
On veut les titres de la table \u00ablivre\u00bb dont le titre contient la cha\u00eene de caract\u00e8res \"Ast\u00e9rix\". Le symbole %
est un joker qui peut symboliser n'importe quelle cha\u00eene de caract\u00e8res.
Plusieurs colonnes
SELECT titre, isbn FROM livre WHERE annee >= 1990;\n
On veut les titres et les ISBN de la table \u00ablivre\u00bb qui sont parus apr\u00e8s 1990.
Toutes les colonnes : *
SELECT * FROM livre WHERE annee >= 1990;\n
On veut toutes les colonnes disponibles de la table \u00ablivre\u00bb pour les livres qui sont parus apr\u00e8s 1990. L'ast\u00e9risque *
est un joker (wildcard en anglais).
Renommer les colonnes : AS
SELECT titre AS titre_du_livre FROM livre WHERE annee >= 1990;\n
Lors de l'affichage du r\u00e9sulats et dans la suite de la requ\u00eate (important), la colonne \"titre\" est renomm\u00e9e \"titre_du_livre\".
Remarque L'alias AS
sera souvent utilis\u00e9 pour raccourcir un nom, notamment lors des jointures de plusieurs tables (voir plus loin).
Les requ\u00eates effectu\u00e9es jusqu'ici ont juste s\u00e9lectionn\u00e9 des donn\u00e9es gr\u00e2ce \u00e0 diff\u00e9rents filtres : aucune action \u00e0 partir de ces donn\u00e9es n'a \u00e9t\u00e9 effectu\u00e9e. Nous allons maintenant effectuer des op\u00e9rations \u00e0 partir des donn\u00e9es s\u00e9lectionn\u00e9es. On appelle ces op\u00e9rations des op\u00e9rations d'agr\u00e9gation.
"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/cours/#121-exemple-7","title":"1.2.1 Exemple 7","text":"Compter : COUNT
SELECT COUNT(*) AS total FROM livre\nWHERE titre LIKE \"%Ast\u00e9rix%\";\n
On veut compter le nombre d'enregistrements de la tables livres comportant le mot \"Ast\u00e9rix\". Le r\u00e9sultat sera le seul \u00e9l\u00e9ment d'une colonne nomm\u00e9e \u00abtotal\u00bb.
Additionner : SUM
SELECT SUM(annee) AS somme\nFROM livre\nWHERE titre LIKE \"%Ast\u00e9rix%\";\n
On veut additionner les ann\u00e9es des livres de la tables livres comportant le mot \"Ast\u00e9rix\". Le r\u00e9sultat sera le seul \u00e9l\u00e9ment d'une colonne nomm\u00e9e \u00absomme\u00bb. Attention : dans notre cas pr\u00e9cis, ce calcul n'a aucun sens...
Faire une moyenne : AVG
SELECT AVG(annee) AS moyenne\nFROM livre\nWHERE titre LIKE \"%Ast\u00e9rix%\";\n
On veut calculer la moyenne des ann\u00e9es de parution des livres de la table livres comportant le mot \"Ast\u00e9rix\". Le r\u00e9sultat sera le seul \u00e9l\u00e9ment d'une colonne nomm\u00e9e \u00abmoyenne\u00bb. Attention : l\u00e0 encore, ce calcul n'a aucun sens...
Trouver les extremums : MIN, MAX
SELECT MIN(annee) AS minimum\nFROM livre\nWHERE titre LIKE \"%Ast\u00e9rix%\";\n
On veut trouver la plus petite valeur de la colonne \u00abannee\u00bb parmi les livres de la tables livre comportant le mot \"Ast\u00e9rix\". Le r\u00e9sultat sera le seul \u00e9l\u00e9ment d'une colonne nomm\u00e9e minimum. Le fonctionnement est identique avec MAX pour la recherche du maximum.
Classer des valeurs : ORDER BY, ASC, DESC, LIMIT
Commande :
SELECT titre, annee FROM livre\nWHERE titre LIKE \"%Ast\u00e9rix%\"\nORDER BY annee DESC;\n
Traduction :
On veut afficher tous les albums d'Ast\u00e9rix, et leur ann\u00e9e de parution, class\u00e9s par ann\u00e9e d\u00e9croissante.
Comportement par d\u00e9faut : Si le param\u00e8tre ASC ou DESC est omis, le classement se fait par ordre croissant (donc ASC est le param\u00e8tre par d\u00e9faut).
Utilisation de LIMIT : Le mot-cl\u00e9 LIMIT (suivi d'un nombre) permet de limiter le nombre de r\u00e9sultats affich\u00e9s. Ainsi la requ\u00eate
SELECT titre, annee FROM livre\nWHERE titre LIKE \"%Ast\u00e9rix%\"\nORDER BY annee DESC\nLIMIT 1;\n
permet d'obtenir les renseignements sur l'Ast\u00e9rix le plus r\u00e9cent. Suppression des doublons : DISTINCT
SELECT DISTINCT editeur FROM livre;\n
On veut la liste de tous les \u00e9diteurs. Sans le mot-cl\u00e9 DISTINCT
, beaucoup de doublons appara\u00eetraient.
Observons le contenu de la table \u00abemprunt\u00bb :
SELECT * FROM emprunt;\n
Le contenu est peu lisible : qui a emprunt\u00e9 quel livre ? Souvenons-nous du diagramme de la base de donn\u00e9es.
Pour que la table \u00abemprunt\u00bb soit lisible, il faudrait (dans un premier temps) que l'on affiche \u00e0 la place de l'ISBN le titre de l'ouvrage. Or ce titre est disponible dans la table \u00ablivres\u00bb. On va donc proc\u00e9der \u00e0 une jointure de ces deux tables.
"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/cours/#131-exemple-13","title":"1.3.1 Exemple 13","text":"Jointure de 2 tables : JOIN
SELECT livre.titre, emprunt.code_barre, emprunt.retour FROM emprunt\nJOIN livre ON emprunt.isbn = livre.isbn;\n
L'expression
JOIN livre ON emprunt.isbn = livre.isbn\n
doit se comprendre comme ceci : on \u00abinvite\u00bb la table \u00ablivres\u00bb (dont on va afficher la colonne \u00abtitre\u00bb). La correspondance entre la table \u00ablivres\u00bb et la table \u00abemprunt\u00bb doit se faire sur l'attribut ISBN, qui est la cl\u00e9 primaire de \u00ablivres\u00bb et une cl\u00e9 \u00e9trang\u00e8re d'\u00abemprunts\u00bb. Il est donc tr\u00e8s important de sp\u00e9cifier ce sur quoi les deux tables vont se retrouver (ici, l'ISBN) Le r\u00e9sultat pr\u00e9c\u00e9dent a permis d'am\u00e9liorer la visibilit\u00e9 de la table \u00abemprunt\u00bb, mais il reste la colonne \u00abcode_barre\u00bb qui est peu lisible. Nous pouvons la remplacer par le titre du livre, en faisant une nouvelle jointure, en invitant maintenant les deux tables \u00ablivre\u00bb et \u00abusager\u00bb.
Jointure de 3 tables : JOIN
SELECT u.nom, u.prenom, l.titre, e.retour FROM emprunt AS e\nJOIN livre AS l ON e.isbn = l.isbn\nJOIN usager AS u ON e.code_barre = u.code_barre;\n
Traduction : Il faut bien comprendre que la table principale qui nous int\u00e9resse ici est \u00abemprunts\u00bb, mais qu'on modifie les valeurs affich\u00e9es en allant chercher des correspondances dans deux autres tables. Notez ici que des alias sont donn\u00e9s aux tables (par AS) afin de faciliter l'\u00e9criture.
R\u00e9sultat :
Cet exercice en ligne est propos\u00e9 le Knight Lab de l'universit\u00e9 am\u00e9ricaine Northwerstern University.
Le point de d\u00e9part de l'histoire : un meurtre a \u00e9t\u00e9 commis dans la ville de SQL City le 15 janvier 2018.
\u00c0 partir de ce point de d\u00e9part et d'une base de donn\u00e9es dont le diagramme est donn\u00e9 ci-dessous, il s'agit de trouver le meurtrier.
Rendez-vous sur cette page, et bonne enqu\u00eate \u00e0 coups de requ\u00eates !
Vous pouvez travailler en ligne ou bien dans votre SGBD pr\u00e9f\u00e9r\u00e9, avec la base sql-murder-mystery.db. Attention pour valider votre r\u00e9ponse, il faudra vous rendre en bas de la page officielle.
Vous pouvez trouver des \u00e9l\u00e9ments de correction ici...
rappel :
L'objectif est de cr\u00e9er la table suivante :
id Nom Maths Anglais NSI 1 Alice 16 11 17 2 Bob 12 15 10 3 Charles 9 11 18"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/cours/#21-exemple-15","title":"2.1 Exemple 15","text":"La cr\u00e9ation d'une table n'est pas explicitement au programme de NSI. Personne ne sait vraiment pourquoi
Cr\u00e9ation d'une table : CREATE TABLE
CREATE TABLE Table_notes (\nId INTEGER PRIMARY KEY,\nNom TEXT,\nMaths INTEGER,\nAnglais INTEGER,\nNSI INTEGER\n);\n
Remarque : C'est l'utilisateur qui sp\u00e9cifie, \u00e9ventuellement, quel attribut sera une cl\u00e9 primaire.
R\u00e9sultat : Dans DB Browser, il faut avoir au pr\u00e9alable cr\u00e9\u00e9 une nouvelle base de donn\u00e9es.
Insertion de valeurs : INSERT INTO, VALUES
Commande :
INSERT INTO Table_notes VALUES (1, 'Alice', 16, 11, 17),\n(2, 'Bob', 12, 15, 10),\n(3, 'Charles', 9, 11, 18);\n
R\u00e9sultat :
Essayons d'ins\u00e9rer un 4\u00e8me enregistrement ayant le m\u00eame id
qu'un autre \u00e9l\u00e8ve.
Commande :
INSERT INTO Table_notes VALUES (3, 'Denis', 18, 10, 12);\n
R\u00e9sultat : La contrainte de relation est viol\u00e9e : le SGBD \u00abprot\u00e8ge\u00bb la base de donn\u00e9es en n'acceptant pas la proposition d'insertion. La base de donn\u00e9es n'est pas modifi\u00e9e.
Remarque : Il est possible de \u00abd\u00e9l\u00e9guer\u00bb la gestion des valeurs de la cl\u00e9 primaire avec l'instruction AUTOINCREMENT
. La d\u00e9claration de la table et l'insertion des valeurs serait :
CREATE TABLE Table_notes (\nId INTEGER PRIMARY KEY AUTOINCREMENT,\nNom TEXT,\nMaths INTEGER,\nAnglais INTEGER,\nNSI INTEGER\n);\n\nINSERT INTO Table_notes (Nom, Maths, Anglais, NSI) VALUES\n('Alice', 16, 11, 17),\n('Bob', 12, 15, 10),\n('Charles', 9, 11, 18);\n
et le r\u00e9sultat serait : L'attribut id
est donc g\u00e9r\u00e9 automatiquement par le SGBD.
Modification d'une valeur UPDATE, SET
Pour modifier la note de Maths d'Alice :
UPDATE Table_notes SET Maths = 18 WHERE Nom = 'Alice';\n
Suppression d'un enregistrement : DELETE
Pour supprimer totalement la ligne concernant Charles :
DELETE FROM Table_notes WHERE Nom = 'Charles';\n
Si une autre table contient par exemple l'attribut id
comme cl\u00e9 \u00e9trang\u00e8re, et si l'id
de Charles fait partie de cette table, le SGBD refusera de supprimer cette ligne, afin de ne pas violer la contrainte de r\u00e9f\u00e9rence.
Suppression totale d'une table : DROP TABLE
Pour supprimer totalement et d\u00e9fitivement la table :
DROP TABLE Table_notes;\n
L\u00e0 encore, si une autre table est reli\u00e9e \u00e0 Table_notes
par une cl\u00e9 \u00e9trang\u00e8re, la suppression sera bloqu\u00e9e par le SGBD.
\u00e0 venir...
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/","title":"Syst\u00e8mes sur puce","text":"pr\u00e9ambule : cours de Premi\u00e8re sur l'architecture Von Neumann
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#1-loi-de-moore-et-miniaturisation-progressive","title":"1. Loi de Moore et miniaturisation progressive","text":""},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#11-la-loi-de-moore","title":"1.1 La Loi de Moore","text":"En 1965, Gordon Moore postule que le nombre de transistors pr\u00e9sents sur une puce de microprocesseur doublera tous les deux ans.
Cette pr\u00e9diction s'est r\u00e9v\u00e9l\u00e9e \u00e9tonnamment juste (\u00e0 quelques approximations pr\u00e8s) et les \u00e9quipements \u00e9lectroniques n'ont depuis jamais cess\u00e9 de devenir toujours plus performants / miniatures / \u00e9conomes en \u00e9nergie.
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#12-evolution-de-la-taille-des-ordinateurs","title":"1.2 \u00c9volution de la taille des ordinateurs","text":""},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#121-ibm-650-le-premier-ordinateur-fabrique-en-serie-1955","title":"1.2.1 IBM 650, le premier ordinateur fabriqu\u00e9 en s\u00e9rie (1955)","text":"Cet ordinateur n'a pas encore de transistors mais des tubes \u00e0 vide.
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#122-ibm-7090-le-premier-ordinateur-a-transistors-1959","title":"1.2.2 IBM 7090, le premier ordinateur \u00e0 transistors (1959)","text":"Le transistor
Le transistor est un composant \u00e9lectronique essentiel : il permet de laisser (ou non) passer un courant \u00e9lectrique.
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#123-le-role-crucial-de-la-taille-des-transistors","title":"1.2.3 Le r\u00f4le crucial de la taille des transistors","text":"Ainsi que l'avait pr\u00e9dit Moore, c'est la progression du nombre de transistors gravables sur le processeur qui guidera pendant des ann\u00e9es l'\u00e9volution de l'informatique :
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#2-composition-dun-pc-actuel","title":"2. Composition d'un pc actuel","text":"Chaque composant a un r\u00f4le sp\u00e9cifique. Ils communiquent entre eux par des bus de diff\u00e9rentes vitesses. Chaque composant est rempla\u00e7able, et il est possible d'ajouter de nouveaux composants sur la carte m\u00e8re qui poss\u00e8de des slots d'extension.
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#3-tout-un-pc-sur-une-seule-puce-les-soc","title":"3. Tout un pc sur une seule puce : les SoC","text":""},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#31-lintegration-de-composants-differents-au-sein-dune-meme-puce","title":"3.1 L'int\u00e9gration de composants diff\u00e9rents au sein d'une m\u00eame puce","text":"Le principe d'un syst\u00e8me sur puce ou System On a Chip (SoC) est d'int\u00e9grer au sein d'une puce unique un ensemble de composants habituellement physiquement dissoci\u00e9s dans un ordinateur classique (ordinateur de bureau ou ordinateur portable).
On peut retrouver ainsi au sein d'une m\u00eame puce :
+ \u00e9ventuellement des composants de communication (WiFi, Bluetooth...)
Avantages et inconv\u00e9nients d'un SoC
Avantages
Inconv\u00e9nients
Observons par exemple la puce Apple A15 Bionic, qui \u00e9quipe les iPhone 13. Cette puce est fabriqu\u00e9e par TSMC.
Cette puce contient :
L'int\u00e9gration dans un SoC n'est pas totale : il reste des puces d\u00e9di\u00e9es \u00e0 des t\u00e2ches tr\u00e8s sp\u00e9cifiques qui ne sont pas forc\u00e9ment int\u00e9gr\u00e9es dans le SoC.
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#41-au-sein-dun-telephone","title":"4.1 Au sein d'un t\u00e9l\u00e9phone","text":"Ainsi, d'apr\u00e8s le site iFixit, on peut retrouver ceci dans l'iPhone Pro 13, au c\u00f4t\u00e9 de la puce A15 \u00e9voqu\u00e9e plus haut :
On voit que (par exemple) qu'il existe une puce sp\u00e9cifique pour g\u00e9rer l'audio, une puce sp\u00e9cifique pour le module WiFi, une puce sp\u00e9cifique pour le module Modem 5G...
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#42-en-electronique-grand-public","title":"4.2 En \u00e9lectronique \u00abgrand public\u00bb","text":"Ce composant (pouvant \u00eatre utilis\u00e9 dans un montage personnel, sur un Arduino par exemple) ne sert qu'\u00e0 faire des calculs cryptographiques.
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#43-un-principe-general","title":"4.3 Un principe g\u00e9n\u00e9ral","text":"Il est important de comprendre que certains processeurs sont optimis\u00e9s pour un certains types de calcul. C'est le cas par exemple d'une carte graphique, qui excelle dans le calcul de rendus de polygones.
On s'est aper\u00e7u que cette aptitude \u00e0 faire des calculs \u00abb\u00eates et r\u00e9p\u00e9titifs\u00bb \u00e9tait parfaite pour faire les calculs math\u00e9matiques (inutiles) n\u00e9cessaires au minage des cryptomonnaies. Les cartes graphiques ont donc \u00e9t\u00e9 d\u00e9tourn\u00e9es de leur usage originel, \u00e0 cause de la sp\u00e9cificit\u00e9 de l'impl\u00e9mentation de leur puce.
De m\u00eame, les calculs sur les r\u00e9seaux de neurones (essentiels en IA) n\u00e9cessitent une grande rapidit\u00e9 dans les multiplications de matrices. Pour cette raison, Apple a int\u00e9gr\u00e9 directement dans son SoC A15 une puce sp\u00e9calis\u00e9e dans ces calculs (voir plus haut).
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#44-conclusion","title":"4.4 Conclusion","text":"L'orientation actuelle de l'\u00e9lectronique est donc \u00e0 la fois :
Exercice (Polyn\u00e9sie 2021)
\u00c9nonc\u00e9CorrectionUn constructeur automobile int\u00e8gre \u00e0 ses v\u00e9hicules des syst\u00e8mes embarqu\u00e9s, comme par exemple un syst\u00e8me de guidage par satellites (GPS), un syst\u00e8me de freinage antiblocage (ABS)...
Ces dispositifs utilisent des syst\u00e8mes sur puces (SoC : System on a Chip).
Citer deux avantages \u00e0 utiliser ces syst\u00e8mes sur puces plut\u00f4t qu'une architecture classique d'ordinateur.
Bibliographie / Sitographie2021, sujet Am\u00e9rique du Nord
Un constructeur automobile utilise des ordinateurs pour la conception de ses v\u00e9hicules. Ceux-ci sont munis d'un syst\u00e8me d'exploitation ainsi que de nombreuses applications parmi lesquelles on peut citer :
Chaque ordinateur est \u00e9quip\u00e9 des p\u00e9riph\u00e9riques classiques : clavier, souris, \u00e9cran et est reli\u00e9 \u00e0 une imprimante r\u00e9seau.
La lettre M signifie que la donn\u00e9e est mobilis\u00e9e par l'application ; la lettre A signifie que l'application est en attente de cette donn\u00e9e.
Lecture du tableau : le logiciel de traitement de texte mobilise (M) la donn\u00e9e D1 et est en attente (A) de la donn\u00e9e D2.
D1 D2 D3 D4 D5 Traitement de texte M A - - - Tableur A - - - M SGBD - M A A - CAO - - A M AMontrer que les applications s'attendent mutuellement. Comment s'appelle cette situation ?
CorrectionLe cycle en pointill\u00e9s montre que les applications s'attendent mutuellement : cette situation s'appelle un interblocage.
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/Exercices/#exercice-2","title":"Exercice 2","text":"2021, M\u00e9tropole sujet 1
Partie A Cette partie est un questionnaire \u00e0 choix multiples (QCM). Pour chacune des questions, une seule des quatre r\u00e9ponses est exacte.
dir
ps
man
ls
stop
interrupt
end
kill
Partie B
Q1. Un processeur choisit \u00e0 chaque cycle d\u2019ex\u00e9cution le processus qui doit \u00eatre ex\u00e9cut\u00e9. Le tableau ci-dessous donne pour trois processus P1, P2, P3 :
Le num\u00e9ro de priorit\u00e9 est d\u2019autant plus petit que la priorit\u00e9 est grande. On suppose qu\u2019\u00e0 chaque instant, c\u2019est le processus qui a le plus petit num\u00e9ro de priorit\u00e9 qui est ex\u00e9cut\u00e9, ce qui peut provoquer la suspension d\u2019un autre processus, lequel reprendra lorsqu\u2019il sera le plus prioritaire.
Reproduire le tableau ci-dessous sur la copie et indiquer dans chacune des cases le processus ex\u00e9cut\u00e9 \u00e0 chaque cycle.
correctionQ2. On suppose maintenant que les trois processus pr\u00e9c\u00e9dents s\u2019ex\u00e9cutent et utilisent une ou plusieurs ressources parmi R1, R2 et R3. Parmi les sc\u00e9narios suivants, lequel provoque un interblocage ? Justifier.
correctionSeul le scenario 2 pr\u00e9sente un cycle d'interd\u00e9pendance : seul le sc\u00e9nario 2 va donc provoquer un interblocage.
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/Exercices/#exercice-3","title":"Exercice 3","text":"2021, M\u00e9tropole sujet 2
Partie A
Dans un bureau d\u2019architectes, on dispose de certaines ressources qui ne peuvent \u00eatre utilis\u00e9es simultan\u00e9ment par plus d\u2019un processus, comme l\u2019imprimante, la table tra\u00e7ante, le modem. Chaque programme, lorsqu\u2019il s\u2019ex\u00e9cute, demande l\u2019allocation des ressources qui lui sont n\u00e9cessaires. Lorsqu\u2019il a fini de s\u2019ex\u00e9cuter, il lib\u00e8re ses ressources.
On appelle p1, p2 et p3 les processus associ\u00e9s respectivement aux programmes 1, 2 et 3
Q1. Les processus s'ex\u00e9cutent de mani\u00e8re concurrente. Justifier qu'une situation d'interblocage peut se produire.
correctionSupposons que chaque ligne de chaque programme s'effectue cons\u00e9cutivement (d'abord la ligne 1 de P1, puis celle de P2, puis celle de P3, puis la ligne 2 de P1, etc.). Dans ce cas-l\u00e0, le diagramme de d\u00e9pendance serait : On voit appara\u00eetre un cycle d'interd\u00e9pendance : il peut donc y avoir une situation d'interblocage.
Q2. Modifier l'ordre des instructions du programme 3 pour qu'une telle situation ne puisse pas se produire. Aucune justification n'est attendue.
correctionOn peut par exemple inverser la demande d'imprimante et de table tra\u00e7ante.
Il sera \u00e0 l'\u00e9tat bloqu\u00e9.
Partie B
Avec une ligne de commande dans un terminal sous Linux, on obtient l'affichage suivant :
La documentation Linux donne la signification des diff\u00e9rents champs :
UID
: identifiant utilisateur effectif ;PID
: identifiant de processus ;PPID
: PID
du processus parent ;C
: partie enti\u00e8re du pourcentage d'utilisation du processeur par rapport au temps de vie des processus ;STIME
: l'heure de lancement du processus ;TTY
: terminal de contr\u00f4leTIME
: temps d'ex\u00e9cutionCMD
: nom de la commande du processusQ1. Parmi les quatre commandes suivantes, laquelle a permis cet affichage ?
ls -l
ps -ef
cd ..
chmod 741 processus.txt
Q2. Quel est l'identifiant du processus parent \u00e0 l'origine de tous les processus concernant le navigateur Web (chromium-browser) ?
Q3. Quel est l'identifiant du processus dont le temps d'ex\u00e9cution est le plus long ?
correctionQ1. b.
Q2. 6211
Q3. 6211
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/Exercices/#exercice-4","title":"Exercice 4","text":"2021, M\u00e9tropole Candidats Libres sujet 2
Q1. Les \u00e9tats possibles d\u2019un processus sont : pr\u00eat, \u00e9lu, termin\u00e9 et bloqu\u00e9.
Q1.a. Expliquer \u00e0 quoi correspond l\u2019\u00e9tat \u00e9lu. Q1.b. Proposer un sch\u00e9ma illustrant les passages entre les diff\u00e9rents \u00e9tats.
correctionQ1a. \u00c9lu signifie que le processus est actuellement en cours d'ex\u00e9cution par le processeur.
Q1b.
Q2. On suppose que quatre processus C\u2081, C\u2082, C\u2083 et C\u2084 sont cr\u00e9\u00e9s sur un ordinateur, et qu\u2019aucun autre processus n\u2019est lanc\u00e9 sur celui-ci, ni pr\u00e9alablement ni pendant l\u2019ex\u00e9cution des quatre processus. L\u2019ordonnanceur, pour ex\u00e9cuter les diff\u00e9rents processus pr\u00eats, les place dans une structure de donn\u00e9es de type file. Un processus pr\u00eat est enfil\u00e9 et un processus \u00e9lu est d\u00e9fil\u00e9.
Q2.a. Parmi les propositions suivantes, recopier celle qui d\u00e9crit le fonctionnement des entr\u00e9es/sorties dans une file :
Q2a. ii. Premier entr\u00e9, premier sorti
Q2.b. On suppose que les quatre processus arrivent dans la file et y sont plac\u00e9s dans l\u2019ordre C\u2081, C\u2082, C\u2083 et C\u2084.
Sur la frise chronologique ci-dessous, les \u00e9tats du processus C\u2082 sont donn\u00e9s. Compl\u00e9ter la frise avec les \u00e9tats des processus C\u2081, C\u2083 et C\u2084.
correction "},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/Exercices/#exercice-5","title":"Exercice 5","text":"Exercice 2 du sujet Am\u00e9rique du Nord J2 2022
correction Q1.a.proposition 2
correction Q1.b.cd lycee
mkdir algorithmique
rm image1.jpg
927
correction Q2.b.1058 (ou 927)
correction Q2.c.1153 et 1154
correction Q2.d.923 et 1036
correction Q3.a. correction Q3.b. correction Q4.a.Un processus peut \u00eatre Pr\u00eat, Elu, ou Bloqu\u00e9. Si chaque ligne de chaque processus est ex\u00e9cut\u00e9e \u00e0 tour de r\u00f4le, un cycle d'interd\u00e9pendance apparait, et donc un interblocage.
correction Q4.b.En inversant la demande de R3 et R1 pour le processus P3, le risque d'interblocage dispara\u00eet. Fichier svg d'explication
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/","title":"Gestion des processus","text":""},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#1-notion-de-processus","title":"1. Notion de processus","text":""},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#11-definition-dun-processus","title":"1.1 D\u00e9finition d'un processus","text":"Lorsqu'un programme est ex\u00e9cut\u00e9 sur un ordinateur, celui-ci va cr\u00e9er un (ou plusieurs) processus.
On dit que ce processus est une instance d'ex\u00e9cution de ce programme.
Un processus est caract\u00e9ris\u00e9 par :
ps
","text":"Dans un terminal, la commande ps
va permettre d'afficher la liste des processus actifs.
Plus pr\u00e9cis\u00e9ment, nous allons utiliser la commande ps -lu nom_user
. L'option l
permet d'afficher un grand nombre de renseignements et l'option u
permet de sp\u00e9cifier l'utilisateur propri\u00e9taire des processus.
On retrouve notamment dans ce tableau les colonnes :
CMD
(Command) : le nom de la commande qui a cr\u00e9\u00e9 le processus. Vous pouvez y retrouver par ordre chronologique le nom de tous les programmes actifs. Certains sont ceux que vous avez ouverts volontairement (navigateur...) mais on y trouve surtout tous les programmes n\u00e9cessaires au bon fonctionnement du syst\u00e8me d'exploitation. Le dernier processus en bas de la liste est forc\u00e9ment ps
, puisque vous venez de l'appeler.
PID
(Process Identifier) : le num\u00e9ro unique d'identification, affect\u00e9 chronologiquement par le syst\u00e8me d'exploitation. Le processus de PID \u00e9gal \u00e0 1 est systemd
, qui est le tout premier programme lanc\u00e9 par le noyau Linux au d\u00e9marrage.
PPID
(Parent PID) : certains processus vont eux-m\u00eames lancer plusieurs processus-fils, qui porteront le m\u00eame nom. C'est ainsi qu'on peut retrouver de multiples processus s'appelant chrome
:
Ici, l'instance \u00abprincipale\u00bb de Chrome (PID
1453) a g\u00e9n\u00e9r\u00e9 6 autres instances de PID
diff\u00e9rents, dont le PPID
vaut 1453.
Dans Chrome/Chromium, vous pouvez comprendre le r\u00f4le de chaque processus en le retrouvant dans le gestionnaire des t\u00e2ches (clic-droit sur une zone vide de la barre d'onglets)
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#122-la-commande-pstree","title":"1.2.2 La commandepstree
","text":"\u00c0 noter que la commande pstree
permet d'afficher les processus sous forme d'arborescence :
top
","text":"La commande top
permet de conna\u00eetre en temps r\u00e9el la liste des processus, class\u00e9s par ordre d\u00e9croissant de consommation de CPU.
On ferme top
par la combinaison de touches Ctrl-C
.
Pourcentage d'utilisation du CPU
En face de chaque processus est affich\u00e9e sa consommation de CPU. Elle est calcul\u00e9e en prenant, sur un intervalle de temps donn\u00e9, le temps qu'a pass\u00e9 le CPU \u00e0 traiter le processus en question, et en divisant ce temps par le temps total de la mesure.
\\[\\text{Pourcentage d'utilisation CPU} = \\frac{\\text{Temps d'utilisation CPU}}{\\text{Temps total \u00e9coul\u00e9}} \\times 100\\]Si on rep\u00e8re alors un processus qui consomme beaucoup trop de ressources, on peut utiliser...
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#124-la-commande-kill","title":"1.2.4 La commandekill
","text":"La commande kill
permet de fermer un processus, en donnant son PID
en argument.
Exemple : kill 1453
tuera Chrome (voir la capture du 1.2.1)
Un ordinateur donne l'illusion de r\u00e9aliser plusieurs t\u00e2ches simultan\u00e9ment. Hormis pour les processeurs fonctionnant avec plusieurs c\u0153urs, il n'en est rien.
Comme nous l'avons vu, ces processus sont lanc\u00e9s s\u00e9quentiellement par le syst\u00e8me d'exploitation, et sont ensuite en apparence tous \u00abactifs en m\u00eame temps\u00bb (les guillemets sont importants) : on parle de programmation concurrente.
Revenons sur l'expression \u00abactifs en m\u00eame temps\u00bb, car elle v\u00e9hicule une fausse id\u00e9e : ces processus sont bien vivants dans un m\u00eame laps de temps, mais ils s'ex\u00e9cutent LES UNS APR\u00c8S LES AUTRES, le processeur ne pouvant en traiter qu'un seul \u00e0 la fois.
Un cadencement extr\u00eamement rapide et efficace donne l'apparence d'une (fausse) simultan\u00e9it\u00e9. Nous allons la mettre en \u00e9vidence :
Consid\u00e9rons les fichiers progA.py
et progB.py
ci-dessous :
import time\n\nfor i in range(10):\n print(\"programme A en cours, it\u00e9ration\", i)\n time.sleep(0.02) \n
progB.pyimport time\ntime.sleep(0.01)\nfor i in range(10):\n print(\"programme B en cours, it\u00e9ration\", i)\n time.sleep(0.02) \n
Le programme progB.py
est l\u00e9g\u00e8rement retard\u00e9 au d\u00e9marrage par le time.sleep(0.01)
. Il devrait donc en r\u00e9sulter un entrelacement entre les phrases programme A en cours
et programme B en cours
.
L'ex\u00e9cution \u00abd'apparence simultan\u00e9e\u00bb de ces deux programmes peut se faire dans un Terminal via la commande python3 progA.py & python3 progB.py
.
Il en r\u00e9sulte ceci :
Nous retrouvons bien l'alternance pr\u00e9vue \u00e0 la lecture du code. Tout se passe donc comme si les deux processus avaient \u00e9t\u00e9 lanc\u00e9s et trait\u00e9s simultan\u00e9ment.
R\u00e9duisons maintenant les temporisations (en passant du centi\u00e8me de seconde \u00e0 la milliseconde):
progA.pyimport time\n\nfor i in range(10):\n print(\"programme A en cours, it\u00e9ration\", i)\n time.sleep(0.002) \n
progB.pyimport time\ntime.sleep(0.001)\nfor i in range(10):\n print(\"programme B en cours, it\u00e9ration\", i)\n time.sleep(0.002) \n
Il en r\u00e9sulte maintenant ceci :
L'alternance pr\u00e9vue n'est plus respect\u00e9e (et les r\u00e9sultats deviennent non-reproductibles).
Si la gestion des processus \u00e9tait r\u00e9ellement simultan\u00e9e, m\u00eame en consid\u00e9rant des ralentissements du processeur par des sollicitations ext\u00e9rieures, chaque processus serait ralenti de la m\u00eame mani\u00e8re : l'entrelacement des phrases serait toujours le m\u00eame.
En r\u00e9alit\u00e9, le processeur passe son temps \u00e0 alterner entre les divers processus qu'il a \u00e0 g\u00e9rer, et les met en attente quand il ne peut pas s'occuper d'eux. Il ob\u00e9it pour cela aux instructions de son ordonnanceur.
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#22-lordonnancement-des-processus","title":"2.2 L'ordonnancement des processus","text":""},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#221-differents-types-dordonnancement","title":"2.2.1 Diff\u00e9rents types d'ordonnancement","text":"Si on vous donne 4 t\u00e2ches A, B, C et D \u00e0 accomplir, vous pouvez d\u00e9cider :
Un processeur est confront\u00e9 aux m\u00eames choix : comment d\u00e9terminer quel processus doit \u00eatre trait\u00e9 \u00e0 quel moment ?
Le sch\u00e9ma ci-dessous (issu de ce site) pr\u00e9sente quelques politiques d'ordonnancement :
Sous Linux, l'ordonnancement est effectu\u00e9 par un syst\u00e8me hybride o\u00f9 les processus sont ex\u00e9cut\u00e9s \u00e0 tour de r\u00f4le (on parle de tourniquet ou de Round Robin) suivant un ordre de priorit\u00e9 dynamique.
Dans le cas (tr\u00e8s fr\u00e9quent maintenant) d'un processeur multi-c\u0153urs, le probl\u00e8me reste identique. Certes, sur 4 c\u0153urs, 4 processus pourront \u00eatre trait\u00e9s simultan\u00e9ment (une r\u00e9elle simultan\u00e9it\u00e9) mais il reste toujours beaucoup plus de processus \u00e0 traiter que de c\u0153urs dans le processeur... et un ordonnancement est donc toujours n\u00e9cessaire.
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#222-les-differents-etats-dun-processus","title":"2.2.2 Les diff\u00e9rents \u00e9tats d'un processus","text":"Selon que l'ordonnanceur aura d\u00e9cid\u00e9 de le confier ou non au processeur pour son ex\u00e9cution, un processus peut donc se trouver dans 3 \u00e9tats :
Voici les transitions possibles entre ces \u00e9tats (diagramme issu de https://info.blaisepascal.fr/nsi-processus-et-ressources) :
Ou de mani\u00e8re simplifi\u00e9e :
On peut utiliser la m\u00e9taphore suivante :
Sur le bureau d'un professeur, il y a 3 paquets de copies, correspondant aux classes A, B, et C. Ces paquets sont Pr\u00eats \u00e0 \u00eatre corrig\u00e9s.
Au cours de cette proc\u00e9dure, le professeur n'a toujours eu devant lui qu'un seul paquet de copies (soit A, soit B, soit C).
Pourquoi l'acc\u00e8s \u00e0 une ressource peut bloquer un processus ?
Pendant son ex\u00e9cution, un processus peut avoir besoin d'acc\u00e9der \u00e0 une ressource d\u00e9j\u00e0 occup\u00e9e (un fichier d\u00e9j\u00e0 ouvert, par exemple) ou \u00eatre en attente d'une entr\u00e9e-utilisateur (un input()
dans un code Python
par exemple). Dans ce cas-l\u00e0, le processeur va passer ce processus \u00e0 l'\u00e9tat Bloqu\u00e9, pour pouvoir ainsi se consacrer \u00e0 un autre processus.
Une fois d\u00e9bloqu\u00e9, le processus va repasser \u00e0 l'\u00e9tat Pr\u00eat et rejoindre (par exemple) la file d'attente des processus avant d'\u00eatre \u00e0 nouveau \u00c9lu et donc ex\u00e9cut\u00e9.
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#3-interblocage","title":"3. Interblocage","text":""},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#31-definition-et-exemple","title":"3.1 D\u00e9finition et exemple","text":"Comme nous venons de le voir, un processus peut \u00eatre dans l'\u00e9tat bloqu\u00e9 dans l'attente de la lib\u00e9ration d'une ressource.
Ces ressources (l'acc\u00e8s en \u00e9criture \u00e0 un fichier, \u00e0 un registre de la m\u00e9moire...) ne peuvent \u00eatre donn\u00e9es \u00e0 deux processus \u00e0 la fois. Des processus souhaitant acc\u00e9der \u00e0 cette ressource sont donc en concurrence sur cette ressource. Un processus peut donc devoir attendre qu'une ressource se lib\u00e8re avant de pouvoir y acc\u00e9der (et ainsi passer de l'\u00e9tat Bloqu\u00e9 \u00e0 l'\u00e9tat Pr\u00eat).
Probl\u00e8me : Et si deux processus se bloquent mutuellement la ressource dont ils ont besoin ?
Exemple : Consid\u00e9rons 2 processus A et B, et deux ressources R et S. L'action des processus A et B est d\u00e9crite ci-dessous :
D\u00e9roulement des processus A et B :
Les deux processus A et B sont donc dans l'\u00e9tat Bloqu\u00e9, chacun en attente de la lib\u00e9ration d'une ressource bloqu\u00e9e par l'autre : ils se bloquent mutuellement.
Cette situation (critique) est appel\u00e9e interblocage ou deadlock.
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#33-representation-schematique","title":"3.3 Repr\u00e9sentation sch\u00e9matique","text":"Avec ces conventions, la situation pr\u00e9c\u00e9dente peut donc se sch\u00e9matiser par :
Ce type de sch\u00e9ma fait appara\u00eetre un cycle d'interd\u00e9pendance, qui caract\u00e9rise ici la situation de deadlock.
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#34-comment-sen-premunir-hp","title":"3.4 Comment s'en pr\u00e9munir ? (HP)","text":"Il existe trois strat\u00e9gies pour \u00e9viter les interblocages :
Exercice 1
Exercice 5 du sujet La R\u00e9union J1 2022
Correction Q1.a.Une adresse IPv4 se code \u00e0 l'aide de 4 octets.
Correction Q1.b.Le PC3 a pour adresse 172.150.4.30 / 24
. Cela signfie que son masque, en notation CIDR, est 24. Ses 24 premiers bits sont donc \u00e0 1. Cela correspond au masque 255.255.255.0
en notation d\u00e9cimale.
Pour \u00eatre dans le r\u00e9seau 1, il faut que le & logique entre l'IP de la machine et l'adresse du masque donne l'adresse r\u00e9seau (172.150.4.0
).
Le r\u00e9seau \u00e9tant en /24
(\u00e9quivalent au masque 255.255.255.0
), cela signifie que l'adresse IP de la machine soit de la forme 172.150.4.???
.
Attention, il faut en plus s'assurer que l'adresse ne soit pas d\u00e9j\u00e0 utilis\u00e9e, et qu'elle ne soit pas l'adresse du r\u00e9seau (172.150.4.0
) ou de broadcast (172.150.4.255
).
Il reste alors les adresses 4) et 6). (172.150.4.11
et 172.150.4.200
)
La commande permettant de conna\u00eetre son adresse IP est ifconfig
ou ip addr
sous Linux / MacOS. Ou bien ipconfig
sous Windows.
La solution de relier les switchs entre eux n'est pas satisfaisante. Les deux r\u00e9seaux ne pourront pas communiquer entre eux, \u00e0 moins d'\u00e9largir (beaucoup) leur masque de sous-r\u00e9seau.
La meilleure solution est d'installer un routeur entre les deux switchs, de lui attribuer une adresse IP dans chaque sous-r\u00e9seau, et de renseigner cette adresse IP comme adresse de passerelle sur chacun des PCs des deux sous-r\u00e9seaux.
Correction Q5.def adresse(IP, liste_IP):\n if IP in liste_IP:\n print(\"trouv\u00e9e\")\n else:\n liste_IP.append(IP)\n print(\"pas trouv\u00e9e, ajout\u00e9e\")\n
Exercice 2
\u00c9nonc\u00e9CorrectionCr\u00e9er une fonction meme_sous_reseau(ip_a, ip_b, masque)
qui renvoie un bool\u00e9en indiquant si A et B sont partie du m\u00eame sous-r\u00e9seau.
Exercice (difficile) \u00e0 r\u00e9aliser en Test Driven Developpement \u00e0 partir du squelette de code ci-dessous, en testant chaque fonction apr\u00e8s sa r\u00e9alisation, jusqu'\u00e0 la fonction finale.
def convert_ip_to_list(ip):\n\"\"\"\n entr\u00e9e : ip (string) \n sortie : liste d'entiers\n \"\"\"\n # \u00e0 vous\n\ndef test_convert_ip_to_list():\n assert convert_ip_to_list('192.168.0.1') == [192, 168, 0, 1]\n\n\ndef nb_to_binary_word(masque):\n\"\"\"\n entr\u00e9e : masque (int)\n sortie : string\n \"\"\"\n # \u00e0 vous\n\ndef test_nb_convert_to_binary_word():\n assert nb_to_binary_word(24) == '11111111111111111111111100000000'\n\n\ndef binary_word_to_list(word):\n\"\"\"\n entr\u00e9e : word (string de 32 caract\u00e8res)\n sortie : liste de 4 entiers\n \"\"\"\n # \u00e0 vous\n\n\ndef test_binary_word_to_list():\n assert binary_word_to_list('11111111111111111111111100000000') == [255, 255, 255, 0]\n\n\n\ndef meme_sous_reseau(ip_a, ip_b, masque):\n\"\"\"\n ip_a: string contenant une IP (ex \"192.168.0.1\")\n ip_b : string contenant une IP\n masque : entier du masque en notation CIDR (ex : 24)\n renvoie un bool\u00e9en indiquant si ip_a et ip_b sont dans\n le m\u00eame sous-r\u00e9seau\n \"\"\"\n # \u00e0 vous\n\n\ndef test_meme_sous_reseau():\n assert meme_sous_reseau(\"192.168.0.1\", \"192.168.1.3\", 24) == False\n assert meme_sous_reseau(\"192.168.0.1\", \"192.168.1.3\", 20) == True\n assert meme_sous_reseau(\"192.168.0.1\", \"192.168.0.3\", 30) == True\n
Exercice difficile, il n'est pas \u00e0 savoir faire mais c'est bien de le comprendre !
def convert_ip_to_list(ip):\n\"\"\"\n entr\u00e9e : ip (string) \n sortie : liste d'entiers\n \"\"\"\n return [int(k) for k in ip.split(\".\")]\n\ndef test_convert_ip_to_list():\n assert convert_ip_to_list('192.168.0.1') == [192, 168, 0, 1]\n\n\ndef nb_to_binary_word(masque):\n\"\"\"\n entr\u00e9e : masque (int)\n sortie : string\n \"\"\"\n return '1'*masque + '0'*(32-masque)\n\ndef test_nb_convert_to_binary_word():\n assert nb_to_binary_word(24) == '11111111111111111111111100000000'\n\n\ndef binary_word_to_list(word):\n\"\"\"\n entr\u00e9e : word (string de 32 caract\u00e8res)\n sortie : liste de 4 entiers\n \"\"\"\n decoupe = [word[8*i:8*(i+1)] for i in range(4)]\n return [int(k,2) for k in decoupe]\n\ndef test_binary_word_to_list():\n assert binary_word_to_list('11111111111111111111111100000000') == [255, 255, 255, 0]\n\ndef meme_sous_reseau(ip_a, ip_b, masque):\n lstA = convert_ip_to_list(ip_a)\n lstB = convert_ip_to_list(ip_b)\n mask = binary_word_to_list(nb_to_binary_word(masque))\n resA = [lstA[i] & mask[i] for i in range(4)]\n resB = [lstB[i] & mask[i] for i in range(4)]\n return resA == resB\n\ndef test_meme_sous_reseau():\n assert meme_sous_reseau(\"192.168.0.1\", \"192.168.1.3\", 24) == False\n assert meme_sous_reseau(\"192.168.0.1\", \"192.168.1.3\", 20) == True\n assert meme_sous_reseau(\"192.168.0.1\", \"192.168.0.3\", 30) == True\n
Exercice 3
\u00c9nonc\u00e9Correction2020, sujet 0
On consid\u00e8re un r\u00e9seau compos\u00e9 de plusieurs routeurs reli\u00e9s de la fa\u00e7on suivante :
Le protocole RIP permet de construire les tables de routage des diff\u00e9rents routeurs, en indiquant pour chaque routeur la distance, en nombre de sauts, qui le s\u00e9pare d\u2019un autre routeur. Pour le r\u00e9seau ci-dessus, on dispose des tables de routage suivantes :
Question 1
Question 2
Le routeur C tombe en panne. Reconstruire la table de routage du routeur A en suivant le protocole RIP.
Q1.1. Le trajet parcouru de A \u00e0 G est A-C-F-G Q1.2. Table de routage de G :
Destination Routeur suivant Distance A F 3 B E 3 C E 2 D E 2 E E 1 F F 1Q2 Nouvelle table de routage de A :
Destination Routeur suivant Distance B B 1 D D 1 E D 2 G D 3 F D 4Exercice 4
\u00c9nonc\u00e9Correction2021, sujet M\u00e9tropole 1
On repr\u00e9sente ci-dessous un r\u00e9seau dans lequel R1, R2, R3, R4, R5 et R6 sont des routeurs. Le r\u00e9seau local L1 est reli\u00e9 au routeur R1 et le r\u00e9seau local L2 au routeur R6.
Dans cet exercice, les adresses IP sont compos\u00e9es de 4 octets, soit 32 bits. Elles sont not\u00e9es X1.X2.X3.X4, o\u00f9 X1, X2, X3 et X4 sont les valeurs des 4 octets, convertis en notation d\u00e9cimale. La notation X1.X2.X3.X4/n signifie que les n premiers bits de poids forts de l\u2019adresse IP repr\u00e9sentent la partie \u00ab r\u00e9seau \u00bb, les bits suivants repr\u00e9sentent la partie \u00ab h\u00f4te \u00bb. Toutes les adresses des h\u00f4tes connect\u00e9s \u00e0 un r\u00e9seau local ont la m\u00eame partie r\u00e9seau et peuvent donc communiquer directement. L\u2019adresse IP dont tous les bits de la partie \u00ab h\u00f4te \u00bb sont \u00e0 0 est appel\u00e9e \u00ab adresse du r\u00e9seau \u00bb.
On donne \u00e9galement des extraits de la table de routage des routeurs R1 \u00e0 R5 dans le tableau suivant :
1/ Un paquet part du r\u00e9seau local L1 \u00e0 destination du r\u00e9seau local L2.
1.a. En utilisant l\u2019extrait de la table de routage de R1, vers quel routeur R1 envoie-t-il ce paquet : R2 ou R3 ? Justifier.
1.b. A l\u2019aide des extraits de tables de routage ci-dessus, nommer les routeurs travers\u00e9s par ce paquet, lorsqu\u2019il va du r\u00e9seau L1 au r\u00e9seau L2.
2/ La liaison entre R1 et R2 est rompue.
2.a. Sachant que ce r\u00e9seau utilise le protocole RIP (distance en nombre de sauts), donner l\u2019un des deux chemins possibles que pourra suivre un paquet allant de L1 vers L2.
2.b. Dans les extraits de tables de routage ci-dessus, pour le chemin de la question 2.a, quelle(s) ligne(s) sera (seront) modifi\u00e9e(s) ?
3/ On a r\u00e9tabli la liaison entre R1 et R2. Par ailleurs, pour tenir compte du d\u00e9bit des liaisons, on d\u00e9cide d\u2019utiliser le protocole OSPF (distance li\u00e9e au co\u00fbt minimal des liaisons) pour effectuer le routage. Le co\u00fbt des liaisons entre les routeurs est donn\u00e9 par le tableau suivant :
a. Le co\u00fbt C d\u2019une liaison est donn\u00e9 ici par la formule \\(C = \\frac{10^9}{BP}\\)
o\u00f9 \\(BP\\) est la bande passante de la connexion en bps (bits par seconde). Sachant que la bande passante de la liaison R2-R3 est de 10 Mbps, calculer le co\u00fbt correspondant.
b. D\u00e9terminer le chemin parcouru par un paquet partant du r\u00e9seau L1 et arrivant au r\u00e9seau L2, en utilisant le protocole OSPF.
c. Indiquer pour quel(s) routeur(s) l\u2019extrait de la table de routage sera modifi\u00e9 pour un paquet \u00e0 destination de L2, avec la m\u00e9trique OSPF.
1.a. D'apr\u00e8s la table, R1 doit passer par la passerelle 86.154.10.1 qui correspond au routeur R2. 1.b. Le paquet va traverser R1, R2, R6 avant d'arriver \u00e0 L2. 2.a. RIP doit minimiser le nombre de sauts, donc les deux chemins minimaux possibles sont R1-R3-R4-R6 et R1-R3-R2-R6. 2.b. La ligne R1 sera modifi\u00e9e, il faudra partir vers R3 (et son r\u00e9seau 112.44.65.0/24). Les autres lignes n'ont pas \u00e0 \u00eatre modifi\u00e9es puisque R3 am\u00e8ne en R4 qui am\u00e8ne en R6. 3.a \\(\\dfrac{10^9}{10 \\times 10^6}=100\\) donc le co\u00fbt R2-R3 est 100. 3.b. Avec OSPF, le chemin qui minimise le co\u00fbt est le chemin R1-R2-R4-R5-R6 (co\u00fbt 103) : 3.c. Dans la table de routage initiale, il faut modifier R2 pour qu'elle envoie sur R4 (et non sur R6), mais aussi R4 pour qu'elle envoie sur R5 (et non sur R6).
Exercice 5
\u00c9nonc\u00e9Correction2021, sujet M\u00e9tropole 2 (sujet modifi\u00e9, correction d'erreurs sur les adresses passerelles)
Figure 1La figure 1 ci-dessus repr\u00e9sente le sch\u00e9ma d\u2019un r\u00e9seau d\u2019entreprise. Il y figure deux r\u00e9seaux locaux L1 et L2. Ces deux r\u00e9seaux locaux sont interconnect\u00e9s par les routeurs R2, R3, R4 et R5. Le r\u00e9seau local L1 est constitu\u00e9 des PC portables P1 et P2 connect\u00e9s \u00e0 la passerelle R1 par le switch Sw1. Les serveurs S1 et S2 sont connect\u00e9s \u00e0 la passerelle R6 par le switch Sw2.
Le tableau 1 suivant indique les adresses IPv4 des machines constituants le r\u00e9seau de l\u2019entreprise.
Tableau 1 : adresses IPv4 des machinesRappels et notations
Rappelons qu\u2019une adresse IP est compos\u00e9e de 4 octets, soit 32 bits. Elle est not\u00e9e X1.X2.X3.X4, o\u00f9 X1, X2, X3 et X4 sont les valeurs des 4 octets. Dans le tableau 1, les valeurs des 4 octets ont \u00e9t\u00e9 converties en notation d\u00e9cimale.
La notation X1.X2.X3.X4/n signifie que les n premiers bits de poids forts de l\u2019adresse IP repr\u00e9sentent la partie \u00ab r\u00e9seau \u00bb, les bits suivants de poids faibles repr\u00e9sentent la partie \u00ab machine \u00bb.
Toutes les adresses des machines connect\u00e9es \u00e0 un r\u00e9seau local ont la m\u00eame partie r\u00e9seau. L\u2019adresse IP dont tous les bits de la partie \u00ab machine \u00bb sont \u00e0 0 est appel\u00e9e \u00ab adresse du r\u00e9seau \u00bb. L\u2019adresse IP dont tous les bits de la partie \u00ab machine \u00bb sont \u00e0 1 est appel\u00e9e \u00ab adresse de diffusion \u00bb.
1/ 1.a. Quelles sont les adresses des r\u00e9seaux locaux L1 et L2 ?
1.b. Donner la plus petite et la plus grande adresse IP valides pouvant \u00eatre attribu\u00e9es \u00e0 un ordinateur portable ou un serveur sur chacun des r\u00e9seaux L1 et L2 sachant que l\u2019adresse du r\u00e9seau et l\u2019adresse de diffusion ne peuvent pas \u00eatre attribu\u00e9es \u00e0 une machine.
1.c. Combien de machines peut-on connecter au maximum \u00e0 chacun des r\u00e9seaux locaux L1 et L2 ?
2/ 2.a. Expliquer l\u2019utilit\u00e9 d\u2019avoir plusieurs chemins possibles reliant les r\u00e9seaux L1 et L2.
2.b. Quel est le chemin le plus court en nombre de sauts pour relier R1 et R6 ? Donner le nombre de sauts de ce chemin et pr\u00e9ciser les routeurs utilis\u00e9s.
2.c. La bande passante d\u2019une liaison Ether (quantit\u00e9 d\u2019information qui peut \u00eatre transmise en bits/s) est de \\(10^7\\) bits/s et celle d\u2019une liaison FastEther est de \\(10^8\\) bits/s. Le co\u00fbt d\u2019une liaison est d\u00e9fini par \\(\\frac{10^8}{d}\\) , o\u00f9 \\(d\\) est sa bande passante en bits/s.
Tableau 2 : type des liaisons entre les routeursQuel est le chemin reliant R1 et R6 qui a le plus petit co\u00fbt ? Donner le co\u00fbt de ce chemin et pr\u00e9ciser les routeurs utilis\u00e9s.
3/ Dans l\u2019annexe A figurent les tables de routages des routeurs R1, R2, R5 et R6 au d\u00e9marrage du r\u00e9seau. Indiquer sur votre copie ce qui doit figurer dans les lignes laiss\u00e9es vides des tables de routage des routeurs R5 et R6 pour que les \u00e9changes entre les ordinateurs des r\u00e9seaux L1 et L2 se fassent en empruntant le chemin le plus court en nombre de sauts.
1.a L'adresse du r\u00e9seau L1 est 192.168.1.0/24. L'adresse de L2 est 175.6.0.0/16. 1.b Pour le r\u00e9seau L1 (192.168.1.0/24), l'adresse min est 192.168.1.1/24, l'adresse max est 192.168.1.254/24. Pour le r\u00e9seau L2 (175.6.0.0/16), l'adresse min est 175.6.0.1/16 et l'adresse max est 175.6.255.254/16 1.c. Pour le r\u00e9seau L1, il y a donc 254 adresses (256 moins les deux interdites) Pour le r\u00e9seau L2, il y en a \\(256^2-2\\), soit 65534.
2.a Il est utile d'avoir plusieurs chemins en cas de panne d'un routeur. 2.b En nombres de sauts (protocole RIP), le chemin le plus court est R1-R2-R5-R6, qui contient 3 sauts. 2.c Les liaisons Ether ont un co\u00fbt de 10, les liaisons FastEther ont un co\u00fbt de 1. Ce qui donne : Le chemin le plus court est donc R1-R2-R3-R4-R5-R6, avec un co\u00fbt total de 23.
Dans la table R6, on peut compl\u00e9ter comme ceci (il faudrait des lignes suppl\u00e9mentaires pour y inscrire tous les r\u00e9seaux)
IP destination Passerelle Interface 10.1.7.0/24 Interface 2 192.168.1.0/24 10.1.7.1 Interface 2Exercice 6
\u00c9nonc\u00e9Correction2021, sujet Am\u00e9rique du Nord
Un constructeur automobile poss\u00e8de six sites de production qui \u00e9changent des documents entre eux. Les sites de production sont reli\u00e9s entre eux par six routeurs A, B, C, D, E et F. On donne ci-dessous les tables de routage des routeurs A \u00e0 F obtenues avec le protocole RIP.
En s'appuyant sur les tables de routage, tracer les liaisons entre les routeurs.
2.
Exercice 7
Exercice 4 du sujet Nouvelle-Cal\u00e9donie J2 2022.
Correction Q1.a.195.168.1.0/24
195.168.1.17/24
Le r\u00e9seau T2 a pour adresse 172.162.1.0/24
. Sur ce r\u00e9seau, 254 adresses sont initialement disponibles (de 172.162.1.1
\u00e0 172.162.1.254
, puisque l'adresse 172.162.1.255
est r\u00e9serv\u00e9e pour le broadcast sur le r\u00e9seau). Comme le routeur R2 et le portable 5 prennent chacun une adresse IP, il en reste donc 252 pour le portable 4.
200.158.4.1
198.164.3.2
(car la 198.164.3.1
est d\u00e9j\u00e0 prise par R2)199.160.1.1
Parcours possibles : - S1-R1-R2-S2 - S1-R1-R4-R2-S2 - S1-R1-R4-R3-R2-S2
Correction Q3.b.Suivant le protocole RIP, le parcours le plus court est celui passant par R1 puis R2. Il comporte 2 sauts.
Correction Q3.cSi la liaison R1-R2 est rompue, le protocole RIP sera emprunter le chemin R1-R4-R2, qui est le nouveau meilleur chemin, comportant 3 sauts.
Correction Q4.Le c\u00e2ble utilis\u00e9 est le cable c) Ethernet.
(le c\u00e2ble \u00abInternet\u00bb n'existe, les c\u00e2bles VGA et HDMI servent \u00e0 relier un ordinateur \u00e0 un \u00e9cran).
Correction Q5.a.\\(10=\\dfrac{10^9}{d}\\) donc \\(d=\\dfrac{10^9}{10}=10^8\\).
Le d\u00e9bit de cette liaison est donc de \\(10^8\\) bits par seconde, soit 100 Mbps.
Correction Q5.b.Le parcours de co\u00fbt minimal est le parcours R1-R4-R2, qui a un co\u00fbt total de 2.
Co\u00fbt des autres parcours : - R1-R2 : 10 - R1-R4-R3-R2 : 151
Le parcours R1-R4-R2 est donc bien le parcours minimal.
Exercice 8
Parties 2, 3 et 4 de l'exercice 2 du sujet Nouvelle-Cal\u00e9donie J1 2022.
Partie 2
Correction Q1.Le r\u00e9seau services a pour adresse IP 195.168.254.0
.
Le r\u00e9seau services a pour adresse 195.168.254.0
. Comme le masque de sous-r\u00e9seau utilis\u00e9 est 255.255.255.0
, 254 adresses sont initialement disponibles (195.168.254.1
\u00e0 195.168.254.254
, puisque l'adresse 195.168.254.255
est r\u00e9serv\u00e9e pour le broadcast sur le r\u00e9seau). Comme deux adresses sont d\u00e9j\u00e0 prises par le routeur 1 et le routeur 2, il en reste 252.
Le serveur web acc\u00e8de \u00e0 internet via le routeur 2, dont l'adresse sur le r\u00e9seau services est 192.168.254.2
. C'est donc cette adresse qui joue est l'adresse de passerelle pour le serveur web.
Partie 3
Correction Q1.La ligne 2 montre que l'adresse MAC du serveur DNS est 8A:FD:54:49:D0:CC
.
La couche Transport montre que le protocole utilis\u00e9 est le protocole UDP.
Correction Q3.Le commentaire de la couche Application indique que l'adresse IP du serveur web est 192.168.254.201
.
Partie 4
Correction Q1.Table de routage du routeur R4 :
Destination Routeur suivant Distance R1 R2 2 R2 R2 1 R3 R2 2 R5 R6 2 R6 R6 1 Correction Q2.Pour minimiser le nombre de sauts (protocole RIP), le trajet sera R1-R2-R4-R6
.
Notions essentielles
Lorsqu'une machine A, d'adresse IP_A veut discuter avec une machine B, d'adresse IP_B :
Ces questions trouveront des r\u00e9ponses gr\u00e2ce \u00e0 table de routage du routeur.
"},{"location":"T5_Architecture_materielle/5.3_Protocoles_de_routage/cours/#1-tables-de-routage","title":"1. Tables de routage","text":"Les tables de routage sont des informations stock\u00e9es dans le routeur permettant d'aiguiller intelligemment les donn\u00e9es qui lui sont transmises.
Dans le r\u00e9seau ci-dessus, si l'ordinateur d'adresse 192.168.0.5
veut interroger le serveur 10.7.3.8
:
10.7.3.8
n'\u00e9tant pas dans le sous-r\u00e9seau F (d'adresse 192.168.0.0 / 24
), la requ\u00eate est confi\u00e9e au routeur via son adresse passerelle dans le r\u00e9seau F (ici 192.168.0.254
).10.7.3.8
n'appartient ni au sous-r\u00e9seau A ou E. interface et passerelle
Les tables de routage des routeurs font tr\u00e8s souvent appara\u00eetre deux colonnes, interface et passerelle, dont il ne faut pas confondre l'utilit\u00e9 :
interface : c'est l'adresse IP de la carte r\u00e9seau du routeur par o\u00f9 va sortir le paquet \u00e0 envoyer. Il y a donc toujours une adresse d'interface \u00e0 renseigner (car un paquet sort bien de quelque part !). Parfois cette interface sera juste nomm\u00e9e interface1 ou interface2.
passerelle : c'est l'adresse IP de la carte r\u00e9seau du routeur \u00e0 qui on va confier le paquet, si on n'est pas capable de le d\u00e9livrer directement (donc si l'adresse IP de destination n'est pas dans notre propre sous-r\u00e9seau). Cette adresse de passerelle n'est donc pas syst\u00e9matiquement mentionn\u00e9e. Quand elle l'est, elle donne le renseignement sur le prochain routeur \u00e0 qui le paquet est confi\u00e9.
Exemple: table de routage du routeur R1
Destination Interface Passerelle F 192.168.0.254 A 10.0.5.152 E 172.17.1.254 B 172.17.1.254 172.17.1.123 C 10.0.5.152 10.0.5.135Les trois r\u00e9seaux F, A et E sont directement accessibles au routeur R1, puisqu'il en fait partie : il n'a donc pas besoin d'adresse passerelle pour communiquer avec ces r\u00e9seaux.
Par contre, la communication avec le r\u00e9seau B n\u00e9cessite de confier le paquet au routeur R2 (c'est le choix de cette table de routage). Il faut donc mentionner l'adresse IP de ce routeur R2 (172.17.1.123), qu'on appelle adresse de passerelle.
De la m\u00eame mani\u00e8re, la communication avec le r\u00e9seau C n\u00e9cessite de confier le paquet au routeur R3 (c'est le choix de cette table de routage). Il faut donc mentionner l'adresse IP de ce routeur R3 (10.0.5.135).
"},{"location":"T5_Architecture_materielle/5.3_Protocoles_de_routage/cours/#comment-sont-construites-les-tables-de-routage","title":"Comment sont construites les tables de routage ?","text":"voir le TP d\u00e9branch\u00e9 : le jeu dont vous \u00eates le routeur
Les r\u00e8gles du protocole RIP
Le Routing Information Protocol (RIP) est bas\u00e9 sur l'\u00e9change (toutes les 30 secondes) des tables de routage de chaque routeur. Au d\u00e9but, chaque routeur ne conna\u00eet que les r\u00e9seaux auquel il est directement connect\u00e9, associ\u00e9 \u00e0 la distance 1. Ensuite, chaque routeur va recevoir p\u00e9riodiquement (toutes les 30 secondes) la table des r\u00e9seaux auquel il est connect\u00e9, et mettre \u00e0 jour sa propre table suivant les r\u00e8gles ci-dessous :
s'il d\u00e9couvre une route vers un nouveau r\u00e9seau inconnu, il l'ajoute \u00e0 sa table en augmentant de 1 la distance annonc\u00e9e par le routeur qui lui a transmis sa table.
s'il d\u00e9couvre une route vers un r\u00e9seau connu mais plus courte (en rajoutant 1) que celle qu'il poss\u00e8de dans sa table, il actualise sa table.
s'il d\u00e9couvre une route vers un r\u00e9seau connu mais plus longue que celle qu'il poss\u00e8de dans sa table, il ignore cette route.
s'il re\u00e7oit une route vers un r\u00e9seau connu en provenance d'un routeur d\u00e9j\u00e0 existant dans sa table, s'il met \u00e0 jour sa table car la topologie du r\u00e9seau a \u00e9t\u00e9 modifi\u00e9e.
si le r\u00e9seau n'\u00e9volue pas (panne ou ajout de nouveau mat\u00e9riel), les tables de routage convergent vers une valeur stable. Elles n'\u00e9voluent plus.
si un routeur ne re\u00e7oit pas pendant 3 minutes d'information de la part d'un routeur qui lui avait auparavant communiqu\u00e9 sa table de routage, ce routeur est consid\u00e9r\u00e9 comme en panne, et toutes les routes passant par lui sont affect\u00e9es de la distance infinie : 16.
Remarques et inconv\u00e9nients:
Le protocole RIP n'admet qu'une distance maximale \u00e9gale \u00e0 15 (ceci explique que 16 soit consid\u00e9r\u00e9 comme la distance infinie), ce qui le limite aux r\u00e9seaux de petite taille.
Chaque routeur n'a jamais connaissance de la topologie du r\u00e9seau tout entier : il ne le conna\u00eet que par ce que les autres routeurs lui ont racont\u00e9. On dit que ce protocole de routage est du routing by rumor.
La m\u00e9trique utilis\u00e9e (le nombre de sauts) ne tient pas compte de la qualit\u00e9 de la liaison, contrairement au protocole OSPF.
OSPF : Open Shortest Path First
Un inconv\u00e9nient majeur du protocole pr\u00e9c\u00e9dent est la non-prise en compte de la bande passante reliant les routeurs.
principe fondamental du protocole OSPF
Le chemin le plus rapide n'est pas forc\u00e9ment le plus court.
En gris, le chemin RIP. En bleu, l'OSPF.Dans le protocole OSPF, les tables de routage vont prendre en consid\u00e9ration la vitesse de communication entre les routeurs.
Dans une premi\u00e8re phase d'initialisation, chaque routeur va acqu\u00e9rir (par succession de messages envoy\u00e9s et re\u00e7us) la connaissance totale du r\u00e9seau (diff\u00e9rence fondamentale avec RIP) et de la qualit\u00e9 technique de la liaison entre chaque routeur.
"},{"location":"T5_Architecture_materielle/5.3_Protocoles_de_routage/cours/#31-les-differents-types-de-liaison-et-leur-cout","title":"3.1 Les diff\u00e9rents types de liaison et leur co\u00fbt","text":"On peut, approximativement, classer les types de liaison suivant ce tableau de d\u00e9bits th\u00e9oriques :
Technologie BP descendante BP montante Modem 56 kbit/s 48 kbit/s Bluetooth 3 Mbit/s 3 Mbit/s Ethernet 10 Mbit/s 10 Mbit/s Wi-Fi 10 Mbit/s ~ 10 Gbits/s 10 Mbit/s ~ 10 Gbits/s ADSL 13 Mbit/s 1 Mbit/s 4G 100 Mbit/s 50 Mbit/s Satellite 50 Mbit/s 1 Mbit/s Fast Ethernet 100 Mbit/s 100 Mbit/s FFTH (fibre) 10 Gbit/s 10 Gbit/s 5G 20 Gbit/s 10 Gbit/sL'id\u00e9e du protocole OSPF est de pond\u00e9rer chaque trajet entre routeurs (comptant simplement pour \u00ab1\u00bb dans le protocole RIP) par une valeur de co\u00fbt inversement proportionnelle au d\u00e9bit de transfert.
Par exemple, si le d\u00e9bit \\(d\\) est exprim\u00e9 en bits/s, on peut calculer le co\u00fbt de chaque liaison par la formule :
\\[ \\text{co\u00fbt} = \\frac{10^8}{d} \\]Cette formule de calcul peut \u00eatre diff\u00e9rente suivant les exercices, et sera syst\u00e9matiquement redonn\u00e9e. N\u00e9anmoins la valeur \\(d\\) sera toujours au d\u00e9nominateur, pour assurer la proportionnalit\u00e9 inverse du d\u00e9bit.
Avec cette convention, un route entre deux routeurs reli\u00e9s en Fast Ethernet (100 Mbits/s) aura a un poids de 1, une liaison satellite de 20 Mbits/s aura un poids de 5, etc.
"},{"location":"T5_Architecture_materielle/5.3_Protocoles_de_routage/cours/#32-exemple","title":"3.2 Exemple","text":"Reprenons le r\u00e9seau suivant :
et simplifions-le en ne gardant que les liens entre routeurs, en indiquant leur d\u00e9bit :
Notre r\u00e9seau est devenu un graphe.
Nous allons pond\u00e9rer ses ar\u00eates avec la fonction co\u00fbt introduite pr\u00e9c\u00e9demment. L'unit\u00e9 \u00e9tant le Mbit/s, l'ar\u00eate entre R1 et R3 aura un poids de \\(\\frac{100}{20}=5\\).
Le graphe pond\u00e9r\u00e9 est donc :
Le chemin le plus rapide pour aller de l'ordinateur au serveur est donc R1-R2-R4, et non plus R1-R3 comme l'aurait indiqu\u00e9 le protocole RIP.
"},{"location":"T5_Architecture_materielle/5.3_Protocoles_de_routage/cours/#33-trouver-le-plus-court-chemin-dans-un-graphe-pondere","title":"3.3 Trouver le plus court chemin dans un graphe pond\u00e9r\u00e9","text":"L'exemple pr\u00e9c\u00e9dent \u00e9tait tr\u00e8s simple et de solution intuitive. Dans le cas d'un graphe pond\u00e9r\u00e9 complexe, existe-t-il un algorithme de d\u00e9termination du plus court chemin d'un point \u00e0 un autre ?
La r\u00e9ponse est oui, depuis la d\u00e9couverte en 1959 par Edsger Dijkstra de l'algorithme qui porte son nom, l'algorithme de Dijkstra.
Pour le comprendre, vous pouvez regarder la vid\u00e9o d'un c\u00e9l\u00e8bre YouTuber :
Cet algorithme, ici ex\u00e9cut\u00e9 de mani\u00e8re manuelle, est bien s\u00fbr programmable. Et c'est donc gr\u00e2ce \u00e0 lui que chaque routeur calcule la route la plus rapide pour acheminer les donn\u00e9es qu'il re\u00e7oit.
Exercice d'application de l'algorithme de Dijkstra (HP)
Donner le plus court chemin pour aller de E \u00e0 F dans le graphe ci-dessous :
correction E A B C D F Choix 0 -- -- -- -- -- E(0) . 30vE -- 40vE 10vE -- D(10) . 20vD -- 40vE . 80vD A(20) . . 60vA 30vA . 80vD C(30) . . 50vC . . 80vD B(50) . . . . . 70vB F(70)Le meilleur trajet est donc E-D-A-C-B-F. Attention ce trajet correspond \u00e0 la colonne choix (dans l'ordre) mais c'est un hasard.
"},{"location":"T5_Architecture_materielle/5.3_Protocoles_de_routage/cours/#34-exercice","title":"3.4 Exercice","text":"(extrait du sujet 0)
On consid\u00e8re le r\u00e9seau suivant :
On rappelle que le co\u00fbt d\u2019une liaison est donn\u00e9 par la formule suivante :
\\[ \\text{co\u00fbt} = \\frac{10^8}{d} \\]Question 1
Question 2
Le routeur A doit transmettre un message au routeur G, en empruntant le chemin dont la somme des co\u00fbts sera la plus petite possible. D\u00e9terminer le chemin parcouru. On indiquera le raisonnement utilis\u00e9.
CorrectionQ1 1. \\(\\text{co\u00fbt} = \\dfrac{10^8}{10 \\times 10^9}= \\dfrac{10^8}{10^{10}}= 10^{-2}=0,01\\) 2. \\(5=\\dfrac{10^8}{d}\\) donc \\(d=\\dfrac{10^8}{5}=20 \\times 10^6\\) = 20 Mb/s
Q2 Le graphe pond\u00e9r\u00e9 par les co\u00fbts est :
On peut y deviner le chemin de co\u00fbt minimal entre A et G, qui est A-D-E-G (co\u00fbt 1,011). Pour le justifier, on peut (non obligatoire) faire un algorithme de Dijkstra :
Bibliographie
Utilisation des biblitoh\u00e8ques cryptographiques du module sympy
.
Documentation : https://docs.sympy.org/latest/modules/crypto.html
D\u00e9coder la phrase RYTVJKGCLJWRTZCVRMVTLEDFULCVHLZWRZKKFLKRMFKIVGCRTV
, sachant qu'elle a \u00e9t\u00e9 chiffr\u00e9e par d\u00e9calage (shift en anglais...)
from sympy.crypto.crypto import decipher_shift\n\nmsg = 'RYTVJKGCLJWRTZCVRMVTLEDFULCVHLZWRZKKFLKRMFKIVGCRTV'\n\nfor cle in range(26):\n phrase = decipher_shift(msg, cle)\n print(phrase)\n
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/Exercices/#exercice-2","title":"Exercice 2","text":"Chiffrage affine
Principe du chiffrage affine :
o\u00f9 \\(a\\) et \\(b\\) sont deux nombres entiers. Attention, a doit \u00eatre premier avec 26.
Q1. Codez votre fonction affine(msg, a, b)
def rang(lettre):\n return ord(lettre) - 65\n\ndef affine(msg, a, b):\n sol = \"\"\n for lettre in msg:\n rg = rang(lettre)\n nv_rg = (a*rg + b) % 26 #chiffrement affine\n nv_lettre = chr(nv_rg + 65)\n sol += nv_lettre\n return sol\n
Q2. Comparez vos r\u00e9sultats avec ceux obtenus par la fonction encipher_affine()
de sympy
.
Q3. D\u00e9codez la phrase UCGXLODCMOXPMFMSRJCFQOGTCRSUSXC
, sachant qu'elle contient le mot TRAVAIL
et que \\(a\\) et \\(b\\) sont inf\u00e9rieurs \u00e0 20.
from sympy.crypto.crypto import decipher_affine\nfrom math import gcd\n\nfor a in range(1,20):\n for b in range(1,20):\n if gcd(a,26) == 1:\n p = decipher_affine('UCGXLODCMOXPMFMSRJCFQOGTCRSUSXC', (a,b))\n if 'TRAVAIL' in p:\n print(p)\n
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/Exercices/#exercice-3","title":"Exercice 3","text":"Cryptographie RSA presque \u00e0 la main
import Crypto\nimport libnum\nfrom Crypto.Util.number import bytes_to_long, long_to_bytes\nfrom Crypto.Random import get_random_bytes \n\nbits = 256\nmsg = \"en NSI on fait de la crypto\"\n\np = Crypto.Util.number.getPrime(bits, randfunc=get_random_bytes)\nq = Crypto.Util.number.getPrime(bits, randfunc=get_random_bytes)\n\nn = p * q\nphi = (p - 1) * (q - 1)\n\ne = 65537 # 65537 est un nombre premier, donc forc\u00e9ment premier avec phi\nd = libnum.invmod(e, phi) # on calcule l'inverse de e modulo phi\n\nM = bytes_to_long(msg.encode('utf-8'))\n\nc = pow(M, e, n) # M puissance e modulo n\nres = pow(c, d, n)\n\nprint(long_to_bytes(res))\n
En vous servant du code pr\u00e9c\u00e9dent, d\u00e9chiffrez le message 58152918114477529438769495136495430966050302170947748011925859233600631318929939319619808279389222131229963717435870597641010567365311762267359794338657867540621133550787677728203831932548041236152866441194127191404729294628415184239755221703677388875259927092794165578604353985011899152968982365630138088486380827379488939561996226754182
sachant que :
module RSA dans les r\u00e8gles de l'art
from Crypto.PublicKey import RSA\nfrom Crypto.Cipher import PKCS1_OAEP\nimport binascii\n\nkeyPair = RSA.generate(1024)\n\npubKey = keyPair.publickey()\n\npubKeyPEM = pubKey.exportKey()\n\nprivKeyPEM = keyPair.exportKey()\n\n\nmsg = b'vive la crypto en NSI !'\nencryptor = PKCS1_OAEP.new(pubKey)\nencrypted = encryptor.encrypt(msg)\nprint(\"Encrypted:\", binascii.hexlify(encrypted))\n\n\ndecryptor = PKCS1_OAEP.new(keyPair)\ndecrypted = decryptor.decrypt(encrypted)\nprint('Decrypted:', decrypted)\n
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/","title":"Cryptographie","text":""},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#1-chiffrement-symetrique","title":"1. Chiffrement sym\u00e9trique","text":""},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#11-activite-du-masque-jetable","title":"1.1 Activit\u00e9 du masque jetable","text":"Exercice
\u00c9nonc\u00e9AideCorrectionOn consid\u00e8re la variable suivante :
masque = \"CETTEPHRASEESTVRAIMENTTRESTRESLONGUEMAISCESTFAITEXPRES\"\n
chiffre(message, masque)
qui chiffre message
en le XORant avec masque
.XOR
(voir ici) est une op\u00e9ration sym\u00e9trique : >>> 34 ^ 23\n53\n>>> 53 ^ 23\n34\n
ord
permet de renvoyer le code ASCII d'un caract\u00e8re. La fonction chr
fait l'op\u00e9ration inverse. >>> ord('A')\n65\n>>> chr(65)\n'A'\n
masque = \"CETTEPHRASEESTVRAIMENTTRESTRESLONGUEMAISCESTFAITEXPRES\"\n\ndef chiffre(message, masque):\n message_chiffre = \"\"\n for i in range(len(message)):\n lettre_chiffree = chr(ord(message[i]) ^ ord(masque[i]))\n message_chiffre += lettre_chiffree\n return message_chiffre\n
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#12-principe-du-chiffrement-symetrique","title":"1.2 Principe du chiffrement sym\u00e9trique","text":"Chiffrement sym\u00e9trique
Dans un chiffrement sym\u00e9trique, c'est la m\u00eame cl\u00e9 qui va servir au chiffrement et au d\u00e9chiffrement.
Illustration :
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#quappelle-t-on-une-cle","title":"Qu'appelle-t-on une cl\u00e9 ?","text":"La cl\u00e9 est un renseignement permettant de chiffrer ou d\u00e9chiffrer un message. Cela peut \u00eatre :
Un chiffrement est dit sym\u00e9trique lorsque la connaissance de la cl\u00e9 ayant servi au chiffrement permet de d\u00e9chiffrer le message. Par exemple, Alice chiffre son message en d\u00e9calant les lettres de 3 rangs vers la droite dans l'alphabet, Bob saura qu'il doit les d\u00e9caler de 3 rangs vers la gauche pour retrouver le message initial.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#quel-est-lavantage-dun-chiffrement-symetrique","title":"Quel est l'avantage d'un chiffrement sym\u00e9trique ?","text":"Les chiffrements sym\u00e9triques sont souvent rapides, consommant peu de ressources et donc adapt\u00e9s au chiffrement de flux important d'informations.
Comme nous le verrons, la s\u00e9curisation des donn\u00e9es transitant par le protocole https
est bas\u00e9e sur un chiffrement sym\u00e9trique.
La cl\u00e9 ! Si Alice et Bob ont besoin d'utiliser un chiffrement pour se parler, comment peuvent-ils \u00e9changer leurs cl\u00e9s puisque leur canal de transmission n'est pas s\u00fbr ?
Le chiffrement sym\u00e9trique impose qu'Alice et Bob aient pu se rencontrer physiquement au pr\u00e9alable pour convenir d'une cl\u00e9 secr\u00e8te, ou bien qu'ils aient r\u00e9ussi \u00e0 \u00e9tablir une connexion s\u00e9curis\u00e9e pour s'\u00e9changer cette cl\u00e9.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#un-chiffrement-symetrique-est-il-un-chiffrement-de-mauvaise-qualite","title":"Un chiffrement sym\u00e9trique est-il un chiffrement de mauvaise qualit\u00e9 ?","text":"Pas du tout ! S'il est associ\u00e9 naturellement \u00e0 des chiffrements simples et faibles (comme le d\u00e9calage de C\u00e9sar), un chiffrement sym\u00e9trique peut \u00eatre tr\u00e8s robuste... voire inviolable.
C'est le cas du masque jetable. Si le masque avec lequel on effectue le XOR sur le message est aussi long que le message, alors il est impossible de retrouver le message initial. Pourquoi ?
Imaginons qu'Alice veuille transmettre le message clair \"LUNDI\". Elle le chiffre avec un masque jetable (que connait aussi Bob), et Bob re\u00e7oit donc \"KHZOK\". Si Marc a intercept\u00e9 le message \"KHZOK\", m\u00eame s'il sait que la m\u00e9thode de chiffrement utilis\u00e9e est celle du masque jetable (principe de Kerckhoffs), il n'a pas d'autre choix que de tester tous les masques de 5 lettres possibles.
Principe de Kerckhoffs
La s\u00e9curit\u00e9 d'un syst\u00e8me de chiffrement ne doit reposer que sur le secret de la cl\u00e9, et non pas sur la connaissance de l'algorithme de chiffrement. Cet algorithme peut m\u00eame \u00eatre public (ce qui est pratiquement toujours le cas).
Ce qui lui donne \\(26^5\\) possibilit\u00e9s (plus de 11 millions) pour le masque, et par cons\u00e9quent (propri\u00e9t\u00e9 de bijectivit\u00e9 du XOR) \\(26^5\\) possibilit\u00e9s pour le message \u00abd\u00e9chiffr\u00e9\u00bb...
Cela signifie que Marc verra appara\u00eetre, dans sa tentative de d\u00e9chiffrage, les mots \"MARDI\", \"JEUDI\", \"JOUDI\", \"STYLO\", \"FSDJK\", \"LUNDI\", \"LUNDA\"... Il n'a aucune possibilit\u00e9 de savoir o\u00f9 est le bon message original parmi toutes les propositions (on parle de s\u00e9curit\u00e9 s\u00e9mantique).
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#quels-sont-les-chiffrements-symetriques-modernes","title":"Quels sont les chiffrements sym\u00e9triques modernes ?","text":"L'algorithme de chiffrement sym\u00e9trique le plus utilis\u00e9 actuellement est le chiffrement AES, pour Advanced Encryption Standard.
Invent\u00e9 par Whitfield Diffie et Martin Hellman en 1976, le chiffrement asym\u00e9trique vient r\u00e9soudre l'inconv\u00e9nient essentiel du chiffrement sym\u00e9trique : le n\u00e9cessaire partage d'un secret (la cl\u00e9) avant l'\u00e9tablissement de la communication s\u00e9curis\u00e9e.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#21-principe-du-chiffrement-asymetrique","title":"2.1 Principe du chiffrement asym\u00e9trique","text":"Le principe de base est l'existence d'une cl\u00e9 publique, appel\u00e9e \u00e0 \u00eatre distribu\u00e9e largement, et d'une cl\u00e9 priv\u00e9e, qui ne quitte jamais son propri\u00e9taire.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#22-le-role-interchangeable-des-cles-publiques-et-privees","title":"2.2 Le r\u00f4le interchangeable des cl\u00e9s publiques et priv\u00e9es","text":"L'illustration pr\u00e9c\u00e9dente associe :
Concr\u00e8tement, (nous le verrons dans l'application par le chiffrement RSA), la cl\u00e9 priv\u00e9e et la cl\u00e9 publique sont deux nombres aux r\u00f4les identiques. Appelons-les A et B :
A et B ont donc des r\u00f4les interchangeables (chacun peut \u00eatre un cadenas, chacun peut \u00eatre une cl\u00e9), et ce n'est qu'en connaissant A et B qu'on peut d\u00e9chiffrer le message.
Nous allons donc maintenant adopter une nouvelle convention infographique :
Si ce message est chiffr\u00e9 avec la cl\u00e9 publique d'Alice, le message sera :
Si on d\u00e9chiffre ce message avec la cl\u00e9 priv\u00e9e d'Alice, il deviendra et donc
puisque l'application de la cl\u00e9 priv\u00e9e sur la cl\u00e9 publique, ou bien de la cl\u00e9 publique sur la cl\u00e9 priv\u00e9e, permet de retrouver le message en clair.
De mani\u00e8re graphique, la connaissance des deux moiti\u00e9s du disque qui s'assemblent permet de les faire disparaitre, peu importe qu'on ait commenc\u00e9 par chiffrer avec la cl\u00e9 publique ou avec la cl\u00e9 priv\u00e9e.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#23-communication-authentifiee","title":"2.3 Communication authentifi\u00e9e.","text":"Dans la situation du 2.1, Alice (qui a distribu\u00e9 largement sa cl\u00e9 publique) ne peut pas s'assurer que le message vient bien de Bob. Il peut avoir \u00e9t\u00e9 cr\u00e9\u00e9 par Marc, qui signe \u00abBob\u00bb et usurpe ainsi son identit\u00e9.
Le protocole que nous allons d\u00e9crire ci-dessous permet :
En r\u00e9sum\u00e9 :
Lorsqu'en 1976 Diffie et Hellman (chercheurs \u00e0 Stanford) pr\u00e9sentent le concept de chiffrement asym\u00e9trique (souvent appel\u00e9 cryptographie \u00e0 cl\u00e9s publiques), ils en proposent uniquement un mod\u00e8le th\u00e9orique, n'ayant pas trouv\u00e9 une r\u00e9elle impl\u00e9mentation de leur protocole.
Trois chercheurs du MIT (Boston), Ron Rivest, Adi Shamir et Len Adleman se penchent alors sur ce protocole, convaincus qu'il est en effet impossible d'en trouver une impl\u00e9mentation pratique. En 1977, au cours de leurs recherches, ils d\u00e9montrent en fait l'inverse de ce qu'ils cherchaient : ils cr\u00e9ent le premier protocole concret de chiffrement asym\u00e9trique : le chiffrement RSA.
Au m\u00eame moment \u00e0 Londres, Clifford Cocks, (chercheur au tr\u00e8s secret GCHQ) apprend que Rivest Shamir et Adleman viennent de d\u00e9couvrir ce que lui-m\u00eame a d\u00e9couvert 3 ans auparavant mais qui est rest\u00e9 class\u00e9 Secret D\u00e9fense.
Il est le v\u00e9ritable inventeur du RSA... mais le reste du monde ne l'apprendra qu'en 1997 au moment de la d\u00e9classification de cette information.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#231-description","title":"2.3.1 Description","text":"Le chiffrement RSA est bas\u00e9 sur l'arithm\u00e9tique modulaire. Faire des calculs modulo un entier \\(n\\), c'est ne garder que le reste de la division euclidienne par \\(n\\).
Le fait que 15 soit \u00e9gal \u00e0 1 modulo 7 (car \\(15=2 \\times 7+1\\)) s'\u00e9crira \\(15 \\equiv 1 [7]\\).
De m\u00eame, \\(10 \\equiv 3 [7]\\), \\(25 \\equiv 4 [7]\\), \\(32 \\equiv 2 [10]\\), etc.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#etape-1","title":"\u00c9tape 1","text":"Alice choisit 2 grands nombres premiers \\(p\\) et \\(q\\). Dans la r\u00e9alit\u00e9 ces nombres seront vraiment tr\u00e8s grands (plus de 100 chiffres). Dans notre exemple, nous prendrons \\(p = 3\\) et \\(q = 11\\).
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#etape-2","title":"\u00c9tape 2","text":"Alice multiplie ces deux nombres \\(p\\) et \\(q\\) et obtient ainsi un nombre \\(n\\).
Il est tr\u00e8s facile pour Alice de calculer \\(n\\) en connaissant \\(p\\) et \\(q\\), mais il extr\u00eamement difficile pour Marc de faire le travail inverse : trouver \\(p\\) et \\(q\\) en connaissant \\(n\\) prend un temps exponentiel avec la taille de \\(n\\). C'est sur cette difficult\u00e9 (appel\u00e9e difficult\u00e9 de factorisation) que repose la robustesse du syst\u00e8me RSA.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#etape-3","title":"\u00c9tape 3","text":"Alice choisit un nombre \\(e\\) qui doit \u00eatre premier avec \\((p-1)(q-1)\\). On note \\(\\phi(n)\\) le nombre \\((p-1)(q-1)\\).
Dans notre exemple, \\((p-1)(q-1) = 20\\), Alice choisit donc \\(e = 3\\). (mais elle aurait pu aussi choisir 7, 9, 13...).
Le couple \\((e, n)\\) sera la cl\u00e9 publique d'Alice. Elle la diffuse \u00e0 qui veut lui \u00e9crire.
Dans notre exemple, la cl\u00e9 publique d'Alice est \\((3, 33)\\).
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#etape-4","title":"\u00c9tape 4","text":"Alice calcule maintenant sa cl\u00e9 priv\u00e9e : elle doit trouver un nombre d qui v\u00e9rifie l'\u00e9galit\u00e9 \\(e d \\equiv 1 [\\phi(n)]\\).
Dans notre exemple, comme \\(7 \\times 3 \\equiv 1 [20]\\), ce nombre \\(d\\) est \u00e9gal \u00e0 7.
En pratique, il existe un algorithme simple (algorithme d'Euclide \u00e9tendu) pour trouver cette valeur \\(d\\), appel\u00e9e inverse de e.
Le couple \\((d, n)\\) sera la cl\u00e9 priv\u00e9e d'Alice. Elle ne la diffuse \u00e0 personne.
Dans notre exemple, la cl\u00e9 priv\u00e9e d'Alice est \\((7, 33)\\).
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#etape-5","title":"\u00c9tape 5","text":"Supposons que Bob veuille \u00e9crire \u00e0 Alice pour lui envoyer le nombre 4. Il poss\u00e8de la cl\u00e9 publique d'Alice, qui est \\((3, 33)\\).
Il calcule donc \\(4^3\\) modulo 33, qui vaut 31. C'est cette valeur 31 qu'il transmet \u00e0 Alice.
\\[4^3 \\equiv 31 [33]\\]Si Marc intercepte cette valeur 31, m\u00eame en connaissant la cl\u00e9 publique d'Alice (3,33), il ne peut pas r\u00e9soudre l'\u00e9quation \\(x^3 \\equiv 31 [33]\\) de mani\u00e8re efficace.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#etape-6","title":"\u00c9tape 6","text":"Alice re\u00e7oit la valeur 31. Il lui suffit alors d'\u00e9lever 31 \u00e0 la puissance 7 (sa cl\u00e9 priv\u00e9e), et de calculer le reste modulo 33 :
\\(31^7 = 27512614111\\)
\\(27512614111 \\equiv 4 [33]\\)
Elle r\u00e9cup\u00e8re la valeur 4, qui est bien le message original de Bob.
Comment \u00e7a marche ? Gr\u00e2ce au Petit Th\u00e9or\u00e8me de Fermat, on d\u00e9montre (voir ici) assez facilement que \\(M^{ed} \\equiv M [n]\\).
Il faut remarquer que \\(M^{ed} = M^{de}\\). On voit que les r\u00f4les de la cl\u00e9 publique et de la cl\u00e9 priv\u00e9e sont sym\u00e9triques : un message chiffr\u00e9 avec la cl\u00e9 publique se d\u00e9chiffrera en le chiffrant avec la cl\u00e9 priv\u00e9e, tout comme un message chiffr\u00e9 avec la cl\u00e9 priv\u00e9e se d\u00e9chiffrera en le chiffrant avec la cl\u00e9 publique.
Animation interactive voir https://animations.interstices.info/interstices-rsa/rsa.html
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#rsa-un-systeme-inviolable","title":"RSA, un syst\u00e8me inviolable ?","text":"Le chiffrement RSA a des d\u00e9fauts (notamment une grande consommation des ressources, due \u00e0 la manipulation de tr\u00e8s grands nombres). Mais le choix d'une cl\u00e9 publique de grande taille (actuellement 1024 ou 2048 bits) le rend pour l'instant inviolable.
Actuellement, il n'existe pas d'algorithme efficace pour factoriser un nombre ayant plusieurs centaines de chiffres.
Deux \u00e9v\u00e8nements pourraient faire s'\u00e9crouler la s\u00e9curit\u00e9 du RSA :
Aujourd'hui, plus de 90 % du trafic sur internet est chiffr\u00e9 : les donn\u00e9es ne transitent plus en clair (protocole http
) mais de mani\u00e8re chiffr\u00e9e (protocole https
), ce qui emp\u00eache la lecture de paquets \u00e9ventuellements intercept\u00e9s.
Le protocole https
est la r\u00e9union de deux protocoles :
TLS
(Transport Layer Security, qui a succ\u00e9d\u00e9 au SSL) : ce protocole, bas\u00e9 sur du chiffrement asym\u00e9trique, va conduire \u00e0 la g\u00e9n\u00e9ration d'une cl\u00e9 identique chez le client et chez le serveur.http
, mais qui convoiera maintenant des donn\u00e9es chiffr\u00e9es avec la cl\u00e9 g\u00e9n\u00e9r\u00e9e \u00e0 l'\u00e9tape pr\u00e9c\u00e9dente. Les donn\u00e9es peuvent toujours \u00eatre intercept\u00e9es, mais sont illisibles. Le chiffrement sym\u00e9trique utilis\u00e9 est actuellement le chiffrement AES.Pourquoi ne pas utiliser que le chiffrement asym\u00e9trique, RSA par exemple ? Car il est tr\u00e8s gourmand en ressources ! Le chiffrement/d\u00e9chiffrement doit \u00eatre rapide pour ne pas ralentir les communications ou l'exploitation des donn\u00e9es. Le chiffrement asym\u00e9trique est donc r\u00e9serv\u00e9 \u00e0 l'\u00e9change de cl\u00e9s (au d\u00e9but de la communication). Le chiffrement sym\u00e9trique, bien plus rapide, prend ensuite le relais pour l'ensemble de la communication.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#32-hp-fonctionnement-du-tls-explication-du-handshake","title":"3.2 (HP) Fonctionnement du TLS : explication du handshake","text":"Observons en d\u00e9tail le fonctionnement du protocole TLS
, dont le r\u00f4le est de g\u00e9n\u00e9rer de mani\u00e8re s\u00e9curis\u00e9e une cl\u00e9 dont disposeront \u00e0 la fois le client et le serveur, leur permettant ainsi d'appliquer un chiffrement sym\u00e9trique \u00e0 leurs \u00e9changes.
\u00e9tape 1 : le \u00abclient Hello\u00bb. Le client envoie sa version de TLS utilis\u00e9e.
\u00e9tape 2 : le \u00abserver Hello\u00bb. Le serveur r\u00e9pond en renvoyant son certificat prouvant son identit\u00e9, ainsi que sa cl\u00e9 publique.
\u00e9tape 3 : le client interroge l'autorit\u00e9 de certification pour valider le fait que le certificat est bien valide et que le serveur est bien celui qu'il pr\u00e9tend \u00eatre. Cette v\u00e9rification est faite gr\u00e2ce \u00e0 un m\u00e9canisme de chiffrement asym\u00e9trique.
La pr\u00e9sentation du certificat \u00e0 l'autorit\u00e9 de certification peut se repr\u00e9senter comme le scan d'une pi\u00e8ce d'identit\u00e9 dans un a\u00e9roport. L'autorit\u00e9 de certification est alors l'\u00c9tat (dont la base de donn\u00e9es est interrog\u00e9e par un logiciel) qui valide que la pi\u00e8ce d'identit\u00e9 est bien un document officiel.
Le transmission par protocole http
de donn\u00e9es chiffr\u00e9es au pr\u00e9alable avec la cl\u00e9 AES peut commencer.
Remarque : en r\u00e9alit\u00e9, ce n'est pas la cl\u00e9 AES qui est transmise \u00e0 l'\u00e9tape 4, mais un nombre choisi par le client, qui permettra, avec deux autres nombres choisis par le client (\u00e9tape 1) et le serveur (\u00e9tape 2) de reconstituer la cl\u00e9 AES, qui sera donc identique c\u00f4t\u00e9 client et c\u00f4t\u00e9 serveur.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#bibliographie","title":"Bibliographie","text":"Vous pouvez consulter le cours de Premi\u00e8re \u00e0 l'adresse https://glassus.github.io/premiere_nsi/.
Penser \u00e0 utiliser la barre de recherche pour vous aider dans votre navigation.
"},{"location":"T6_5_algos_coeur/cours/","title":"Algorithmes de r\u00e9f\u00e9rence","text":""},{"location":"T6_5_algos_coeur/cours/#1-factorielle-recursive","title":"1. Factorielle r\u00e9cursive","text":"def factorielle(n):\n if n == 1:\n return 1\n else:\n return n * factorielle(n - 1)\n
"},{"location":"T6_5_algos_coeur/cours/#2-pgcd-recursif","title":"2. PGCD r\u00e9cursif","text":"def pgcd(a, b):\n if b == 0:\n return a\n else:\n return pgcd(b, a%b)\n
"},{"location":"T6_5_algos_coeur/cours/#3-puissance-recursive-simple","title":"3. Puissance r\u00e9cursive (simple)","text":"def puissance(x, n):\n if n == 0:\n return 1\n else:\n return x * puissance(x, n-1)\n
"},{"location":"T6_5_algos_coeur/cours/#4-puissance-recursive-optimisee","title":"4. Puissance r\u00e9cursive (optimis\u00e9e)","text":"def puissance(x, n):\n if n == 0:\n return 1\n else:\n if n % 2 == 0:\n return puissance(x*x, n//2)\n else :\n return x*puissance(x*x, (n-1)//2)\n
"},{"location":"T6_5_algos_coeur/cours/#5-recherche-dichotomique-recursive-avec-slicing","title":"5. Recherche dichotomique r\u00e9cursive (avec slicing)","text":"Note : le slicing de liste n'est pas au programme de NSI.
def recherche(lst, m):\n if len(lst) == 1: \n if lst[0] == m:\n return True\n else :\n return False\n else: \n mid = len(lst)//2\n if lst[mid] > m:\n return recherche(lst[:mid], m)\n else :\n return recherche(lst[mid:], m)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/","title":"\u00c9preuve pratique \ud83d\udcbb","text":"Vous trouverez ci-dessous l'int\u00e9gralit\u00e9 des sujets de l'\u00e9preuve pratique, disponibles publiquement sur la Banque Nationale des Sujets (novembre 2021).
Une nouvelle version (qui sera a priori en grande partie semblable \u00e0 celle-ci) sera publi\u00e9e en janvier 2022 sur le site Eduscol.
update : les sujets sont disponibles, une premi\u00e8re version centralis\u00e9e se trouve ici
Rappel des conditions de passation sur cette page.
Pdf de l'int\u00e9gralit\u00e9 des exercices.
Exercice 01.1
\u00c9nonc\u00e9CorrectionProgrammer la fonction recherche
, prenant en param\u00e8tre un tableau non vide tab
(type list
) d'entiers et un entier n
, et qui renvoie l'indice de la derni\u00e8re occurrence de l'\u00e9l\u00e9ment cherch\u00e9. Si l'\u00e9l\u00e9ment n'est pas pr\u00e9sent, la fonction renvoie la longueur du tableau.
Exemples
>>> recherche([5, 3],1)\n2\n>>> recherche([2,4],2)\n0\n>>> recherche([2,3,5,2,4],2)\n3\n
def recherche(tab, n):\n indice_solution = len(tab)\n for i in range(len(tab)):\n if tab[i] == n:\n indice_solution = i\n return indice_solution\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-012","title":"Exercice 01.2 \u25a1","text":"Exercice 01.2
\u00c9nonc\u00e9CorrectionOn souhaite programmer une fonction donnant la distance la plus courte entre un point de d\u00e9part et une liste de points. Les points sont tous \u00e0 coordonn\u00e9es enti\u00e8res. Les points sont donn\u00e9s sous la forme d'un tuple de deux entiers. La liste des points \u00e0 traiter est donc un tableau de tuples.
On rappelle que la distance entre deux points du plan de coordonn\u00e9es \\((x;y)\\) et \\((x';y')\\) est donn\u00e9e par la formule :
\\[d=\\sqrt{(x-x')^2+(y-y')^2}\\]On importe pour cela la fonction racine carr\u00e9e (sqrt
) du module math
de Python.
On dispose d'une fonction distance
et d'une fonction plus_courte_distance
:
from math import sqrt # import de la fonction racine carr\u00e9e\n\ndef distance(point1, point2):\n\"\"\" Calcule et renvoie la distance entre deux points. \"\"\"\n return sqrt((...)**2 + (...)**2)\n\nassert distance((1, 0), (5, 3)) == 5.0, \"erreur de calcul\"\n\ndef plus_courte_distance(tab, depart):\n\"\"\" Renvoie le point du tableau tab se trouvant \u00e0 la plus courte distance du point depart.\"\"\"\n point = tab[0]\n min_dist = ...\n for i in range (1, ...):\n if distance(tab[i], depart)...:\n point = ...\n min_dist = ...\n return point\n\nassert plus_courte_distance([(7, 9), (2, 5), (5, 2)], (0, 0)) == (2, 5), \"erreur\"\n
Recopier sous Python (sans les commentaires) ces deux fonctions puis compl\u00e9ter leur code et ajouter une ou des d\u00e9clarations (assert
) \u00e0 la fonction distance
permettant de v\u00e9rifier la ou les pr\u00e9conditions. from math import sqrt\n\ndef distance(point1, point2):\n\"\"\" Calcule et renvoie la distance entre deux points. \"\"\"\n return sqrt((point1[0] - point2[0])**2 + ((point1[1] - point2[1]))**2)\n\nassert distance((1, 0), (5, 3)) == 5.0, \"erreur de calcul\"\n\n\ndef plus_courte_distance(tab, depart):\n\"\"\" Renvoie le point du tableau tab se trouvant \u00e0 la plus courte distance du point depart.\"\"\"\n point = tab[0]\n min_dist = distance(point, depart)\n for i in range (1, len(tab)):\n if distance(tab[i], depart) < min_dist:\n point = tab[i]\n min_dist = distance(tab[i], depart)\n return point\n\nassert plus_courte_distance([(7, 9), (2, 5), (5, 2)], (0, 0)) == (2, 5), \"erreur\"\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-021","title":"Exercice 02.1 \u25a1","text":"Exercice 02.1
\u00c9nonc\u00e9CorrectionProgrammer la fonction moyenne
prenant en param\u00e8tre un tableau d'entiers tab
(type list
) qui renvoie la moyenne de ses \u00e9l\u00e9ments si le tableau est non vide et affiche 'erreur' si le tableau est vide.
Exemples :
>>> moyenne([5,3,8])\n5.333333333333333\n>>> moyenne([1,2,3,4,5,6,7,8,9,10])\n5.5\n>>> moyenne([])\n'erreur'\n
L'\u00e9nonc\u00e9 n'est pas tr\u00e8s clair quand il dit \u00abd'afficher 'erreur'\u00bb (ce qui suppose un print
et non un return
). Nous choississons donc dans ce cas de renvoyer None
.
def moyenne(tab):\n if tab == []:\n print('erreur')\n return None\n else:\n somme = 0\n for elt in tab:\n somme += elt\n return somme / len(tab)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-022","title":"Exercice 02.2 \u25a1","text":"Exercice 02.2
\u00c9nonc\u00e9CorrectionOn consid\u00e8re un tableau d'entiers tab
(type list
dont les \u00e9l\u00e9ments sont des 0
ou des 1
). On se propose de trier ce tableau selon l'algorithme suivant : \u00e0 chaque \u00e9tape du tri,le tableau est constitu\u00e9 de trois zones cons\u00e9cutives, la premi\u00e8re ne contenant que des 0
, la seconde n'\u00e9tant pas tri\u00e9e et la derni\u00e8re ne contenant que des 1
.
Zone de 0Zone non tri\u00e9eZone de 1
Tant que la zone non tri\u00e9e n'est pas r\u00e9duite \u00e0 un seul \u00e9l\u00e9ment, on regarde son premier \u00e9l\u00e9ment :
Dans tous les cas, la longueur de la zone non tri\u00e9e diminue de 1.
Recopier sous Python en la compl\u00e9tant la fonction tri
suivante :
def tri(tab):\n #i est le premier indice de la zone non triee, j le dernier indice.\n #Au debut, la zone non triee est le tableau entier.\n i = ...\n j = ...\n while i != j :\n if tab[i]== 0:\n i = ...\n else :\n valeur = tab[j]\n tab[j] = ...\n ...\n j = ...\n ...\n
Exemple :
>>> tri([0,1,0,1,0,1,0,1,0])\n[0, 0, 0, 0, 0, 1, 1, 1, 1] \n
def tri(tab):\n #i est le premier indice de la zone non triee, j le dernier indice.\n #Au debut, la zone non triee est le tableau entier.\n i = 0\n j = len(tab) - 1\n while i != j :\n if tab[i]== 0:\n i = i + 1\n else :\n valeur = tab[j]\n tab[j] = tab[i]\n tab[i] = valeur\n j = j - 1\n return tab\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-031","title":"Exercice 03.1 \u25a1","text":"Exercice 03.1
\u00c9nonc\u00e9CorrectionProgrammer la fonction multiplication
, prenant en param\u00e8tres deux nombres entiers n1
et n2
, et qui renvoie le produit de ces deux nombres. Les seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.
\u00c9nonc\u00e9 peu clair, on ne sait pas si n1
et n2
sont entiers naturels ou relatifs. Nous d\u00e9cidons qu'ils sont relatifs et donc qu'ils peuvent \u00eatre n\u00e9gatifs, auquel cas on utilise le fait que \\(5 \\times (-6)= - (5 \\times 6)\\).
def multiplication(n1, n2):\n if n1 < 0:\n return -multiplication(-n1, n2)\n if n2 < 0:\n return -multiplication(n1, -n2)\n resultat = 0\n for _ in range(n2):\n resultat += n1\n return resultat\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-032","title":"Exercice 03.2 \u25a1","text":"Exercice 03.2
\u00c9nonc\u00e9CorrectionRecopier et compl\u00e9ter sous Python la fonction suivante en respectant la sp\u00e9cification. On ne recopiera pas les commentaires.
def dichotomie(tab, x):\n\"\"\"\n tab : tableau d\u2019entiers tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\nFalse\n
def dichotomie(tab, x):\n\"\"\"\n tab : tableau d\u2019entiers tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = (debut + fin) // 2\n if x == tab[m]:\n return True\n if x > tab[m]:\n debut = m + 1\n else:\n fin = m - 1\n return False\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-041","title":"Exercice 04.1 \u25a1","text":"Exercice 04.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction qui prend en param\u00e8tre un tableau d'entiers non vide et qui renvoie la moyenne de ces entiers. La fonction est sp\u00e9cifi\u00e9e ci-apr\u00e8s et doit passer les assertions fournies.
def moyenne (tab):\n'''\n moyenne(list) -> float\n Entr\u00e9e : un tableau non vide d'entiers\n Sortie : nombre de type float\n Correspondant \u00e0 la moyenne des valeurs pr\u00e9sentes dans le\n tableau\n '''\n\nassert moyenne([1]) == 1\nassert moyenne([1,2,3,4,5,6,7] == 4\nassert moyenne([1,2]) == 1.5\n
def moyenne(tab):\n'''\n moyenne(list) -> float\n Entr\u00e9e : un tableau non vide d'entiers\n Sortie : nombre de type float\n Correspondant \u00e0 la moyenne des valeurs pr\u00e9sentes dans le\n tableau\n '''\n somme = 0\n for elt in tab:\n somme += elt\n return somme / len(tab)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-042","title":"Exercice 04.2 \u25a1","text":"Exercice 04.2
\u00c9nonc\u00e9CorrectionLe but de l'exercice est de compl\u00e9ter une fonction qui d\u00e9termine si une valeur est pr\u00e9sente dans un tableau de valeurs tri\u00e9es dans l'ordre croissant.
L'algorithme traite le cas du tableau vide.
L'algorithme est \u00e9crit pour que la recherche dichotomique ne se fasse que dans le cas o\u00f9 la valeur est comprise entre les valeurs extr\u00eames du tableau.
On distingue les trois cas qui renvoient False
en renvoyant False,1
, False,2
et False,3
.
Compl\u00e9ter l'algorithme de dichotomie donn\u00e9 ci-apr\u00e8s.
def dichotomie(tab, x):\n\"\"\"\n tab : tableau tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n # cas du tableau vide\n if ...:\n return False,1\n # cas o\u00f9 x n'est pas compris entre les valeurs extr\u00eames\n if (x < tab[0]) or ...:\n return False,2\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\n(False, 3)\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],1)\n(False, 2)\n>>> dichotomie([],28)\n(False, 1)\n
def dichotomie(tab, x):\n\"\"\"\n tab : tableau tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n # cas du tableau vide\n if tab = []:\n return False,1\n # cas o\u00f9 x n'est pas compris entre les valeurs extr\u00eames\n if (x < tab[0]) or (x > tab[-1]):\n return False,2\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = (debut + fin) // 2\n if x == tab[m]:\n return True\n if x > tab[m]:\n debut = m + 1\n else:\n fin = m - 1\n return False\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-051","title":"Exercice 05.1 \u25a1","text":"Exercice 05.1
\u00c9nonc\u00e9CorrectionOn mod\u00e9lise la repr\u00e9sentation binaire d'un entier non sign\u00e9 par un tableau d'entiers dont les \u00e9l\u00e9ments sont 0 ou 1. Par exemple, le tableau [1, 0, 1, 0, 0, 1, 1]
repr\u00e9sente l'\u00e9criture binaire de l'entier dont l'\u00e9criture d\u00e9cimale est 2**6 + 2**4 + 2**1 + 2**0 = 83
.
\u00c0 l'aide d'un parcours s\u00e9quentiel, \u00e9crire la fonction convertir r\u00e9pondant aux sp\u00e9cifications suivantes :
def convertir(T):\n\"\"\"\n T est un tableau d'entiers, dont les \u00e9l\u00e9ments sont 0 ou 1 et\n repr\u00e9sentant un entier \u00e9crit en binaire. Renvoie l'\u00e9criture\n d\u00e9cimale de l'entier positif dont la repr\u00e9sentation binaire\n est donn\u00e9e par le tableau T\n \"\"\"\n
Exemple : >>> convertir([1, 0, 1, 0, 0, 1, 1])\n83\n>>> convertir([1, 0, 0, 0, 0, 0, 1, 0])\n130\n
def convertir(T):\n puissance = 0\n total = 0\n for i in range(len(T)-1, -1, -1):\n total += T[i]*(2**puissance)\n puissance += 1\n return total\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-052","title":"Exercice 05.2 \u25a1","text":"Exercice 05.2
\u00c9nonc\u00e9CorrectionLa fonction tri_insertion
suivante prend en argument une liste L
et trie cette liste en utilisant la m\u00e9thode du tri par insertion. Compl\u00e9ter cette fonction pour qu'elle r\u00e9ponde \u00e0 la sp\u00e9cification demand\u00e9e.
def tri_insertion(L):\n n = len(L)\n\n # cas du tableau vide\n if ...:\n return L\n for j in range(1,n):\n e = L[j]\n i = j\n\n # A l'\u00e9tape j, le sous-tableau L[0,j-1] est tri\u00e9\n # et on ins\u00e8re L[j] dans ce sous-tableau en d\u00e9terminant\n # le plus petit i tel que 0 <= i <= j et L[i-1] > L[j].\n\n while i > 0 and L[i-1] > ...:\n i = ...\n\n # si i != j, on d\u00e9cale le sous tableau L[i,j-1] d\u2019un cran\n # vers la droite et on place L[j] en position i\n\n if i != j:\n for k in range(j,i,...):\n L[k] = L[...]\n L[i] = ...\n return L\n
Exemples :
>>> tri_insertion([2,5,-1,7,0,28])\n[-1, 0, 2, 5, 7, 28]\n>>> tri_insertion([10,9,8,7,6,5,4,3,2,1,0])\n[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n
def tri_insertion(L):\n n = len(L)\n\n # cas du tableau vide\n if L == []:\n return L\n\n for j in range(1,n):\n e = L[j]\n i = j\n\n # A l'\u00e9tape j, le sous-tableau L[0,j-1] est tri\u00e9\n # et on ins\u00e8re L[j] dans ce sous-tableau en d\u00e9terminant\n # le plus petit i tel que 0 <= i <= j et L[i-1] > L[j].\n\n while i > 0 and L[i-1] > e:\n i = i - 1\n\n # si i != j, on d\u00e9cale le sous tableau L[i,j-1] d\u2019un cran\n # vers la droite et on place L[j] en position i\n\n if i != j:\n for k in range(j,i,-1):\n L[k] = L[k-1]\n L[i] = e\n return L\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-061","title":"Exercice 06.1 \u25a1","text":"Exercice 06.1
\u00c9nonc\u00e9CorrectionOn s\u2019int\u00e9resse au probl\u00e8me du rendu de monnaie. On suppose qu\u2019on dispose d\u2019un nombre infini de billets de 5 euros, de pi\u00e8ces de 2 euros et de pi\u00e8ces de 1 euro. Le but est d\u2019\u00e9crire une fonction nomm\u00e9e rendu
dont le param\u00e8tre est un entier positif non nul somme_a_rendre
et qui retourne une liste de trois entiers n1
, n2
et n3
qui correspondent aux nombres de billets de 5 euros (n1
) de pi\u00e8ces de 2 euros (n2
) et de pi\u00e8ces de 1 euro (n3
) \u00e0 rendre afin que le total rendu soit \u00e9gal \u00e0 somme_a_rendre
.
On utilisera un algorithme glouton : on commencera par rendre le nombre maximal de billets de 5 euros, puis celui des pi\u00e8ces de 2 euros et enfin celui des pi\u00e8ces de 1 euros.
Exemples :
>>> rendu(13)\n[2,1,1]\n>>> rendu(64)\n[12,2,0]\n>>> rendu(89)\n[17,2,0]\n
def rendu(somme_a_rendre):\n pieces = [5, 2, 1]\n retour = [0, 0, 0]\n reste_a_rendre = somme_a_rendre\n for i in range(3):\n retour[i] = reste_a_rendre // pieces[i]\n reste_a_rendre = reste_a_rendre % pieces[i]\n return retour\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-062","title":"Exercice 06.2 \u25a1","text":"\u00e0 noter une erreur dans la version officielle, sur la m\u00e9thode enfile()
Exercice 06.2
\u00c9nonc\u00e9CorrectionOn veut \u00e9crire une classe pour g\u00e9rer une file \u00e0 l\u2019aide d\u2019une liste cha\u00een\u00e9e. On dispose d\u2019une classe Maillon
permettant la cr\u00e9ation d\u2019un maillon de la cha\u00eene, celui-ci \u00e9tant constitu\u00e9 d\u2019une valeur et d\u2019une r\u00e9f\u00e9rence au maillon suivant de la cha\u00eene :
class Maillon :\n def __init__(self,v) :\n self.valeur = v\n self.suivant = None\n
Compl\u00e9ter la classe File suivante
o\u00f9 l\u2019attribut dernier_file
contient le maillon correspondant \u00e0 l\u2019\u00e9l\u00e9ment arriv\u00e9 en dernier dans la file : class File :\n def __init__(self) :\n self.dernier_file = None\n\n def enfile(self,element) :\n nouveau_maillon = Maillon(...)\n nouveau_maillon.suivant = self.dernier_file\n self.dernier_file = ...\n\n def est_vide(self) :\n return self.dernier_file == None\n\n def affiche(self) :\n maillon = self.dernier_file\n while maillon != ... :\n print(maillon.valeur)\n maillon = ...\n\n def defile(self) :\n if not self.est_vide() :\n if self.dernier_file.suivant == None :\n resultat = self.dernier_file.valeur\n self.dernier_file = None\n return resultat\n maillon = ...\n while maillon.suivant.suivant != None :\n maillon = maillon.suivant\n resultat = ...\n maillon.suivant = None\n return resultat\n return None\n
On pourra tester le fonctionnement de la classe en utilisant les commandes suivantes dans la console Python : >>> F = File()\n>>> F.est_vide()\nTrue\n>>> F.enfile(2)\n>>> F.affiche()\n2\n>>> F.est_vide()\nFalse\n>>> F.enfile(5)\n>>> F.enfile(7)\n>>> F.affiche()\n7\n5\n2\n>>> F.defile()\n2\n>>> F.defile()\n5\n>>> F.affiche()\n7\n
class Maillon :\n def __init__(self,v) :\n self.valeur = v\n self.suivant = None\n\nclass File :\n def __init__(self) :\n self.dernier_file = None\n\n def enfile(self,element) :\n nouveau_maillon = Maillon(element)\n nouveau_maillon.suivant = self.dernier_file\n self.dernier_file = nouveau_maillon\n\n def est_vide(self) :\n return self.dernier_file == None\n\n def affiche(self) :\n maillon = self.dernier_file\n while maillon != None :\n print(maillon.valeur)\n maillon = maillon.suivant\n\n def defile(self) :\n if not self.est_vide() :\n if self.dernier_file.suivant == None :\n resultat = self.dernier_file.valeur\n self.dernier_file = None\n return resultat\n maillon = self.dernier_file\n while maillon.suivant.suivant != None :\n maillon = maillon.suivant\n resultat = maillon.suivant.valeur\n maillon.suivant = None\n return resultat\n return None\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-071","title":"Exercice 07.1 \ud83d\uddf9","text":"Exercice 07.1
\u00c9nonc\u00e9CorrectionOn s\u2019int\u00e9resse \u00e0 la suite d\u2019entiers d\u00e9finie par U1 = 1
, U2 = 1
et, pour tout entier naturel n
, par Un+2 = Un+1 + Un
.
Elle s\u2019appelle la suite de Fibonacci.
\u00c9crire la fonction fibonacci
qui prend un entier n > 0
et qui renvoie l\u2019\u00e9l\u00e9ment d\u2019indice n
de cette suite.
On utilisera une programmation dynamique (pas de r\u00e9cursivit\u00e9).
Exemple :
>>> fibonacci(1)\n1\n>>> fibonacci(2)\n1\n>>> fibonacci(25)\n75025\n>>> fibonacci(45)\n1134903170\n
On utilise un dictionnaire pour stocker au fur et \u00e0 mesure les valeurs.
def fibonnaci(n):\n d = {}\n d[1] = 1\n d[2] = 1\n for k in range(3, n+1):\n d[k] = d[k-1] + d[k-2]\n return d[n]\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-072","title":"Exercice 07.2 \u25a1","text":"Exercice 07.2
\u00c9nonc\u00e9CorrectionLes variables liste_eleves
et liste_notes
ayant \u00e9t\u00e9 pr\u00e9alablement d\u00e9finies et \u00e9tant de m\u00eame longueur, la fonction meilleures_notes
renvoie la note maximale qui a \u00e9t\u00e9 attribu\u00e9e, le nombre d\u2019\u00e9l\u00e8ves ayant obtenu cette note et la liste des noms de ces \u00e9l\u00e8ves.
Compl\u00e9ter le code Python de la fonction meilleures_notes
ci-dessous.
liste_eleves = ['a','b','c','d','e','f','g','h','i','j']\nliste_notes = [1, 40, 80, 60, 58, 80, 75, 80, 60, 24]\n\ndef meilleures_notes():\n note_maxi = 0\n nb_eleves_note_maxi = ...\n liste_maxi = ...\n\n for compteur in range(...):\n if liste_notes[compteur] == ...:\n nb_eleves_note_maxi = nb_eleves_note_maxi + 1\n liste_maxi.append(liste_eleves[...])\n if liste_notes[compteur] > note_maxi:\n note_maxi = liste_notes[compteur]\n nb_eleves_note_maxi = ...\n liste_maxi = [...]\n\n return (note_maxi,nb_eleves_note_maxi,liste_maxi)\n
Une fois compl\u00e9t\u00e9, le code ci-dessus donne
>>> meilleures_notes()\n(80, 3, ['c', 'f', 'h'])\n
liste_eleves = ['a','b','c','d','e','f','g','h','i','j']\nliste_notes = [1, 40, 80, 60, 58, 80, 75, 80, 60, 24]\n\ndef meilleures_notes():\n note_maxi = 0\n nb_eleves_note_maxi = 0\n liste_maxi = []\n\n for compteur in range(len(liste_eleves)):\n if liste_notes[compteur] == note_maxi:\n nb_eleves_note_maxi = nb_eleves_note_maxi + 1\n liste_maxi.append(liste_eleves[compteur])\n if liste_notes[compteur] > note_maxi:\n note_maxi = liste_notes[compteur]\n nb_eleves_note_maxi = 1\n liste_maxi = [liste_eleves[compteur]]\n\n return (note_maxi,nb_eleves_note_maxi,liste_maxi)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-081","title":"Exercice 08.1 \ud83d\uddf9","text":"Exercice 08.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction recherche
qui prend en param\u00e8tres caractere
, un caract\u00e8re, et mot
, une cha\u00eene de caract\u00e8res, et qui renvoie le nombre d\u2019occurrences de caractere
dans mot
, c\u2019est-\u00e0-dire le nombre de fois o\u00f9 caractere
appara\u00eet dans mot
.
Exemples :
>>> recherche('e', \"sciences\")\n2\n>>> recherche('i',\"mississippi\")\n4\n>>> recherche('a',\"mississippi\")\n0\n
def recherche(caractere, mot):\n somme = 0\n for lettre in mot:\n if lettre == caractere:\n somme += 1\n return somme\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-082","title":"Exercice 08.2 \u25a1","text":"Exercice 08.2
\u00c9nonc\u00e9CorrectionOn s\u2019int\u00e9resse \u00e0 un algorithme r\u00e9cursif qui permet de rendre la monnaie \u00e0 partir d\u2019une liste donn\u00e9e de valeurs de pi\u00e8ces et de billets - le syst\u00e8me mon\u00e9taire est donn\u00e9 sous forme d\u2019une liste pieces=[100, 50, 20, 10, 5, 2, 1]
- (on supposera qu\u2019il n\u2019y a pas de limitation quant \u00e0 leur nombre), on cherche \u00e0 donner la liste de pi\u00e8ces \u00e0 rendre pour une somme donn\u00e9e en argument. Compl\u00e9ter le code Python ci-dessous de la fonction rendu_glouton
qui impl\u00e9mente cet algorithme et renvoie la liste des pi\u00e8ces \u00e0 rendre.
pieces = [100,50,20,10,5,2,1]\n\ndef rendu_glouton(arendre, solution=[], i=0):\n if arendre == 0:\n return ...\n p = pieces[i]\n if p <= ... :\n solution.append(...)\n return rendu_glouton(arendre - p, solution,i)\n else :\n return rendu_glouton(arendre, solution, ...)\n
On devra obtenir : >>>rendu_glouton(68,[],0)\n[50, 10, 5, 2, 1]\n>>>rendu_glouton(291,[],0)\n[100, 100, 50, 20, 20, 1]\n
pieces = [100,50,20,10,5,2,1]\n\ndef rendu_glouton(arendre, solution=[], i=0):\n if arendre == 0:\n return solution\n p = pieces[i]\n if p <= arendre :\n solution.append(p)\n return rendu_glouton(arendre - p, solution,i)\n else :\n return rendu_glouton(arendre, solution, i+1)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-091","title":"Exercice 09.1 \u25a1","text":"Exercice 09.1
\u00c9nonc\u00e9CorrectionSoit le couple (note
,coefficient
):
note
est un nombre de type flottant (float
) compris entre 0 et 20 ;coefficient
est un nombre entier positif.Les r\u00e9sultats aux \u00e9valuations d'un \u00e9l\u00e8ve sont regroup\u00e9s dans une liste compos\u00e9e de couples (note
,coefficient
).
\u00c9crire une fonction moyenne qui renvoie la moyenne pond\u00e9r\u00e9e de cette liste donn\u00e9e en param\u00e8tre.
Par exemple, l\u2019expression moyenne([(15,2),(9,1),(12,3)])
devra renvoyer le r\u00e9sultat du calcul suivant :
\\(\\dfrac{2 \\times 15 + 1 \\times 9 + 3 \\times 12 }{2+1+3}=12,5\\)
def moyenne(tab):\n somme_notes = 0\n somme_coeffs = 0\n for devoir in tab:\n note = devoir[0]\n coeff = devoir[1]\n somme_notes += note * coeff\n somme_coeffs += coeff\n return somme_notes / somme_coeffs\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-092","title":"Exercice 09.2 \u25a1","text":"Exercice 09.2
\u00c9nonc\u00e9CorrectionOn cherche \u00e0 d\u00e9terminer les valeurs du triangle de Pascal. Dans ce tableau de forme triangulaire, chaque ligne commence et se termine par le nombre 1. Par ailleurs, la valeur qui occupe une case situ\u00e9e \u00e0 l\u2019int\u00e9rieur du tableau s\u2019obtient en ajoutant les valeurs des deux cases situ\u00e9es juste au-dessus, comme l\u2019indique la figure suivante :
Compl\u00e9ter la fonction pascal
ci-apr\u00e8s. Elle doit renvoyer une liste correspondant au triangle de Pascal de la ligne 1
\u00e0 la ligne n
o\u00f9 n
est un nombre entier sup\u00e9rieur ou \u00e9gal \u00e0 2
(le tableau sera contenu dans la variable C
). La variable Ck
doit, quant \u00e0 elle, contenir, \u00e0 l\u2019\u00e9tape num\u00e9ro k
, la k
-i\u00e8me ligne du tableau.
def pascal(n):\n C= [[1]]\n for k in range(1,...):\n Ck = [...]\n for i in range(1,k):\n Ck.append(C[...][i-1]+C[...][...] )\n Ck.append(...)\n C.append(Ck)\n return C\n
Pour n = 4
, voici ce qu'on devra obtenir :
>>> pascal(4)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]\n
Pour n = 5
, voici ce qu'on devra obtenir : >>> pascal(5)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1]]\n
def pascal(n):\n C = [[1]]\n for k in range(1,n+1):\n Ck = [1]\n for i in range(1,k):\n Ck.append(C[k-1][i-1]+C[k-1][i] )\n Ck.append(1)\n C.append(Ck)\n return C\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-101","title":"Exercice 10.1 \ud83d\uddf9","text":"Exercice 10.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction maxi
qui prend en param\u00e8tre une liste tab
de nombres entiers et renvoie un couple donnant le plus grand \u00e9l\u00e9ment de cette liste, ainsi que l\u2019indice de la premi\u00e8re apparition de ce maximum dans la liste.
Exemple :
>>> maxi([1,5,6,9,1,2,3,7,9,8])\n(9,3)\n
def maxi(tab):\n val_max = tab[0]\n pos_max = 0\n for i in range(len(tab)):\n if tab[i] > val_max:\n val_max = tab[i]\n pos_max = i\n return (val_max, pos_max)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-102","title":"Exercice 10.2 \ud83d\uddf9","text":"Exercice 10.2
\u00c9nonc\u00e9CorrectionCet exercice utilise des piles qui seront repr\u00e9sent\u00e9es en Python par des listes (type list
).
On rappelle que l\u2019expression T1 = list(T)
fait une copie de T
ind\u00e9pendante de T
, que l\u2019expression x = T.pop()
enl\u00e8ve le sommet de la pile T
et le place dans la variable x
et, enfin, que l\u2019expression T.append(v)
place la valeur v
au sommet de la pile T
.
Compl\u00e9ter le code Python de la fonction positif
ci-dessous qui prend une pile T
de nombres entiers en param\u00e8tre et qui renvoie la pile des entiers positifs dans le m\u00eame ordre, sans modifier la variable T
.
def positif(T):\n T2 = ...(T)\n T3 = ...\n while T2 != []:\n x = ...\n if ... >= 0:\n T3.append(...)\n T2 = []\n while T3 != ...:\n x = T3.pop()\n ...\n print('T = ',T)\n return T2\n
Exemple :
>>> positif([-1,0,5,-3,4,-6,10,9,-8 ])\nT = [-1, 0, 5, -3, 4, -6, 10, 9, -8]\n[0, 5, 4, 10, 9]\n
def positif(T):\n T2 = list(T)\n T3 = []\n while T2 != []:\n x = T2.pop()\n if x >= 0:\n T3.append(x)\n T2 = [] # <- NB : cette ligne est inutile\n while T3 != []:\n x = T3.pop()\n T2.append(x)\n print('T = ',T)\n return T2\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-111","title":"Exercice 11.1 \u25a1","text":"Exercice 11.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction conv_bin
qui prend en param\u00e8tre un entier positif n
et renvoie un couple (b,bit)
o\u00f9 :
b
est une liste d'entiers correspondant \u00e0 la repr\u00e9sentation binaire de n
;bit
correspond aux nombre de bits qui constituent b
.Exemple :
>>> conv_bin(9)\n([1,0,0,1],4)\n
Aide :
//
donne le quotient de la division euclidienne : 5//2
donne 2
;%
donne le reste de la division euclidienne :5%2
donne 1
;append
est une m\u00e9thode qui ajoute un \u00e9l\u00e9ment \u00e0 une liste existante : Soit T=[5,2,4]
, alors T.append(10)
ajoute 10
\u00e0 la liste T
. Ainsi, T
devient [5,2,4,10]
.reverse
est une m\u00e9thode qui renverse les \u00e9l\u00e9ments d'une liste. Soit T=[5,2,4,10]
. Apr\u00e8s T.reverse()
, la liste devient [10,4,2,5]
.On remarquera qu\u2019on r\u00e9cup\u00e8re la repr\u00e9sentation binaire d\u2019un entier n
en partant de la gauche en appliquant successivement les instructions :
b = n%2
n = n//2
r\u00e9p\u00e9t\u00e9es autant que n\u00e9cessaire.
def conv_bin(n):\n b = []\n bits = 0\n while n != 0:\n b.append(n % 2)\n bits += 1\n n = n // 2\n b.reverse()\n return (b, bits)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-112","title":"Exercice 11.2 \u25a1","text":"Exercice 11.2
\u00c9nonc\u00e9CorrectionLa fonction tri_bulles
prend en param\u00e8tre une liste T
d\u2019entiers non tri\u00e9s et renvoie la liste tri\u00e9e par ordre croissant. Compl\u00e9ter le code Python ci-dessous qui impl\u00e9mente la fonction tri_bulles
.
def tri_bulles(T):\n n = len(T)\n for i in range(...,...,-1):\n for j in range(i):\n if T[j] > T[...]:\n ... = T[j]\n T[j] = T[...]\n T[j+1] = temp\n return T\n
\u00c9crire une autre version de l\u2019algorithme avec for i in range(n-1):\n
en lieu et place de la troisi\u00e8me ligne du code pr\u00e9c\u00e9dent. def tri_bulles(T):\n n = len(T)\n for i in range(n-1,0,-1):\n for j in range(i):\n if T[j] > T[j+1]:\n temp = T[j]\n T[j] = T[j+1]\n T[j+1] = temp\n return T\n\n#version 2\n\ndef tri_bulles(T):\n n = len(T)\n for i in range(n-1):\n for j in range(n-1,i,-1):\n if T[j] < T[j-1]:\n temp = T[j]\n T[j] = T[j-1]\n T[j-1] = temp\n return T\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-121","title":"Exercice 12.1 \u25a1","text":"Ce sujet est le m\u00eame que le 10.1... \u00af\\_(\u30c4)_/\u00af
Exercice 12.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction maxi
qui prend en param\u00e8tre une liste tab
de nombres entiers et renvoie un couple donnant le plus grand \u00e9l\u00e9ment de cette liste, ainsi que l\u2019indice de la premi\u00e8re apparition de ce maximum dans la liste.
Exemple :
>>> maxi([1,5,6,9,1,2,3,7,9,8])\n(9,3)\n
def maxi(tab):\n val_max = tab[0]\n pos_max = 0\n for i in range(len(tab)):\n if tab[i] > val_max:\n val_max = tab[i]\n pos_max = i\n return (val_max, pos_max)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-122","title":"Exercice 12.2 \ud83d\uddf9","text":"Exercice 12.2
\u00c9nonc\u00e9CorrectionLa fonction recherche
prend en param\u00e8tres deux chaines de caract\u00e8res gene
et seq_adn
et renvoie True
si on retrouve gene
dans seq_adn
et False
sinon. Compl\u00e9ter le code Python ci-dessous pour qu\u2019il impl\u00e9mente la fonction recherche
.
def recherche(gene, seq_adn):\n n = len(seq_adn)\n g = len(gene)\n i = ...\n trouve = False\n while i < ... and trouve == ... :\n j = 0\n while j < g and gene[j] == seq_adn[i+j]:\n ...\n if j == g:\n trouve = True\n ...\n return trouve\n
Exemples :
>>> recherche(\"AATC\", \"GTACAAATCTTGCC\")\nTrue\n>>> recherche(\"AGTC\", \"GTACAAATCTTGCC\")\nFalse\n
def recherche(gene, seq_adn):\n n = len(seq_adn)\n g = len(gene)\n i = 0\n trouve = False\n while i < n-g and trouve == False :\n j = 0\n while j < g and gene[j] == seq_adn[i+j]:\n j += 1\n if j == g:\n trouve = True\n i += 1\n return trouve\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-131","title":"Exercice 13.1 \u25a1","text":"Exercice 13.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction tri_selection
qui prend en param\u00e8tre une liste tab
de nombres entiers et qui renvoie le tableau tri\u00e9 par ordre croissant.
On utilisera l\u2019algorithme suivant :
Exemple :
>>> tri_selection([1,52,6,-9,12])\n[-9, 1, 6, 12, 52]\n
def tri_selection(tab):\n for i in range(len(tab)-1):\n indice_min = i\n for j in range(i+1, len(tab)):\n if tab[j] < tab[indice_min]:\n indice_min = j\n tab[i], tab[indice_min] = tab[indice_min], tab[i]\n return tab\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-132","title":"Exercice 13.2 \u25a1","text":"Exercice 13.2
\u00c9nonc\u00e9CorrectionLe jeu du \u00ab plus ou moins \u00bb consiste \u00e0 deviner un nombre entier choisi entre 1 et 99. Un \u00e9l\u00e8ve de NSI d\u00e9cide de le coder en langage Python de la mani\u00e8re suivante :
La fonction randint
est utilis\u00e9e. Si a et b sont des entiers, randint(a,b)
renvoie un nombre entier compris entre a
et b
. Compl\u00e9ter le code ci-dessous et le tester :
from random import randint\n\ndef plus_ou_moins():\n nb_mystere = randint(1,...)\n nb_test = int(input(\"Proposez un nombre entre 1 et 99 : \"))\n compteur = ...\n\n while nb_mystere != ... and compteur < ... :\n compteur = compteur + ...\n if nb_mystere ... nb_test:\n nb_test = int(input(\"Trop petit ! Testez encore : \"))\n else:\n nb_test = int(input(\"Trop grand ! Testez encore : \"))\n\n if nb_mystere == nb_test:\n print (\"Bravo ! Le nombre \u00e9tait \",...)\n print(\"Nombre d'essais: \",...)\n else:\n print (\"Perdu ! Le nombre \u00e9tait \",...)\n
from random import randint\n\ndef plus_ou_moins():\n nb_mystere = randint(1,100)\n nb_test = int(input('Proposez un nombre entre 1 et 99 : '))\n compteur = 0\n\n while nb_mystere != nb_test and compteur < 10 :\n compteur = compteur + 1\n if nb_mystere > nb_test:\n nb_test = int(input('Trop petit ! Testez encore : '))\n else:\n nb_test = int(input('Trop grand ! Testez encore : '))\n\n if nb_mystere == nb_test:\n print ('Bravo ! Le nombre \u00e9tait ', nb_mystere)\n print('Nombre d essais: ', compteur)\n else:\n print ('Perdu ! Le nombre \u00e9tait ', nb_mystere)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-141","title":"Exercice 14.1 \u25a1","text":"Exercice 14.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction recherche
qui prend en param\u00e8tres elt
un nombre et tab
un tableau de nombres, et qui renvoie le tableau des indices de elt
dans tab
si elt
est dans tab
et le tableau vide []
sinon.
Exemples :
>>> recherche(3, [3, 2, 1, 3, 2, 1])\n[0, 3]\n>>> recherche(4, [1, 2, 3])\n[]\n
def recherche(elt, tab):\n tab_indices = []\n for i in range(len(tab)):\n if tab[i] == elt:\n tab_indices.append(i)\n return tab_indices \n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-142","title":"Exercice 14.2 \u25a1","text":"Exercice 14.2
\u00c9nonc\u00e9CorrectionUn professeur de NSI d\u00e9cide de g\u00e9rer les r\u00e9sultats de sa classe sous la forme d\u2019un dictionnaire :
Avec :
resultats = {'Dupont':{ 'DS1' : [15.5, 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [13, 4],\n 'PROJET1' : [16, 3],\n 'DS3' : [14, 4]},\n 'Durand':{ 'DS1' : [6 , 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [8, 4],\n 'PROJET1' : [9, 3],\n 'IE1' : [7, 2],\n 'DS3' : [8, 4],\n 'DS4' :[15, 4]}}\n
L\u2019\u00e9l\u00e8ve dont le nom est Durand a ainsi obtenu au DS2 la note de 8 avec un coefficient 4. Le professeur cr\u00e9e une fonction moyenne
qui prend en param\u00e8tre le nom d\u2019un de ces \u00e9l\u00e8ves et lui renvoie sa moyenne arrondie au dixi\u00e8me.
Compl\u00e9ter le code du professeur ci-dessous :
def moyenne(nom):\n if nom in ...:\n notes = resultats[nom]\n total_points = ...\n total_coefficients = ...\n for ... in notes.values():\n note , coefficient = valeurs\n total_points = total_points + ... * coefficient\n total_coefficients = ... + coefficient\n return round( ... / total_coefficients , 1 )\n else:\n return -1\n
resultats = {'Dupont':{ 'DS1' : [15.5, 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [13, 4],\n 'PROJET1' : [16, 3],\n 'DS3' : [14, 4]},\n 'Durand':{ 'DS1' : [6 , 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [8, 4],\n 'PROJET1' : [9, 3],\n 'IE1' : [7, 2],\n 'DS3' : [8, 4],\n 'DS4' :[15, 4]}}\n\ndef moyenne(nom):\n if nom in resultats:\n notes = resultats[nom]\n total_points = 0\n total_coefficients = 0\n for valeurs in notes.values():\n note , coefficient = valeurs\n total_points = total_points + note * coefficient\n total_coefficients = total_coefficients + coefficient\n return round( total_points / total_coefficients , 1 )\n else:\n return -1\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-151","title":"Exercice 15.1 \u25a1","text":"Exercice 15.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction rechercheMinMax
qui prend en param\u00e8tre un tableau de nombres non tri\u00e9s tab
, et qui renvoie la plus petite et la plus grande valeur du tableau sous la forme d\u2019un dictionnaire \u00e0 deux cl\u00e9s \u2018min\u2019 et \u2018max\u2019. Les tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.
Exemples :
>>> tableau = [0, 1, 4, 2, -2, 9, 3, 1, 7, 1]\n>>> resultat = rechercheMinMax(tableau)\n>>> resultat\n{'min': -2, 'max': 9}\n>>> tableau = []\n>>> resultat = rechercheMinMax(tableau)\n>>> resultat\n{'min': None, 'max': None}\n
def rechercheMinMax(tab):\n if tab == []:\n return {'min': None, 'max': None}\n d = {}\n d['min'] = None\n d['max'] = None\n for val in tab:\n if val < d['min']:\n d['min'] = val\n if val > d['max']:\n d['max'] = val\n return d\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-152","title":"Exercice 15.2 \u25a1","text":"Exercice 15.2
\u00c9nonc\u00e9CorrectionOn dispose d\u2019un programme permettant de cr\u00e9er un objet de type PaquetDeCarte
, selon les \u00e9l\u00e9ments indiqu\u00e9s dans le code ci-dessous. Compl\u00e9ter ce code aux endroits indiqu\u00e9s par #A compl\u00e9ter
, puis ajouter des assertions dans l\u2019initialiseur de Carte
, ainsi que dans la m\u00e9thode getCarteAt()
.
class Carte:\n\"\"\"Initialise Couleur (entre 1 \u00e0 4), et Valeur (entre 1 \u00e0 13)\"\"\"\n def __init__(self, c, v):\n self.Couleur = c\n self.Valeur = v\n\n\"\"\"Renvoie le nom de la Carte As, 2, ... 10, Valet, Dame, Roi\"\"\"\n def getNom(self):\n if (self.Valeur > 1 and self.Valeur < 11):\n return str(self.Valeur)\n elif self.Valeur == 11:\n return \"Valet\"\n elif self.Valeur == 12:\n return \"Dame\"\n elif self.Valeur == 13:\n return \"Roi\"\n else:\n return \"As\"\n\n\"\"\"Renvoie la couleur de la Carte (parmi pique, coeur, carreau, trefle\"\"\"\n def getCouleur(self):\n return ['pique', 'coeur', 'carreau', 'trefle'][self.Couleur - 1]\n\nclass PaquetDeCarte:\n def __init__(self):\n self.contenu = []\n\n\"\"\"Remplit le paquet de cartes\"\"\"\n def remplir(self):\n #A compl\u00e9ter\n\n\"\"\"Renvoie la Carte qui se trouve \u00e0 la position donn\u00e9e\"\"\"\n def getCarteAt(self, pos):\n #A compl\u00e9ter\n
Exemple : >>> unPaquet = PaquetDeCarte()\n>>> unPaquet.remplir()\n>>> uneCarte = unPaquet.getCarteAt(20)\n>>> print(uneCarte.getNom() + \" de \" + uneCarte.getCouleur())\n
Attention, le code propos\u00e9 ne respecte pas les standards de notation :
class Carte:\n\"\"\"Initialise Couleur (entre 1 \u00e0 4), et Valeur (entre 1 \u00e0 13)\"\"\"\n def __init__(self, c, v):\n assert c in range(1,5)\n assert v in range(1,14)\n self.Couleur = c\n self.Valeur = v\n\n\"\"\"Renvoie le nom de la Carte As, 2, ... 10, Valet, Dame, Roi\"\"\"\n def getNom(self):\n if (self.Valeur > 1 and self.Valeur < 11):\n return str( self.Valeur)\n elif self.Valeur == 11:\n return \"Valet\"\n elif self.Valeur == 12:\n return \"Dame\"\n elif self.Valeur == 13:\n return \"Roi\"\n else:\n return \"As\"\n\n\"\"\"Renvoie la couleur de la Carte (parmi pique, coeur, carreau, trefle\"\"\"\n def getCouleur(self):\n return ['pique', 'coeur', 'carreau', 'trefle'][self.Couleur]\n\nclass PaquetDeCarte:\n def __init__(self):\n self.contenu = []\n\n\"\"\"Remplit le paquet de cartes\"\"\"\n def remplir(self):\n for nb_coul in range(1,5):\n for val in range(1,14):\n self.contenu.append(Carte(nb_coul, val))\n\n\"\"\"Renvoie la Carte qui se trouve \u00e0 la position donn\u00e9e\"\"\"\n def getCarteAt(self, pos):\n assert pos in range(56)\n return self.contenu[pos]\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-161","title":"Exercice 16.1 \u25a1","text":"Exercice 16.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction moyenne
qui prend en param\u00e8tre un tableau non vide de nombres flottants et qui renvoie la moyenne des valeurs du tableau. Les tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.
Exemples :
>>> moyenne([1.0])\n1.0\n>>> moyenne([1.0, 2.0, 4.0])\n2.3333333333333335\n
def moyenne(tab):\n somme = 0\n for val in tab:\n somme += val\n return somme / len(tab)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-162","title":"Exercice 16.2 \u25a1","text":"Exercice 16.2
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la fonction dec_to_bin
ci-dessous qui prend en param\u00e8tre un entier positif a
en \u00e9criture d\u00e9cimale et qui renvoie son \u00e9criture binaire sous la forme d'une chaine de caract\u00e8res.
def dec_to_bin(a):\n bin_a = ...\n a = a//2\n while a ... :\n bin_a = ... + bin_a\n a = ...\n return bin_a\n
Compl\u00e9ter la fonction dec_to_bin
. Exemples :
>>> dec_to_bin(83)\n'1010011'\n>>> dec_to_bin(127)\n'1111111'\n
def dec_to_bin(a):\n bin_a = ''\n a = a // 2\n while a != 0 :\n bin_a = str(a%2) + bin_a\n a = a // 2\n return bin_a\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-171","title":"Exercice 17.1 \ud83d\uddf9","text":"Exercice 17.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction indice_du_min
qui prend en param\u00e8tre un tableau de nombres non tri\u00e9 tab
, et qui renvoie l'indice de la premi\u00e8re occurrence du minimum de ce tableau. Les tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.
Exemples :
>>> indice_du_min([5])\n0\n>>> indice_du_min([2, 4, 1])\n2\n>>> indice_du_min([5, 3, 2, 2, 4])\n2\n
def indice_du_min(tab):\n indice_min = 0\n for i in range(len(tab)):\n if tab[i] < tab[indice_min]:\n indice_min = i\n return indice_min\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-172","title":"Exercice 17.2 \ud83d\uddf9","text":"Exercice 17.2
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la fonction separe
ci-dessous qui prend en argument un tableau tab
dont les \u00e9l\u00e9ments sont des 0
et des 1
et qui s\u00e9pare les 0
des 1
en pla\u00e7ant les 0
en d\u00e9but de tableau et les 1
\u00e0 la suite.
def separe(tab):\n i = 0\n j = ...\n while i < j :\n if tab[i] == 0 :\n i = ...\n else :\n tab[i], tab[j] = ...\n j = ...\n return tab\n
Compl\u00e9ter la fonction separe
ci-dessus.
Exemples :
>>> separe([1, 0, 1, 0, 1, 0, 1, 0])\n[0, 0, 0, 0, 1, 1, 1, 1]\n>>> separe([1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0])\n[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\n
def separe(tab):\n i = 0\n j = len(tab) - 1\n while i < j :\n if tab[i] == 0 :\n i = i + 1\n else :\n tab[i], tab[j] = tab[j], tab[i]\n j = j - 1\n return tab\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-181","title":"Exercice 18.1 \u25a1","text":"Exercice 18.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction recherche
qui prend en param\u00e8tres elt
un nombre entier et tab
un tableau de nombres entiers, et qui renvoie l\u2019indice de la premi\u00e8re occurrence de elt
dans tab
si elt
est dans tab
et -1
sinon.
Exemples :
>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(50, [1, 50, 1])\n1\n>>> recherche(15, [8, 9, 10, 15])\n3\n
def recherche(elt, tab):\n for i in range(len(tab)):\n if tab[i] == elt:\n return i \n return -1 \n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-182","title":"Exercice 18.2 \u25a1","text":"Exercice 18.2
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la fonction insere
ci-dessous qui prend en argument un entier a
et un tableau tab
d'entiers tri\u00e9s par ordre croissant. Cette fonction ins\u00e8re la valeur a
dans le tableau et renvoie le nouveau tableau. Les tableaux seront repr\u00e9sent\u00e9s sous la forme de listes python.
Sujet l\u00e9g\u00e8rement modifi\u00e9
def insere(a, tab):\n l = list(tab) #l contient les m\u00eames \u00e9l\u00e9ments que tab\n l.append(a)\n i = ...\n while a < ... and i >= ...:\n l[i+1] = ...\n l[i] = a\n i = ...\n return l\n
Compl\u00e9ter la fonction insere
ci-dessus.
Exemples :
>>> insere(3,[1,2,4,5])\n[1, 2, 3, 4, 5]\n>>> insere(10,[1,2,7,12,14,25])\n[1, 2, 7, 10, 12, 14, 25]\n>>> insere(1,[2,3,4])\n[1, 2, 3, 4]\n
def insere(a, tab):\n l = list(tab) #l contient les m\u00eames \u00e9l\u00e9ments que tab\n l.append(a)\n i = len(l) - 2\n while a < l[i] and i >= 0:\n l[i+1] = l[i]\n l[i] = a\n i = i - 1\n return l\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-191","title":"Exercice 19.1 \u25a1","text":"Exercice 19.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction recherche
qui prend en param\u00e8tres un tableau tab
de nombres entiers tri\u00e9s par ordre croissant et un nombre entier n
, et qui effectue une recherche dichotomique du nombre entier n
dans le tableau non vide tab
. Cette fonction doit renvoyer un indice correspondant au nombre cherch\u00e9 s\u2019il est dans le tableau, -1
sinon.
Exemples :
>>> recherche([2, 3, 4, 5, 6], 5)\n3\n>>> recherche([2, 3, 4, 6, 7], 5)\n-1\n
def recherche(tab, n):\n ind_debut = 0\n ind_fin = len(tab) - 1\n while ind_debut <= ind_fin:\n ind_milieu = (ind_debut + ind_fin) // 2\n if tab[ind_milieu] == n:\n return ind_milieu\n elif tab[ind_milieu] < n:\n ind_debut = ind_milieu + 1\n else:\n ind_fin = ind_milieu - 1\n return -1\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-192","title":"Exercice 19.2 \u25a1","text":"Exercice 19.2
\u00c9nonc\u00e9CorrectionLe codage de C\u00e9sar transforme un message en changeant chaque lettre en la d\u00e9calant dans l\u2019alphabet. Par exemple, avec un d\u00e9calage de 3, le A se transforme en D, le B en E, ..., le X en A, le Y en B et le Z en C. Les autres caract\u00e8res (\u2018!\u2019,\u2019 ?\u2019\u2026) ne sont pas cod\u00e9s.
La fonction position_alphabet
ci-dessous prend en param\u00e8tre un caract\u00e8re lettre
et renvoie la position de lettre
dans la cha\u00eene de caract\u00e8res ALPHABET
s\u2019il s\u2019y trouve et -1
sinon. La fonction cesar
prend en param\u00e8tre une cha\u00eene de caract\u00e8res message
et un nombre entier decalage
et renvoie le nouveau message cod\u00e9 avec le codage de C\u00e9sar utilisant le d\u00e9calage decalage
.
ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\ndef position_alphabet(lettre):\n return ALPHABET.find(lettre)\n\ndef cesar(message, decalage):\n resultat = ''\n for ... in message:\n if lettre in ALPHABET:\n indice = ( ... ) % 26\n resultat = resultat + ALPHABET[indice]\n else:\n resultat = ...\n return resultat\n
Compl\u00e9ter la fonction cesar
.
Exemples :
>>> cesar('BONJOUR A TOUS. VIVE LA MATIERE NSI !',4)\n'FSRNSYV E XSYW. ZMZI PE QEXMIVI RWM !'\n>>> cesar('GTSOTZW F YTZX. ANAJ QF RFYNJWJ SXN !',-5)\n'BONJOUR A TOUS. VIVE LA MATIERE NSI !'\n
ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\ndef position_alphabet(lettre):\n return ALPHABET.find(lettre)\n\ndef cesar(message, decalage):\n resultat = ''\n for lettre in message:\n if lettre in ALPHABET:\n indice = (position_alphabet(lettre) + decalage) % 26\n resultat = resultat + ALPHABET[indice]\n else:\n resultat = resultat + lettre\n return resultat\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-201","title":"Exercice 20.1 \ud83d\uddf9","text":"Exercice 20.1
\u00c9nonc\u00e9CorrectionOn a relev\u00e9 les valeurs moyennes annuelles des temp\u00e9ratures \u00e0 Paris pour la p\u00e9riode allant de 2013 \u00e0 2019. Les r\u00e9sultats ont \u00e9t\u00e9 r\u00e9cup\u00e9r\u00e9s sous la forme de deux listes : l\u2019une pour les temp\u00e9ratures, l\u2019autre pour les ann\u00e9es :
t_moy = [14.9, 13.3, 13.1, 12.5, 13.0, 13.6, 13.7]\nannees = [2013, 2014, 2015, 2016, 2017, 2018, 2019]\n
\u00c9crire la fonction mini
qui prend en param\u00e8tres le tableau releve
des relev\u00e9s et le tableau date
des dates et qui renvoie la plus petite valeur relev\u00e9e au cours de la p\u00e9riode et l\u2019ann\u00e9e correspondante.
Exemple :
>>> mini(t_moy, annees)\n(12.5, 2016)\n
t_moy = [14.9, 13.3, 13.1, 12.5, 13.0, 13.6, 13.7]\nannees = [2013, 2014, 2015, 2016, 2017, 2018, 2019]\n\ndef mini(releve, date):\n temp_mini = releve[0]\n date_mini = date[0]\n for i in range(len(releve)):\n if releve[i] < temp_mini:\n temp_mini = releve[i]\n date_mini = date[i]\n return temp_mini, date_mini\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-202","title":"Exercice 20.2 \ud83d\uddf9","text":"Exercice 20.2
\u00c9nonc\u00e9CorrectionUn mot palindrome peut se lire de la m\u00eame fa\u00e7on de gauche \u00e0 droite ou de droite \u00e0 gauche : bob, radar, et non sont des mots palindromes.
De m\u00eame certains nombres sont eux aussi des palindromes : 33, 121, 345543.
L\u2019objectif de cet exercice est d\u2019obtenir un programme Python permettant de tester si un nombre est un nombre palindrome.
Pour remplir cette t\u00e2che, on vous demande de compl\u00e9ter le code des trois fonctions ci- dessous sachant que la fonction est_nbre_palindrome
s\u2019appuiera sur la fonction est_palindrome
qui elle-m\u00eame s\u2019appuiera sur la fonction inverse_chaine
.
La fonction inverse_chaine
inverse l'ordre des caract\u00e8res d'une cha\u00eene de caract\u00e8res chaine
et renvoie la cha\u00eene invers\u00e9e.
La fonction est_palindrome
teste si une chaine de caract\u00e8res chaine
est un palindrome. Elle renvoie True
si c\u2019est le cas et False
sinon. Cette fonction s\u2019appuie sur la fonction pr\u00e9c\u00e9dente.
La fonction est_nbre_palindrome
teste si un nombre nbre
est un palindrome. Elle renvoie True
si c\u2019est le cas et False
sinon. Cette fonction s\u2019appuie sur la fonction pr\u00e9c\u00e9dente.
Compl\u00e9ter le code des trois fonctions ci-dessous.
def inverse_chaine(chaine):\n result = ...\n for caractere in chaine:\n result = ...\n return result\n\ndef est_palindrome(chaine):\n inverse = inverse_chaine(chaine)\n return ...\n\ndef est_nbre_palindrome(nbre):\n chaine = ...\n return est_palindrome(chaine)\n
Exemples : >>> inverse_chaine('bac')\n'cab'\n>>> est_palindrome('NSI')\nFalse\n>>> est_palindrome('ISN-NSI')\nTrue\n>>> est_nbre_palindrome(214312)\nFalse\n>>> est_nbre_palindrome(213312)\nTrue\n
def inverse_chaine(chaine):\n result = ''\n for caractere in chaine:\n result = caractere + result\n return result\n\ndef est_palindrome(chaine):\n inverse = inverse_chaine(chaine)\n return chaine == inverse\n\ndef est_nbre_palindrome(nbre):\n chaine = str(nbre)\n return est_palindrome(chaine)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-211","title":"Exercice 21.1 \u25a1","text":"Exercice 21.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction python appel\u00e9e nb_repetitions
qui prend en param\u00e8tres un \u00e9l\u00e9ment elt
et une liste tab
et renvoie le nombre de fois o\u00f9 l\u2019\u00e9l\u00e9ment appara\u00eet dans la liste.
Exemples :
>>> nb_repetitions(5,[2,5,3,5,6,9,5])\n3\n>>> nb_repetitions('A',[ 'B', 'A', 'B', 'A', 'R'])\n2\n>>> nb_repetitions(12,[1, '! ',7,21,36,44])\n0\n
def nb_repetitions(elt, tab):\n nb = 0\n for element in tab:\n if element == elt:\n nb += 1\n return nb\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-212","title":"Exercice 21.2 \u25a1","text":"Exercice 21.2
\u00c9nonc\u00e9CorrectionPour rappel, la conversion d\u2019un nombre entier positif en binaire peut s\u2019effectuer \u00e0 l\u2019aide des divisions successives comme illustr\u00e9 ici :
Voici une fonction Python bas\u00e9e sur la m\u00e9thode des divisions successives permettant de convertir un nombre entier positif en binaire :
def binaire(a):\n bin_a = str(...)\n a = a // 2\n while a ... :\n bin_a = ...(a%2) + ...\n a = ...\n return bin_a\n
Compl\u00e9ter la fonction binaire
. Exemples :
>>> binaire(0)\n'0'\n>>> binaire(77)\n'1001101'\n
def binaire(a):\n bin_a = str(a%2)\n a = a // 2\n while a != 0 :\n bin_a = str(a%2) + bin_a\n a = a // 2\n return bin_a\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-221","title":"Exercice 22.1 \u25a1","text":"Exercice 22.1
\u00c9nonc\u00e9Correction\u00c9crire en langage Python une fonction recherche
prenant comme param\u00e8tres une variable a
de type num\u00e9rique (float
ou int
) et un tableau t
(type list
) et qui renvoie le nombre d'occurrences de a
dans t
.
Exemples :
>>> recherche(5,[])\n0\n>>> recherche(5,[-2, 3, 4, 8])\n0\n>>> recherche(5,[-2, 3, 1, 5, 3, 7, 4])\n1\n>>> recherche(5,[-2, 5, 3, 5, 4, 5])\n3\n
def recherche(a, t):\n nb = 0\n for element in t:\n if element == a:\n nb += 1\n return nb\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-222","title":"Exercice 22.2 \u25a1","text":"Exercice 22.2
\u00c9nonc\u00e9CorrectionLa fonction rendu_monnaie_centimes
prend en param\u00e8tres deux nombres entiers positifs s_due
ets_versee
et elle permet de proc\u00e9der au rendu de monnaie de la diff\u00e9rence s_versee \u2013 s_due
pour des achats effectu\u00e9s avec le syst\u00e8me de pi\u00e8ces de la zone Euro. On utilise pour cela un algorithme qui commence par rendre le maximum de pi\u00e8ces de plus grandes valeurs et ainsi de suite. La fonction renvoie la liste des pi\u00e8ces qui composent le rendu.
Toutes les sommes sont exprim\u00e9es en centimes d\u2019euros. Les valeurs possibles pour les pi\u00e8ces sont donc [1, 2, 5, 10, 20, 50, 100, 200]
.
Ainsi, l\u2019instruction rendu_monnaie_centimes(452, 500)
renverra [20, 20, 5, 2, 1]
.
En effet, la somme \u00e0 rendre est de 48
centimes soit 20 + 20 + 5 + 2 + 1
. Le code de la fonction est donn\u00e9 ci-dessous :
def rendu_monnaie_centimes(s_due, s_versee):\n pieces = [1, 2, 5, 10, 20, 50, 100, 200]\n rendu = ...\n a_rendre = ...\n i = len(pieces) - 1\n while a_rendre > ... :\n if pieces[i] <= a_rendre :\n rendu.append(...)\n a_rendre = ...\n else :\n i = ...\n return rendu\n
Compl\u00e9ter ce code pour qu'il donne :
>>> rendu_monnaie_centimes(700,700)\n[]\n>>> rendu_monnaie_centimes(112,500)\n[200, 100, 50, 20, 10, 5, 2, 1]\n
def rendu_monnaie_centimes(s_due, s_versee):\n pieces = [1, 2, 5, 10, 20, 50, 100, 200]\n rendu = []\n a_rendre = s_versee - s_due\n i = len(pieces) - 1\n while a_rendre > 0 :\n if pieces[i] <= a_rendre :\n rendu.append(pieces[i])\n a_rendre = a_rendre - pieces[i]\n else :\n i = i - 1\n return rendu\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-231","title":"Exercice 23.1 \u25a1","text":"Exercice 23.1
\u00c9nonc\u00e9CorrectionL\u2019occurrence d\u2019un caract\u00e8re dans un phrase est le nombre de fois o\u00f9 ce caract\u00e8re est pr\u00e9sent.
Exemples :
On cherche les occurrences des caract\u00e8res dans une phrase. On souhaite stocker ces occurrences dans un dictionnaire dont les clefs seraient les caract\u00e8res de la phrase et les valeurs l\u2019occurrence de ces caract\u00e8res.
Par exemple : avec la phrase 'Hello world !' le dictionnaire est le suivant :
{'H': 1,'e': 1,'l': 3,'o': 2,' ': 2,'w': 1,'r': 1,'d': 1,'!': 1}
\u00c9crire une fonction occurence_lettres
prenant comme param\u00e8tre une variable phrase
de type str
. Cette fonction doit renvoyer un dictionnaire de type constitu\u00e9 des occurrences des caract\u00e8res pr\u00e9sents dans la phrase.
def occurence_lettres(phrase):\n occ = {}\n for caractere in phrase:\n if caractere in occ:\n occ[caractere] += 1\n else:\n occ[caractere] = 1\n return occ\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-232","title":"Exercice 23.2 \u25a1","text":"Exercice 23.2
\u00c9nonc\u00e9CorrectionLa fonction fusion
prend deux listes L1
, L2
d\u2019entiers tri\u00e9es par ordre croissant et les fusionne en une liste tri\u00e9e L12
qu\u2019elle renvoie.
Le code Python de la fonction est
def fusion(L1,L2):\n n1 = len(L1)\n n2 = len(L2)\n L12 = [0]*(n1+n2)\n i1 = 0\n i2 = 0\n i = 0\n while i1 < n1 and ... :\n if L1[i1] < L2[i2]:\n L12[i] = ...\n i1 = ...\n else:\n L12[i] = L2[i2]\n i2 = ...\n i += 1\n while i1 < n1:\n L12[i] = ...\n i1 = i1 + 1\n i = ...\n while i2 < n2:\n L12[i] = ...\n i2 = i2 + 1\n i = ...\n return L12\n
Compl\u00e9ter le code.
Exemple :
>>> fusion([1,6,10],[0,7,8,9])\n[0, 1, 6, 7, 8, 9, 10]\n
def fusion(L1,L2):\n n1 = len(L1)\n n2 = len(L2)\n L12 = [0]*(n1+n2)\n i1 = 0\n i2 = 0\n i = 0\n while i1 < n1 and i2 < n2 :\n if L1[i1] < L2[i2]:\n L12[i] = L1[i1]\n i1 = i1 + 1\n else:\n L12[i] = L2[i2]\n i2 = i2 + 1\n i += 1\n while i1 < n1:\n L12[i] = L1[i1]\n i1 = i1 + 1\n i = i + 1\n while i2 < n2:\n L12[i] = L2[i2]\n i2 = i2 + 1\n i = i + 1\n return L12\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-241","title":"Exercice 24.1 \u25a1","text":"identique au 18.1
Exercice 24.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction recherche
qui prend en param\u00e8tres elt
un nombre entier et tab
un tableau de nombres entiers, et qui renvoie l\u2019indice de la premi\u00e8re occurrence de elt
dans tab
si elt
est dans tab
et -1
sinon.
Exemples :
>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(50, [1, 50, 1])\n1\n>>> recherche(15, [8, 9, 10, 15])\n3\n
def recherche(tab, n):\n ind_debut = 0\n ind_fin = len(tab) - 1\n while ind_debut <= ind_fin:\n ind_milieu = (ind_debut + ind_fin) // 2\n if tab[ind_milieu] == n:\n return ind_milieu\n elif tab[ind_milieu] < n:\n ind_debut = ind_milieu + 1\n else:\n ind_fin = ind_milieu - 1\n return -1\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-242","title":"Exercice 24.2 \u25a1","text":"Exercice 24.2
\u00c9nonc\u00e9CorrectionOn d\u00e9finit une classe g\u00e9rant une adresse IPv4. On rappelle qu\u2019une adresse IPv4 est une adresse de longueur 4 octets, not\u00e9e en d\u00e9cimale \u00e0 point, en s\u00e9parant chacun des octets par un point. On consid\u00e8re un r\u00e9seau priv\u00e9 avec une plage d\u2019adresses IP de 192.168.0.0
\u00e0 192.168.0.255
.
On consid\u00e8re que les adresses IP saisies sont valides.
Les adresses IP 192.168.0.0
et 192.168.0.255
sont des adresses r\u00e9serv\u00e9es.
Le code ci-dessous impl\u00e9mente la classe AdresseIP
.
class AdresseIP:\n def __init__(self, adresse):\n self.adresse = ...\n\n def liste_octet(self):\n\"\"\"renvoie une liste de nombres entiers,\n la liste des octets de l'adresse IP\"\"\"\n return [int(i) for i in self.adresse.split(\".\")]\n\n def est_reservee(self):\n\"\"\"renvoie True si l'adresse IP est une adresse\n r\u00e9serv\u00e9e, False sinon\"\"\"\n return ... or ...\n\n def adresse_suivante(self):\n\"\"\"renvoie un objet de AdresseIP avec l'adresse\n IP qui suit l\u2019adresse self\n si elle existe et False sinon\"\"\"\n if ... < 254:\n octet_nouveau = ... + ...\n return AdresseIP('192.168.0.' + ...)\n else:\n return False\n
Compl\u00e9ter le code ci-dessus et instancier trois objets : adresse1
, adresse2
, adresse3
avec respectivement les arguments suivants : '192.168.0.1'
, '192.168.0.2'
, '192.168.0.0'
V\u00e9rifier que :
>>> adresse1.est_reservee()\nFalse\n>>> adresse3.est_reservee()\nTrue\n>>> adresse2.adresse_suivante().adresse\n'192.168.0.3'\n
class AdresseIP:\n def __init__(self, adresse):\n self.adresse = adresse\n\n def liste_octet(self):\n\"\"\"renvoie une liste de nombres entiers,\n la liste des octets de l'adresse IP\"\"\"\n return [int(i) for i in self.adresse.split(\".\")]\n\n def est_reservee(self):\n\"\"\"renvoie True si l'adresse IP est une adresse\n r\u00e9serv\u00e9e, False sinon\"\"\"\n return self.liste_octet()[3] == 0 or self.liste_octet()[3] == 255\n\n def adresse_suivante(self):\n\"\"\"renvoie un objet de AdresseIP avec l'adresse\n IP qui suit l\u2019adresse self\n si elle existe et False sinon\"\"\"\n if self.liste_octet()[3] < 254:\n octet_nouveau = self.liste_octet()[3] + 1\n return AdresseIP('192.168.0.' + str(octet_nouveau))\n else:\n return False\n\nadresse1 = AdresseIP('192.168.0.1')\nadresse2 = AdresseIP('192.168.0.2')\nadresse3 = AdresseIP('192.168.0.0')\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-251","title":"Exercice 25.1 \u25a1","text":"Exercice 25.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction recherche
qui prend en param\u00e8tre un tableau de nombres entiers tab
, et qui renvoie la liste (\u00e9ventuellement vide) des couples d'entiers cons\u00e9cutifs successifs qu'il peut y avoir dans tab
.
Exemples :
>>> recherche([1, 4, 3, 5])\n[]\n>>> recherche([1, 4, 5, 3])\n[(4, 5)]\n>>> recherche([7, 1, 2, 5, 3, 4])\n[(1, 2), (3, 4)]\n>>> recherche([5, 1, 2, 3, 8, -5, -4, 7])\n[(1, 2), (2, 3), (-5, -4)]\n
def recherche(tab):\n solution = []\n for i in range(len(tab)-1):\n if tab[i] + 1 == tab[i+1]:\n solution.append((tab[i], tab[i+1]))\n return solution\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-252","title":"Exercice 25.2 \u25a1","text":"Exercice 25.2
\u00c9nonc\u00e9CorrectionSoit une image binaire repr\u00e9sent\u00e9e dans un tableau \u00e0 2 dimensions. Les \u00e9l\u00e9ments M[i][j]
, appel\u00e9s pixels, sont \u00e9gaux soit \u00e0 0
soit \u00e0 1
.
Une composante d\u2019une image est un sous-ensemble de l\u2019image constitu\u00e9 uniquement de 1
et de 0
qui sont c\u00f4te \u00e0 c\u00f4te, soit horizontalement soit verticalement.
Par exemple, les composantes de sont
On souhaite, \u00e0 partir d\u2019un pixel \u00e9gal \u00e0 1
dans une image M
, donner la valeur val
\u00e0 tous les pixels de la composante \u00e0 laquelle appartient ce pixel.
La fonction propager
prend pour param\u00e8tre une image M
, deux entiers i
et j
et une valeur enti\u00e8re val
. Elle met \u00e0 la valeur val
tous les pixels de la composante du pixel M[i][j]
s\u2019il vaut 1
et ne fait rien s\u2019il vaut 0
.
Par exemple, propager(M,2,1,3)
donne
Compl\u00e9ter le code r\u00e9cursif de la fonction propager
donn\u00e9 ci-dessous :
def propager(M, i, j, val):\n if M[i][j]== ...:\n return None\n\n M[i][j] = val\n\n # l'\u00e9l\u00e9ment en haut fait partie de la composante\n if ((i-1) >= 0 and M[i-1][j] == ...):\n propager(M, i-1, j, val)\n\n # l'\u00e9l\u00e9ment en bas fait partie de la composante\n if ((...) < len(M) and M[i+1][j] == 1):\n propager(M, ..., j, val)\n\n # l'\u00e9l\u00e9ment \u00e0 gauche fait partie de la composante\n if ((...) >= 0 and M[i][j-1] == 1):\n propager(M, i, ..., val)\n\n # l'\u00e9l\u00e9ment \u00e0 droite fait partie de la composante\n if ((...) < len(M) and M[i][j+1] == 1):\n propager(M, i, ..., val)\n
Exemple : >>> M = [[0,0,1,0],[0,1,0,1],[1,1,1,0],[0,1,1,0]]\n>>> propager(M,2,1,3)\n>>> M\n[[0, 0, 1, 0], [0, 3, 0, 1], [3, 3, 3, 0], [0, 3, 3, 0]]\n
def propager(M, i, j, val):\n if M[i][j]== 0 :\n return None\n\n M[i][j] = val\n\n # l'\u00e9l\u00e9ment en haut fait partie de la composante\n if ((i-1) >= 0 and M[i-1][j] == 1):\n propager(M, i-1, j, val)\n\n # l'\u00e9l\u00e9ment en bas fait partie de la composante\n if ((i+1) < len(M) and M[i+1][j] == 1):\n propager(M, i+1, j, val)\n\n # l'\u00e9l\u00e9ment \u00e0 gauche fait partie de la composante\n if ((j-1) >= 0 and M[i][j-1] == 1):\n propager(M, i, j-1, val)\n\n # l'\u00e9l\u00e9ment \u00e0 droite fait partie de la composante\n if ((j+1) < len(M) and M[i][j+1] == 1):\n propager(M, i, j+1, val)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-261","title":"Exercice 26.1 \u25a1","text":"Exercice 26.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction occurrence_max
prenant en param\u00e8tres une cha\u00eene de caract\u00e8res chaine
et qui renvoie le caract\u00e8re le plus fr\u00e9quent de la cha\u00eene. La chaine ne contient que des lettres en minuscules sans accent. On pourra s\u2019aider du tableau
alphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o,','p','q','r','s','t','u','v','w','x','y','z']
et du tableau occurrence
de 26 \u00e9l\u00e9ments o\u00f9 l\u2019on mettra dans occurrence[i]
le nombre d\u2019apparitions de alphabet[i]
dans la chaine. Puis on calculera l\u2019indice k
d\u2019un maximum du tableau occurrence
et on affichera alphabet[k]
.
Exemple :
>>> ch = 'je suis en terminale et je passe le bac et je souhaite poursuivre des etudes pour devenir expert en informatique'\n>>> occurrence_max(ch)\n\u2018e\u2019\n
alphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o,','p','q','r','s','t','u','v','w','x','y','z']\n\ndef occurrence_max(chaine):\n occurence = [0] * 26\n for i in range(26):\n compteur = 0\n for caractere in chaine:\n if caractere == alphabet[i]:\n compteur += 1\n occurence[i] = compteur\n ind_max = 0\n for i in range(26):\n if occurence[i] > occurence[ind_max]:\n ind_max = i\n return alphabet[ind_max]\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-262","title":"Exercice 26.2 \u25a1","text":"Exercice 26.2
\u00c9nonc\u00e9CorrectionOn consid\u00e8re une image en 256 niveaux de gris que l\u2019on repr\u00e9sente par une grille de nombres, c\u2019est-\u00e0-dire une liste compos\u00e9e de sous-listes toutes de longueurs identiques. La largeur de l\u2019image est donc la longueur d\u2019une sous-liste et la hauteur de l\u2019image est le nombre de sous-listes.
Chaque sous-liste repr\u00e9sente une ligne de l\u2019image et chaque \u00e9l\u00e9ment des sous-listes est un entier compris entre 0 et 255, repr\u00e9sentant l\u2019intensit\u00e9 lumineuse du pixel.
Compl\u00e9ter le programme ci-dessous :
def nbLig(image):\n'''renvoie le nombre de lignes de l'image'''\n return ...\n\ndef nbCol(image):\n'''renvoie la largeur de l'image'''\n return ...\n\ndef negatif(image):\n'''renvoie le n\u00e9gatif de l'image sous la forme d'une liste de listes'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9\u00e9 une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(...):\n L[i][j] = ...\n return L\n\ndef binaire(image, seuil):\n'''renvoie une image binaris\u00e9e de l'image sous la forme\n d'une liste de listes contenant des 0 si la valeur\n du pixel est strictement inf\u00e9rieure au seuil\n et 1 sinon'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9e une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(...):\n if image[i][j] < ... :\n L[i][j] = ...\n else:\n L[i][j] = ...\n return L \n
Exemple :
>>> img = [[20, 34, 254, 145, 6], [23, 124, 287, 225, 69], [197, 174, 207, 25, 87], [255, 0, 24, 197, 189]]\n>>> nbLig(img)\n4\n>>> nbCol(img)\n5\n>>> negatif(img)\n[[235, 221, 1, 110, 249], [232, 131, -32, 30, 186], [58, 81, 48, 230, 168], [0, 255, 231, 58, 66]]\n>>> binaire(negatif(img),120)\n[[1, 1, 0, 0, 1], [1, 1, 0, 0, 1], [0, 0, 0, 1, 1], [0, 1, 1, 0, 0]]\n
def nbLig(image):\n'''renvoie le nombre de lignes de l'image'''\n return len(image)\n\ndef nbCol(image):\n'''renvoie la largeur de l'image'''\n return len(image[0])\n\ndef negatif(image):\n'''renvoie le n\u00e9gatif de l'image sous la forme d'une liste de listes'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9\u00e9 une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(nbCol(image)):\n L[i][j] = 255-image[i][j]\n return L\n\ndef binaire(image, seuil):\n'''renvoie une image binaris\u00e9e de l'image sous la forme\n d'une liste de listes contenant des 0 si la valeur\n du pixel est strictement inf\u00e9rieure au seuil\n et 1 sinon'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9e une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(nbCol(image)):\n if image[i][j] < seuil :\n L[i][j] = 0\n else:\n L[i][j] = 1\n return L \n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-271","title":"Exercice 27.1 \u25a1","text":"Exercice 27.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction moyenne
prenant en param\u00e8tres une liste d\u2019entiers et qui renvoie la moyenne des valeurs de cette liste.
Exemple :
>>> moyenne([10,20,30,40,60,110])\n45.0\n
def moyenne(tab):\n somme = 0\n for val in tab:\n somme += val\n return somme / len(tab)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-272","title":"Exercice 27.2 \u25a1","text":"Exercice 27.2
\u00c9nonc\u00e9CorrectionOn travaille sur des dessins en noir et blanc obtenu \u00e0 partir de pixels noirs et blancs : La figure \u00ab c\u0153ur \u00bb ci-dessus va servir d\u2019exemple. On la repr\u00e9sente par une grille de nombres, c\u2019est-\u00e0-dire par une liste compos\u00e9e de sous-listes de m\u00eame longueurs. Chaque sous-liste repr\u00e9sentera donc une ligne du dessin.
Dans le code ci-dessous, la fonction affiche
permet d\u2019afficher le dessin. Les pixels noirs (1 dans la grille) seront repr\u00e9sent\u00e9s par le caract\u00e8re \"*\" et les blancs (0 dans la grille) par deux espaces.
La fonction zoomListe
prend en argument une liste liste_depart
et un entier k
. Elle renvoie une liste o\u00f9 chaque \u00e9l\u00e9ment de liste_depart
est dupliqu\u00e9 k
fois.
La fonction zoomDessin
prend en argument la grille dessin
et renvoie une grille o\u00f9 toutes les lignes de dessin
sont zoom\u00e9es k
fois et r\u00e9p\u00e9t\u00e9es k
fois.
Soit le code ci-dessous :
coeur = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], \\\n [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0], \\\n [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \\\n [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0], \\\n [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n\ndef affiche(dessin):\n''' affichage d'une grille : les 1 sont repr\u00e9sent\u00e9s par \n des \" *\" , les 0 par deux espaces \" \" '''\n for ligne in dessin:\n for col in ligne:\n if col == 1:\n print(\" *\", end=\"\")\n else:\n print(\" \", end=\"\")\n print()\n\n\ndef zoomListe(liste_depart,k):\n'''renvoie une liste contenant k fois chaque \n \u00e9l\u00e9ment de liste_depart'''\n liste_zoom = ...\n for elt in ... :\n for i in range(k):\n ...\n return liste_zoom\n\ndef zoomDessin(grille,k):\n'''renvoie une grille o\u00f9 les lignes sont zoom\u00e9es k fois \n ET r\u00e9p\u00e9t\u00e9es k fois'''\n grille_zoom=[]\n for elt in grille:\n liste_zoom = ...\n for i in range(k):\n ... .append(...)\n return grille_zoom\n
R\u00e9sultats \u00e0 obtenir :
>>> affiche(coeur)\n
>>> affiche(zoomDessin(coeur,3))\n
* * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * \n * * * \n * * *\n
coeur = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], \\\n [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0], \\\n [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \\\n [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0], \\\n [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n\ndef affiche(dessin):\n for ligne in dessin:\n for col in ligne:\n if col == 1:\n print(' *',end='')\n else:\n print(' ',end='')\n print()\n\n\ndef zoomListe(liste_depart, k):\n liste_zoom = []\n for elt in liste_depart:\n for i in range(k):\n liste_zoom.append(elt)\n return liste_zoom\n\ndef zoomDessin(grille, k):\n grille_zoom = []\n for elt in grille:\n liste_zoom = zoomListe(elt, k)\n for i in range(k):\n grille_zoom.append(liste_zoom)\n return grille_zoom\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-281","title":"Exercice 28.1 \u25a1","text":"Exercice 28.1
\u00c9nonc\u00e9CorrectionDans cet exercice, un arbre binaire de caract\u00e8res est stock\u00e9 sous la forme d\u2019un dictionnaire o\u00f9 les clefs sont les caract\u00e8res des n\u0153uds de l\u2019arbre et les valeurs, pour chaque clef, la liste des caract\u00e8res des fils gauche et droit du n\u0153ud.
Par exemple, l\u2019arbre
est stock\u00e9 dans
a = {'F':['B','G'], 'B':['A','D'], 'A':['',''], 'D':['C','E'], \\\n'C':['',''], 'E':['',''], 'G':['','I'], 'I':['','H'], \\\n'H':['','']}\n
\u00c9crire une fonction r\u00e9cursive taille
prenant en param\u00e8tres un arbre binaire arbre
sous la forme d\u2019un dictionnaire et un caract\u00e8re lettre
qui est la valeur du sommet de l\u2019arbre, et qui renvoie la taille de l\u2019arbre \u00e0 savoir le nombre total de n\u0153ud. On pourra distinguer les 4 cas o\u00f9 les deux \u00ab fils \u00bb du n\u0153ud sont ''
, le fils gauche seulement est ''
, le fils droit seulement est ''
, aucun des deux fils n\u2019est ''
.
Exemple :
>>> taille(a, \u2019F\u2019)\n9\n
a = {'F':['B','G'], 'B':['A','D'], 'A':['',''], 'D':['C','E'], 'C':['',''], 'E':['',''], 'G':['','I'], 'I':['','H'], 'H':['','']}\n\ndef taille(arbre, lettre):\n fils_gauche = arbre[lettre][0]\n fils_droit = arbre[lettre][1]\n\n if fils_gauche != '' and fils_droit != '':\n return 1 + taille(arbre, fils_gauche) + taille(arbre, fils_droit)\n\n if fils_gauche != '' and fils_droit == '':\n return 1 + taille(arbre, fils_gauche)\n\n if fils_gauche == '' and fils_droit != '':\n return 1 + taille(arbre, fils_droit)\n\n else:\n return 1\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-282","title":"Exercice 28.2 \u25a1","text":"Exercice 28.2
\u00c9nonc\u00e9CorrectionOn consid\u00e8re l'algorithme de tri de tableau suivant : \u00e0 chaque \u00e9tape, on parcourt depuis le d\u00e9but du tableau tous les \u00e9l\u00e9ments non rang\u00e9s et on place en derni\u00e8re position le plus grand \u00e9l\u00e9ment.
Exemple avec le tableau : t = [41, 55, 21, 18, 12, 6, 25]
Le tableau devient t = [41, 25, 21, 18, 12, 6, 55]
Le tableau devient : t = [6, 25, 21, 18, 12, 41, 55]
Et ainsi de suite. La code de la fonction tri_iteratif
qui impl\u00e9mente cet algorithme est donn\u00e9 ci- dessous.
def tri_iteratif(tab):\n for k in range(..., 0 ,-1):\n imax = ...\n for i in range(0, ...):\n if tab[i] > ... :\n imax = i\n if tab[max] > ... :\n ..., tab[imax] = tab[imax], ...\n return tab\n
Compl\u00e9ter le code qui doit donner :
>>> tri_iteratif([41, 55, 21, 18, 12, 6, 25])\n[6, 12, 18, 21, 25, 41, 55]\n
On rappelle que l'instruction a, b = b, a
\u00e9change les contenus de a
et b
.
def tri_iteratif(tab):\n for k in range(len(tab)-1, 0, -1):\n imax = 0\n for i in range(0, k):\n if tab[i] > tab[imax] :\n imax = i\n if tab[imax] > tab[k] :\n tab[k], tab[imax] = tab[imax], tab[k] \n return tab\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-291","title":"Exercice 29.1 \u25a1","text":"Exercice 29.1
\u00c9nonc\u00e9CorrectionSoit un nombre entier sup\u00e9rieur ou \u00e9gal \u00e0 1 :
Puis on recommence ces \u00e9tapes avec le nombre entier obtenu, jusqu\u2019\u00e0 ce que l\u2019on obtienne la valeur 1.
On d\u00e9finit ainsi la suite \\((U_n)\\) par :
On admet que, quel que soit l'entier k
choisi au d\u00e9part, la suite finit toujours sur la valeur 1.
\u00c9crire une fonction calcul
prenant en param\u00e8tres un entier n
strictement positif et qui renvoie la liste des valeurs de la suite, en partant de n
et jusqu'\u00e0 atteindre 1.
Exemple :
>>> calcul(7)\n[7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-292","title":"Exercice 29.2 \u25a1","text":"Exercice 29.2
\u00c9nonc\u00e9CorrectionOn affecte \u00e0 chaque lettre de l'alphabet un code selon le tableau ci-dessous :
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26Pour un mot donn\u00e9, on d\u00e9termine d\u2019une part son code alphab\u00e9tique concat\u00e9n\u00e9, obtenu par la juxtaposition des codes de chacun de ses caract\u00e8res, et d\u2019autre part, son code additionn\u00e9, qui est la somme des codes de chacun de ses caract\u00e8res.
Par ailleurs, on dit que ce mot est \u00ab parfait \u00bb si le code additionn\u00e9 divise le code concat\u00e9n\u00e9.
Exemples :
Pour le mot \"PAUL\"
, le code concat\u00e9n\u00e9 est la cha\u00eene '1612112'
, soit l\u2019entier 1 612 112. Son code additionn\u00e9 est l\u2019entier 50 car 16 + 1 + 21 + 12 = 50. 50 ne divise pas l\u2019entier 1 612 112 ; par cons\u00e9quent, le mot \"PAUL\"
n\u2019est pas parfait.
Pour le mot \"ALAIN\"
, le code concat\u00e9n\u00e9 est la cha\u00eene '1121914'
, soit l\u2019entier 1 121 914. Le code additionn\u00e9 est l\u2019entier 37 car 1 + 12 + 1 + 9 + 14 = 37. 37 divise l\u2019entier 1 121 914 ; par cons\u00e9quent, le mot \"ALAIN\"
est parfait.
Compl\u00e9ter la fonction est_parfait
ci-dessous qui prend comme argument une cha\u00eene de caract\u00e8res mot
(en lettres majuscules) et qui renvoie le code alphab\u00e9tique concat\u00e9n\u00e9, le code additionn\u00e9 de mot
, ainsi qu\u2019un bool\u00e9en qui indique si mot
est parfait ou pas.
dico = {\"A\":1, \"B\":2, \"C\":3, \"D\":4, \"E\":5, \"F\":6, \"G\":7, \\\n\"H\":8, \"I\":9, \"J\":10, \"K\":11, \"L\":12, \"M\":13, \\\n\"N\":14, \"O\":15, \"P\":16, \"Q\":17, \"R\":18, \"S\":19, \\\n\"T\":20, \"U\":21,\"V\":22, \"W\":23, \"X\":24, \"Y\":25, \"Z\":26}\n\ndef est_parfait(mot) :\n #mot est une cha\u00eene de caract\u00e8res (en lettres majuscules)\n code_c = \"\"\n code_a = ???\n for c in mot :\n code_c = code_c + ???\n code_a = ???\n code_c = int(code_c)\n if ??? :\n mot_est_parfait = True\n else :\n mot_est_parfait = False\n return [code_a, code_c, mot_est_parfait]\n
Exemples :
>>> est_parfait(\"PAUL\")\n[50, 1612112, False]\n>>> est_parfait(\"ALAIN\")\n[37, 1121914, True]\n
dico = {\"A\":1, \"B\":2, \"C\":3, \"D\":4, \"E\":5, \"F\":6, \"G\":7, \\\n\"H\":8, \"I\":9, \"J\":10, \"K\":11, \"L\":12, \"M\":13, \\\n\"N\":14, \"O\":15, \"P\":16, \"Q\":17, \"R\":18, \"S\":19, \\\n\"T\":20, \"U\":21,\"V\":22, \"W\":23, \"X\":24, \"Y\":25, \"Z\":26}\n\ndef est_parfait(mot) :\n #mot est une cha\u00eene de caract\u00e8res (en lettres majuscules)\n code_c = \"\"\n code_a = 0\n for c in mot :\n code_c = code_c + str(dico[c])\n code_a = code_a + dico[c]\n code_c = int(code_c)\n if code_c % code_a == 0:\n mot_est_parfait = True\n else :\n mot_est_parfait = False\n return [code_a, code_c, mot_est_parfait]\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-301","title":"Exercice 30.1 \u25a1","text":"Exercice 30.1
\u00c9nonc\u00e9CorrectionProgrammer la fonction multiplication
, prenant en param\u00e8tres deux nombres entiers n1
et n2
, et qui renvoie le produit de ces deux nombres. Les seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.
Exemples :
>>> multiplication(3,5)\n15\n>>> multiplication(-4,-8)\n32\n>>> multiplication(-2,6)\n-12\n>>> multiplication(-2,0)\n0\n
def multiplication(n1, n2):\n if n1 < 0:\n return -multiplication(-n1, n2)\n if n2 < 0:\n return -multiplication(n1, -n2)\n resultat = 0\n for _ in range(n2):\n resultat += n1\n return resultat\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-302","title":"Exercice 30.2 \u25a1","text":"Exercice 30.2
\u00c9nonc\u00e9CorrectionSources en MarkdownSoit T
un tableau non vide d'entiers tri\u00e9s dans l'ordre croissant et n
un entier. La fonction chercher
, donn\u00e9e \u00e0 la page suivante, doit renvoyer un indice o\u00f9 la valeur n
appara\u00eet \u00e9ventuellement dans T
, et None
sinon.
Les param\u00e8tres de la fonction sont :
T
, le tableau dans lequel s'effectue la recherche ;n
, l'entier \u00e0 chercher dans le tableau ;i
, l'indice de d\u00e9but de la partie du tableau o\u00f9 s'effectue la recherche ;j
, l'indice de fin de la partie du tableau o\u00f9 s'effectue la recherche.La fonction chercher
est une fonction r\u00e9cursive bas\u00e9e sur le principe \u00ab diviser pour r\u00e9gner \u00bb.
Le code de la fonction commence par v\u00e9rifier si 0 <= i
et j < len(T)
. Si cette condition n\u2019est pas v\u00e9rifi\u00e9e, elle affiche \"Erreur\"
puis renvoie None
.
Recopier et compl\u00e9ter le code de la fonction chercher
propos\u00e9e ci-dessous :
def chercher(T, n, i, j):\n if i < 0 or ??? :\n print(\"Erreur\")\n return None\n if i > j :\n return None\n m = (i + j) // ???\n if T[m] < ??? :\n return chercher(T, n, ??? , ???)\n elif ??? :\n return chercher(T, n, ??? , ??? )\n else :\n return ???\n
L'ex\u00e9cution du code doit donner :
>>> chercher([1,5,6,6,9,12],7,0,10)\nErreur\n>>> chercher([1,5,6,6,9,12],7,0,5)\n>>> chercher([1,5,6,6,9,12],9,0,5)\n4\n>>> chercher([1,5,6,6,9,12],6,0,5)\n2\n
def chercher(T, n, i, j):\n if i < 0 or j >= len(T) :\n print('Erreur')\n return None\n if i > j :\n return None\n m = (i + j) // 2\n if T[m] < n :\n return chercher(T, n, m + 1, j)\n elif T[m] > n :\n return chercher(T, n, i, m - 1 )\n else :\n return m\n
Soit `T` un tableau non vide d'entiers tri\u00e9s dans l'ordre croissant et `n` un entier.\nLa fonction `chercher`, donn\u00e9e \u00e0 la page suivante, doit renvoyer un indice o\u00f9 la valeur `n`\nappara\u00eet \u00e9ventuellement dans `T`, et `None` sinon. \n\nLes param\u00e8tres de la fonction sont :\n\n- `T`, le tableau dans lequel s'effectue la recherche ;\n- `n`, l'entier \u00e0 chercher dans le tableau ;\n- `i`, l'indice de d\u00e9but de la partie du tableau o\u00f9 s'effectue la recherche ;\n- `j`, l'indice de fin de la partie du tableau o\u00f9 s'effectue la recherche.\n\nLa fonction `chercher` est une fonction r\u00e9cursive bas\u00e9e sur le principe \u00ab diviser pour\nr\u00e9gner \u00bb.\n\n\nLe code de la fonction commence par v\u00e9rifier si `0 <= i` et `j < len(T)`. \nSi cette\ncondition n\u2019est pas v\u00e9rifi\u00e9e, elle affiche `\"Erreur\"` puis renvoie `None`.\n\nRecopier et compl\u00e9ter le code de la fonction `chercher` propos\u00e9e ci-dessous :\n\n```python linenums='1'\ndef chercher(T, n, i, j):\n if i < 0 or ??? :\n print(\"Erreur\")\n return None\n if i > j :\n return None\n m = (i + j) // ???\n if T[m] < ??? :\n return chercher(T, n, ??? , ???)\n elif ??? :\n return chercher(T, n, ??? , ??? )\n else :\n return ???\n```\n\nL'ex\u00e9cution du code doit donner :\n```python\n>>> chercher([1,5,6,6,9,12],7,0,10)\nErreur\n>>> chercher([1,5,6,6,9,12],7,0,5)\n>>> chercher([1,5,6,6,9,12],9,0,5)\n4\n>>> chercher([1,5,6,6,9,12],6,0,5)\n2\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/","title":"\u00c9preuve Pratique BNS 2022","text":"\u00c0 lire
Pourquoi proposer une correction ?
Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-011","title":"Exercice 01.1 \u25a1","text":"Exercice 01.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche
qui prend en param\u00e8tres caractere
, un caract\u00e8re, et mot
, une cha\u00eene de caract\u00e8res, et qui renvoie le nombre d\u2019occurrences de caractere
dans mot
, c\u2019est-\u00e0-dire le nombre de fois o\u00f9 caractere
appara\u00eet dans mot
.
Exemples :
>>> recherche('e', \"sciences\")\n2\n>>> recherche('i',\"mississippi\")\n4\n>>> recherche('a',\"mississippi\")\n0\n
def recherche(caractere, mot):\n somme = 0\n for lettre in mot:\n if lettre == caractere:\n somme += 1\n return somme\n
\u00c9crire une fonction `recherche` qui prend en param\u00e8tres `caractere`, un caract\u00e8re, et\n`mot`, une cha\u00eene de caract\u00e8res, et qui renvoie le nombre d\u2019occurrences de `caractere`\ndans `mot`, c\u2019est-\u00e0-dire le nombre de fois o\u00f9 `caractere` appara\u00eet dans `mot`.\n\nExemples :\n```python\n>>> recherche('e', \"sciences\")\n2\n>>> recherche('i',\"mississippi\")\n4\n>>> recherche('a',\"mississippi\")\n0\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-012","title":"Exercice 01.2 \u25a1","text":"Exercice 01.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn s\u2019int\u00e9resse \u00e0 un algorithme r\u00e9cursif qui permet de rendre la monnaie \u00e0 partir d\u2019une liste donn\u00e9e de valeurs de pi\u00e8ces et de billets.
Le syst\u00e8me mon\u00e9taire est donn\u00e9 sous forme d\u2019une liste pieces=[100, 50, 20, 10, 5, 2, 1]
. (on supposera qu\u2019il n\u2019y a pas de limitation quant \u00e0 leur nombre).
On cherche \u00e0 donner la liste de pi\u00e8ces \u00e0 rendre pour une somme donn\u00e9e en argument. Compl\u00e9ter le code Python ci-dessous de la fonction rendu_glouton
qui impl\u00e9mente cet algorithme et renvoie la liste des pi\u00e8ces \u00e0 rendre.
pieces = [100,50,20,10,5,2,1] # (1)\n\ndef rendu_glouton(arendre, solution=[], i=0):\n if arendre == 0:\n return ...\n p = pieces[i]\n if p <= ... :\n solution.append(...)\n return rendu_glouton(arendre - p, solution,i)\n else :\n return rendu_glouton(arendre, solution, ...)\n
Pieces
On devra obtenir :
>>> rendu_glouton(68, [], 0) \n[50, 10, 5, 2, 1]\n>>> rendu_glouton(291, [], 0) \n[100, 100, 50, 20, 20, 1]\n
pieces = [100,50,20,10,5,2,1]\n\ndef rendu_glouton(arendre, solution=[], i=0):\n if arendre == 0:\n return solution\n p = pieces[i]\n if p <= arendre :\n solution.append(p)\n return rendu_glouton(arendre - p, solution,i)\n else :\n return rendu_glouton(arendre, solution, i+1)\n
On s\u2019int\u00e9resse \u00e0 un algorithme r\u00e9cursif qui permet de rendre la monnaie \u00e0 partir d\u2019une\nliste donn\u00e9e de valeurs de pi\u00e8ces et de billets.\n\nLe syst\u00e8me mon\u00e9taire est donn\u00e9 sous\nforme d\u2019une liste `pieces=[100, 50, 20, 10, 5, 2, 1]`.\n(on supposera qu\u2019il n\u2019y a\npas de limitation quant \u00e0 leur nombre).\n\nOn cherche \u00e0 donner la liste de pi\u00e8ces \u00e0 rendre\npour une somme donn\u00e9e en argument.\nCompl\u00e9ter le code Python ci-dessous de la fonction `rendu_glouton` qui impl\u00e9mente cet\nalgorithme et renvoie la liste des pi\u00e8ces \u00e0 rendre.\n\n```python linenums='1'\npieces = [100,50,20,10,5,2,1] # (1)\n\ndef rendu_glouton(arendre, solution=[], i=0):\n if arendre == 0:\n return ...\n p = pieces[i]\n if p <= ... :\n solution.append(...)\n return rendu_glouton(arendre - p, solution,i)\n else :\n return rendu_glouton(arendre, solution, ...)\n
Pieces
On devra obtenir :
>>> rendu_glouton(68, [], 0) \n[50, 10, 5, 2, 1]\n>>> rendu_glouton(291, [], 0) \n[100, 100, 50, 20, 20, 1]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-02","title":"\u25b6 Sujet 02","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-021","title":"Exercice 02.1 \u25a1","text":"Exercice 02.1
\u00c9nonc\u00e9CorrectionSource MarkdownSoit le couple (note
,coefficient
):
note
est un nombre de type flottant (float
) compris entre 0 et 20 ;coefficient
est un nombre entier positif.Les r\u00e9sultats aux \u00e9valuations d'un \u00e9l\u00e8ve sont regroup\u00e9s dans une liste compos\u00e9e de couples (note
,coefficient
).
\u00c9crire une fonction moyenne qui renvoie la moyenne pond\u00e9r\u00e9e de cette liste donn\u00e9e en param\u00e8tre.
Par exemple, l\u2019expression moyenne([(15,2),(9,1),(12,3)])
devra renvoyer le r\u00e9sultat du calcul suivant :
\\(\\dfrac{2 \\times 15 + 1 \\times 9 + 3 \\times 12 }{2+1+3}=12,5\\)
def moyenne(tab):\n somme_notes = 0\n somme_coeffs = 0\n for devoir in tab:\n note = devoir[0]\n coeff = devoir[1]\n somme_notes += note * coeff\n somme_coeffs += coeff\n return somme_notes / somme_coeffs\n
Soit le couple (`note`,`coefficient`):\n\n- `note` est un nombre de type flottant (`float`) compris entre 0 et 20 ;\n- `coefficient` est un nombre entier positif.\n\nLes r\u00e9sultats aux \u00e9valuations d'un \u00e9l\u00e8ve sont regroup\u00e9s dans une liste compos\u00e9e de\ncouples (`note`,`coefficient`).\n\n\u00c9crire une fonction moyenne qui renvoie la moyenne pond\u00e9r\u00e9e de cette liste donn\u00e9e en\nparam\u00e8tre.\n\nPar exemple, l\u2019expression `moyenne([(15,2),(9,1),(12,3)])` devra renvoyer le\nr\u00e9sultat du calcul suivant :\n\n$\\dfrac{2 \\times 15 + 1 \\times 9 + 3 \\times 12 }{2+1+3}=12,5$\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-022","title":"Exercice 02.2 \u25a1","text":"Exercice 02.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn cherche \u00e0 d\u00e9terminer les valeurs du triangle de Pascal. Dans ce tableau de forme triangulaire, chaque ligne commence et se termine par le nombre 1. Par ailleurs, la valeur qui occupe une case situ\u00e9e \u00e0 l\u2019int\u00e9rieur du tableau s\u2019obtient en ajoutant les valeurs des deux cases situ\u00e9es juste au-dessus, comme l\u2019indique la figure suivante :
Compl\u00e9ter la fonction pascal
ci-apr\u00e8s. Elle doit renvoyer une liste correspondant au triangle de Pascal de la ligne 1
\u00e0 la ligne n
o\u00f9 n
est un nombre entier sup\u00e9rieur ou \u00e9gal \u00e0 2
(le tableau sera contenu dans la variable C
). La variable Ck
doit, quant \u00e0 elle, contenir, \u00e0 l\u2019\u00e9tape num\u00e9ro k
, la k
-i\u00e8me ligne du tableau.
def pascal(n):\n C= [[1]]\n for k in range(1,...):\n Ck = [...]\n for i in range(1,k):\n Ck.append(C[...][i-1]+C[...][...] )\n Ck.append(...)\n C.append(Ck)\n return C\n
Pour n = 4
, voici ce qu'on devra obtenir :
>>> pascal(4)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]\n
Pour n = 5
, voici ce qu'on devra obtenir : >>> pascal(5)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1]]\n
def pascal(n):\n C = [[1]]\n for k in range(1,n+1):\n Ck = [1]\n for i in range(1,k):\n Ck.append(C[k-1][i-1]+C[k-1][i] )\n Ck.append(1)\n C.append(Ck)\n return C\n
On cherche \u00e0 d\u00e9terminer les valeurs du triangle de Pascal. Dans ce tableau de forme\ntriangulaire, chaque ligne commence et se termine par le nombre 1. Par ailleurs, la valeur\nqui occupe une case situ\u00e9e \u00e0 l\u2019int\u00e9rieur du tableau s\u2019obtient en ajoutant les valeurs des\ndeux cases situ\u00e9es juste au-dessus, comme l\u2019indique la figure suivante :\n\n![image](data/img9_2t.png){: .center width=60%}\n\nCompl\u00e9ter la fonction `pascal` ci-apr\u00e8s. Elle doit renvoyer une liste correspondant au\ntriangle de Pascal de la ligne `1` \u00e0 la ligne `n` o\u00f9 `n` est un nombre entier sup\u00e9rieur ou \u00e9gal \u00e0\n`2` (le tableau sera contenu dans la variable `C`). La variable `Ck` doit, quant \u00e0 elle, contenir,\n\u00e0 l\u2019\u00e9tape num\u00e9ro `k`, la `k`-i\u00e8me ligne du tableau.\n\n```python linenums='1'\ndef pascal(n):\n C= [[1]]\n for k in range(1,...):\n Ck = [...]\n for i in range(1,k):\n Ck.append(C[...][i-1]+C[...][...] )\n Ck.append(...)\n C.append(Ck)\n return C\n
Pour n = 4
, voici ce qu'on devra obtenir :
>>> pascal(4)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]\n
Pour n = 5
, voici ce qu'on devra obtenir : >>> pascal(5)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1]]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-03","title":"\u25b6 Sujet 03","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-031","title":"Exercice 03.1 \u25a1","text":"Exercice 03.1
\u00c9nonc\u00e9CorrectionSource MarkdownLe codage par diff\u00e9rence (delta encoding en anglais) permet de compresser un tableau de donn\u00e9es en indiquant pour chaque donn\u00e9e, sa diff\u00e9rence avec la pr\u00e9c\u00e9dente (plut\u00f4t que la donn\u00e9e elle-m\u00eame). On se retrouve alors avec un tableau de donn\u00e9es assez petites n\u00e9cessitant moins de place en m\u00e9moire. Cette m\u00e9thode se r\u00e9v\u00e8le efficace lorsque les valeurs cons\u00e9cutives sont proches.
Programmer la fonction delta
qui prend en param\u00e8tre un tableau non vide de nombres entiers et qui renvoie un tableau contenant les valeurs enti\u00e8res compress\u00e9es \u00e0 l\u2019aide cette technique.
Exemples :
>>> delta([1000, 800, 802, 1000, 1003])\n[1000, -200, 2, 198, 3]\n>>> delta([42])\n[42] \n
def delta(tab):\n diff = [tab[0]]\n for i in range(1, len(tab)):\n diff.append(tab[i] - tab[i-1])\n return diff\n
Le codage par diff\u00e9rence (delta encoding en anglais) permet de compresser un tableau de\ndonn\u00e9es en indiquant pour chaque donn\u00e9e, sa diff\u00e9rence avec la pr\u00e9c\u00e9dente (plut\u00f4t que la\ndonn\u00e9e elle-m\u00eame). On se retrouve alors avec un tableau de donn\u00e9es assez petites n\u00e9cessitant\nmoins de place en m\u00e9moire. Cette m\u00e9thode se r\u00e9v\u00e8le efficace lorsque les valeurs cons\u00e9cutives\nsont proches.\n\nProgrammer la fonction `delta` qui prend en param\u00e8tre un tableau non vide de nombres entiers\net qui renvoie un tableau contenant les valeurs enti\u00e8res compress\u00e9es \u00e0 l\u2019aide cette technique.\n\nExemples :\n\n```python\n>>> delta([1000, 800, 802, 1000, 1003])\n[1000, -200, 2, 198, 3]\n>>> delta([42])\n[42] \n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-032","title":"Exercice 03.2 \u25a1","text":"Exercice 03.2
\u00c9nonc\u00e9CorrectionSources MarkdownUne expression arithm\u00e9tique ne comportant que les quatre op\u00e9rations +, \u2212,\u00d7,\u00f7 peut \u00eatre repr\u00e9sent\u00e9e sous forme d\u2019arbre binaire. Les n\u0153uds internes sont des op\u00e9rateurs et les feuilles sont des nombres. Dans un tel arbre, la disposition des n\u0153uds joue le r\u00f4le des parenth\u00e8ses que nous connaissons bien.
En parcourant en profondeur infixe l\u2019arbre binaire ci-dessus, on retrouve l\u2019expression not\u00e9e habituellement :
\\[3 \\times (8 + 7) \u2212 (2 + 1)\\]La classe Noeud
ci-apr\u00e8s permet d\u2019impl\u00e9menter une structure d\u2019arbre binaire. Compl\u00e9ter la fonction r\u00e9cursive expression_infixe
qui prend en param\u00e8tre un objet de la classe Noeud
et qui renvoie l\u2019expression arithm\u00e9tique repr\u00e9sent\u00e9e par l\u2019arbre binaire pass\u00e9 en param\u00e8tre, sous forme d\u2019une cha\u00eene de caract\u00e8res contenant des parenth\u00e8ses.
R\u00e9sultat attendu avec l\u2019arbre ci-dessus :
>>> e = Noeud(Noeud(Noeud(None, 3, None), '*', Noeud(Noeud(None, 8, None),\n'+', Noeud(None, 7, None))), '-', Noeud(Noeud(None, 2, None), '+',\nNoeud(None, 1, None)))\n\n>>> expression_infixe(e)\n'((3*(8+7))-(2+1))'\n
class Noeud:\n'''\n Classe impl\u00e9mentant un noeud d'arbre binaire disposant de 3\n attributs :\n - valeur : la valeur de l'\u00e9tiquette,\n - gauche : le sous-arbre gauche.\n - droit : le sous-arbre droit.\n '''\n def __init__(self, g, v, d):\n self.gauche = g\n self.valeur = v\n self.droit = d\n\n def est_une_feuille(self):\n'''Renvoie True si et seulement si le noeud est une feuille'''\n return self.gauche is None and self.droit is None\n\ndef expression_infixe(e):\n s = ...\n if e.gauche is not None:\n s = '(' + s + expression_infixe(...)\n s = s + ...\n if ... is not None:\n s = s + ... + ...\n return s # (1)\n
return
d'un if ...
qui a \u00e9t\u00e9 supprim\u00e9 ici. Il faudrait \u00e9crire if True:
, ce qui est inutile... class Noeud:\n'''\n Classe impl\u00e9mentant un noeud d'arbre binaire disposant de 3\n attributs :\n - valeur : la valeur de l'\u00e9tiquette,\n - gauche : le sous-arbre gauche.\n - droit : le sous-arbre droit.\n '''\n def __init__(self, g, v, d):\n self.gauche = g\n self.valeur = v\n self.droit = d\n\n def est_une_feuille(self):\n'''Renvoie True si et seulement si le noeud est une feuille'''\n return self.gauche is None and self.droit is None\n\ne = Noeud(Noeud(Noeud(None, 3, None), '*', Noeud(Noeud(None, 8, None),\n'+', Noeud(None, 7, None))), '-', Noeud(Noeud(None, 2, None), '+',\nNoeud(None, 1, None)))\n\ndef expression_infixe(e):\n s = ''\n if e.gauche is not None:\n s = '(' + s + expression_infixe(e.gauche)\n s = s + str(e.valeur)\n if e.droit is not None:\n s = s + expression_infixe(e.droit) + ')'\n return s\n
Une expression arithm\u00e9tique ne comportant que les quatre op\u00e9rations +, \u2212,\u00d7,\u00f7 peut \u00eatre\nrepr\u00e9sent\u00e9e sous forme d\u2019arbre binaire. Les n\u0153uds internes sont des op\u00e9rateurs et les feuilles\nsont des nombres. Dans un tel arbre, la disposition des n\u0153uds joue le r\u00f4le des parenth\u00e8ses que\nnous connaissons bien. \n\n![image](data/img3_2.png){: .center width=30%}\n\nEn parcourant en profondeur infixe l\u2019arbre binaire ci-dessus, on\nretrouve l\u2019expression not\u00e9e habituellement : \n\n\n$$3 \\times (8 + 7) \u2212 (2 + 1)$$\n\n\nLa classe `Noeud` ci-apr\u00e8s permet d\u2019impl\u00e9menter une structure\nd\u2019arbre binaire.\nCompl\u00e9ter la fonction r\u00e9cursive `expression_infixe` qui prend\nen param\u00e8tre un objet de la classe `Noeud` et qui renvoie\nl\u2019expression arithm\u00e9tique repr\u00e9sent\u00e9e par l\u2019arbre binaire pass\u00e9\nen param\u00e8tre, sous forme d\u2019une cha\u00eene de caract\u00e8res contenant\ndes parenth\u00e8ses. \n\nR\u00e9sultat attendu avec l\u2019arbre ci-dessus :\n\n```python\n>>> e = Noeud(Noeud(Noeud(None, 3, None), '*', Noeud(Noeud(None, 8, None),\n'+', Noeud(None, 7, None))), '-', Noeud(Noeud(None, 2, None), '+',\nNoeud(None, 1, None)))\n\n>>> expression_infixe(e)\n'((3*(8+7))-(2+1))'\n
class Noeud:\n'''\n Classe impl\u00e9mentant un noeud d'arbre binaire disposant de 3\n attributs :\n - valeur : la valeur de l'\u00e9tiquette,\n - gauche : le sous-arbre gauche.\n - droit : le sous-arbre droit.\n '''\n def __init__(self, g, v, d):\n self.gauche = g\n self.valeur = v\n self.droit = d\n\n def est_une_feuille(self):\n'''Renvoie True si et seulement si le noeud est une feuille'''\n return self.gauche is None and self.droit is None\n\ndef expression_infixe(e):\n s = ...\n if e.gauche is not None:\n s = '(' + s + expression_infixe(...)\n s = s + ...\n if ... is not None:\n s = s + ... + ...\n return s # (1)\n
return
d'un if ...
qui a \u00e9t\u00e9 supprim\u00e9 ici. Il faudrait \u00e9crire if True:
, ce qui est inutile... ``` Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-041","title":"Exercice 04.1 \u25a1","text":"Exercice 04.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche
qui prend en param\u00e8tre un tableau de nombres entiers tab
, et qui renvoie la liste (\u00e9ventuellement vide) des couples d'entiers cons\u00e9cutifs successifs qu'il peut y avoir dans tab
.
Exemples :
>>> recherche([1, 4, 3, 5])\n[]\n>>> recherche([1, 4, 5, 3])\n[(4, 5)]\n>>> recherche([7, 1, 2, 5, 3, 4])\n[(1, 2), (3, 4)]\n>>> recherche([5, 1, 2, 3, 8, -5, -4, 7])\n[(1, 2), (2, 3), (-5, -4)]\n
def recherche(tab):\n solution = []\n for i in range(len(tab)-1):\n if tab[i] + 1 == tab[i+1]:\n solution.append((tab[i], tab[i+1]))\n return solution\n
\u00c9crire une fonction `recherche` qui prend en param\u00e8tre un tableau de nombres entiers\n`tab`, et qui renvoie la liste (\u00e9ventuellement vide) des couples d'entiers cons\u00e9cutifs\nsuccessifs qu'il peut y avoir dans `tab`.\n\nExemples :\n```python\n>>> recherche([1, 4, 3, 5])\n[]\n>>> recherche([1, 4, 5, 3])\n[(4, 5)]\n>>> recherche([7, 1, 2, 5, 3, 4])\n[(1, 2), (3, 4)]\n>>> recherche([5, 1, 2, 3, 8, -5, -4, 7])\n[(1, 2), (2, 3), (-5, -4)]\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-042","title":"Exercice 04.2 \u25a1","text":"Exercice 04.2
\u00c9nonc\u00e9CorrectionSources MarkdownSoit une image binaire repr\u00e9sent\u00e9e dans un tableau \u00e0 2 dimensions. Les \u00e9l\u00e9ments M[i][j]
, appel\u00e9s pixels, sont \u00e9gaux soit \u00e0 0
soit \u00e0 1
.
Une composante d\u2019une image est un sous-ensemble de l\u2019image constitu\u00e9 uniquement de 1
et de 0
qui sont c\u00f4te \u00e0 c\u00f4te, soit horizontalement soit verticalement.
Par exemple, les composantes de sont
On souhaite, \u00e0 partir d\u2019un pixel \u00e9gal \u00e0 1
dans une image M
, donner la valeur val
\u00e0 tous les pixels de la composante \u00e0 laquelle appartient ce pixel.
La fonction propager
prend pour param\u00e8tre une image M
, deux entiers i
et j
et une valeur enti\u00e8re val
. Elle met \u00e0 la valeur val
tous les pixels de la composante du pixel M[i][j]
s\u2019il vaut 1
et ne fait rien s\u2019il vaut 0
.
Par exemple, propager(M,2,1,3)
donne
Compl\u00e9ter le code r\u00e9cursif de la fonction propager
donn\u00e9 ci-dessous :
def propager(M, i, j, val):\n if M[i][j]== ...:\n return None # (1)\n\n M[i][j] = val\n\n # l'\u00e9l\u00e9ment en haut fait partie de la composante\n if ((i-1) >= 0 and M[i-1][j] == ...):\n propager(M, i-1, j, val)\n\n # l'\u00e9l\u00e9ment en bas fait partie de la composante\n if ((...) < len(M) and M[i+1][j] == 1):\n propager(M, ..., j, val)\n\n # l'\u00e9l\u00e9ment \u00e0 gauche fait partie de la composante\n if ((...) >= 0 and M[i][j-1] == 1):\n propager(M, i, ..., val)\n\n # l'\u00e9l\u00e9ment \u00e0 droite fait partie de la composante\n if ((...) < len(M) and M[i][j+1] == 1): # (2)\n propager(M, i, ..., val)\n
return
. len(M[0])
plut\u00f4t que len(M)
. (\u00e9quivalent ici car l'image est carr\u00e9e...)Exemple :
>>> M = [[0,0,1,0],[0,1,0,1],[1,1,1,0],[0,1,1,0]]\n>>> propager(M,2,1,3)\n>>> M\n[[0, 0, 1, 0], [0, 3, 0, 1], [3, 3, 3, 0], [0, 3, 3, 0]]\n
def propager(M, i, j, val):\n if M[i][j]== 0 :\n return None\n\n M[i][j] = val\n\n # l'\u00e9l\u00e9ment en haut fait partie de la composante\n if ((i-1) >= 0 and M[i-1][j] == 1):\n propager(M, i-1, j, val)\n\n # l'\u00e9l\u00e9ment en bas fait partie de la composante\n if ((i+1) < len(M) and M[i+1][j] == 1):\n propager(M, i+1, j, val)\n\n # l'\u00e9l\u00e9ment \u00e0 gauche fait partie de la composante\n if ((j-1) >= 0 and M[i][j-1] == 1):\n propager(M, i, j-1, val)\n\n # l'\u00e9l\u00e9ment \u00e0 droite fait partie de la composante\n if ((j+1) < len(M) and M[i][j+1] == 1):\n propager(M, i, j+1, val)\n
Soit une image binaire repr\u00e9sent\u00e9e dans un tableau \u00e0 2 dimensions. Les \u00e9l\u00e9ments\n`M[i][j]`, appel\u00e9s pixels, sont \u00e9gaux soit \u00e0 `0` soit \u00e0 `1`.\n\nUne composante d\u2019une image est un sous-ensemble de l\u2019image constitu\u00e9 uniquement de\n`1` et de `0` qui sont c\u00f4te \u00e0 c\u00f4te, soit horizontalement soit verticalement.\n\nPar exemple, les composantes de\n![image](data/252a.png){: .center width=30%}\nsont\n![image](data/252b.png){: .center width=30%}\n\nOn souhaite, \u00e0 partir d\u2019un pixel \u00e9gal \u00e0 `1` dans une image `M`, donner la valeur `val` \u00e0 tous\nles pixels de la composante \u00e0 laquelle appartient ce pixel.\n\nLa fonction `propager` prend pour param\u00e8tre une image `M`, deux entiers `i` et `j` et une\nvaleur enti\u00e8re `val`. Elle met \u00e0 la valeur `val` tous les pixels de la composante du pixel\n`M[i][j]` s\u2019il vaut `1` et ne fait rien s\u2019il vaut `0`.\n\nPar exemple, `propager(M,2,1,3)` donne\n![image](data/252c.png){: .center width=30%}\n\nCompl\u00e9ter le code r\u00e9cursif de la fonction `propager` donn\u00e9 ci-dessous :\n\n```python linenums='1'\ndef propager(M, i, j, val):\n if M[i][j]== ...:\n return None # (1)\n\n M[i][j] = val\n\n # l'\u00e9l\u00e9ment en haut fait partie de la composante\n if ((i-1) >= 0 and M[i-1][j] == ...):\n propager(M, i-1, j, val)\n\n # l'\u00e9l\u00e9ment en bas fait partie de la composante\n if ((...) < len(M) and M[i+1][j] == 1):\n propager(M, ..., j, val)\n\n # l'\u00e9l\u00e9ment \u00e0 gauche fait partie de la composante\n if ((...) >= 0 and M[i][j-1] == 1):\n propager(M, i, ..., val)\n\n # l'\u00e9l\u00e9ment \u00e0 droite fait partie de la composante\n if ((...) < len(M) and M[i][j+1] == 1): # (2)\n propager(M, i, ..., val)\n
return
. len(M[0])
plut\u00f4t que len(M)
. (\u00e9quivalent ici car l'image est carr\u00e9e...)Exemple :
>>> M = [[0,0,1,0],[0,1,0,1],[1,1,1,0],[0,1,1,0]]\n>>> propager(M,2,1,3)\n>>> M\n[[0, 0, 1, 0], [0, 3, 0, 1], [3, 3, 3, 0], [0, 3, 3, 0]]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-05","title":"\u25b6 Sujet 05","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-051","title":"Exercice 05.1 \u25a1","text":"Exercice 05.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction rechercheMinMax
qui prend en param\u00e8tre un tableau de nombres non tri\u00e9s tab
, et qui renvoie la plus petite et la plus grande valeur du tableau sous la forme d\u2019un dictionnaire \u00e0 deux cl\u00e9s \u2018min\u2019 et \u2018max\u2019. Les tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.
Exemples :
>>> tableau = [0, 1, 4, 2, -2, 9, 3, 1, 7, 1]\n>>> resultat = rechercheMinMax(tableau)\n>>> resultat\n{'min': -2, 'max': 9}\n>>> tableau = []\n>>> resultat = rechercheMinMax(tableau)\n>>> resultat\n{'min': None, 'max': None}\n
def rechercheMinMax(tab):\n if tab == []:\n return {'min': None, 'max': None}\n d = {}\n d['min'] = tab[0]\n d['max'] = tab[0]\n for val in tab:\n if val < d['min']:\n d['min'] = val\n if val > d['max']:\n d['max'] = val\n return d\n
\u00c9crire une fonction `rechercheMinMax` qui prend en param\u00e8tre un tableau de nombres\nnon tri\u00e9s `tab`, et qui renvoie la plus petite et la plus grande valeur du tableau sous la\nforme d\u2019un dictionnaire \u00e0 deux cl\u00e9s \u2018min\u2019 et \u2018max\u2019. Les tableaux seront repr\u00e9sent\u00e9s sous\nforme de liste Python.\n\nExemples :\n```python\n>>> tableau = [0, 1, 4, 2, -2, 9, 3, 1, 7, 1]\n>>> resultat = rechercheMinMax(tableau)\n>>> resultat\n{'min': -2, 'max': 9}\n>>> tableau = []\n>>> resultat = rechercheMinMax(tableau)\n>>> resultat\n{'min': None, 'max': None}\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-052","title":"Exercice 05.2 \u25a1","text":"Exercice 05.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn dispose d\u2019un programme permettant de cr\u00e9er un objet de type PaquetDeCarte
, selon les \u00e9l\u00e9ments indiqu\u00e9s dans le code ci-dessous. Compl\u00e9ter ce code aux endroits indiqu\u00e9s par #A compl\u00e9ter
, puis ajouter des assertions dans l\u2019initialiseur de Carte
, ainsi que dans la m\u00e9thode getCarteAt()
.
class Carte:\n\"\"\"Initialise Couleur (entre 1 a 4), et Valeur (entre 1 a 13)\"\"\"\n def __init__(self, c, v):\n self.Couleur = c\n self.Valeur = v\n\n\"\"\"Renvoie le nom de la Carte As, 2, ... 10, \n Valet, Dame, Roi\"\"\"\n def getNom(self):\n if ( self.Valeur > 1 and self.Valeur < 11):\n return str( self.Valeur)\n elif self.Valeur == 11:\n return \"Valet\"\n elif self.Valeur == 12:\n return \"Dame\"\n elif self.Valeur == 13:\n return \"Roi\"\n else:\n return \"As\"\n\n\"\"\"Renvoie la couleur de la Carte (parmi pique, coeur, carreau, trefle\"\"\"\n def getCouleur(self):\n return ['pique', 'coeur', 'carreau', 'trefle' ][self.Couleur - 1]\n\nclass PaquetDeCarte:\n def __init__(self):\n self.contenu = []\n\n\"\"\"Remplit le paquet de cartes\"\"\"\n def remplir(self):\n ??? = [ ??? for couleur in range(1, ???) for valeur in range( 1, ???)]\n\n\"\"\"Renvoie la Carte qui se trouve a\u00a0 la position donnee\"\"\"\n def getCarteAt(self, pos):\n if 0 <= pos < ??? :\n return ???\n
Exemple : >>> unPaquet = PaquetDeCarte()\n>>> unPaquet.remplir()\n>>> uneCarte = unPaquet.getCarteAt(20)\n>>> print(uneCarte.getNom() + \" de \" + uneCarte.getCouleur())\n 8 de coeur\n
Attention, le code propos\u00e9 ne respecte pas les standards de notation :
class Carte:\n\"\"\"Initialise Couleur (entre 1 \u00e0 4), et Valeur (entre 1 \u00e0 13)\"\"\"\n def __init__(self, c, v):\n assert c in range(1, 5)\n assert v in range(1, 14)\n self.Couleur = c\n self.Valeur = v\n\n\"\"\"Renvoie le nom de la Carte As, 2, ... 10, Valet, Dame, Roi\"\"\"\n def getNom(self):\n if (self.Valeur > 1 and self.Valeur < 11):\n return str( self.Valeur)\n elif self.Valeur == 11:\n return \"Valet\"\n elif self.Valeur == 12:\n return \"Dame\"\n elif self.Valeur == 13:\n return \"Roi\"\n else:\n return \"As\"\n\n\"\"\"Renvoie la couleur de la Carte (parmi pique, coeur, carreau, trefle\"\"\"\n def getCouleur(self):\n return ['pique', 'coeur', 'carreau', 'trefle'][self.Couleur - 1]\n\nclass PaquetDeCarte:\n def __init__(self):\n self.contenu = []\n\n\"\"\"Remplit le paquet de cartes\"\"\"\n def remplir(self):\n self.contenu = [Carte(couleur, valeur) for couleur in range(1, 5) for valeur in range(1, 14)]\n\n\"\"\"Renvoie la Carte qui se trouve \u00e0 la position donn\u00e9e\"\"\"\n def getCarteAt(self, pos):\n assert pos in range(0, 52)\n if 0 <= pos < len(self.contenu) :\n return self.contenu[pos]\n
On dispose d\u2019un programme permettant de cr\u00e9er un objet de type `PaquetDeCarte`,\nselon les \u00e9l\u00e9ments indiqu\u00e9s dans le code ci-dessous.\nCompl\u00e9ter ce code aux endroits indiqu\u00e9s par `#A compl\u00e9ter`, puis ajouter des\nassertions dans l\u2019initialiseur de `Carte`, ainsi que dans la m\u00e9thode `getCarteAt()`.\n\n```python linenums='1'\nclass Carte:\n \"\"\"Initialise Couleur (entre 1 a 4), et Valeur (entre 1 a 13)\"\"\"\n def __init__(self, c, v):\n self.Couleur = c\n self.Valeur = v\n\n \"\"\"Renvoie le nom de la Carte As, 2, ... 10, \n Valet, Dame, Roi\"\"\"\n def getNom(self):\n if ( self.Valeur > 1 and self.Valeur < 11):\n return str( self.Valeur)\n elif self.Valeur == 11:\n return \"Valet\"\n elif self.Valeur == 12:\n return \"Dame\"\n elif self.Valeur == 13:\n return \"Roi\"\n else:\n return \"As\"\n\n \"\"\"Renvoie la couleur de la Carte (parmi pique, coeur, carreau, trefle\"\"\"\n def getCouleur(self):\n return ['pique', 'coeur', 'carreau', 'trefle' ][self.Couleur - 1]\n\nclass PaquetDeCarte:\n def __init__(self):\n self.contenu = []\n\n \"\"\"Remplit le paquet de cartes\"\"\"\n def remplir(self):\n ??? = [ ??? for couleur in range(1, ???) for valeur in range( 1, ???)]\n\n \"\"\"Renvoie la Carte qui se trouve a\u00a0 la position donnee\"\"\"\n def getCarteAt(self, pos):\n if 0 <= pos < ??? :\n return ???\n
Exemple : >>> unPaquet = PaquetDeCarte()\n>>> unPaquet.remplir()\n>>> uneCarte = unPaquet.getCarteAt(20)\n>>> print(uneCarte.getNom() + \" de \" + uneCarte.getCouleur())\n 8 de coeur\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-06","title":"\u25b6 Sujet 06","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-061","title":"Exercice 06.1 \u25a1","text":"Exercice 06.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction maxi
qui prend en param\u00e8tre une liste tab
de nombres entiers et renvoie un couple donnant le plus grand \u00e9l\u00e9ment de cette liste, ainsi que l\u2019indice de la premi\u00e8re apparition de ce maximum dans la liste.
Exemple :
>>> maxi([1,5,6,9,1,2,3,7,9,8])\n(9,3)\n
def maxi(tab):\n val_max = tab[0]\n pos_max = 0\n for i in range(len(tab)):\n if tab[i] > val_max:\n val_max = tab[i]\n pos_max = i\n return (val_max, pos_max)\n
\u00c9crire une fonction `maxi` qui prend en param\u00e8tre une liste `tab` de nombres entiers et renvoie un couple donnant le plus grand \u00e9l\u00e9ment de cette liste, ainsi que l\u2019indice de la premi\u00e8re apparition de ce maximum dans la liste.\n\nExemple :\n```python\n>>> maxi([1,5,6,9,1,2,3,7,9,8])\n(9,3)\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-062","title":"Exercice 06.2 \u25a1","text":"Exercice 06.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa fonction recherche
prend en param\u00e8tres deux chaines de caract\u00e8res gene
et seq_adn
et renvoie True
si on retrouve gene
dans seq_adn
et False
sinon. Compl\u00e9ter le code Python ci-dessous pour qu\u2019il impl\u00e9mente la fonction recherche
.
def recherche(gene, seq_adn):\n n = len(seq_adn)\n g = len(gene)\n i = ...\n trouve = False\n while i < ... and trouve == ... :\n j = 0\n while j < g and gene[j] == seq_adn[i+j]:\n ...\n if j == g:\n trouve = True\n ...\n return trouve\n
Exemples :
>>> recherche(\"AATC\", \"GTACAAATCTTGCC\")\nTrue\n>>> recherche(\"AGTC\", \"GTACAAATCTTGCC\")\nFalse\n
def recherche(gene, seq_adn):\n n = len(seq_adn)\n g = len(gene)\n i = 0\n trouve = False\n while i < n-g+1 and trouve == False :\n j = 0\n while j < g and gene[j] == seq_adn[i+j]:\n j += 1\n if j == g:\n trouve = True\n i += 1\n return trouve\n
La fonction `recherche` prend en param\u00e8tres deux chaines de caract\u00e8res `gene` et\n`seq_adn` et renvoie `True` si on retrouve `gene` dans `seq_adn` et `False` sinon.\nCompl\u00e9ter le code Python ci-dessous pour qu\u2019il impl\u00e9mente la fonction `recherche`.\n\n```python linenums='1'\ndef recherche(gene, seq_adn):\n n = len(seq_adn)\n g = len(gene)\n i = ...\n trouve = False\n while i < ... and trouve == ... :\n j = 0\n while j < g and gene[j] == seq_adn[i+j]:\n ...\n if j == g:\n trouve = True\n ...\n return trouve\n
Exemples :
>>> recherche(\"AATC\", \"GTACAAATCTTGCC\")\nTrue\n>>> recherche(\"AGTC\", \"GTACAAATCTTGCC\")\nFalse\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-07","title":"\u25b6 Sujet 07","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-071","title":"Exercice 07.1 \u25a1","text":"Exercice 07.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction conv_bin
qui prend en param\u00e8tre un entier positif n
et renvoie un couple (b,bit)
o\u00f9 :
b
est une liste d'entiers correspondant \u00e0 la repr\u00e9sentation binaire de n
;bit
correspond aux nombre de bits qui constituent b
.Exemple :
>>> conv_bin(9)\n([1,0,0,1],4)\n
Aide :
//
donne le quotient de la division euclidienne : 5//2
donne 2
;%
donne le reste de la division euclidienne :5%2
donne 1
;append
est une m\u00e9thode qui ajoute un \u00e9l\u00e9ment \u00e0 une liste existante : Soit T=[5,2,4]
, alors T.append(10)
ajoute 10
\u00e0 la liste T
. Ainsi, T
devient [5,2,4,10]
.reverse
est une m\u00e9thode qui renverse les \u00e9l\u00e9ments d'une liste. Soit T=[5,2,4,10]
. Apr\u00e8s T.reverse()
, la liste devient [10,4,2,5]
.On remarquera qu\u2019on r\u00e9cup\u00e8re la repr\u00e9sentation binaire d\u2019un entier n
en partant de la gauche en appliquant successivement les instructions :
b = n%2
n = n//2
r\u00e9p\u00e9t\u00e9es autant que n\u00e9cessaire.
def conv_bin(n):\n # cas particulier pour n = 0\n if n == 0:\n return ([0], 1)\n # cas g\u00e9n\u00e9ral\n b = []\n bits = 0\n while n != 0:\n b.append(n % 2)\n bits += 1\n n = n // 2\n b.reverse()\n return (b, bits)\n
\u00c9crire une fonction `conv_bin` qui prend en param\u00e8tre un entier positif `n` et renvoie un\ncouple (`b,bit)` o\u00f9 :\n\n- `b` est une liste d'entiers correspondant \u00e0 la repr\u00e9sentation binaire de `n`;\n- `bit` correspond aux nombre de bits qui constituent `b`.\n\nExemple :\n```python\n>>> conv_bin(9)\n([1,0,0,1],4)\n```\n\nAide :\n\n- l'op\u00e9rateur `//` donne le quotient de la division euclidienne : `5//2` donne `2` ;\n- l'op\u00e9rateur `%` donne le reste de la division euclidienne :` 5%2` donne `1` ;\n- `append` est une m\u00e9thode qui ajoute un \u00e9l\u00e9ment \u00e0 une liste existante :\nSoit `T=[5,2,4]`, alors `T.append(10)` ajoute `10` \u00e0 la liste `T`. Ainsi, `T` devient\n`[5,2,4,10]`.\n- `reverse` est une m\u00e9thode qui renverse les \u00e9l\u00e9ments d'une liste.\nSoit `T=[5,2,4,10]`. Apr\u00e8s `T.reverse()`, la liste devient `[10,4,2,5]`.\n\nOn remarquera qu\u2019on r\u00e9cup\u00e8re la repr\u00e9sentation binaire d\u2019un entier `n` en partant de la gauche en appliquant successivement les instructions :\n\n`b = n%2`\n\n`n = n//2`\n\nr\u00e9p\u00e9t\u00e9es autant que n\u00e9cessaire.\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-072","title":"Exercice 07.2 \u25a1","text":"Exercice 07.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa fonction tri_bulles
prend en param\u00e8tre une liste T
d\u2019entiers non tri\u00e9s et renvoie la liste tri\u00e9e par ordre croissant. Compl\u00e9ter le code Python ci-dessous qui impl\u00e9mente la fonction tri_bulles
.
def tri_bulles(T):\n n = len(T)\n for i in range(...,...,-1):\n for j in range(i):\n if T[j] > T[...]:\n ... = T[j]\n T[j] = T[...]\n T[j+1] = temp\n return T\n
def tri_bulles(T):\n n = len(T)\n for i in range(n-1,0,-1):\n for j in range(i):\n if T[j] > T[j+1]:\n temp = T[j]\n T[j] = T[j+1]\n T[j+1] = temp\n return T\n
La fonction `tri_bulles` prend en param\u00e8tre une liste `T` d\u2019entiers non tri\u00e9s et renvoie la liste tri\u00e9e par ordre croissant.\nCompl\u00e9ter le code Python ci-dessous qui impl\u00e9mente la fonction `tri_bulles`.\n\n```python linenums='1'\ndef tri_bulles(T):\n n = len(T)\n for i in range(...,...,-1):\n for j in range(i):\n if T[j] > T[...]:\n ... = T[j]\n T[j] = T[...]\n T[j+1] = temp\n return T\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-08","title":"\u25b6 Sujet 08","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-081","title":"Exercice 08.1 \u25a1","text":"Exercice 08.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche
qui prend en param\u00e8tres elt
un nombre entier et tab
un tableau de nombres entiers, et qui renvoie l\u2019indice de la premi\u00e8re occurrence de elt
dans tab
si elt
est dans tab
et -1
sinon.
Exemples :
>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(50, [1, 50, 1])\n1\n>>> recherche(15, [8, 9, 10, 15])\n3\n
def recherche(elt, tab):\n for i in range(len(tab)):\n if tab[i] == elt:\n return i \n return -1 \n
\u00c9crire une fonction `recherche` qui prend en param\u00e8tres `elt` un nombre entier et `tab`\nun tableau de nombres entiers, et qui renvoie l\u2019indice de la premi\u00e8re occurrence de `elt`\ndans `tab` si `elt` est dans `tab` et `-1` sinon.\n\nExemples :\n```python\n>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(50, [1, 50, 1])\n1\n>>> recherche(15, [8, 9, 10, 15])\n3\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-082","title":"Exercice 08.2 \u25a1","text":"Exercice 08.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re la fonction insere
ci-dessous qui prend en argument un entier a
et un tableau tab
d'entiers tri\u00e9s par ordre croissant. Cette fonction ins\u00e8re la valeur a
dans le tableau et renvoie le nouveau tableau. Les tableaux seront repr\u00e9sent\u00e9s sous la forme de listes python.
def insere(a, tab):\n l = list(tab) #l contient les m\u00eames \u00e9l\u00e9ments que tab\n l.append(a)\n i = ...\n while a < ... and i >= 0:\n l[i+1] = ...\n l[i] = a\n i = ...\n return l\n
Compl\u00e9ter la fonction insere
ci-dessus.
Exemples :
>>> insere(3,[1,2,4,5])\n[1, 2, 3, 4, 5]\n>>> insere(10,[1,2,7,12,14,25])\n[1, 2, 7, 10, 12, 14, 25]\n>>> insere(1,[2,3,4])\n[1, 2, 3, 4]\n
def insere(a, tab):\n l = list(tab) #l contient les m\u00eames \u00e9l\u00e9ments que tab\n l.append(a)\n i = len(l) - 2\n while a < l[i] and i >= 0:\n l[i+1] = l[i]\n l[i] = a\n i = i - 1\n return l\n
On consid\u00e8re la fonction `insere` ci-dessous qui prend en argument un entier `a` et un\ntableau `tab` d'entiers tri\u00e9s par ordre croissant. Cette fonction ins\u00e8re la valeur `a` dans le\ntableau et renvoie le nouveau tableau. Les tableaux seront repr\u00e9sent\u00e9s sous la forme de\nlistes python.\n\n\n```python linenums='1'\ndef insere(a, tab):\n l = list(tab) #l contient les m\u00eames \u00e9l\u00e9ments que tab\n l.append(a)\n i = ...\n while a < ... and i >= 0:\n l[i+1] = ...\n l[i] = a\n i = ...\n return l\n
Compl\u00e9ter la fonction insere
ci-dessus.
Exemples :
>>> insere(3,[1,2,4,5])\n[1, 2, 3, 4, 5]\n>>> insere(10,[1,2,7,12,14,25])\n[1, 2, 7, 10, 12, 14, 25]\n>>> insere(1,[2,3,4])\n[1, 2, 3, 4]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-09","title":"\u25b6 Sujet 09","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-091","title":"Exercice 09.1 \u25a1","text":"Exercice 09.1
\u00c9nonc\u00e9CorrectionSource MarkdownSoit un nombre entier sup\u00e9rieur ou \u00e9gal \u00e0 1 :
Puis on recommence ces \u00e9tapes avec le nombre entier obtenu, jusqu\u2019\u00e0 ce que l\u2019on obtienne la valeur 1.
On d\u00e9finit ainsi la suite \\((U_n)\\) par :
On admet que, quel que soit l'entier k
choisi au d\u00e9part, la suite finit toujours sur la valeur 1.
\u00c9crire une fonction calcul
prenant en param\u00e8tres un entier k
strictement positif et qui renvoie la liste des valeurs de la suite, en partant de k
et jusqu'\u00e0 atteindre 1.
Exemple :
>>> calcul(7)\n[7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]\n
def calcul(k):\n valeurs = []\n n = k\n valeurs.append(n)\n while n != 1:\n if n % 2 == 0:\n n = n // 2\n else:\n n = 3*n + 1\n valeurs.append(n)\n return valeurs\n
Soit un nombre entier sup\u00e9rieur ou \u00e9gal \u00e0 1 :\n\n- s'il est pair, on le divise par 2 ;\n- s\u2019il est impair, on le multiplie par 3 et on ajoute 1.\n\nPuis on recommence ces \u00e9tapes avec le nombre entier obtenu, jusqu\u2019\u00e0 ce que l\u2019on\nobtienne la valeur 1.\n\nOn d\u00e9finit ainsi la suite $(U_n)$ par :\n\n- $U_0=k$, o\u00f9 $k$ est un entier choisi initialement;\n- $U_{n+1} = \\dfrac{U_n}{2}$ si $U_n$ est pair;\n- $U_{n+1} = 3 \\times U_n + 1$ si $U_n$ est impair.\n\n**On admet que, quel que soit l'entier ```k``` choisi au d\u00e9part, la suite finit toujours sur la valeur 1.**\n\n\u00c9crire une fonction ```calcul``` prenant en param\u00e8tres un entier ```k``` strictement positif et qui renvoie la liste des valeurs de la suite, en partant de ```k``` et jusqu'\u00e0 atteindre 1.\n\nExemple :\n```python\n>>> calcul(7)\n[7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-092","title":"Exercice 09.2 \u25a1","text":"Exercice 09.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn affecte \u00e0 chaque lettre de l'alphabet un code selon le tableau ci-dessous :
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26Pour un mot donn\u00e9, on d\u00e9termine d\u2019une part son code alphab\u00e9tique concat\u00e9n\u00e9, obtenu par la juxtaposition des codes de chacun de ses caract\u00e8res, et d\u2019autre part, son code additionn\u00e9, qui est la somme des codes de chacun de ses caract\u00e8res.
Par ailleurs, on dit que ce mot est \u00ab parfait \u00bb si le code additionn\u00e9 divise le code concat\u00e9n\u00e9.
Exemples :
Pour le mot \"PAUL\"
, le code concat\u00e9n\u00e9 est la cha\u00eene '1612112'
, soit l\u2019entier 1 612 112. Son code additionn\u00e9 est l\u2019entier 50 car 16 + 1 + 21 + 12 = 50. 50 ne divise pas l\u2019entier 1 612 112 ; par cons\u00e9quent, le mot \"PAUL\"
n\u2019est pas parfait.
Pour le mot \"ALAIN\"
, le code concat\u00e9n\u00e9 est la cha\u00eene '1121914'
, soit l\u2019entier 1 121 914. Le code additionn\u00e9 est l\u2019entier 37 car 1 + 12 + 1 + 9 + 14 = 37. 37 divise l\u2019entier 1 121 914 ; par cons\u00e9quent, le mot \"ALAIN\"
est parfait.
Compl\u00e9ter la fonction est_parfait
ci-dessous qui prend comme argument une cha\u00eene de caract\u00e8res mot
(en lettres majuscules) et qui renvoie le code alphab\u00e9tique concat\u00e9n\u00e9, le code additionn\u00e9 de mot
, ainsi qu\u2019un bool\u00e9en qui indique si mot
est parfait ou pas.
dico = {\"A\":1, \"B\":2, \"C\":3, \"D\":4, \"E\":5, \"F\":6, \"G\":7, \\\n\"H\":8, \"I\":9, \"J\":10, \"K\":11, \"L\":12, \"M\":13, \\\n\"N\":14, \"O\":15, \"P\":16, \"Q\":17, \"R\":18, \"S\":19, \\\n\"T\":20, \"U\":21,\"V\":22, \"W\":23, \"X\":24, \"Y\":25, \"Z\":26}\n\ndef est_parfait(mot) :\n #mot est une cha\u00eene de caract\u00e8res (en lettres majuscules)\n code_c = \"\"\n code_a = ???\n for c in mot :\n code_c = code_c + ???\n code_a = ???\n code_c = int(code_c)\n if ??? :\n mot_est_parfait = True\n else :\n mot_est_parfait = False\n return [code_a, code_c, mot_est_parfait]\n
Exemples :
>>> est_parfait(\"PAUL\")\n[50, 1612112, False]\n>>> est_parfait(\"ALAIN\")\n[37, 1121914, True]\n
dico = {\"A\":1, \"B\":2, \"C\":3, \"D\":4, \"E\":5, \"F\":6, \"G\":7, \\\n\"H\":8, \"I\":9, \"J\":10, \"K\":11, \"L\":12, \"M\":13, \\\n\"N\":14, \"O\":15, \"P\":16, \"Q\":17, \"R\":18, \"S\":19, \\\n\"T\":20, \"U\":21,\"V\":22, \"W\":23, \"X\":24, \"Y\":25, \"Z\":26}\n\ndef est_parfait(mot) :\n #mot est une cha\u00eene de caract\u00e8res (en lettres majuscules)\n code_c = \"\"\n code_a = 0\n for c in mot :\n code_c = code_c + str(dico[c])\n code_a = code_a + dico[c]\n code_c = int(code_c)\n if code_c % code_a == 0:\n mot_est_parfait = True\n else :\n mot_est_parfait = False\n return [code_a, code_c, mot_est_parfait]\n
On affecte \u00e0 chaque lettre de l'alphabet un code selon le tableau ci-dessous :\n\n| A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z | \n|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|\n| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | \n\n\nPour un mot donn\u00e9, on d\u00e9termine d\u2019une part son *code alphab\u00e9tique concat\u00e9n\u00e9*, obtenu\npar la juxtaposition des codes de chacun de ses caract\u00e8res, et d\u2019autre part, *son code\nadditionn\u00e9*, qui est la somme des codes de chacun de ses caract\u00e8res.\n\nPar ailleurs, on dit que ce mot est \u00ab *parfait* \u00bb si le code additionn\u00e9 divise le code concat\u00e9n\u00e9.\n\nExemples :\n\n- Pour le mot `\"PAUL\"`, le code concat\u00e9n\u00e9 est la cha\u00eene `'1612112'`, soit l\u2019entier 1 612 112.\nSon code additionn\u00e9 est l\u2019entier 50 car 16 + 1 + 21 + 12 = 50.\n50 ne divise pas l\u2019entier 1 612 112 ; par cons\u00e9quent, le mot `\"PAUL\"` n\u2019est pas\nparfait.\n\n- Pour le mot `\"ALAIN\"`, le code concat\u00e9n\u00e9 est la cha\u00eene `'1121914'`, soit l\u2019entier\n1 121 914. Le code additionn\u00e9 est l\u2019entier 37 car 1 + 12 + 1 + 9 + 14 = 37.\n37 divise l\u2019entier 1 121 914 ; par cons\u00e9quent, le mot `\"ALAIN\"` est parfait.\n\n\nCompl\u00e9ter la fonction `est_parfait` ci-dessous qui prend comme argument une cha\u00eene\nde caract\u00e8res `mot` (en lettres majuscules) et qui renvoie le code alphab\u00e9tique concat\u00e9n\u00e9,\nle code additionn\u00e9 de `mot`, ainsi qu\u2019un bool\u00e9en qui indique si `mot` est parfait ou pas.\n\n```python linenums='1'\ndico = {\"A\":1, \"B\":2, \"C\":3, \"D\":4, \"E\":5, \"F\":6, \"G\":7, \\\n\"H\":8, \"I\":9, \"J\":10, \"K\":11, \"L\":12, \"M\":13, \\\n\"N\":14, \"O\":15, \"P\":16, \"Q\":17, \"R\":18, \"S\":19, \\\n\"T\":20, \"U\":21,\"V\":22, \"W\":23, \"X\":24, \"Y\":25, \"Z\":26}\n\ndef est_parfait(mot) :\n #mot est une cha\u00eene de caract\u00e8res (en lettres majuscules)\n code_c = \"\"\n code_a = ???\n for c in mot :\n code_c = code_c + ???\n code_a = ???\n code_c = int(code_c)\n if ??? :\n mot_est_parfait = True\n else :\n mot_est_parfait = False\n return [code_a, code_c, mot_est_parfait]\n
Exemples :
>>> est_parfait(\"PAUL\")\n[50, 1612112, False]\n>>> est_parfait(\"ALAIN\")\n[37, 1121914, True]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-10","title":"\u25b6 Sujet 10","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-101","title":"Exercice 10.1 \u25a1","text":"Exercice 10.1
\u00c9nonc\u00e9CorrectionSource MarkdownL\u2019occurrence d\u2019un caract\u00e8re dans un phrase est le nombre de fois o\u00f9 ce caract\u00e8re est pr\u00e9sent.
Exemples :
On cherche les occurrences des caract\u00e8res dans une phrase. On souhaite stocker ces occurrences dans un dictionnaire dont les clefs seraient les caract\u00e8res de la phrase et les valeurs l\u2019occurrence de ces caract\u00e8res.
Par exemple : avec la phrase 'Hello world !' le dictionnaire est le suivant :
{'H': 1,'e': 1,'l': 3,'o': 2,' ': 2,'w': 1,'r': 1,'d': 1,'!': 1}
\u00c9crire une fonction occurrence_lettres
prenant comme param\u00e8tre une variable phrase
de type str
. Cette fonction doit renvoyer un dictionnaire de type constitu\u00e9 des occurrences des caract\u00e8res pr\u00e9sents dans la phrase.
def occurrence_lettres(phrase):\n occ = {}\n for caractere in phrase:\n if caractere in occ:\n occ[caractere] += 1\n else:\n occ[caractere] = 1\n return occ\n
L\u2019occurrence d\u2019un caract\u00e8re dans un phrase est le nombre de fois o\u00f9 ce caract\u00e8re est\npr\u00e9sent.\n\nExemples :\n\n- l\u2019occurrence du caract\u00e8re \u2018o\u2019 dans \u2018bonjour\u2019 est 2 ;\n- l\u2019occurrence du caract\u00e8re \u2018b\u2019 dans \u2018B\u00e9b\u00e9\u2019 est 1 ;\n- l\u2019occurrence du caract\u00e8re \u2018B\u2019 dans \u2018B\u00e9b\u00e9\u2019 est 1 ;\n- l\u2019occurrence du caract\u00e8re \u2018 \u2018 dans \u2018Hello world !\u2019 est 2.\n\nOn cherche les occurrences des caract\u00e8res dans une phrase. On souhaite stocker ces\noccurrences dans un dictionnaire dont les clefs seraient les caract\u00e8res de la phrase et\nles valeurs l\u2019occurrence de ces caract\u00e8res.\n\nPar exemple : avec la phrase 'Hello world !' le dictionnaire est le suivant :\n\n`{'H': 1,'e': 1,'l': 3,'o': 2,' ': 2,'w': 1,'r': 1,'d': 1,'!': 1}`\n\n\u00c9crire une fonction `occurrence_lettres` prenant comme param\u00e8tre une variable\n`phrase` de type `str`. Cette fonction doit renvoyer un dictionnaire de type constitu\u00e9 des\noccurrences des caract\u00e8res pr\u00e9sents dans la phrase.\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-102","title":"Exercice 10.2 \u25a1","text":"Exercice 10.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa fonction fusion
prend deux listes L1
, L2
d\u2019entiers tri\u00e9es par ordre croissant et les fusionne en une liste tri\u00e9e L12
qu\u2019elle renvoie.
Le code Python de la fonction est
def fusion(L1,L2):\n n1 = len(L1)\n n2 = len(L2)\n L12 = [0]*(n1+n2)\n i1 = 0\n i2 = 0\n i = 0\n while i1 < n1 and ... :\n if L1[i1] < L2[i2]:\n L12[i] = ...\n i1 = ...\n else:\n L12[i] = L2[i2]\n i2 = ...\n i += 1\n while i1 < n1:\n L12[i] = ...\n i1 = i1 + 1\n i = ...\n while i2 < n2:\n L12[i] = ...\n i2 = i2 + 1\n i = ...\n return L12\n
Compl\u00e9ter le code.
Exemple :
>>> fusion([1,6,10],[0,7,8,9])\n[0, 1, 6, 7, 8, 9, 10]\n
def fusion(L1,L2):\n n1 = len(L1)\n n2 = len(L2)\n L12 = [0]*(n1+n2)\n i1 = 0\n i2 = 0\n i = 0\n while i1 < n1 and i2 < n2 :\n if L1[i1] < L2[i2]:\n L12[i] = L1[i1]\n i1 = i1 + 1\n else:\n L12[i] = L2[i2]\n i2 = i2 + 1\n i += 1\n while i1 < n1:\n L12[i] = L1[i1]\n i1 = i1 + 1\n i = i + 1\n while i2 < n2:\n L12[i] = L2[i2]\n i2 = i2 + 1\n i = i + 1\n return L12\n
La fonction `fusion` prend deux listes `L1`, `L2` d\u2019entiers tri\u00e9es par ordre croissant et les\nfusionne en une liste tri\u00e9e `L12` qu\u2019elle renvoie.\n\nLe code Python de la fonction est\n\n```python linenums='1'\ndef fusion(L1,L2):\n n1 = len(L1)\n n2 = len(L2)\n L12 = [0]*(n1+n2)\n i1 = 0\n i2 = 0\n i = 0\n while i1 < n1 and ... :\n if L1[i1] < L2[i2]:\n L12[i] = ...\n i1 = ...\n else:\n L12[i] = L2[i2]\n i2 = ...\n i += 1\n while i1 < n1:\n L12[i] = ...\n i1 = i1 + 1\n i = ...\n while i2 < n2:\n L12[i] = ...\n i2 = i2 + 1\n i = ...\n return L12\n
Compl\u00e9ter le code.
Exemple :
>>> fusion([1,6,10],[0,7,8,9])\n[0, 1, 6, 7, 8, 9, 10]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-11","title":"\u25b6 Sujet 11","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-111","title":"Exercice 11.1 \u25a1","text":"Exercice 11.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche
qui prend en param\u00e8tres un tableau tab
de nombres entiers tri\u00e9s par ordre croissant et un nombre entier n
, et qui effectue une recherche dichotomique du nombre entier n
dans le tableau non vide tab
. Cette fonction doit renvoyer un indice correspondant au nombre cherch\u00e9 s\u2019il est dans le tableau, -1
sinon.
Exemples :
>>> recherche([2, 3, 4, 5, 6], 5)\n3\n>>> recherche([2, 3, 4, 6, 7], 5)\n-1\n
def recherche(tab, n):\n ind_debut = 0\n ind_fin = len(tab) - 1\n while ind_debut <= ind_fin:\n ind_milieu = (ind_debut + ind_fin) // 2\n if tab[ind_milieu] == n:\n return ind_milieu\n elif tab[ind_milieu] < n:\n ind_debut = ind_milieu + 1\n else:\n ind_fin = ind_milieu - 1\n return -1\n
\u00c9crire une fonction `recherche` qui prend en param\u00e8tres un tableau `tab` de nombres\nentiers tri\u00e9s par ordre croissant et un nombre entier `n`, et qui effectue une recherche\ndichotomique du nombre entier `n` dans le tableau non vide `tab`.\nCette fonction doit renvoyer un indice correspondant au nombre cherch\u00e9 s\u2019il est dans le\ntableau, `-1` sinon.\n\nExemples :\n```python\n>>> recherche([2, 3, 4, 5, 6], 5)\n3\n>>> recherche([2, 3, 4, 6, 7], 5)\n-1\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-112","title":"Exercice 11.2 \u25a1","text":"Exercice 11.2
\u00c9nonc\u00e9CorrectionSources MarkdownLe codage de C\u00e9sar transforme un message en changeant chaque lettre en la d\u00e9calant dans l\u2019alphabet. Par exemple, avec un d\u00e9calage de 3, le A se transforme en D, le B en E, ..., le X en A, le Y en B et le Z en C. Les autres caract\u00e8res (\u2018!\u2019,\u2019 ?\u2019\u2026) ne sont pas cod\u00e9s.
La fonction position_alphabet
ci-dessous prend en param\u00e8tre un caract\u00e8re lettre
et renvoie la position de lettre
dans la cha\u00eene de caract\u00e8res ALPHABET
s\u2019il s\u2019y trouve et -1
sinon. La fonction cesar
prend en param\u00e8tre une cha\u00eene de caract\u00e8res message
et un nombre entier decalage
et renvoie le nouveau message cod\u00e9 avec le codage de C\u00e9sar utilisant le d\u00e9calage decalage
.
ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\ndef position_alphabet(lettre):\n return ALPHABET.find(lettre)\n\ndef cesar(message, decalage):\n resultat = ''\n for ... in message:\n if lettre in ALPHABET:\n indice = ( ... ) % 26\n resultat = resultat + ALPHABET[indice]\n else:\n resultat = ...\n return resultat\n
Compl\u00e9ter la fonction cesar
.
Exemples :
>>> cesar('BONJOUR A TOUS. VIVE LA MATIERE NSI !',4)\n'FSRNSYV E XSYW. ZMZI PE QEXMIVI RWM !'\n>>> cesar('GTSOTZW F YTZX. ANAJ QF RFYNJWJ SXN !',-5)\n'BONJOUR A TOUS. VIVE LA MATIERE NSI !'\n
ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\ndef position_alphabet(lettre):\n return ALPHABET.find(lettre)\n\ndef cesar(message, decalage):\n resultat = ''\n for lettre in message:\n if lettre in ALPHABET:\n indice = (position_alphabet(lettre) + decalage) % 26\n resultat = resultat + ALPHABET[indice]\n else:\n resultat = resultat + lettre\n return resultat\n
Le codage de C\u00e9sar transforme un message en changeant chaque lettre en la d\u00e9calant\ndans l\u2019alphabet.\nPar exemple, avec un d\u00e9calage de 3, le A se transforme en D, le B en E, ..., le X en A,\nle Y en B et le Z en C. Les autres caract\u00e8res (\u2018!\u2019,\u2019 ?\u2019\u2026) ne sont pas cod\u00e9s.\n\nLa fonction `position_alphabet` ci-dessous prend en param\u00e8tre un caract\u00e8re `lettre`\net renvoie la position de `lettre` dans la cha\u00eene de caract\u00e8res `ALPHABET` s\u2019il s\u2019y trouve\net `-1` sinon.\nLa fonction `cesar` prend en param\u00e8tre une cha\u00eene de caract\u00e8res `message` et un nombre\nentier `decalage` et renvoie le nouveau message cod\u00e9 avec le codage de C\u00e9sar utilisant\nle d\u00e9calage `decalage`.\n\n```python linenums='1'\nALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\ndef position_alphabet(lettre):\n return ALPHABET.find(lettre)\n\ndef cesar(message, decalage):\n resultat = ''\n for ... in message:\n if lettre in ALPHABET:\n indice = ( ... ) % 26\n resultat = resultat + ALPHABET[indice]\n else:\n resultat = ...\n return resultat\n
Compl\u00e9ter la fonction cesar
.
Exemples :
>>> cesar('BONJOUR A TOUS. VIVE LA MATIERE NSI !',4)\n'FSRNSYV E XSYW. ZMZI PE QEXMIVI RWM !'\n>>> cesar('GTSOTZW F YTZX. ANAJ QF RFYNJWJ SXN !',-5)\n'BONJOUR A TOUS. VIVE LA MATIERE NSI !'\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-12","title":"\u25b6 Sujet 12","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-121","title":"Exercice 12.1 \u25a1","text":"Exercice 12.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction moyenne
prenant en param\u00e8tre un tableau d'entiers tab
(type list
) qui renvoie la moyenne de ses \u00e9l\u00e9ments si le tableau est non vide et affiche 'erreur' si le tableau est vide.
Exemples :
>>> moyenne([5,3,8])\n5.333333333333333\n>>> moyenne([1,2,3,4,5,6,7,8,9,10])\n5.5\n>>> moyenne([])\n'erreur'\n
L'\u00e9nonc\u00e9 n'est pas tr\u00e8s clair quand il dit \u00abd'afficher 'erreur'\u00bb (ce qui suppose un print
et non un return
). Nous choississons donc dans ce cas de renvoyer None
.
def moyenne(tab):\n if tab == []:\n print('erreur')\n return None\n else:\n somme = 0\n for elt in tab:\n somme += elt\n return somme / len(tab)\n
Programmer la fonction ```moyenne``` prenant en param\u00e8tre un tableau d'entiers ```tab``` (type\n`list`) qui renvoie la moyenne de ses \u00e9l\u00e9ments si le tableau est non vide et affiche\n'erreur' si le tableau est vide.\n\nExemples :\n```python\n>>> moyenne([5,3,8])\n5.333333333333333\n>>> moyenne([1,2,3,4,5,6,7,8,9,10])\n5.5\n>>> moyenne([])\n'erreur'\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-122","title":"Exercice 12.2 \u25a1","text":"Exercice 12.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re un tableau d'entiers tab
(type list
dont les \u00e9l\u00e9ments sont des 0
ou des 1
). On se propose de trier ce tableau selon l'algorithme suivant : \u00e0 chaque \u00e9tape du tri,le tableau est constitu\u00e9 de trois zones cons\u00e9cutives, la premi\u00e8re ne contenant que des 0
, la seconde n'\u00e9tant pas tri\u00e9e et la derni\u00e8re ne contenant que des 1
.
Zone de 0Zone non tri\u00e9eZone de 1
Tant que la zone non tri\u00e9e n'est pas r\u00e9duite \u00e0 un seul \u00e9l\u00e9ment, on regarde son premier \u00e9l\u00e9ment :
Dans tous les cas, la longueur de la zone non tri\u00e9e diminue de 1.
Recopier sous Python en la compl\u00e9tant la fonction tri
suivante :
def tri(tab):\n #i est le premier indice de la zone non triee, j le dernier indice.\n #Au debut, la zone non triee est le tableau entier.\n i = ...\n j = ...\n while i != j :\n if tab[i]== 0:\n i = ...\n else :\n valeur = tab[j]\n tab[j] = ...\n ...\n j = ...\n ...\n
Exemple :
>>> tri([0,1,0,1,0,1,0,1,0])\n[0, 0, 0, 0, 0, 1, 1, 1, 1] \n
def tri(tab):\n #i est le premier indice de la zone non triee, j le dernier indice.\n #Au debut, la zone non triee est le tableau entier.\n i = 0\n j = len(tab) - 1\n while i != j :\n if tab[i]== 0:\n i = i + 1\n else :\n valeur = tab[j]\n tab[j] = tab[i]\n tab[i] = valeur\n j = j - 1\n return tab\n
On consid\u00e8re un tableau d'entiers `tab` (type `list` dont les \u00e9l\u00e9ments sont des `0` ou des `1`). On se propose de trier ce tableau selon l'algorithme suivant : \u00e0 chaque \u00e9tape du tri,le tableau est constitu\u00e9 de trois zones cons\u00e9cutives, la premi\u00e8re ne contenant que des `0`,\nla seconde n'\u00e9tant pas tri\u00e9e et la derni\u00e8re ne contenant que des `1`.\n\n<table>\n<tr>\n<td>Zone de 0</td><td>Zone non tri\u00e9e</td><td>Zone de 1</td>\n</tr>\n</table>\n\nTant que la zone non tri\u00e9e n'est pas r\u00e9duite \u00e0 un seul \u00e9l\u00e9ment, on regarde son premier\n\u00e9l\u00e9ment :\n\n- si cet \u00e9l\u00e9ment vaut 0, on consid\u00e8re qu'il appartient d\u00e9sormais \u00e0 la zone ne contenant\nque des 0 ;\n- si cet \u00e9l\u00e9ment vaut 1, il est \u00e9chang\u00e9 avec le dernier \u00e9l\u00e9ment de la zone non tri\u00e9e et on\nconsid\u00e8re alors qu\u2019il appartient \u00e0 la zone ne contenant que des 1.\n\nDans tous les cas, la longueur de la zone non tri\u00e9e diminue de 1.\n\nRecopier sous Python en la compl\u00e9tant la fonction `tri` suivante :\n\n```python linenums='1'\ndef tri(tab):\n #i est le premier indice de la zone non triee, j le dernier indice.\n #Au debut, la zone non triee est le tableau entier.\n i = ...\n j = ...\n while i != j :\n if tab[i]== 0:\n i = ...\n else :\n valeur = tab[j]\n tab[j] = ...\n ...\n j = ...\n ...\n
Exemple :
>>> tri([0,1,0,1,0,1,0,1,0])\n[0, 0, 0, 0, 0, 1, 1, 1, 1] \n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-13","title":"\u25b6 Sujet 13","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-131","title":"Exercice 13.1 \u25a1","text":"Exercice 13.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn s\u2019int\u00e9resse au probl\u00e8me du rendu de monnaie. On suppose qu\u2019on dispose d\u2019un nombre infini de billets de 5 euros, de pi\u00e8ces de 2 euros et de pi\u00e8ces de 1 euro. Le but est d\u2019\u00e9crire une fonction nomm\u00e9e rendu
dont le param\u00e8tre est un entier positif non nul somme_a_rendre
et qui retourne une liste de trois entiers n1
, n2
et n3
qui correspondent aux nombres de billets de 5 euros (n1
) de pi\u00e8ces de 2 euros (n2
) et de pi\u00e8ces de 1 euro (n3
) \u00e0 rendre afin que le total rendu soit \u00e9gal \u00e0 somme_a_rendre
.
On utilisera un algorithme glouton : on commencera par rendre le nombre maximal de billets de 5 euros, puis celui des pi\u00e8ces de 2 euros et enfin celui des pi\u00e8ces de 1 euros.
Exemples :
>>> rendu(13)\n[2,1,1]\n>>> rendu(64)\n[12,2,0]\n>>> rendu(89)\n[17,2,0]\n
def rendu(somme_a_rendre):\n pieces = [5, 2, 1]\n retour = [0, 0, 0]\n reste_a_rendre = somme_a_rendre\n for i in range(3):\n retour[i] = reste_a_rendre // pieces[i]\n reste_a_rendre = reste_a_rendre % pieces[i]\n return retour\n
On s\u2019int\u00e9resse au probl\u00e8me du rendu de monnaie. On suppose qu\u2019on dispose d\u2019un\nnombre infini de billets de 5 euros, de pi\u00e8ces de 2 euros et de pi\u00e8ces de 1 euro.\nLe but est d\u2019\u00e9crire une fonction nomm\u00e9e `rendu` dont le param\u00e8tre est un entier positif non\nnul `somme_a_rendre` et qui retourne une liste de trois entiers `n1`, `n2` et `n3` qui\ncorrespondent aux nombres de billets de 5 euros (`n1`) de pi\u00e8ces de 2 euros (`n2`) et de\npi\u00e8ces de 1 euro (`n3`) \u00e0 rendre afin que le total rendu soit \u00e9gal \u00e0 `somme_a_rendre`.\n\nOn utilisera un algorithme glouton : on commencera par rendre le nombre maximal de\nbillets de 5 euros, puis celui des pi\u00e8ces de 2 euros et enfin celui des pi\u00e8ces de 1 euros.\n\nExemples :\n```python\n>>> rendu(13)\n[2,1,1]\n>>> rendu(64)\n[12,2,0]\n>>> rendu(89)\n[17,2,0]\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-132","title":"Exercice 13.2 \u25a1","text":"Exercice 13.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn veut \u00e9crire une classe pour g\u00e9rer une file \u00e0 l\u2019aide d\u2019une liste cha\u00een\u00e9e. On dispose d\u2019une classe Maillon
permettant la cr\u00e9ation d\u2019un maillon de la cha\u00eene, celui-ci \u00e9tant constitu\u00e9 d\u2019une valeur et d\u2019une r\u00e9f\u00e9rence au maillon suivant de la cha\u00eene :
class Maillon :\n def __init__(self,v) :\n self.valeur = v\n self.suivant = None\n
Compl\u00e9ter la classe File suivante
o\u00f9 l\u2019attribut dernier_file
contient le maillon correspondant \u00e0 l\u2019\u00e9l\u00e9ment arriv\u00e9 en dernier dans la file : class File :\n def __init__(self) :\n self.dernier_file = None\n\n def enfile(self,element) :\n nouveau_maillon = Maillon(...)\n nouveau_maillon.suivant = self.dernier_file\n self.dernier_file = ...\n\n def est_vide(self) :\n return self.dernier_file == None\n\n def affiche(self) :\n maillon = self.dernier_file\n while maillon != ... :\n print(maillon.valeur)\n maillon = ...\n\n def defile(self) :\n if not self.est_vide() :\n if self.dernier_file.suivant == None :\n resultat = self.dernier_file.valeur\n self.dernier_file = None\n return resultat\n maillon = ...\n while maillon.suivant.suivant != None :\n maillon = maillon.suivant\n resultat = ...\n maillon.suivant = None\n return resultat\n return None\n
On pourra tester le fonctionnement de la classe en utilisant les commandes suivantes dans la console Python : >>> F = File()\n>>> F.est_vide()\nTrue\n>>> F.enfile(2)\n>>> F.affiche()\n2\n>>> F.est_vide()\nFalse\n>>> F.enfile(5)\n>>> F.enfile(7)\n>>> F.affiche()\n7\n5\n2\n>>> F.defile()\n2\n>>> F.defile()\n5\n>>> F.affiche()\n7\n
class Maillon :\n def __init__(self,v) :\n self.valeur = v\n self.suivant = None\n\nclass File :\n def __init__(self) :\n self.dernier_file = None\n\n def enfile(self,element) :\n nouveau_maillon = Maillon(element)\n nouveau_maillon.suivant = self.dernier_file\n self.dernier_file = nouveau_maillon\n\n def est_vide(self) :\n return self.dernier_file == None\n\n def affiche(self) :\n maillon = self.dernier_file\n while maillon != None :\n print(maillon.valeur)\n maillon = maillon.suivant\n\n def defile(self) :\n if not self.est_vide() :\n if self.dernier_file.suivant == None :\n resultat = self.dernier_file.valeur\n self.dernier_file = None\n return resultat\n maillon = self.dernier_file\n while maillon.suivant.suivant != None :\n maillon = maillon.suivant\n resultat = maillon.suivant.valeur\n maillon.suivant = None\n return resultat\n return None\n
On veut \u00e9crire une classe pour g\u00e9rer une file \u00e0 l\u2019aide d\u2019une liste cha\u00een\u00e9e. On dispose d\u2019une\nclasse ```Maillon``` permettant la cr\u00e9ation d\u2019un maillon de la cha\u00eene, celui-ci \u00e9tant constitu\u00e9\nd\u2019une valeur et d\u2019une r\u00e9f\u00e9rence au maillon suivant de la cha\u00eene :\n\n```python linenums='1'\nclass Maillon :\n def __init__(self,v) :\n self.valeur = v\n self.suivant = None\n
Compl\u00e9ter la classe File suivante
o\u00f9 l\u2019attribut dernier_file
contient le maillon correspondant \u00e0 l\u2019\u00e9l\u00e9ment arriv\u00e9 en dernier dans la file : class File :\n def __init__(self) :\n self.dernier_file = None\n\n def enfile(self,element) :\n nouveau_maillon = Maillon(...)\n nouveau_maillon.suivant = self.dernier_file\n self.dernier_file = ...\n\n def est_vide(self) :\n return self.dernier_file == None\n\n def affiche(self) :\n maillon = self.dernier_file\n while maillon != ... :\n print(maillon.valeur)\n maillon = ...\n\n def defile(self) :\n if not self.est_vide() :\n if self.dernier_file.suivant == None :\n resultat = self.dernier_file.valeur\n self.dernier_file = None\n return resultat\n maillon = ...\n while maillon.suivant.suivant != None :\n maillon = maillon.suivant\n resultat = ...\n maillon.suivant = None\n return resultat\n return None\n
On pourra tester le fonctionnement de la classe en utilisant les commandes suivantes dans la console Python : >>> F = File()\n>>> F.est_vide()\nTrue\n>>> F.enfile(2)\n>>> F.affiche()\n2\n>>> F.est_vide()\nFalse\n>>> F.enfile(5)\n>>> F.enfile(7)\n>>> F.affiche()\n7\n5\n2\n>>> F.defile()\n2\n>>> F.defile()\n5\n>>> F.affiche()\n7\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-14","title":"\u25b6 Sujet 14","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-141","title":"Exercice 14.1 \u25a1","text":"Exercice 14.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn consid\u00e8re des mots \u00e0 trous : ce sont des cha\u00eenes de caract\u00e8res contenant uniquement des majuscules et des caract\u00e8res *
. Par exemple INFO*MA*IQUE
, ***I***E**
et *S*
sont des mots \u00e0 trous. Programmer une fonction correspond qui :
mot
et mot_a_trous
o\u00f9 mot_a_trous
est un mot \u00e0 trous comme indiqu\u00e9 ci-dessus, True
si on peut obtenir mot
en rempla\u00e7ant convenablement les caract\u00e8res '*'
de mot_a_trous
.False
sinon.Exemple :
>>> correspond('INFORMATIQUE', 'INFO*MA*IQUE')\nTrue\n>>> correspond('AUTOMATIQUE', 'INFO*MA*IQUE')\nFalse\n
def correspond(mot, mot_a_trous):\n if len(mot) != len(mot_a_trous):\n return False\n for i in range(len(mot)):\n if mot[i] != mot_a_trous[i] and mot_a_trous[i] != '*':\n return False\n return True\n
On consid\u00e8re des mots \u00e0 trous : ce sont des cha\u00eenes de caract\u00e8res contenant uniquement\ndes majuscules et des caract\u00e8res `*`. Par exemple `INFO*MA*IQUE`, `***I***E**` et\n`*S*` sont des mots \u00e0 trous. \nProgrammer une fonction correspond qui :\n\n- prend en param\u00e8tres deux cha\u00eenes de caract\u00e8res `mot` et `mot_a_trous` o\u00f9\n`mot_a_trous` est un mot \u00e0 trous comme indiqu\u00e9 ci-dessus, \n- renvoie :\n - `True` si on peut obtenir `mot` en rempla\u00e7ant convenablement les caract\u00e8res\n`'*'` de `mot_a_trous`.\n - `False` sinon.\n\nExemple :\n\n```python\n>>> correspond('INFORMATIQUE', 'INFO*MA*IQUE')\nTrue\n>>> correspond('AUTOMATIQUE', 'INFO*MA*IQUE')\nFalse\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-142","title":"Exercice 14.2 \u25a1","text":"Exercice 14.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re au plus 26 personnes A, B, C, D, E, F ... qui peuvent s'envoyer des messages avec deux r\u00e8gles \u00e0 respecter :
Voici un exemple - avec 6 personnes - de \u00ab plan d'envoi des messages \u00bb qui respecte les r\u00e8gles ci-dessus, puisque chaque personne est pr\u00e9sente une seule fois dans chaque colonne :
Et le dictionnaire correspondant \u00e0 ce plan d'envoi est le suivant :
plan_a = {'A':'E', 'B':'F', 'C':'D', 'D':'C', 'E':'B', 'F':'A'}
Sur le plan d'envoi plan_a des messages ci-dessus, il y a deux cycles distincts : un premier cycle avec A, E, B, F et un second cycle avec C et D.
En revanche, le plan d\u2019envoi plan_b ci-dessous :
plan_b = {'A':'C', 'B':'F', 'C':'E', 'D':'A', 'E':'B', 'F':'D'}
comporte un unique cycle : A, C, E, B, F, D. Dans ce cas, lorsqu\u2019un plan d\u2019envoi comporte un unique cycle, on dit que le plan d\u2019envoi est cyclique.
Pour savoir si un plan d'envoi de messages comportant N personnes est cyclique, on peut utiliser l'algorithme ci-dessous :
On part de la personne A et on inspecte les N \u2013 1 successeurs dans le plan d'envoi :
Si un de ces N \u2013 1 successeurs est A lui-m\u00eame, on a trouv\u00e9 un cycle de taille inf\u00e9rieure ou \u00e9gale \u00e0 N \u2013 1. Il y a donc au moins deux cycles et le plan d'envoi n'est pas cyclique.
Si on ne retombe pas sur A lors de cette inspection, on a un unique cycle qui passe par toutes les personnes : le plan d'envoi est cyclique.
Compl\u00e9ter la fonction suivante en respectant la sp\u00e9cification.
Remarque : la fonction python len
permet d'obtenir la longueur d'un dictionnaire.
def est_cyclique(plan):\n'''\n Prend en param\u00e8tre un dictionnaire plan correspondant\n \u00e0 un plan d'envoi de messages entre N personnes A, B, C,\n D, E, F ...(avec N <= 26).\n Renvoie True si le plan d'envoi de messages est cyclique\n et False sinon.\n '''\n personne = 'A'\n N = len(...)\n for i in range(...):\n if plan[...] == ...:\n return ...\n else:\n personne = ...\n return ...\n
Exemples :
>>> est_cyclique({'A':'E', 'F':'A', 'C':'D', 'E':'B', 'B':'F', 'D':'C'})\nFalse\n>>> est_cyclique({'A':'E', 'F':'C', 'C':'D', 'E':'B', 'B':'F', 'D':'A'})\nTrue\n>>> est_cyclique({'A':'B', 'F':'C', 'C':'D', 'E':'A', 'B':'F', 'D':'E'})\nTrue\n>>> est_cyclique({'A':'B', 'F':'A', 'C':'D', 'E':'C', 'B':'F', 'D':'E'})\nFalse\n
def est_cyclique(plan):\n'''\n Prend en param\u00e8tre un dictionnaire plan correspondant\n \u00e0 un plan d'envoi de messages entre N personnes A, B, C,\n D, E, F ...(avec N <= 26).\n Renvoie True si le plan d'envoi de messages est cyclique\n et False sinon.\n '''\n personne = 'A'\n N = len(plan)\n for i in range(N-1):\n if plan[personne] == 'A':\n return False\n else:\n personne = plan[personne]\n return True\n\nprint(est_cyclique({'A':'E', 'F':'A', 'C':'D', 'E':'B', 'B':'F', 'D':'C'}))\n\nprint(est_cyclique({'A':'E', 'F':'C', 'C':'D', 'E':'B', 'B':'F', 'D':'A'}))\n\nprint(est_cyclique({'A':'B', 'F':'C', 'C':'D', 'E':'A', 'B':'F', 'D':'E'}))\n\nprint(est_cyclique({'A':'B', 'F':'A', 'C':'D', 'E':'C', 'B':'F', 'D':'E'}))\n
On consid\u00e8re au plus 26 personnes A, B, C, D, E, F ... qui peuvent s'envoyer des messages\navec deux r\u00e8gles \u00e0 respecter :\n\n- chaque personne ne peut envoyer des messages qu'\u00e0 la m\u00eame personne\n(\u00e9ventuellement elle-m\u00eame),\n- chaque personne ne peut recevoir des messages qu'en provenance d'une seule\npersonne (\u00e9ventuellement elle-m\u00eame).\n\n\nVoici un exemple - avec 6 personnes - de \u00ab plan d'envoi des messages \u00bb qui respecte les\nr\u00e8gles ci-dessus, puisque chaque personne est pr\u00e9sente une seule fois dans chaque\ncolonne :\n\n- A envoie ses messages \u00e0 E\n- E envoie ses messages \u00e0 B\n- B envoie ses messages \u00e0 F\n- F envoie ses messages \u00e0 A\n- C envoie ses messages \u00e0 D\n- D envoie ses messages \u00e0 C\n\nEt le dictionnaire correspondant \u00e0 ce plan d'envoi est le suivant :\n\n`plan_a = {'A':'E', 'B':'F', 'C':'D', 'D':'C', 'E':'B', 'F':'A'}`\n\nSur le plan d'envoi plan_a des messages ci-dessus, il y a deux cycles distincts : un premier\ncycle avec A, E, B, F et un second cycle avec C et D.\n\nEn revanche, le plan d\u2019envoi plan_b ci-dessous :\n\n`plan_b = {'A':'C', 'B':'F', 'C':'E', 'D':'A', 'E':'B', 'F':'D'}`\n\ncomporte un unique cycle : A, C, E, B, F, D. Dans ce cas, lorsqu\u2019un plan d\u2019envoi comporte un\nunique cycle, on dit que le plan d\u2019envoi est *cyclique*.\n\nPour savoir si un plan d'envoi de messages comportant N personnes est cyclique, on peut\nutiliser l'algorithme ci-dessous :\n\n\nOn part de la personne A et on inspecte les N \u2013 1 successeurs dans le plan d'envoi :\n\n- Si un de ces N \u2013 1 successeurs est A lui-m\u00eame, on a trouv\u00e9 un cycle de taille\ninf\u00e9rieure ou \u00e9gale \u00e0 N \u2013 1. Il y a donc au moins deux cycles et le plan d'envoi n'est\npas cyclique.\n\n- Si on ne retombe pas sur A lors de cette inspection, on a un unique cycle qui passe\npar toutes les personnes : le plan d'envoi est cyclique.\n\n\nCompl\u00e9ter la fonction suivante en respectant la sp\u00e9cification.\n\n*Remarque :* la fonction python `len` permet d'obtenir la longueur d'un dictionnaire.\n\n\n```python linenums='1'\ndef est_cyclique(plan):\n '''\n Prend en param\u00e8tre un dictionnaire plan correspondant\n \u00e0 un plan d'envoi de messages entre N personnes A, B, C,\n D, E, F ...(avec N <= 26).\n Renvoie True si le plan d'envoi de messages est cyclique\n et False sinon.\n '''\n personne = 'A'\n N = len(...)\n for i in range(...):\n if plan[...] == ...:\n return ...\n else:\n personne = ...\n return ...\n
Exemples :
>>> est_cyclique({'A':'E', 'F':'A', 'C':'D', 'E':'B', 'B':'F', 'D':'C'})\nFalse\n>>> est_cyclique({'A':'E', 'F':'C', 'C':'D', 'E':'B', 'B':'F', 'D':'A'})\nTrue\n>>> est_cyclique({'A':'B', 'F':'C', 'C':'D', 'E':'A', 'B':'F', 'D':'E'})\nTrue\n>>> est_cyclique({'A':'B', 'F':'A', 'C':'D', 'E':'C', 'B':'F', 'D':'E'})\nFalse\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-15","title":"\u25b6 Sujet 15","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-151","title":"Exercice 15.1 \u25a1","text":"Exercice 15.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction python appel\u00e9e nb_repetitions
qui prend en param\u00e8tres un \u00e9l\u00e9ment elt
et une liste tab
et renvoie le nombre de fois o\u00f9 l\u2019\u00e9l\u00e9ment appara\u00eet dans la liste.
Exemples :
>>> nb_repetitions(5, [2, 5, 3, 5, 6, 9, 5])\n3\n>>> nb_repetitions('A', ['B', 'A', 'B', 'A', 'R'])\n2\n>>> nb_repetitions(12, [1, '!', 7, 21, 36, 44])\n0\n
def nb_repetitions(elt, tab):\n nb = 0\n for element in tab:\n if element == elt:\n nb += 1\n return nb\n
\u00c9crire une fonction python appel\u00e9e `nb_repetitions` qui prend en param\u00e8tres un\n\u00e9l\u00e9ment `elt` et une liste `tab` et renvoie le nombre de fois o\u00f9 l\u2019\u00e9l\u00e9ment appara\u00eet dans la\nliste.\n\nExemples :\n```python\n>>> nb_repetitions(5, [2, 5, 3, 5, 6, 9, 5])\n3\n>>> nb_repetitions('A', ['B', 'A', 'B', 'A', 'R'])\n2\n>>> nb_repetitions(12, [1, '!', 7, 21, 36, 44])\n0\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-152","title":"Exercice 15.2 \u25a1","text":"Exercice 15.2
\u00c9nonc\u00e9CorrectionSources MarkdownPour rappel, la conversion d\u2019un nombre entier positif en binaire peut s\u2019effectuer \u00e0 l\u2019aide des divisions successives comme illustr\u00e9 ici :
Voici une fonction Python bas\u00e9e sur la m\u00e9thode des divisions successives permettant de convertir un nombre entier positif en binaire :
def binaire(a):\n bin_a = str(...)\n a = a // 2\n while a ... :\n bin_a = ...(a%2) + ...\n a = ...\n return bin_a\n
Compl\u00e9ter la fonction binaire
. Exemples :
>>> binaire(0)\n'0'\n>>> binaire(77)\n'1001101'\n
def binaire(a):\n bin_a = str(a%2)\n a = a // 2\n while a != 0 :\n bin_a = str(a%2) + bin_a\n a = a // 2\n return bin_a\n
Pour rappel, la conversion d\u2019un nombre entier positif en binaire peut s\u2019effectuer \u00e0 l\u2019aide\ndes divisions successives comme illustr\u00e9 ici :\n\n![image](data/img21_2.png){: .center}\n\nVoici une fonction Python bas\u00e9e sur la m\u00e9thode des divisions successives permettant de\nconvertir un nombre entier positif en binaire :\n```python linenums='1'\ndef binaire(a):\n bin_a = str(...)\n a = a // 2\n while a ... :\n bin_a = ...(a%2) + ...\n a = ...\n return bin_a\n
Compl\u00e9ter la fonction binaire
. Exemples :
>>> binaire(0)\n'0'\n>>> binaire(77)\n'1001101'\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-16","title":"\u25b6 Sujet 16","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-161","title":"Exercice 16.1 \u25a1","text":"Exercice 16.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction maxi
qui prend en param\u00e8tre une liste tab
de nombres entiers et renvoie un couple donnant le plus grand \u00e9l\u00e9ment de cette liste, ainsi que l\u2019indice de la premi\u00e8re apparition de ce maximum dans la liste.
Exemple :
>>> maxi([1,5,6,9,1,2,3,7,9,8])\n(9,3)\n
def maxi(tab):\n val_max = tab[0]\n pos_max = 0\n for i in range(len(tab)):\n if tab[i] > val_max:\n val_max = tab[i]\n pos_max = i\n return (val_max, pos_max)\n
\u00c9crire une fonction `maxi` qui prend en param\u00e8tre une liste `tab` de nombres entiers et renvoie un couple donnant le plus grand \u00e9l\u00e9ment de cette liste, ainsi que l\u2019indice de la premi\u00e8re apparition de ce maximum dans la liste.\n\nExemple :\n```python\n>>> maxi([1,5,6,9,1,2,3,7,9,8])\n(9,3)\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-162","title":"Exercice 16.2 \u25a1","text":"Exercice 16.2
\u00c9nonc\u00e9CorrectionSources MarkdownCet exercice utilise des piles qui seront repr\u00e9sent\u00e9es en Python par des listes (type list
).
On rappelle que l\u2019expression T1 = list(T)
fait une copie de T
ind\u00e9pendante de T
, que l\u2019expression x = T.pop()
enl\u00e8ve le sommet de la pile T
et le place dans la variable x
et, enfin, que l\u2019expression T.append(v)
place la valeur v
au sommet de la pile T
.
Compl\u00e9ter le code Python de la fonction positif
ci-dessous qui prend une pile T
de nombres entiers en param\u00e8tre et qui renvoie la pile des entiers positifs dans le m\u00eame ordre, sans modifier la variable T
.
def positif(T):\n T2 = ...(T)\n T3 = ...\n while T2 != []:\n x = ...\n if ... >= 0:\n T3.append(...)\n T2 = []\n while T3 != ...:\n x = T3.pop()\n ...\n print('T = ',T)\n return T2\n
Exemple :
>>> positif([-1, 0, 5, -3, 4, -6, 10, 9, -8])\nT = [-1, 0, 5, -3, 4, -6, 10, 9, -8]\n[0, 5, 4, 10, 9]\n
def positif(T):\n T2 = list(T)\n T3 = []\n while T2 != []:\n x = T2.pop()\n if x >= 0:\n T3.append(x)\n T2 = [] # <- NB : cette ligne est inutile\n while T3 != []:\n x = T3.pop()\n T2.append(x)\n print('T = ',T)\n return T2\n
Cet exercice utilise des piles qui seront repr\u00e9sent\u00e9es en Python par des listes (type `list`).\n\nOn rappelle que l\u2019expression `T1 = list(T)` fait une copie de `T `ind\u00e9pendante de `T`, que\nl\u2019expression `x = T.pop()` enl\u00e8ve le sommet de la pile `T` et le place dans la variable `x` et,\nenfin, que l\u2019expression `T.append(v)` place la valeur `v` au sommet de la pile `T`.\n\nCompl\u00e9ter le code Python de la fonction `positif` ci-dessous qui prend une pile `T` de\nnombres entiers en param\u00e8tre et qui renvoie la pile des entiers positifs dans le m\u00eame\nordre, sans modifier la variable `T`.\n\n```python linenums='1'\ndef positif(T):\n T2 = ...(T)\n T3 = ...\n while T2 != []:\n x = ...\n if ... >= 0:\n T3.append(...)\n T2 = []\n while T3 != ...:\n x = T3.pop()\n ...\n print('T = ',T)\n return T2\n
Exemple :
>>> positif([-1, 0, 5, -3, 4, -6, 10, 9, -8])\nT = [-1, 0, 5, -3, 4, -6, 10, 9, -8]\n[0, 5, 4, 10, 9]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-17","title":"\u25b6 Sujet 17","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-171","title":"Exercice 17.1 \u25a1","text":"Exercice 17.1
\u00c9nonc\u00e9CorrectionSource MarkdownPour cet exercice :
On appelle \u00ab mot \u00bb une cha\u00eene de caract\u00e8res compos\u00e9e avec des caract\u00e8res choisis parmi les 26 lettres minuscules ou majuscules de l'alphabet,
On appelle \u00ab phrase \u00bb une cha\u00eene de caract\u00e8res :
' '
,'.'
qui est alors coll\u00e9 au dernier mot,'!'
ou d'interrogation '?'
qui est alors s\u00e9par\u00e9 du dernier mot par un seul caract\u00e8re espace ' '
.Exemples :
Apr\u00e8s avoir remarqu\u00e9 le lien entre le nombre de mots et le nombres de caract\u00e8res espace dans une phrase, programmer une fonction nombre_de_mots
qui prend en param\u00e8tre une phrase et renvoie le nombre de mots pr\u00e9sents dans cette phrase.
>>> nombre_de_mots('Le point d exclamation est separe !')\n6\n>>> nombre_de_mots('Il y a un seul espace entre les mots !')\n9\n
def nombre_de_mots(phrase):\n nb_mots = 0\n for caractere in phrase:\n if caractere == ' ' or caractere == '.':\n nb_mots += 1\n return nb_mots\n
Pour cet exercice :\n\n- On appelle \u00ab mot \u00bb une cha\u00eene de caract\u00e8res compos\u00e9e avec des caract\u00e8res choisis\nparmi les 26 lettres minuscules ou majuscules de l'alphabet,\n\n- On appelle \u00ab phrase \u00bb une cha\u00eene de caract\u00e8res :\n - compos\u00e9e avec un ou plusieurs \u00ab mots \u00bb s\u00e9par\u00e9s entre eux par un seul\ncaract\u00e8re espace `' '`,\n - se finissant :\n - soit par un point `'.'` qui est alors coll\u00e9 au dernier mot,\n - soit par un point d'exclamation `'!'` ou d'interrogation `'?'` qui est alors\ns\u00e9par\u00e9 du dernier mot par un seul caract\u00e8re espace `' '`.\n\n*Exemples :*\n\nApr\u00e8s avoir remarqu\u00e9 le lien entre le nombre de mots et le nombres de caract\u00e8res espace\ndans une phrase, programmer une fonction `nombre_de_mots` qui prend en param\u00e8tre une\nphrase et renvoie le nombre de mots pr\u00e9sents dans cette phrase.\n\n```python\n>>> nombre_de_mots('Le point d exclamation est separe !')\n6\n>>> nombre_de_mots('Il y a un seul espace entre les mots !')\n9\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-172","title":"Exercice 17.2 \u25a1","text":"Exercice 17.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa classe ABR ci-dessous permet d'impl\u00e9menter une structure d'arbre binaire de recherche.
class Noeud:\n''' Classe impl\u00e9mentant un noeud d'arbre binaire\n disposant de 3 attributs :\n - valeur : la valeur de l'\u00e9tiquette,\n - gauche : le sous-arbre gauche.\n - droit : le sous-arbre droit. '''\n def __init__(self, v, g, d):\n self.valeur = v\n self.gauche = g\n self.droite = d\n\nclass ABR:\n''' Classe impl\u00e9mentant une structure\n d'arbre binaire de recherche. '''\n def __init__(self):\n'''Cr\u00e9e un arbre binaire de recherche vide'''\n self.racine = None\n\n def est_vide(self):\n'''Renvoie True si l'ABR est vide et False sinon.'''\n return self.racine is None\n\n def parcours(self, tab = []):\n''' Renvoie la liste tab compl\u00e9t\u00e9e avec tous les\n \u00e9l\u00e9ments de l'ABR tri\u00e9s par ordre croissant. '''\n\n if self.est_vide():\n return tab\n else:\n self.racine.gauche.parcours(tab)\n tab.append(...)\n ...\n return tab\n\n def insere(self, element):\n'''Ins\u00e8re un \u00e9l\u00e9ment dans l'arbre binaire de recherche.'''\n if self.est_vide():\n self.racine = Noeud(element, ABR(), ABR())\n else:\n if element < self.racine.valeur:\n self.racine.gauche.insere(element)\n else :\n self.racine.droite.insere(element)\n\n def recherche(self, element):\n'''\n Renvoie True si element est pr\u00e9sent dans l'arbre\n binaire et False sinon.\n '''\n if self.est_vide():\n return ...\n else:\n if element < self.racine.valeur:\n return ...\n elif element > self.racine.valeur:\n return ...\n else:\n return ...\n
Compl\u00e9ter les fonctions r\u00e9cursives parcours et recherche afin qu'elles respectent leurs sp\u00e9cifications.
Voici un exemple d'utilisation :
>>> a = ABR()\n>>> a.insere(7)\n>>> a.insere(3)\n>>> a.insere(9)\n>>> a.insere(1)\n>>> a.insere(9)\n>>> a.parcours()\n[1,3, 7, 9, 9]\n\n>>> a.recherche(4)\nFalse\n>>> a.recherche(3)\nTrue\n
class Noeud:\n''' Classe impl\u00e9mentant un noeud d'arbre binaire\n disposant de 3 attributs :\n - valeur : la valeur de l'\u00e9tiquette,\n - gauche : le sous-arbre gauche.\n - droit : le sous-arbre droit. '''\n def __init__(self, v, g, d):\n self.valeur = v\n self.gauche = g\n self.droite = d\n\nclass ABR:\n''' Classe impl\u00e9mentant une structure\n d'arbre binaire de recherche. '''\n def __init__(self):\n'''Cr\u00e9e un arbre binaire de recherche vide'''\n self.racine = None\n\n def est_vide(self):\n'''Renvoie True si l'ABR est vide et False sinon.'''\n return self.racine is None\n\n def parcours(self, tab = []):\n''' Renvoie la liste tab compl\u00e9t\u00e9e avec tous les\n \u00e9l\u00e9ments de l'ABR tri\u00e9s par ordre croissant. '''\n\n if self.est_vide():\n return tab\n else:\n self.racine.gauche.parcours(tab)\n tab.append(self.racine.valeur)\n self.racine.droite.parcours(tab)\n return tab\n\n def insere(self, element):\n'''Ins\u00e8re un \u00e9l\u00e9ment dans l'arbre binaire de recherche.'''\n if self.est_vide():\n self.racine = Noeud(element, ABR(), ABR())\n else:\n if element < self.racine.valeur:\n self.racine.gauche.insere(element)\n else :\n self.racine.droite.insere(element)\n\n def recherche(self, element):\n'''\n Renvoie True si element est pr\u00e9sent dans l'arbre\n binaire et False sinon.\n '''\n if self.est_vide():\n return False\n else:\n if element < self.racine.valeur:\n return self.racine.gauche.recherche(element)\n elif element > self.racine.valeur:\n return self.racine.droite.recherche(element)\n else:\n return True\n
Cette mani\u00e8re de coder le parcours est maladroite car elle conduit \u00e0 ceci :
>>> a.parcours()\n[1, 3, 7, 9, 9]\n>>> a.parcours()\n[1, 3, 7, 9, 9, 1, 3, 7, 9, 9]\n
Comme le param\u00e8tre optionnel tab
est un \u00e9l\u00e9ment mutable (de type list
), Python ne le r\u00e9initialise pas avant chaque appel de la fonction. Vous pouvez constater les cons\u00e9quences f\u00e2cheuses.
Une solution pourrait \u00eatre d'\u00e9crire ceci :
def parcours(self, tab = None):\n''' Renvoie la liste tab compl\u00e9t\u00e9e avec tous les\n \u00e9l\u00e9ments de l'ABR tri\u00e9s par ordre croissant. '''\n if tab is None:\n tab = []\n if self.est_vide():\n return tab\n else:\n self.racine.gauche.parcours(tab)\n tab.append(self.racine.valeur)\n self.racine.droite.parcours(tab)\n return tab\n
La classe ABR ci-dessous permet d'impl\u00e9menter une structure d'arbre binaire de recherche.\n\n```python linenums='1'\nclass Noeud:\n ''' Classe impl\u00e9mentant un noeud d'arbre binaire\n disposant de 3 attributs :\n - valeur : la valeur de l'\u00e9tiquette,\n - gauche : le sous-arbre gauche.\n - droit : le sous-arbre droit. '''\n def __init__(self, v, g, d):\n self.valeur = v\n self.gauche = g\n self.droite = d\n\nclass ABR:\n ''' Classe impl\u00e9mentant une structure\n d'arbre binaire de recherche. '''\n def __init__(self):\n '''Cr\u00e9e un arbre binaire de recherche vide'''\n self.racine = None\n\n def est_vide(self):\n '''Renvoie True si l'ABR est vide et False sinon.'''\n return self.racine is None\n\n def parcours(self, tab = []):\n ''' Renvoie la liste tab compl\u00e9t\u00e9e avec tous les\n \u00e9l\u00e9ments de l'ABR tri\u00e9s par ordre croissant. '''\n\n if self.est_vide():\n return tab\n else:\n self.racine.gauche.parcours(tab)\n tab.append(...)\n ...\n return tab\n\n def insere(self, element):\n '''Ins\u00e8re un \u00e9l\u00e9ment dans l'arbre binaire de recherche.'''\n if self.est_vide():\n self.racine = Noeud(element, ABR(), ABR())\n else:\n if element < self.racine.valeur:\n self.racine.gauche.insere(element)\n else :\n self.racine.droite.insere(element)\n\n def recherche(self, element):\n '''\n Renvoie True si element est pr\u00e9sent dans l'arbre\n binaire et False sinon.\n '''\n if self.est_vide():\n return ...\n else:\n if element < self.racine.valeur:\n return ...\n elif element > self.racine.valeur:\n return ...\n else:\n return ...\n
Compl\u00e9ter les fonctions r\u00e9cursives parcours et recherche afin qu'elles respectent leurs sp\u00e9cifications.
Voici un exemple d'utilisation :
>>> a = ABR()\n>>> a.insere(7)\n>>> a.insere(3)\n>>> a.insere(9)\n>>> a.insere(1)\n>>> a.insere(9)\n>>> a.parcours()\n[1,3, 7, 9, 9]\n\n>>> a.recherche(4)\nFalse\n>>> a.recherche(3)\nTrue\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-18","title":"\u25b6 Sujet 18","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-181","title":"Exercice 18.1 \u25a1","text":"Exercice 18.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn a relev\u00e9 les valeurs moyennes annuelles des temp\u00e9ratures \u00e0 Paris pour la p\u00e9riode allant de 2013 \u00e0 2019. Les r\u00e9sultats ont \u00e9t\u00e9 r\u00e9cup\u00e9r\u00e9s sous la forme de deux listes : l\u2019une pour les temp\u00e9ratures, l\u2019autre pour les ann\u00e9es :
t_moy = [14.9, 13.3, 13.1, 12.5, 13.0, 13.6, 13.7]\nannees = [2013, 2014, 2015, 2016, 2017, 2018, 2019]\n
\u00c9crire la fonction mini
qui prend en param\u00e8tres le tableau releve
des relev\u00e9s et le tableau date
des dates et qui renvoie la plus petite valeur relev\u00e9e au cours de la p\u00e9riode et l\u2019ann\u00e9e correspondante.
Exemple :
>>> mini(t_moy, annees)\n(12.5, 2016)\n
t_moy = [14.9, 13.3, 13.1, 12.5, 13.0, 13.6, 13.7]\nannees = [2013, 2014, 2015, 2016, 2017, 2018, 2019]\n\ndef mini(releve, date):\n temp_mini = releve[0]\n date_mini = date[0]\n for i in range(len(releve)):\n if releve[i] < temp_mini:\n temp_mini = releve[i]\n date_mini = date[i]\n return temp_mini, date_mini\n
On a relev\u00e9 les valeurs moyennes annuelles des temp\u00e9ratures \u00e0 Paris pour la p\u00e9riode\nallant de 2013 \u00e0 2019. Les r\u00e9sultats ont \u00e9t\u00e9 r\u00e9cup\u00e9r\u00e9s sous la forme de deux listes : l\u2019une pour les temp\u00e9ratures, l\u2019autre pour les ann\u00e9es :\n```python\nt_moy = [14.9, 13.3, 13.1, 12.5, 13.0, 13.6, 13.7]\nannees = [2013, 2014, 2015, 2016, 2017, 2018, 2019]\n```\n\n\u00c9crire la fonction `mini` qui prend en param\u00e8tres le tableau `releve` des relev\u00e9s et le\ntableau `date` des dates et qui renvoie la plus petite valeur relev\u00e9e au cours de la\np\u00e9riode et l\u2019ann\u00e9e correspondante.\n\nExemple :\n```python\n>>> mini(t_moy, annees)\n(12.5, 2016)\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-182","title":"Exercice 18.2 \u25a1","text":"Exercice 18.2
\u00c9nonc\u00e9CorrectionSources MarkdownUn mot palindrome peut se lire de la m\u00eame fa\u00e7on de gauche \u00e0 droite ou de droite \u00e0 gauche : bob, radar, et non sont des mots palindromes.
De m\u00eame certains nombres sont eux aussi des palindromes : 33, 121, 345543.
L\u2019objectif de cet exercice est d\u2019obtenir un programme Python permettant de tester si un nombre est un nombre palindrome.
Pour remplir cette t\u00e2che, on vous demande de compl\u00e9ter le code des trois fonctions ci- dessous sachant que la fonction est_nbre_palindrome
s\u2019appuiera sur la fonction est_palindrome
qui elle-m\u00eame s\u2019appuiera sur la fonction inverse_chaine
.
La fonction inverse_chaine
inverse l'ordre des caract\u00e8res d'une cha\u00eene de caract\u00e8res chaine
et renvoie la cha\u00eene invers\u00e9e.
La fonction est_palindrome
teste si une chaine de caract\u00e8res chaine
est un palindrome. Elle renvoie True
si c\u2019est le cas et False
sinon. Cette fonction s\u2019appuie sur la fonction pr\u00e9c\u00e9dente.
La fonction est_nbre_palindrome
teste si un nombre nbre
est un palindrome. Elle renvoie True
si c\u2019est le cas et False
sinon. Cette fonction s\u2019appuie sur la fonction pr\u00e9c\u00e9dente.
Compl\u00e9ter le code des trois fonctions ci-dessous.
def inverse_chaine(chaine):\n result = ...\n for caractere in chaine:\n result = ...\n return result\n\ndef est_palindrome(chaine):\n inverse = inverse_chaine(chaine)\n return ...\n\ndef est_nbre_palindrome(nbre):\n chaine = ...\n return est_palindrome(chaine)\n
Exemples : >>> inverse_chaine('bac')\n'cab'\n>>> est_palindrome('NSI')\nFalse\n>>> est_palindrome('ISN-NSI')\nTrue\n>>> est_nbre_palindrome(214312)\nFalse\n>>> est_nbre_palindrome(213312)\nTrue\n
def inverse_chaine(chaine):\n result = ''\n for caractere in chaine:\n result = caractere + result\n return result\n\ndef est_palindrome(chaine):\n inverse = inverse_chaine(chaine)\n return chaine == inverse\n\ndef est_nbre_palindrome(nbre):\n chaine = str(nbre)\n return est_palindrome(chaine)\n
Un mot palindrome peut se lire de la m\u00eame fa\u00e7on de gauche \u00e0 droite ou de droite \u00e0\ngauche : *bob*, *radar*, et *non* sont des mots palindromes.\n\nDe m\u00eame certains nombres sont eux aussi des palindromes : 33, 121, 345543.\n\nL\u2019objectif de cet exercice est d\u2019obtenir un programme Python permettant de tester si un\nnombre est un nombre palindrome.\n\nPour remplir cette t\u00e2che, on vous demande de compl\u00e9ter le code des trois fonctions ci-\ndessous sachant que la fonction `est_nbre_palindrome` s\u2019appuiera sur la fonction\n`est_palindrome` qui elle-m\u00eame s\u2019appuiera sur la fonction `inverse_chaine`.\n\nLa fonction `inverse_chaine` inverse l'ordre des caract\u00e8res d'une cha\u00eene de caract\u00e8res\n`chaine` et renvoie la cha\u00eene invers\u00e9e.\n\nLa fonction `est_palindrome` teste si une chaine de caract\u00e8res `chaine` est un\npalindrome. Elle renvoie `True` si c\u2019est le cas et `False` sinon. Cette fonction s\u2019appuie sur\nla fonction pr\u00e9c\u00e9dente.\n\nLa fonction `est_nbre_palindrome` teste si un nombre `nbre` est un palindrome. Elle\nrenvoie `True` si c\u2019est le cas et `False` sinon. Cette fonction s\u2019appuie sur la fonction\npr\u00e9c\u00e9dente.\n\nCompl\u00e9ter le code des trois fonctions ci-dessous.\n\n```python\ndef inverse_chaine(chaine):\n result = ...\n for caractere in chaine:\n result = ...\n return result\n\ndef est_palindrome(chaine):\n inverse = inverse_chaine(chaine)\n return ...\n\ndef est_nbre_palindrome(nbre):\n chaine = ...\n return est_palindrome(chaine)\n
Exemples : >>> inverse_chaine('bac')\n'cab'\n>>> est_palindrome('NSI')\nFalse\n>>> est_palindrome('ISN-NSI')\nTrue\n>>> est_nbre_palindrome(214312)\nFalse\n>>> est_nbre_palindrome(213312)\nTrue\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-19","title":"\u25b6 Sujet 19","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-191","title":"Exercice 19.1 \u25a1","text":"Exercice 19.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction multiplication
, prenant en param\u00e8tres deux nombres entiers n1
et n2
, et qui renvoie le produit de ces deux nombres. Les seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.
Exemples :
>>> multiplication(3,5)\n15\n>>> multiplication(-4,-8)\n32\n>>> multiplication(-2,6)\n-12\n>>> multiplication(-2,0)\n0\n
def multiplication(n1, n2):\n if n1 < 0:\n return -multiplication(-n1, n2)\n if n2 < 0:\n return -multiplication(n1, -n2)\n resultat = 0\n for _ in range(n2):\n resultat += n1\n return resultat\n
Programmer la fonction `multiplication`, prenant en param\u00e8tres deux nombres entiers\n`n1` et `n2`, et qui renvoie le produit de ces deux nombres.\nLes seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.\n\nExemples :\n```python\n>>> multiplication(3,5)\n15\n>>> multiplication(-4,-8)\n32\n>>> multiplication(-2,6)\n-12\n>>> multiplication(-2,0)\n0\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-192","title":"Exercice 19.2 \u25a1","text":"Exercice 19.2
\u00c9nonc\u00e9CorrectionSources MarkdownSoit T
un tableau non vide d'entiers tri\u00e9s dans l'ordre croissant et n
un entier. La fonction chercher
, donn\u00e9e \u00e0 la page suivante, doit renvoyer un indice o\u00f9 la valeur n
appara\u00eet \u00e9ventuellement dans T
, et None
sinon.
Les param\u00e8tres de la fonction sont :
T
, le tableau dans lequel s'effectue la recherche ;n
, l'entier \u00e0 chercher dans le tableau ;i
, l'indice de d\u00e9but de la partie du tableau o\u00f9 s'effectue la recherche ;j
, l'indice de fin de la partie du tableau o\u00f9 s'effectue la recherche.La fonction chercher
est une fonction r\u00e9cursive bas\u00e9e sur le principe \u00ab diviser pour r\u00e9gner \u00bb.
Le code de la fonction commence par v\u00e9rifier si 0 <= i
et j < len(T)
. Si cette condition n\u2019est pas v\u00e9rifi\u00e9e, elle affiche \"Erreur\"
puis renvoie None
.
Recopier et compl\u00e9ter le code de la fonction chercher
propos\u00e9e ci-dessous :
def chercher(T, n, i, j):\n if i < 0 or ??? :\n print(\"Erreur\")\n return None\n if i > j :\n return None\n m = (i + j) // ???\n if T[m] < ??? :\n return chercher(T, n, ??? , ???)\n elif ??? :\n return chercher(T, n, ??? , ??? )\n else :\n return ???\n
L'ex\u00e9cution du code doit donner :
>>> chercher([1,5,6,6,9,12],7,0,10)\nErreur\n>>> chercher([1,5,6,6,9,12],7,0,5)\n>>> chercher([1,5,6,6,9,12],9,0,5)\n4\n>>> chercher([1,5,6,6,9,12],6,0,5)\n2\n
def chercher(T, n, i, j):\n if i < 0 or j >= len(T) :\n print('Erreur')\n return None\n if i > j :\n return None\n m = (i + j) // 2\n if T[m] < n :\n return chercher(T, n, m + 1, j)\n elif T[m] > n :\n return chercher(T, n, i, m - 1 )\n else :\n return m\n
Soit `T` un tableau non vide d'entiers tri\u00e9s dans l'ordre croissant et `n` un entier.\nLa fonction `chercher`, donn\u00e9e \u00e0 la page suivante, doit renvoyer un indice o\u00f9 la valeur `n`\nappara\u00eet \u00e9ventuellement dans `T`, et `None` sinon. \n\nLes param\u00e8tres de la fonction sont :\n\n- `T`, le tableau dans lequel s'effectue la recherche ;\n- `n`, l'entier \u00e0 chercher dans le tableau ;\n- `i`, l'indice de d\u00e9but de la partie du tableau o\u00f9 s'effectue la recherche ;\n- `j`, l'indice de fin de la partie du tableau o\u00f9 s'effectue la recherche.\n\nLa fonction `chercher` est une fonction r\u00e9cursive bas\u00e9e sur le principe \u00ab diviser pour\nr\u00e9gner \u00bb.\n\n\nLe code de la fonction commence par v\u00e9rifier si `0 <= i` et `j < len(T)`. \nSi cette\ncondition n\u2019est pas v\u00e9rifi\u00e9e, elle affiche `\"Erreur\"` puis renvoie `None`.\n\nRecopier et compl\u00e9ter le code de la fonction `chercher` propos\u00e9e ci-dessous :\n\n```python linenums='1'\ndef chercher(T, n, i, j):\n if i < 0 or ??? :\n print(\"Erreur\")\n return None\n if i > j :\n return None\n m = (i + j) // ???\n if T[m] < ??? :\n return chercher(T, n, ??? , ???)\n elif ??? :\n return chercher(T, n, ??? , ??? )\n else :\n return ???\n
L'ex\u00e9cution du code doit donner :
>>> chercher([1,5,6,6,9,12],7,0,10)\nErreur\n>>> chercher([1,5,6,6,9,12],7,0,5)\n>>> chercher([1,5,6,6,9,12],9,0,5)\n4\n>>> chercher([1,5,6,6,9,12],6,0,5)\n2\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-20","title":"\u25b6 Sujet 20","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-201","title":"Exercice 20.1 \u25a1","text":"Exercice 20.1
\u00c9nonc\u00e9CorrectionSource MarkdownL'op\u00e9rateur \u00ab ou exclusif \u00bb entre deux bits renvoie 0 si les deux bits sont \u00e9gaux et 1 s'ils sont diff\u00e9rents : 0 \u2295 0 = 0 , 0 \u2295 1 = 1 , 1 \u2295 0 = 1 , 1 \u2295 1 = 0
On repr\u00e9sente ici une suite de bits par un tableau contenant des 0 et des 1.
Exemples :
a = [1, 0, 1, 0, 1, 1, 0, 1]\nb = [0, 1, 1, 1, 0, 1, 0, 0]\nc = [1, 1, 0, 1]\nd = [0, 0, 1, 1]\n
\u00c9crire la fonction xor
qui prend en param\u00e8tres deux tableaux de m\u00eame longueur et qui renvoie un tableau o\u00f9 l\u2019\u00e9l\u00e9ment situ\u00e9 \u00e0 position i
est le r\u00e9sultat, par l\u2019op\u00e9rateur \u00ab ou exclusif \u00bb, des \u00e9l\u00e9ments \u00e0 la position i
des tableaux pass\u00e9s en param\u00e8tres.
En consid\u00e9rant les quatre exemples ci-dessus, cette fonction doit passer les tests suivants :
assert(xor(a, b) == [1, 1, 0, 1, 1, 0, 0, 1])\nassert(xor(c, d) == [1, 1, 1, 0])\n
Correction propos\u00e9e par Yves Laurent
def xor(tab1, tab2):\n\"\"\"\n\n Parameters\n ----------\n tab1 : type(tab1) = list\n Binaire 1\n tab2 : type(tab1) = list\n Binaire 2\n\n Returns\n -------\n resultat : list\n tab1 xor tab2.\n\n \"\"\"\n assert len(tab1) == len(tab2), \"pas la m\u00eame taille\"\n\n resultat = []\n\n taille = len(tab1)\n\n for compteur in range(taille):\n resultat.append(tab1[compteur]^tab2[compteur])\n\n return resultat\n
L'op\u00e9rateur \u00ab ou exclusif \u00bb entre deux bits renvoie 0 si les deux bits sont \u00e9gaux et 1 s'ils sont\ndiff\u00e9rents : \n0 \u2295 0 = 0 , 0 \u2295 1 = 1 , 1 \u2295 0 = 1 , 1 \u2295 1 = 0\n\nOn repr\u00e9sente ici une suite de bits par un tableau contenant des 0 et des 1.\n\nExemples :\n\n```python\na = [1, 0, 1, 0, 1, 1, 0, 1]\nb = [0, 1, 1, 1, 0, 1, 0, 0]\nc = [1, 1, 0, 1]\nd = [0, 0, 1, 1]\n```\n\n\u00c9crire la fonction ```xor``` qui prend en param\u00e8tres deux tableaux de m\u00eame longueur et qui renvoie\nun tableau o\u00f9 l\u2019\u00e9l\u00e9ment situ\u00e9 \u00e0 position `i` est le r\u00e9sultat, par l\u2019op\u00e9rateur \u00ab ou exclusif \u00bb, des\n\u00e9l\u00e9ments \u00e0 la position `i` des tableaux pass\u00e9s en param\u00e8tres.\n\nEn consid\u00e9rant les quatre exemples ci-dessus, cette fonction doit passer les tests suivants :\n\n```python\nassert(xor(a, b) == [1, 1, 0, 1, 1, 0, 0, 1])\nassert(xor(c, d) == [1, 1, 1, 0])\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-202","title":"Exercice 20.2 \u25a1","text":"Exercice 20.2
\u00c9nonc\u00e9CorrectionSources MarkdownDans cet exercice, on appelle carr\u00e9 d\u2019ordre \\(n\\) un tableau de \\(n\\) lignes et \\(n\\) colonnes dont chaque case contient un entier naturel.
Exemples :
Un carr\u00e9 est dit magique lorsque les sommes des \u00e9l\u00e9ments situ\u00e9s sur chaque ligne, chaque colonne et chaque diagonale sont \u00e9gales. Ainsi c2 et c3 sont magiques car la somme de chaque ligne, chaque colonne et chaque diagonale est \u00e9gale \u00e0 2 pour c2 et 15 pour c3. c4 n\u2019est pas magique car la somme de la premi\u00e8re ligne est \u00e9gale \u00e0 34 alors que celle de la derni\u00e8re colonne est \u00e9gale \u00e0 27.
La classe Carre
ci-apr\u00e8s contient des m\u00e9thodes qui permettent de manipuler des carr\u00e9s.
Compl\u00e9ter la fonction est_magique
qui prend en param\u00e8tre un carr\u00e9 et qui renvoie la valeur de la somme si ce carr\u00e9 est magique, False
sinon.
class Carre:\n def __init__(self, tableau = [[]]):\n self.ordre = len(tableau)\n self.valeurs = tableau\n\n def affiche(self):\n'''Affiche un carr\u00e9'''\n for i in range(self.ordre):\n print(self.valeurs[i])\n\n def somme_ligne(self, i):\n'''Calcule la somme des valeurs de la ligne i'''\n return sum(self.valeurs[i])\n\n def somme_col(self, j):\n'''Calcule la somme des valeurs de la colonne j'''\n return sum([self.valeurs[i][j] for i in range(self.ordre)])\n\ndef est_magique(carre):\n n = carre.ordre\n s = carre.somme_ligne(0)\n\n #test de la somme de chaque ligne\n for i in range(..., ...):\n if carre.somme_ligne(i) != s:\n return ...\n\n #test de la somme de chaque colonne\n for j in range(n):\n if ... != s:\n return False\n\n #test de la somme de chaque diagonale\n if sum([carre.valeurs[...][...] for k in range(n)]) != s:\n return False\n if sum([carre.valeurs[k][n-1-k] for k in range(n)]) != s:\n return False\n return ...\n
Tester la fonction est_magique
sur les carr\u00e9s c2, c3 et c4.
class Carre:\n def __init__(self, tableau = [[]]):\n self.ordre = len(tableau)\n self.valeurs = tableau\n\n def affiche(self):\n'''Affiche un carr\u00e9'''\n for i in range(self.ordre):\n print(self.valeurs[i])\n\n def somme_ligne(self, i):\n'''Calcule la somme des valeurs de la ligne i'''\n return sum(self.valeurs[i])\n\n def somme_col(self, j):\n'''Calcule la somme des valeurs de la colonne j'''\n return sum([self.valeurs[i][j] for i in range(self.ordre)])\n\ndef est_magique(carre):\n n = carre.ordre\n s = carre.somme_ligne(0)\n\n #test de la somme de chaque ligne\n for i in range(1, n):\n if carre.somme_ligne(i) != s:\n return False\n\n #test de la somme de chaque colonne\n for j in range(n):\n if carre.somme_col(j) != s:\n return False\n\n #test de la somme de chaque diagonale\n if sum([carre.valeurs[k][k] for k in range(n)]) != s:\n return False\n if sum([carre.valeurs[k][n-1-k] for k in range(n)]) != s:\n return False\n return s\n\nc1 = Carre([[1, 1],\n [1, 1]])\n\nc2 = Carre([[2, 9, 4],\n [7, 5, 3],\n [6, 1, 8]])\n\nc3 = Carre([[4, 5, 16, 9],\n [14, 7, 2, 11],\n [3, 10, 15, 6],\n [13, 12, 8, 1]])\n\nassert est_magique(c1) == 2\nassert est_magique(c2) == 15\nassert est_magique(c3) == False\n
Dans cet exercice, on appelle carr\u00e9 d\u2019ordre $n$ un tableau de $n$ lignes et $n$ colonnes dont chaque case contient un entier naturel.\n\nExemples :\n![image](data/img20_2.png){: .center width=70%}\n\nUn carr\u00e9 est dit magique lorsque les sommes des \u00e9l\u00e9ments situ\u00e9s sur chaque ligne, chaque\ncolonne et chaque diagonale sont \u00e9gales. Ainsi c2 et c3 sont magiques car la somme de chaque\nligne, chaque colonne et chaque diagonale est \u00e9gale \u00e0 2 pour c2 et 15 pour c3. c4 n\u2019est pas\nmagique car la somme de la premi\u00e8re ligne est \u00e9gale \u00e0 34 alors que celle de la derni\u00e8re colonne\nest \u00e9gale \u00e0 27.\n\nLa classe `Carre` ci-apr\u00e8s contient des m\u00e9thodes qui permettent de manipuler des carr\u00e9s.\n\nCompl\u00e9ter la fonction `est_magique` qui prend en param\u00e8tre un carr\u00e9 et qui renvoie la valeur de\nla somme si ce carr\u00e9 est magique, `False` sinon.\n\n```python linenums='1'\nclass Carre:\n def __init__(self, tableau = [[]]):\n self.ordre = len(tableau)\n self.valeurs = tableau\n\n def affiche(self):\n '''Affiche un carr\u00e9'''\n for i in range(self.ordre):\n print(self.valeurs[i])\n\n def somme_ligne(self, i):\n '''Calcule la somme des valeurs de la ligne i'''\n return sum(self.valeurs[i])\n\n def somme_col(self, j):\n '''Calcule la somme des valeurs de la colonne j'''\n return sum([self.valeurs[i][j] for i in range(self.ordre)])\n\ndef est_magique(carre):\n n = carre.ordre\n s = carre.somme_ligne(0)\n\n #test de la somme de chaque ligne\n for i in range(..., ...):\n if carre.somme_ligne(i) != s:\n return ...\n\n #test de la somme de chaque colonne\n for j in range(n):\n if ... != s:\n return False\n\n #test de la somme de chaque diagonale\n if sum([carre.valeurs[...][...] for k in range(n)]) != s:\n return False\n if sum([carre.valeurs[k][n-1-k] for k in range(n)]) != s:\n return False\n return ...\n
Tester la fonction est_magique
sur les carr\u00e9s c2, c3 et c4. ```
Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-211","title":"Exercice 21.1 \u25a1","text":"Exercice 21.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction multiplication
, prenant en param\u00e8tres deux nombres entiers n1
et n2
, et qui renvoie le produit de ces deux nombres. Les seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.
\u00c9nonc\u00e9 peu clair, on ne sait pas si n1
et n2
sont entiers naturels ou relatifs. Nous d\u00e9cidons qu'ils sont relatifs et donc qu'ils peuvent \u00eatre n\u00e9gatifs, auquel cas on utilise le fait que \\(5 \\times (-6)= - (5 \\times 6)\\).
def multiplication(n1, n2):\n if n1 < 0:\n return -multiplication(-n1, n2)\n if n2 < 0:\n return -multiplication(n1, -n2)\n resultat = 0\n for _ in range(n2):\n resultat += n1\n return resultat\n
Programmer la fonction `multiplication`, prenant en param\u00e8tres deux nombres entiers\n`n1` et `n2`, et qui renvoie le produit de ces deux nombres.\nLes seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-212","title":"Exercice 21.2 \u25a1","text":"Exercice 21.2
\u00c9nonc\u00e9CorrectionSources MarkdownRecopier et compl\u00e9ter sous Python la fonction suivante en respectant la sp\u00e9cification. On ne recopiera pas les commentaires.
def dichotomie(tab, x):\n\"\"\"\n tab : tableau d\u2019entiers tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\nFalse\n
def dichotomie(tab, x):\n\"\"\"\n tab : tableau d\u2019entiers tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = (debut + fin) // 2\n if x == tab[m]:\n return True\n if x > tab[m]:\n debut = m + 1\n else:\n fin = m - 1\n return False\n
Recopier et compl\u00e9ter sous Python la fonction suivante en respectant la sp\u00e9cification. On\nne recopiera pas les commentaires.\n\n```python linenums='1'\ndef dichotomie(tab, x):\n \"\"\"\n tab : tableau d\u2019entiers tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\nFalse\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-22","title":"\u25b6 Sujet 22","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-221","title":"Exercice 22.1 \u25a1","text":"Exercice 22.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer une fonction renverse
, prenant en param\u00e8tre une cha\u00eene de caract\u00e8res non vide mot
et renvoie une cha\u00eene de caract\u00e8res en inversant ceux de la cha\u00eene mot
.
Exemple :
>>> renverse(\"informatique\")\n\"euqitamrofni\"\n
def renverse(mot):\n sol = ''\n for lettre in mot:\n sol = lettre + sol\n return sol\n
Programmer une fonction `renverse`, prenant en param\u00e8tre une cha\u00eene de caract\u00e8res non vide\n`mot` et renvoie une cha\u00eene de caract\u00e8res en inversant ceux de la cha\u00eene `mot`.\n\nExemple :\n\n```python\n>>> renverse(\"informatique\")\n\"euqitamrofni\"\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-222","title":"Exercice 22.2 \u25a1","text":"Exercice 22.2
\u00c9nonc\u00e9CorrectionSources MarkdownUn nombre premier est un nombre entier naturel qui admet exactement deux diviseurs distincts entiers et positifs : 1 et lui-m\u00eame.
Le crible d\u2019\u00c9ratosth\u00e8ne permet de d\u00e9terminer les nombres premiers plus petit qu\u2019un certain nombre N fix\u00e9.
On consid\u00e8re pour cela un tableau tab
de N bool\u00e9ens, initialement tous \u00e9gaux \u00e0 True
, sauf tab[0]
et tab[1]
qui valent False
, 0 et 1 n\u2019\u00e9tant pas des nombres premiers.
On parcourt alors ce tableau de gauche \u00e0 droite.
Pour chaque indice i
:
si tab[i]
vaut True
: le nombre i
est premier et on donne la valeur False
\u00e0 toutes les cases du tableau dont l\u2019indice est un multiple de i
, \u00e0 partir de 2*i
(c\u2019est-\u00e0-dire 2*i
, 3*i
...).
si tab[i]
vaut False
: le nombre i
n\u2019est pas premier et on n\u2019effectue aucun changement sur le tableau.
On dispose de la fonction crible
, incompl\u00e8te et donn\u00e9e ci-dessous, prenant en param\u00e8tre un entier N strictement positif et renvoyant un tableau contenant tous les nombres premiers plus petits que N.
def crible(N):\n\"\"\"\n Renvoie un tableau contenant tous les nombres premiers plus petits que N\n \"\"\"\n premiers = []\n tab = [True] * N\n tab[0], tab[1] = False, False\n for i in range(..., N):\n if tab[i] == ...:\n premiers.append(...)\n for multiple in range(2*i, N, ...):\n tab[multiple] = ...\n return premiers\n\nassert crible(40) == [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]\n
Compl\u00e9ter le code de cette fonction.
def crible(N):\n\"\"\"\n Renvoie un tableau contenant tous les nombres premiers plus petits que N\n \"\"\"\n premiers = []\n tab = [True] * N\n tab[0], tab[1] = False, False\n for i in range(2, N):\n if tab[i] == True:\n premiers.append(i)\n for multiple in range(2*i, N, i):\n tab[multiple] = False\n return premiers\n\nassert crible(40) == [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]\n
Un nombre premier est un nombre entier naturel qui admet exactement deux diviseurs distincts\nentiers et positifs : 1 et lui-m\u00eame. \n\nLe crible d\u2019\u00c9ratosth\u00e8ne permet de d\u00e9terminer les nombres premiers plus petit qu\u2019un certain\nnombre N fix\u00e9. \n\nOn consid\u00e8re pour cela un tableau `tab` de N bool\u00e9ens, initialement tous \u00e9gaux \u00e0 `True`, sauf\n`tab[0]` et `tab[1]` qui valent `False`, 0 et 1 n\u2019\u00e9tant pas des nombres premiers. \n\nOn parcourt alors ce tableau de gauche \u00e0 droite. \n\nPour chaque indice `i` :\n\n- si `tab[i]` vaut `True` : le nombre `i` est premier et on donne la valeur `False` \u00e0 toutes les\ncases du tableau dont l\u2019indice est un multiple de `i`, \u00e0 partir de `2*i` (c\u2019est-\u00e0-dire `2*i`, `3*i` ...).\n\n- si `tab[i]` vaut `False` : le nombre `i` n\u2019est pas premier et on n\u2019effectue aucun\nchangement sur le tableau. \n\nOn dispose de la fonction `crible`, incompl\u00e8te et donn\u00e9e ci-dessous, prenant en param\u00e8tre un\nentier N strictement positif et renvoyant un tableau contenant tous les nombres premiers plus\npetits que N.\n\n```python linenums='1'\ndef crible(N):\n \"\"\"\n Renvoie un tableau contenant tous les nombres premiers plus petits que N\n \"\"\"\n premiers = []\n tab = [True] * N\n tab[0], tab[1] = False, False\n for i in range(..., N):\n if tab[i] == ...:\n premiers.append(...)\n for multiple in range(2*i, N, ...):\n tab[multiple] = ...\n return premiers\n\nassert crible(40) == [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]\n
Compl\u00e9ter le code de cette fonction.
```
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-23","title":"\u25b6 Sujet 23","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-231","title":"Exercice 23.1 \u25a1","text":"Exercice 23.1
\u00c9nonc\u00e9CorrectionSource MarkdownSur le r\u00e9seau social TipTop, on s\u2019int\u00e9resse au nombre de \u00ab like \u00bb des abonn\u00e9s. Les donn\u00e9es sont stock\u00e9es dans des dictionnaires o\u00f9 les cl\u00e9s sont les pseudos et les valeurs correspondantes sont les nombres de \u00ab like \u00bb comme ci-dessous :
{'Bob': 102, 'Ada': 201, 'Alice': 103, 'Tim': 50}
\u00c9crire une fonction max_dico
qui :
dico
non vide dont les cl\u00e9s sont des cha\u00eenes de caract\u00e8res et les valeurs associ\u00e9es sont des entiers ;Exemples :
>>> max_dico({'Bob': 102, 'Ada': 201, 'Alice': 103, 'Tim': 50})\n('Ada', 201)\n>>> max_dico({'Alan': 222, 'Ada': 201, 'Eve': 220, 'Tim': 50})\n('Alan', 222)\n
def max_dico(dico):\n cle_max = ''\n val_max = 0\n for cle in dico:\n if dico[cle] > val_max:\n val_max = dico[cle]\n cle_max = cle\n return (cle_max, val_max)\n
Sur le r\u00e9seau social TipTop, on s\u2019int\u00e9resse au nombre de \u00ab like \u00bb des abonn\u00e9s.\nLes donn\u00e9es sont stock\u00e9es dans des dictionnaires o\u00f9 les cl\u00e9s sont les pseudos et les valeurs\ncorrespondantes sont les nombres de \u00ab like \u00bb comme ci-dessous :\n\n`{'Bob': 102, 'Ada': 201, 'Alice': 103, 'Tim': 50}`\n\n\u00c9crire une fonction `max_dico` qui :\n\n- Prend en param\u00e8tre un dictionnaire `dico` non vide dont les cl\u00e9s sont des cha\u00eenes de\ncaract\u00e8res et les valeurs associ\u00e9es sont des entiers ;\n- Renvoie un tuple dont :\n - La premi\u00e8re valeur est la cl\u00e9 du dictionnaire associ\u00e9e \u00e0 la valeur maximale ;\n - La seconde valeur est la premi\u00e8re valeur maximale pr\u00e9sente dans le\ndictionnaire.\n\nExemples :\n\n```python\n>>> max_dico({'Bob': 102, 'Ada': 201, 'Alice': 103, 'Tim': 50})\n('Ada', 201)\n>>> max_dico({'Alan': 222, 'Ada': 201, 'Eve': 220, 'Tim': 50})\n('Alan', 222)\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-232","title":"Exercice 23.2 \u25a1","text":"Exercice 23.2
\u00c9nonc\u00e9CorrectionSources MarkdownNous avons l\u2019habitude de noter les expressions arithm\u00e9tiques avec des parenth\u00e8ses comme par exemple : (2 + 3) \u00d7 5.
Il existe une autre notation utilis\u00e9e par certaines calculatrices, appel\u00e9e notation postfixe, qui n\u2019utilise pas de parenth\u00e8ses. L\u2019expression arithm\u00e9tique pr\u00e9c\u00e9dente est alors obtenue en saisissant successivement 2, puis 3, puis l\u2019op\u00e9rateur +, puis 5, et enfin l\u2019op\u00e9rateur \u00d7. On mod\u00e9lise cette saisie par le tableau [2, 3, '+', 5, '*'].
Autre exemple, la notation postfixe de 3 \u00d7 2 + 5 est mod\u00e9lis\u00e9e par le tableau :
[3, 2, '*', 5, '+'].
D\u2019une mani\u00e8re plus g\u00e9n\u00e9rale, la valeur associ\u00e9e \u00e0 une expression arithm\u00e9tique en notation postfixe est d\u00e9termin\u00e9e \u00e0 l\u2019aide d\u2019une pile en parcourant l\u2019expression arithm\u00e9tique de gauche \u00e0 droite de la fa\u00e7on suivante :
Dans le cadre de cet exercice, on se limitera aux op\u00e9rations \u00d7 et +.
Pour cet exercice, on dispose d\u2019une classe Pile
qui impl\u00e9mente les m\u00e9thodes de base sur la structure de pile.
Compl\u00e9ter le script de la fonction eval_expression
qui re\u00e7oit en param\u00e8tre une liste python repr\u00e9sentant la notation postfixe d\u2019une expression arithm\u00e9tique et qui renvoie sa valeur associ\u00e9e.
Exemple :
>>> eval_expression([2, 3, '+', 5, '*'])\n25\n
class Pile:\n\"\"\"Classe d\u00e9finissant une structure de pile.\"\"\"\n def __init__(self):\n self.contenu = []\n\n def est_vide(self):\n\"\"\"Renvoie le bool\u00e9en True si la pile est vide, False sinon.\"\"\"\n return self.contenu == []\n\n def empiler(self, v):\n\"\"\"Place l'\u00e9l\u00e9ment v au sommet de la pile\"\"\"\n self.contenu.append(v)\n\n def depiler(self):\n\"\"\"\n Retire et renvoie l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile,\n si la pile n\u2019est pas vide.\n \"\"\"\n if not self.est_vide():\n return self.contenu.pop()\n\n\ndef eval_expression(tab):\n p = Pile()\n for ... in tab:\n if element != '+' ... element != '*':\n p.empiler(...)\n else:\n if element == ...:\n resultat = p.depiler() + ...\n else:\n resultat = ...\n p.empiler(...)\n return ...\n
class Pile:\n\"\"\"Classe d\u00e9finissant une structure de pile.\"\"\"\n def __init__(self):\n self.contenu = []\n\n def est_vide(self):\n\"\"\"Renvoie le bool\u00e9en True si la pile est vide, False sinon.\"\"\"\n return self.contenu == []\n\n def empiler(self, v):\n\"\"\"Place l'\u00e9l\u00e9ment v au sommet de la pile\"\"\"\n self.contenu.append(v)\n\n def depiler(self):\n\"\"\"\n Retire et renvoie l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile,\n si la pile n\u2019est pas vide.\n \"\"\"\n if not self.est_vide():\n return self.contenu.pop()\n\n\ndef eval_expression(tab):\n p = Pile()\n for element in tab:\n print(element)\n if element != '+' and element != '*':\n p.empiler(element)\n else:\n if element == '+':\n resultat = p.depiler() + p.depiler()\n else:\n resultat = p.depiler() * p.depiler()\n p.empiler(resultat)\n return p.depiler()\n
Nous avons l\u2019habitude de noter les expressions arithm\u00e9tiques avec des parenth\u00e8ses comme\npar exemple : (2 + 3) \u00d7 5. \n\nIl existe une autre notation utilis\u00e9e par certaines calculatrices, appel\u00e9e notation postfixe, qui n\u2019utilise pas de parenth\u00e8ses. L\u2019expression arithm\u00e9tique pr\u00e9c\u00e9dente est alors obtenue en\nsaisissant successivement 2, puis 3, puis l\u2019op\u00e9rateur +, puis 5, et enfin l\u2019op\u00e9rateur \u00d7. On\nmod\u00e9lise cette saisie par le tableau [2, 3, '+', 5, '*']. \n\nAutre exemple, la notation postfixe de 3 \u00d7 2 + 5 est mod\u00e9lis\u00e9e par le tableau : \n\n[3, 2, '*', 5, '+']. \n\n\nD\u2019une mani\u00e8re plus g\u00e9n\u00e9rale, la valeur associ\u00e9e \u00e0 une expression arithm\u00e9tique en notation\npostfixe est d\u00e9termin\u00e9e \u00e0 l\u2019aide d\u2019une pile en parcourant l\u2019expression arithm\u00e9tique de gauche\n\u00e0 droite de la fa\u00e7on suivante :\n\n- Si l\u2019\u00e9l\u00e9ment parcouru est un nombre, on le place au sommet de la pile ;\n- Si l\u2019\u00e9l\u00e9ment parcouru est un op\u00e9rateur, on r\u00e9cup\u00e8re les deux \u00e9l\u00e9ments situ\u00e9s au\nsommet de la pile et on leur applique l\u2019op\u00e9rateur. On place alors le r\u00e9sultat au sommet\nde la pile.\n- \u00c0 la fin du parcours, il reste alors un seul \u00e9l\u00e9ment dans la pile qui est le r\u00e9sultat de\nl\u2019expression arithm\u00e9tique.\n\n\nDans le cadre de cet exercice, on se limitera aux op\u00e9rations \u00d7 et +.\n\n\nPour cet exercice, on dispose d\u2019une classe `Pile` qui impl\u00e9mente les m\u00e9thodes de base sur la\nstructure de pile.\n\nCompl\u00e9ter le script de la fonction `eval_expression` qui re\u00e7oit en param\u00e8tre une liste python\nrepr\u00e9sentant la notation postfixe d\u2019une expression arithm\u00e9tique et qui renvoie sa valeur\nassoci\u00e9e.\n\nExemple :\n\n```python\n>>> eval_expression([2, 3, '+', 5, '*'])\n25\n
class Pile:\n\"\"\"Classe d\u00e9finissant une structure de pile.\"\"\"\n def __init__(self):\n self.contenu = []\n\n def est_vide(self):\n\"\"\"Renvoie le bool\u00e9en True si la pile est vide, False sinon.\"\"\"\n return self.contenu == []\n\n def empiler(self, v):\n\"\"\"Place l'\u00e9l\u00e9ment v au sommet de la pile\"\"\"\n self.contenu.append(v)\n\n def depiler(self):\n\"\"\"\n Retire et renvoie l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile,\n si la pile n\u2019est pas vide.\n \"\"\"\n if not self.est_vide():\n return self.contenu.pop()\n\n\ndef eval_expression(tab):\n p = Pile()\n for ... in tab:\n if element != '+' ... element != '*':\n p.empiler(...)\n else:\n if element == ...:\n resultat = p.depiler() + ...\n else:\n resultat = ...\n p.empiler(...)\n return ...\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-24","title":"\u25b6 Sujet 24","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-241","title":"Exercice 24.1 \u25a1","text":"Exercice 24.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire la fonction maxliste
, prenant en param\u00e8tre un tableau non vide de nombres tab
(type list
) et renvoyant le plus grand \u00e9l\u00e9ment de ce tableau.
Exemples :
>>> maxliste([98, 12, 104, 23, 131, 9])\n131\n>>> maxliste([-27, 24, -3, 15])\n24\n
def maxliste(tab):\n maximum = tab[0]\n for element in tab:\n if element > maximum:\n maximum = element\n return maximum\n
\u00c9crire la fonction `maxliste`, prenant en param\u00e8tre un tableau non vide de nombres `tab` (type\n`list`) et renvoyant le plus grand \u00e9l\u00e9ment de ce tableau.\n\nExemples :\n\n```python\n>>> maxliste([98, 12, 104, 23, 131, 9])\n131\n>>> maxliste([-27, 24, -3, 15])\n24\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-242","title":"Exercice 24.2 \u25a1","text":"Exercice 24.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn dispose de cha\u00eenes de caract\u00e8res contenant uniquement des parenth\u00e8ses ouvrantes et fermantes.
Un parenth\u00e9sage est correct si :
Ainsi, ((()())(()))
est un parenth\u00e9sage correct.
Les parenth\u00e9sages ())(()
et (())(()
sont, eux, incorrects.
On dispose du code de la classe Pile
suivant :
class Pile:\n\"\"\" Classe d\u00e9finissant une pile \"\"\"\n def __init__(self, valeurs=[]):\n self.valeurs = valeurs\n\n def est_vide(self):\n\"\"\"Renvoie True si la pile est vide, False sinon\"\"\"\n return self.valeurs == []\n\n def empiler(self, c):\n\"\"\"Place l\u2019\u00e9l\u00e9ment c au sommet de la pile\"\"\"\n self.valeurs.append(c)\n\n def depiler(self):\n\"\"\"Supprime l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile, \u00e0 condition qu\u2019elle soit non vide\"\"\"\n if self.est_vide() == False:\n self.valeurs.pop()\n
On souhaite programmer une fonction parenthesage qui prend en param\u00e8tre une cha\u00eene ch de parenth\u00e8ses et renvoie True
si la cha\u00eene est bien parenth\u00e9s\u00e9e et False
sinon. Cette fonction utilise une pile et suit le principe suivant : en parcourant la cha\u00eene de gauche \u00e0 droite, si on trouve une parenth\u00e8se ouvrante, on l\u2019empile au sommet de la pile et si on trouve une parenth\u00e8se fermante, on d\u00e9pile (si possible !) la parenth\u00e8se ouvrante stock\u00e9e au sommet de la pile.
La cha\u00eene est alors bien parenth\u00e9s\u00e9e si, \u00e0 la fin du parcours, la pile est vide.
Elle est, par contre, mal parenth\u00e9s\u00e9e :
def parenthesage(ch):\n\"\"\"Renvoie True si la cha\u00eene ch est bien parenth\u00e9s\u00e9e et False sinon\"\"\"\n p = Pile()\n for c in ch:\n if c == ...:\n p.empiler(c)\n elif c == ...:\n if p.est_vide():\n return ...\n else:\n ...\n return p.est_vide()\n\nassert parenthesage(\"((()())(()))\") == True\nassert parenthesage(\"())(()\") == False\nassert parenthesage(\"(())(()\") == False\n
Compl\u00e9ter le code de la fonction parenthesage
.
class Pile:\n\"\"\" Classe d\u00e9finissant une pile \"\"\"\n def __init__(self, valeurs=[]):\n self.valeurs = valeurs\n\n def est_vide(self):\n\"\"\"Renvoie True si la pile est vide, False sinon\"\"\"\n return self.valeurs == []\n\n def empiler(self, c):\n\"\"\"Place l\u2019\u00e9l\u00e9ment c au sommet de la pile\"\"\"\n self.valeurs.append(c)\n\n def depiler(self):\n\"\"\"Supprime l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile, \u00e0 condition qu\u2019elle soit non vide\"\"\"\n if self.est_vide() == False:\n self.valeurs.pop()\n\ndef parenthesage(ch):\n\"\"\"Renvoie True si la cha\u00eene ch est bien parenth\u00e9s\u00e9e et False sinon\"\"\"\n p = Pile()\n for c in ch:\n if c == '(':\n p.empiler(c)\n elif c == ')':\n if p.est_vide():\n return False\n else:\n p.depiler()\n return p.est_vide()\n\n\nprint(parenthesage(\"((()())(()))\"))\nassert parenthesage(\"((()())(()))\") == True\nassert parenthesage(\"())(()\") == False\nassert parenthesage(\"(())(()\") == False\n
On dispose de cha\u00eenes de caract\u00e8res contenant uniquement des parenth\u00e8ses ouvrantes et\nfermantes. \n\nUn parenth\u00e9sage est correct si :\n\n- le nombre de parenth\u00e8ses ouvrantes de la cha\u00eene est \u00e9gal au nombre de parenth\u00e8ses\nfermantes.\n- en parcourant la cha\u00eene de gauche \u00e0 droite, le nombre de parenth\u00e8ses d\u00e9j\u00e0 ouvertes doit\n\u00eatre, \u00e0 tout moment, sup\u00e9rieur ou \u00e9gal au nombre de parenth\u00e8ses d\u00e9j\u00e0 ferm\u00e9es.\n\n\nAinsi, `((()())(()))` est un parenth\u00e9sage correct. \n\nLes parenth\u00e9sages `())(()` et `(())(()` sont, eux, incorrects.\n\n\nOn dispose du code de la classe `Pile` suivant :\n\n```python linenums='1'\nclass Pile:\n \"\"\" Classe d\u00e9finissant une pile \"\"\"\n def __init__(self, valeurs=[]):\n self.valeurs = valeurs\n\n def est_vide(self):\n \"\"\"Renvoie True si la pile est vide, False sinon\"\"\"\n return self.valeurs == []\n\n def empiler(self, c):\n \"\"\"Place l\u2019\u00e9l\u00e9ment c au sommet de la pile\"\"\"\n self.valeurs.append(c)\n\n def depiler(self):\n \"\"\"Supprime l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile, \u00e0 condition qu\u2019elle soit non vide\"\"\"\n if self.est_vide() == False:\n self.valeurs.pop()\n
On souhaite programmer une fonction parenthesage qui prend en param\u00e8tre une cha\u00eene ch de parenth\u00e8ses et renvoie True
si la cha\u00eene est bien parenth\u00e9s\u00e9e et False
sinon. Cette fonction utilise une pile et suit le principe suivant : en parcourant la cha\u00eene de gauche \u00e0 droite, si on trouve une parenth\u00e8se ouvrante, on l\u2019empile au sommet de la pile et si on trouve une parenth\u00e8se fermante, on d\u00e9pile (si possible !) la parenth\u00e8se ouvrante stock\u00e9e au sommet de la pile.
La cha\u00eene est alors bien parenth\u00e9s\u00e9e si, \u00e0 la fin du parcours, la pile est vide.
Elle est, par contre, mal parenth\u00e9s\u00e9e :
def parenthesage(ch):\n\"\"\"Renvoie True si la cha\u00eene ch est bien parenth\u00e9s\u00e9e et False sinon\"\"\"\n p = Pile()\n for c in ch:\n if c == ...:\n p.empiler(c)\n elif c == ...:\n if p.est_vide():\n return ...\n else:\n ...\n return p.est_vide()\n\nassert parenthesage(\"((()())(()))\") == True\nassert parenthesage(\"())(()\") == False\nassert parenthesage(\"(())(()\") == False\n
Compl\u00e9ter le code de la fonction parenthesage
. ```
Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-251","title":"Exercice 25.1 \u25a1","text":"Exercice 25.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn consid\u00e8re des tables (des tableaux de dictionnaires) qui contiennent des enregistrements relatifs \u00e0 des animaux h\u00e9berg\u00e9s dans un refuge. Les attributs des enregistrements sont 'nom'
, 'espece'
, 'age'
, 'enclos'
. Voici un exemple d'une telle table :
animaux = [ {'nom':'Medor', 'espece':'chien', 'age':5, 'enclos':2},\n {'nom':'Titine', 'espece':'chat', 'age':2, 'enclos':5},\n {'nom':'Tom', 'espece':'chat', 'age':7, 'enclos':4},\n {'nom':'Belle', 'espece':'chien', 'age':6, 'enclos':3},\n {'nom':'Mirza', 'espece':'chat', 'age':6, 'enclos':5}]\n
Programmer une fonction selection_enclos
qui :
table_animaux
contenant des enregistrements relatifs \u00e0 des animaux (comme dans l'exemple ci-dessus),num_enclos
;table_animaux
dont l'attribut 'enclos'
est num_enclos
.Exemples avec la table animaux ci-dessus :
>>> selection_enclos(animaux, 5)\n[{'nom':'Titine', 'espece':'chat', 'age':2, 'enclos':5},\n {'nom':'Mirza', 'espece':'chat', 'age':6, 'enclos':5}]\n\n>>> selection_enclos(animaux, 2)\n[{'nom':'Medor', 'espece':'chien', 'age':5, 'enclos':2}]\n\n>>> selection_enclos(animaux, 7)\n[]\n
def selection_enclos(table_animaux, num_enclos):\n table = []\n for animal in table_animaux:\n if animal['enclos'] == num_enclos:\n table.append(animal)\n return table\n
On consid\u00e8re des tables (des tableaux de dictionnaires) qui contiennent des enregistrements\nrelatifs \u00e0 des animaux h\u00e9berg\u00e9s dans un refuge. Les attributs des enregistrements sont\n`'nom'`, `'espece'`, `'age'`, `'enclos'`. Voici un exemple d'une telle table :\n\n```python\nanimaux = [ {'nom':'Medor', 'espece':'chien', 'age':5, 'enclos':2},\n {'nom':'Titine', 'espece':'chat', 'age':2, 'enclos':5},\n {'nom':'Tom', 'espece':'chat', 'age':7, 'enclos':4},\n {'nom':'Belle', 'espece':'chien', 'age':6, 'enclos':3},\n {'nom':'Mirza', 'espece':'chat', 'age':6, 'enclos':5}]\n```\n\nProgrammer une fonction `selection_enclos` qui :\n\n- prend en param\u00e8tres :\n - une table `table_animaux` contenant des enregistrements relatifs \u00e0 des\nanimaux (comme dans l'exemple ci-dessus),\n - un num\u00e9ro d'enclos `num_enclos` ;\n- renvoie une table contenant les enregistrements de `table_animaux` dont l'attribut\n`'enclos'` est `num_enclos`.\n\nExemples avec la table animaux ci-dessus :\n\n```python\n>>> selection_enclos(animaux, 5)\n[{'nom':'Titine', 'espece':'chat', 'age':2, 'enclos':5},\n {'nom':'Mirza', 'espece':'chat', 'age':6, 'enclos':5}]\n\n>>> selection_enclos(animaux, 2)\n[{'nom':'Medor', 'espece':'chien', 'age':5, 'enclos':2}]\n\n>>> selection_enclos(animaux, 7)\n[]\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-252","title":"Exercice 25.2 \u25a1","text":"Exercice 25.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re des tableaux de nombres dont tous les \u00e9l\u00e9ments sont pr\u00e9sents exactement trois fois et \u00e0 suivre, sauf un \u00e9l\u00e9ment qui est pr\u00e9sent une unique fois et que l'on appelle \u00ab l'intrus \u00bb. Voici quelques exemples :
tab_a = [3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5, 5, 5]\n#l'intrus est 7\n\ntab_b = [8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3]\n#l'intrus est 8\n\ntab_c = [5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8, 8, 8]\n#l'intrus est 3\n
On remarque qu'avec de tels tableaux : Ce que l'on peut observer ci-dessous en observant les valeurs des paires de voisins marqu\u00e9es par des caract\u00e8res ^ :
[3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5, 5, 5]\n ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^\n 0 3 6 9 12 15 18 21\n
Dans des listes comme celles ci-dessus, un algorithme r\u00e9cursif pour trouver l'intrus consiste alors \u00e0 choisir un indice i
multiple de 3 situ\u00e9 approximativement au milieu des indices parmi lesquels se trouve l'intrus.
Puis, en fonction des valeurs de l'\u00e9l\u00e9ment d'indice i
et de son voisin de droite, \u00e0 appliquer r\u00e9cursivement l'algorithme \u00e0 la moiti\u00e9 droite ou \u00e0 la moiti\u00e9 gauche des indices parmi lesquels se trouve l'intrus.
Compl\u00e9ter la fonction ci-dessous qui met en \u0153uvre cet algorithme.
def trouver_intrus(tab, g, d):\n'''\n Renvoie la valeur de l'intrus situ\u00e9 entre les indices g et d \n dans la liste tab o\u00f9 \n tab v\u00e9rifie les conditions de l'exercice,\n g et d sont des multiples de 3.\n '''\n if g == d:\n return ...\n\n else:\n nombre_de_triplets = (d - g) // ...\n indice = g + 3 * (nombre_de_triplets // 2)\n if ... :\n return ...\n else:\n return ...\n
Exemples :
>>> trouver_intrus([3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8,\n8, 5, 5, 5], 0, 21)\n7\n\n>>> trouver_intrus([8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3], 0, 12)\n8\n\n>>> trouver_intrus([5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8, 8, 8], 0, 15)\n3\n
def trouver_intrus(tab, g, d):\n'''\n Renvoie la valeur de l'intrus situ\u00e9 entre les indices g et d \n dans la liste tab o\u00f9 tab v\u00e9rifie les conditions de l'exercice,\n g et d sont des multiples de 3.\n '''\n if g == d:\n return tab[g]\n\n else:\n nombre_de_triplets = (d - g) // 3\n indice = g + 3 * (nombre_de_triplets // 2)\n if tab[indice] != tab[indice + 1] :\n return trouver_intrus(tab, g, indice)\n else:\n return trouver_intrus(tab, indice + 3, d)\n
On consid\u00e8re des tableaux de nombres dont tous les \u00e9l\u00e9ments sont pr\u00e9sents exactement\ntrois fois et \u00e0 suivre, sauf un \u00e9l\u00e9ment qui est pr\u00e9sent une unique fois et que l'on appelle \u00ab\nl'intrus \u00bb. Voici quelques exemples :\n\n```python\ntab_a = [3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5, 5, 5]\n#l'intrus est 7\n\ntab_b = [8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3]\n#l'intrus est 8\n\ntab_c = [5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8, 8, 8]\n#l'intrus est 3\n
On remarque qu'avec de tels tableaux : Ce que l'on peut observer ci-dessous en observant les valeurs des paires de voisins marqu\u00e9es par des caract\u00e8res ^ :
[3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5, 5, 5]\n ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^\n 0 3 6 9 12 15 18 21\n
Dans des listes comme celles ci-dessus, un algorithme r\u00e9cursif pour trouver l'intrus consiste alors \u00e0 choisir un indice i
multiple de 3 situ\u00e9 approximativement au milieu des indices parmi lesquels se trouve l'intrus.
Puis, en fonction des valeurs de l'\u00e9l\u00e9ment d'indice i
et de son voisin de droite, \u00e0 appliquer r\u00e9cursivement l'algorithme \u00e0 la moiti\u00e9 droite ou \u00e0 la moiti\u00e9 gauche des indices parmi lesquels se trouve l'intrus.
Compl\u00e9ter la fonction ci-dessous qui met en \u0153uvre cet algorithme.
def trouver_intrus(tab, g, d):\n'''\n Renvoie la valeur de l'intrus situ\u00e9 entre les indices g et d \n dans la liste tab o\u00f9 \n tab v\u00e9rifie les conditions de l'exercice,\n g et d sont des multiples de 3.\n '''\n if g == d:\n return ...\n\n else:\n nombre_de_triplets = (d - g) // ...\n indice = g + 3 * (nombre_de_triplets // 2)\n if ... :\n return ...\n else:\n return ...\n
Exemples :
>>> trouver_intrus([3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8,\n8, 5, 5, 5], 0, 21)\n7\n\n>>> trouver_intrus([8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3], 0, 12)\n8\n\n>>> trouver_intrus([5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8, 8, 8], 0, 15)\n3\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-26","title":"\u25b6 Sujet 26","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-261","title":"Exercice 26.1 \u25a1","text":"Exercice 26.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction RechercheMin
qui prend en param\u00e8tre un tableau de nombres non tri\u00e9 tab
, et qui renvoie l'indice de la premi\u00e8re occurrence du minimum de ce tableau. Les tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.
Exemples :
>>> RechercheMin([5])\n0\n>>> RechercheMin([2, 4, 1])\n2\n>>> RechercheMin([5, 3, 2, 2, 4])\n2\n
def RechercheMin(tab):\n indice_min = 0\n for i in range(len(tab)):\n if tab[i] < tab[indice_min]:\n indice_min = i\n return indice_min\n
\u00c9crire une fonction `RechercheMin` qui prend en param\u00e8tre un tableau de nombres non\ntri\u00e9 `tab`, et qui renvoie l'indice de la premi\u00e8re occurrence du minimum de ce tableau. Les\ntableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.\n\nExemples :\n```python\n>>> RechercheMin([5])\n0\n>>> RechercheMin([2, 4, 1])\n2\n>>> RechercheMin([5, 3, 2, 2, 4])\n2\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-262","title":"Exercice 26.2 \u25a1","text":"Exercice 26.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re la fonction separe
ci-dessous qui prend en argument un tableau tab
dont les \u00e9l\u00e9ments sont des 0
et des 1
et qui s\u00e9pare les 0
des 1
en pla\u00e7ant les 0
en d\u00e9but de tableau et les 1
\u00e0 la suite.
def separe(tab):\n i = 0\n j = ...\n while i < j :\n if tab[i] == 0 :\n i = ...\n else :\n tab[i], tab[j] = ...\n j = ...\n return tab\n
Compl\u00e9ter la fonction separe
ci-dessus.
Exemples :
>>> separe([1, 0, 1, 0, 1, 0, 1, 0])\n[0, 0, 0, 0, 1, 1, 1, 1]\n>>> separe([1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0])\n[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\n
def separe(tab):\n i = 0\n j = len(tab) - 1\n while i < j :\n if tab[i] == 0 :\n i = i + 1\n else :\n tab[i], tab[j] = tab[j], tab[i]\n j = j - 1\n return tab\n
On consid\u00e8re la fonction `separe` ci-dessous qui prend en argument un tableau `tab` dont\nles \u00e9l\u00e9ments sont des `0` et des `1` et qui s\u00e9pare les `0` des `1` en pla\u00e7ant les `0` en d\u00e9but de\ntableau et les `1` \u00e0 la suite.\n\n```python linenums='1'\ndef separe(tab):\n i = 0\n j = ...\n while i < j :\n if tab[i] == 0 :\n i = ...\n else :\n tab[i], tab[j] = ...\n j = ...\n return tab\n
Compl\u00e9ter la fonction separe
ci-dessus.
Exemples :
>>> separe([1, 0, 1, 0, 1, 0, 1, 0])\n[0, 0, 0, 0, 1, 1, 1, 1]\n>>> separe([1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0])\n[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-27","title":"\u25b6 Sujet 27","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-271","title":"Exercice 27.1 \u25a1","text":"Exercice 27.1
\u00c9nonc\u00e9CorrectionSource MarkdownDans cet exercice, un arbre binaire de caract\u00e8res est stock\u00e9 sous la forme d\u2019un dictionnaire o\u00f9 les clefs sont les caract\u00e8res des n\u0153uds de l\u2019arbre et les valeurs, pour chaque clef, la liste des caract\u00e8res des fils gauche et droit du n\u0153ud.
Par exemple, l\u2019arbre
est stock\u00e9 dans
a = {'F':['B','G'], 'B':['A','D'], 'A':['',''], 'D':['C','E'], \\\n'C':['',''], 'E':['',''], 'G':['','I'], 'I':['','H'], \\\n'H':['','']}\n
\u00c9crire une fonction r\u00e9cursive taille
prenant en param\u00e8tres un arbre binaire arbre
sous la forme d\u2019un dictionnaire et un caract\u00e8re lettre
qui est la valeur du sommet de l\u2019arbre, et qui renvoie la taille de l\u2019arbre \u00e0 savoir le nombre total de n\u0153ud. On pourra distinguer les 4 cas o\u00f9 les deux \u00ab fils \u00bb du n\u0153ud sont ''
, le fils gauche seulement est ''
, le fils droit seulement est ''
, aucun des deux fils n\u2019est ''
.
Exemple :
>>> taille(a, \u2019F\u2019)\n9\n
a = {'F':['B','G'], 'B':['A','D'], 'A':['',''], 'D':['C','E'], 'C':['',''], 'E':['',''], 'G':['','I'], 'I':['','H'], 'H':['','']}\n\ndef taille(arbre, lettre):\n fils_gauche = arbre[lettre][0]\n fils_droit = arbre[lettre][1]\n\n if fils_gauche != '' and fils_droit != '':\n return 1 + taille(arbre, fils_gauche) + taille(arbre, fils_droit)\n\n if fils_gauche != '' and fils_droit == '':\n return 1 + taille(arbre, fils_gauche)\n\n if fils_gauche == '' and fils_droit != '':\n return 1 + taille(arbre, fils_droit)\n\n else:\n return 1\n
Dans cet exercice, un arbre binaire de caract\u00e8res est stock\u00e9 sous la forme d\u2019un\ndictionnaire o\u00f9 les clefs sont les caract\u00e8res des n\u0153uds de l\u2019arbre et les valeurs, pour\nchaque clef, la liste des caract\u00e8res des fils gauche et droit du n\u0153ud.\n\nPar exemple, l\u2019arbre\n\n![image](data/img28_1.png){: .center width=40%}\n\nest stock\u00e9 dans\n\n```python\na = {'F':['B','G'], 'B':['A','D'], 'A':['',''], 'D':['C','E'], \\\n'C':['',''], 'E':['',''], 'G':['','I'], 'I':['','H'], \\\n'H':['','']}\n```\n\n\u00c9crire une fonction r\u00e9cursive `taille` prenant en param\u00e8tres un arbre binaire `arbre`\nsous la forme d\u2019un dictionnaire et un caract\u00e8re `lettre` qui est la valeur du sommet de\nl\u2019arbre, et qui renvoie la taille de l\u2019arbre \u00e0 savoir le nombre total de n\u0153ud.\nOn pourra distinguer les 4 cas o\u00f9 les deux \u00ab fils \u00bb du n\u0153ud sont `''`, le fils gauche\nseulement est `''`, le fils droit seulement est `''`, aucun des deux fils n\u2019est `''`.\n\nExemple :\n```python\n>>> taille(a, \u2019F\u2019)\n9\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-272","title":"Exercice 27.2 \u25a1","text":"Exercice 27.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re l'algorithme de tri de tableau suivant : \u00e0 chaque \u00e9tape, on parcourt depuis le d\u00e9but du tableau tous les \u00e9l\u00e9ments non rang\u00e9s et on place en derni\u00e8re position le plus grand \u00e9l\u00e9ment.
Exemple avec le tableau : t = [41, 55, 21, 18, 12, 6, 25]
Le tableau devient t = [41, 25, 21, 18, 12, 6, 55]
Le tableau devient : t = [6, 25, 21, 18, 12, 41, 55]
Et ainsi de suite. La code de la fonction tri_iteratif
qui impl\u00e9mente cet algorithme est donn\u00e9 ci- dessous.
def tri_iteratif(tab):\n for k in range(..., 0 ,-1):\n imax = ...\n for i in range(0, ...):\n if tab[i] > ... :\n imax = i\n if tab[imax] > ... :\n ..., tab[imax] = tab[imax], ...\n return tab\n
Compl\u00e9ter le code qui doit donner :
>>> tri_iteratif([41, 55, 21, 18, 12, 6, 25])\n[6, 12, 18, 21, 25, 41, 55]\n
On rappelle que l'instruction a, b = b, a
\u00e9change les contenus de a
et b
.
def tri_iteratif(tab):\n for k in range(len(tab)-1, 0, -1):\n imax = 0\n for i in range(0, k):\n if tab[i] > tab[imax] :\n imax = i\n if tab[imax] > tab[k] :\n tab[k], tab[imax] = tab[imax], tab[k] \n return tab\n
On consid\u00e8re l'algorithme de tri de tableau suivant : \u00e0 chaque \u00e9tape, on parcourt depuis\nle d\u00e9but du tableau tous les \u00e9l\u00e9ments non rang\u00e9s et on place en derni\u00e8re position le plus\ngrand \u00e9l\u00e9ment.\n\nExemple avec le tableau : ```t = [41, 55, 21, 18, 12, 6, 25]``` \n\n- \u00c9tape 1 : on parcourt tous les \u00e9l\u00e9ments du tableau, on permute le plus grand \u00e9l\u00e9ment avec le dernier.\n\nLe tableau devient `t = [41, 25, 21, 18, 12, 6, 55]`\n\n- \u00c9tape 2 : on parcourt tous les \u00e9l\u00e9ments **sauf le dernier**, on permute le plus grand \u00e9l\u00e9ment trouv\u00e9 avec l'avant dernier.\n\nLe tableau devient : ```t = [6, 25, 21, 18, 12, 41, 55]``` \n\nEt ainsi de suite. La code de la fonction `tri_iteratif` qui impl\u00e9mente cet algorithme est donn\u00e9 ci-\ndessous.\n\n```python linenums='1'\ndef tri_iteratif(tab):\n for k in range(..., 0 ,-1):\n imax = ...\n for i in range(0, ...):\n if tab[i] > ... :\n imax = i\n if tab[imax] > ... :\n ..., tab[imax] = tab[imax], ...\n return tab\n
Compl\u00e9ter le code qui doit donner :
>>> tri_iteratif([41, 55, 21, 18, 12, 6, 25])\n[6, 12, 18, 21, 25, 41, 55]\n
On rappelle que l'instruction a, b = b, a
\u00e9change les contenus de a
et b
. ```
Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-281","title":"Exercice 28.1 \u25a1","text":"Exercice 28.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction moyenne
qui prend en param\u00e8tre un tableau non vide de nombres flottants et qui renvoie la moyenne des valeurs du tableau. Les tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.
Exemples :
>>> moyenne([1.0])\n1.0\n>>> moyenne([1.0, 2.0, 4.0])\n2.3333333333333335\n
def moyenne(tab):\n somme = 0\n for val in tab:\n somme += val\n return somme / len(tab)\n
\u00c9crire une fonction `moyenne` qui prend en param\u00e8tre un tableau non vide de nombres\nflottants et qui renvoie la moyenne des valeurs du tableau. Les tableaux seront\nrepr\u00e9sent\u00e9s sous forme de liste Python.\n\nExemples :\n```python\n>>> moyenne([1.0])\n1.0\n>>> moyenne([1.0, 2.0, 4.0])\n2.3333333333333335\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-282","title":"Exercice 28.2 \u25a1","text":"Exercice 28.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re la fonction dec_to_bin
ci-dessous qui prend en param\u00e8tre un entier positif a
en \u00e9criture d\u00e9cimale et qui renvoie son \u00e9criture binaire sous la forme d'une chaine de caract\u00e8res.
def dec_to_bin(a):\n bin_a = ...\n a = a//2\n while a ... :\n bin_a = ... + bin_a\n a = ...\n return bin_a\n
Compl\u00e9ter la fonction dec_to_bin
. Exemples :
>>> dec_to_bin(83)\n'1010011'\n>>> dec_to_bin(127)\n'1111111'\n
def dec_to_bin(a):\n bin_a = str(a%2)\n a = a // 2\n while a != 0 :\n bin_a = str(a%2) + bin_a\n a = a // 2\n return bin_a\n
On consid\u00e8re la fonction `dec_to_bin` ci-dessous qui prend en param\u00e8tre un entier positif `a` en \u00e9criture d\u00e9cimale et qui renvoie son \u00e9criture binaire sous la forme d'une chaine de caract\u00e8res.\n\n```python linenums='1'\ndef dec_to_bin(a):\n bin_a = ...\n a = a//2\n while a ... :\n bin_a = ... + bin_a\n a = ...\n return bin_a\n
Compl\u00e9ter la fonction dec_to_bin
. Exemples :
>>> dec_to_bin(83)\n'1010011'\n>>> dec_to_bin(127)\n'1111111'\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-29","title":"\u25b6 Sujet 29","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-291","title":"Exercice 29.1 \u25a1","text":"Exercice 29.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn s\u2019int\u00e9resse \u00e0 la suite d\u2019entiers d\u00e9finie par U1 = 1
, U2 = 1
et, pour tout entier naturel n
, par Un+2 = Un+1 + Un
.
Elle s\u2019appelle la suite de Fibonacci.
\u00c9crire la fonction fibonacci
qui prend un entier n > 0
et qui renvoie l\u2019\u00e9l\u00e9ment d\u2019indice n
de cette suite.
On utilisera une programmation dynamique (pas de r\u00e9cursivit\u00e9).
Exemple :
>>> fibonacci(1)\n1\n>>> fibonacci(2)\n1\n>>> fibonacci(25)\n75025\n>>> fibonacci(45)\n1134903170\n
On utilise un dictionnaire pour stocker au fur et \u00e0 mesure les valeurs.
def fibonnaci(n):\n d = {}\n d[1] = 1\n d[2] = 1\n for k in range(3, n+1):\n d[k] = d[k-1] + d[k-2]\n return d[n]\n
On s\u2019int\u00e9resse \u00e0 la suite d\u2019entiers d\u00e9finie par\n`U1 = 1`, `U2 = 1` et, pour tout entier naturel `n`, par `Un+2 = Un+1 + Un`.\n\nElle s\u2019appelle la suite de Fibonacci.\n\n\u00c9crire la fonction `fibonacci` qui prend un entier `n > 0` et qui renvoie l\u2019\u00e9l\u00e9ment d\u2019indice\n`n` de cette suite.\n\nOn utilisera une programmation dynamique (pas de r\u00e9cursivit\u00e9).\n\nExemple :\n\n```python\n>>> fibonacci(1)\n1\n>>> fibonacci(2)\n1\n>>> fibonacci(25)\n75025\n>>> fibonacci(45)\n1134903170\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-292","title":"Exercice 29.2 \u25a1","text":"Exercice 29.2
\u00c9nonc\u00e9CorrectionSources MarkdownLes variables liste_eleves
et liste_notes
ayant \u00e9t\u00e9 pr\u00e9alablement d\u00e9finies et \u00e9tant de m\u00eame longueur, la fonction meilleures_notes
renvoie la note maximale qui a \u00e9t\u00e9 attribu\u00e9e, le nombre d\u2019\u00e9l\u00e8ves ayant obtenu cette note et la liste des noms de ces \u00e9l\u00e8ves.
Compl\u00e9ter le code Python de la fonction meilleures_notes
ci-dessous.
liste_eleves = ['a','b','c','d','e','f','g','h','i','j']\nliste_notes = [1, 40, 80, 60, 58, 80, 75, 80, 60, 24]\n\ndef meilleures_notes():\n note_maxi = 0\n nb_eleves_note_maxi = ...\n liste_maxi = ...\n\n for compteur in range(...):\n if liste_notes[compteur] == ...:\n nb_eleves_note_maxi = nb_eleves_note_maxi + 1\n liste_maxi.append(liste_eleves[...])\n if liste_notes[compteur] > note_maxi:\n note_maxi = liste_notes[compteur]\n nb_eleves_note_maxi = ...\n liste_maxi = [...]\n\n return (note_maxi,nb_eleves_note_maxi,liste_maxi)\n
Une fois compl\u00e9t\u00e9, le code ci-dessus donne
>>> meilleures_notes()\n(80, 3, ['c', 'f', 'h'])\n
liste_eleves = ['a','b','c','d','e','f','g','h','i','j']\nliste_notes = [1, 40, 80, 60, 58, 80, 75, 80, 60, 24]\n\ndef meilleures_notes():\n note_maxi = 0\n nb_eleves_note_maxi = 0\n liste_maxi = []\n\n for compteur in range(len(liste_eleves)):\n if liste_notes[compteur] == note_maxi:\n nb_eleves_note_maxi = nb_eleves_note_maxi + 1\n liste_maxi.append(liste_eleves[compteur])\n if liste_notes[compteur] > note_maxi:\n note_maxi = liste_notes[compteur]\n nb_eleves_note_maxi = 1\n liste_maxi = [liste_eleves[compteur]]\n\n return (note_maxi,nb_eleves_note_maxi,liste_maxi)\n
Les variables `liste_eleves` et `liste_notes` ayant \u00e9t\u00e9 pr\u00e9alablement d\u00e9finies et \u00e9tant\nde m\u00eame longueur, la fonction `meilleures_notes` renvoie la note maximale qui a \u00e9t\u00e9\nattribu\u00e9e, le nombre d\u2019\u00e9l\u00e8ves ayant obtenu cette note et la liste des noms de ces \u00e9l\u00e8ves.\n\nCompl\u00e9ter le code Python de la fonction `meilleures_notes` ci-dessous.\n\n```python linenums='1'\nliste_eleves = ['a','b','c','d','e','f','g','h','i','j']\nliste_notes = [1, 40, 80, 60, 58, 80, 75, 80, 60, 24]\n\ndef meilleures_notes():\n note_maxi = 0\n nb_eleves_note_maxi = ...\n liste_maxi = ...\n\n for compteur in range(...):\n if liste_notes[compteur] == ...:\n nb_eleves_note_maxi = nb_eleves_note_maxi + 1\n liste_maxi.append(liste_eleves[...])\n if liste_notes[compteur] > note_maxi:\n note_maxi = liste_notes[compteur]\n nb_eleves_note_maxi = ...\n liste_maxi = [...]\n\n return (note_maxi,nb_eleves_note_maxi,liste_maxi)\n
Une fois compl\u00e9t\u00e9, le code ci-dessus donne
>>> meilleures_notes()\n(80, 3, ['c', 'f', 'h'])\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-30","title":"\u25b6 Sujet 30","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-301","title":"Exercice 30.1 \u25a1","text":"Exercice 30.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction fusion
prenant en param\u00e8tres deux tableaux non vides tab1
et tab2
(type list
) d'entiers, chacun dans l\u2019ordre croissant, et renvoyant un tableau tri\u00e9 dans l\u2019ordre croissant et contenant l\u2019ensemble des valeurs de tab1
et tab2
.
Exemples :
>>> fusion([3, 5], [2, 5])\n[2, 3, 5, 5]\n>>> fusion([-2, 4], [-3, 5, 10])\n[-3, -2, 4, 5, 10]\n>>> fusion([4], [2, 6])\n[2, 4, 6]\n
def fusion(tab1, tab2):\n tab_fusion = []\n i1 = 0\n i2 = 0\n while i1 < len(tab1) and i2 < len(tab2):\n if tab1[i1] < tab2[i2]:\n tab_fusion.append(tab1[i1])\n i1 += 1\n else:\n tab_fusion.append(tab2[i2])\n i2 += 1\n\n if i1 == len(tab1):\n while i2 < len(tab2):\n tab_fusion.append(tab2[i2])\n i2 += 1\n else:\n while i1 < len(tab1):\n tab_fusion.append(tab1[i1])\n i1 += 1 \n\n return tab_fusion\n
Programmer la fonction `fusion` prenant en param\u00e8tres deux tableaux non vides `tab1` et `tab2`\n(type `list`) d'entiers, chacun dans l\u2019ordre croissant, et renvoyant un tableau tri\u00e9 dans l\u2019ordre\ncroissant et contenant l\u2019ensemble des valeurs de `tab1` et `tab2`.\n\nExemples :\n\n```python\n>>> fusion([3, 5], [2, 5])\n[2, 3, 5, 5]\n>>> fusion([-2, 4], [-3, 5, 10])\n[-3, -2, 4, 5, 10]\n>>> fusion([4], [2, 6])\n[2, 4, 6]\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-302","title":"Exercice 30.2 \u25a1","text":"Exercice 30.2
\u00c9nonc\u00e9CorrectionSources MarkdownLes chiffres romains sont un syst\u00e8me ancien d\u2019\u00e9criture des nombres.
Les chiffres romains sont: I, V, X, L, C, D, et M. Ces symboles repr\u00e9sentent respectivement 1, 5, 10, 50, 100, 500, et 1000 en base dix.
Lorsque deux caract\u00e8res successifs sont tels que le caract\u00e8re plac\u00e9 \u00e0 gauche poss\u00e8de une valeur sup\u00e9rieure ou \u00e9gale \u00e0 celui de droite, le nombre s\u2019obtient en additionnant le caract\u00e8re de gauche \u00e0 la valeur de la cha\u00eene situ\u00e9e \u00e0 droite.
Ainsi, \"XVI\" est le nombre 16 car X + VI = 10 + 6.
Lorsque deux caract\u00e8res successifs sont tels que le caract\u00e8re plac\u00e9 \u00e0 gauche poss\u00e8de une valeur strictement inf\u00e9rieure \u00e0 celui de droite, le nombre s\u2019obtient en retranchant le caract\u00e8re de gauche \u00e0 la valeur de la cha\u00eene situ\u00e9e \u00e0 droite.
Ainsi, \"CDIII\" est le nombre 403 car DIII \u2013 C = 503 \u2013 100.
On dispose d\u2019un dictionnaire dico
, \u00e0 compl\u00e9ter, o\u00f9 les cl\u00e9s sont les caract\u00e8res apparaissant dans l\u2019\u00e9criture en chiffres romains et o\u00f9 les valeurs sont les nombres entiers associ\u00e9s en \u00e9criture d\u00e9cimale.
On souhaite cr\u00e9er une fonction r\u00e9cursive rom_to_dec
qui prend en param\u00e8tre une cha\u00eene de caract\u00e8res (non vide) repr\u00e9sentant un nombre \u00e9crit en chiffres romains et renvoyant le nombre associ\u00e9 en \u00e9criture d\u00e9cimale :
def rom_to_dec(nombre):\n\n\"\"\" Renvoie l\u2019\u00e9criture d\u00e9cimale du nombre donn\u00e9 en chiffres romains \"\"\"\n\n dico = {\"I\":1, \"V\":5, ...}\n if len(nombre) == 1:\n return ...\n\n else:\n ### on supprime le premier caract\u00e8re de la cha\u00eene contenue dans la variable nombre\n ### et cette nouvelle cha\u00eene est enregistr\u00e9e dans la variable nombre_droite\n nombre_droite = nombre[1:]\n\n\n if dico[nombre[0]] >= dico[nombre[1]]:\n return dico[nombre[0]] + ...\n else:\n return ...\n\nassert rom_to_dec(\"CXLII\") == 142\n
def rom_to_dec(nombre):\n\n\"\"\" Renvoie l\u2019\u00e9criture d\u00e9cimale du nombre donn\u00e9 en chiffres romains \"\"\"\n\n dico = {\"I\":1, \"V\":5, \"X\":10, \"L\":50, \"C\":100, \"D\":500, \"M\":1000}\n if len(nombre) == 1:\n return dico[nombre]\n\n else:\n ### on supprime le premier caract\u00e8re de la cha\u00eene contenue dans la variable nombre\n ### et cette nouvelle cha\u00eene est enregistr\u00e9e dans la variable nombre_droite\n nombre_droite = nombre[1:] # (1)\n\n\n if dico[nombre[0]] >= dico[nombre[1]]:\n return dico[nombre[0]] + rom_to_dec(nombre_droite)\n else:\n return rom_to_dec(nombre_droite) - dico[nombre[0]]\n\nassert rom_to_dec(\"CXLII\") == 142\n
Les chiffres romains sont un syst\u00e8me ancien d\u2019\u00e9criture des nombres.\n\n\nLes chiffres romains sont: I, V, X, L, C, D, et M.\nCes symboles repr\u00e9sentent respectivement 1, 5, 10, 50, 100, 500, et 1000 en base dix.\n\n\nLorsque deux caract\u00e8res successifs sont tels que le caract\u00e8re plac\u00e9 \u00e0 gauche poss\u00e8de une\nvaleur sup\u00e9rieure ou \u00e9gale \u00e0 celui de droite, le nombre s\u2019obtient en additionnant le caract\u00e8re de\ngauche \u00e0 la valeur de la cha\u00eene situ\u00e9e \u00e0 droite.\n\nAinsi, \"XVI\" est le nombre 16 car X + VI = 10 + 6.\n\n\nLorsque deux caract\u00e8res successifs sont tels que le caract\u00e8re plac\u00e9 \u00e0 gauche poss\u00e8de une\nvaleur strictement inf\u00e9rieure \u00e0 celui de droite, le nombre s\u2019obtient en retranchant le caract\u00e8re de\ngauche \u00e0 la valeur de la cha\u00eene situ\u00e9e \u00e0 droite.\n\n\nAinsi, \"CDIII\" est le nombre 403 car DIII \u2013 C = 503 \u2013 100.\n\n\nOn dispose d\u2019un dictionnaire `dico`, \u00e0 compl\u00e9ter, o\u00f9 les cl\u00e9s sont les caract\u00e8res apparaissant\ndans l\u2019\u00e9criture en chiffres romains et o\u00f9 les valeurs sont les nombres entiers associ\u00e9s en\n\u00e9criture d\u00e9cimale.\n\n\nOn souhaite cr\u00e9er une fonction r\u00e9cursive `rom_to_dec` qui prend en param\u00e8tre une cha\u00eene de\ncaract\u00e8res (non vide) repr\u00e9sentant un nombre \u00e9crit en chiffres romains et renvoyant le nombre\nassoci\u00e9 en \u00e9criture d\u00e9cimale :\n\n```python linenums='1'\ndef rom_to_dec(nombre):\n\n \"\"\" Renvoie l\u2019\u00e9criture d\u00e9cimale du nombre donn\u00e9 en chiffres romains \"\"\"\n\n dico = {\"I\":1, \"V\":5, ...}\n if len(nombre) == 1:\n return ...\n\n else:\n ### on supprime le premier caract\u00e8re de la cha\u00eene contenue dans la variable nombre\n ### et cette nouvelle cha\u00eene est enregistr\u00e9e dans la variable nombre_droite\n nombre_droite = nombre[1:]\n\n\n if dico[nombre[0]] >= dico[nombre[1]]:\n return dico[nombre[0]] + ...\n else:\n return ...\n\nassert rom_to_dec(\"CXLII\") == 142\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-31","title":"\u25b6 Sujet 31","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-311","title":"Exercice 31.1 \u25a1","text":"Exercice 31.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire en langage Python une fonction recherche
prenant comme param\u00e8tres une variable a
de type num\u00e9rique (float
ou int
) et un tableau t
(type list
) et qui renvoie le nombre d'occurrences de a
dans t
.
Exemples :
>>> recherche(5,[])\n0\n>>> recherche(5,[-2, 3, 4, 8])\n0\n>>> recherche(5,[-2, 3, 1, 5, 3, 7, 4])\n1\n>>> recherche(5,[-2, 5, 3, 5, 4, 5])\n3\n
def recherche(a, t):\n nb = 0\n for element in t:\n if element == a:\n nb += 1\n return nb\n
\u00c9crire en langage Python une fonction `recherche` prenant comme param\u00e8tres une\nvariable `a` de type num\u00e9rique (`float` ou `int`) et un tableau `t` (type `list`) et qui\nrenvoie le nombre d'occurrences de `a` dans `t`.\n\nExemples :\n```python\n>>> recherche(5,[])\n0\n>>> recherche(5,[-2, 3, 4, 8])\n0\n>>> recherche(5,[-2, 3, 1, 5, 3, 7, 4])\n1\n>>> recherche(5,[-2, 5, 3, 5, 4, 5])\n3\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-312","title":"Exercice 31.2 \u25a1","text":"Exercice 31.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa fonction rendu_monnaie_centimes
prend en param\u00e8tres deux nombres entiers positifs s_due
ets_versee
et elle permet de proc\u00e9der au rendu de monnaie de la diff\u00e9rence s_versee \u2013 s_due
pour des achats effectu\u00e9s avec le syst\u00e8me de pi\u00e8ces de la zone Euro. On utilise pour cela un algorithme qui commence par rendre le maximum de pi\u00e8ces de plus grandes valeurs et ainsi de suite. La fonction renvoie la liste des pi\u00e8ces qui composent le rendu.
Toutes les sommes sont exprim\u00e9es en centimes d\u2019euros. Les valeurs possibles pour les pi\u00e8ces sont donc [1, 2, 5, 10, 20, 50, 100, 200]
.
Ainsi, l\u2019instruction rendu_monnaie_centimes(452, 500)
renverra [20, 20, 5, 2, 1]
.
En effet, la somme \u00e0 rendre est de 48
centimes soit 20 + 20 + 5 + 2 + 1
. Le code de la fonction est donn\u00e9 ci-dessous :
def rendu_monnaie_centimes(s_due, s_versee):\n pieces = [1, 2, 5, 10, 20, 50, 100, 200]\n rendu = ...\n a_rendre = ...\n i = len(pieces) - 1\n while a_rendre > ... :\n if pieces[i] <= a_rendre :\n rendu.append(...)\n a_rendre = ...\n else :\n i = ...\n return rendu\n
Compl\u00e9ter ce code pour qu'il donne :
>>> rendu_monnaie_centimes(700,700)\n[]\n>>> rendu_monnaie_centimes(112,500)\n[200, 100, 50, 20, 10, 5, 2, 1]\n
def rendu_monnaie_centimes(s_due, s_versee):\n pieces = [1, 2, 5, 10, 20, 50, 100, 200]\n rendu = []\n a_rendre = s_versee - s_due\n i = len(pieces) - 1\n while a_rendre > 0 :\n if pieces[i] <= a_rendre :\n rendu.append(pieces[i])\n a_rendre = a_rendre - pieces[i]\n else :\n i = i - 1\n return rendu\n
La fonction `rendu_monnaie_centimes` prend en param\u00e8tres deux nombres entiers\npositifs `s_due` et` s_versee` et elle permet de proc\u00e9der au rendu de monnaie de la\ndiff\u00e9rence `s_versee \u2013 s_due` pour des achats effectu\u00e9s avec le syst\u00e8me de pi\u00e8ces de\nla zone Euro. On utilise pour cela un algorithme qui commence par rendre le maximum de\npi\u00e8ces de plus grandes valeurs et ainsi de suite. La fonction renvoie la liste des pi\u00e8ces qui\ncomposent le rendu.\n\nToutes les sommes sont exprim\u00e9es en centimes d\u2019euros. Les valeurs possibles pour les\npi\u00e8ces sont donc `[1, 2, 5, 10, 20, 50, 100, 200]`.\n\nAinsi, l\u2019instruction `rendu_monnaie_centimes(452, 500)`\nrenverra\n`[20, 20, 5, 2, 1]`.\n\nEn effet, la somme \u00e0 rendre est de `48` centimes soit `20 + 20 + 5 + 2 + 1`.\nLe code de la fonction est donn\u00e9 ci-dessous :\n\n```python linenums='1'\ndef rendu_monnaie_centimes(s_due, s_versee):\n pieces = [1, 2, 5, 10, 20, 50, 100, 200]\n rendu = ...\n a_rendre = ...\n i = len(pieces) - 1\n while a_rendre > ... :\n if pieces[i] <= a_rendre :\n rendu.append(...)\n a_rendre = ...\n else :\n i = ...\n return rendu\n
Compl\u00e9ter ce code pour qu'il donne :
>>> rendu_monnaie_centimes(700,700)\n[]\n>>> rendu_monnaie_centimes(112,500)\n[200, 100, 50, 20, 10, 5, 2, 1]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-32","title":"\u25b6 Sujet 32","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-321","title":"Exercice 32.1 \u25a1","text":"Exercice 32.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche
qui prend en param\u00e8tres elt
un nombre entier et tab
un tableau de nombres entiers, et qui renvoie l\u2019indice de la premi\u00e8re occurrence de elt
dans tab
si elt
est dans tab
et -1
sinon.
Exemples :
>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(50, [1, 50, 1])\n1\n>>> recherche(15, [8, 9, 10, 15])\n3\n
def recherche(elt, tab):\n for i in range(len(tab)):\n if tab[i] == elt:\n return i\n return -1\n
\u00c9crire une fonction `recherche` qui prend en param\u00e8tres `elt` un nombre entier et `tab`\nun tableau de nombres entiers, et qui renvoie l\u2019indice de la premi\u00e8re occurrence de `elt`\ndans `tab` si `elt` est dans `tab` et `-1` sinon.\n\nExemples :\n```python\n>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(50, [1, 50, 1])\n1\n>>> recherche(15, [8, 9, 10, 15])\n3\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-322","title":"Exercice 32.2 \u25a1","text":"Exercice 32.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn d\u00e9finit une classe g\u00e9rant une adresse IPv4. On rappelle qu\u2019une adresse IPv4 est une adresse de longueur 4 octets, not\u00e9e en d\u00e9cimale \u00e0 point, en s\u00e9parant chacun des octets par un point. On consid\u00e8re un r\u00e9seau priv\u00e9 avec une plage d\u2019adresses IP de 192.168.0.0
\u00e0 192.168.0.255
.
On consid\u00e8re que les adresses IP saisies sont valides.
Les adresses IP 192.168.0.0
et 192.168.0.255
sont des adresses r\u00e9serv\u00e9es.
Le code ci-dessous impl\u00e9mente la classe AdresseIP
.
class AdresseIP:\n def __init__(self, adresse):\n self.adresse = ...\n\n def liste_octet(self):\n\"\"\"renvoie une liste de nombres entiers,\n la liste des octets de l'adresse IP\"\"\"\n return [int(i) for i in self.adresse.split(\".\")]\n\n def est_reservee(self):\n\"\"\"renvoie True si l'adresse IP est une adresse\n r\u00e9serv\u00e9e, False sinon\"\"\"\n return ... or ...\n\n def adresse_suivante(self):\n\"\"\"renvoie un objet de AdresseIP avec l'adresse\n IP qui suit l\u2019adresse self\n si elle existe et False sinon\"\"\"\n if ... < 254:\n octet_nouveau = ... + ...\n return AdresseIP('192.168.0.' + ...)\n else:\n return False\n
Compl\u00e9ter le code ci-dessus et instancier trois objets : adresse1
, adresse2
, adresse3
avec respectivement les arguments suivants : '192.168.0.1'
, '192.168.0.2'
, '192.168.0.0'
V\u00e9rifier que :
>>> adresse1.est_reservee()\nFalse\n>>> adresse3.est_reservee()\nTrue\n>>> adresse2.adresse_suivante().adresse\n'192.168.0.3'\n
class AdresseIP:\n def __init__(self, adresse):\n self.adresse = adresse\n\n def liste_octet(self):\n\"\"\"renvoie une liste de nombres entiers,\n la liste des octets de l'adresse IP\"\"\"\n return [int(i) for i in self.adresse.split(\".\")]\n\n def est_reservee(self):\n\"\"\"renvoie True si l'adresse IP est une adresse\n r\u00e9serv\u00e9e, False sinon\"\"\"\n return self.liste_octet()[3] == 0 or self.liste_octet()[3] == 255\n\n def adresse_suivante(self):\n\"\"\"renvoie un objet de AdresseIP avec l'adresse\n IP qui suit l\u2019adresse self\n si elle existe et False sinon\"\"\"\n if self.liste_octet()[3] < 254:\n octet_nouveau = self.liste_octet()[3] + 1\n return AdresseIP('192.168.0.' + str(octet_nouveau))\n else:\n return False\n\nadresse1 = AdresseIP('192.168.0.1')\nadresse2 = AdresseIP('192.168.0.2')\nadresse3 = AdresseIP('192.168.0.0')\n
On d\u00e9finit une classe g\u00e9rant une adresse IPv4.\nOn rappelle qu\u2019une adresse IPv4 est une adresse de longueur 4 octets, not\u00e9e en d\u00e9cimale\n\u00e0 point, en s\u00e9parant chacun des octets par un point. On consid\u00e8re un r\u00e9seau priv\u00e9 avec\nune plage d\u2019adresses IP de `192.168.0.0` \u00e0 `192.168.0.255`.\n\nOn consid\u00e8re que les adresses IP saisies sont valides.\n\nLes adresses IP `192.168.0.0` et `192.168.0.255` sont des adresses r\u00e9serv\u00e9es.\n\nLe code ci-dessous impl\u00e9mente la classe `AdresseIP`.\n\n```python linenums='1'\nclass AdresseIP:\n def __init__(self, adresse):\n self.adresse = ...\n\n def liste_octet(self):\n \"\"\"renvoie une liste de nombres entiers,\n la liste des octets de l'adresse IP\"\"\"\n return [int(i) for i in self.adresse.split(\".\")]\n\n def est_reservee(self):\n \"\"\"renvoie True si l'adresse IP est une adresse\n r\u00e9serv\u00e9e, False sinon\"\"\"\n return ... or ...\n\n def adresse_suivante(self):\n \"\"\"renvoie un objet de AdresseIP avec l'adresse\n IP qui suit l\u2019adresse self\n si elle existe et False sinon\"\"\"\n if ... < 254:\n octet_nouveau = ... + ...\n return AdresseIP('192.168.0.' + ...)\n else:\n return False\n
Compl\u00e9ter le code ci-dessus et instancier trois objets : adresse1
, adresse2
, adresse3
avec respectivement les arguments suivants : '192.168.0.1'
, '192.168.0.2'
, '192.168.0.0'
V\u00e9rifier que :
>>> adresse1.est_reservee()\nFalse\n>>> adresse3.est_reservee()\nTrue\n>>> adresse2.adresse_suivante().adresse\n'192.168.0.3'\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-33","title":"\u25b6 Sujet 33","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-331","title":"Exercice 33.1 \u25a1","text":"Exercice 33.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn mod\u00e9lise la repr\u00e9sentation binaire d'un entier non sign\u00e9 par un tableau d'entiers dont les \u00e9l\u00e9ments sont 0 ou 1. Par exemple, le tableau [1, 0, 1, 0, 0, 1, 1]
repr\u00e9sente l'\u00e9criture binaire de l'entier dont l'\u00e9criture d\u00e9cimale est 2**6 + 2**4 + 2**1 + 2**0 = 83
.
\u00c0 l'aide d'un parcours s\u00e9quentiel, \u00e9crire la fonction convertir r\u00e9pondant aux sp\u00e9cifications suivantes :
def convertir(T):\n\"\"\"\n T est un tableau d'entiers, dont les \u00e9l\u00e9ments sont 0 ou 1 et\n repr\u00e9sentant un entier \u00e9crit en binaire. Renvoie l'\u00e9criture\n d\u00e9cimale de l'entier positif dont la repr\u00e9sentation binaire\n est donn\u00e9e par le tableau T\n \"\"\"\n
Exemple : >>> convertir([1, 0, 1, 0, 0, 1, 1])\n83\n>>> convertir([1, 0, 0, 0, 0, 0, 1, 0])\n130\n
def convertir(T):\n puissance = 0\n total = 0\n for i in range(len(T)-1, -1, -1):\n total += T[i]*(2**puissance)\n puissance += 1\n return total\n
On mod\u00e9lise la repr\u00e9sentation binaire d'un entier non sign\u00e9 par un tableau d'entiers dont\nles \u00e9l\u00e9ments sont 0 ou 1. Par exemple, le tableau `[1, 0, 1, 0, 0, 1, 1]` repr\u00e9sente\nl'\u00e9criture binaire de l'entier dont l'\u00e9criture d\u00e9cimale est\n`2**6 + 2**4 + 2**1 + 2**0 = 83`.\n\n\u00c0 l'aide d'un parcours s\u00e9quentiel, \u00e9crire la fonction convertir r\u00e9pondant aux\nsp\u00e9cifications suivantes :\n\n```python\ndef convertir(T):\n \"\"\"\n T est un tableau d'entiers, dont les \u00e9l\u00e9ments sont 0 ou 1 et\n repr\u00e9sentant un entier \u00e9crit en binaire. Renvoie l'\u00e9criture\n d\u00e9cimale de l'entier positif dont la repr\u00e9sentation binaire\n est donn\u00e9e par le tableau T\n \"\"\"\n```\nExemple :\n```python\n>>> convertir([1, 0, 1, 0, 0, 1, 1])\n83\n>>> convertir([1, 0, 0, 0, 0, 0, 1, 0])\n130\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-332","title":"Exercice 33.2 \u25a1","text":"Exercice 33.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa fonction tri_insertion
suivante prend en argument une liste L
et trie cette liste en utilisant la m\u00e9thode du tri par insertion. Compl\u00e9ter cette fonction pour qu'elle r\u00e9ponde \u00e0 la sp\u00e9cification demand\u00e9e.
def tri_insertion(L):\n n = len(L)\n\n # cas du tableau vide\n if ...:\n return L\n for j in range(1,n):\n e = L[j]\n i = j\n\n # A l'\u00e9tape j, le sous-tableau L[0,j-1] est tri\u00e9\n # et on ins\u00e8re L[j] dans ce sous-tableau en d\u00e9terminant\n # le plus petit i tel que 0 <= i <= j et L[i-1] > L[j].\n\n while i > 0 and L[i-1] > ...:\n i = ...\n\n # si i != j, on d\u00e9cale le sous tableau L[i,j-1] d\u2019un cran\n # vers la droite et on place L[j] en position i\n\n if i != j:\n for k in range(j,i,...):\n L[k] = L[...]\n L[i] = ...\n return L\n
Exemples :
>>> tri_insertion([2,5,-1,7,0,28])\n[-1, 0, 2, 5, 7, 28]\n>>> tri_insertion([10,9,8,7,6,5,4,3,2,1,0])\n[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n
def tri_insertion(L):\n n = len(L)\n\n # cas du tableau vide\n if L == []:\n return L\n\n for j in range(1,n):\n e = L[j]\n i = j\n\n # A l'\u00e9tape j, le sous-tableau L[0,j-1] est tri\u00e9\n # et on ins\u00e8re L[j] dans ce sous-tableau en d\u00e9terminant\n # le plus petit i tel que 0 <= i <= j et L[i-1] > L[j].\n\n while i > 0 and L[i-1] > e:\n i = i - 1\n\n # si i != j, on d\u00e9cale le sous tableau L[i,j-1] d\u2019un cran\n # vers la droite et on place L[j] en position i\n\n if i != j:\n for k in range(j,i,-1):\n L[k] = L[k-1]\n L[i] = e\n return L\n
La fonction `tri_insertion` suivante prend en argument une liste `L` et trie cette liste en\nutilisant la m\u00e9thode du tri par insertion. Compl\u00e9ter cette fonction pour qu'elle r\u00e9ponde \u00e0 la\nsp\u00e9cification demand\u00e9e.\n\n```python linenums='1'\ndef tri_insertion(L):\n n = len(L)\n\n # cas du tableau vide\n if ...:\n return L\n for j in range(1,n):\n e = L[j]\n i = j\n\n # A l'\u00e9tape j, le sous-tableau L[0,j-1] est tri\u00e9\n # et on ins\u00e8re L[j] dans ce sous-tableau en d\u00e9terminant\n # le plus petit i tel que 0 <= i <= j et L[i-1] > L[j].\n\n while i > 0 and L[i-1] > ...:\n i = ...\n\n # si i != j, on d\u00e9cale le sous tableau L[i,j-1] d\u2019un cran\n # vers la droite et on place L[j] en position i\n\n if i != j:\n for k in range(j,i,...):\n L[k] = L[...]\n L[i] = ...\n return L\n
Exemples :
>>> tri_insertion([2,5,-1,7,0,28])\n[-1, 0, 2, 5, 7, 28]\n>>> tri_insertion([10,9,8,7,6,5,4,3,2,1,0])\n[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-34","title":"\u25b6 Sujet 34","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-341","title":"Exercice 34.1 \u25a1","text":"Exercice 34.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction occurrence_max
prenant en param\u00e8tres une cha\u00eene de caract\u00e8res chaine
et qui renvoie le caract\u00e8re le plus fr\u00e9quent de la cha\u00eene. La chaine ne contient que des lettres en minuscules sans accent. On pourra s\u2019aider du tableau
alphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
et du tableau occurrence
de 26 \u00e9l\u00e9ments o\u00f9 l\u2019on mettra dans occurrence[i]
le nombre d\u2019apparitions de alphabet[i]
dans la chaine. Puis on calculera l\u2019indice k
d\u2019un maximum du tableau occurrence
et on affichera alphabet[k]
.
Exemple :
>>> ch = 'je suis en terminale et je passe le bac et je souhaite poursuivre des etudes pour devenir expert en informatique'\n>>> occurrence_max(ch)\n\u2018e\u2019\n
alphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o,','p','q','r','s','t','u','v','w','x','y','z']\n\ndef occurrence_max(chaine):\n occurence = [0] * 26\n for i in range(26):\n compteur = 0\n for caractere in chaine:\n if caractere == alphabet[i]:\n compteur += 1\n occurence[i] = compteur\n ind_max = 0\n for i in range(26):\n if occurence[i] > occurence[ind_max]:\n ind_max = i\n return alphabet[ind_max]\n
\u00c9crire une fonction `occurrence_max` prenant en param\u00e8tres une cha\u00eene de caract\u00e8res\n`chaine` et qui renvoie le caract\u00e8re le plus fr\u00e9quent de la cha\u00eene. La chaine ne contient\nque des lettres en minuscules sans accent.\nOn pourra s\u2019aider du tableau\n\n`alphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']`\n\net du tableau `occurrence` de 26 \u00e9l\u00e9ments o\u00f9 l\u2019on mettra dans `occurrence[i]` le\nnombre d\u2019apparitions de `alphabet[i]` dans la chaine. \nPuis on calculera l\u2019indice `k` d\u2019un maximum du tableau `occurrence` et on affichera `alphabet[k]`.\n\nExemple :\n```python\n>>> ch = 'je suis en terminale et je passe le bac et je souhaite poursuivre des etudes pour devenir expert en informatique'\n>>> occurrence_max(ch)\n\u2018e\u2019\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-342","title":"Exercice 34.2 \u25a1","text":"Exercice 34.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re une image en 256 niveaux de gris que l\u2019on repr\u00e9sente par une grille de nombres, c\u2019est-\u00e0-dire une liste compos\u00e9e de sous-listes toutes de longueurs identiques. La largeur de l\u2019image est donc la longueur d\u2019une sous-liste et la hauteur de l\u2019image est le nombre de sous-listes.
Chaque sous-liste repr\u00e9sente une ligne de l\u2019image et chaque \u00e9l\u00e9ment des sous-listes est un entier compris entre 0 et 255, repr\u00e9sentant l\u2019intensit\u00e9 lumineuse du pixel.
Compl\u00e9ter le programme ci-dessous :
def nbLig(image):\n'''renvoie le nombre de lignes de l'image'''\n return ...\n\ndef nbCol(image):\n'''renvoie la largeur de l'image'''\n return ...\n\ndef negatif(image):\n'''renvoie le n\u00e9gatif de l'image sous la forme d'une liste de listes'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9\u00e9 une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(...):\n L[i][j] = ...\n return L\n\ndef binaire(image, seuil):\n'''renvoie une image binaris\u00e9e de l'image sous la forme\n d'une liste de listes contenant des 0 si la valeur\n du pixel est strictement inf\u00e9rieure au seuil\n et 1 sinon'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9e une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(...):\n if image[i][j] < ... :\n L[i][j] = ...\n else:\n L[i][j] = ...\n return L \n
Exemple :
>>> img = [[20, 34, 254, 145, 6], [23, 124, 287, 225, 69], [197, 174, 207, 25, 87], [255, 0, 24, 197, 189]]\n>>> nbLig(img)\n4\n>>> nbCol(img)\n5\n>>> negatif(img)\n[[235, 221, 1, 110, 249], [232, 131, -32, 30, 186], [58, 81, 48, 230, 168], [0, 255, 231, 58, 66]]\n>>> binaire(negatif(img),120)\n[[1, 1, 0, 0, 1], [1, 1, 0, 0, 1], [0, 0, 0, 1, 1], [0, 1, 1, 0, 0]]\n
def nbLig(image):\n'''renvoie le nombre de lignes de l'image'''\n return len(image)\n\ndef nbCol(image):\n'''renvoie la largeur de l'image'''\n return len(image[0])\n\ndef negatif(image):\n'''renvoie le n\u00e9gatif de l'image sous la forme d'une liste de listes'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9\u00e9 une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(nbCol(image)):\n L[i][j] = 255-image[i][j]\n return L\n\ndef binaire(image, seuil):\n'''renvoie une image binaris\u00e9e de l'image sous la forme\n d'une liste de listes contenant des 0 si la valeur\n du pixel est strictement inf\u00e9rieure au seuil\n et 1 sinon'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9e une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(nbCol(image)):\n if image[i][j] < seuil :\n L[i][j] = 0\n else:\n L[i][j] = 1\n return L \n
On consid\u00e8re une image en 256 niveaux de gris que l\u2019on repr\u00e9sente par une grille de\nnombres, c\u2019est-\u00e0-dire une liste compos\u00e9e de sous-listes toutes de longueurs identiques.\nLa largeur de l\u2019image est donc la longueur d\u2019une sous-liste et la hauteur de l\u2019image est le\nnombre de sous-listes.\n\nChaque sous-liste repr\u00e9sente une ligne de l\u2019image et chaque \u00e9l\u00e9ment des sous-listes est\nun entier compris entre 0 et 255, repr\u00e9sentant l\u2019intensit\u00e9 lumineuse du pixel.\n\nCompl\u00e9ter le programme ci-dessous :\n\n```python linenums='1'\ndef nbLig(image):\n '''renvoie le nombre de lignes de l'image'''\n return ...\n\ndef nbCol(image):\n '''renvoie la largeur de l'image'''\n return ...\n\ndef negatif(image):\n '''renvoie le n\u00e9gatif de l'image sous la forme d'une liste de listes'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9\u00e9 une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(...):\n L[i][j] = ...\n return L\n\ndef binaire(image, seuil):\n '''renvoie une image binaris\u00e9e de l'image sous la forme\n d'une liste de listes contenant des 0 si la valeur\n du pixel est strictement inf\u00e9rieure au seuil\n et 1 sinon'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9e une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(...):\n if image[i][j] < ... :\n L[i][j] = ...\n else:\n L[i][j] = ...\n return L \n
Exemple :
>>> img = [[20, 34, 254, 145, 6], [23, 124, 287, 225, 69], [197, 174, 207, 25, 87], [255, 0, 24, 197, 189]]\n>>> nbLig(img)\n4\n>>> nbCol(img)\n5\n>>> negatif(img)\n[[235, 221, 1, 110, 249], [232, 131, -32, 30, 186], [58, 81, 48, 230, 168], [0, 255, 231, 58, 66]]\n>>> binaire(negatif(img),120)\n[[1, 1, 0, 0, 1], [1, 1, 0, 0, 1], [0, 0, 0, 1, 1], [0, 1, 1, 0, 0]]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-35","title":"\u25b6 Sujet 35","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-351","title":"Exercice 35.1 \u25a1","text":"Exercice 35.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction qui prend en param\u00e8tre un tableau d'entiers non vide et qui renvoie la moyenne de ces entiers. La fonction est sp\u00e9cifi\u00e9e ci-apr\u00e8s et doit passer les assertions fournies.
def moyenne (tab):\n'''\n moyenne(list) -> float\n Entr\u00e9e : un tableau non vide d'entiers\n Sortie : nombre de type float\n Correspondant \u00e0 la moyenne des valeurs pr\u00e9sentes dans le\n tableau\n '''\n\nassert moyenne([1]) == 1\nassert moyenne([1, 2, 3, 4, 5, 6, 7] == 4\nassert moyenne([1, 2]) == 1.5\n
def moyenne(tab):\n'''\n moyenne(list) -> float\n Entr\u00e9e : un tableau non vide d'entiers\n Sortie : nombre de type float\n Correspondant \u00e0 la moyenne des valeurs pr\u00e9sentes dans le\n tableau\n '''\n somme = 0\n for elt in tab:\n somme += elt\n return somme / len(tab)\n
\u00c9crire une fonction qui prend en param\u00e8tre un tableau d'entiers non vide et qui renvoie la\nmoyenne de ces entiers. La fonction est sp\u00e9cifi\u00e9e ci-apr\u00e8s et doit passer les assertions\nfournies.\n```python\ndef moyenne (tab):\n '''\n moyenne(list) -> float\n Entr\u00e9e : un tableau non vide d'entiers\n Sortie : nombre de type float\n Correspondant \u00e0 la moyenne des valeurs pr\u00e9sentes dans le\n tableau\n '''\n\nassert moyenne([1]) == 1\nassert moyenne([1, 2, 3, 4, 5, 6, 7] == 4\nassert moyenne([1, 2]) == 1.5\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-352","title":"Exercice 35.2 \u25a1","text":"Exercice 35.2
\u00c9nonc\u00e9CorrectionSources MarkdownLe but de l'exercice est de compl\u00e9ter une fonction qui d\u00e9termine si une valeur est pr\u00e9sente dans un tableau de valeurs tri\u00e9es dans l'ordre croissant.
L'algorithme traite le cas du tableau vide.
L'algorithme est \u00e9crit pour que la recherche dichotomique ne se fasse que dans le cas o\u00f9 la valeur est comprise entre les valeurs extr\u00eames du tableau.
On distingue les trois cas qui renvoient False
en renvoyant False, 1
, False, 2
et False, 3
.
Compl\u00e9ter l'algorithme de dichotomie donn\u00e9 ci-apr\u00e8s.
def dichotomie(tab, x):\n\"\"\"\n tab : tableau tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n # cas du tableau vide\n if ...:\n return False,1\n # cas o\u00f9 x n'est pas compris entre les valeurs extr\u00eames\n if (x < tab[0]) or ...:\n return False, 2\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\n(False, 3)\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],1)\n(False, 2)\n>>> dichotomie([],28)\n(False, 1)\n
def dichotomie(tab, x):\n\"\"\"\n tab : tableau tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n # cas du tableau vide\n if tab = []:\n return False, 1\n # cas o\u00f9 x n'est pas compris entre les valeurs extr\u00eames\n if (x < tab[0]) or (x > tab[-1]):\n return False, 2\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = (debut + fin) // 2\n if x == tab[m]:\n return True\n if x > tab[m]:\n debut = m + 1\n else:\n fin = m - 1\n return False, 3\n
Le but de l'exercice est de compl\u00e9ter une fonction qui d\u00e9termine si une valeur est pr\u00e9sente\ndans un tableau de valeurs tri\u00e9es dans l'ordre croissant.\n\nL'algorithme traite le cas du tableau vide.\n\nL'algorithme est \u00e9crit pour que la recherche dichotomique ne se fasse que dans le cas o\u00f9\nla valeur est comprise entre les valeurs extr\u00eames du tableau.\n\nOn distingue les trois cas qui renvoient `False` en renvoyant `False, 1` , `False, 2` et\n`False, 3`.\n\nCompl\u00e9ter l'algorithme de dichotomie donn\u00e9 ci-apr\u00e8s.\n\n```python linenums='1'\ndef dichotomie(tab, x):\n \"\"\"\n tab : tableau tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n # cas du tableau vide\n if ...:\n return False,1\n # cas o\u00f9 x n'est pas compris entre les valeurs extr\u00eames\n if (x < tab[0]) or ...:\n return False, 2\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\n(False, 3)\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],1)\n(False, 2)\n>>> dichotomie([],28)\n(False, 1)\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-36","title":"\u25b6 Sujet 36","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-361","title":"Exercice 36.1 \u25a1","text":"Exercice 36.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction recherche
, prenant en param\u00e8tre un tableau non vide tab
(type list
) d'entiers et un entier n
, et qui renvoie l'indice de la derni\u00e8re occurrence de l'\u00e9l\u00e9ment cherch\u00e9. Si l'\u00e9l\u00e9ment n'est pas pr\u00e9sent, la fonction renvoie la longueur du tableau.
Exemples
>>> recherche([5, 3],1)\n2\n>>> recherche([2,4],2)\n0\n>>> recherche([2,3,5,2,4],2)\n3\n
def recherche(tab, n):\n indice_solution = len(tab)\n for i in range(len(tab)):\n if tab[i] == n:\n indice_solution = i\n return indice_solution\n
Programmer la fonction `recherche`, prenant en param\u00e8tre un tableau non vide `tab` (type `list`) d'entiers et un entier `n`, et qui renvoie l'indice de la **derni\u00e8re** occurrence de l'\u00e9l\u00e9ment cherch\u00e9. Si l'\u00e9l\u00e9ment n'est pas pr\u00e9sent, la fonction renvoie la longueur du tableau.\n\nExemples\n```python\n>>> recherche([5, 3],1)\n2\n>>> recherche([2,4],2)\n0\n>>> recherche([2,3,5,2,4],2)\n3\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-362","title":"Exercice 36.2 \u25a1","text":"Exercice 36.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn souhaite programmer une fonction donnant la distance la plus courte entre un point de d\u00e9part et une liste de points. Les points sont tous \u00e0 coordonn\u00e9es enti\u00e8res. Les points sont donn\u00e9s sous la forme d'un tuple de deux entiers. La liste des points \u00e0 traiter est donc un tableau de tuples.
On rappelle que la distance entre deux points du plan de coordonn\u00e9es \\((x;y)\\) et \\((x';y')\\) est donn\u00e9e par la formule :
\\[d=\\sqrt{(x-x')^2+(y-y')^2}\\]On importe pour cela la fonction racine carr\u00e9e (sqrt
) du module math
de Python.
On dispose d'une fonction distance
et d'une fonction plus_courte_distance
:
from math import sqrt # import de la fonction racine carr\u00e9e\n\ndef distance(point1, point2):\n\"\"\" Calcule et renvoie la distance entre deux points. \"\"\"\n return sqrt((...)**2 + (...)**2)\n\nassert distance((1, 0), (5, 3)) == 5.0, \"erreur de calcul\"\n\ndef plus_courte_distance(tab, depart):\n\"\"\" Renvoie le point du tableau tab se trouvant \u00e0 la plus courte distance du point depart.\"\"\"\n point = tab[0]\n min_dist = ...\n for i in range (1, ...):\n if distance(tab[i], depart)...:\n point = ...\n min_dist = ...\n return point\n\nassert plus_courte_distance([(7, 9), (2, 5), (5, 2)], (0, 0)) == (2, 5), \"erreur\"\n
Recopier sous Python (sans les commentaires) ces deux fonctions puis compl\u00e9ter leur code et ajouter une ou des d\u00e9clarations (assert
) \u00e0 la fonction distance
permettant de v\u00e9rifier la ou les pr\u00e9conditions. from math import sqrt\n\ndef distance(point1, point2):\n\"\"\" Calcule et renvoie la distance entre deux points. \"\"\"\n assert int(point1[0]) == point1[0], \"coordonn\u00e9e non enti\u00e8re\"\n assert int(point1[1]) == point1[1], \"coordonn\u00e9e non enti\u00e8re\"\n assert int(point2[0]) == point2[0], \"coordonn\u00e9e non enti\u00e8re\"\n assert int(point2[1]) == point2[1], \"coordonn\u00e9e non enti\u00e8re\"\n return sqrt((point1[0] - point2[0])**2 + ((point1[1] - point2[1]))**2)\n\nassert distance((1, 0), (5, 3)) == 5.0, \"erreur de calcul\"\n\n\ndef plus_courte_distance(tab, depart):\n\"\"\" Renvoie le point du tableau tab se trouvant \u00e0 la plus courte distance du point depart.\"\"\"\n point = tab[0]\n min_dist = distance(point, depart)\n for i in range (1, len(tab)):\n if distance(tab[i], depart) < min_dist:\n point = tab[i]\n min_dist = distance(tab[i], depart)\n return point\n\nassert plus_courte_distance([(7, 9), (2, 5), (5, 2)], (0, 0)) == (2, 5), \"erreur\"\n
On souhaite programmer une fonction donnant la distance la plus courte entre un point\nde d\u00e9part et une liste de points. Les points sont tous \u00e0 coordonn\u00e9es enti\u00e8res.\nLes points sont donn\u00e9s sous la forme d'un tuple de deux entiers.\nLa liste des points \u00e0 traiter est donc un tableau de tuples.\n\nOn rappelle que la distance entre deux points du plan de coordonn\u00e9es $(x;y)$ et $(x';y')$\nest donn\u00e9e par la formule :\n\n$$d=\\sqrt{(x-x')^2+(y-y')^2}$$\n\nOn importe pour cela la fonction racine carr\u00e9e (`sqrt`) du module `math` de Python.\n\nOn dispose d'une fonction `distance` et d'une fonction `plus_courte_distance` :\n\n```python\nfrom math import sqrt # import de la fonction racine carr\u00e9e\n\ndef distance(point1, point2):\n \"\"\" Calcule et renvoie la distance entre deux points. \"\"\"\n return sqrt((...)**2 + (...)**2)\n\nassert distance((1, 0), (5, 3)) == 5.0, \"erreur de calcul\"\n\ndef plus_courte_distance(tab, depart):\n \"\"\" Renvoie le point du tableau tab se trouvant \u00e0 la plus courte distance du point depart.\"\"\"\n point = tab[0]\n min_dist = ...\n for i in range (1, ...):\n if distance(tab[i], depart)...:\n point = ...\n min_dist = ...\n return point\n\nassert plus_courte_distance([(7, 9), (2, 5), (5, 2)], (0, 0)) == (2, 5), \"erreur\"\n
Recopier sous Python (sans les commentaires) ces deux fonctions puis compl\u00e9ter leur code et ajouter une ou des d\u00e9clarations (assert
) \u00e0 la fonction distance
permettant de v\u00e9rifier la ou les pr\u00e9conditions. ``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-37","title":"\u25b6 Sujet 37","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-371","title":"Exercice 37.1 \u25a1","text":"Exercice 37.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction verifie
qui prend en param\u00e8tre un tableau de valeurs num\u00e9riques non vide et qui renvoie True
si ce tableau est tri\u00e9 dans l\u2019ordre croissant, False
sinon.
Exemples :
Exemples :\n>>> verifie([0, 5, 8, 8, 9])\nTrue\n>>> verifie([8, 12, 4])\nFalse\n>>> verifie([-1, 4])\nTrue\n>>> verifie([5])\nTrue\n
def verifie(tab):\n for i in range(1, len(tab)):\n if tab[i] < tab[i-1]:\n return False\n return True\n
Programmer la fonction `verifie` qui prend en param\u00e8tre un tableau de valeurs num\u00e9riques non\nvide et qui renvoie `True` si ce tableau est tri\u00e9 dans l\u2019ordre croissant, `False` sinon.\n\nExemples :\n\n```python\nExemples :\n>>> verifie([0, 5, 8, 8, 9])\nTrue\n>>> verifie([8, 12, 4])\nFalse\n>>> verifie([-1, 4])\nTrue\n>>> verifie([5])\nTrue\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-372","title":"Exercice 37.2 \u25a1","text":"Exercice 37.2
\u00c9nonc\u00e9CorrectionSources MarkdownChaque soir, les auditeurs d\u2019une radio votent en ligne pour leur artiste favori. Ces votes sont stock\u00e9s dans un tableau.
Exemple :
urne = ['A', 'A', 'A', 'B', 'C', 'B', 'C', 'B', 'C', 'B']\n
La fonction depouille
doit permettre de compter le nombre de votes exprim\u00e9s pour chaque artiste. Elle prend en param\u00e8tre un tableau et renvoie le r\u00e9sultat dans un dictionnaire dont les cl\u00e9s sont les noms des artistes et les valeurs le nombre de votes en leur faveur.
La fonction vainqueur doit d\u00e9signer le nom du ou des gagnants. Elle prend en param\u00e8tre un dictionnaire dont la structure est celle du dictionnaire renvoy\u00e9 par la fonction depouille
et renvoie un tableau. Ce tableau peut donc contenir plusieurs \u00e9l\u00e9ments s\u2019il y a des artistes ex- aequo. Compl\u00e9ter les fonctions depouille
et vainqueur ci-apr\u00e8s pour qu\u2019elles renvoient les r\u00e9sultats attendus.
urne = ['A', 'A', 'A','B', 'C', 'B', 'C','B', 'C', 'B']\n\ndef depouille(urne):\n resultat = ...\n for bulletin in urne:\n if ...:\n resultat[bulletin] = resultat[bulletin] + 1\n else:\n ...\n return resultat\n\ndef vainqueur(election):\n vainqueur = ''\n nmax = 0\n for candidat in election:\n if ... > ... :\n nmax = ...\n vainqueur = candidat\n liste_finale = [nom for nom in election if election[nom] == ...]\n return ...\n
Exemples d\u2019utilisation :
>>> election = depouille(urne)\n>>> election\n{'A': 3, 'B': 4, 'C': 3} # (1)\n>>> vainqueur(election)\n['B']\n
urne = ['A', 'A', 'A', 'B', 'C', 'B', 'C', 'B', 'C', 'B']\n\ndef depouille(urne):\n resultat = {}\n for bulletin in urne:\n if bulletin in resultat:\n resultat[bulletin] = resultat[bulletin] + 1\n else:\n resultat[bulletin] = 1\n return resultat\n\ndef vainqueur(election):\n vainqueur = '' #(1)\n nmax = 0\n for candidat in election:\n if election[candidat] > nmax :\n nmax = election[candidat]\n vainqueur = candidat #(2)\n liste_finale = [nom for nom in election if election[nom] == nmax]\n return liste_finale\n
vainqueur
est inutile, on ne s'en sert pas dans l'\u00e9laboration de la liste finale.Chaque soir, les auditeurs d\u2019une radio votent en ligne pour leur artiste favori. Ces votes sont\nstock\u00e9s dans un tableau.\n\nExemple :\n\n```python\nurne = ['A', 'A', 'A', 'B', 'C', 'B', 'C', 'B', 'C', 'B']\n
La fonction depouille
doit permettre de compter le nombre de votes exprim\u00e9s pour chaque artiste. Elle prend en param\u00e8tre un tableau et renvoie le r\u00e9sultat dans un dictionnaire dont les cl\u00e9s sont les noms des artistes et les valeurs le nombre de votes en leur faveur.
La fonction vainqueur doit d\u00e9signer le nom du ou des gagnants. Elle prend en param\u00e8tre un dictionnaire dont la structure est celle du dictionnaire renvoy\u00e9 par la fonction depouille
et renvoie un tableau. Ce tableau peut donc contenir plusieurs \u00e9l\u00e9ments s\u2019il y a des artistes ex- aequo. Compl\u00e9ter les fonctions depouille
et vainqueur ci-apr\u00e8s pour qu\u2019elles renvoient les r\u00e9sultats attendus.
urne = ['A', 'A', 'A','B', 'C', 'B', 'C','B', 'C', 'B']\n\ndef depouille(urne):\n resultat = ...\n for bulletin in urne:\n if ...:\n resultat[bulletin] = resultat[bulletin] + 1\n else:\n ...\n return resultat\n\ndef vainqueur(election):\n vainqueur = ''\n nmax = 0\n for candidat in election:\n if ... > ... :\n nmax = ...\n vainqueur = candidat\n liste_finale = [nom for nom in election if election[nom] == ...]\n return ...\n
Exemples d\u2019utilisation :
>>> election = depouille(urne)\n>>> election\n{'A': 3, 'B': 4, 'C': 3} # (1)\n>>> vainqueur(election)\n['B']\n
Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-381","title":"Exercice 38.1 \u25a1","text":"Exercice 38.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction tri_selection
qui prend en param\u00e8tre une liste tab
de nombres entiers et qui renvoie le tableau tri\u00e9 par ordre croissant.
On utilisera l\u2019algorithme suivant :
Exemple :
>>> tri_selection([1,52,6,-9,12])\n[-9, 1, 6, 12, 52]\n
def tri_selection(tab):\n for i in range(len(tab)-1):\n indice_min = i\n for j in range(i+1, len(tab)):\n if tab[j] < tab[indice_min]:\n indice_min = j\n tab[i], tab[indice_min] = tab[indice_min], tab[i]\n return tab\n
\u00c9crire une fonction `tri_selection` qui prend en param\u00e8tre une liste `tab` de nombres\nentiers et qui renvoie le tableau tri\u00e9 par ordre croissant.\n\nOn utilisera l\u2019algorithme suivant :\n\n- on recherche le plus petit \u00e9l\u00e9ment du tableau, et on l'\u00e9change avec l'\u00e9l\u00e9ment d'indice 0 ;\n- on recherche le second plus petit \u00e9l\u00e9ment du tableau, et on l'\u00e9change avec l'\u00e9l\u00e9ment\nd'indice 1 ;\n- on continue de cette fa\u00e7on jusqu'\u00e0 ce que le tableau soit enti\u00e8rement tri\u00e9.\n\nExemple :\n```python\n>>> tri_selection([1,52,6,-9,12])\n[-9, 1, 6, 12, 52]\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-382","title":"Exercice 38.2 \u25a1","text":"Exercice 38.2
\u00c9nonc\u00e9CorrectionSources MarkdownLe jeu du \u00ab plus ou moins \u00bb consiste \u00e0 deviner un nombre entier choisi entre 1 et 99. Un \u00e9l\u00e8ve de NSI d\u00e9cide de le coder en langage Python de la mani\u00e8re suivante :
La fonction randint
est utilis\u00e9e. Si a et b sont des entiers, randint(a,b)
renvoie un nombre entier compris entre a
et b
. Compl\u00e9ter le code ci-dessous et le tester :
from random import randint\n\ndef plus_ou_moins():\n nb_mystere = randint(1,...)\n nb_test = int(input(\"Proposez un nombre entre 1 et 99 : \"))\n compteur = ...\n\n while nb_mystere != ... and compteur < ... :\n compteur = compteur + ...\n if nb_mystere ... nb_test:\n nb_test = int(input(\"Trop petit ! Testez encore : \"))\n else:\n nb_test = int(input(\"Trop grand ! Testez encore : \"))\n\n if nb_mystere == nb_test:\n print (\"Bravo ! Le nombre \u00e9tait \",...)\n print(\"Nombre d'essais: \",...)\n else:\n print (\"Perdu ! Le nombre \u00e9tait \",...)\n
from random import randint\n\ndef plus_ou_moins():\n nb_mystere = randint(1,99)\n nb_test = int(input('Proposez un nombre entre 1 et 99 : '))\n compteur = 1\n\n while nb_mystere != nb_test and compteur < 10 :\n compteur = compteur + 1\n if nb_mystere > nb_test:\n nb_test = int(input('Trop petit ! Testez encore : '))\n else:\n nb_test = int(input('Trop grand ! Testez encore : '))\n\n if nb_mystere == nb_test:\n print ('Bravo ! Le nombre \u00e9tait ', nb_mystere)\n print('Nombre d essais: ', compteur)\n else:\n print ('Perdu ! Le nombre \u00e9tait ', nb_mystere)\n
Le jeu du \u00ab plus ou moins \u00bb consiste \u00e0 deviner un nombre entier choisi entre 1 et 99.\nUn \u00e9l\u00e8ve de NSI d\u00e9cide de le coder en langage Python de la mani\u00e8re suivante :\n\n- le programme g\u00e9n\u00e8re un nombre entier al\u00e9atoire compris entre 1 et 99 ;\n- si la proposition de l\u2019utilisateur est plus petite que le nombre cherch\u00e9, l\u2019utilisateur en\nest averti. Il peut alors en tester un autre ;\n- si la proposition de l\u2019utilisateur est plus grande que le nombre cherch\u00e9, l\u2019utilisateur en\nest averti. Il peut alors en tester un autre ;\n- si l\u2019utilisateur trouve le bon nombre en 10 essais ou moins, il gagne ;\n- si l\u2019utilisateur a fait plus de 10 essais sans trouver le bon nombre, il perd.\n\nLa fonction `randint` est utilis\u00e9e. Si a et b sont des entiers, `randint(a,b)` renvoie un\nnombre entier compris entre `a` et `b`.\nCompl\u00e9ter le code ci-dessous et le tester :\n\n```python linenums='1'\nfrom random import randint\n\ndef plus_ou_moins():\n nb_mystere = randint(1,...)\n nb_test = int(input(\"Proposez un nombre entre 1 et 99 : \"))\n compteur = ...\n\n while nb_mystere != ... and compteur < ... :\n compteur = compteur + ...\n if nb_mystere ... nb_test:\n nb_test = int(input(\"Trop petit ! Testez encore : \"))\n else:\n nb_test = int(input(\"Trop grand ! Testez encore : \"))\n\n if nb_mystere == nb_test:\n print (\"Bravo ! Le nombre \u00e9tait \",...)\n print(\"Nombre d'essais: \",...)\n else:\n print (\"Perdu ! Le nombre \u00e9tait \",...)\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-39","title":"\u25b6 Sujet 39","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-391","title":"Exercice 39.1 \u25a1","text":"Exercice 39.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction moyenne
prenant en param\u00e8tres une liste d\u2019entiers et qui renvoie la moyenne des valeurs de cette liste.
Exemple :
>>> moyenne([10,20,30,40,60,110])\n45.0\n
def moyenne(tab):\n somme = 0\n for val in tab:\n somme += val\n return somme / len(tab)\n
\u00c9crire une fonction `moyenne` prenant en param\u00e8tres une liste d\u2019entiers et qui renvoie la\nmoyenne des valeurs de cette liste.\n\nExemple :\n```python\n>>> moyenne([10,20,30,40,60,110])\n45.0\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-392","title":"Exercice 39.2 \u25a1","text":"Exercice 39.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn travaille sur des dessins en noir et blanc obtenu \u00e0 partir de pixels noirs et blancs : La figure \u00ab c\u0153ur \u00bb ci-dessus va servir d\u2019exemple. On la repr\u00e9sente par une grille de nombres, c\u2019est-\u00e0-dire par une liste compos\u00e9e de sous-listes de m\u00eame longueurs. Chaque sous-liste repr\u00e9sentera donc une ligne du dessin.
Dans le code ci-dessous, la fonction affiche
permet d\u2019afficher le dessin. Les pixels noirs (1 dans la grille) seront repr\u00e9sent\u00e9s par le caract\u00e8re \"*\" et les blancs (0 dans la grille) par deux espaces.
La fonction zoomListe
prend en argument une liste liste_depart
et un entier k
. Elle renvoie une liste o\u00f9 chaque \u00e9l\u00e9ment de liste_depart
est dupliqu\u00e9 k
fois.
La fonction zoomDessin
prend en argument la grille dessin
et renvoie une grille o\u00f9 toutes les lignes de dessin
sont zoom\u00e9es k
fois et r\u00e9p\u00e9t\u00e9es k
fois.
Soit le code ci-dessous :
coeur = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], \\\n [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0], \\\n [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \\\n [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0], \\\n [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n\ndef affiche(dessin):\n''' affichage d'une grille : les 1 sont repr\u00e9sent\u00e9s par \n des \" *\" , les 0 par deux espaces \" \" '''\n for ligne in dessin:\n for col in ligne:\n if col == 1:\n print(\" *\", end=\"\")\n else:\n print(\" \", end=\"\")\n print()\n\n\ndef zoomListe(liste_depart,k):\n'''renvoie une liste contenant k fois chaque \n \u00e9l\u00e9ment de liste_depart'''\n liste_zoom = ...\n for elt in ... :\n for i in range(k):\n ...\n return liste_zoom\n\ndef zoomDessin(grille,k):\n'''renvoie une grille o\u00f9 les lignes sont zoom\u00e9es k fois \n ET r\u00e9p\u00e9t\u00e9es k fois'''\n grille_zoom=[]\n for elt in grille:\n liste_zoom = ...\n for i in range(k):\n ... .append(...)\n return grille_zoom\n
R\u00e9sultats \u00e0 obtenir :
>>> affiche(coeur)\n
>>> affiche(zoomDessin(coeur,3))\n
* * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * \n * * * \n * * *\n
coeur = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], \\\n [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0], \\\n [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \\\n [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0], \\\n [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n\ndef affiche(dessin):\n for ligne in dessin:\n for col in ligne:\n if col == 1:\n print(' *',end='')\n else:\n print(' ',end='')\n print()\n\n\ndef zoomListe(liste_depart, k):\n liste_zoom = []\n for elt in liste_depart:\n for i in range(k):\n liste_zoom.append(elt)\n return liste_zoom\n\ndef zoomDessin(grille, k):\n grille_zoom = []\n for elt in grille:\n liste_zoom = zoomListe(elt, k)\n for i in range(k):\n grille_zoom.append(liste_zoom)\n return grille_zoom\n
![image](data/272a.png){: .center width=30%}\nOn travaille sur des dessins en noir et blanc obtenu \u00e0 partir de pixels noirs et blancs :\nLa figure \u00ab c\u0153ur \u00bb ci-dessus va servir d\u2019exemple.\nOn la repr\u00e9sente par une grille de nombres, c\u2019est-\u00e0-dire par une liste compos\u00e9e de sous-listes de m\u00eame longueurs.\nChaque sous-liste repr\u00e9sentera donc une ligne du dessin.\n\nDans le code ci-dessous, la fonction `affiche` permet d\u2019afficher le dessin. Les pixels noirs\n(1 dans la grille) seront repr\u00e9sent\u00e9s par le caract\u00e8re \"*\" et les blancs (0 dans la grille) par\ndeux espaces.\n\nLa fonction `zoomListe` prend en argument une liste `liste_depart` et un entier `k`. Elle\nrenvoie une liste o\u00f9 chaque \u00e9l\u00e9ment de `liste_depart` est dupliqu\u00e9 `k` fois.\n\nLa fonction `zoomDessin` prend en argument la grille `dessin` et renvoie une grille o\u00f9\ntoutes les lignes de `dessin` sont zoom\u00e9es `k` fois et r\u00e9p\u00e9t\u00e9es `k` fois.\n\nSoit le code ci-dessous :\n\n```python linenums='1'\ncoeur = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], \\\n [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0], \\\n [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \\\n [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0], \\\n [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n\ndef affiche(dessin):\n ''' affichage d'une grille : les 1 sont repr\u00e9sent\u00e9s par \n des \" *\" , les 0 par deux espaces \" \" '''\n for ligne in dessin:\n for col in ligne:\n if col == 1:\n print(\" *\", end=\"\")\n else:\n print(\" \", end=\"\")\n print()\n\n\ndef zoomListe(liste_depart,k):\n '''renvoie une liste contenant k fois chaque \n \u00e9l\u00e9ment de liste_depart'''\n liste_zoom = ...\n for elt in ... :\n for i in range(k):\n ...\n return liste_zoom\n\ndef zoomDessin(grille,k):\n '''renvoie une grille o\u00f9 les lignes sont zoom\u00e9es k fois \n ET r\u00e9p\u00e9t\u00e9es k fois'''\n grille_zoom=[]\n for elt in grille:\n liste_zoom = ...\n for i in range(k):\n ... .append(...)\n return grille_zoom\n
R\u00e9sultats \u00e0 obtenir :
>>> affiche(coeur)\n
>>> affiche(zoomDessin(coeur,3))\n
* * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * \n * * * \n * * *\n
```
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-40","title":"\u25b6 Sujet 40","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-401","title":"Exercice 40.1 \u25a1","text":"Exercice 40.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche
qui prend en param\u00e8tres elt
un nombre et tab
un tableau de nombres, et qui renvoie le tableau des indices de elt
dans tab
si elt
est dans tab
et le tableau vide []
sinon.
Exemples :
>>> recherche(3, [3, 2, 1, 3, 2, 1])\n[0, 3]\n>>> recherche(4, [1, 2, 3])\n[]\n
def recherche(elt, tab):\n tab_indices = []\n for i in range(len(tab)):\n if tab[i] == elt:\n tab_indices.append(i)\n return tab_indices \n
\u00c9crire une fonction `recherche` qui prend en param\u00e8tres `elt` un nombre et `tab` un\ntableau de nombres, et qui renvoie le tableau des indices de `elt` dans `tab` si `elt` est dans `tab` et le tableau vide `[]` sinon.\n\nExemples :\n```python\n>>> recherche(3, [3, 2, 1, 3, 2, 1])\n[0, 3]\n>>> recherche(4, [1, 2, 3])\n[]\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-402","title":"Exercice 40.2 \u25a1","text":"Exercice 40.2
\u00c9nonc\u00e9CorrectionSources MarkdownUn professeur de NSI d\u00e9cide de g\u00e9rer les r\u00e9sultats de sa classe sous la forme d\u2019un dictionnaire :
Avec :
resultats = {'Dupont':{ 'DS1' : [15.5, 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [13, 4],\n 'PROJET1' : [16, 3],\n 'DS3' : [14, 4]},\n 'Durand':{ 'DS1' : [6 , 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [8, 4],\n 'PROJET1' : [9, 3],\n 'IE1' : [7, 2],\n 'DS3' : [8, 4],\n 'DS4' :[15, 4]}}\n
L\u2019\u00e9l\u00e8ve dont le nom est Durand a ainsi obtenu au DS2 la note de 8 avec un coefficient 4. Le professeur cr\u00e9e une fonction moyenne
qui prend en param\u00e8tre le nom d\u2019un de ces \u00e9l\u00e8ves et lui renvoie sa moyenne arrondie au dixi\u00e8me.
Compl\u00e9ter le code du professeur ci-dessous :
def moyenne(nom):\n if nom in ...:\n notes = resultats[nom]\n total_points = ...\n total_coefficients = ...\n for ... in notes.values():\n note , coefficient = valeurs\n total_points = total_points + ... * coefficient\n total_coefficients = ... + coefficient\n return round( ... / total_coefficients , 1 )\n else:\n return -1\n
resultats = {'Dupont':{ 'DS1' : [15.5, 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [13, 4],\n 'PROJET1' : [16, 3],\n 'DS3' : [14, 4]},\n 'Durand':{ 'DS1' : [6 , 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [8, 4],\n 'PROJET1' : [9, 3],\n 'IE1' : [7, 2],\n 'DS3' : [8, 4],\n 'DS4' :[15, 4]}}\n\ndef moyenne(nom):\n if nom in resultats:\n notes = resultats[nom]\n total_points = 0\n total_coefficients = 0\n for valeurs in notes.values():\n note , coefficient = valeurs\n total_points = total_points + note * coefficient\n total_coefficients = total_coefficients + coefficient\n return round( total_points / total_coefficients , 1 )\n else:\n return -1\n
Un professeur de NSI d\u00e9cide de g\u00e9rer les r\u00e9sultats de sa classe sous la forme d\u2019un\ndictionnaire :\n\n- les clefs sont les noms des \u00e9l\u00e8ves ;\n- les valeurs sont des dictionnaires dont les clefs sont les types d\u2019\u00e9preuves et les\nvaleurs sont les notes obtenues associ\u00e9es \u00e0 leurs coefficients.\n\nAvec :\n\n```python\nresultats = {'Dupont':{ 'DS1' : [15.5, 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [13, 4],\n 'PROJET1' : [16, 3],\n 'DS3' : [14, 4]},\n 'Durand':{ 'DS1' : [6 , 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [8, 4],\n 'PROJET1' : [9, 3],\n 'IE1' : [7, 2],\n 'DS3' : [8, 4],\n 'DS4' :[15, 4]}}\n
L\u2019\u00e9l\u00e8ve dont le nom est Durand a ainsi obtenu au DS2 la note de 8 avec un coefficient 4. Le professeur cr\u00e9e une fonction moyenne
qui prend en param\u00e8tre le nom d\u2019un de ces \u00e9l\u00e8ves et lui renvoie sa moyenne arrondie au dixi\u00e8me.
Compl\u00e9ter le code du professeur ci-dessous :
def moyenne(nom):\n if nom in ...:\n notes = resultats[nom]\n total_points = ...\n total_coefficients = ...\n for ... in notes.values():\n note , coefficient = valeurs\n total_points = total_points + ... * coefficient\n total_coefficients = ... + coefficient\n return round( ... / total_coefficients , 1 )\n else:\n return -1\n
``` Remerciements pour le signalement et la correction des nombreuses erreurs : Alexandre Hainaut, No\u00e9 Pierre, Cyrille Jochault, S\u00e9bastien Rivillon, Cl\u00e9mentine et Laorine (AEFE Montr\u00e9al), Th\u00e9o EwzZer, Laurent Briend, Matteo Gaillard, Pierre Mouries.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/","title":"\u00c9preuve Pratique BNS 2023","text":"Les sujets ci-dessous correspondent \u00e0 la derni\u00e8re version officielle, publi\u00e9e le 25/01/2023. Pour signaler des erreurs \u00e9ventuelles : gilles.lassus@ac-bordeaux.fr
(merci \u00e0 R\u00e9mi Vanicat, Pierre Mouri\u00e8s, Cyrille Jochault, Vincent Bruneau, Tristan Bringuier, Mireille Coilhac)
T\u00e9l\u00e9chargements
.pdf
et .py
) : BNS_2023.zip (2,9 Mo)Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-011","title":"Exercice 01.1","text":"Exercice 01.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction verifie
qui prend en param\u00e8tre un tableau de valeurs num\u00e9riques non vide et qui renvoie True
si ce tableau est tri\u00e9 dans l\u2019ordre croissant, False
sinon.
Exemples :
Exemples :\n>>> verifie([0, 5, 8, 8, 9])\nTrue\n>>> verifie([8, 12, 4])\nFalse\n>>> verifie([-1, 4])\nTrue\n>>> verifie([5])\nTrue\n
def verifie(tab):\n for i in range(1, len(tab)):\n if tab[i] < tab[i-1]:\n return False\n return True\n
Programmer la fonction `verifie` qui prend en param\u00e8tre un tableau de valeurs num\u00e9riques non\nvide et qui renvoie `True` si ce tableau est tri\u00e9 dans l\u2019ordre croissant, `False` sinon.\n\nExemples :\n\n```python\nExemples :\n>>> verifie([0, 5, 8, 8, 9])\nTrue\n>>> verifie([8, 12, 4])\nFalse\n>>> verifie([-1, 4])\nTrue\n>>> verifie([5])\nTrue\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-012","title":"Exercice 01.2","text":"Exercice 01.2
\u00c9nonc\u00e9CorrectionSources MarkdownLes r\u00e9sultats d'un vote ayant trois issues possibles 'A', 'B' et 'C' sont stock\u00e9s dans un tableau.
Exemple :
urne = ['A', 'A', 'A', 'B', 'C', 'B', 'C', 'B', 'C', 'B']\n
La fonction depouille
doit permettre de compter le nombre de votes exprim\u00e9s pour chaque artiste. Elle prend en param\u00e8tre un tableau et renvoie le r\u00e9sultat dans un dictionnaire dont les cl\u00e9s sont les noms des artistes et les valeurs le nombre de votes en leur faveur.
La fonction vainqueur doit d\u00e9signer le nom du ou des gagnants. Elle prend en param\u00e8tre un dictionnaire dont la structure est celle du dictionnaire renvoy\u00e9 par la fonction depouille
et renvoie un tableau. Ce tableau peut donc contenir plusieurs \u00e9l\u00e9ments s\u2019il y a des artistes ex- aequo. Compl\u00e9ter les fonctions depouille
et vainqueur ci-apr\u00e8s pour qu\u2019elles renvoient les r\u00e9sultats attendus.
urne = ['A', 'A', 'A','B', 'C', 'B', 'C','B', 'C', 'B']\n\ndef depouille(urne):\n resultat = ...\n for bulletin in urne:\n if ...:\n resultat[bulletin] = resultat[bulletin] + 1\n else:\n ...\n return resultat\n\ndef vainqueur(election):\n vainqueur = ''\n nmax = 0\n for candidat in election:\n if ... > ... :\n nmax = ...\n vainqueur = candidat\n liste_finale = [nom for nom in election if election[nom] == ...]\n return ...\n
Exemples d\u2019utilisation :
>>> election = depouille(urne)\n>>> election\n{'A': 3, 'B': 4, 'C': 3}\n>>> vainqueur(election)\n['B']\n
urne = ['A', 'A', 'A', 'B', 'C', 'B', 'C', 'B', 'C', 'B']\n\ndef depouille(urne):\nresultat = {}\nfor bulletin in urne:\nif bulletin in resultat:\nresultat[bulletin] = resultat[bulletin] + 1\n else:\nresultat[bulletin] = 1\nreturn resultat\n\ndef vainqueur(election):\n vainqueur = '' #(1)\n nmax = 0\n for candidat in election:\nif election[candidat] > nmax :\nnmax = election[candidat]\nvainqueur = candidat #(2)\nliste_finale = [nom for nom in election if election[nom] == nmax]\nreturn liste_finale\n
vainqueur
est inutile, on ne s'en sert pas dans l'\u00e9laboration de la liste finale.Les r\u00e9sultats d'un vote ayant trois issues possibles 'A', 'B' et 'C' sont stock\u00e9s dans un tableau.\n\nExemple :\n\n```python\nurne = ['A', 'A', 'A', 'B', 'C', 'B', 'C', 'B', 'C', 'B']\n
La fonction depouille
doit permettre de compter le nombre de votes exprim\u00e9s pour chaque artiste. Elle prend en param\u00e8tre un tableau et renvoie le r\u00e9sultat dans un dictionnaire dont les cl\u00e9s sont les noms des artistes et les valeurs le nombre de votes en leur faveur.
La fonction vainqueur doit d\u00e9signer le nom du ou des gagnants. Elle prend en param\u00e8tre un dictionnaire dont la structure est celle du dictionnaire renvoy\u00e9 par la fonction depouille
et renvoie un tableau. Ce tableau peut donc contenir plusieurs \u00e9l\u00e9ments s\u2019il y a des artistes ex- aequo. Compl\u00e9ter les fonctions depouille
et vainqueur ci-apr\u00e8s pour qu\u2019elles renvoient les r\u00e9sultats attendus.
urne = ['A', 'A', 'A','B', 'C', 'B', 'C','B', 'C', 'B']\n\ndef depouille(urne):\n resultat = ...\n for bulletin in urne:\n if ...:\n resultat[bulletin] = resultat[bulletin] + 1\n else:\n ...\n return resultat\n\ndef vainqueur(election):\n vainqueur = ''\n nmax = 0\n for candidat in election:\n if ... > ... :\n nmax = ...\n vainqueur = candidat\n liste_finale = [nom for nom in election if election[nom] == ...]\n return ...\n
Exemples d\u2019utilisation :
>>> election = depouille(urne)\n>>> election\n{'A': 3, 'B': 4, 'C': 3}\n>>> vainqueur(election)\n['B']\n
```
Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-02","title":"\u25b6 Sujet 02","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-021","title":"Exercice 02.1","text":"Exercice 02.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction indices_maxi
qui prend en param\u00e8tre une liste tab
, non vide, de nombres entiers et renvoie un couple donnant d\u2019une part le plus grand \u00e9l\u00e9ment de cette liste et d\u2019autre part la liste des indices de la liste tab
o\u00f9 appara\u00eet ce plus grand \u00e9l\u00e9ment.
Exemple :
>>> indices_maxi([1, 5, 6, 9, 1, 2, 3, 7, 9, 8])\n(9, [3, 8])\n>>> indices_maxi([7])\n(7, [0])\n
def indices_maxi(tab):\n val_max = tab[0]\n ind_max = []\n for i in range(len(tab)):\n if tab[i] > val_max:\n val_max = tab[i]\n for i in range(len(tab)):\n if tab[i] == val_max:\n ind_max.append(i)\n return (val_max, ind_max)\n
\u00c9crire une fonction `indices_maxi` qui prend en param\u00e8tre une liste `tab`, non vide, de\nnombres entiers et renvoie un couple donnant d\u2019une part le plus grand \u00e9l\u00e9ment de cette\nliste et d\u2019autre part la liste des indices de la liste `tab` o\u00f9 appara\u00eet ce plus grand \u00e9l\u00e9ment.\n\nExemple :\n```python\n>>> indices_maxi([1, 5, 6, 9, 1, 2, 3, 7, 9, 8])\n(9, [3, 8])\n>>> indices_maxi([7])\n(7, [0])\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-022","title":"Exercice 02.2","text":"Exercice 02.2
\u00c9nonc\u00e9CorrectionSources MarkdownCet exercice utilise des piles qui seront repr\u00e9sent\u00e9es en Python par des listes (type list
).
On rappelle que l\u2019expression liste_1 = list(liste)
fait une copie de liste
ind\u00e9pendante de liste
, que l\u2019expression x = liste.pop()
enl\u00e8ve le sommet de la pile liste
et le place dans la variable x
et, enfin, que l\u2019expression liste.append(v)
place la valeur v
au sommet de la pile liste
.
Compl\u00e9ter le code Python de la fonction positif
ci-dessous qui prend une pile liste
de nombres entiers en param\u00e8tre et qui renvoie la pile des entiers positifs dans le m\u00eame ordre, sans modifier la variable liste
.
def positif(pile):\n pile_1 = ...(pile)\n pile_2 = ...\n while pile_1 != []:\n x = ...\n if ... >= 0:\n pile_2.append(...)\n while pile_2 != ...:\n x = pile_2.pop()\n ...\n return pile_1\n
Exemple :
>>> positif([-1, 0, 5, -3, 4, -6, 10, 9, -8])\n[0, 5, 4, 10, 9]\n>>> positif([-2])\n[]\n
def positif(pile):\npile_1 = list(pile)\npile_2 = []\nwhile pile_1 != []:\nx = pile_1.pop()\nif x >= 0:\npile_2.append(x)\nwhile pile_2 != []:\nx = pile_2.pop()\npile_1.append(x)\nreturn pile_1\n
Cet exercice utilise des piles qui seront repr\u00e9sent\u00e9es en Python par des listes (type `list`).\n\nOn rappelle que l\u2019expression `liste_1 = list(liste)` fait une copie de `liste `ind\u00e9pendante de `liste`, que\nl\u2019expression `x = liste.pop()` enl\u00e8ve le sommet de la pile `liste` et le place dans la variable `x` et,\nenfin, que l\u2019expression `liste.append(v)` place la valeur `v` au sommet de la pile `liste`.\n\nCompl\u00e9ter le code Python de la fonction `positif` ci-dessous qui prend une pile `liste` de\nnombres entiers en param\u00e8tre et qui renvoie la pile des entiers positifs dans le m\u00eame\nordre, sans modifier la variable `liste`.\n\n```python linenums='1'\ndef positif(pile):\n pile_1 = ...(pile)\n pile_2 = ...\n while pile_1 != []:\n x = ...\n if ... >= 0:\n pile_2.append(...)\n while pile_2 != ...:\n x = pile_2.pop()\n ...\n return pile_1\n
Exemple :
>>> positif([-1, 0, 5, -3, 4, -6, 10, 9, -8])\n[0, 5, 4, 10, 9]\n>>> positif([-2])\n[]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-03","title":"\u25b6 Sujet 03","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-031","title":"Exercice 03.1","text":"Exercice 03.1
\u00c9nonc\u00e9CorrectionSource MarkdownDans cet exercice, les nombres sont des entiers ou des flottants.
\u00c9crire une fonction moyenne
renvoyant la moyenne pond\u00e9r\u00e9e d\u2019une liste non vide, pass\u00e9e en param\u00e8tre, de tuples \u00e0 deux \u00e9l\u00e9ments de la forme (valeur
, coefficient
) o\u00f9 valeur
et coefficient
sont des nombres positifs ou nuls. Si la somme des coefficients est nulle, la fonction renvoie None
, si la somme des coefficients est non nulle, la fonction renvoie, sous forme de flottant, la moyenne des valeurs affect\u00e9es de leur coefficient.
Exemple :
>>> moyenne([(8, 2), (12, 0), (13.5, 1), (5, 0.5)])\n9.142857142857142\n>>> moyenne([(3, 0), (5, 0)])\nNone\n
Dans le premier exemple la moyenne est calcul\u00e9e par la formule :
\\(\\dfrac{8 \\times 2 + 12 \\times 0 + 13,5 \\times 1 + 5 \\times 0,5}{2+0+1+0,5}\\)
def moyenne(tab):\n somme = 0\n coeffs = 0\n for couple in tab:\n somme += couple[0] * couple[1]\n coeffs += couple[1]\n if coeffs == 0:\n return None\n return somme / coeffs\n
Dans cet exercice, les nombres sont des entiers ou des flottants.\n\n\u00c9crire une fonction `moyenne` renvoyant la moyenne pond\u00e9r\u00e9e d\u2019une liste non vide,\npass\u00e9e en param\u00e8tre, de tuples \u00e0 deux \u00e9l\u00e9ments de la forme (`valeur`,\n`coefficient`) o\u00f9 `valeur` et `coefficient` sont des nombres positifs ou nuls.\nSi la somme des coefficients est nulle, la fonction renvoie `None`, si la somme des\ncoefficients est non nulle, la fonction renvoie, sous forme de flottant, la moyenne des\nvaleurs affect\u00e9es de leur coefficient.\n\nExemple :\n```python\n>>> moyenne([(8, 2), (12, 0), (13.5, 1), (5, 0.5)])\n9.142857142857142\n>>> moyenne([(3, 0), (5, 0)])\nNone\n```\n\nDans le premier exemple la moyenne est calcul\u00e9e par la formule :\n\n$\\dfrac{8 \\times 2 + 12 \\times 0 + 13,5 \\times 1 + 5 \\times 0,5}{2+0+1+0,5}$\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-032","title":"Exercice 03.2","text":"Exercice 03.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn travaille sur des dessins en noir et blanc obtenu \u00e0 partir de pixels noirs et blancs : La figure \u00ab c\u0153ur \u00bb ci-dessus va servir d\u2019exemple. On la repr\u00e9sente par une grille de nombres, c\u2019est-\u00e0-dire par une liste compos\u00e9e de sous-listes de m\u00eame longueurs. Chaque sous-liste repr\u00e9sentera donc une ligne du dessin.
Dans le code ci-dessous, la fonction affiche
permet d\u2019afficher le dessin. Les pixels noirs (1 dans la grille) seront repr\u00e9sent\u00e9s par le caract\u00e8re \"*\" et les blancs (0 dans la grille) par deux espaces.
La fonction zoomListe
prend en argument une liste liste_depart
et un entier k
. Elle renvoie une liste o\u00f9 chaque \u00e9l\u00e9ment de liste_depart
est dupliqu\u00e9 k
fois.
La fonction zoomDessin
prend en argument la grille dessin
et renvoie une grille o\u00f9 toutes les lignes de dessin
sont zoom\u00e9es k
fois et r\u00e9p\u00e9t\u00e9es k
fois.
Soit le code ci-dessous :
coeur = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], \\\n [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0], \\\n [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \\\n [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0], \\\n [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n\ndef affiche(dessin):\n''' affichage d'une grille : les 1 sont repr\u00e9sent\u00e9s par \n des \" *\" , les 0 par deux espaces \" \" '''\n for ligne in dessin:\n for col in ligne:\n if col == 1:\n print(\" *\", end=\"\")\n else:\n print(\" \", end=\"\")\n print()\n\n\ndef zoomListe(liste_depart,k):\n'''renvoie une liste contenant k fois chaque \n \u00e9l\u00e9ment de liste_depart'''\n liste_zoom = ...\n for elt in ... :\n for i in range(k):\n ...\n return liste_zoom\n\ndef zoomDessin(grille,k):\n'''renvoie une grille o\u00f9 les lignes sont zoom\u00e9es k fois \n ET r\u00e9p\u00e9t\u00e9es k fois'''\n grille_zoom=[]\n for elt in grille:\n liste_zoom = ...\n for i in range(k):\n ... .append(...)\n return grille_zoom\n
R\u00e9sultats \u00e0 obtenir :
>>> affiche(coeur)\n
>>> affiche(zoomDessin(coeur,3))\n
* * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * \n * * * \n * * *\n
coeur = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], \\\n [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0], \\\n [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \\\n [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0], \\\n [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n\ndef affiche(dessin):\n''' affichage d'une grille : les 1 sont repr\u00e9sent\u00e9s par \n des \" *\" , les 0 par deux espaces \" \" '''\n for ligne in dessin:\n for col in ligne:\n if col == 1:\n print(' *',end='')\n else:\n print(' ',end='')\n print()\n\n\ndef zoomListe(liste_depart, k):\n'''renvoie une liste contenant k fois chaque \n \u00e9l\u00e9ment de liste_depart'''\nliste_zoom = []\nfor elt in liste_depart:\nfor i in range(k):\nliste_zoom.append(elt)\nreturn liste_zoom\n\ndef zoomDessin(grille, k):\n'''renvoie une grille o\u00f9 les lignes sont zoom\u00e9es k fois \n ET r\u00e9p\u00e9t\u00e9es k fois'''\n grille_zoom = []\n for elt in grille:\nliste_zoom = zoomListe(elt, k)\nfor i in range(k):\ngrille_zoom.append(liste_zoom)\nreturn grille_zoom\n
![image](data2023/03_coeur.png){: .center width=30%}\nOn travaille sur des dessins en noir et blanc obtenu \u00e0 partir de pixels noirs et blancs :\nLa figure \u00ab c\u0153ur \u00bb ci-dessus va servir d\u2019exemple.\nOn la repr\u00e9sente par une grille de nombres, c\u2019est-\u00e0-dire par une liste compos\u00e9e de sous-listes de m\u00eame longueurs.\nChaque sous-liste repr\u00e9sentera donc une ligne du dessin.\n\nDans le code ci-dessous, la fonction `affiche` permet d\u2019afficher le dessin. Les pixels noirs\n(1 dans la grille) seront repr\u00e9sent\u00e9s par le caract\u00e8re \"*\" et les blancs (0 dans la grille) par\ndeux espaces.\n\nLa fonction `zoomListe` prend en argument une liste `liste_depart` et un entier `k`. Elle\nrenvoie une liste o\u00f9 chaque \u00e9l\u00e9ment de `liste_depart` est dupliqu\u00e9 `k` fois.\n\nLa fonction `zoomDessin` prend en argument la grille `dessin` et renvoie une grille o\u00f9\ntoutes les lignes de `dessin` sont zoom\u00e9es `k` fois et r\u00e9p\u00e9t\u00e9es `k` fois.\n\nSoit le code ci-dessous :\n\n```python linenums='1'\ncoeur = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], \\\n [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0], \\\n [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \\\n [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0], \\\n [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n\ndef affiche(dessin):\n ''' affichage d'une grille : les 1 sont repr\u00e9sent\u00e9s par \n des \" *\" , les 0 par deux espaces \" \" '''\n for ligne in dessin:\n for col in ligne:\n if col == 1:\n print(\" *\", end=\"\")\n else:\n print(\" \", end=\"\")\n print()\n\n\ndef zoomListe(liste_depart,k):\n '''renvoie une liste contenant k fois chaque \n \u00e9l\u00e9ment de liste_depart'''\n liste_zoom = ...\n for elt in ... :\n for i in range(k):\n ...\n return liste_zoom\n\ndef zoomDessin(grille,k):\n '''renvoie une grille o\u00f9 les lignes sont zoom\u00e9es k fois \n ET r\u00e9p\u00e9t\u00e9es k fois'''\n grille_zoom=[]\n for elt in grille:\n liste_zoom = ...\n for i in range(k):\n ... .append(...)\n return grille_zoom\n
R\u00e9sultats \u00e0 obtenir :
>>> affiche(coeur)\n
>>> affiche(zoomDessin(coeur,3))\n
* * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * \n * * * \n * * *\n
```
Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-04","title":"\u25b6 Sujet 04","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-041","title":"Exercice 04.1","text":"Exercice 04.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction a_doublon
qui prend en param\u00e8tre une liste tri\u00e9e de nombres et renvoie True
si la liste contient au moins deux nombres identiques, False
sinon.
Par exemple :
>>> a_doublon([])\nFalse\n>>> a_doublon([1])\nFalse\n>>> a_doublon([1, 2, 4, 6, 6])\nTrue\n>>> a_doublon([2, 5, 7, 7, 7, 9])\nTrue\n>>> a_doublon([0, 2, 3])\nFalse\n
def a_doublon(lst):\n for i in range(len(lst)-1):\n if lst[i] == lst[i+1]:\n return True\n return False\n
\u00c9crire une fonction `a_doublon` qui prend en param\u00e8tre une liste **tri\u00e9e** de nombres et\nrenvoie `True` si la liste contient au moins deux nombres identiques, `False` sinon.\n\nPar exemple :\n\n```python\n>>> a_doublon([])\nFalse\n>>> a_doublon([1])\nFalse\n>>> a_doublon([1, 2, 4, 6, 6])\nTrue\n>>> a_doublon([2, 5, 7, 7, 7, 9])\nTrue\n>>> a_doublon([0, 2, 3])\nFalse\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-042","title":"Exercice 04.2","text":"Exercice 04.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn souhaite g\u00e9n\u00e9rer des grilles du jeu de d\u00e9mineur \u00e0 partir de la position des bombes \u00e0 placer. On se limite \u00e0 la g\u00e9n\u00e9ration de grilles carr\u00e9es de taille \\(n \\times n\\) o\u00f9 \\(n\\) est le nombre de bombes du jeu.
Dans le jeu du d\u00e9mineur, chaque case de la grille contient soit une bombe, soit une valeur qui correspond aux nombres de bombes situ\u00e9es dans le voisinage direct de la case (au- dessus, en dessous, \u00e0 droite, \u00e0 gauche ou en diagonale : chaque case a donc 8 voisins si elle n'est pas situ\u00e9e au bord de la grille).
Voici un exemple de grille \\(5 \\times 5\\) de d\u00e9mineur dans laquelle la bombe est repr\u00e9sent\u00e9e par une \u00e9toile :
On utilise une liste de listes pour repr\u00e9senter la grille et on choisit de coder une bombe par la valeur -1.
L'exemple ci-contre sera donc cod\u00e9 par la liste :
[[1, 1, 1, 0, 0],\n[1, -1, 1, 1, 1],\n[2, 2, 3, 2, -1],\n[1, -1, 2, -1, 3],\n[1, 1, 2, 2, -1]]\n
Compl\u00e9ter le code suivant afin de g\u00e9n\u00e9rer des grilles de d\u00e9mineur, on pourra v\u00e9rifier que l\u2019instruction genere_grille([(1, 1), (2, 4), (3, 1), (3, 3), (4, 4)])
produit bien la liste donn\u00e9e en exemple.
def voisinage(n, ligne, colonne):\n\"\"\" Renvoie la liste des coordonn\u00e9es des voisins de la case\n (ligne, colonne) en g\u00e9rant les cases sur les bords. \"\"\"\n voisins = []\n for l in range(max(0,ligne-1), min(n, ligne+2)):\n for c in range(max(0, colonne-1), min(n, colonne+2)):\n if (l, c) != (ligne, colonne):\n voisins.append((l,c))\n return voisins\n\n\ndef incremente_voisins(grille, ligne, colonne):\n\"\"\" Incr\u00e9mente de 1 toutes les cases voisines d'une bombe.\"\"\"\n voisins = ...\n for l, c in voisins:\n if grille[l][c] != ...: # si ce n'est pas une bombe\n ... # on ajoute 1 \u00e0 sa valeur\n\n\n\ndef genere_grille(bombes):\n\"\"\" Renvoie une grille de d\u00e9mineur de taille nxn o\u00f9 n est\n le nombre de bombes, en pla\u00e7ant les bombes \u00e0 l'aide de\n la liste bombes de coordonn\u00e9es (tuples) pass\u00e9e en\n param\u00e8tre. \"\"\"\n n = len(bombes)\n # Initialisation d'une grille nxn remplie de 0\n grille = [[0 for colonne in range(n)] for ligne in range(n)]\n # Place les bombes et calcule les valeurs des autres cases\n for ligne, colonne in bombes:\n grille[ligne][colonne] = ... # place la bombe\n ... # incr\u00e9mente ses voisins\n\n return grille\n
def voisinage(n, ligne, colonne):\n\"\"\" Renvoie la liste des coordonn\u00e9es des voisins de la case\n (ligne, colonne) en g\u00e9rant les cases sur les bords. \"\"\"\n voisins = []\n for l in range(max(0,ligne-1), min(n, ligne+2)):\n for c in range(max(0, colonne-1), min(n, colonne+2)):\n if (l, c) != (ligne, colonne):\n voisins.append((l,c))\n return voisins\n\n\ndef incremente_voisins(grille, ligne, colonne):\n\"\"\" Incr\u00e9mente de 1 toutes les cases voisines d'une bombe.\"\"\"\nvoisins = voisinage(len(grille), ligne, colonne)\nfor l, c in voisins:\nif grille[l][c] != -1: # si ce n'est pas une bombe\ngrille[l][c] += 1 # on ajoute 1 \u00e0 sa valeur\ndef genere_grille(bombes):\n\"\"\" Renvoie une grille de d\u00e9mineur de taille nxn o\u00f9 n est\n le nombre de bombes, en pla\u00e7ant les bombes \u00e0 l'aide de\n la liste bombes de coordonn\u00e9es (tuples) pass\u00e9e en\n param\u00e8tre. \"\"\"\n n = len(bombes)\n # Initialisation d'une grille nxn remplie de 0\n grille = [[0 for colonne in range(n)] for ligne in range(n)]\n # Place les bombes et calcule les valeurs des autres cases\n for ligne, colonne in bombes:\ngrille[ligne][colonne] = -1 # place la bombe\nincremente_voisins(grille, ligne, colonne) # incr\u00e9mente ses voisins\nreturn grille\n
On souhaite g\u00e9n\u00e9rer des grilles du jeu de d\u00e9mineur \u00e0 partir de la position des bombes \u00e0\nplacer. \nOn se limite \u00e0 la g\u00e9n\u00e9ration de grilles carr\u00e9es de taille $n \\times n$ o\u00f9 $n$ est le nombre de bombes du jeu. \n\nDans le jeu du d\u00e9mineur, chaque case de la grille contient soit une bombe, soit une valeur\nqui correspond aux nombres de bombes situ\u00e9es dans le voisinage direct de la case (au-\ndessus, en dessous, \u00e0 droite, \u00e0 gauche ou en diagonale : chaque case a donc 8 voisins si\nelle n'est pas situ\u00e9e au bord de la grille).\n\nVoici un exemple de grille $5 \\times 5$ de d\u00e9mineur dans laquelle la bombe est repr\u00e9sent\u00e9e par une \u00e9toile :\n\n![image](data2023/04grille.png){: .center}\n\n\nOn utilise une liste de listes pour repr\u00e9senter la grille et on choisit de coder une bombe par la valeur -1.\n\nL'exemple ci-contre sera donc cod\u00e9 par la liste :\n\n```python\n[[1, 1, 1, 0, 0],\n[1, -1, 1, 1, 1],\n[2, 2, 3, 2, -1],\n[1, -1, 2, -1, 3],\n[1, 1, 2, 2, -1]]\n
Compl\u00e9ter le code suivant afin de g\u00e9n\u00e9rer des grilles de d\u00e9mineur, on pourra v\u00e9rifier que l\u2019instruction genere_grille([(1, 1), (2, 4), (3, 1), (3, 3), (4, 4)])
produit bien la liste donn\u00e9e en exemple.
def voisinage(n, ligne, colonne):\n\"\"\" Renvoie la liste des coordonn\u00e9es des voisins de la case\n (ligne, colonne) en g\u00e9rant les cases sur les bords. \"\"\"\n voisins = []\n for l in range(max(0,ligne-1), min(n, ligne+2)):\n for c in range(max(0, colonne-1), min(n, colonne+2)):\n if (l, c) != (ligne, colonne):\n voisins.append((l,c))\n return voisins\n\n\ndef incremente_voisins(grille, ligne, colonne):\n\"\"\" Incr\u00e9mente de 1 toutes les cases voisines d'une bombe.\"\"\"\n voisins = ...\n for l, c in voisins:\n if grille[l][c] != ...: # si ce n'est pas une bombe\n ... # on ajoute 1 \u00e0 sa valeur\n\n\n\ndef genere_grille(bombes):\n\"\"\" Renvoie une grille de d\u00e9mineur de taille nxn o\u00f9 n est\n le nombre de bombes, en pla\u00e7ant les bombes \u00e0 l'aide de\n la liste bombes de coordonn\u00e9es (tuples) pass\u00e9e en\n param\u00e8tre. \"\"\"\n n = len(bombes)\n # Initialisation d'une grille nxn remplie de 0\n grille = [[0 for colonne in range(n)] for ligne in range(n)]\n # Place les bombes et calcule les valeurs des autres cases\n for ligne, colonne in bombes:\n grille[ligne][colonne] = ... # place la bombe\n ... # incr\u00e9mente ses voisins\n\n return grille\n
```
Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-05","title":"\u25b6 Sujet 05","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-051","title":"Exercice 05.1","text":"Exercice 05.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire en python deux fonctions :
lancer
de param\u00e8tre n
, un entier positif, qui renvoie un tableau de type list
de n
entiers obtenus al\u00e9atoirement entre 1 et 6 (1 et 6 inclus) ;
paire_6
de param\u00e8tre tab
, un tableau de type list
de n
entiers entre 1 et 6 obtenus al\u00e9atoirement, qui renvoie un bool\u00e9en \u00e9gal \u00e0 True
si le nombre de 6 est sup\u00e9rieur ou \u00e9gal \u00e0 2, False
sinon.
On pourra utiliser la fonction randint(a,b)
du module random
pour laquelle la documentation officielle est la suivante :
Renvoie un entier al\u00e9atoire N tel que a <=N <= b.
Exemples :
>>> lancer1 = lancer(5)\n[5, 6, 6, 2, 2]\n>>> paire_6(lancer1)\nTrue\n>>> lancer2 = lancer(5)\n[6, 5, 1, 6, 6]\n>>> paire_6(lancer2)\nTrue\n>>> lancer3 = lancer(3)\n[2, 2, 6]\n>>> paire_6(lancer3)\nFalse\n>>> lancer4 = lancer(0)\n[]\n>>> paire_6(lancer4)\nFalse\n
from random import randint\n\ndef lancer(n):\n return [randint(1,6) for _ in range(n)]\n\ndef paire_6(tab):\n nb = 0\n for elt in tab:\n if elt == 6:\n nb += 1\n if nb >=2 :\n return True\n else:\n return False\n
\u00c9crire en python deux fonctions :\n\n- `lancer` de param\u00e8tre `n`, un entier positif, qui renvoie un tableau de type `list` de\n`n` entiers obtenus al\u00e9atoirement entre 1 et 6 (1 et 6 inclus) ;\n\n- `paire_6` de param\u00e8tre `tab`, un tableau de type `list` de `n` entiers entre 1 et\n6 obtenus al\u00e9atoirement, qui renvoie un bool\u00e9en \u00e9gal \u00e0 `True` si le nombre de 6\nest sup\u00e9rieur ou \u00e9gal \u00e0 2, `False` sinon.\n\nOn pourra utiliser la fonction `randint(a,b)` du module `random` pour laquelle la\ndocumentation officielle est la suivante :\n\n`Renvoie un entier al\u00e9atoire N tel que a <=N <= b.`\n\nExemples :\n\n```python\n>>> lancer1 = lancer(5)\n[5, 6, 6, 2, 2]\n>>> paire_6(lancer1)\nTrue\n>>> lancer2 = lancer(5)\n[6, 5, 1, 6, 6]\n>>> paire_6(lancer2)\nTrue\n>>> lancer3 = lancer(3)\n[2, 2, 6]\n>>> paire_6(lancer3)\nFalse\n>>> lancer4 = lancer(0)\n[]\n>>> paire_6(lancer4)\nFalse\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-052","title":"Exercice 05.2","text":"Exercice 05.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re une image en 256 niveaux de gris que l\u2019on repr\u00e9sente par une grille de nombres, c\u2019est-\u00e0-dire une liste compos\u00e9e de sous-listes toutes de longueurs identiques.
La largeur de l\u2019image est donc la longueur d\u2019une sous-liste et la hauteur de l\u2019image est le nombre de sous-listes.
Chaque sous-liste repr\u00e9sente une ligne de l\u2019image et chaque \u00e9l\u00e9ment des sous-listes est un entier compris entre 0 et 255, repr\u00e9sentant l\u2019intensit\u00e9 lumineuse du pixel.
Le n\u00e9gatif d\u2019une image est l\u2019image constitu\u00e9e des pixels x_n
tels que x_n + x_i = 255
o\u00f9 x_i
est le pixel correspondant de l\u2019image initiale.
Compl\u00e9ter le programme suivant :
def nbLig(image):\n'''renvoie le nombre de lignes de l'image'''\n return ...\n\ndef nbCol(image):\n'''renvoie la largeur de l'image'''\n return ...\n\ndef negatif(image):\n'''renvoie le negatif de l'image sous la forme\n d'une liste de listes'''\n\n # on cree une image de 0 aux memes dimensions que le parametre image\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))]\n\n for i in range(nbLig(image)):\n for j in range(...):\n L[i][j] = ...\n return L\n\ndef binaire(image, seuil):\n'''renvoie une image binarisee de l'image sous la forme\n d'une liste de listes contenant des 0 si la valeur\n du pixel est strictement inferieure au seuil\n et 1 sinon'''\n\n # on cree une image de 0 aux memes dimensions que le parametre image\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))]\n\n for i in range(nbLig(image)):\n for j in range(...):\n if image[i][j] < ... :\n L[i][j] = ...\n else:\n L[i][j] = ...\n return L\n
Exemples :
>>> img=[[20, 34, 254, 145, 6], [23, 124, 237, 225, 69], [197, 174,\n207, 25, 87], [255, 0, 24, 197, 189]]\n>>> nbLig(img)\n4\n>>> nbCol(img)\n5\n>>> negatif(img)\n[[235, 221, 1, 110, 249], [232, 131, 18, 30, 186], [58, 81, 48, 230,\n168], [0, 255, 231, 58, 66]]\n>>> binaire(img,120)\n[[0, 0, 1, 1, 0], [0, 1, 1, 1, 0], [1, 1, 1, 0, 0], [1, 0, 0, 1, 1]]\n
def nbLig(image):\n'''renvoie le nombre de lignes de l'image'''\nreturn len(image)\ndef nbCol(image):\n'''renvoie la largeur de l'image'''\nreturn len(image[0])\ndef negatif(image):\n'''renvoie le negatif de l'image sous la forme\n d'une liste de listes'''\n\n # on cree une image de 0 aux memes dimensions que le parametre image\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))]\n\n for i in range(nbLig(image)):\nfor j in range(nbCol(image)):\nL[i][j] = 255 - image[i][j]\nreturn L\n\ndef binaire(image, seuil):\n'''renvoie une image binarisee de l'image sous la forme\n d'une liste de listes contenant des 0 si la valeur\n du pixel est strictement inferieure au seuil\n et 1 sinon'''\n\n # on cree une image de 0 aux memes dimensions que le parametre image\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))]\n\n for i in range(nbLig(image)):\nfor j in range(nbCol(image)):\nif image[i][j] < seuil :\nL[i][j] = 0\nelse:\nL[i][j] = 1\nreturn L\n
On consid\u00e8re une image en 256 niveaux de gris que l\u2019on repr\u00e9sente par une grille de\nnombres, c\u2019est-\u00e0-dire une liste compos\u00e9e de sous-listes toutes de longueurs identiques.\n\n\nLa largeur de l\u2019image est donc la longueur d\u2019une sous-liste et la hauteur de l\u2019image est le\nnombre de sous-listes.\n\n\nChaque sous-liste repr\u00e9sente une ligne de l\u2019image et chaque \u00e9l\u00e9ment des sous-listes est\nun entier compris entre 0 et 255, repr\u00e9sentant l\u2019intensit\u00e9 lumineuse du pixel.\n\n\nLe n\u00e9gatif d\u2019une image est l\u2019image constitu\u00e9e des pixels `x_n` tels que\n`x_n + x_i = 255` o\u00f9 `x_i` est le pixel correspondant de l\u2019image initiale.\n\nCompl\u00e9ter le programme suivant :\n```python linenums='1'\ndef nbLig(image):\n '''renvoie le nombre de lignes de l'image'''\n return ...\n\ndef nbCol(image):\n '''renvoie la largeur de l'image'''\n return ...\n\ndef negatif(image):\n '''renvoie le negatif de l'image sous la forme\n d'une liste de listes'''\n\n # on cree une image de 0 aux memes dimensions que le parametre image\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))]\n\n for i in range(nbLig(image)):\n for j in range(...):\n L[i][j] = ...\n return L\n\ndef binaire(image, seuil):\n '''renvoie une image binarisee de l'image sous la forme\n d'une liste de listes contenant des 0 si la valeur\n du pixel est strictement inferieure au seuil\n et 1 sinon'''\n\n # on cree une image de 0 aux memes dimensions que le parametre image\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))]\n\n for i in range(nbLig(image)):\n for j in range(...):\n if image[i][j] < ... :\n L[i][j] = ...\n else:\n L[i][j] = ...\n return L\n
Exemples :
>>> img=[[20, 34, 254, 145, 6], [23, 124, 237, 225, 69], [197, 174,\n207, 25, 87], [255, 0, 24, 197, 189]]\n>>> nbLig(img)\n4\n>>> nbCol(img)\n5\n>>> negatif(img)\n[[235, 221, 1, 110, 249], [232, 131, 18, 30, 186], [58, 81, 48, 230,\n168], [0, 255, 231, 58, 66]]\n>>> binaire(img,120)\n[[0, 0, 1, 1, 0], [0, 1, 1, 1, 0], [1, 1, 1, 0, 0], [1, 0, 0, 1, 1]]\n
```
Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-06","title":"\u25b6 Sujet 06","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-061","title":"Exercice 06.1","text":"Exercice 06.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction recherche
, prenant en param\u00e8tre un tableau non vide tab
(type list
) d'entiers et un entier n
, et qui renvoie l'indice de la derni\u00e8re occurrence de l'\u00e9l\u00e9ment cherch\u00e9. Si l'\u00e9l\u00e9ment n'est pas pr\u00e9sent, la fonction renvoie la longueur du tableau.
Exemples
>>> recherche([5, 3],1)\n2\n>>> recherche([2,4],2)\n0\n>>> recherche([2,3,5,2,4],2)\n3\n
def recherche(tab, n):\n indice_solution = len(tab)\n for i in range(len(tab)):\n if tab[i] == n:\n indice_solution = i\n return indice_solution\n
Programmer la fonction `recherche`, prenant en param\u00e8tre un tableau non vide `tab` (type `list`) d'entiers et un entier `n`, et qui renvoie l'indice de la **derni\u00e8re** occurrence de l'\u00e9l\u00e9ment cherch\u00e9. Si l'\u00e9l\u00e9ment n'est pas pr\u00e9sent, la fonction renvoie la longueur du tableau.\n\nExemples\n```python\n>>> recherche([5, 3],1)\n2\n>>> recherche([2,4],2)\n0\n>>> recherche([2,3,5,2,4],2)\n3\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-062","title":"Exercice 06.2","text":"Exercice 06.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn souhaite programmer une fonction donnant la distance la plus courte entre un point de d\u00e9part et une liste de points. Les points sont tous \u00e0 coordonn\u00e9es enti\u00e8res. Les points sont donn\u00e9s sous la forme d'un tuple de deux entiers. La liste des points \u00e0 traiter est donc un tableau de tuples.
On rappelle que la distance entre deux points du plan de coordonn\u00e9es \\((x;y)\\) et \\((x';y')\\) est donn\u00e9e par la formule :
\\[d=\\sqrt{(x-x')^2+(y-y')^2}\\]On importe pour cela la fonction racine carr\u00e9e (sqrt
) du module math
de Python.
Compl\u00e9ter le code des fonctions distance
et plus_courte_distance
fournies ci-dessous pour qu\u2019elles r\u00e9pondent \u00e0 leurs sp\u00e9cifications.
from math import sqrt # import de la fonction racine carr\u00e9e\n\ndef distance(point1, point2):\n\"\"\" Calcule et renvoie la distance entre deux points. \"\"\"\n return sqrt((...)**2 + (...)**2)\n\ndef plus_courte_distance(tab, depart):\n\"\"\" Renvoie le point du tableau tab se trouvant \u00e0 la plus courte distance du point depart.\"\"\"\n point = tab[0]\n min_dist = ...\n for i in range (1, ...):\n if distance(tab[i], depart)...:\n point = ...\n min_dist = ...\n return point\n
Exemples :
>>> distance((1, 0), (5, 3))\n5.0\n>>> distance((1, 0), (0, 1))\n1.4142135623730951\n>>> plus_courte_distance([(7, 9), (2, 5), (5, 2)], (0, 0))\n(2, 5)\n>>> plus_courte_distance([(7, 9), (2, 5), (5, 2)], (5, 2))\n(5, 2)\n
from math import sqrt\n\ndef distance(point1, point2):\n\"\"\" Calcule et renvoie la distance entre deux points. \"\"\"\nreturn sqrt((point1[0] - point2[0])**2 + ((point1[1] - point2[1]))**2)\ndef plus_courte_distance(tab, depart):\n\"\"\" Renvoie le point du tableau tab se trouvant \u00e0 la plus courte distance du point depart.\"\"\"\n point = tab[0]\nmin_dist = distance(point, depart)\nfor i in range (1, len(tab)):\nif distance(tab[i], depart) < min_dist:\npoint = tab[i]\nmin_dist = distance(tab[i], depart)\nreturn point\n
On souhaite programmer une fonction donnant la distance la plus courte entre un point\nde d\u00e9part et une liste de points. Les points sont tous \u00e0 coordonn\u00e9es enti\u00e8res.\nLes points sont donn\u00e9s sous la forme d'un tuple de deux entiers.\nLa liste des points \u00e0 traiter est donc un tableau de tuples.\n\nOn rappelle que la distance entre deux points du plan de coordonn\u00e9es $(x;y)$ et $(x';y')$\nest donn\u00e9e par la formule :\n\n$$d=\\sqrt{(x-x')^2+(y-y')^2}$$\n\nOn importe pour cela la fonction racine carr\u00e9e (`sqrt`) du module `math` de Python.\n\n\nCompl\u00e9ter le code des fonctions `distance` et `plus_courte_distance` fournies ci-dessous pour qu\u2019elles r\u00e9pondent \u00e0 leurs sp\u00e9cifications.\n\n```python linenums='1'\nfrom math import sqrt # import de la fonction racine carr\u00e9e\n\ndef distance(point1, point2):\n \"\"\" Calcule et renvoie la distance entre deux points. \"\"\"\n return sqrt((...)**2 + (...)**2)\n\ndef plus_courte_distance(tab, depart):\n \"\"\" Renvoie le point du tableau tab se trouvant \u00e0 la plus courte distance du point depart.\"\"\"\n point = tab[0]\n min_dist = ...\n for i in range (1, ...):\n if distance(tab[i], depart)...:\n point = ...\n min_dist = ...\n return point\n
Exemples :
>>> distance((1, 0), (5, 3))\n5.0\n>>> distance((1, 0), (0, 1))\n1.4142135623730951\n>>> plus_courte_distance([(7, 9), (2, 5), (5, 2)], (0, 0))\n(2, 5)\n>>> plus_courte_distance([(7, 9), (2, 5), (5, 2)], (5, 2))\n(5, 2)\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-07","title":"\u25b6 Sujet 07","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-071","title":"Exercice 07.1","text":"Exercice 07.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction fusion
prenant en param\u00e8tres deux tableaux non vides tab1
et tab2
(type list
) d'entiers, chacun dans l\u2019ordre croissant, et renvoyant un tableau tri\u00e9 dans l\u2019ordre croissant et contenant l\u2019ensemble des valeurs de tab1
et tab2
.
Exemples :
>>> fusion([3, 5], [2, 5])\n[2, 3, 5, 5]\n>>> fusion([-2, 4], [-3, 5, 10])\n[-3, -2, 4, 5, 10]\n>>> fusion([4], [2, 6])\n[2, 4, 6]\n
def fusion(tab1, tab2):\n tab_fusion = []\n i1 = 0\n i2 = 0\n while i1 < len(tab1) and i2 < len(tab2):\n if tab1[i1] < tab2[i2]:\n tab_fusion.append(tab1[i1])\n i1 += 1\n else:\n tab_fusion.append(tab2[i2])\n i2 += 1\n\n if i1 == len(tab1):\n while i2 < len(tab2):\n tab_fusion.append(tab2[i2])\n i2 += 1\n else:\n while i1 < len(tab1):\n tab_fusion.append(tab1[i1])\n i1 += 1 \n\n return tab_fusion\n
Programmer la fonction `fusion` prenant en param\u00e8tres deux tableaux non vides `tab1` et `tab2`\n(type `list`) d'entiers, chacun dans l\u2019ordre croissant, et renvoyant un tableau tri\u00e9 dans l\u2019ordre\ncroissant et contenant l\u2019ensemble des valeurs de `tab1` et `tab2`.\n\nExemples :\n\n```python\n>>> fusion([3, 5], [2, 5])\n[2, 3, 5, 5]\n>>> fusion([-2, 4], [-3, 5, 10])\n[-3, -2, 4, 5, 10]\n>>> fusion([4], [2, 6])\n[2, 4, 6]\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-072","title":"Exercice 07.2","text":"Exercice 07.2
\u00c9nonc\u00e9CorrectionSources MarkdownLe but de cet exercice est d\u2019\u00e9crire une fonction r\u00e9cursive traduire_romain
qui prend en param\u00e8tre une cha\u00eene de caract\u00e8res, non vide, repr\u00e9sentant un nombre \u00e9crit en chiffres romains et qui renvoie son \u00e9criture d\u00e9cimale.
Les chiffres romains consid\u00e9r\u00e9s sont : I, V, X, L, C, D et M. Ils repr\u00e9sentent respectivement les nombres 1, 5, 10, 50, 100, 500, et 1000 en base dix.
On dispose d\u2019un dictionnaire romains
dont les cl\u00e9s sont les caract\u00e8res apparaissant dans l\u2019\u00e9criture en chiffres romains et les valeurs sont les nombres entiers associ\u00e9s en \u00e9criture d\u00e9cimale :
romains = {\"I\":1, \"V\":5, \"X\":10, \"L\":50, \"C\":100, \"D\":500, \"M\":1000}
Le code de la fonction traduire_romain
fournie repose sur le principe suivant :
la valeur d\u2019un caract\u00e8re est ajout\u00e9e \u00e0 la valeur du reste de la cha\u00eene si ce caract\u00e8re a une valeur sup\u00e9rieure (ou \u00e9gale) \u00e0 celle du caract\u00e8re qui le suit ;
la valeur d\u2019un caract\u00e8re est retranch\u00e9e \u00e0 la valeur du reste de la cha\u00eene si ce caract\u00e8re a une valeur strictement inf\u00e9rieure \u00e0 celle du caract\u00e8re qui le suit.
Ainsi, XIV correspond au nombre 10 + 5 - 1 puisque :
la valeur de X (10) est sup\u00e9rieure \u00e0 celle de I (1), on ajoute donc 10 \u00e0 la valeur du reste de la cha\u00eene, c\u2019est-\u00e0-dire IV ;
la valeur de I (1) est strictement inf\u00e9rieure \u00e0 celle de V (5), on soustrait donc 1 \u00e0 la valeur du reste de la cha\u00eene, c\u2019est-\u00e0-dire V.
On rappelle que pour priver une cha\u00eene de caract\u00e8res de son premier caract\u00e8re, on utilisera l\u2019instruction :
nom_de_variable[1:]
Par exemple, si la variable mot
contient la cha\u00eene \"CDI\"
, mot[1:]
renvoie \"DI\"
.
romains = {\"I\":1, \"V\":5, \"X\":10, \"L\":50, \"C\":100, \"D\":500, \"M\":1000}\n\ndef traduire_romain(nombre):\n\"\"\" Renvoie l\u2019\u00e9criture d\u00e9cimale du nombre donn\u00e9 en chiffres\n romains \"\"\"\n if len(nombre) == 1:\n return ...\n elif romains[nombre[0]] >= ...\n return romains[nombre[0]] + ...\n else:\n return ...\n
Compl\u00e9ter le code de la fonction traduire_romain
et le tester.
Exemples :
>>> traduire_romain(\"XIV\")\n14\n>>> traduire_romain(\"CXLII\")\n142\n>>> traduire_romain(\"MMXXIII\")\n2023\n
romains = {\"I\":1, \"V\":5, \"X\":10, \"L\":50, \"C\":100, \"D\":500, \"M\":1000}\n\ndef traduire_romain(nombre):\n\"\"\" Renvoie l\u2019\u00e9criture d\u00e9cimale du nombre donn\u00e9 en chiffres\n romains \"\"\"\n if len(nombre) == 1:\nreturn romains[nombre]\nelif romains[nombre[0]] >= romains[nombre[1]]:\nreturn romains[nombre[0]] + traduire_romain(nombre[1:])\nelse:\nreturn traduire_romain(nombre[1:]) - romains[nombre[0]]\n
Le but de cet exercice est d\u2019\u00e9crire une fonction r\u00e9cursive `traduire_romain` qui prend\nen param\u00e8tre une cha\u00eene de caract\u00e8res, non vide, repr\u00e9sentant un nombre \u00e9crit en\nchiffres romains et qui renvoie son \u00e9criture d\u00e9cimale.\n\n\nLes chiffres romains consid\u00e9r\u00e9s sont : I, V, X, L, C, D et M. Ils repr\u00e9sentent\nrespectivement les nombres 1, 5, 10, 50, 100, 500, et 1000 en base dix.\n\n\nOn dispose d\u2019un dictionnaire `romains` dont les cl\u00e9s sont les caract\u00e8res apparaissant\ndans l\u2019\u00e9criture en chiffres romains et les valeurs sont les nombres entiers associ\u00e9s en\n\u00e9criture d\u00e9cimale :\n\n\n`romains = {\"I\":1, \"V\":5, \"X\":10, \"L\":50, \"C\":100, \"D\":500, \"M\":1000}`\n\n\nLe code de la fonction `traduire_romain` fournie repose sur le\nprincipe suivant :\n\n- la valeur d\u2019un caract\u00e8re est ajout\u00e9e \u00e0 la valeur du reste de la cha\u00eene si ce\ncaract\u00e8re a une valeur sup\u00e9rieure (ou \u00e9gale) \u00e0 celle du caract\u00e8re qui le suit ;\n\n- la valeur d\u2019un caract\u00e8re est retranch\u00e9e \u00e0 la valeur du reste de la cha\u00eene si ce\ncaract\u00e8re a une valeur strictement inf\u00e9rieure \u00e0 celle du caract\u00e8re qui le suit.\n\nAinsi, XIV correspond au nombre 10 + 5 - 1 puisque :\n\n- la valeur de X (10) est sup\u00e9rieure \u00e0 celle de I (1), on ajoute donc 10 \u00e0 la valeur du\nreste de la cha\u00eene, c\u2019est-\u00e0-dire IV ;\n\n- la valeur de I (1) est strictement inf\u00e9rieure \u00e0 celle de V (5), on soustrait donc 1 \u00e0\nla valeur du reste de la cha\u00eene, c\u2019est-\u00e0-dire V.\n\nOn rappelle que pour priver une cha\u00eene de caract\u00e8res de son premier caract\u00e8re, on\nutilisera l\u2019instruction :\n\n`nom_de_variable[1:]`\n\nPar exemple, si la variable `mot` contient la cha\u00eene `\"CDI\"`, `mot[1:]` renvoie `\"DI\"`.\n\n```python linenums='1'\nromains = {\"I\":1, \"V\":5, \"X\":10, \"L\":50, \"C\":100, \"D\":500, \"M\":1000}\n\ndef traduire_romain(nombre):\n \"\"\" Renvoie l\u2019\u00e9criture d\u00e9cimale du nombre donn\u00e9 en chiffres\n romains \"\"\"\n if len(nombre) == 1:\n return ...\n elif romains[nombre[0]] >= ...\n return romains[nombre[0]] + ...\n else:\n return ...\n
Compl\u00e9ter le code de la fonction traduire_romain
et le tester.
Exemples :
>>> traduire_romain(\"XIV\")\n14\n>>> traduire_romain(\"CXLII\")\n142\n>>> traduire_romain(\"MMXXIII\")\n2023\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-08","title":"\u25b6 Sujet 08","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-081","title":"Exercice 08.1","text":"Exercice 08.1
\u00c9nonc\u00e9CorrectionSource MarkdownSur le r\u00e9seau social TipTop, on s\u2019int\u00e9resse au nombre de \u00ab like \u00bb des abonn\u00e9s. Les donn\u00e9es sont stock\u00e9es dans des dictionnaires o\u00f9 les cl\u00e9s sont les pseudos et les valeurs correspondantes sont les nombres de \u00ab like \u00bb comme ci-dessous :
{'Bob': 102, 'Ada': 201, 'Alice': 103, 'Tim': 50}
\u00c9crire une fonction max_dico
qui :
dico
non vide dont les cl\u00e9s sont des cha\u00eenes de caract\u00e8res et les valeurs associ\u00e9es sont des entiers ;Exemples :
>>> max_dico({'Bob': 102, 'Ada': 201, 'Alice': 103, 'Tim': 50})\n('Ada', 201)\n>>> max_dico({'Alan': 222, 'Ada': 201, 'Eve': 220, 'Tim': 50})\n('Alan', 222)\n
def max_dico(dico):\n cle_max = ''\n val_max = 0\n for cle in dico:\n if dico[cle] > val_max:\n val_max = dico[cle]\n cle_max = cle\n return (cle_max, val_max)\n
Sur le r\u00e9seau social TipTop, on s\u2019int\u00e9resse au nombre de \u00ab like \u00bb des abonn\u00e9s.\nLes donn\u00e9es sont stock\u00e9es dans des dictionnaires o\u00f9 les cl\u00e9s sont les pseudos et les valeurs\ncorrespondantes sont les nombres de \u00ab like \u00bb comme ci-dessous :\n\n`{'Bob': 102, 'Ada': 201, 'Alice': 103, 'Tim': 50}`\n\n\u00c9crire une fonction `max_dico` qui :\n\n- Prend en param\u00e8tre un dictionnaire `dico` non vide dont les cl\u00e9s sont des cha\u00eenes de\ncaract\u00e8res et les valeurs associ\u00e9es sont des entiers ;\n- Renvoie un tuple dont :\n - La premi\u00e8re valeur est la cl\u00e9 du dictionnaire associ\u00e9e \u00e0 la valeur maximale ;\n - La seconde valeur est la premi\u00e8re valeur maximale pr\u00e9sente dans le\ndictionnaire.\n\nExemples :\n\n```python\n>>> max_dico({'Bob': 102, 'Ada': 201, 'Alice': 103, 'Tim': 50})\n('Ada', 201)\n>>> max_dico({'Alan': 222, 'Ada': 201, 'Eve': 220, 'Tim': 50})\n('Alan', 222)\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-082","title":"Exercice 08.2","text":"Exercice 08.2
\u00c9nonc\u00e9CorrectionSources MarkdownNous avons l\u2019habitude de noter les expressions arithm\u00e9tiques avec des parenth\u00e8ses comme par exemple : (2 + 3) \u00d7 5.
Il existe une autre notation utilis\u00e9e par certaines calculatrices, appel\u00e9e notation postfixe, qui n\u2019utilise pas de parenth\u00e8ses. L\u2019expression arithm\u00e9tique pr\u00e9c\u00e9dente est alors obtenue en saisissant successivement 2, puis 3, puis l\u2019op\u00e9rateur +, puis 5, et enfin l\u2019op\u00e9rateur \u00d7. On mod\u00e9lise cette saisie par le tableau [2, 3, '+', 5, '*'].
Autre exemple, la notation postfixe de 3 \u00d7 2 + 5 est mod\u00e9lis\u00e9e par le tableau :
[3, 2, '*', 5, '+'].
D\u2019une mani\u00e8re plus g\u00e9n\u00e9rale, la valeur associ\u00e9e \u00e0 une expression arithm\u00e9tique en notation postfixe est d\u00e9termin\u00e9e \u00e0 l\u2019aide d\u2019une pile en parcourant l\u2019expression arithm\u00e9tique de gauche \u00e0 droite de la fa\u00e7on suivante :
Dans le cadre de cet exercice, on se limitera aux op\u00e9rations \u00d7 et +.
Pour cet exercice, on dispose d\u2019une classe Pile
qui impl\u00e9mente les m\u00e9thodes de base sur la structure de pile.
Compl\u00e9ter le script de la fonction eval_expression
qui re\u00e7oit en param\u00e8tre une liste python repr\u00e9sentant la notation postfixe d\u2019une expression arithm\u00e9tique et qui renvoie sa valeur associ\u00e9e.
class Pile:\n\"\"\"Classe d\u00e9finissant une structure de pile.\"\"\"\n def __init__(self):\n self.contenu = []\n\n def est_vide(self):\n\"\"\"Renvoie le bool\u00e9en True si la pile est vide, False sinon.\"\"\"\n return self.contenu == []\n\n def empiler(self, v):\n\"\"\"Place l'\u00e9l\u00e9ment v au sommet de la pile\"\"\"\n self.contenu.append(v)\n\n def depiler(self):\n\"\"\"\n Retire et renvoie l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile,\n si la pile n\u2019est pas vide.\n \"\"\"\n if not self.est_vide():\n return self.contenu.pop()\n\n\ndef eval_expression(tab):\n p = Pile()\n for ... in tab:\n if element != '+' ... element != '*':\n p.empiler(...)\n else:\n if element == ...:\n resultat = p.depiler() + ...\n else:\n resultat = ...\n p.empiler(...)\n return ...\n
Exemple :
>>> eval_expression([2, 3, '+', 5, '*'])\n25\n
class Pile:\n\"\"\"Classe d\u00e9finissant une structure de pile.\"\"\"\n def __init__(self):\n self.contenu = []\n\n def est_vide(self):\n\"\"\"Renvoie le bool\u00e9en True si la pile est vide, False sinon.\"\"\"\n return self.contenu == []\n\n def empiler(self, v):\n\"\"\"Place l'\u00e9l\u00e9ment v au sommet de la pile\"\"\"\n self.contenu.append(v)\n\n def depiler(self):\n\"\"\"\n Retire et renvoie l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile,\n si la pile n\u2019est pas vide.\n \"\"\"\n if not self.est_vide():\n return self.contenu.pop()\n\n\ndef eval_expression(tab):\n p = Pile()\nfor element in tab:\nif element != '+' and element != '*':\np.empiler(element)\nelse:\nif element == '+':\nresultat = p.depiler() + p.depiler()\nelse:\nresultat = p.depiler() * p.depiler()\np.empiler(resultat)\nreturn p.depiler()\n
Nous avons l\u2019habitude de noter les expressions arithm\u00e9tiques avec des parenth\u00e8ses comme\npar exemple : (2 + 3) \u00d7 5. \n\nIl existe une autre notation utilis\u00e9e par certaines calculatrices, appel\u00e9e notation postfixe, qui n\u2019utilise pas de parenth\u00e8ses. L\u2019expression arithm\u00e9tique pr\u00e9c\u00e9dente est alors obtenue en\nsaisissant successivement 2, puis 3, puis l\u2019op\u00e9rateur +, puis 5, et enfin l\u2019op\u00e9rateur \u00d7. On\nmod\u00e9lise cette saisie par le tableau [2, 3, '+', 5, '*']. \n\nAutre exemple, la notation postfixe de 3 \u00d7 2 + 5 est mod\u00e9lis\u00e9e par le tableau : \n\n[3, 2, '*', 5, '+']. \n\n\nD\u2019une mani\u00e8re plus g\u00e9n\u00e9rale, la valeur associ\u00e9e \u00e0 une expression arithm\u00e9tique en notation\npostfixe est d\u00e9termin\u00e9e \u00e0 l\u2019aide d\u2019une pile en parcourant l\u2019expression arithm\u00e9tique de gauche\n\u00e0 droite de la fa\u00e7on suivante :\n\n- Si l\u2019\u00e9l\u00e9ment parcouru est un nombre, on le place au sommet de la pile ;\n- Si l\u2019\u00e9l\u00e9ment parcouru est un op\u00e9rateur, on r\u00e9cup\u00e8re les deux \u00e9l\u00e9ments situ\u00e9s au\nsommet de la pile et on leur applique l\u2019op\u00e9rateur. On place alors le r\u00e9sultat au sommet\nde la pile.\n- \u00c0 la fin du parcours, il reste alors un seul \u00e9l\u00e9ment dans la pile qui est le r\u00e9sultat de\nl\u2019expression arithm\u00e9tique.\n\n\nDans le cadre de cet exercice, on se limitera aux op\u00e9rations \u00d7 et +.\n\n\nPour cet exercice, on dispose d\u2019une classe `Pile` qui impl\u00e9mente les m\u00e9thodes de base sur la\nstructure de pile.\n\nCompl\u00e9ter le script de la fonction `eval_expression` qui re\u00e7oit en param\u00e8tre une liste python\nrepr\u00e9sentant la notation postfixe d\u2019une expression arithm\u00e9tique et qui renvoie sa valeur\nassoci\u00e9e.\n\n```python linenums='1'\nclass Pile:\n \"\"\"Classe d\u00e9finissant une structure de pile.\"\"\"\n def __init__(self):\n self.contenu = []\n\n def est_vide(self):\n \"\"\"Renvoie le bool\u00e9en True si la pile est vide, False sinon.\"\"\"\n return self.contenu == []\n\n def empiler(self, v):\n \"\"\"Place l'\u00e9l\u00e9ment v au sommet de la pile\"\"\"\n self.contenu.append(v)\n\n def depiler(self):\n \"\"\"\n Retire et renvoie l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile,\n si la pile n\u2019est pas vide.\n \"\"\"\n if not self.est_vide():\n return self.contenu.pop()\n\n\ndef eval_expression(tab):\n p = Pile()\n for ... in tab:\n if element != '+' ... element != '*':\n p.empiler(...)\n else:\n if element == ...:\n resultat = p.depiler() + ...\n else:\n resultat = ...\n p.empiler(...)\n return ...\n
Exemple :
>>> eval_expression([2, 3, '+', 5, '*'])\n25\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-09","title":"\u25b6 Sujet 09","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-091","title":"Exercice 09.1","text":"Exercice 09.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction multiplication
, prenant en param\u00e8tres deux nombres entiers n1
et n2
, et qui renvoie le produit de ces deux nombres. Les seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.
Exemples :
>>> multiplication(3,5)\n15\n>>> multiplication(-4,-8)\n32\n>>> multiplication(-2,6)\n-12\n>>> multiplication(-2,0)\n0\n
def multiplication(n1, n2):\n if n1 < 0:\n return -multiplication(-n1, n2)\n if n2 < 0:\n return -multiplication(n1, -n2)\n resultat = 0\n for _ in range(n2):\n resultat += n1\n return resultat\n
Programmer la fonction `multiplication`, prenant en param\u00e8tres deux nombres entiers\n`n1` et `n2`, et qui renvoie le produit de ces deux nombres.\nLes seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.\n\nExemples :\n```python\n>>> multiplication(3,5)\n15\n>>> multiplication(-4,-8)\n32\n>>> multiplication(-2,6)\n-12\n>>> multiplication(-2,0)\n0\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-092","title":"Exercice 09.2","text":"Exercice 09.2
\u00c9nonc\u00e9CorrectionSources MarkdownSoit tab
un tableau non vide d'entiers tri\u00e9s dans l'ordre croissant et n
un entier.
La fonction chercher
ci-dessous doit renvoyer un indice o\u00f9 la valeur n
appara\u00eet dans tab
si cette valeur y figure et None
sinon.
Les param\u00e8tres de la fonction sont :
tab
, le tableau dans lequel s'effectue la recherche ;n
, l'entier \u00e0 chercher dans le tableau ;i
, l'indice de d\u00e9but de la partie du tableau o\u00f9 s'effectue la recherche ;j
, l'indice de fin de la partie du tableau o\u00f9 s'effectue la recherche.L\u2019algorithme demand\u00e9 est une recherche dichotomique r\u00e9cursive.
Recopier et compl\u00e9ter le code de la fonction chercher
suivante :
def chercher(tab, n, i, j):\n if i < 0 or j > len(tab) :\n return None\n if i > j :\n return None\n m = (i + j) // ...\n if ... < n :\n return chercher(tab, n, ... , ...)\n elif ... > n :\n return chercher(tab, n, ... , ... )\n else :\n return ...\n
L'ex\u00e9cution du code doit donner :
>>> chercher([1, 5, 6, 6, 9, 12], 7, 0, 10)\n\n>>> chercher([1, 5, 6, 6, 9, 12], 7, 0, 5)\n\n>>> chercher([1, 5, 6, 6, 9, 12], 9, 0, 5)\n4\n>>> chercher([1, 5, 6, 6, 9, 12], 6, 0, 5)\n2\n
def chercher(tab, n, i, j):\n if i < 0 or j > len(tab) :\n return None\n if i > j :\n return None\nm = (i + j) // 2\nif tab[m] < n :\nreturn chercher(tab, n, m+1 , j)\nelif tab[m] > n :\nreturn chercher(tab, n, i , m-1 )\nelse :\nreturn m\n
Soit `tab` un tableau non vide d'entiers tri\u00e9s dans l'ordre croissant et `n` un entier.\n\nLa fonction `chercher` ci-dessous doit renvoyer un indice o\u00f9 la valeur `n`\nappara\u00eet dans `tab` si cette valeur y figure et `None` sinon. \n\nLes param\u00e8tres de la fonction sont :\n\n- `tab`, le tableau dans lequel s'effectue la recherche ;\n- `n`, l'entier \u00e0 chercher dans le tableau ;\n- `i`, l'indice de d\u00e9but de la partie du tableau o\u00f9 s'effectue la recherche ;\n- `j`, l'indice de fin de la partie du tableau o\u00f9 s'effectue la recherche.\n\nL\u2019algorithme demand\u00e9 est une recherche dichotomique r\u00e9cursive.\n\nRecopier et compl\u00e9ter le code de la fonction `chercher` suivante :\n\n```python linenums='1'\ndef chercher(tab, n, i, j):\n if i < 0 or j > len(tab) :\n return None\n if i > j :\n return None\n m = (i + j) // ...\n if ... < n :\n return chercher(tab, n, ... , ...)\n elif ... > n :\n return chercher(tab, n, ... , ... )\n else :\n return ...\n
L'ex\u00e9cution du code doit donner :
>>> chercher([1, 5, 6, 6, 9, 12], 7, 0, 10)\n\n>>> chercher([1, 5, 6, 6, 9, 12], 7, 0, 5)\n\n>>> chercher([1, 5, 6, 6, 9, 12], 9, 0, 5)\n4\n>>> chercher([1, 5, 6, 6, 9, 12], 6, 0, 5)\n2\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-10","title":"\u25b6 Sujet 10","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-101","title":"Exercice 10.1","text":"Exercice 10.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire la fonction maxliste
, prenant en param\u00e8tre un tableau non vide de nombres tab
(de type list
) et renvoyant le plus grand \u00e9l\u00e9ment de ce tableau.
Exemples :
>>> maxliste([98, 12, 104, 23, 131, 9])\n131\n>>> maxliste([-27, 24, -3, 15])\n24\n
def maxliste(tab):\n maximum = tab[0]\n for element in tab:\n if element > maximum:\n maximum = element\n return maximum\n
\u00c9crire la fonction `maxliste`, prenant en param\u00e8tre un tableau non vide de nombres `tab` (de type\n`list`) et renvoyant le plus grand \u00e9l\u00e9ment de ce tableau.\n\nExemples :\n\n```python\n>>> maxliste([98, 12, 104, 23, 131, 9])\n131\n>>> maxliste([-27, 24, -3, 15])\n24\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-102","title":"Exercice 10.2","text":"Exercice 10.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn dispose de cha\u00eenes de caract\u00e8res contenant uniquement des parenth\u00e8ses ouvrantes et fermantes.
Un parenth\u00e9sage est correct si :
Ainsi, ((()())(()))
est un parenth\u00e9sage correct.
Les parenth\u00e9sages ())(()
et (())(()
sont, eux, incorrects.
On dispose du code de la classe Pile
suivant :
class Pile:\n\"\"\" Classe d\u00e9finissant une pile \"\"\"\n def __init__(self):\n self.valeurs = []\n\n def est_vide(self):\n\"\"\"Renvoie True si la pile est vide, False sinon\"\"\"\n return self.valeurs == []\n\n def empiler(self, c):\n\"\"\"Place l\u2019\u00e9l\u00e9ment c au sommet de la pile\"\"\"\n self.valeurs.append(c)\n\n def depiler(self):\n\"\"\"Supprime l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile, \u00e0 condition qu\u2019elle soit non vide\"\"\"\n if self.est_vide() == False:\n self.valeurs.pop()\n
On souhaite programmer une fonction parenthesage qui prend en param\u00e8tre une cha\u00eene de caract\u00e8res ch
form\u00e9e de parenth\u00e8ses et renvoie True
si la cha\u00eene est bien parenth\u00e9s\u00e9e et False
sinon.
Cette fonction utilise une pile et suit le principe suivant : en parcourant la cha\u00eene de gauche \u00e0 droite, si on trouve une parenth\u00e8se ouvrante, on l\u2019empile au sommet de la pile et si on trouve une parenth\u00e8se fermante, on d\u00e9pile (si possible) la parenth\u00e8se ouvrante stock\u00e9e au sommet de la pile.
La cha\u00eene est alors bien parenth\u00e9s\u00e9e si, \u00e0 la fin du parcours, la pile est vide.
Elle est, par contre, mal parenth\u00e9s\u00e9e :
def parenthesage(ch):\n\"\"\"Renvoie True si la cha\u00eene ch est bien parenth\u00e9s\u00e9e et False sinon\"\"\"\n p = Pile()\n for c in ch:\n if c == ...:\n p.empiler(c)\n elif c == ...:\n if p.est_vide():\n return ...\n else:\n ...\n return p.est_vide()\n
Compl\u00e9ter le code de la fonction parenthesage
.
Exemples :
>>> parenthesage(\"((()())(()))\")\nTrue\n>>> parenthesage(\"())(()\")\nFalse\n>>> parenthesage(\"(())(()\")\nFalse\n
class Pile:\n\"\"\" Classe d\u00e9finissant une pile \"\"\"\n def __init__(self):\n self.valeurs = []\n\n def est_vide(self):\n\"\"\"Renvoie True si la pile est vide, False sinon\"\"\"\n return self.valeurs == []\n\n def empiler(self, c):\n\"\"\"Place l\u2019\u00e9l\u00e9ment c au sommet de la pile\"\"\"\n self.valeurs.append(c)\n\n def depiler(self):\n\"\"\"Supprime l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile, \u00e0 condition qu\u2019elle soit non vide\"\"\"\n if self.est_vide() == False:\n self.valeurs.pop()\n\ndef parenthesage(ch):\n\"\"\"Renvoie True si la cha\u00eene ch est bien parenth\u00e9s\u00e9e et False sinon\"\"\"\n p = Pile()\n for c in ch:\nif c == '(':\np.empiler(c)\nelif c == ')':\nif p.est_vide():\nreturn False\nelse:\np.depiler()\nreturn p.est_vide()\n
On dispose de cha\u00eenes de caract\u00e8res contenant uniquement des parenth\u00e8ses ouvrantes et\nfermantes. \n\nUn parenth\u00e9sage est correct si :\n\n- le nombre de parenth\u00e8ses ouvrantes de la cha\u00eene est \u00e9gal au nombre de parenth\u00e8ses\nfermantes.\n- en parcourant la cha\u00eene de gauche \u00e0 droite, le nombre de parenth\u00e8ses d\u00e9j\u00e0 ouvertes doit\n\u00eatre, \u00e0 tout moment, sup\u00e9rieur ou \u00e9gal au nombre de parenth\u00e8ses d\u00e9j\u00e0 ferm\u00e9es.\n\n\nAinsi, `((()())(()))` est un parenth\u00e9sage correct. \n\nLes parenth\u00e9sages `())(()` et `(())(()` sont, eux, incorrects.\n\n\nOn dispose du code de la classe `Pile` suivant :\n\n```python linenums='1'\nclass Pile:\n \"\"\" Classe d\u00e9finissant une pile \"\"\"\n def __init__(self):\n self.valeurs = []\n\n def est_vide(self):\n \"\"\"Renvoie True si la pile est vide, False sinon\"\"\"\n return self.valeurs == []\n\n def empiler(self, c):\n \"\"\"Place l\u2019\u00e9l\u00e9ment c au sommet de la pile\"\"\"\n self.valeurs.append(c)\n\n def depiler(self):\n \"\"\"Supprime l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile, \u00e0 condition qu\u2019elle soit non vide\"\"\"\n if self.est_vide() == False:\n self.valeurs.pop()\n
On souhaite programmer une fonction parenthesage qui prend en param\u00e8tre une cha\u00eene de caract\u00e8res ch
form\u00e9e de parenth\u00e8ses et renvoie True
si la cha\u00eene est bien parenth\u00e9s\u00e9e et False
sinon.
Cette fonction utilise une pile et suit le principe suivant : en parcourant la cha\u00eene de gauche \u00e0 droite, si on trouve une parenth\u00e8se ouvrante, on l\u2019empile au sommet de la pile et si on trouve une parenth\u00e8se fermante, on d\u00e9pile (si possible) la parenth\u00e8se ouvrante stock\u00e9e au sommet de la pile.
La cha\u00eene est alors bien parenth\u00e9s\u00e9e si, \u00e0 la fin du parcours, la pile est vide.
Elle est, par contre, mal parenth\u00e9s\u00e9e :
def parenthesage(ch):\n\"\"\"Renvoie True si la cha\u00eene ch est bien parenth\u00e9s\u00e9e et False sinon\"\"\"\n p = Pile()\n for c in ch:\n if c == ...:\n p.empiler(c)\n elif c == ...:\n if p.est_vide():\n return ...\n else:\n ...\n return p.est_vide()\n
Compl\u00e9ter le code de la fonction parenthesage
.
Exemples :
>>> parenthesage(\"((()())(()))\")\nTrue\n>>> parenthesage(\"())(()\")\nFalse\n>>> parenthesage(\"(())(()\")\nFalse\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-11","title":"\u25b6 Sujet 11","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-111","title":"Exercice 11.1","text":"Exercice 11.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn mod\u00e9lise la repr\u00e9sentation binaire d'un entier non sign\u00e9 par un tableau d'entiers dont les \u00e9l\u00e9ments sont 0 ou 1. Par exemple, le tableau [1, 0, 1, 0, 0, 1, 1]
repr\u00e9sente l'\u00e9criture binaire de l'entier dont l'\u00e9criture d\u00e9cimale est 2**6 + 2**4 + 2**1 + 2**0 = 83
.
\u00c0 l'aide d'un parcours s\u00e9quentiel, \u00e9crire la fonction convertir
r\u00e9pondant aux sp\u00e9cifications suivantes :
def convertir(tab):\n\"\"\"\n tab est un tableau d'entiers, dont les \u00e9l\u00e9ments sont 0 ou 1 et\n repr\u00e9sentant un entier \u00e9crit en binaire. Renvoie l'\u00e9criture\n d\u00e9cimale de l'entier positif dont la repr\u00e9sentation binaire\n est donn\u00e9e par le tableau tab\n \"\"\"\n
Exemple : >>> convertir([1, 0, 1, 0, 0, 1, 1])\n83\n>>> convertir([1, 0, 0, 0, 0, 0, 1, 0])\n130\n
def convertir(tab):\n puissance = 0\n total = 0\n for i in range(len(tab)-1, -1, -1):\n total += tab[i]*(2**puissance)\n puissance += 1\n return total\n
On mod\u00e9lise la repr\u00e9sentation binaire d'un entier non sign\u00e9 par un tableau d'entiers dont\nles \u00e9l\u00e9ments sont 0 ou 1. Par exemple, le tableau `[1, 0, 1, 0, 0, 1, 1]` repr\u00e9sente\nl'\u00e9criture binaire de l'entier dont l'\u00e9criture d\u00e9cimale est\n`2**6 + 2**4 + 2**1 + 2**0 = 83`.\n\n\u00c0 l'aide d'un parcours s\u00e9quentiel, \u00e9crire la fonction `convertir` r\u00e9pondant aux\nsp\u00e9cifications suivantes :\n\n```python\ndef convertir(tab):\n \"\"\"\n tab est un tableau d'entiers, dont les \u00e9l\u00e9ments sont 0 ou 1 et\n repr\u00e9sentant un entier \u00e9crit en binaire. Renvoie l'\u00e9criture\n d\u00e9cimale de l'entier positif dont la repr\u00e9sentation binaire\n est donn\u00e9e par le tableau tab\n \"\"\"\n```\nExemple :\n```python\n>>> convertir([1, 0, 1, 0, 0, 1, 1])\n83\n>>> convertir([1, 0, 0, 0, 0, 0, 1, 0])\n130\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-112","title":"Exercice 11.2","text":"Exercice 11.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa fonction tri_insertion
suivante prend en argument une liste tab
et trie cette liste en utilisant la m\u00e9thode du tri par insertion. Compl\u00e9ter cette fonction pour qu'elle r\u00e9ponde \u00e0 la sp\u00e9cification demand\u00e9e.
On rappelle le principe du tri par insertion : on consid\u00e8re les \u00e9l\u00e9ments \u00e0 trier un par un, le premier \u00e9l\u00e9ment constituant, \u00e0 lui tout seul, une liste tri\u00e9e de longueur 1. On range ensuite le second \u00e9l\u00e9ment pour constituer une liste tri\u00e9e de longueur 2, puis on range le troisi\u00e8me \u00e9l\u00e9ment pour avoir une liste tri\u00e9e de longueur 3 et ainsi de suite\u2026 A chaque \u00e9tape, le premier \u00e9l\u00e9ment de la sous-liste non tri\u00e9e est plac\u00e9 dans la sous-liste des \u00e9l\u00e9ments d\u00e9j\u00e0 tri\u00e9s de sorte que cette sous-liste demeure tri\u00e9e.
Le principe du tri par insertion est donc d'ins\u00e9rer \u00e0 la n-i\u00e8me it\u00e9ration, le n-i\u00e8me \u00e9l\u00e9ment \u00e0 la bonne place.
def tri_insertion(tab):\n n = len(tab)\n for i in range(1, n):\n valeur_insertion = tab[...]\n # la variable j sert \u00e0 d\u00e9terminer o\u00f9 placer la valeur \u00e0 ranger\n j = ...\n # tant qu'on a pas trouv\u00e9 la place de l'\u00e9l\u00e9ment \u00e0 ins\u00e9rer\n # on d\u00e9cale les valeurs du tableau vers la droite\n while j > ... and valeur_insertion < tab[...]:\n tab[j] = tab[j-1]\n j = ...\n tab[j] = ...\n
Exemples :
>>> liste = [9, 5, 8, 4, 0, 2, 7, 1, 10, 3, 6]\n>>> tri_insertion(liste)\n>>> liste\n[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n
def tri_insertion(tab):\n n = len(tab)\n for i in range(1, n):\nvaleur_insertion = tab[i]\n# la variable j sert \u00e0 d\u00e9terminer o\u00f9 placer la valeur \u00e0 ranger\nj = i\n# tant qu'on a pas trouv\u00e9 la place de l'\u00e9l\u00e9ment \u00e0 ins\u00e9rer\n # on d\u00e9cale les valeurs du tableau vers la droite\nwhile j > 0 and valeur_insertion < tab[j-1]:\ntab[j] = tab[j-1]\nj = j - 1\ntab[j] = valeur_insertion\n
La fonction `tri_insertion` suivante prend en argument une liste `tab` et trie cette liste en\nutilisant la m\u00e9thode du tri par insertion. Compl\u00e9ter cette fonction pour qu'elle r\u00e9ponde \u00e0 la\nsp\u00e9cification demand\u00e9e.\n\nOn rappelle le principe du tri par insertion : on consid\u00e8re les \u00e9l\u00e9ments \u00e0 trier un par un,\nle premier \u00e9l\u00e9ment constituant, \u00e0 lui tout seul, une liste tri\u00e9e de longueur 1. On range\nensuite le second \u00e9l\u00e9ment pour constituer une liste tri\u00e9e de longueur 2, puis on range le\ntroisi\u00e8me \u00e9l\u00e9ment pour avoir une liste tri\u00e9e de longueur 3 et ainsi de suite\u2026 A chaque\n\u00e9tape, le premier \u00e9l\u00e9ment de la sous-liste non tri\u00e9e est plac\u00e9 dans la sous-liste des\n\u00e9l\u00e9ments d\u00e9j\u00e0 tri\u00e9s de sorte que cette sous-liste demeure tri\u00e9e. \n\nLe principe du tri par insertion est donc d'ins\u00e9rer \u00e0 la n-i\u00e8me it\u00e9ration, le n-i\u00e8me \u00e9l\u00e9ment\n\u00e0 la bonne place.\n\n\n```python linenums='1'\ndef tri_insertion(tab):\n n = len(tab)\n for i in range(1, n):\n valeur_insertion = tab[...]\n # la variable j sert \u00e0 d\u00e9terminer o\u00f9 placer la valeur \u00e0 ranger\n j = ...\n # tant qu'on a pas trouv\u00e9 la place de l'\u00e9l\u00e9ment \u00e0 ins\u00e9rer\n # on d\u00e9cale les valeurs du tableau vers la droite\n while j > ... and valeur_insertion < tab[...]:\n tab[j] = tab[j-1]\n j = ...\n tab[j] = ...\n
Exemples :
>>> liste = [9, 5, 8, 4, 0, 2, 7, 1, 10, 3, 6]\n>>> tri_insertion(liste)\n>>> liste\n[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-12","title":"\u25b6 Sujet 12","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-121","title":"Exercice 12.1","text":"Exercice 12.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn consid\u00e8re la classe ABR
, dont le constructeur est le suivant :
class ABR:\n def __init__(self, g0, v0, d0):\n self.gauche = g0\n self.cle = v0\n self.droit = d0\n\n def __repr__(self):\n if self is None:\n return ''\n else:\n return '(' + (self.gauche).__repr__() + ',' + str(self.cle) + ',' +(self.droit).__repr__() + ')'\n
Ainsi, l\u2019arbre binaire de recherche abr1
ci- contre est cr\u00e9\u00e9 par le code python ci- dessous
n0 = ABR(None, 0, None)\nn3 = ABR(None, 3, None)\nn2 = ABR(None, 2, n3)\nn3 = ABR(n0, 1, n2)\n
Dans tout le code, None
correspondra \u00e0 un arbre vide.
La classe ABR
dispose aussi d\u2019une m\u00e9thode de repr\u00e9sentation (__repr__
), qui affiche entre parenth\u00e8ses le contenu du sous arbre gauche, puis la cl\u00e9 de l\u2019arbre, et enfin le contenu du sous arbre droit. Elle s\u2019utilise en console de la mani\u00e8re suivante :
>>> abr1\n((None,0,None),1,(None,2,(None,3,None)))\n
\u00c9crire une fonction r\u00e9cursive ajoute(cle, a)
qui prend en param\u00e8tres une cl\u00e9 cle
et un arbre binaire de recherche a
, et qui renvoie un arbre binaire de recherche dans lequel cle
a \u00e9t\u00e9 ins\u00e9r\u00e9e. Dans le cas o\u00f9 cle
est d\u00e9j\u00e0 pr\u00e9sente dans a
, la fonction renvoie l\u2019arbre a
inchang\u00e9.
R\u00e9sultats \u00e0 obtenir :
>>> a = ajoute(4, abr1)\n>>> a\n((None,0,None),1,(None,2,(None,3,(None,4,None))))\n\n>>> ajoute(-5, abr1)\n(((None,-5,None),0,None),1,(None,2,(None,3,None)))\n\n>>> ajoute(2, abr1)\n((None,0,None),1,(None,2,(None,3,None)))\n
def ajoute(cle, a): \n if a is None:\n a = ABR(None, cle, None)\n elif cle > a.cle:\n a.droit = ajoute(cle, a.droit)\n elif cle < a.cle:\n a.gauche = ajoute(cle, a.gauche)\n return a\n
On consid\u00e8re la classe `ABR`, dont le constructeur est le suivant :\n\n```python\nclass ABR:\n def __init__(self, g0, v0, d0):\n self.gauche = g0\n self.cle = v0\n self.droit = d0\n\n def __repr__(self):\n if self is None:\n return ''\n else:\n return '(' + (self.gauche).__repr__() + ',' + str(self.cle) + ',' +(self.droit).__repr__() + ')'\n\n```\n\n![image](data2023/12_arbre.png){: .center width=30%}\n\nAinsi, l\u2019arbre binaire de recherche `abr1` ci-\ncontre est cr\u00e9\u00e9 par le code python ci-\ndessous\n\n```python\nn0 = ABR(None, 0, None)\nn3 = ABR(None, 3, None)\nn2 = ABR(None, 2, n3)\nn3 = ABR(n0, 1, n2)\n```\n\nDans tout le code, `None` correspondra \u00e0 un arbre vide.\n\nLa classe `ABR` dispose aussi d\u2019une m\u00e9thode de repr\u00e9sentation (```__repr__``` ), qui affiche entre\nparenth\u00e8ses le contenu du sous arbre gauche, puis la cl\u00e9 de l\u2019arbre, et enfin le\ncontenu du sous arbre droit. Elle s\u2019utilise en console de la mani\u00e8re suivante :\n\n```python\n>>> abr1\n((None,0,None),1,(None,2,(None,3,None)))\n```\n\n\u00c9crire une fonction r\u00e9cursive `ajoute(cle, a)` qui prend en param\u00e8tres une cl\u00e9 `cle`\net un arbre binaire de recherche ```a``` , et qui renvoie un arbre binaire de recherche dans\nlequel `cle` a \u00e9t\u00e9 ins\u00e9r\u00e9e.\nDans le cas o\u00f9 `cle` est d\u00e9j\u00e0 pr\u00e9sente dans `a`, la fonction renvoie l\u2019arbre `a` inchang\u00e9.\n\nR\u00e9sultats \u00e0 obtenir :\n\n```python\n>>> a = ajoute(4, abr1)\n>>> a\n((None,0,None),1,(None,2,(None,3,(None,4,None))))\n\n>>> ajoute(-5, abr1)\n(((None,-5,None),0,None),1,(None,2,(None,3,None)))\n\n>>> ajoute(2, abr1)\n((None,0,None),1,(None,2,(None,3,None)))\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-122","title":"Exercice 12.2","text":"Exercice 12.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn dispose d\u2019un ensemble d\u2019objets dont on conna\u00eet, pour chacun, la masse. On souhaite ranger l\u2019ensemble de ces objets dans des boites identiques de telle mani\u00e8re que la somme des masses des objets contenus dans une bo\u00eete ne d\u00e9passe pas la capacit\u00e9 c
de la bo\u00eete. On souhaite utiliser le moins de bo\u00eetes possibles pour ranger cet ensemble d\u2019objets.
Pour r\u00e9soudre ce probl\u00e8me, on utilisera un algorithme glouton consistant \u00e0 placer chacun des objets dans la premi\u00e8re bo\u00eete o\u00f9 cela est possible.
Par exemple, pour ranger dans des bo\u00eetes de capacit\u00e9 c = 5
un ensemble de trois objets dont les masses sont repr\u00e9sent\u00e9es en Python par la liste [1, 5, 2]
, on proc\u00e8de de la fa\u00e7on suivante :
On a donc utilis\u00e9 deux bo\u00eetes de capacit\u00e9 c = 5
pour ranger les 3 objets.
Compl\u00e9ter la fonction Python empaqueter(liste_masses, c)
suivante pour qu\u2019elle renvoie le nombre de bo\u00eetes de capacit\u00e9 c n\u00e9cessaires pour empaqueter un ensemble d\u2019objets dont les masses sont contenues dans la liste liste_masses
.
def empaqueter(liste_masses, c):\n n = len(liste_masses)\n nb_boites = 0\n boites = [0]*n\n for masse in ... :\n i = 0\n while i <= nb_boites and boites[i] + ... > C:\n i = i + 1\n if i == nb_boites + 1:\n ...\n boites[i] = ...\n return ...\n
Tester ensuite votre fonction :
>>> empaqueter([7, 6, 3, 4, 8, 5, 9, 2], 11)\n5\n
def empaqueterR(liste_masses, c):\n n = len(liste_masses)\n nb_boites = 0\n boites = [0]*n\nfor masse in liste_masses :\ni = 0\nwhile i <= nb_boites and boites[i] + masse > c:\ni = i + 1\n if i == nb_boites + 1:\nnb_boites = nb_boites + 1\nboites[i] = boites[i] + masse\nreturn nb_boites + 1\n
On dispose d\u2019un ensemble d\u2019objets dont on conna\u00eet, pour chacun, la masse. On\nsouhaite ranger l\u2019ensemble de ces objets dans des boites identiques de telle\nmani\u00e8re que la somme des masses des objets contenus dans une bo\u00eete ne d\u00e9passe\npas la capacit\u00e9 `c` de la bo\u00eete. On souhaite utiliser le moins de bo\u00eetes possibles pour\nranger cet ensemble d\u2019objets.\n\n\nPour r\u00e9soudre ce probl\u00e8me, on utilisera un algorithme glouton consistant \u00e0 placer\nchacun des objets dans la premi\u00e8re bo\u00eete o\u00f9 cela est possible.\n\nPar exemple, pour ranger dans des bo\u00eetes de capacit\u00e9 `c = 5` un ensemble de trois\nobjets dont les masses sont repr\u00e9sent\u00e9es en Python par la liste `[1, 5, 2]`, on\nproc\u00e8de de la fa\u00e7on suivante :\n\n- Le premier objet, de masse 1, va dans une premi\u00e8re boite.\n- Le deuxi\u00e8me objet, de masse 5, ne peut pas aller dans la m\u00eame boite que le\npremier objet car cela d\u00e9passerait la capacit\u00e9 de la boite. On place donc cet\nobjet dans une deuxi\u00e8me bo\u00eete.\n- Le troisi\u00e8me objet, de masse 2, va dans la premi\u00e8re bo\u00eete.\n\nOn a donc utilis\u00e9 deux bo\u00eetes de capacit\u00e9 `c = 5` pour ranger les 3 objets.\n\nCompl\u00e9ter la fonction Python `empaqueter(liste_masses, c)` suivante pour\nqu\u2019elle renvoie le nombre de bo\u00eetes de capacit\u00e9 c n\u00e9cessaires pour empaqueter un\nensemble d\u2019objets dont les masses sont contenues dans la liste `liste_masses`.\n\n```python linenums='1'\ndef empaqueter(liste_masses, c):\n n = len(liste_masses)\n nb_boites = 0\n boites = [0]*n\n for masse in ... :\n i = 0\n while i <= nb_boites and boites[i] + ... > C:\n i = i + 1\n if i == nb_boites + 1:\n ...\n boites[i] = ...\n return ...\n
Tester ensuite votre fonction :
>>> empaqueter([7, 6, 3, 4, 8, 5, 9, 2], 11)\n5\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-13","title":"\u25b6 Sujet 13","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-131","title":"Exercice 13.1","text":"Exercice 13.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire en langage Python une fonction recherche
prenant comme param\u00e8tres une variable a
de type num\u00e9rique (float
ou int
) et un tableau tab
(type list
) et qui renvoie le nombre d'occurrences de a
dans tab
.
Exemples :
>>> recherche(5, [])\n0\n>>> recherche(5, [-2, 3, 4, 8])\n0\n>>> recherche(5, [-2, 3, 1, 5, 3, 7, 4])\n1\n>>> recherche(5, [-2, 5, 3, 5, 4, 5])\n3\n
def recherche(a, tab):\n nb = 0\n for element in tab:\n if element == a:\n nb += 1\n return nb\n
\u00c9crire en langage Python une fonction `recherche` prenant comme param\u00e8tres une\nvariable `a` de type num\u00e9rique (`float` ou `int`) et un tableau `tab` (type `list`) et qui\nrenvoie le nombre d'occurrences de `a` dans `tab`.\n\nExemples :\n```python\n>>> recherche(5, [])\n0\n>>> recherche(5, [-2, 3, 4, 8])\n0\n>>> recherche(5, [-2, 3, 1, 5, 3, 7, 4])\n1\n>>> recherche(5, [-2, 5, 3, 5, 4, 5])\n3\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-132","title":"Exercice 13.2","text":"Exercice 13.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa fonction rendu_monnaie
prend en param\u00e8tres deux nombres entiers positifs somme_due
et somme_versee
et elle permet de proc\u00e9der au rendu de monnaie de la diff\u00e9rence somme_versee \u2013 somme_due
pour des achats effectu\u00e9s avec le syst\u00e8me de pi\u00e8ces de la zone Euro. On utilise pour cela un algorithme glouton qui commence par rendre le maximum de pi\u00e8ces de plus grandes valeurs et ainsi de suite. Par la suite, on assimilera les billets \u00e0 des pi\u00e8ces.
La fonction rendu_monnaie
renvoie un tableau de type list
contenant les pi\u00e8ces qui composent le rendu.
Toutes les sommes sont exprim\u00e9es en euros. Les valeurs possibles pour les pi\u00e8ces sont donc [1, 2, 5, 10, 20, 50, 100, 200]
.
Ainsi, l\u2019instruction rendu_monnaie(452, 500)
renvoie le tableau [20, 20, 5, 2, 1]
.
En effet, la somme \u00e0 rendre est de 48
euros soit 20 + 20 + 5 + 2 + 1
.
Le code de la fonction rendu_monnaie
est donn\u00e9 ci-dessous :
def rendu_monnaie(somme_due, somme_versee):\n pieces = [1, 2, 5, 10, 20, 50, 100, 200]\n rendu = ...\n a_rendre = ...\n i = len(pieces) - 1\n while a_rendre > ... :\n if pieces[i] <= a_rendre :\n rendu.append(...)\n a_rendre = ...\n else :\n i = ...\n return rendu\n
Compl\u00e9ter ce code et le tester :
>>> rendu_monnaie(700,700)\n[]\n>>> rendu_monnaie(102,500)\n[200, 100, 50, 20, 20, 5, 2, 1]\n
def rendu_monnaie(somme_due, somme_versee):\n pieces = [1, 2, 5, 10, 20, 50, 100, 200]\nrendu = []\na_rendre = somme_versee - somme_due\ni = len(pieces) - 1\nwhile a_rendre > 0 :\nif pieces[i] <= a_rendre :\nrendu.append(pieces[i])\na_rendre = a_rendre - pieces[i]\nelse :\ni = i - 1\nreturn rendu\n
La fonction `rendu_monnaie` prend en param\u00e8tres deux nombres entiers\npositifs `somme_due` et `somme_versee` et elle permet de proc\u00e9der au rendu de monnaie de la\ndiff\u00e9rence `somme_versee \u2013 somme_due` pour des achats effectu\u00e9s avec le syst\u00e8me de pi\u00e8ces de\nla zone Euro. On utilise pour cela un algorithme glouton qui commence par rendre le maximum de\npi\u00e8ces de plus grandes valeurs et ainsi de suite. Par la suite, on\nassimilera les billets \u00e0 des pi\u00e8ces.\n\n\nLa fonction `rendu_monnaie` renvoie un tableau de type `list` contenant les pi\u00e8ces qui\ncomposent le rendu.\n\nToutes les sommes sont exprim\u00e9es en euros. Les valeurs possibles pour les\npi\u00e8ces sont donc `[1, 2, 5, 10, 20, 50, 100, 200]`.\n\nAinsi, l\u2019instruction `rendu_monnaie(452, 500)`\nrenvoie le tableau\n`[20, 20, 5, 2, 1]`.\n\nEn effet, la somme \u00e0 rendre est de `48` euros soit `20 + 20 + 5 + 2 + 1`.\n\nLe code de la fonction `rendu_monnaie` est donn\u00e9 ci-dessous :\n\n```python linenums='1'\ndef rendu_monnaie(somme_due, somme_versee):\n pieces = [1, 2, 5, 10, 20, 50, 100, 200]\n rendu = ...\n a_rendre = ...\n i = len(pieces) - 1\n while a_rendre > ... :\n if pieces[i] <= a_rendre :\n rendu.append(...)\n a_rendre = ...\n else :\n i = ...\n return rendu\n
Compl\u00e9ter ce code et le tester :
>>> rendu_monnaie(700,700)\n[]\n>>> rendu_monnaie(102,500)\n[200, 100, 50, 20, 20, 5, 2, 1]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-14","title":"\u25b6 Sujet 14","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-141","title":"Exercice 14.1","text":"Exercice 14.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche
qui prend en param\u00e8tres elt
un nombre entier et tab
un tableau de nombres entiers, et qui renvoie l\u2019indice de la premi\u00e8re occurrence de elt
dans tab
si elt
est dans tab
et -1
sinon.
Ne pas oublier d\u2019ajouter au corps de la fonction une documentation et une ou plusieurs assertions pour v\u00e9rifier les pr\u00e9-conditions.
Exemples :
>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(50, [1, 50, 1])\n1\n>>> recherche(15, [8, 9, 10, 15])\n3\n
def recherche(elt, tab):\n'''\n renvoie l\u2019indice de la premi\u00e8re occurrence de\n elt dans tab si elt est dans tab et -1 sinon. \n '''\n assert tab != [], \"le tableau est vide\"\n for i in range(len(tab)):\n if tab[i] == elt:\n return i \n return -1 \n
\u00c9crire une fonction `recherche` qui prend en param\u00e8tres `elt` un nombre entier et `tab`\nun tableau de nombres entiers, et qui renvoie l\u2019indice de la premi\u00e8re occurrence de `elt`\ndans `tab` si `elt` est dans `tab` et `-1` sinon.\n\nNe pas oublier d\u2019ajouter au corps de la fonction une documentation et une ou plusieurs\nassertions pour v\u00e9rifier les pr\u00e9-conditions.\n\nExemples :\n```python\n>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(50, [1, 50, 1])\n1\n>>> recherche(15, [8, 9, 10, 15])\n3\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-142","title":"Exercice 14.2","text":"Exercice 14.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re la fonction insere
ci-dessous qui prend en argument un entier a
et un tableau tab
d'entiers tri\u00e9s par ordre croissant. Cette fonction cr\u00e9e et renvoie un nouveau tableau \u00e0 partir de celui fourni en param\u00e8tre en y ins\u00e9rant la valeur a
de sorte que le tableau renvoy\u00e9 soit encore tri\u00e9 par ordre croissant. Les tableaux seront repr\u00e9sent\u00e9s sous la forme de listes Python.
def insere(a, tab):\n\"\"\"\n Ins\u00e8re l'\u00e9l\u00e9ment a (int) dans le tableau tab (list)\n tri\u00e9 par ordre croissant \u00e0 sa place et renvoie le\n nouveau tableau.\n \"\"\"\n l = list(tab) #l contient les m\u00eames \u00e9l\u00e9ments que tab\n l.append(a)\n i = ...\n while a < ... and i >= 0:\n l[i+1] = ...\n l[i] = a\n i = ...\n return l\n
Compl\u00e9ter la fonction insere
ci-dessus.
Exemples :
>>> insere(3, [1, 2, 4, 5])\n[1, 2, 3, 4, 5]\n>>> insere(30, [1, 2, 7, 12, 14, 25])\n[1, 2, 7, 12, 14, 25, 30]\n>>> insere(1, [2, 3, 4])\n[1, 2, 3, 4]\n>>> insere(1, [])\n[1]\n
def insere(a, tab):\n\"\"\"\n Ins\u00e8re l'\u00e9l\u00e9ment a (int) dans le tableau tab (list)\n tri\u00e9 par ordre croissant \u00e0 sa place et renvoie le\n nouveau tableau.\n \"\"\"\n l = list(tab) #l contient les m\u00eames \u00e9l\u00e9ments que tab\n l.append(a)\ni = len(l) - 2\nwhile a < l[i] and i >= 0:\nl[i+1] = l[i]\nl[i] = a\ni = i - 1\nreturn l\n
On consid\u00e8re la fonction `insere` ci-dessous qui prend en argument un entier `a` et un\ntableau `tab` d'entiers tri\u00e9s par ordre croissant. Cette fonction cr\u00e9e et renvoie un nouveau\ntableau \u00e0 partir de celui fourni en param\u00e8tre en y ins\u00e9rant la valeur `a` de sorte que le\ntableau renvoy\u00e9 soit encore tri\u00e9 par ordre croissant. Les tableaux seront repr\u00e9sent\u00e9s sous\nla forme de listes Python.\n\n\n```python linenums='1'\ndef insere(a, tab):\n \"\"\"\n Ins\u00e8re l'\u00e9l\u00e9ment a (int) dans le tableau tab (list)\n tri\u00e9 par ordre croissant \u00e0 sa place et renvoie le\n nouveau tableau.\n \"\"\"\n l = list(tab) #l contient les m\u00eames \u00e9l\u00e9ments que tab\n l.append(a)\n i = ...\n while a < ... and i >= 0:\n l[i+1] = ...\n l[i] = a\n i = ...\n return l\n
Compl\u00e9ter la fonction insere
ci-dessus.
Exemples :
>>> insere(3, [1, 2, 4, 5])\n[1, 2, 3, 4, 5]\n>>> insere(30, [1, 2, 7, 12, 14, 25])\n[1, 2, 7, 12, 14, 25, 30]\n>>> insere(1, [2, 3, 4])\n[1, 2, 3, 4]\n>>> insere(1, [])\n[1]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-15","title":"\u25b6 Sujet 15","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-151","title":"Exercice 15.1","text":"Exercice 15.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn a relev\u00e9 les valeurs moyennes annuelles des temp\u00e9ratures \u00e0 Paris pour la p\u00e9riode allant de 2013 \u00e0 2019. Les r\u00e9sultats ont \u00e9t\u00e9 r\u00e9cup\u00e9r\u00e9s sous la forme de deux listes : l\u2019une pour les temp\u00e9ratures, l\u2019autre pour les ann\u00e9es :
t_moy = [14.9, 13.3, 13.1, 12.5, 13.0, 13.6, 13.7]\nannees = [2013, 2014, 2015, 2016, 2017, 2018, 2019]\n
\u00c9crire la fonction mini
qui prend en param\u00e8tres un tableau releve
des relev\u00e9s et un tableau date
des dates et qui renvoie la plus petite valeur relev\u00e9e au cours de la p\u00e9riode et l\u2019ann\u00e9e correspondante. On suppose que la temp\u00e9rature minimale est atteinte une seule fois.
Exemple :
>>> mini(t_moy, annees)\n(12.5, 2016)\n
t_moy = [14.9, 13.3, 13.1, 12.5, 13.0, 13.6, 13.7]\nannees = [2013, 2014, 2015, 2016, 2017, 2018, 2019]\n\ndef mini(releve, date):\n temp_mini = releve[0]\n date_mini = date[0]\n for i in range(len(releve)):\n if releve[i] < temp_mini:\n temp_mini = releve[i]\n date_mini = date[i]\n return temp_mini, date_mini\n
On a relev\u00e9 les valeurs moyennes annuelles des temp\u00e9ratures \u00e0 Paris pour la p\u00e9riode\nallant de 2013 \u00e0 2019. Les r\u00e9sultats ont \u00e9t\u00e9 r\u00e9cup\u00e9r\u00e9s sous la forme de deux listes : l\u2019une pour les temp\u00e9ratures, l\u2019autre pour les ann\u00e9es :\n```python\nt_moy = [14.9, 13.3, 13.1, 12.5, 13.0, 13.6, 13.7]\nannees = [2013, 2014, 2015, 2016, 2017, 2018, 2019]\n```\n\n\u00c9crire la fonction `mini` qui prend en param\u00e8tres un tableau `releve` des relev\u00e9s et un\ntableau `date` des dates et qui renvoie la plus petite valeur relev\u00e9e au cours de la\np\u00e9riode et l\u2019ann\u00e9e correspondante. On suppose que la temp\u00e9rature minimale est atteinte\nune seule fois.\n\nExemple :\n```python\n>>> mini(t_moy, annees)\n(12.5, 2016)\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-152","title":"Exercice 15.2","text":"Exercice 15.2
\u00c9nonc\u00e9CorrectionSources MarkdownUn mot palindrome peut se lire de la m\u00eame fa\u00e7on de gauche \u00e0 droite ou de droite \u00e0 gauche : bob, radar, et non sont des mots palindromes.
De m\u00eame certains nombres sont eux aussi des palindromes : 33, 121, 345543.
L\u2019objectif de cet exercice est d\u2019obtenir un programme Python permettant de tester si un nombre est un nombre palindrome.
Pour remplir cette t\u00e2che, on vous demande de compl\u00e9ter le code des trois fonctions ci- dessous sachant que la fonction est_nbre_palindrome
s\u2019appuiera sur la fonction est_palindrome
qui elle-m\u00eame s\u2019appuiera sur la fonction inverse_chaine
.
La fonction inverse_chaine
inverse l'ordre des caract\u00e8res d'une cha\u00eene de caract\u00e8res chaine
et renvoie la cha\u00eene invers\u00e9e.
La fonction est_palindrome
teste si une chaine de caract\u00e8res chaine
est un palindrome. Elle renvoie True
si c\u2019est le cas et False
sinon. Cette fonction s\u2019appuie sur la fonction pr\u00e9c\u00e9dente.
La fonction est_nbre_palindrome
teste si un nombre nbre
est un palindrome. Elle renvoie True
si c\u2019est le cas et False
sinon. Cette fonction s\u2019appuie sur la fonction pr\u00e9c\u00e9dente.
Compl\u00e9ter le code des trois fonctions ci-dessous.
def inverse_chaine(chaine):\n result = ...\n for caractere in chaine:\n result = ...\n return result\n\ndef est_palindrome(chaine):\n inverse = inverse_chaine(chaine)\n return ...\n\ndef est_nbre_palindrome(nbre):\n chaine = ...\n return est_palindrome(chaine)\n
Exemples : >>> inverse_chaine('bac')\n'cab'\n>>> est_palindrome('NSI')\nFalse\n>>> est_palindrome('ISN-NSI')\nTrue\n>>> est_nbre_palindrome(214312)\nFalse\n>>> est_nbre_palindrome(213312)\nTrue\n
def inverse_chaine(chaine):\nresult = ''\nfor caractere in chaine:\nresult = caractere + result\nreturn result\n\ndef est_palindrome(chaine):\n inverse = inverse_chaine(chaine)\nreturn chaine == inverse\ndef est_nbre_palindrome(nbre):\nchaine = str(nbre)\nreturn est_palindrome(chaine)\n
Un mot palindrome peut se lire de la m\u00eame fa\u00e7on de gauche \u00e0 droite ou de droite \u00e0\ngauche : *bob*, *radar*, et *non* sont des mots palindromes.\n\nDe m\u00eame certains nombres sont eux aussi des palindromes : 33, 121, 345543.\n\nL\u2019objectif de cet exercice est d\u2019obtenir un programme Python permettant de tester si un\nnombre est un nombre palindrome.\n\nPour remplir cette t\u00e2che, on vous demande de compl\u00e9ter le code des trois fonctions ci-\ndessous sachant que la fonction `est_nbre_palindrome` s\u2019appuiera sur la fonction\n`est_palindrome` qui elle-m\u00eame s\u2019appuiera sur la fonction `inverse_chaine`.\n\nLa fonction `inverse_chaine` inverse l'ordre des caract\u00e8res d'une cha\u00eene de caract\u00e8res\n`chaine` et renvoie la cha\u00eene invers\u00e9e.\n\nLa fonction `est_palindrome` teste si une chaine de caract\u00e8res `chaine` est un\npalindrome. Elle renvoie `True` si c\u2019est le cas et `False` sinon. Cette fonction s\u2019appuie sur\nla fonction pr\u00e9c\u00e9dente.\n\nLa fonction `est_nbre_palindrome` teste si un nombre `nbre` est un palindrome. Elle\nrenvoie `True` si c\u2019est le cas et `False` sinon. Cette fonction s\u2019appuie sur la fonction\npr\u00e9c\u00e9dente.\n\nCompl\u00e9ter le code des trois fonctions ci-dessous.\n\n```python linenums='1'\ndef inverse_chaine(chaine):\n result = ...\n for caractere in chaine:\n result = ...\n return result\n\ndef est_palindrome(chaine):\n inverse = inverse_chaine(chaine)\n return ...\n\ndef est_nbre_palindrome(nbre):\n chaine = ...\n return est_palindrome(chaine)\n
Exemples : >>> inverse_chaine('bac')\n'cab'\n>>> est_palindrome('NSI')\nFalse\n>>> est_palindrome('ISN-NSI')\nTrue\n>>> est_nbre_palindrome(214312)\nFalse\n>>> est_nbre_palindrome(213312)\nTrue\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-16","title":"\u25b6 Sujet 16","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-161","title":"Exercice 16.1","text":"Exercice 16.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche_indices_classement
qui prend en param\u00e8tres un entier elt
et une liste d\u2019entiers tab
, et qui renvoie trois listes :
tab
strictement inf\u00e9rieures \u00e0 elt
;tab
\u00e9gales \u00e0 elt
;tab
strictement sup\u00e9rieures \u00e0 elt
.Exemples :
>>> recherche_indices_classement(3, [1, 3, 4, 2, 4, 6, 3, 0])\n([0, 3, 7], [1, 6], [2, 4, 5])\n>>> recherche_indices_classement(3, [1, 4, 2, 4, 6, 0])\n([0, 2, 5], [], [1, 3, 4])\n>>>recherche_indices_classement(3, [1, 1, 1, 1])\n([0, 1, 2, 3], [], [])\n>>> recherche_indices_classement(3, [])\n([], [], [])\n
def recherche_indices_classement(elt, tab):\n ind_inf = []\n ind_egal = []\n ind_sup = [] \n for i in range(len(tab)):\n if tab[i] < elt:\n ind_inf.append(i)\n elif tab[i] > elt:\n ind_sup.append(i)\n else:\n ind_egal.append(i)\n return (ind_inf, ind_egal, ind_sup)\n
\u00c9crire une fonction `recherche_indices_classement` qui prend en param\u00e8tres un\nentier `elt` et une liste d\u2019entiers `tab`, et qui renvoie trois listes :\n\n- la premi\u00e8re liste contient les indices des valeurs de la liste `tab` strictement\ninf\u00e9rieures \u00e0 `elt` ;\n- la deuxi\u00e8me liste contient les indices des valeurs de la liste `tab` \u00e9gales \u00e0 `elt` ;\n- la troisi\u00e8me liste contient les indices des valeurs de la liste `tab` strictement\nsup\u00e9rieures \u00e0 `elt`.\n\nExemples :\n\n```python\n>>> recherche_indices_classement(3, [1, 3, 4, 2, 4, 6, 3, 0])\n([0, 3, 7], [1, 6], [2, 4, 5])\n>>> recherche_indices_classement(3, [1, 4, 2, 4, 6, 0])\n([0, 2, 5], [], [1, 3, 4])\n>>>recherche_indices_classement(3, [1, 1, 1, 1])\n([0, 1, 2, 3], [], [])\n>>> recherche_indices_classement(3, [])\n([], [], [])\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-162","title":"Exercice 16.2","text":"Exercice 16.2
\u00c9nonc\u00e9CorrectionSources MarkdownUn professeur de NSI d\u00e9cide de g\u00e9rer les r\u00e9sultats de sa classe sous la forme d\u2019un dictionnaire :
Avec :
resultats = {'Dupont': {\n 'DS1': [15.5, 4],\n 'DM1': [14.5, 1],\n 'DS2': [13, 4],\n 'PROJET1': [16, 3],\n 'DS3': [14, 4]\n },\n 'Durand': {\n 'DS1': [6 , 4],\n 'DM1': [14.5, 1],\n 'DS2': [8, 4],\n 'PROJET1': [9, 3],\n 'IE1': [7, 2],\n 'DS3': [8, 4],\n 'DS4':[15, 4]\n }\n }\n
L\u2019\u00e9l\u00e8ve dont le nom est Durand a ainsi obtenu au DS2 la note de 8 avec un coefficient 4.
Le professeur cr\u00e9e une fonction moyenne
qui prend en param\u00e8tre le nom d\u2019un de ses \u00e9l\u00e8ves et renvoie sa moyenne arrondie au dixi\u00e8me.
Compl\u00e9ter le code du professeur ci-dessous :
def moyenne(nom, dico_result):\n if nom in ...:\n notes = dico_result[nom]\n total_points = ...\n total_coefficients = ...\n for ... in notes.values():\n note, coefficient = valeurs\n total_points = total_points + ... * coefficient\n total_coefficients = ... + coefficient\n return round( ... / total_coefficients, 1 )\n else:\n return -1\n
def moyenne(nom, dico_result):\nif nom in dico_result:\nnotes = dico_result[nom]\ntotal_points = 0.\ntotal_coefficients = 0\nfor valeurs in notes.values():\nnote, coefficient = valeurs\ntotal_points = total_points + note * coefficient\ntotal_coefficients = total_coefficients + coefficient\nreturn round( total_points / total_coefficients, 1 )\nelse:\n return -1\n
Un professeur de NSI d\u00e9cide de g\u00e9rer les r\u00e9sultats de sa classe sous la forme d\u2019un\ndictionnaire :\n\n- les clefs sont les noms des \u00e9l\u00e8ves ;\n- les valeurs sont des dictionnaires dont les clefs sont les types d\u2019\u00e9preuves sous\nforme de cha\u00eene de caract\u00e8res et les valeurs sont les notes obtenues associ\u00e9es \u00e0\nleurs coefficients dans une liste.\n\nAvec :\n\n```python\nresultats = {'Dupont': {\n 'DS1': [15.5, 4],\n 'DM1': [14.5, 1],\n 'DS2': [13, 4],\n 'PROJET1': [16, 3],\n 'DS3': [14, 4]\n },\n 'Durand': {\n 'DS1': [6 , 4],\n 'DM1': [14.5, 1],\n 'DS2': [8, 4],\n 'PROJET1': [9, 3],\n 'IE1': [7, 2],\n 'DS3': [8, 4],\n 'DS4':[15, 4]\n }\n }\n
L\u2019\u00e9l\u00e8ve dont le nom est Durand a ainsi obtenu au DS2 la note de 8 avec un coefficient 4.
Le professeur cr\u00e9e une fonction moyenne
qui prend en param\u00e8tre le nom d\u2019un de ses \u00e9l\u00e8ves et renvoie sa moyenne arrondie au dixi\u00e8me.
Compl\u00e9ter le code du professeur ci-dessous :
def moyenne(nom, dico_result):\n if nom in ...:\n notes = dico_result[nom]\n total_points = ...\n total_coefficients = ...\n for ... in notes.values():\n note, coefficient = valeurs\n total_points = total_points + ... * coefficient\n total_coefficients = ... + coefficient\n return round( ... / total_coefficients, 1 )\n else:\n return -1\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-17","title":"\u25b6 Sujet 17","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-171","title":"Exercice 17.1","text":"Exercice 17.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction moyenne(liste_notes)
qui renvoie la moyenne pond\u00e9r\u00e9e des r\u00e9sultats contenus dans la liste liste_notes
, non vide, donn\u00e9e en param\u00e8tre. Cette liste contient des couples (note, coefficient)
dans lesquels :
note
est un nombre de type flottant (float
) compris entre 0 et 20 ;coefficient
est un nombre entier strictement positif.Ainsi l\u2019expression moyenne([(15,2),(9,1),(12,3)])
devra renvoyer 12.5
.
\\(\\dfrac{2 \\times 15 + 1 \\times 9 + 3 \\times 12 }{2+1+3}=12,5\\)
def moyenne(liste_notes):\n somme_notes = 0\n somme_coeffs = 0\n for devoir in liste_notes:\n note = devoir[0]\n coeff = devoir[1]\n somme_notes += note * coeff\n somme_coeffs += coeff\n return somme_notes / somme_coeffs\n
\u00c9crire une fonction `moyenne(liste_notes)` qui renvoie la moyenne pond\u00e9r\u00e9e des\nr\u00e9sultats contenus dans la liste `liste_notes`, non vide, donn\u00e9e en param\u00e8tre. Cette\nliste contient des couples `(note, coefficient)` dans lesquels :\n\n- `note` est un nombre de type flottant (`float`) compris entre 0 et 20 ;\n- `coefficient` est un nombre entier strictement positif.\n\nAinsi l\u2019expression `moyenne([(15,2),(9,1),(12,3)])` devra renvoyer `12.5`.\n\n$\\dfrac{2 \\times 15 + 1 \\times 9 + 3 \\times 12 }{2+1+3}=12,5$\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-172","title":"Exercice 17.2","text":"Exercice 17.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn cherche \u00e0 d\u00e9terminer les valeurs du triangle de Pascal (Figure 1).
Dans le triangle de Pascal, chaque ligne commence et se termine par le nombre 1. Comme l\u2019illustre la Figure 2, on additionne deux valeurs successives d\u2019une ligne pour obtenir la valeur qui se situe sous la deuxi\u00e8me valeur.
Compl\u00e9ter la fonction pascal
ci-apr\u00e8s prenant en param\u00e8tre un entier n
sup\u00e9rieur ou \u00e9gal \u00e0 2. Cette fonction doit renvoyer une liste correspondant au triangle de Pascal de la ligne 0 \u00e0 la ligne n
. Le tableau repr\u00e9sentant le triangle de Pascal sera contenu dans la variable triangle
.
def pascal(n):\n triangle = [[1]]\n for k in range(1,...):\n ligne_k = [...]\n for i in range(1,k):\n ligne_k.append(triangle[...][i-1]+triangle[...][...])\n ligne_k.append(...)\n triangle.append(ligne_k)\n return triangle\n
Pour n = 4
, voici ce qu'on devra obtenir :
>>> pascal(4)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]\n
Pour n = 5
, voici ce qu'on devra obtenir : >>> pascal(5)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1]]\n
def pascal(n):\n triangle = [[1]]\nfor k in range(1, n+1):\nligne_k = [1]\nfor i in range(1, k):\nligne_k.append(triangle[k-1][i-1] + triangle[k-1][i])\nligne_k.append(1)\ntriangle.append(ligne_k)\n return triangle\n
On cherche \u00e0 d\u00e9terminer les valeurs du triangle de Pascal (Figure 1).\n\nDans le triangle de Pascal, chaque ligne commence et se termine par le nombre 1.\nComme l\u2019illustre la Figure 2, on additionne deux valeurs successives d\u2019une ligne pour\nobtenir la valeur qui se situe sous la deuxi\u00e8me valeur.\n\n![image](data2023/17_triangle.png){: .center width=60%}\n\nCompl\u00e9ter la fonction `pascal` ci-apr\u00e8s prenant en param\u00e8tre un entier `n` sup\u00e9rieur ou\n\u00e9gal \u00e0 2. Cette fonction doit renvoyer une liste correspondant au triangle de Pascal de la\nligne 0 \u00e0 la ligne `n`. Le tableau repr\u00e9sentant le triangle de Pascal sera contenu dans la\nvariable `triangle`.\n\n```python linenums='1'\ndef pascal(n):\n triangle = [[1]]\n for k in range(1,...):\n ligne_k = [...]\n for i in range(1,k):\n ligne_k.append(triangle[...][i-1]+triangle[...][...])\n ligne_k.append(...)\n triangle.append(ligne_k)\n return triangle\n
Pour n = 4
, voici ce qu'on devra obtenir :
>>> pascal(4)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]\n
Pour n = 5
, voici ce qu'on devra obtenir : >>> pascal(5)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1]]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-18","title":"\u25b6 Sujet 18","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-181","title":"Exercice 18.1","text":"Exercice 18.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction max_et_indice
qui prend en param\u00e8tre une liste non vide tab
de nombres entiers et qui renvoie la valeur du plus grand \u00e9l\u00e9ment de cette liste ainsi que l\u2019indice de sa premi\u00e8re apparition dans cette liste.
L\u2019utilisation de la fonction native max
n\u2019est pas autoris\u00e9e.
Ne pas oublier d\u2019ajouter au corps de la fonction une documentation et une ou plusieurs assertions pour v\u00e9rifier les pr\u00e9-conditions.
Exemples :
>>> max_et_indice([1, 5, 6, 9, 1, 2, 3, 7, 9, 8])\n(9, 3)\n>>> max_et_indice([-2])\n(-2, 0)\n>>> max_et_indice([-1, -1, 3, 3, 3])\n(3, 2)\n>>> max_et_indice([1, 1, 1, 1])\n(1, 0)\n
def max_et_indice(tab):\n'''\n renvoie la valeur du plus grand \u00e9l\u00e9ment de cette liste ainsi\n que l\u2019indice de sa premi\u00e8re apparition dans cette liste.\n '''\n assert tab != [], 'le tableau est vide'\n\n val_max = tab[0]\n ind_max = 0\n for i in range(len(tab)):\n if tab[i] > val_max:\n val_max = tab[i]\n ind_max = i\n return (val_max, ind_max)\n
\u00c9crire une fonction `max_et_indice` qui prend en param\u00e8tre une liste non vide `tab` de\nnombres entiers et qui renvoie la valeur du plus grand \u00e9l\u00e9ment de cette liste ainsi que\nl\u2019indice de sa premi\u00e8re apparition dans cette liste.\n\nL\u2019utilisation de la fonction native `max` n\u2019est pas autoris\u00e9e.\n\nNe pas oublier d\u2019ajouter au corps de la fonction une documentation et une ou plusieurs\nassertions pour v\u00e9rifier les pr\u00e9-conditions.\n\nExemples :\n\n```python\n>>> max_et_indice([1, 5, 6, 9, 1, 2, 3, 7, 9, 8])\n(9, 3)\n>>> max_et_indice([-2])\n(-2, 0)\n>>> max_et_indice([-1, -1, 3, 3, 3])\n(3, 2)\n>>> max_et_indice([1, 1, 1, 1])\n(1, 0)\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-182","title":"Exercice 18.2","text":"Exercice 18.2
\u00c9nonc\u00e9CorrectionSources MarkdownL\u2019ordre des g\u00e8nes sur un chromosome est repr\u00e9sent\u00e9 par un tableau ordre
de n
cases d\u2019entiers distincts deux \u00e0 deux et compris entre 1 et n
.
Par exemple, ordre = [5, 4, 3, 6, 7, 2, 1, 8, 9]
dans le cas n = 9
.
On dit qu\u2019il y a un point de rupture dans ordre
dans chacune des situations suivantes :
ordre
n\u2019est pas 1 ;ordre
n\u2019est pas n.Par exemple, si ordre = [5, 4, 3, 6, 7, 2, 1, 8, 9]
avec n = 9
, on a
Il y a donc 4 points de rupture.
Compl\u00e9ter les fonctions Python est_un_ordre
et nombre_points_rupture
propos\u00e9es \u00e0 la page suivante pour que :
la fonction est_un_ordre
renvoie True
si le tableau pass\u00e9 en param\u00e8tre repr\u00e9sente bien un ordre de g\u00e8nes de chromosome et False
sinon ;
la fonction nombre_points_rupture
renvoie le nombre de points de rupture d\u2019un tableau pass\u00e9 en param\u00e8tre repr\u00e9sentant l\u2019ordre de g\u00e8nes d\u2019un chromosome.
def est_un_ordre(tab):\n'''\n Renvoie True si tab est de longueur n et contient tous les entiers\n de 1 \u00e0 n, False sinon\n '''\n for i in range(1,...):\n if ...:\n return False\n return True\n\n\ndef nombre_points_rupture(ordre):\n'''\n Renvoie le nombre de point de rupture de ordre qui repr\u00e9sente un ordre\n de g\u00e8nes de chromosome\n '''\n assert ... # ordre n'est pas un ordre de g\u00e8nes\n n = len(ordre)\n nb = 0\n if ordre[...] != 1: # le premier n'est pas 1\n nb = nb + 1\n i = 0\n while i < ...:\n if ... not in [-1, 1]: # l'\u00e9cart n'est pas 1\n nb = nb + 1\n i = i + 1\n if ordre[...] != n: # le dernier n'est pas n\n nb = nb + 1\n return nb\n
Exemples :
>>> est_un_ordre([1, 6, 2, 8, 3, 7])\nFalse\n>>> est_un_ordre([5, 4, 3, 6, 7, 2, 1, 8, 9])\nTrue\n>>> nombre_points_rupture([5, 4, 3, 6, 7, 2, 1, 8, 9])\n4\n>>> nombre_points_rupture([1, 2, 3, 4, 5])\n0\n>>> nombre_points_rupture([1, 6, 2, 8, 3, 7, 4, 5])\n7\n>>> nombre_points_rupture([2, 1, 3, 4])\n2\n
def est_un_ordre(tab):\n'''\n Renvoie True si tab est de longueur n et contient tous les entiers\n de 1 \u00e0 n, False sinon\n '''\nfor i in range(1, len(tab)+1):\nif i not in tab:\nreturn False\n return True\n\n\ndef nombre_points_rupture(ordre):\n'''\n Renvoie le nombre de point de rupture de ordre qui repr\u00e9sente un ordre\n de g\u00e8nes de chromosome\n '''\n assert est_un_ordre(ordre) # ordre n'est pas un ordre de g\u00e8nes\n n = len(ordre)\n nb = 0\nif ordre[0] != 1: # le premier n'est pas 1\nnb = nb + 1\n i = 0\nwhile i < n-1:\nif ordre[i+1] - ordre[i] not in [-1, 1]: # l'\u00e9cart n'est pas 1\nnb = nb + 1\n i = i + 1\nif ordre[n-1] != n: # le dernier n'est pas n\nnb = nb + 1\n return nb\n
L\u2019ordre des g\u00e8nes sur un chromosome est repr\u00e9sent\u00e9 par un tableau `ordre` de `n` cases\nd\u2019entiers distincts deux \u00e0 deux et compris entre 1 et `n`.\n\nPar exemple, `ordre = [5, 4, 3, 6, 7, 2, 1, 8, 9]` dans le cas `n = 9`.\n\nOn dit qu\u2019il y a un point de rupture dans `ordre` dans chacune des situations suivantes :\n\n- la premi\u00e8re valeur de `ordre` n\u2019est pas 1 ;\n- l\u2019\u00e9cart entre deux g\u00e8nes cons\u00e9cutifs n\u2019est pas \u00e9gal \u00e0 1 ;\n- la derni\u00e8re valeur de `ordre` n\u2019est pas n.\n\nPar exemple, si `ordre = [5, 4, 3, 6, 7, 2, 1, 8, 9]` avec `n = 9`, on a\n\n- un point de rupture au d\u00e9but car 5 est diff\u00e9rent de 1\n- un point de rupture entre 3 et 6 (l\u2019\u00e9cart est de 3)\n- un point de rupture entre 7 et 2 (l\u2019\u00e9cart est de 5)\n- un point de rupture entre 1 et 8 (l\u2019\u00e9cart est de 7)\n\nIl y a donc 4 points de rupture.\n\nCompl\u00e9ter les fonctions Python `est_un_ordre` et `nombre_points_rupture`\npropos\u00e9es \u00e0 la page suivante pour que :\n\n\n- la fonction `est_un_ordre` renvoie `True` si le tableau pass\u00e9 en param\u00e8tre\nrepr\u00e9sente bien un ordre de g\u00e8nes de chromosome et `False` sinon ;\n\n- la fonction `nombre_points_rupture` renvoie le nombre de points de rupture\nd\u2019un tableau pass\u00e9 en param\u00e8tre repr\u00e9sentant l\u2019ordre de g\u00e8nes d\u2019un\nchromosome.\n\n```python linenums='1'\ndef est_un_ordre(tab):\n '''\n Renvoie True si tab est de longueur n et contient tous les entiers\n de 1 \u00e0 n, False sinon\n '''\n for i in range(1,...):\n if ...:\n return False\n return True\n\n\ndef nombre_points_rupture(ordre):\n '''\n Renvoie le nombre de point de rupture de ordre qui repr\u00e9sente un ordre\n de g\u00e8nes de chromosome\n '''\n assert ... # ordre n'est pas un ordre de g\u00e8nes\n n = len(ordre)\n nb = 0\n if ordre[...] != 1: # le premier n'est pas 1\n nb = nb + 1\n i = 0\n while i < ...:\n if ... not in [-1, 1]: # l'\u00e9cart n'est pas 1\n nb = nb + 1\n i = i + 1\n if ordre[...] != n: # le dernier n'est pas n\n nb = nb + 1\n return nb\n
Exemples :
>>> est_un_ordre([1, 6, 2, 8, 3, 7])\nFalse\n>>> est_un_ordre([5, 4, 3, 6, 7, 2, 1, 8, 9])\nTrue\n>>> nombre_points_rupture([5, 4, 3, 6, 7, 2, 1, 8, 9])\n4\n>>> nombre_points_rupture([1, 2, 3, 4, 5])\n0\n>>> nombre_points_rupture([1, 6, 2, 8, 3, 7, 4, 5])\n7\n>>> nombre_points_rupture([2, 1, 3, 4])\n2\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-19","title":"\u25b6 Sujet 19","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-191","title":"Exercice 19.1","text":"Exercice 19.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche
qui prend en param\u00e8tres un tableau tab
de nombres entiers tri\u00e9s par ordre croissant et un nombre entier n
, et qui effectue une recherche dichotomique du nombre entier n
dans le tableau non vide tab
.
Cette fonction doit renvoyer un indice correspondant au nombre cherch\u00e9 s\u2019il est dans le tableau, -1
sinon.
Exemples :
>>> recherche([2, 3, 4, 5, 6], 5)\n3\n>>> recherche([2, 3, 4, 6, 7], 5)\n-1\n
def recherche(tab, n):\n ind_debut = 0\n ind_fin = len(tab) - 1\n while ind_debut <= ind_fin:\n ind_milieu = (ind_debut + ind_fin) // 2\n if tab[ind_milieu] == n:\n return ind_milieu\n elif tab[ind_milieu] < n:\n ind_debut = ind_milieu + 1\n else:\n ind_fin = ind_milieu - 1\n return -1\n
\u00c9crire une fonction `recherche` qui prend en param\u00e8tres un tableau `tab` de nombres\nentiers tri\u00e9s par ordre croissant et un nombre entier `n`, et qui effectue une recherche\ndichotomique du nombre entier `n` dans le tableau non vide `tab`.\n\nCette fonction doit renvoyer un indice correspondant au nombre cherch\u00e9 s\u2019il est dans le\ntableau, `-1` sinon.\n\nExemples :\n```python\n>>> recherche([2, 3, 4, 5, 6], 5)\n3\n>>> recherche([2, 3, 4, 6, 7], 5)\n-1\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-192","title":"Exercice 19.2","text":"Exercice 19.2
\u00c9nonc\u00e9CorrectionSources MarkdownLe codage de C\u00e9sar transforme un message en changeant chaque lettre en la d\u00e9calant dans l\u2019alphabet. Par exemple, avec un d\u00e9calage de 3, le A se transforme en D, le B en E, ..., le X en A, le Y en B et le Z en C. Les autres caract\u00e8res (\u2018!\u2019,\u2019 ?\u2019 ...) ne sont pas cod\u00e9s.
La fonction position_alphabet
ci-dessous prend en param\u00e8tre un caract\u00e8re lettre
et renvoie la position de lettre
dans la cha\u00eene de caract\u00e8res ALPHABET
s\u2019il s\u2019y trouve.
La fonction cesar
prend en param\u00e8tre une cha\u00eene de caract\u00e8res message
et un nombre entier decalage
et renvoie le nouveau message cod\u00e9 avec le codage de C\u00e9sar utilisant le d\u00e9calage decalage
.
ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\ndef position_alphabet(lettre):\n return ord(lettre) - ord('A')\n\ndef cesar(message, decalage):\n resultat = ''\n for ... in message:\n if 'A' <= c and c <= 'Z':\n indice = ( ... ) % 26\n resultat = resultat + ALPHABET[indice]\n else:\n resultat = ...\n return resultat\n
Compl\u00e9ter la fonction cesar
.
Exemples :
>>> cesar('BONJOUR A TOUS. VIVE LA MATIERE NSI !', 4)\n'FSRNSYV E XSYW. ZMZI PE QEXMIVI RWM !'\n>>> cesar('GTSOTZW F YTZX. ANAJ QF RFYNJWJ SXN !', -5)\n'BONJOUR A TOUS. VIVE LA MATIERE NSI !'\n
ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\ndef position_alphabet(lettre):\n return ord(lettre) - ord('A')\n\ndef cesar(message, decalage):\n resultat = ''\nfor c in message:\nif 'A' <= c and c <= 'Z':\nindice = (position_alphabet(c) + decalage) % 26\nresultat = resultat + ALPHABET[indice]\n else:\nresultat = resultat + c\nreturn resultat\n
Le codage de C\u00e9sar transforme un message en changeant chaque lettre en la d\u00e9calant\ndans l\u2019alphabet.\nPar exemple, avec un d\u00e9calage de 3, le A se transforme en D, le B en E, ..., le X en A,\nle Y en B et le Z en C. Les autres caract\u00e8res (\u2018!\u2019,\u2019 ?\u2019 ...) ne sont pas cod\u00e9s.\n\nLa fonction `position_alphabet` ci-dessous prend en param\u00e8tre un caract\u00e8re `lettre`\net renvoie la position de `lettre` dans la cha\u00eene de caract\u00e8res `ALPHABET` s\u2019il s\u2019y trouve.\n\nLa fonction `cesar` prend en param\u00e8tre une cha\u00eene de caract\u00e8res `message` et un nombre\nentier `decalage` et renvoie le nouveau message cod\u00e9 avec le codage de C\u00e9sar utilisant\nle d\u00e9calage `decalage`.\n\n```python linenums='1'\nALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\ndef position_alphabet(lettre):\n return ord(lettre) - ord('A')\n\ndef cesar(message, decalage):\n resultat = ''\n for ... in message:\n if 'A' <= c and c <= 'Z':\n indice = ( ... ) % 26\n resultat = resultat + ALPHABET[indice]\n else:\n resultat = ...\n return resultat\n
Compl\u00e9ter la fonction cesar
.
Exemples :
>>> cesar('BONJOUR A TOUS. VIVE LA MATIERE NSI !', 4)\n'FSRNSYV E XSYW. ZMZI PE QEXMIVI RWM !'\n>>> cesar('GTSOTZW F YTZX. ANAJ QF RFYNJWJ SXN !', -5)\n'BONJOUR A TOUS. VIVE LA MATIERE NSI !'\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-20","title":"\u25b6 Sujet 20","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-201","title":"Exercice 20.1","text":"Exercice 20.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction ajoute_dictionnaires
qui prend en param\u00e8tres deux dictionnaires d1
et d2
dont les cl\u00e9s sont des nombres et renvoie le dictionnaire d
d\u00e9fini de la fa\u00e7on suivante :
d
sont celles de d1
et celles de d2
r\u00e9unies.d1
et d2
, sa valeur associ\u00e9e dans le dictionnaire d est la somme de ses valeurs dans les dictionnaires d1
et d2
.d
est la m\u00eame que sa valeur dans le dictionnaire o\u00f9 elle est pr\u00e9sente.Exemples :
>>> ajoute_dictionnaires({1: 5, 2: 7}, {2: 9, 3: 11})\n{1: 5, 2: 16, 3: 11}\n>>> ajoute_dictionnaires({}, {2: 9, 3: 11})\n{2: 9, 3: 11}\n>>> ajoute_dictionnaires({1: 5, 2: 7}, {})\n{1: 5, 2: 7}\n
def ajoute_dictionnaires(d1, d2):\nfor cle in d2:\n if cle in d1:\n d1[cle] += d2[cle]\n else:\n d1[cle] = d2[cle]\nreturn d1\n
\u00c9crire une fonction `ajoute_dictionnaires` qui prend en param\u00e8tres deux\ndictionnaires `d1` et `d2` dont les cl\u00e9s sont des nombres et renvoie le dictionnaire `d` d\u00e9fini de\nla fa\u00e7on suivante :\n\n- Les cl\u00e9s de `d` sont celles de `d1` et celles de `d2` r\u00e9unies.\n- Si une cl\u00e9 est pr\u00e9sente dans les deux dictionnaires `d1` et `d2`, sa valeur associ\u00e9e\ndans le dictionnaire d est la somme de ses valeurs dans les dictionnaires `d1` et `d2`.\n- Si une cl\u00e9 n\u2019est pr\u00e9sente que dans un des deux dictionnaires, sa valeur associ\u00e9e\ndans le dictionnaire `d` est la m\u00eame que sa valeur dans le dictionnaire o\u00f9 elle est\npr\u00e9sente.\n\nExemples :\n\n```python\n>>> ajoute_dictionnaires({1: 5, 2: 7}, {2: 9, 3: 11})\n{1: 5, 2: 16, 3: 11}\n>>> ajoute_dictionnaires({}, {2: 9, 3: 11})\n{2: 9, 3: 11}\n>>> ajoute_dictionnaires({1: 5, 2: 7}, {})\n{1: 5, 2: 7}\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-202","title":"Exercice 20.2","text":"Exercice 20.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re une piste carr\u00e9e qui contient 4 cases par c\u00f4t\u00e9. Les cases sont num\u00e9rot\u00e9es de 0 inclus \u00e0 12 exclu comme ci-dessous :
L\u2019objectif de l\u2019exercice est d\u2019impl\u00e9menter le jeu suivant :
Au d\u00e9part, le joueur place son pion sur la case 0. A chaque coup, il lance un d\u00e9 \u00e9quilibr\u00e9 \u00e0 six faces et avance son pion d\u2019autant de cases que le nombre indiqu\u00e9 par le d\u00e9 (entre 1 et 6 inclus) dans le sens des aiguilles d\u2019une montre.
Par exemple, s\u2019il obtient 2 au premier lancer, il pose son pion sur la case 2 puis s\u2019il obtient 6 au deuxi\u00e8me lancer, il le pose sur la case 8, puis s\u2019il obtient \u00e0 nouveau 6, il pose le pion sur la case 2.
Le jeu se termine lorsque le joueur a pos\u00e9 son pion sur toutes les cases de la piste.
Compl\u00e9ter la fonction nbre_coups
ci-dessous de sorte qu\u2019elle renvoie le nombre de lancers al\u00e9atoires n\u00e9cessaires pour terminer le jeu.
Proposer ensuite quelques tests pour en v\u00e9rifier le fonctionnement.
from random import randint\n\ndef nbre_coups():\n n = ...\n cases_vues = [0]\n case_en_cours = 0\n nbre_cases = 12\n while ... < ...:\n x = randint(1, 6)\n case_en_cours = (case_en_cours + ...) % ...\n if ...:\n cases_vues.append(case_en_cours)\n n = ...\n return n\n
from random import randint\n\ndef nbre_coups():\nn = 0\ncases_vues = [0]\n case_en_cours = 0\n nbre_cases = 12\nwhile len(cases_vues) < nbre_cases:\nx = randint(1, 6)\ncase_en_cours = (case_en_cours + x) % nbre_cases\nif case_en_cours not in cases_vues:\ncases_vues.append(case_en_cours)\nn = n + 1\nreturn n\n
On consid\u00e8re une piste carr\u00e9e qui contient 4 cases par c\u00f4t\u00e9. Les cases sont num\u00e9rot\u00e9es\nde 0 inclus \u00e0 12 exclu comme ci-dessous :\n\n![image](data2023/20_carre.png){: .center width=20%}\n\nL\u2019objectif de l\u2019exercice est d\u2019impl\u00e9menter le jeu suivant :\n\nAu d\u00e9part, le joueur place son pion sur la case 0. A chaque coup, il lance un d\u00e9 \u00e9quilibr\u00e9\n\u00e0 six faces et avance son pion d\u2019autant de cases que le nombre indiqu\u00e9 par le d\u00e9 (entre\n1 et 6 inclus) dans le sens des aiguilles d\u2019une montre.\n\nPar exemple, s\u2019il obtient 2 au premier lancer, il pose son pion sur la case 2 puis s\u2019il\nobtient 6 au deuxi\u00e8me lancer, il le pose sur la case 8, puis s\u2019il obtient \u00e0 nouveau 6, il\npose le pion sur la case 2.\n\nLe jeu se termine lorsque le joueur a pos\u00e9 son pion sur **toutes les cases** de la piste.\n\nCompl\u00e9ter la fonction `nbre_coups` ci-dessous de sorte qu\u2019elle renvoie le nombre de\nlancers al\u00e9atoires n\u00e9cessaires pour terminer le jeu.\n\nProposer ensuite quelques tests pour en v\u00e9rifier le fonctionnement.\n\n```python linenums='1'\nfrom random import randint\n\ndef nbre_coups():\n n = ...\n cases_vues = [0]\n case_en_cours = 0\n nbre_cases = 12\n while ... < ...:\n x = randint(1, 6)\n case_en_cours = (case_en_cours + ...) % ...\n if ...:\n cases_vues.append(case_en_cours)\n n = ...\n return n\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-21","title":"\u25b6 Sujet 21","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-211","title":"Exercice 21.1","text":"Exercice 21.1
\u00c9nonc\u00e9CorrectionSource MarkdownLe codage par diff\u00e9rence (delta encoding en anglais) permet de compresser un tableau de donn\u00e9es en indiquant pour chaque donn\u00e9e, sa diff\u00e9rence avec la pr\u00e9c\u00e9dente (plut\u00f4t que la donn\u00e9e elle-m\u00eame). On se retrouve alors avec un tableau de donn\u00e9es plus petit, n\u00e9cessitant moins de place en m\u00e9moire. Cette m\u00e9thode se r\u00e9v\u00e8le efficace lorsque les valeurs cons\u00e9cutives sont proches.
Programmer la fonction delta(liste)
qui prend en param\u00e8tre un tableau non vide de nombres entiers et qui renvoie un tableau contenant les valeurs enti\u00e8res compress\u00e9es \u00e0 l\u2019aide cette technique.
Exemples :
>>> delta([1000, 800, 802, 1000, 1003])\n[1000, -200, 2, 198, 3]\n>>> delta([42])\n[42] \n
def delta(tab):\n diff = [tab[0]]\n for i in range(1, len(tab)):\n diff.append(tab[i] - tab[i-1])\n return diff\n
Le codage par diff\u00e9rence (*delta encoding* en anglais) permet de compresser un tableau de\ndonn\u00e9es en indiquant pour chaque donn\u00e9e, sa diff\u00e9rence avec la pr\u00e9c\u00e9dente (plut\u00f4t que la\ndonn\u00e9e elle-m\u00eame). On se retrouve alors avec un tableau de donn\u00e9es plus petit, n\u00e9cessitant\nmoins de place en m\u00e9moire. Cette m\u00e9thode se r\u00e9v\u00e8le efficace lorsque les valeurs cons\u00e9cutives\nsont proches.\n\nProgrammer la fonction `delta(liste)` qui prend en param\u00e8tre un tableau non vide de nombres entiers\net qui renvoie un tableau contenant les valeurs enti\u00e8res compress\u00e9es \u00e0 l\u2019aide cette technique.\n\nExemples :\n\n```python\n>>> delta([1000, 800, 802, 1000, 1003])\n[1000, -200, 2, 198, 3]\n>>> delta([42])\n[42] \n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-212","title":"Exercice 21.2","text":"Exercice 21.2
\u00c9nonc\u00e9CorrectionSources MarkdownUne expression arithm\u00e9tique ne comportant que les quatre op\u00e9rations +, \u2212, \u00d7, \u00f7 peut \u00eatre repr\u00e9sent\u00e9e sous forme d\u2019arbre binaire. Les n\u0153uds internes sont des op\u00e9rateurs et les feuilles sont des nombres. Dans un tel arbre, la disposition des n\u0153uds joue le r\u00f4le des parenth\u00e8ses que nous connaissons bien.
En parcourant en profondeur infixe l\u2019arbre binaire ci-dessus, on retrouve l\u2019expression not\u00e9e habituellement :
\\[(3 \\times (8 + 7)) \u2212 (2 + 1)\\]La classe Noeud
ci-apr\u00e8s permet d\u2019impl\u00e9menter une structure d\u2019arbre binaire.
Compl\u00e9ter la fonction r\u00e9cursive expression_infixe
qui prend en param\u00e8tre un objet de la classe Noeud
et qui renvoie l\u2019expression arithm\u00e9tique repr\u00e9sent\u00e9e par l\u2019arbre binaire pass\u00e9 en param\u00e8tre, sous forme d\u2019une cha\u00eene de caract\u00e8res contenant des parenth\u00e8ses.
R\u00e9sultat attendu avec l\u2019arbre ci-dessus :
>>> e = Noeud(Noeud(Noeud(None, 3, None), '*', Noeud(Noeud(None, 8, None),\n'+', Noeud(None, 7, None))), '-', Noeud(Noeud(None, 2, None), '+',\nNoeud(None, 1, None)))\n\n>>> expression_infixe(e)\n'((3*(8+7))-(2+1))'\n
class Noeud:\n'''\n classe impl\u00e9mentant un noeud d'arbre binaire\n '''\n\n def __init__(self, g, v, d):\n'''\n un objet Noeud poss\u00e8de 3 attributs :\n - gauche : le sous-arbre gauche,\n - valeur : la valeur de l'\u00e9tiquette,\n - droit : le sous-arbre droit.\n '''\n self.gauche = g\n self.valeur = v\n self.droit = d\n\n def __str__(self):\n'''\n renvoie la repr\u00e9sentation du noeud en chaine de caract\u00e8res\n '''\n return str(self.valeur)\n\n def est_une_feuille(self):\n'''\n renvoie True si et seulement si le noeud est une feuille\n '''\n return self.gauche is None and self.droit is None\n\n\ndef expression_infixe(e):\n s = ...\n if e.gauche is not None:\n s = '(' + s + expression_infixe(...)\n s = s + ...\n if ... is not None:\n s = s + ... + ...\n return s\n
class Noeud:\n'''\n classe impl\u00e9mentant un noeud d'arbre binaire\n '''\n\n def __init__(self, g, v, d):\n'''\n un objet Noeud poss\u00e8de 3 attributs :\n - gauche : le sous-arbre gauche,\n - valeur : la valeur de l'\u00e9tiquette,\n - droit : le sous-arbre droit.\n '''\n self.gauche = g\n self.valeur = v\n self.droit = d\n\n def __str__(self):\n'''\n renvoie la repr\u00e9sentation du noeud en chaine de caract\u00e8res\n '''\n return str(self.valeur)\n\n def est_une_feuille(self):\n'''\n renvoie True si et seulement si le noeud est une feuille\n '''\n return self.gauche is None and self.droit is None\n\n\ndef expression_infixe(e):\ns = ''\nif e.gauche is not None:\ns = '(' + s + expression_infixe(e.gauche)\ns = s + str(e.valeur)\nif e.droit is not None:\ns = s + expression_infixe(e.droit) + ')'\nreturn s\n
Une expression arithm\u00e9tique ne comportant que les quatre op\u00e9rations +, \u2212, \u00d7, \u00f7 peut \u00eatre\nrepr\u00e9sent\u00e9e sous forme d\u2019arbre binaire. Les n\u0153uds internes sont des op\u00e9rateurs et les feuilles\nsont des nombres. Dans un tel arbre, la disposition des n\u0153uds joue le r\u00f4le des parenth\u00e8ses que\nnous connaissons bien. \n\n![image](data2023/21_arbre.png){: .center width=30%}\n\nEn parcourant en profondeur infixe l\u2019arbre binaire ci-dessus, on\nretrouve l\u2019expression not\u00e9e habituellement : \n\n\n$$(3 \\times (8 + 7)) \u2212 (2 + 1)$$\n\n\nLa classe `Noeud` ci-apr\u00e8s permet d\u2019impl\u00e9menter une structure\nd\u2019arbre binaire.\n\nCompl\u00e9ter la fonction r\u00e9cursive `expression_infixe` qui prend\nen param\u00e8tre un objet de la classe `Noeud` et qui renvoie\nl\u2019expression arithm\u00e9tique repr\u00e9sent\u00e9e par l\u2019arbre binaire pass\u00e9\nen param\u00e8tre, sous forme d\u2019une cha\u00eene de caract\u00e8res contenant\ndes parenth\u00e8ses. \n\nR\u00e9sultat attendu avec l\u2019arbre ci-dessus :\n\n```python\n>>> e = Noeud(Noeud(Noeud(None, 3, None), '*', Noeud(Noeud(None, 8, None),\n'+', Noeud(None, 7, None))), '-', Noeud(Noeud(None, 2, None), '+',\nNoeud(None, 1, None)))\n\n>>> expression_infixe(e)\n'((3*(8+7))-(2+1))'\n
class Noeud:\n'''\n classe impl\u00e9mentant un noeud d'arbre binaire\n '''\n\n def __init__(self, g, v, d):\n'''\n un objet Noeud poss\u00e8de 3 attributs :\n - gauche : le sous-arbre gauche,\n - valeur : la valeur de l'\u00e9tiquette,\n - droit : le sous-arbre droit.\n '''\n self.gauche = g\n self.valeur = v\n self.droit = d\n\n def __str__(self):\n'''\n renvoie la repr\u00e9sentation du noeud en chaine de caract\u00e8res\n '''\n return str(self.valeur)\n\n def est_une_feuille(self):\n'''\n renvoie True si et seulement si le noeud est une feuille\n '''\n return self.gauche is None and self.droit is None\n\n\ndef expression_infixe(e):\n s = ...\n if e.gauche is not None:\n s = '(' + s + expression_infixe(...)\n s = s + ...\n if ... is not None:\n s = s + ... + ...\n return s\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-22","title":"\u25b6 Sujet 22","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-221","title":"Exercice 22.1","text":"Exercice 22.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn rappelle que :
t[-1]
permet d\u2019acc\u00e9der au dernier \u00e9l\u00e9ment du tableau t
.Dans cet exercice, l\u2019op\u00e9rateur **
et la fonction pow
ne sont pas autoris\u00e9s.
Programmer en langage Python une fonction liste_puissances
qui prend en argument un nombre entier a
, un entier strictement positif n
et qui renvoie la liste de ses puissances \\(\\rm{[a^1, a^2, ..., a^n]}\\).
Programmer \u00e9galement une fonction liste_puisssances_borne
qui prend en argument un nombre entier a
sup\u00e9rieur ou \u00e9gal \u00e0 2 et un entier borne
, et qui renvoie la liste de ses puissances, \u00e0 l\u2019exclusion de \\(\\rm{a^0}\\), strictement inf\u00e9rieures \u00e0 borne
.
Exemples :
>>> liste_puissances(3, 5)\n[3, 9, 27, 81, 243]\n>>> liste_puissances(-2, 4)\n[-2, 4, -8, 16]\n>>> liste_puissances_borne(2, 16)\n[2, 4, 8]\n>>> liste_puissances_borne(2, 17)\n[2, 4, 8, 16]\n>>> liste_puissances_borne(5, 5)\n[]\n
def liste_puissances(a,n):\n puissances = [a]\n for i in range(n-1):\n puissances.append(puissances[-1] * a)\n return puissances\n\ndef liste_puissances_borne(a, borne):\n lst = []\n val = a\n while val < borne:\n lst.append(val)\n val = val * a\n return lst\n
On rappelle que :\n\n- le nombre $a^n$ est le nombre $a \\times a \\times a \\times \\dots \\times a$, o\u00f9 le facteur $a$ appara\u00eet $n$ fois,\n- en langage Python, l\u2019instruction `t[-1]` permet d\u2019acc\u00e9der au dernier \u00e9l\u00e9ment du\ntableau `t`.\n\nDans cet exercice, l\u2019op\u00e9rateur ```**``` et la fonction `pow` ne sont pas autoris\u00e9s.\n\nProgrammer en langage Python une fonction `liste_puissances` qui prend en argument\nun nombre entier `a`, un entier strictement positif `n` et qui renvoie la liste de ses puissances\n$\\rm{[a^1, a^2, ..., a^n]}$.\n\nProgrammer \u00e9galement une fonction `liste_puisssances_borne` qui prend en\nargument un nombre entier `a` sup\u00e9rieur ou \u00e9gal \u00e0 2 et un entier `borne`, et qui renvoie la\nliste de ses puissances, \u00e0 l\u2019exclusion de $\\rm{a^0}$, strictement inf\u00e9rieures \u00e0 `borne`.\n\nExemples :\n\n```python\n>>> liste_puissances(3, 5)\n[3, 9, 27, 81, 243]\n>>> liste_puissances(-2, 4)\n[-2, 4, -8, 16]\n>>> liste_puissances_borne(2, 16)\n[2, 4, 8]\n>>> liste_puissances_borne(2, 17)\n[2, 4, 8, 16]\n>>> liste_puissances_borne(5, 5)\n[]\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-222","title":"Exercice 22.2","text":"Exercice 22.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn affecte \u00e0 chaque lettre de l'alphabet un code selon le tableau ci-dessous :
A B C D E F G H I J K L M 1 2 3 4 5 6 7 8 9 10 11 12 13 N O P Q R S T U V W X Y Z 14 15 16 17 18 19 20 21 22 23 24 25 26Pour un mot donn\u00e9, on d\u00e9termine d\u2019une part son code alphab\u00e9tique concat\u00e9n\u00e9, obtenu par la juxtaposition des codes de chacun de ses caract\u00e8res, et d\u2019autre part, son code additionn\u00e9, qui est la somme des codes de chacun de ses caract\u00e8res.
Par ailleurs, on dit que ce mot est \u00ab parfait \u00bb si le code additionn\u00e9 divise le code concat\u00e9n\u00e9.
Exemples :
Pour le mot \"PAUL\"
, le code concat\u00e9n\u00e9 est la cha\u00eene '1612112'
, soit l\u2019entier 1 612 112. Son code additionn\u00e9 est l\u2019entier 50 car 16 + 1 + 21 + 12 = 50. 50 ne divise pas l\u2019entier 1 612 112 ; par cons\u00e9quent, le mot \"PAUL\"
n\u2019est pas parfait.
Pour le mot \"ALAIN\"
, le code concat\u00e9n\u00e9 est la cha\u00eene '1121914'
, soit l\u2019entier 1 121 914. Le code additionn\u00e9 est l\u2019entier 37 car 1 + 12 + 1 + 9 + 14 = 37. 37 divise l\u2019entier 1 121 914 ; par cons\u00e9quent, le mot \"ALAIN\"
est parfait.
Compl\u00e9ter la fonction est_parfait
ci-dessous qui prend comme argument une cha\u00eene de caract\u00e8res mot
(en lettres majuscules) et qui renvoie le code alphab\u00e9tique concat\u00e9n\u00e9, le code additionn\u00e9 de mot
, ainsi qu\u2019un bool\u00e9en qui indique si mot
est parfait ou pas.
dico = {\"A\": 1, \"B\": 2, \"C\": 3, \"D\": 4, \"E\": 5, \"F\": 6,\n \"G\": 7, \"H\": 8, \"I\": 9, \"J\": 10, \"K\": 11, \"L\": 12,\n \"M\": 13, \"N\": 14, \"O\": 15, \"P\": 16, \"Q\": 17,\n \"R\": 18, \"S\": 19, \"T\": 20, \"U\": 21, \"V\": 22,\n \"W\": 23, \"X\": 24, \"Y\": 25, \"Z\": 26}\n\n\ndef est_parfait(mot):\n # mot est une cha\u00eene de caract\u00e8res (en lettres majuscules)\n code_concatene = \"\"\n code_additionne = ...\n for c in mot:\n code_concatene = code_concatene + ...\n code_additionne = ...\n code_concatene = int(code_concatene)\n if ... :\n mot_est_parfait = True\n else:\n mot_est_parfait = False\n return code_additionne, code_concatene, mot_est_parfait\n
Exemples :
>>> est_parfait(\"PAUL\")\n(50, 1612112, False)\n>>> est_parfait(\"ALAIN\")\n(37, 1121914, True)\n
dico = {\"A\": 1, \"B\": 2, \"C\": 3, \"D\": 4, \"E\": 5, \"F\": 6,\n \"G\": 7, \"H\": 8, \"I\": 9, \"J\": 10, \"K\": 11, \"L\": 12,\n \"M\": 13, \"N\": 14, \"O\": 15, \"P\": 16, \"Q\": 17,\n \"R\": 18, \"S\": 19, \"T\": 20, \"U\": 21, \"V\": 22,\n \"W\": 23, \"X\": 24, \"Y\": 25, \"Z\": 26}\n\n\ndef est_parfait(mot):\n # mot est une cha\u00eene de caract\u00e8res (en lettres majuscules)\n code_concatene = \"\"\ncode_additionne = 0\nfor c in mot:\ncode_concatene = code_concatene + str(dico[c])\ncode_additionne = code_additionne + dico[c]\ncode_concatene = int(code_concatene)\nif code_concatene % code_additionne == 0:\nmot_est_parfait = True\n else:\n mot_est_parfait = False\n return code_additionne, code_concatene, mot_est_parfait\n
On affecte \u00e0 chaque lettre de l'alphabet un code selon le tableau ci-dessous :\n\n| A | B | C | D | E | F | G | H | I | J | K | L | M |\n|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|\n| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |\n\n\n| N | O | P | Q | R | S | T | U | V | W | X | Y | Z | \n|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|\n| 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | \n\n\n\nPour un mot donn\u00e9, on d\u00e9termine d\u2019une part son *code alphab\u00e9tique concat\u00e9n\u00e9*, obtenu\npar la juxtaposition des codes de chacun de ses caract\u00e8res, et d\u2019autre part, *son code\nadditionn\u00e9*, qui est la somme des codes de chacun de ses caract\u00e8res.\n\nPar ailleurs, on dit que ce mot est \u00ab *parfait* \u00bb si le code additionn\u00e9 divise le code concat\u00e9n\u00e9.\n\nExemples :\n\n- Pour le mot `\"PAUL\"`, le code concat\u00e9n\u00e9 est la cha\u00eene `'1612112'`, soit l\u2019entier 1 612 112.\nSon code additionn\u00e9 est l\u2019entier 50 car 16 + 1 + 21 + 12 = 50.\n50 ne divise pas l\u2019entier 1 612 112 ; par cons\u00e9quent, le mot `\"PAUL\"` n\u2019est pas\nparfait.\n\n- Pour le mot `\"ALAIN\"`, le code concat\u00e9n\u00e9 est la cha\u00eene `'1121914'`, soit l\u2019entier\n1 121 914. Le code additionn\u00e9 est l\u2019entier 37 car 1 + 12 + 1 + 9 + 14 = 37.\n37 divise l\u2019entier 1 121 914 ; par cons\u00e9quent, le mot `\"ALAIN\"` est parfait.\n\n\nCompl\u00e9ter la fonction `est_parfait` ci-dessous qui prend comme argument une cha\u00eene\nde caract\u00e8res `mot` (en lettres majuscules) et qui renvoie le code alphab\u00e9tique concat\u00e9n\u00e9,\nle code additionn\u00e9 de `mot`, ainsi qu\u2019un bool\u00e9en qui indique si `mot` est parfait ou pas.\n\n```python linenums='1'\ndico = {\"A\": 1, \"B\": 2, \"C\": 3, \"D\": 4, \"E\": 5, \"F\": 6,\n \"G\": 7, \"H\": 8, \"I\": 9, \"J\": 10, \"K\": 11, \"L\": 12,\n \"M\": 13, \"N\": 14, \"O\": 15, \"P\": 16, \"Q\": 17,\n \"R\": 18, \"S\": 19, \"T\": 20, \"U\": 21, \"V\": 22,\n \"W\": 23, \"X\": 24, \"Y\": 25, \"Z\": 26}\n\n\ndef est_parfait(mot):\n # mot est une cha\u00eene de caract\u00e8res (en lettres majuscules)\n code_concatene = \"\"\n code_additionne = ...\n for c in mot:\n code_concatene = code_concatene + ...\n code_additionne = ...\n code_concatene = int(code_concatene)\n if ... :\n mot_est_parfait = True\n else:\n mot_est_parfait = False\n return code_additionne, code_concatene, mot_est_parfait\n
Exemples :
>>> est_parfait(\"PAUL\")\n(50, 1612112, False)\n>>> est_parfait(\"ALAIN\")\n(37, 1121914, True)\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-23","title":"\u25b6 Sujet 23","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-231","title":"Exercice 23.1","text":"Exercice 23.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn consid\u00e8re des tables (des tableaux de dictionnaires) qui contiennent des enregistrements relatifs \u00e0 des animaux h\u00e9berg\u00e9s dans un refuge. Les attributs des enregistrements sont 'nom'
, 'espece'
, 'age'
, 'enclos'
. Voici un exemple d'une telle table :
animaux = [ {'nom':'Medor', 'espece':'chien', 'age':5, 'enclos':2},\n {'nom':'Titine', 'espece':'chat', 'age':2, 'enclos':5},\n {'nom':'Tom', 'espece':'chat', 'age':7, 'enclos':4},\n {'nom':'Belle', 'espece':'chien', 'age':6, 'enclos':3},\n {'nom':'Mirza', 'espece':'chat', 'age':6, 'enclos':5}]\n
Programmer une fonction selection_enclos
qui :
table_animaux
contenant des enregistrements relatifs \u00e0 des animaux (comme dans l'exemple ci-dessus),num_enclos
;table_animaux
dont l'attribut 'enclos'
est num_enclos
.Exemples avec la table animaux
ci-dessus :
>>> selection_enclos(animaux, 5)\n[{'nom':'Titine', 'espece':'chat', 'age':2, 'enclos':5},\n {'nom':'Mirza', 'espece':'chat', 'age':6, 'enclos':5}]\n\n>>> selection_enclos(animaux, 2)\n[{'nom':'Medor', 'espece':'chien', 'age':5, 'enclos':2}]\n\n>>> selection_enclos(animaux, 7)\n[]\n
def selection_enclos(table_animaux, num_enclos):\n table = []\n for animal in table_animaux:\n if animal['enclos'] == num_enclos:\n table.append(animal)\n return table\n
On consid\u00e8re des tables (des tableaux de dictionnaires) qui contiennent des enregistrements\nrelatifs \u00e0 des animaux h\u00e9berg\u00e9s dans un refuge. Les attributs des enregistrements sont\n`'nom'`, `'espece'`, `'age'`, `'enclos'`. Voici un exemple d'une telle table :\n\n```python\nanimaux = [ {'nom':'Medor', 'espece':'chien', 'age':5, 'enclos':2},\n {'nom':'Titine', 'espece':'chat', 'age':2, 'enclos':5},\n {'nom':'Tom', 'espece':'chat', 'age':7, 'enclos':4},\n {'nom':'Belle', 'espece':'chien', 'age':6, 'enclos':3},\n {'nom':'Mirza', 'espece':'chat', 'age':6, 'enclos':5}]\n```\n\nProgrammer une fonction `selection_enclos` qui :\n\n- prend en param\u00e8tres :\n - une table `table_animaux` contenant des enregistrements relatifs \u00e0 des\nanimaux (comme dans l'exemple ci-dessus),\n - un num\u00e9ro d'enclos `num_enclos` ;\n- renvoie une table contenant les enregistrements de `table_animaux` dont l'attribut\n`'enclos'` est `num_enclos`.\n\nExemples avec la table `animaux` ci-dessus :\n\n```python\n>>> selection_enclos(animaux, 5)\n[{'nom':'Titine', 'espece':'chat', 'age':2, 'enclos':5},\n {'nom':'Mirza', 'espece':'chat', 'age':6, 'enclos':5}]\n\n>>> selection_enclos(animaux, 2)\n[{'nom':'Medor', 'espece':'chien', 'age':5, 'enclos':2}]\n\n>>> selection_enclos(animaux, 7)\n[]\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-232","title":"Exercice 23.2","text":"Exercice 23.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re des tableaux de nombres dont tous les \u00e9l\u00e9ments sont pr\u00e9sents exactement trois fois \u00e0 la suite, sauf un \u00e9l\u00e9ment qui est pr\u00e9sent une unique fois et que l'on appelle \u00ab l'intrus \u00bb. Voici quelques exemples :
tab_a = [3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5, 5, 5]\n#l'intrus est 7\n\ntab_b = [8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3]\n#l'intrus est 8\n\ntab_c = [5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8, 8, 8]\n#l'intrus est 3\n
On remarque qu'avec de tels tableaux : Ce que l'on peut observer ci-dessous en observant les valeurs des paires de voisins marqu\u00e9es par des caract\u00e8res ^ :
[3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5, 5, 5]\n ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^\n 0 3 6 9 12 15 18 21\n
Dans des listes comme celles ci-dessus, un algorithme r\u00e9cursif pour trouver l'intrus consiste alors \u00e0 choisir un indice i
multiple de 3 situ\u00e9 approximativement au milieu des indices parmi lesquels se trouve l'intrus.
Puis, en fonction des valeurs de l'\u00e9l\u00e9ment d'indice i
et de son voisin de droite, \u00e0 appliquer r\u00e9cursivement l'algorithme \u00e0 la moiti\u00e9 droite ou \u00e0 la moiti\u00e9 gauche des indices parmi lesquels se trouve l'intrus.
Par exemple, si on s\u2019int\u00e9resse \u00e0 l\u2019indice 12, on voit les valeurs 2 et 4 qui sont diff\u00e9rentes : l\u2019intrus est donc \u00e0 gauche de l\u2019indice 12 (indice 12 compris)
En revanche, si on s\u2019int\u00e9resse \u00e0 l\u2019indice 3, on voit les valeurs 9 et 9 qui sont identiques : l\u2019intrus est donc \u00e0 droite des indices 3-4-5, donc \u00e0 partir de l\u2019indice 6.
Compl\u00e9ter la fonction r\u00e9cursive trouver_intrus
propos\u00e9e page suivante qui met en \u0153uvre cet algorithme.
def trouver_intrus(tab, g, d):\n'''\n Renvoie la valeur de l'intrus situ\u00e9 entre les indices g et d \n dans la liste tab o\u00f9 :\n tab v\u00e9rifie les conditions de l'exercice,\n g et d sont des multiples de 3.\n '''\n if g == d:\n return ...\n\n else:\n nombre_de_triplets = (d - g) // ...\n indice = g + 3 * (nombre_de_triplets // 2)\n if ... :\n return ...\n else:\n return ...\n
Exemples :
>>> trouver_intrus([3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8,\n8, 5, 5, 5], 0, 21)\n7\n\n>>> trouver_intrus([8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3], 0, 12)\n8\n\n>>> trouver_intrus([5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8, 8, 8], 0, 15)\n3\n
def trouver_intrus(tab, g, d):\n'''\n Renvoie la valeur de l'intrus situ\u00e9 entre les indices g et d \n dans la liste tab o\u00f9 :\n tab v\u00e9rifie les conditions de l'exercice,\n g et d sont des multiples de 3.\n '''\n if g == d:\nreturn tab[g]\nelse:\nnombre_de_triplets = (d - g) // 3\nindice = g + 3 * (nombre_de_triplets // 2)\nif tab[indice] != tab[indice + 1] :\nreturn trouver_intrus(tab, g, indice)\nelse:\nreturn trouver_intrus(tab, indice + 3, d)\n
On consid\u00e8re des tableaux de nombres dont tous les \u00e9l\u00e9ments sont pr\u00e9sents exactement\ntrois fois \u00e0 la suite, sauf un \u00e9l\u00e9ment qui est pr\u00e9sent une unique fois et que l'on appelle \u00ab\nl'intrus \u00bb. Voici quelques exemples :\n\n```python\ntab_a = [3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5, 5, 5]\n#l'intrus est 7\n\ntab_b = [8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3]\n#l'intrus est 8\n\ntab_c = [5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8, 8, 8]\n#l'intrus est 3\n
On remarque qu'avec de tels tableaux : Ce que l'on peut observer ci-dessous en observant les valeurs des paires de voisins marqu\u00e9es par des caract\u00e8res ^ :
[3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5, 5, 5]\n ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^\n 0 3 6 9 12 15 18 21\n
Dans des listes comme celles ci-dessus, un algorithme r\u00e9cursif pour trouver l'intrus consiste alors \u00e0 choisir un indice i
multiple de 3 situ\u00e9 approximativement au milieu des indices parmi lesquels se trouve l'intrus.
Puis, en fonction des valeurs de l'\u00e9l\u00e9ment d'indice i
et de son voisin de droite, \u00e0 appliquer r\u00e9cursivement l'algorithme \u00e0 la moiti\u00e9 droite ou \u00e0 la moiti\u00e9 gauche des indices parmi lesquels se trouve l'intrus.
Par exemple, si on s\u2019int\u00e9resse \u00e0 l\u2019indice 12, on voit les valeurs 2 et 4 qui sont diff\u00e9rentes : l\u2019intrus est donc \u00e0 gauche de l\u2019indice 12 (indice 12 compris)
En revanche, si on s\u2019int\u00e9resse \u00e0 l\u2019indice 3, on voit les valeurs 9 et 9 qui sont identiques : l\u2019intrus est donc \u00e0 droite des indices 3-4-5, donc \u00e0 partir de l\u2019indice 6.
Compl\u00e9ter la fonction r\u00e9cursive trouver_intrus
propos\u00e9e page suivante qui met en \u0153uvre cet algorithme.
def trouver_intrus(tab, g, d):\n'''\n Renvoie la valeur de l'intrus situ\u00e9 entre les indices g et d \n dans la liste tab o\u00f9 :\n tab v\u00e9rifie les conditions de l'exercice,\n g et d sont des multiples de 3.\n '''\n if g == d:\n return ...\n\n else:\n nombre_de_triplets = (d - g) // ...\n indice = g + 3 * (nombre_de_triplets // 2)\n if ... :\n return ...\n else:\n return ...\n
Exemples :
>>> trouver_intrus([3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8,\n8, 5, 5, 5], 0, 21)\n7\n\n>>> trouver_intrus([8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3], 0, 12)\n8\n\n>>> trouver_intrus([5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8, 8, 8], 0, 15)\n3\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-24","title":"\u25b6 Sujet 24","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-241","title":"Exercice 24.1","text":"Exercice 24.1
\u00c9nonc\u00e9CorrectionSource MarkdownLe nombre d\u2019occurrences d\u2019un caract\u00e8re dans une cha\u00eene de caract\u00e8re est le nombre d\u2019apparitions de ce caract\u00e8re dans la cha\u00eene.
Exemples :
On cherche les occurrences des caract\u00e8res dans une phrase. On souhaite stocker ces occurrences dans un dictionnaire dont les clefs seraient les caract\u00e8res de la phrase et les valeurs l\u2019occurrence de ces caract\u00e8res.
Par exemple : avec la phrase 'Hello world !' le dictionnaire est le suivant :
{'H': 1,'e': 1,'l': 3,'o': 2,' ': 2,'w': 1,'r': 1,'d': 1,'!': 1}
L\u2019ordre des clefs n\u2019a pas d\u2019importance.
\u00c9crire une fonction nbr_occurrences
prenant comme param\u00e8tre une cha\u00eene de caract\u00e8res chaine
et renvoyant le dictionnaire des nombres d\u2019occurrences des caract\u00e8res de cette cha\u00eene.
def nbr_occurrences(chaine):\n nb_occ = {}\n for caractere in chaine:\n if caractere in nb_occ:\n nb_occ[caractere] += 1\n else:\n nb_occ[caractere] = 1\n return nb_occ\n
Le nombre d\u2019occurrences d\u2019un caract\u00e8re dans une cha\u00eene de caract\u00e8re est le nombre\nd\u2019apparitions de ce caract\u00e8re dans la cha\u00eene.\n\nExemples :\n\n- le nombre d\u2019occurrences du caract\u00e8re \u2018o\u2019 dans \u2018bonjour\u2019 est 2 ;\n- le nombre d\u2019occurrences du caract\u00e8re \u2018b\u2019 dans \u2018B\u00e9b\u00e9\u2019 est 1 ;\n- le nombre d\u2019occurrences du caract\u00e8re \u2018B\u2019 dans \u2018B\u00e9b\u00e9\u2019 est 1 ;\n- le nombre d\u2019occurrences du caract\u00e8re \u2018 \u2018 dans \u2018Hello world !\u2019 est 2.\n\nOn cherche les occurrences des caract\u00e8res dans une phrase. On souhaite stocker ces\noccurrences dans un dictionnaire dont les clefs seraient les caract\u00e8res de la phrase et\nles valeurs l\u2019occurrence de ces caract\u00e8res.\n\nPar exemple : avec la phrase 'Hello world !' le dictionnaire est le suivant :\n\n`{'H': 1,'e': 1,'l': 3,'o': 2,' ': 2,'w': 1,'r': 1,'d': 1,'!': 1}`\n\n*L\u2019ordre des clefs n\u2019a pas d\u2019importance.*\n\n\u00c9crire une fonction `nbr_occurrences` prenant comme param\u00e8tre une cha\u00eene de\ncaract\u00e8res `chaine` et renvoyant le dictionnaire des nombres d\u2019occurrences des\ncaract\u00e8res de cette cha\u00eene.\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-242","title":"Exercice 24.2","text":"Exercice 24.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa fonction fusion
prend deux listes lst1
, lst2
d\u2019entiers tri\u00e9es par ordre croissant et les fusionne en une liste tri\u00e9e lst12
qu\u2019elle renvoie.
Le code Python de la fonction fusion
est
def fusion(lst1,lst2):\n n1 = len(lst1)\n n2 = len(lst2)\n lst12 = [0] * (n1 + n2)\n i1 = 0\n i2 = 0\n i = 0\n while i1 < n1 and ... :\n if lst1[i1] < lst2[i2]:\n lst12[i] = ...\n i1 = ...\n else:\n lst12[i] = lst2[i2]\n i2 = ...\n i += 1\n while i1 < n1:\n lst12[i] = ...\n i1 = i1 + 1\n i = ...\n while i2 < n2:\n lst12[i] = ...\n i2 = i2 + 1\n i = ...\n return lst12\n
Compl\u00e9ter le code.
Exemple :
>>> fusion([1, 6, 10],[0, 7, 8, 9])\n[0, 1, 6, 7, 8, 9, 10]\n
def fusion(lst1, lst2):\n n1 = len(lst1)\n n2 = len(lst2)\n lst12 = [0] * (n1 + n2)\n i1 = 0\n i2 = 0\n i = 0\nwhile i1 < n1 and i2 < n2 :\nif lst1[i1] < lst2[i2]:\nlst12[i] = lst1[i1]\ni1 = i1 + 1\nelse:\n lst12[i] = lst2[i2]\ni2 = i2 + 1\ni += 1\n while i1 < n1:\nlst12[i] = lst1[i1]\ni1 = i1 + 1\ni = i + 1\nwhile i2 < n2:\nlst12[i] = lst2[i2]\ni2 = i2 + 1\ni = i + 1\nreturn lst12\n
La fonction `fusion` prend deux listes `lst1`, `lst2` d\u2019entiers tri\u00e9es par ordre croissant et les\nfusionne en une liste tri\u00e9e `lst12` qu\u2019elle renvoie.\n\nLe code Python de la fonction `fusion` est\n\n```python linenums='1'\ndef fusion(lst1,lst2):\n n1 = len(lst1)\n n2 = len(lst2)\n lst12 = [0] * (n1 + n2)\n i1 = 0\n i2 = 0\n i = 0\n while i1 < n1 and ... :\n if lst1[i1] < lst2[i2]:\n lst12[i] = ...\n i1 = ...\n else:\n lst12[i] = lst2[i2]\n i2 = ...\n i += 1\n while i1 < n1:\n lst12[i] = ...\n i1 = i1 + 1\n i = ...\n while i2 < n2:\n lst12[i] = ...\n i2 = i2 + 1\n i = ...\n return lst12\n
Compl\u00e9ter le code.
Exemple :
>>> fusion([1, 6, 10],[0, 7, 8, 9])\n[0, 1, 6, 7, 8, 9, 10]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-25","title":"\u25b6 Sujet 25","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-251","title":"Exercice 25.1","text":"Exercice 25.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction enumere
qui prend en param\u00e8tre une liste L
et renvoie un dictionnaire d
dont les cl\u00e9s sont les \u00e9l\u00e9ments de L
avec pour valeur associ\u00e9e la liste des indices de l\u2019\u00e9l\u00e9ment dans la liste L
.
Exemple :
>>> enumere([1, 1, 2, 3, 2, 1])\n{1: [0, 1, 5], 2: [2, 4], 3: [3]}\n
def enumere(L):\n d = {}\n for i in range(len(L)):\n if L[i] in d:\n d[L[i]].append(i)\n else:\n d[L[i]] = [i]\n return d\n
\u00c9crire une fonction `enumere` qui prend en param\u00e8tre une liste `L` et renvoie un\ndictionnaire `d` dont les cl\u00e9s sont les \u00e9l\u00e9ments de `L` avec pour valeur associ\u00e9e la liste des\nindices de l\u2019\u00e9l\u00e9ment dans la liste `L`.\n\nExemple :\n\n```python\n>>> enumere([1, 1, 2, 3, 2, 1])\n{1: [0, 1, 5], 2: [2, 4], 3: [3]}\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-252","title":"Exercice 25.2","text":"Exercice 25.2
\u00c9nonc\u00e9CorrectionSources MarkdownUn arbre binaire est impl\u00e9ment\u00e9 par la classe Arbre
donn\u00e9e ci-dessous. Les attributs fg
et fd
prennent pour valeurs des instances de la classe Arbre
ou None
.
class Arbre:\n def __init__(self, etiquette):\n self.v = etiquette\n self.fg = None\n self.fd = None\n\ndef parcours(arbre, liste):\n if arbre != None:\n parcours(arbre.fg, liste)\n liste.append(arbre.v)\n parcours(arbre.fd, liste)\n return liste\n
La fonction r\u00e9cursive parcours
renvoie la liste des \u00e9tiquettes des n\u0153uds de l\u2019arbre impl\u00e9ment\u00e9 par l\u2019instance arbre
dans l\u2019ordre du parcours en profondeur infixe \u00e0 partir d\u2019une liste vide pass\u00e9e en argument.
Compl\u00e9ter le code de la fonction insere
qui ins\u00e8re un n\u0153ud d\u2019\u00e9tiquette cle
en feuille de l\u2019arbre impl\u00e9ment\u00e9 par l\u2019instance arbre
selon la sp\u00e9cification indiqu\u00e9e et de fa\u00e7on que l\u2019arbre ainsi compl\u00e9t\u00e9 soit encore un arbre binaire de recherche.
Tester ensuite ce code en utilisant la fonction parcours
et en ins\u00e9rant successivement des n\u0153uds d\u2019\u00e9tiquette 1, 4, 6 et 8 dans l\u2019arbre binaire de recherche repr\u00e9sent\u00e9 ci- dessous :
def insere(arbre, cle):\n\"\"\" arbre est une instance de la classe Arbre qui impl\u00e9mente\n un arbre binaire de recherche.\n \"\"\"\n if ...:\n if ...:\n insere(arbre.fg, cle)\n else:\n arbre.fg = Arbre(cle)\n else:\n if ...:\n insere(arbre.fd, cle)\n else:\n arbre.fd = Arbre(cle)\n
def insere(arbre, cle):\n\"\"\" arbre est une instance de la classe Arbre qui impl\u00e9mente\n un arbre binaire de recherche.\n\"\"\"\nif cle < arbre.v:\nif arbre.fg is not None:\ninsere(arbre.fg, cle)\n else:\n arbre.fg = Arbre(cle)\n else:\nif arbre.fd is not None:\ninsere(arbre.fd, cle)\n else:\n arbre.fd = Arbre(cle)\n
Tests :
>>> a = Arbre(5)\n>>> insere(a, 2)\n>>> insere(a, 7)\n>>> insere(a, 3)\n>>> parcours(a, [])\n[2, 3, 5, 7]\n>>> insere(a, 1)\n>>> insere(a, 4)\n>>> insere(a, 6)\n>>> insere(a, 8)\n>>> parcours(a, [])\n[1, 2, 3, 4, 5, 6, 7, 8]\n
Un arbre binaire est impl\u00e9ment\u00e9 par la classe `Arbre` donn\u00e9e ci-dessous. \nLes attributs `fg` et `fd` prennent pour valeurs des instances de la classe `Arbre` ou `None`.\n\n```python linenums='1'\nclass Arbre:\n def __init__(self, etiquette):\n self.v = etiquette\n self.fg = None\n self.fd = None\n\ndef parcours(arbre, liste):\n if arbre != None:\n parcours(arbre.fg, liste)\n liste.append(arbre.v)\n parcours(arbre.fd, liste)\n return liste\n
La fonction r\u00e9cursive parcours
renvoie la liste des \u00e9tiquettes des n\u0153uds de l\u2019arbre impl\u00e9ment\u00e9 par l\u2019instance arbre
dans l\u2019ordre du parcours en profondeur infixe \u00e0 partir d\u2019une liste vide pass\u00e9e en argument.
Compl\u00e9ter le code de la fonction insere
qui ins\u00e8re un n\u0153ud d\u2019\u00e9tiquette cle
en feuille de l\u2019arbre impl\u00e9ment\u00e9 par l\u2019instance arbre
selon la sp\u00e9cification indiqu\u00e9e et de fa\u00e7on que l\u2019arbre ainsi compl\u00e9t\u00e9 soit encore un arbre binaire de recherche.
Tester ensuite ce code en utilisant la fonction parcours
et en ins\u00e9rant successivement des n\u0153uds d\u2019\u00e9tiquette 1, 4, 6 et 8 dans l\u2019arbre binaire de recherche repr\u00e9sent\u00e9 ci- dessous :
def insere(arbre, cle):\n\"\"\" arbre est une instance de la classe Arbre qui impl\u00e9mente\n un arbre binaire de recherche.\n \"\"\"\n if ...:\n if ...:\n insere(arbre.fg, cle)\n else:\n arbre.fg = Arbre(cle)\n else:\n if ...:\n insere(arbre.fd, cle)\n else:\n arbre.fd = Arbre(cle)\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-26","title":"\u25b6 Sujet 26","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-261","title":"Exercice 26.1","text":"Exercice 26.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction multiplication
, prenant en param\u00e8tres deux nombres entiers n1
et n2
, et qui renvoie le produit de ces deux nombres.
Les seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.
>>> multiplication(3, 5)\n15\n>>> multiplication(-4, -8)\n32\n>>> multiplication(-2, 6)\n-12\n>>> multiplication(-2, 0)\n0\n
def multiplication(n1, n2):\n # on se ram\u00e8ne d'abord au cas o\u00f9 n1 et n2 sont tous les deux positifs :\n if n1 < 0:\n return -multiplication(-n1, n2)\n if n2 < 0:\n return -multiplication(n1, -n2)\n\n resultat = 0\n for _ in range(n2):\n resultat += n1\n return resultat\n
Programmer la fonction `multiplication`, prenant en param\u00e8tres deux nombres entiers\n`n1` et `n2`, et qui renvoie le produit de ces deux nombres.\n\nLes seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.\n\n```python\n>>> multiplication(3, 5)\n15\n>>> multiplication(-4, -8)\n32\n>>> multiplication(-2, 6)\n-12\n>>> multiplication(-2, 0)\n0\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-262","title":"Exercice 26.2","text":"Exercice 26.2
\u00c9nonc\u00e9CorrectionSources MarkdownRecopier et compl\u00e9ter sous Python la fonction suivante en respectant la sp\u00e9cification. On ne recopiera pas les commentaires.
def dichotomie(tab, x):\n\"\"\"\n tab : tableau d\u2019entiers tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\nFalse\n
def dichotomie(tab, x):\n\"\"\"\n tab : tableau d\u2019entiers tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\nm = (debut + fin) // 2\nif x == tab[m]:\nreturn True\nif x > tab[m]:\n debut = m + 1\n else:\nfin = m - 1\nreturn False\n
Recopier et compl\u00e9ter sous Python la fonction suivante en respectant la sp\u00e9cification. On\nne recopiera pas les commentaires.\n\n```python linenums='1'\ndef dichotomie(tab, x):\n \"\"\"\n tab : tableau d\u2019entiers tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\nFalse\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-27","title":"\u25b6 Sujet 27","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-271","title":"Exercice 27.1","text":"Exercice 27.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche_min
qui prend en param\u00e8tre un tableau de nombres non tri\u00e9 tab
, et qui renvoie l'indice de la premi\u00e8re occurrence du minimum de ce tableau. Les tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.
Exemples :
>>> recherche_min([5])\n0\n>>> recherche_min([2, 4, 1])\n2\n>>> recherche_min([5, 3, 2, 2, 4])\n2\n
def recherche_min(tab):\n indice_min = 0\n for i in range(len(tab)):\n if tab[i] < tab[indice_min]:\n indice_min = i\n return indice_min\n
\u00c9crire une fonction `recherche_min` qui prend en param\u00e8tre un tableau de nombres non\ntri\u00e9 `tab`, et qui renvoie l'indice de la premi\u00e8re occurrence du minimum de ce tableau. Les\ntableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.\n\nExemples :\n```python\n>>> recherche_min([5])\n0\n>>> recherche_min([2, 4, 1])\n2\n>>> recherche_min([5, 3, 2, 2, 4])\n2\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-272","title":"Exercice 27.2","text":"Exercice 27.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re la fonction separe
ci-dessous qui prend en argument un tableau tab
dont les \u00e9l\u00e9ments sont des 0
et des 1
et qui s\u00e9pare les 0
des 1
en pla\u00e7ant les 0
en d\u00e9but de tableau et les 1
\u00e0 la suite.
def separe(tab):\n gauche = 0\n droite = ...\n while gauche < droite :\n if tab[gauche] == 0 :\n gauche = ...\n else :\n tab[gauche], tab[droite] = ...\n droite = ...\n return tab\n
Compl\u00e9ter la fonction separe
ci-dessus.
Exemples :
>>> separe([1, 0, 1, 0, 1, 0, 1, 0])\n[0, 0, 0, 0, 1, 1, 1, 1]\n>>> separe([1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0])\n[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\n
Description d\u2019\u00e9tapes effectu\u00e9es par la fonction separe sur le tableau ci-dessous : tab = [1, 0, 1, 0, 1, 0, 1, 0]
Etape 1 : on regarde la premi\u00e8re case, qui contient un 1 : ce 1 va aller dans la seconde partie du tableau final et on l\u2019\u00e9change avec la derni\u00e8re case. Il est \u00e0 pr\u00e9sent bien positionn\u00e9 : on ne prend plus la derni\u00e8re case en compte. tab = [0, 0, 1, 0, 1, 0, 1, 1]
Etape 2 : on regarde \u00e0 nouveau la premi\u00e8re case, qui contient maintenant un 0 : ce 0 va aller dans la premi\u00e8re partie du tableau final et est bien positionn\u00e9 : on ne prend plus la premi\u00e8re case en compte. tab = [0, 0, 1, 0, 1, 0, 1, 1]
Etape 3 : on regarde la seconde case, qui contient un 0 : ce 0 va aller dans la premi\u00e8re partie du tableau final et est bien positionn\u00e9 : on ne prend plus la seconde case en compte. tab = [0, 0, 1, 0, 1, 0, 1, 1]
Etape 4 : on regarde la troisi\u00e8me case, qui contient un 1 : ce 1 va aller dans la seconde partie du tableau final et on l\u2019\u00e9change avec l\u2019avant-derni\u00e8re case. Il est \u00e0 pr\u00e9sent bien positionn\u00e9 : on ne prend plus l\u2019avant-derni\u00e8re case en compte. tab = [0, 0, 1, 0, 1, 0, 1, 1]
Et ainsi de suite...
tab = [0, 0, 0, 0, 1, 1, 1, 1]
Compl\u00e9ter la fonction separe
pr\u00e9sent\u00e9e \u00e0 la page pr\u00e9c\u00e9dente
def separe(tab):\n gauche = 0\ndroite = len(tab) - 1\nwhile gauche < droite :\n if tab[gauche] == 0 :\ngauche = gauche + 1\nelse :\ntab[gauche], tab[droite] = tab[droite], tab[gauche]\ndroite = droite - 1\nreturn tab\n
On consid\u00e8re la fonction `separe` ci-dessous qui prend en argument un tableau `tab` dont\nles \u00e9l\u00e9ments sont des `0` et des `1` et qui s\u00e9pare les `0` des `1` en pla\u00e7ant les `0` en d\u00e9but de\ntableau et les `1` \u00e0 la suite.\n\n```python linenums='1'\ndef separe(tab):\n gauche = 0\n droite = ...\n while gauche < droite :\n if tab[gauche] == 0 :\n gauche = ...\n else :\n tab[gauche], tab[droite] = ...\n droite = ...\n return tab\n
Compl\u00e9ter la fonction separe
ci-dessus.
Exemples :
>>> separe([1, 0, 1, 0, 1, 0, 1, 0])\n[0, 0, 0, 0, 1, 1, 1, 1]\n>>> separe([1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0])\n[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\n
Description d\u2019\u00e9tapes effectu\u00e9es par la fonction separe sur le tableau ci-dessous : tab = [1, 0, 1, 0, 1, 0, 1, 0]
Etape 1 : on regarde la premi\u00e8re case, qui contient un 1 : ce 1 va aller dans la seconde partie du tableau final et on l\u2019\u00e9change avec la derni\u00e8re case. Il est \u00e0 pr\u00e9sent bien positionn\u00e9 : on ne prend plus la derni\u00e8re case en compte. tab = [0, 0, 1, 0, 1, 0, 1, 1]
Etape 2 : on regarde \u00e0 nouveau la premi\u00e8re case, qui contient maintenant un 0 : ce 0 va aller dans la premi\u00e8re partie du tableau final et est bien positionn\u00e9 : on ne prend plus la premi\u00e8re case en compte. tab = [0, 0, 1, 0, 1, 0, 1, 1]
Etape 3 : on regarde la seconde case, qui contient un 0 : ce 0 va aller dans la premi\u00e8re partie du tableau final et est bien positionn\u00e9 : on ne prend plus la seconde case en compte. tab = [0, 0, 1, 0, 1, 0, 1, 1]
Etape 4 : on regarde la troisi\u00e8me case, qui contient un 1 : ce 1 va aller dans la seconde partie du tableau final et on l\u2019\u00e9change avec l\u2019avant-derni\u00e8re case. Il est \u00e0 pr\u00e9sent bien positionn\u00e9 : on ne prend plus l\u2019avant-derni\u00e8re case en compte. tab = [0, 0, 1, 0, 1, 0, 1, 1]
Et ainsi de suite...
tab = [0, 0, 0, 0, 1, 1, 1, 1]
Compl\u00e9ter la fonction separe
pr\u00e9sent\u00e9e \u00e0 la page pr\u00e9c\u00e9dente ```
Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-28","title":"\u25b6 Sujet 28","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-281","title":"Exercice 28.1","text":"Exercice 28.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction qui prend en param\u00e8tre un tableau d'entiers non vide et qui renvoie la moyenne de ces entiers. La fonction est sp\u00e9cifi\u00e9e ci-apr\u00e8s et doit passer les assertions fournies.
def moyenne (tab):\n'''\n moyenne(list) -> float\n Entr\u00e9e : un tableau non vide d'entiers\n Sortie : nombre de type float\n Correspondant \u00e0 la moyenne des valeurs pr\u00e9sentes dans le\n tableau\n '''\n\nassert moyenne([1]) == 1\nassert moyenne([1, 2, 3, 4, 5, 6, 7]) == 4\nassert moyenne([1, 2]) == 1.5\n
def moyenne(tab):\n'''\n moyenne(list) -> float\n Entr\u00e9e : un tableau non vide d'entiers\n Sortie : nombre de type float\n Correspondant \u00e0 la moyenne des valeurs pr\u00e9sentes dans le\n tableau\n '''\n somme = 0\n for elt in tab:\n somme += elt\n return somme / len(tab)\n
\u00c9crire une fonction qui prend en param\u00e8tre un tableau d'entiers non vide et qui renvoie la\nmoyenne de ces entiers. La fonction est sp\u00e9cifi\u00e9e ci-apr\u00e8s et doit passer les assertions\nfournies.\n```python\ndef moyenne (tab):\n '''\n moyenne(list) -> float\n Entr\u00e9e : un tableau non vide d'entiers\n Sortie : nombre de type float\n Correspondant \u00e0 la moyenne des valeurs pr\u00e9sentes dans le\n tableau\n '''\n\nassert moyenne([1]) == 1\nassert moyenne([1, 2, 3, 4, 5, 6, 7]) == 4\nassert moyenne([1, 2]) == 1.5\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-282","title":"Exercice 28.2","text":"Exercice 28.2
\u00c9nonc\u00e9CorrectionSources MarkdownLe but de l'exercice est de compl\u00e9ter une fonction qui d\u00e9termine si une valeur est pr\u00e9sente dans un tableau de valeurs tri\u00e9es dans l'ordre croissant.
L'algorithme traite le cas du tableau vide et il est \u00e9crit pour que la recherche dichotomique ne se fasse que dans le cas o\u00f9 la valeur est comprise entre les valeurs extr\u00eames du tableau.
On distingue les trois cas qui renvoient False
en renvoyant False, 1
, False, 2
et False, 3
.
Compl\u00e9ter l'algorithme de dichotomie donn\u00e9 ci-apr\u00e8s.
def dichotomie(tab, x):\n\"\"\"\n tab : tableau tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n # cas du tableau vide\n if ...:\n return False, 1\n\n # cas o\u00f9 x n'est pas compris entre les valeurs extr\u00eames\n if (x < tab[0]) or ...:\n return False, 2\n\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\n(False, 3)\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],1)\n(False, 2)\n>>> dichotomie([],28)\n(False, 1)\n
def dichotomie(tab, x):\n\"\"\"\n tab : tableau tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n # cas du tableau vide\nif tab == []:\nreturn False, 1\n\n # cas o\u00f9 x n'est pas compris entre les valeurs extr\u00eames\nif (x < tab[0]) or (x > tab[-1]):\nreturn False, 2\n\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\nm = (debut + fin) // 2\nif x == tab[m]:\nreturn True\nif x > tab[m]:\n debut = m + 1\n else:\nfin = m - 1\nreturn False, 3\n
Le but de l'exercice est de compl\u00e9ter une fonction qui d\u00e9termine si une valeur est pr\u00e9sente\ndans un tableau de valeurs tri\u00e9es dans l'ordre croissant.\n\nL'algorithme traite le cas du tableau vide et il est \u00e9crit pour que la recherche dichotomique ne se fasse que dans le cas o\u00f9\nla valeur est comprise entre les valeurs extr\u00eames du tableau.\n\nOn distingue les trois cas qui renvoient `False` en renvoyant `False, 1` , `False, 2` et\n`False, 3`.\n\nCompl\u00e9ter l'algorithme de dichotomie donn\u00e9 ci-apr\u00e8s.\n\n```python linenums='1'\ndef dichotomie(tab, x):\n \"\"\"\n tab : tableau tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n # cas du tableau vide\n if ...:\n return False, 1\n\n # cas o\u00f9 x n'est pas compris entre les valeurs extr\u00eames\n if (x < tab[0]) or ...:\n return False, 2\n\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\n(False, 3)\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],1)\n(False, 2)\n>>> dichotomie([],28)\n(False, 1)\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-29","title":"\u25b6 Sujet 29","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-291","title":"Exercice 29.1","text":"Exercice 29.1
\u00c9nonc\u00e9CorrectionSource MarkdownUn arbre binaire est impl\u00e9ment\u00e9 par la classe Arbre
donn\u00e9e ci-dessous. Les attributs fg
et fd
prennent pour valeurs des instances de la classe Arbre
ou None
.
class Arbre:\n def __init__(self, etiquette):\n self.v = etiquette\n self.fg = None\n self.fd = None\n
L\u2019arbre ci-dessus sera donc impl\u00e9ment\u00e9 de la mani\u00e8re suivante :
a = Arbre(1)\na.fg = Arbre(4)\na.fd = Arbre(0)\na.fd.fd = Arbre(7)\n
\u00c9crire une fonction r\u00e9cursive taille
prenant en param\u00e8tre une instance a
de la classe Arbre
et qui renvoie la taille de l\u2019arbre que cette instance impl\u00e9mente.
\u00c9crire de m\u00eame une fonction r\u00e9cursive hauteur
prenant en param\u00e8tre une instance a
de la classe Arbre
et qui renvoie la hauteur de l\u2019arbre que cette instance impl\u00e9mente.
Si un arbre a un seul n\u0153ud, sa taille et sa hauteur sont \u00e9gales \u00e0 1. S\u2019il est vide, sa taille et sa hauteur sont \u00e9gales \u00e0 0.
Tester les deux fonctions sur l\u2019arbre repr\u00e9sent\u00e9 ci-dessous :
def taille(a):\n if a is None:\n return 0\n else:\n return 1 + taille(a.fg) + taille(a.fd)\n\ndef hauteur(a):\n if a is None:\n return 0\n else:\n return 1 + max(hauteur(a.fg), hauteur(a.fd))\n
Tests :
a = Arbre(0)\na.fg = Arbre(1)\na.fd = Arbre(2)\na.fg.fg = Arbre(3)\na.fd.fg = Arbre(4)\na.fd.fd = Arbre(5)\na.fd.fg.fd = Arbre(6)\n
>>> taille(a)\n7\n>>> hauteur(a)\n4\n
Un arbre binaire est impl\u00e9ment\u00e9 par la classe `Arbre` donn\u00e9e ci-dessous.\nLes attributs `fg` et `fd` prennent pour valeurs des instances de la classe `Arbre` ou `None`.\n\n```python\nclass Arbre:\n def __init__(self, etiquette):\n self.v = etiquette\n self.fg = None\n self.fd = None\n```\n\n![image](data2023/29_arbre1.png){: .center}\n\nL\u2019arbre ci-dessus sera donc impl\u00e9ment\u00e9 de la mani\u00e8re suivante :\n```python\na = Arbre(1)\na.fg = Arbre(4)\na.fd = Arbre(0)\na.fd.fd = Arbre(7)\n```\n\n\u00c9crire une fonction r\u00e9cursive `taille` prenant en param\u00e8tre une instance `a` de la classe\n`Arbre` et qui renvoie la taille de l\u2019arbre que cette instance impl\u00e9mente.\n\n\u00c9crire de m\u00eame une fonction r\u00e9cursive `hauteur` prenant en param\u00e8tre une instance `a`\nde la classe `Arbre` et qui renvoie la hauteur de l\u2019arbre que cette instance impl\u00e9mente.\n\nSi un arbre a un seul n\u0153ud, sa taille et sa hauteur sont \u00e9gales \u00e0 1.\nS\u2019il est vide, sa taille et sa hauteur sont \u00e9gales \u00e0 0.\n\nTester les deux fonctions sur l\u2019arbre repr\u00e9sent\u00e9 ci-dessous :\n\n![image](data2023/29_arbre2.png){: .center}\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-292","title":"Exercice 29.2","text":"Exercice 29.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa m\u00e9thode insert
de la classe list
permet d\u2019ins\u00e9rer un \u00e9l\u00e9ment dans une liste \u00e0 un indice
donn\u00e9.
Le but de cet exercice est, sans utiliser cette m\u00e9thode, d\u2019\u00e9crire une fonction ajoute
r\u00e9alisant cette insertion en produisant une nouvelle liste.
Cette fonction ajoute
prend en param\u00e8tres trois variables indice
, element
et liste
et renvoie une liste L
dans laquelle les \u00e9l\u00e9ments sont ceux de la liste liste
avec, en plus, l\u2019\u00e9l\u00e9ment element
\u00e0 l\u2019indice indice
. On consid\u00e8re que les variables indice
et element
sont des entiers positifs et que les \u00e9l\u00e9ments de liste
sont \u00e9galement des entiers positifs. Les \u00e9l\u00e9ments de la liste liste
, dont les indices sont sup\u00e9rieurs ou \u00e9gaux \u00e0 indice
apparaissent d\u00e9cal\u00e9s vers la droite dans la liste L
. Si indice
est sup\u00e9rieur ou \u00e9gal au nombre d\u2019\u00e9l\u00e9ments de la liste liste
, l\u2019\u00e9l\u00e9ment element est ajout\u00e9 dans L
apr\u00e8s tous les \u00e9l\u00e9ments de la liste liste
.
Exemple :
>>> ajoute(1, 4, [7, 8, 9])\n[7, 4, 8, 9]\n>>> ajoute(3, 4, [7, 8, 9])\n[7, 8, 9, 4]\n>>> ajoute(4, 4, [7, 8, 9])\n[7, 8, 9, 4]\n
Compl\u00e9ter et tester le code ci-dessous :
def ajoute(indice, element, liste):\n nbre_elts = len(liste)\n L = [0 for i in range(nbre_elts + 1)]\n if ...:\n for i in range(indice):\n L[i] = ...\n L[...] = ...\n for i in range(indice + 1, nbre_elts + 1):\n L[i] = ...\n else:\n for i in range(nbre_elts):\n L[i] = ...\n L[...] = ...\n return L\n
def ajoute(indice, element, liste):\n nbre_elts = len(liste)\n L = [0 for i in range(nbre_elts + 1)]\nif indice < nbre_elts:\nfor i in range(indice):\nL[i] = liste[i]\nL[indice] = element\nfor i in range(indice + 1, nbre_elts + 1):\nL[i] = liste[i-1]\nelse:\n for i in range(nbre_elts):\nL[i] = liste[i]\nL[nbre_elts] = element \nreturn L\n
La m\u00e9thode `insert` de la classe `list` permet d\u2019ins\u00e9rer un \u00e9l\u00e9ment dans une liste \u00e0 un\n`indice` donn\u00e9.\n\nLe but de cet exercice est, *sans utiliser cette m\u00e9thode*, d\u2019\u00e9crire une fonction `ajoute`\nr\u00e9alisant cette insertion en produisant une nouvelle liste.\n\nCette fonction `ajoute` prend en param\u00e8tres trois variables `indice`, `element` et `liste`\net renvoie une liste `L` dans laquelle les \u00e9l\u00e9ments sont ceux de la liste `liste` avec, en\nplus, l\u2019\u00e9l\u00e9ment `element` \u00e0 l\u2019indice `indice`. \nOn consid\u00e8re que les variables `indice` et `element` sont des entiers positifs et que les\n\u00e9l\u00e9ments de `liste` sont \u00e9galement des entiers positifs. \nLes \u00e9l\u00e9ments de la liste `liste`, dont les indices sont sup\u00e9rieurs ou \u00e9gaux \u00e0 `indice`\napparaissent d\u00e9cal\u00e9s vers la droite dans la liste `L`. \nSi `indice` est sup\u00e9rieur ou \u00e9gal au nombre d\u2019\u00e9l\u00e9ments de la liste `liste`, l\u2019\u00e9l\u00e9ment\nelement est ajout\u00e9 dans `L` apr\u00e8s tous les \u00e9l\u00e9ments de la liste `liste`.\n\nExemple :\n```python\n>>> ajoute(1, 4, [7, 8, 9])\n[7, 4, 8, 9]\n>>> ajoute(3, 4, [7, 8, 9])\n[7, 8, 9, 4]\n>>> ajoute(4, 4, [7, 8, 9])\n[7, 8, 9, 4]\n
Compl\u00e9ter et tester le code ci-dessous :
def ajoute(indice, element, liste):\n nbre_elts = len(liste)\n L = [0 for i in range(nbre_elts + 1)]\n if ...:\n for i in range(indice):\n L[i] = ...\n L[...] = ...\n for i in range(indice + 1, nbre_elts + 1):\n L[i] = ...\n else:\n for i in range(nbre_elts):\n L[i] = ...\n L[...] = ...\n return L\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-30","title":"\u25b6 Sujet 30","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-301","title":"Exercice 30.1","text":"Exercice 30.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction moyenne
qui prend en param\u00e8tre un tableau non vide de nombres flottants et qui renvoie la moyenne des valeurs du tableau. Les tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.
Exemples :
>>> moyenne([1.0])\n1.0\n>>> moyenne([1.0, 2.0, 4.0])\n2.3333333333333335\n
def moyenne(tab):\n somme = 0\n for val in tab:\n somme += val\n return somme / len(tab)\n
\u00c9crire une fonction `moyenne` qui prend en param\u00e8tre un tableau non vide de nombres\nflottants et qui renvoie la moyenne des valeurs du tableau. Les tableaux seront\nrepr\u00e9sent\u00e9s sous forme de liste Python.\n\nExemples :\n```python\n>>> moyenne([1.0])\n1.0\n>>> moyenne([1.0, 2.0, 4.0])\n2.3333333333333335\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-302","title":"Exercice 30.2","text":"Exercice 30.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re la fonction binaire
ci-dessous qui prend en param\u00e8tre un entier positif a
en \u00e9criture d\u00e9cimale et qui renvoie son \u00e9criture binaire sous la forme d'une chaine de caract\u00e8res.
L\u2019algorithme utilise la m\u00e9thode des divisions euclidiennes successives comme l\u2019illustre l\u2019exemple ci-apr\u00e8s.
def binaire(a):\n bin_a = ...\n a = a // 2\n while a ... :\n bin_a = ... + bin_a\n a = ...\n return bin_a\n
Compl\u00e9ter le code de la fonction binaire
. Exemples :
>>> binaire(83)\n'1010011'\n>>> binaire(127)\n'1111111'\n>>> binaire(0)\n'0'\n
def binaire(a):\nbin_a = str(a%2)\na = a // 2\nwhile a != 0 :\nbin_a = str(a%2) + bin_a\na = a // 2\nreturn bin_a\n
On consid\u00e8re la fonction `binaire` ci-dessous qui prend en param\u00e8tre un entier positif `a` en \u00e9criture d\u00e9cimale et qui renvoie son \u00e9criture binaire sous la forme d'une chaine de caract\u00e8res.\n\nL\u2019algorithme utilise la m\u00e9thode des divisions euclidiennes successives comme l\u2019illustre\nl\u2019exemple ci-apr\u00e8s.\n\n![image](data2023/30_divisions.png){: .center}\n\n\n\n```python linenums='1'\ndef binaire(a):\n bin_a = ...\n a = a // 2\n while a ... :\n bin_a = ... + bin_a\n a = ...\n return bin_a\n
Compl\u00e9ter le code de la fonction binaire
. Exemples :
>>> binaire(83)\n'1010011'\n>>> binaire(127)\n'1111111'\n>>> binaire(0)\n'0'\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-31","title":"\u25b6 Sujet 31","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-311","title":"Exercice 31.1","text":"Exercice 31.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction Python appel\u00e9e nb_repetitions
qui prend en param\u00e8tres un \u00e9l\u00e9ment elt
et une liste tab
et renvoie le nombre de fois o\u00f9 l\u2019\u00e9l\u00e9ment appara\u00eet dans la liste.
Exemples :
>>> nb_repetitions(5, [2, 5, 3, 5, 6, 9, 5])\n3\n>>> nb_repetitions('A', ['B', 'A', 'B', 'A', 'R'])\n2\n>>> nb_repetitions(12, [1, '!', 7, 21, 36, 44])\n0\n
def nb_repetitions(elt, tab):\n nb = 0\n for element in tab:\n if element == elt:\n nb += 1\n return nb\n
\u00c9crire une fonction Python appel\u00e9e `nb_repetitions` qui prend en param\u00e8tres un\n\u00e9l\u00e9ment `elt` et une liste `tab` et renvoie le nombre de fois o\u00f9 l\u2019\u00e9l\u00e9ment appara\u00eet dans la\nliste.\n\nExemples :\n```python\n>>> nb_repetitions(5, [2, 5, 3, 5, 6, 9, 5])\n3\n>>> nb_repetitions('A', ['B', 'A', 'B', 'A', 'R'])\n2\n>>> nb_repetitions(12, [1, '!', 7, 21, 36, 44])\n0\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-312","title":"Exercice 31.2","text":"Exercice 31.2
\u00c9nonc\u00e9CorrectionSources MarkdownPour rappel, la conversion d\u2019un nombre entier positif en binaire peut s\u2019effectuer \u00e0 l\u2019aide des divisions successives comme illustr\u00e9 ici :
Voici une fonction Python bas\u00e9e sur la m\u00e9thode des divisions successives permettant de convertir un nombre entier positif en binaire :
def binaire(a):\n bin_a = str(...)\n a = a // 2\n while a ... :\n bin_a = ...(a%2) + ...\n a = ...\n return bin_a\n
Compl\u00e9ter la fonction binaire
. Exemples :
>>> binaire(0)\n'0'\n>>> binaire(77)\n'1001101'\n
def binaire(a):\nbin_a = str(a%2)\na = a // 2\nwhile a != 0 :\nbin_a = str(a%2) + bin_a\na = a // 2\nreturn bin_a\n
Pour rappel, la conversion d\u2019un nombre entier positif en binaire peut s\u2019effectuer \u00e0 l\u2019aide\ndes divisions successives comme illustr\u00e9 ici :\n\n![image](data2023/31_divisions.png){: .center}\n\nVoici une fonction Python bas\u00e9e sur la m\u00e9thode des divisions successives permettant de\nconvertir un nombre entier positif en binaire :\n\n```python linenums='1'\ndef binaire(a):\n bin_a = str(...)\n a = a // 2\n while a ... :\n bin_a = ...(a%2) + ...\n a = ...\n return bin_a\n
Compl\u00e9ter la fonction binaire
. Exemples :
>>> binaire(0)\n'0'\n>>> binaire(77)\n'1001101'\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-32","title":"\u25b6 Sujet 32","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-321","title":"Exercice 32.1","text":"Exercice 32.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction min_et_max
qui prend en param\u00e8tre un tableau de nombres tab
non vide, et qui renvoie la plus petite et la plus grande valeur du tableau sous la forme d\u2019un dictionnaire \u00e0 deux cl\u00e9s min
et max
.
Les tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.
L\u2019utilisation des fonctions natives min
, max
et sorted
, ainsi que la m\u00e9thode sort
n\u2019est pas autoris\u00e9e.
Exemples :
>>> min_et_max([0, 1, 4, 2, -2, 9, 3, 1, 7, 1])\n{'min': -2, 'max': 9}\n>>> min_et_max([0, 1, 2, 3])\n{'min': 0, 'max': 3}\n>>> min_et_max([3])\n{'min': 3, 'max': 3}\n>>> min_et_max([1, 3, 2, 1, 3])\n{'min': 1, 'max': 3}\n>>> min_et_max([-1, -1, -1, -1, -1])\n{'min': -1, 'max': -1}\n
def min_et_max(tab):\n d = {}\n d['min'] = tab[0]\n d['max'] = tab[0]\n for val in tab:\n if val < d['min']:\n d['min'] = val\n if val > d['max']:\n d['max'] = val\n return d\n
\u00c9crire une fonction `min_et_max` qui prend en param\u00e8tre un tableau de nombres `tab` non vide, et qui renvoie la plus petite et la plus grande valeur du tableau sous la\nforme d\u2019un dictionnaire \u00e0 deux cl\u00e9s `min` et `max`.\n\nLes tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.\n\nL\u2019utilisation des fonctions natives `min`, `max` et `sorted`, ainsi que la m\u00e9thode `sort` n\u2019est pas\nautoris\u00e9e.\n\nExemples :\n\n```python\n>>> min_et_max([0, 1, 4, 2, -2, 9, 3, 1, 7, 1])\n{'min': -2, 'max': 9}\n>>> min_et_max([0, 1, 2, 3])\n{'min': 0, 'max': 3}\n>>> min_et_max([3])\n{'min': 3, 'max': 3}\n>>> min_et_max([1, 3, 2, 1, 3])\n{'min': 1, 'max': 3}\n>>> min_et_max([-1, -1, -1, -1, -1])\n{'min': -1, 'max': -1}\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-322","title":"Exercice 32.2","text":"Exercice 32.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn dispose d\u2019une classe Carte
permettant de cr\u00e9er des objets mod\u00e9lisant des cartes \u00e0 jouer.
Compl\u00e9ter la classe Paquet_de_cartes
suivante en respectant les sp\u00e9cifications donn\u00e9es dans les cha\u00eenes de documentation.
Ajouter une assertion dans la m\u00e9thode get_carte
afin de v\u00e9rifier que le param\u00e8tre pos
est correct.
class Carte:\n def __init__(self, c, v):\n\"\"\" Initialise les attributs couleur (entre 1 et 4), et valeur (entre 1 et 13). \"\"\"\n self.couleur = c\n self.valeur = v\n\n def get_valeur(self):\n\"\"\" Renvoie la valeur de la carte : As, 2, ..., 10, Valet, Dame, Roi \"\"\"\n valeurs = ['As','2', '3', '4', '5', '6', '7', '8', '9', '10', 'Valet', 'Dame', 'Roi']\n return valeurs[self.valeur - 1]\n\n def get_couleur(self):\n\"\"\" Renvoie la couleur de la carte (parmi pique, coeur, carreau, tr\u00e8fle). \"\"\"\n couleurs = ['pique', 'coeur', 'carreau', 'tr\u00e8fle']\n return couleurs[self.couleur - 1]\n\nclass Paquet_de_cartes:\n def __init__(self):\n\"\"\" Initialise l'attribut contenu avec une liste des 52 objets Carte possibles\n rang\u00e9s par valeurs croissantes en commen\u00e7ant par pique, puis coeur,\n carreau et tr\u00e9fle. \"\"\"\n # A compl\u00e9ter\n\n def get_carte(self, pos):\n\"\"\" Renvoie la carte qui se trouve \u00e0 la position pos (entier compris entre 0 et 51). \"\"\"\n # A compl\u00e9ter\n
Exemple :
Exemple :\n>>> jeu = Paquet_de_cartes()\n>>> carte1 = jeu.get_carte(20)\n>>> print(carte1.get_valeur() + \" de \" + carte1.get_couleur())\n8 de coeur\n>>> carte2 = jeu.get_carte(0)\n>>> print(carte2.get_valeur() + \" de \" + carte2.get_couleur())\nAs de pique\n>>> carte3 = jeu.get_carte(52)\nAssertionError : param\u00e8tre pos invalide\n
class Carte:\n def __init__(self, c, v):\n\"\"\" Initialise les attributs couleur (entre 1 et 4), et valeur (entre 1 et 13). \"\"\"\n self.couleur = c\n self.valeur = v\n\n def get_valeur(self):\n\"\"\" Renvoie la valeur de la carte : As, 2, ..., 10, Valet, Dame, Roi \"\"\"\n valeurs = ['As','2', '3', '4', '5', '6', '7', '8', '9', '10', 'Valet', 'Dame', 'Roi']\n return valeurs[self.valeur - 1]\n\n def get_couleur(self):\n\"\"\" Renvoie la couleur de la carte (parmi pique, coeur, carreau, tr\u00e8fle). \"\"\"\n couleurs = ['pique', 'coeur', 'carreau', 'tr\u00e8fle']\n return couleurs[self.couleur - 1]\n\nclass Paquet_de_cartes:\n def __init__(self):\n\"\"\" Initialise l'attribut contenu avec une liste des 52 objets Carte possibles\n rang\u00e9s par valeurs croissantes en commen\u00e7ant par pique, puis coeur,\n carreau et tr\u00e9fle. \"\"\"\nself.contenu = [Carte(c, v) for c in range(1, 5) for v in range(1, 14)] \ndef get_carte(self, pos):\n\"\"\" Renvoie la carte qui se trouve \u00e0 la position pos (entier compris entre 0 et 51). \"\"\"\nassert 0 <= pos <= 51, 'param\u00e8tre pos invalide'\nreturn self.contenu[pos]\n
On dispose d\u2019une classe `Carte` permettant de cr\u00e9er des objets mod\u00e9lisant des cartes \u00e0\njouer.\n\nCompl\u00e9ter la classe `Paquet_de_cartes` suivante en respectant les sp\u00e9cifications\ndonn\u00e9es dans les cha\u00eenes de documentation.\n\nAjouter une assertion dans la m\u00e9thode `get_carte` afin de v\u00e9rifier que le param\u00e8tre `pos`\nest correct.\n\n```python linenums='1'\nclass Carte:\n def __init__(self, c, v):\n \"\"\" Initialise les attributs couleur (entre 1 et 4), et valeur (entre 1 et 13). \"\"\"\n self.couleur = c\n self.valeur = v\n\n def get_valeur(self):\n \"\"\" Renvoie la valeur de la carte : As, 2, ..., 10, Valet, Dame, Roi \"\"\"\n valeurs = ['As','2', '3', '4', '5', '6', '7', '8', '9', '10', 'Valet', 'Dame', 'Roi']\n return valeurs[self.valeur - 1]\n\n def get_couleur(self):\n \"\"\" Renvoie la couleur de la carte (parmi pique, coeur, carreau, tr\u00e8fle). \"\"\"\n couleurs = ['pique', 'coeur', 'carreau', 'tr\u00e8fle']\n return couleurs[self.couleur - 1]\n\nclass Paquet_de_cartes:\n def __init__(self):\n \"\"\" Initialise l'attribut contenu avec une liste des 52 objets Carte possibles\n rang\u00e9s par valeurs croissantes en commen\u00e7ant par pique, puis coeur,\n carreau et tr\u00e9fle. \"\"\"\n # A compl\u00e9ter\n\n def get_carte(self, pos):\n \"\"\" Renvoie la carte qui se trouve \u00e0 la position pos (entier compris entre 0 et 51). \"\"\"\n # A compl\u00e9ter\n
Exemple :
Exemple :\n>>> jeu = Paquet_de_cartes()\n>>> carte1 = jeu.get_carte(20)\n>>> print(carte1.get_valeur() + \" de \" + carte1.get_couleur())\n8 de coeur\n>>> carte2 = jeu.get_carte(0)\n>>> print(carte2.get_valeur() + \" de \" + carte2.get_couleur())\nAs de pique\n>>> carte3 = jeu.get_carte(52)\nAssertionError : param\u00e8tre pos invalide\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-33","title":"\u25b6 Sujet 33","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-331","title":"Exercice 33.1","text":"Exercice 33.1
\u00c9nonc\u00e9CorrectionSource MarkdownDans cet exercice, un arbre binaire de caract\u00e8res est stock\u00e9 sous la forme d\u2019un dictionnaire o\u00f9 les clefs sont les caract\u00e8res des n\u0153uds de l\u2019arbre et les valeurs, pour chaque clef, la liste des caract\u00e8res des fils gauche et droit du n\u0153ud.
Par exemple, l\u2019arbre
est stock\u00e9 dans
a = {'F':['B','G'], 'B':['A','D'], 'A':['',''], 'D':['C','E'], \\\n'C':['',''], 'E':['',''], 'G':['','I'], 'I':['','H'], \\\n'H':['','']}\n
\u00c9crire une fonction r\u00e9cursive taille
prenant en param\u00e8tres un arbre binaire arbre
sous la forme d\u2019un dictionnaire et un caract\u00e8re lettre
qui est la valeur du sommet de l\u2019arbre, et qui renvoie la taille de l\u2019arbre \u00e0 savoir le nombre total de n\u0153uds.
On observe que, par exemple, arbre[lettre][0]
, respectivement arbre[lettre][1]
, permet d\u2019atteindre la cl\u00e9 du sous-arbre gauche, respectivement droit, de l\u2019arbre arbre
de sommet lettre
.
Exemple :
>>> taille(a, \u2019F\u2019)\n9\n
a = {'F':['B','G'], 'B':['A','D'], 'A':['',''], 'D':['C','E'], 'C':['',''], 'E':['',''], 'G':['','I'], 'I':['','H'], 'H':['','']}\n\ndef taille(arbre, lettre):\n fils_gauche = arbre[lettre][0]\n fils_droit = arbre[lettre][1]\n\n if fils_gauche != '' and fils_droit != '':\n return 1 + taille(arbre, fils_gauche) + taille(arbre, fils_droit)\n\n if fils_gauche != '' and fils_droit == '':\n return 1 + taille(arbre, fils_gauche)\n\n if fils_gauche == '' and fils_droit != '':\n return 1 + taille(arbre, fils_droit)\n\n else:\n return 1\n
ou plus simplement :
def taille(arbre, lettre):\n if lettre == '':\n return 0\n return 1 + taille(arbre, arbre[lettre][0]) + taille(arbre, arbre[lettre][1])\n
Dans cet exercice, un arbre binaire de caract\u00e8res est stock\u00e9 sous la forme d\u2019un\ndictionnaire o\u00f9 les clefs sont les caract\u00e8res des n\u0153uds de l\u2019arbre et les valeurs, pour\nchaque clef, la liste des caract\u00e8res des fils gauche et droit du n\u0153ud.\n\nPar exemple, l\u2019arbre\n\n![image](data2023/33_arbre.png){: .center}\n\nest stock\u00e9 dans\n\n```python\na = {'F':['B','G'], 'B':['A','D'], 'A':['',''], 'D':['C','E'], \\\n'C':['',''], 'E':['',''], 'G':['','I'], 'I':['','H'], \\\n'H':['','']}\n```\n\n\u00c9crire une fonction r\u00e9cursive `taille` prenant en param\u00e8tres un arbre binaire `arbre`\nsous la forme d\u2019un dictionnaire et un caract\u00e8re `lettre` qui est la valeur du sommet de\nl\u2019arbre, et qui renvoie la taille de l\u2019arbre \u00e0 savoir le nombre total de n\u0153uds.\n\nOn observe que, par exemple, `arbre[lettre][0]`, respectivement\n`arbre[lettre][1]`, permet d\u2019atteindre la cl\u00e9 du sous-arbre gauche, respectivement\ndroit, de l\u2019arbre `arbre` de sommet `lettre`.\n\nExemple :\n```python\n>>> taille(a, \u2019F\u2019)\n9\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-332","title":"Exercice 33.2","text":"Exercice 33.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re l'algorithme de tri de tableau suivant : \u00e0 chaque \u00e9tape, on parcourt le sous- tableau des \u00e9l\u00e9ments non rang\u00e9s et on place le plus petit \u00e9l\u00e9ment en premi\u00e8re position de ce sous-tableau.
Exemple avec le tableau : t = [41, 55, 21, 18, 12, 6, 25]
\u00c9tape 1 : on parcourt tous les \u00e9l\u00e9ments du tableau, on permute le plus petit \u00e9l\u00e9ment avec le premier. Le tableau devient t = [6, 55, 21, 18, 12, 41, 25]
\u00c9tape 2 : on parcourt tous les \u00e9l\u00e9ments sauf le premier, on permute le plus petit \u00e9l\u00e9ment trouv\u00e9 avec le second. Le tableau devient : t = [6, 12, 21, 18, 55, 41, 25]
Et ainsi de suite.
La code de la fonction tri_selection
qui impl\u00e9mente cet algorithme est donn\u00e9 ci- dessous.
def tri_selection(tab):\n N = len(tab)\n for k in range(...):\n imin = ...\n for i in range(... , N):\n if tab[i] < ... :\n imin = i\n ... , tab[imin] = tab[imin] , ...\n
Compl\u00e9ter le code de cette fonction de fa\u00e7on \u00e0 obtenir :
>>> liste = [41, 55, 21, 18, 12, 6, 25]\n>>> tri_selection(liste)\n>>> liste\n[6, 12, 18, 21, 25, 41, 55]\n
On rappelle que l'instruction a, b = b, a
\u00e9change les contenus de a
et de b
.
def tri_selection(tab):\n N = len(tab)\nfor k in range(N):\nimin = k\nfor i in range(k+1, N):\nif tab[i] < tab[imin] :\nimin = i\ntab[k] , tab[imin] = tab[imin] , tab[k]\n
On consid\u00e8re l'algorithme de tri de tableau suivant : \u00e0 chaque \u00e9tape, on parcourt le sous-\ntableau des \u00e9l\u00e9ments non rang\u00e9s et on place le plus petit \u00e9l\u00e9ment en premi\u00e8re position de\nce sous-tableau.\n\nExemple avec le tableau : ```t = [41, 55, 21, 18, 12, 6, 25]``` \n\n- \u00c9tape 1 : on parcourt tous les \u00e9l\u00e9ments du tableau, on permute le plus petit \u00e9l\u00e9ment avec\nle premier. Le tableau devient `t = [6, 55, 21, 18, 12, 41, 25]`\n\n- \u00c9tape 2 : on parcourt tous les \u00e9l\u00e9ments sauf le premier, on permute le plus petit \u00e9l\u00e9ment\ntrouv\u00e9 avec le second. Le tableau devient : ```t = [6, 12, 21, 18, 55, 41, 25]``` \n\nEt ainsi de suite. \n\nLa code de la fonction `tri_selection` qui impl\u00e9mente cet algorithme est donn\u00e9 ci-\ndessous.\n\n\n```python linenums='1'\ndef tri_selection(tab):\n N = len(tab)\n for k in range(...):\n imin = ...\n for i in range(... , N):\n if tab[i] < ... :\n imin = i\n ... , tab[imin] = tab[imin] , ...\n
Compl\u00e9ter le code de cette fonction de fa\u00e7on \u00e0 obtenir :
>>> liste = [41, 55, 21, 18, 12, 6, 25]\n>>> tri_selection(liste)\n>>> liste\n[6, 12, 18, 21, 25, 41, 55]\n
On rappelle que l'instruction a, b = b, a
\u00e9change les contenus de a
et de b
. ```
Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-34","title":"\u25b6 Sujet 34","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-341","title":"Exercice 34.1","text":"Exercice 34.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction moyenne
prenant en param\u00e8tre un tableau d'entiers tab
(de type list
) qui renvoie la moyenne de ses \u00e9l\u00e9ments si le tableau est non vide. Proposer une fa\u00e7on de traiter le cas o\u00f9 le tableau pass\u00e9 en param\u00e8tre est vide.
Dans cet exercice, on s\u2019interdira d\u2019utiliser la fonction Python sum
.
Exemples :
>>> moyenne([5,3,8])\n5.333333333333333\n>>> moyenne([1,2,3,4,5,6,7,8,9,10])\n5.5\n>>> moyenne([])\n# Comportement diff\u00e9rent suivant le traitement propos\u00e9.\n
def moyenne(tab):\n if tab == []:\n print('Le tableau donn\u00e9 est vide')\n return None\n else:\n somme = 0\n for elt in tab:\n somme += elt\n return somme / len(tab)\n
Programmer la fonction ```moyenne``` prenant en param\u00e8tre un tableau d'entiers ```tab``` (de type\n`list`) qui renvoie la moyenne de ses \u00e9l\u00e9ments si le tableau est non vide. Proposer une\nfa\u00e7on de traiter le cas o\u00f9 le tableau pass\u00e9 en param\u00e8tre est vide.\n\nDans cet exercice, on s\u2019interdira d\u2019utiliser la fonction Python `sum`.\n\nExemples :\n```python\n>>> moyenne([5,3,8])\n5.333333333333333\n>>> moyenne([1,2,3,4,5,6,7,8,9,10])\n5.5\n>>> moyenne([])\n# Comportement diff\u00e9rent suivant le traitement propos\u00e9.\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-342","title":"Exercice 34.2","text":"Exercice 34.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re un tableau d'entiers tab
(de type list
) dont les \u00e9l\u00e9ments sont des 0
ou des 1
). On se propose de trier ce tableau selon l'algorithme suivant : \u00e0 chaque \u00e9tape du tri, le tableau est constitu\u00e9 de trois zones cons\u00e9cutives, la premi\u00e8re ne contenant que des 0
, la seconde n'\u00e9tant pas tri\u00e9e et la derni\u00e8re ne contenant que des 1
.
Zone de 0Zone non tri\u00e9eZone de 1
Tant que la zone non tri\u00e9e n'est pas r\u00e9duite \u00e0 un seul \u00e9l\u00e9ment, on regarde son premier \u00e9l\u00e9ment :
Dans tous les cas, la longueur de la zone non tri\u00e9e diminue de 1.
Recopier sous Python en la compl\u00e9tant la fonction tri
suivante :
def tri(tab):\n # i est le premier indice de la zone non tri\u00e9e,\n # j est le dernier indice de cette zone non tri\u00e9e.\n # Au d\u00e9but, la zone non tri\u00e9e est le tableau complet.\n i = ...\n j = ...\n while i != j:\n if tab[i]== 0:\n i = ...\n else:\n valeur = tab[j]\n tab[j] = ...\n ...\n j = ...\n ...\n
Exemple :
>>> tri([0,1,0,1,0,1,0,1,0])\n[0, 0, 0, 0, 0, 1, 1, 1, 1] \n
def tri(tab):\n # i est le premier indice de la zone non tri\u00e9e,\n # j est le dernier indice de cette zone non tri\u00e9e.\n # Au d\u00e9but, la zone non tri\u00e9e est le tableau complet.\ni = 0\nj = len(tab) - 1\nwhile i != j :\n if tab[i] == 0:\ni = i + 1\nelse :\n valeur = tab[j]\ntab[j] = tab[i]\ntab[i] = valeur\nj = j - 1\nreturn tab\n
On consid\u00e8re un tableau d'entiers `tab` (de type `list`) dont les \u00e9l\u00e9ments sont des `0` ou des `1`). On se propose de trier ce tableau selon l'algorithme suivant : \u00e0 chaque \u00e9tape du tri, le tableau est constitu\u00e9 de trois zones cons\u00e9cutives, la premi\u00e8re ne contenant que des `0`,\nla seconde n'\u00e9tant pas tri\u00e9e et la derni\u00e8re ne contenant que des `1`.\n\n<table>\n<tr>\n<td>Zone de 0</td><td>Zone non tri\u00e9e</td><td>Zone de 1</td>\n</tr>\n</table>\n\nTant que la zone non tri\u00e9e n'est pas r\u00e9duite \u00e0 un seul \u00e9l\u00e9ment, on regarde son premier\n\u00e9l\u00e9ment :\n\n- si cet \u00e9l\u00e9ment vaut 0, on consid\u00e8re qu'il appartient d\u00e9sormais \u00e0 la zone ne contenant\nque des 0 ;\n- si cet \u00e9l\u00e9ment vaut 1, il est \u00e9chang\u00e9 avec le dernier \u00e9l\u00e9ment de la zone non tri\u00e9e et on\nconsid\u00e8re alors qu\u2019il appartient \u00e0 la zone ne contenant que des 1.\n\nDans tous les cas, la longueur de la zone non tri\u00e9e diminue de 1.\n\nRecopier sous Python en la compl\u00e9tant la fonction `tri` suivante :\n\n```python linenums='1'\ndef tri(tab):\n # i est le premier indice de la zone non tri\u00e9e,\n # j est le dernier indice de cette zone non tri\u00e9e.\n # Au d\u00e9but, la zone non tri\u00e9e est le tableau complet.\n i = ...\n j = ...\n while i != j:\n if tab[i]== 0:\n i = ...\n else:\n valeur = tab[j]\n tab[j] = ...\n ...\n j = ...\n ...\n
Exemple :
>>> tri([0,1,0,1,0,1,0,1,0])\n[0, 0, 0, 0, 0, 1, 1, 1, 1] \n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-35","title":"\u25b6 Sujet 35","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-351","title":"Exercice 35.1","text":"Exercice 35.1
\u00c9nonc\u00e9CorrectionSource MarkdownL'op\u00e9rateur \u00ab ou exclusif \u00bb entre deux bits renvoie 0 si les deux bits sont \u00e9gaux et 1 s'ils sont diff\u00e9rents. Il est symbolis\u00e9 par le caract\u00e8re \u2295. Ainsi :
On repr\u00e9sente ici une suite de bits par un tableau contenant des 0 et des 1.
Exemples :
a = [1, 0, 1, 0, 1, 1, 0, 1]\nb = [0, 1, 1, 1, 0, 1, 0, 0]\nc = [1, 1, 0, 1]\nd = [0, 0, 1, 1]\n
\u00c9crire la fonction ou_exclusif
qui prend en param\u00e8tres deux tableaux de m\u00eame longueur et qui renvoie un tableau o\u00f9 l\u2019\u00e9l\u00e9ment situ\u00e9 \u00e0 position i
est le r\u00e9sultat, par l\u2019op\u00e9rateur \u00ab ou exclusif \u00bb, des \u00e9l\u00e9ments \u00e0 la position i
des tableaux pass\u00e9s en param\u00e8tres.
En consid\u00e9rant les quatre exemples ci-dessus, cette fonction donne :
>>> ou_exclusif(a, b)\n[1, 1, 0, 1, 1, 0, 0, 1]\n>>> ou_exclusif(c, d)\n[1, 1, 1, 0]\n
def ou_exclusif(tab1, tab2):\n resultat = []\n taille = len(tab1)\n for i in range(taille):\n resultat.append(tab1[i] ^ tab2[i])\n return resultat\n
Si on ne connait pas la fonction native ^ qui fait le \u00abou exclusif\u00bb de deux entiers en Python, on peut la recoder :
def ou_exc(a, b):\n if a == 0 and b == 0:\n return 0\n if a == 0 and b == 1:\n return 1\n if a == 1 and b == 0:\n return 1\n if a == 1 and b == 1:\n return 0\n
Le code devient alors :
def ou_exclusif(tab1, tab2):\n resultat = []\n taille = len(tab1)\n for i in range(taille):\n resultat.append(ou_exc(tab1[i],tab2[i]))\n return resultat\n
L'op\u00e9rateur \u00ab ou exclusif \u00bb entre deux bits renvoie 0 si les deux bits sont \u00e9gaux et 1 s'ils sont\ndiff\u00e9rents. Il est symbolis\u00e9 par le caract\u00e8re \u2295.\nAinsi :\n\n- 0 \u2295 0 = 0\n- 0 \u2295 1 = 1\n- 1 \u2295 0 = 1\n- 1 \u2295 1 = 0\n\nOn repr\u00e9sente ici une suite de bits par un tableau contenant des 0 et des 1.\n\nExemples :\n\n```python\na = [1, 0, 1, 0, 1, 1, 0, 1]\nb = [0, 1, 1, 1, 0, 1, 0, 0]\nc = [1, 1, 0, 1]\nd = [0, 0, 1, 1]\n```\n\n\u00c9crire la fonction ```ou_exclusif``` qui prend en param\u00e8tres deux tableaux de m\u00eame longueur et qui renvoie\nun tableau o\u00f9 l\u2019\u00e9l\u00e9ment situ\u00e9 \u00e0 position `i` est le r\u00e9sultat, par l\u2019op\u00e9rateur \u00ab ou exclusif \u00bb, des\n\u00e9l\u00e9ments \u00e0 la position `i` des tableaux pass\u00e9s en param\u00e8tres.\n\nEn consid\u00e9rant les quatre exemples ci-dessus, cette fonction donne :\n\n```python\n>>> ou_exclusif(a, b)\n[1, 1, 0, 1, 1, 0, 0, 1]\n>>> ou_exclusif(c, d)\n[1, 1, 1, 0]\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-352","title":"Exercice 35.2","text":"Exercice 35.2
\u00c9nonc\u00e9CorrectionSources MarkdownDans cet exercice, on appelle carr\u00e9 d\u2019ordre \\(n\\) un tableau de \\(n\\) lignes et \\(n\\) colonnes dont chaque case contient un entier naturel.
Exemples :
Un carr\u00e9 est dit semimagique lorsque les sommes des \u00e9l\u00e9ments situ\u00e9s sur chaque ligne, chaque colonne sont \u00e9gales.
Ainsi c2 et c3 sont semimagiques car la somme de chaque ligne, chaque colonne et chaque diagonale est \u00e9gale \u00e0 8 pour c2 et 12 pour c3.
Le carre c3bis n'est pas semimagique car la somme de la premi\u00e8re ligne est \u00e9gale \u00e0 15 alors que celle de la deuxi\u00e8me ligne est \u00e9gale \u00e0 10.
La classe Carre
ci-apr\u00e8s contient des m\u00e9thodes qui permettent de manipuler des carr\u00e9s.
La m\u00e9thode constructeur cr\u00e9e un carr\u00e9 sous forme d\u2019un tableau \u00e0 deux dimensions \u00e0 partir d\u2019une liste d\u2019entiers, et d\u2019un ordre.
La m\u00e9thode affiche
permet d\u2019afficher le carr\u00e9 cr\u00e9\u00e9.
Exemple :
>>> liste = (3, 4, 5, 4, 4, 4, 5, 4, 3)\n>>> c3 = Carre(liste, 3)\n>>> c3.affiche()\n[3, 4, 5]\n[4, 4, 4]\n[5, 4, 3]\n
Compl\u00e9ter la m\u00e9thode est_semimagique
qui renvoie True
si le carr\u00e9 est semimagique, False
sinon. Puis tester la fonction est_semimagique
sur les carr\u00e9s c2, c3 et c3bis.
class Carre:\n def __init__(self, liste, n):\n self.ordre = n\n self.tableau = [[liste[i + j * n] for i in range(n)] for j in range(n)]\n\n def affiche(self):\n'''Affiche un carr\u00e9'''\n for i in range(self.ordre):\n print(self.tableau[i])\n\n def somme_ligne(self, i):\n'''Calcule la somme des valeurs de la ligne i'''\n somme = 0\n for j in range(self.ordre):\n somme = somme + self.tableau[i][j]\n return somme\n\n def somme_col(self, j):\n'''Calcule la somme des valeurs de la colonne j'''\n somme = 0\n for i in range(self.ordre):\n somme = somme + self.tableau[i][j]\n return somme\n\n def est_semimagique(self):\n s = self.somme_ligne(0)\n\n #test de la somme de chaque ligne\n for i in range(...):\n if ... != s:\n return ...\n\n #test de la somme de chaque colonne\n for j in range(...):\n if ... != s:\n return ...\n\n return ...\n
Listes permettant de g\u00e9n\u00e9rer les carr\u00e9s c2, c3 et c3bis :
lst_c2 = [1, 7, 7, 1]\nlst_c3 = [3, 4, 5, 4, 4, 4, 5, 4, 3]\nlst_c3bis = [2, 9, 4, 7, 0, 3, 6, 1, 8]\n
class Carre:\n def __init__(self, liste, n):\n self.ordre = n\n self.tableau = [[liste[i + j * n] for i in range(n)] for j in range(n)]\n\n def affiche(self):\n'''Affiche un carr\u00e9'''\n for i in range(self.ordre):\n print(self.tableau[i])\n\n def somme_ligne(self, i):\n'''Calcule la somme des valeurs de la ligne i'''\n somme = 0\n for j in range(self.ordre):\n somme = somme + self.tableau[i][j]\n return somme\n\n def somme_col(self, j):\n'''Calcule la somme des valeurs de la colonne j'''\n somme = 0\n for i in range(self.ordre):\n somme = somme + self.tableau[i][j]\n return somme\n\n def est_semimagique(self):\n s = self.somme_ligne(0)\n\n #test de la somme de chaque ligne\nfor i in range(self.ordre):\nif self.somme_ligne(i) != s:\nreturn False\n#test de la somme de chaque colonne\nfor j in range(self.ordre):\nif self.somme_col(j) != s:\nreturn False\nreturn True\n
Tests avec :
lst_c2 = [1, 7, 7, 1]\nlst_c3 = [3, 4, 5, 4, 4, 4, 5, 4, 3]\nlst_c3bis = [2, 9, 4, 7, 0, 3, 6, 1, 8]\n
>>> c2 = Carre(lst_c2, 2)\n>>> c2.est_semimagique()\nTrue\n\n>>> c3 = Carre(lst_c3, 3)\n>>> c3.est_semimagique()\nTrue\n\n>>> c3bis = Carre(lst_c3bis, 2)\n>>> c3bis.est_semimagique()\nFalse\n
Dans cet exercice, on appelle carr\u00e9 d\u2019ordre $n$ un tableau de $n$ lignes et $n$ colonnes dont chaque case contient un entier naturel.\n\nExemples :\n![image](data2023/35_carre.png){: .center}\n\nUn carr\u00e9 est dit semimagique lorsque les sommes des \u00e9l\u00e9ments situ\u00e9s sur chaque ligne, chaque\ncolonne sont \u00e9gales.\n\n- Ainsi c2 et c3 sont semimagiques car la somme de chaque\nligne, chaque colonne et chaque diagonale est \u00e9gale \u00e0 8 pour c2 et 12 pour c3.\n\n- Le carre c3bis n'est pas semimagique car la somme de la premi\u00e8re ligne est \u00e9gale \u00e0 15 alors que celle de la deuxi\u00e8me ligne\nest \u00e9gale \u00e0 10.\n\nLa classe `Carre` ci-apr\u00e8s contient des m\u00e9thodes qui permettent de manipuler des carr\u00e9s.\n\n- La m\u00e9thode constructeur cr\u00e9e un carr\u00e9 sous forme d\u2019un tableau \u00e0 deux dimensions\n\u00e0 partir d\u2019une liste d\u2019entiers, et d\u2019un ordre.\n\n- La m\u00e9thode `affiche` permet d\u2019afficher le carr\u00e9 cr\u00e9\u00e9.\n\nExemple :\n\n```python\n>>> liste = (3, 4, 5, 4, 4, 4, 5, 4, 3)\n>>> c3 = Carre(liste, 3)\n>>> c3.affiche()\n[3, 4, 5]\n[4, 4, 4]\n[5, 4, 3]\n
Compl\u00e9ter la m\u00e9thode est_semimagique
qui renvoie True
si le carr\u00e9 est semimagique, False
sinon. Puis tester la fonction est_semimagique
sur les carr\u00e9s c2, c3 et c3bis.
class Carre:\n def __init__(self, liste, n):\n self.ordre = n\n self.tableau = [[liste[i + j * n] for i in range(n)] for j in range(n)]\n\n def affiche(self):\n'''Affiche un carr\u00e9'''\n for i in range(self.ordre):\n print(self.tableau[i])\n\n def somme_ligne(self, i):\n'''Calcule la somme des valeurs de la ligne i'''\n somme = 0\n for j in range(self.ordre):\n somme = somme + self.tableau[i][j]\n return somme\n\n def somme_col(self, j):\n'''Calcule la somme des valeurs de la colonne j'''\n somme = 0\n for i in range(self.ordre):\n somme = somme + self.tableau[i][j]\n return somme\n\n def est_semimagique(self):\n s = self.somme_ligne(0)\n\n #test de la somme de chaque ligne\n for i in range(...):\n if ... != s:\n return ...\n\n #test de la somme de chaque colonne\n for j in range(...):\n if ... != s:\n return ...\n\n return ...\n
Listes permettant de g\u00e9n\u00e9rer les carr\u00e9s c2, c3 et c3bis :
lst_c2 = [1, 7, 7, 1]\nlst_c3 = [3, 4, 5, 4, 4, 4, 5, 4, 3]\nlst_c3bis = [2, 9, 4, 7, 0, 3, 6, 1, 8]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-36","title":"\u25b6 Sujet 36","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-361","title":"Exercice 36.1","text":"Exercice 36.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction couples_consecutifs
qui prend en param\u00e8tre une liste de nombres entiers tab
non vide, et qui renvoie la liste (\u00e9ventuellement vide) des couples d'entiers cons\u00e9cutifs successifs qu'il peut y avoir dans tab
.
Exemples :
>>> couples_consecutifs([1, 4, 3, 5])\n[]\n>>> couples_consecutifs([1, 4, 5, 3])\n[(4, 5)]\n>>> couples_consecutifs([1, 1, 2, 4])\n[(1, 2)]\n>>> couples_consecutifs([7, 1, 2, 5, 3, 4])\n[(1, 2), (3, 4)]\n>>> couples_consecutifs([5, 1, 2, 3, 8, -5, -4, 7])\n[(1, 2), (2, 3), (-5, -4)]\n
def couples_consecutifs(tab):\n solution = []\n for i in range(len(tab)-1):\n if tab[i] + 1 == tab[i+1]:\n solution.append((tab[i], tab[i+1]))\n return solution\n
\u00c9crire une fonction `couples_consecutifs` qui prend en param\u00e8tre une liste de\nnombres entiers `tab` non vide, et qui renvoie la liste (\u00e9ventuellement vide) des couples d'entiers cons\u00e9cutifs\nsuccessifs qu'il peut y avoir dans `tab`.\n\nExemples :\n```python\n>>> couples_consecutifs([1, 4, 3, 5])\n[]\n>>> couples_consecutifs([1, 4, 5, 3])\n[(4, 5)]\n>>> couples_consecutifs([1, 1, 2, 4])\n[(1, 2)]\n>>> couples_consecutifs([7, 1, 2, 5, 3, 4])\n[(1, 2), (3, 4)]\n>>> couples_consecutifs([5, 1, 2, 3, 8, -5, -4, 7])\n[(1, 2), (2, 3), (-5, -4)]\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-362","title":"Exercice 36.2","text":"Exercice 36.2
\u00c9nonc\u00e9CorrectionSources MarkdownSoit une image binaire repr\u00e9sent\u00e9e dans un tableau \u00e0 2 dimensions. Les \u00e9l\u00e9ments M[i][j]
, appel\u00e9s pixels, sont \u00e9gaux soit \u00e0 0
soit \u00e0 1
.
Une composante d\u2019une image est un sous-ensemble de l\u2019image constitu\u00e9 uniquement de 1
et de 0
qui sont c\u00f4te \u00e0 c\u00f4te, soit horizontalement soit verticalement.
Par exemple, les composantes de sont
On souhaite, \u00e0 partir d\u2019un pixel \u00e9gal \u00e0 1
dans une image M
, donner la valeur val
\u00e0 tous les pixels de la composante \u00e0 laquelle appartient ce pixel.
La fonction propager
prend pour param\u00e8tre une image M
(repr\u00e9sent\u00e9e par une liste de listes), deux entiers i
et j
et unevaleur enti\u00e8re val
. Elle met \u00e0 la valeur val
tous les pixels de la composante du pixel M[i][j]
s\u2019il vaut 1
et ne fait rien s\u2019il vaut 0
.
Par exemple, propager(M, 2, 1, 3)
donne
Compl\u00e9ter le code r\u00e9cursif de la fonction propager
donn\u00e9 ci-dessous :
def propager(M, i, j, val):\n if M[i][j] == ...:\n M[i][j] = val\n\n # l'element en haut fait partie de la composante\n if i-1 >= 0 and M[i-1][j] == ...:\n propager(M, i-1, j, val)\n\n # l'element en bas fait partie de la composante\n if ... < len(M) and M[i+1][j] == 1:\n propager(M, ..., j, val)\n\n # l'element \u00e0 gauche fait partie de la composante\n if ... and M[i][j-1] == 1:\n propager(M, ..., ..., val)\n\n # l'element \u00e0 droite fait partie de la composante\n if ... and ...:\n propager(..., ..., ..., ...)\n
Exemple :
>>> M = [[0, 0, 1, 0], [0, 1, 0, 1], [1, 1, 1, 0], [0, 1, 1, 0]]\n>>> propager(M, 2, 1, 3)\n>>> M\n[[0, 0, 1, 0], [0, 3, 0, 1], [3, 3, 3, 0], [0, 3, 3, 0]]\n
def propager(M, i, j, val):\nif M[i][j] == 1:\nM[i][j] = val\n\n # l'element en haut fait partie de la composante\nif i-1 >= 0 and M[i-1][j] == 1:\npropager(M, i-1, j, val)\n\n # l'element en bas fait partie de la composante\nif i+1 < len(M) and M[i+1][j] == 1:\npropager(M, i+1, j, val)\n# l'element \u00e0 gauche fait partie de la composante\nif j-1 >= 0 and M[i][j-1] == 1:\npropager(M, i, j-1, val)\n# l'element \u00e0 droite fait partie de la composante\nif j+1 < len(M[i]) and M[i][j+1] == 1:\npropager(M, i, j+1, val)\n
ce code va d\u00e9clencher la propagation m\u00eame si la cellule i,j
n'est pas \u00e0 1. C'est sans doute une erreur d'\u00e9nonc\u00e9. Il faudrait plut\u00f4t \u00e9crire ceci :
def propager(M, i, j, val):\nif M[i][j] == 1:\nM[i][j] = val\n\n # l'element en haut fait partie de la composante\nif i-1 >= 0 and M[i-1][j] == 1:\npropager(M, i-1, j, val)\n\n # l'element en bas fait partie de la composante\nif i+1 < len(M) and M[i+1][j] == 1:\npropager(M, i+1, j, val)\n# l'element \u00e0 gauche fait partie de la composante\nif j-1 >= 0 and M[i][j-1] == 1:\npropager(M, i, j-1, val)\n# l'element \u00e0 droite fait partie de la composante\nif j+1 < len(M[i]) and M[i][j+1] == 1:\npropager(M, i, j+1, val)\n
Soit une image binaire repr\u00e9sent\u00e9e dans un tableau \u00e0 2 dimensions. Les \u00e9l\u00e9ments\n`M[i][j]`, appel\u00e9s pixels, sont \u00e9gaux soit \u00e0 `0` soit \u00e0 `1`.\n\nUne composante d\u2019une image est un sous-ensemble de l\u2019image constitu\u00e9 uniquement de\n`1` et de `0` qui sont c\u00f4te \u00e0 c\u00f4te, soit horizontalement soit verticalement.\n\nPar exemple, les composantes de\n![image](data2023/36_carre1.png){: .center}\nsont\n![image](data2023/36_carre2.png){: .center width=30%}\n\nOn souhaite, \u00e0 partir d\u2019un pixel \u00e9gal \u00e0 `1` dans une image `M`, donner la valeur `val` \u00e0 tous\nles pixels de la composante \u00e0 laquelle appartient ce pixel.\n\nLa fonction `propager` prend pour param\u00e8tre une image `M` (repr\u00e9sent\u00e9e par une liste de\nlistes), deux entiers `i` et `j` et unevaleur enti\u00e8re `val`. Elle met \u00e0 la valeur `val` tous les pixels de la composante du pixel\n`M[i][j]` s\u2019il vaut `1` et ne fait rien s\u2019il vaut `0`.\n\nPar exemple, `propager(M, 2, 1, 3)` donne\n![image](data2023/36_carre3.png){: .center width=30%}\n\nCompl\u00e9ter le code r\u00e9cursif de la fonction `propager` donn\u00e9 ci-dessous :\n\n```python linenums='1'\ndef propager(M, i, j, val):\n if M[i][j] == ...:\n M[i][j] = val\n\n # l'element en haut fait partie de la composante\n if i-1 >= 0 and M[i-1][j] == ...:\n propager(M, i-1, j, val)\n\n # l'element en bas fait partie de la composante\n if ... < len(M) and M[i+1][j] == 1:\n propager(M, ..., j, val)\n\n # l'element \u00e0 gauche fait partie de la composante\n if ... and M[i][j-1] == 1:\n propager(M, ..., ..., val)\n\n # l'element \u00e0 droite fait partie de la composante\n if ... and ...:\n propager(..., ..., ..., ...)\n
Exemple :
>>> M = [[0, 0, 1, 0], [0, 1, 0, 1], [1, 1, 1, 0], [0, 1, 1, 0]]\n>>> propager(M, 2, 1, 3)\n>>> M\n[[0, 0, 1, 0], [0, 3, 0, 1], [3, 3, 3, 0], [0, 3, 3, 0]]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-37","title":"\u25b6 Sujet 37","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-371","title":"Exercice 37.1","text":"Exercice 37.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche
qui prend en param\u00e8tres elt
un nombre entier et tab
un tableau de nombres entiers, et qui renvoie l\u2019indice de la derni\u00e8re occurrence de elt
dans tab
si elt
est dans tab
et -1
sinon.
Exemples :
>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(1, [1, 0, 42, 7])\n0\n>>> recherche(1, [1, 50, 1])\n2\n>>> recherche(1, [8, 1, 10, 1, 7, 1, 8])\n5\n
def recherche(elt, tab):\n for i in range(len(tab)-1, -1, -1):\n if tab[i] == elt:\n return i\n return -1\n
\u00c9crire une fonction `recherche` qui prend en param\u00e8tres `elt` un nombre entier et `tab`\nun tableau de nombres entiers, et qui renvoie l\u2019indice de la derni\u00e8re occurrence de `elt`\ndans `tab` si `elt` est dans `tab` et `-1` sinon.\n\nExemples :\n```python\n>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(1, [1, 0, 42, 7])\n0\n>>> recherche(1, [1, 50, 1])\n2\n>>> recherche(1, [8, 1, 10, 1, 7, 1, 8])\n5\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-372","title":"Exercice 37.2","text":"Exercice 37.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn d\u00e9finit une classe g\u00e9rant une adresse IPv4.
On rappelle qu\u2019une adresse IPv4 est une adresse de longueur 4 octets, not\u00e9e en d\u00e9cimale \u00e0 point, en s\u00e9parant chacun des octets par un point. On consid\u00e8re un r\u00e9seau priv\u00e9 avec une plage d\u2019adresses IP de 192.168.0.0
\u00e0 192.168.0.255
.
On consid\u00e8re que les adresses IP saisies sont valides.
Les adresses IP 192.168.0.0
et 192.168.0.255
sont des adresses r\u00e9serv\u00e9es.
Le code ci-dessous impl\u00e9mente la classe AdresseIP
.
class AdresseIP:\n def __init__(self, adresse):\n self.adresse = ...\n\n def liste_octet(self):\n\"\"\"renvoie une liste de nombres entiers,\n la liste des octets de l'adresse IP\"\"\"\n return [int(i) for i in self.adresse.split(\".\")]\n\n def est_reservee(self):\n\"\"\"renvoie True si l'adresse IP est une adresse\n r\u00e9serv\u00e9e, False sinon\"\"\"\n return ... or ...\n\n def adresse_suivante(self):\n\"\"\"renvoie un objet de AdresseIP avec l'adresse\n IP qui suit l\u2019adresse self\n si elle existe et False sinon\"\"\"\n if ... < 254:\n octet_nouveau = ... + ...\n return AdresseIP('192.168.0.' + ...)\n else:\n return False\n
Compl\u00e9ter le code ci-dessus et instancier trois objets : adresse1
, adresse2
, adresse3
avec respectivement les arguments suivants : '192.168.0.1'
, '192.168.0.2'
, '192.168.0.0'
V\u00e9rifier que :
>>> adresse1.est_reservee()\nFalse\n>>> adresse3.est_reservee()\nTrue\n>>> adresse2.adresse_suivante().adresse\n'192.168.0.3'\n
class AdresseIP:\n def __init__(self, adresse):\nself.adresse = adresse\ndef liste_octet(self):\n\"\"\"renvoie une liste de nombres entiers,\n la liste des octets de l'adresse IP\"\"\"\n return [int(i) for i in self.adresse.split(\".\")]\n\n def est_reservee(self):\n\"\"\"renvoie True si l'adresse IP est une adresse\n r\u00e9serv\u00e9e, False sinon\"\"\"\nreturn self.liste_octet()[3] == 0 or self.liste_octet()[3] == 255\ndef adresse_suivante(self):\n\"\"\"renvoie un objet de AdresseIP avec l'adresse\n IP qui suit l\u2019adresse self\n si elle existe et False sinon\"\"\"\nif self.liste_octet()[3] < 254:\noctet_nouveau = self.liste_octet()[3] + 1\nreturn AdresseIP('192.168.0.' + str(octet_nouveau))\nelse:\n return False\n\nadresse1 = AdresseIP('192.168.0.1')\nadresse2 = AdresseIP('192.168.0.2')\nadresse3 = AdresseIP('192.168.0.0')\n
On d\u00e9finit une classe g\u00e9rant une adresse IPv4.\n\nOn rappelle qu\u2019une adresse IPv4 est une adresse de longueur 4 octets, not\u00e9e en d\u00e9cimale\n\u00e0 point, en s\u00e9parant chacun des octets par un point. On consid\u00e8re un r\u00e9seau priv\u00e9 avec\nune plage d\u2019adresses IP de `192.168.0.0` \u00e0 `192.168.0.255`.\n\nOn consid\u00e8re que les adresses IP saisies sont valides.\n\nLes adresses IP `192.168.0.0` et `192.168.0.255` sont des adresses r\u00e9serv\u00e9es.\n\nLe code ci-dessous impl\u00e9mente la classe `AdresseIP`.\n\n```python linenums='1'\nclass AdresseIP:\n def __init__(self, adresse):\n self.adresse = ...\n\n def liste_octet(self):\n \"\"\"renvoie une liste de nombres entiers,\n la liste des octets de l'adresse IP\"\"\"\n return [int(i) for i in self.adresse.split(\".\")]\n\n def est_reservee(self):\n \"\"\"renvoie True si l'adresse IP est une adresse\n r\u00e9serv\u00e9e, False sinon\"\"\"\n return ... or ...\n\n def adresse_suivante(self):\n \"\"\"renvoie un objet de AdresseIP avec l'adresse\n IP qui suit l\u2019adresse self\n si elle existe et False sinon\"\"\"\n if ... < 254:\n octet_nouveau = ... + ...\n return AdresseIP('192.168.0.' + ...)\n else:\n return False\n
Compl\u00e9ter le code ci-dessus et instancier trois objets : adresse1
, adresse2
, adresse3
avec respectivement les arguments suivants : '192.168.0.1'
, '192.168.0.2'
, '192.168.0.0'
V\u00e9rifier que :
>>> adresse1.est_reservee()\nFalse\n>>> adresse3.est_reservee()\nTrue\n>>> adresse2.adresse_suivante().adresse\n'192.168.0.3'\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-38","title":"\u25b6 Sujet 38","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-381","title":"Exercice 38.1","text":"Exercice 38.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn consid\u00e8re des mots \u00e0 trous : ce sont des cha\u00eenes de caract\u00e8res contenant uniquement des majuscules et des caract\u00e8res *
. Par exemple INFO*MA*IQUE
, ***I***E**
et *S*
sont des mots \u00e0 trous.
Programmer une fonction correspond
qui :
mot
et mot_a_trous
o\u00f9 mot_a_trous
est un mot \u00e0 trous comme indiqu\u00e9 ci-dessus, True
si on peut obtenir mot
en rempla\u00e7ant convenablement les caract\u00e8res '*'
de mot_a_trous
.False
sinon.Exemple :
>>> correspond('INFORMATIQUE', 'INFO*MA*IQUE')\nTrue\n>>> correspond('AUTOMATIQUE', 'INFO*MA*IQUE')\nFalse\n>>> correspond('STOP', 'S*')\nFalse\n>>> correspond('AUTO', '*UT*')\nTrue\n
def correspond(mot, mot_a_trous):\n if len(mot) != len(mot_a_trous):\n return False\n for i in range(len(mot)):\n if mot[i] != mot_a_trous[i] and mot_a_trous[i] != '*':\n return False\n return True\n
On consid\u00e8re des mots \u00e0 trous : ce sont des cha\u00eenes de caract\u00e8res contenant uniquement\ndes majuscules et des caract\u00e8res `*`. Par exemple `INFO*MA*IQUE`, `***I***E**` et\n`*S*` sont des mots \u00e0 trous.\n\nProgrammer une fonction `correspond` qui :\n\n- prend en param\u00e8tres deux cha\u00eenes de caract\u00e8res `mot` et `mot_a_trous` o\u00f9\n`mot_a_trous` est un mot \u00e0 trous comme indiqu\u00e9 ci-dessus, \n- renvoie :\n - `True` si on peut obtenir `mot` en rempla\u00e7ant convenablement les caract\u00e8res\n`'*'` de `mot_a_trous`.\n - `False` sinon.\n\nExemple :\n\n```python\n>>> correspond('INFORMATIQUE', 'INFO*MA*IQUE')\nTrue\n>>> correspond('AUTOMATIQUE', 'INFO*MA*IQUE')\nFalse\n>>> correspond('STOP', 'S*')\nFalse\n>>> correspond('AUTO', '*UT*')\nTrue\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-382","title":"Exercice 38.2","text":"Exercice 38.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re au plus 26 personnes A, B, C, D, E, F ... qui peuvent s'envoyer des messages avec deux r\u00e8gles \u00e0 respecter :
Voici un exemple - avec 6 personnes - de \u00ab plan d'envoi des messages \u00bb qui respecte les r\u00e8gles ci-dessus, puisque chaque personne est pr\u00e9sente une seule fois dans chaque colonne :
Et le dictionnaire correspondant \u00e0 ce plan d'envoi est le suivant :
plan_a = {'A':'E', 'B':'F', 'C':'D', 'D':'C', 'E':'B', 'F':'A'}
Un cycle est une suite de personnes dans laquelle la derni\u00e8re est la m\u00eame que la premi\u00e8re.
Sur le plan d'envoi plan_a
des messages ci-dessus, il y a deux cycles distincts : un premier cycle avec A, E, B, F et un second cycle avec C et D.
En revanche, le plan d\u2019envoi plan_b
ci-dessous :
plan_b = {'A':'C', 'B':'F', 'C':'E', 'D':'A', 'E':'B', 'F':'D'}
comporte un unique cycle : A, C, E, B, F, D. Dans ce cas, lorsqu\u2019un plan d\u2019envoi comporte un unique cycle, on dit que le plan d\u2019envoi est cyclique.
Pour savoir si un plan d'envoi de messages comportant N personnes est cyclique, on peut utiliser l'algorithme ci-dessous :
Compl\u00e9ter la fonction est_cyclique
en respectant la sp\u00e9cification.
Remarque : la fonction python len
permet d'obtenir la longueur d'un dictionnaire.
def est_cyclique(plan):\n'''\n Prend en param\u00e8tre un dictionnaire `plan` correspondant \u00e0 un plan d'envoi de messages (ici entre les personnes A, B, C, D, E, F).\n Renvoie True si le plan d'envoi de messages est cyclique et False sinon.\n '''\n expediteur = 'A'\n destinataire = plan[ ... ]\n nb_destinaires = 1\n\n while destinataire != ...:\n destinataire = plan[ ... ]\n nb_destinaires += ...\n\n return nb_destinaires == ...\n
Exemples :
>>> est_cyclique({'A':'E', 'F':'A', 'C':'D', 'E':'B', 'B':'F', 'D':'C'})\nFalse\n>>> est_cyclique({'A':'E', 'F':'C', 'C':'D', 'E':'B', 'B':'F', 'D':'A'})\nTrue\n>>> est_cyclique({'A':'B', 'F':'C', 'C':'D', 'E':'A', 'B':'F', 'D':'E'})\nTrue\n>>> est_cyclique({'A':'B', 'F':'A', 'C':'D', 'E':'C', 'B':'F', 'D':'E'})\nFalse\n
def est_cyclique(plan):\n'''\n Prend en param\u00e8tre un dictionnaire `plan` correspondant \u00e0 un plan d'envoi de messages (ici entre les personnes A, B, C, D, E, F).\n Renvoie True si le plan d'envoi de messages est cyclique et False sinon.\n '''\n expediteur = 'A'\ndestinataire = plan[expediteur]\nnb_destinaires = 1\nwhile destinataire != expediteur:\ndestinataire = plan[destinataire]\nnb_destinaires += 1\nreturn nb_destinaires == len(plan)\n#tests\nprint(est_cyclique({'A':'E', 'F':'A', 'C':'D', 'E':'B', 'B':'F', 'D':'C'}))\nprint(est_cyclique({'A':'E', 'F':'C', 'C':'D', 'E':'B', 'B':'F', 'D':'A'}))\nprint(est_cyclique({'A':'B', 'F':'C', 'C':'D', 'E':'A', 'B':'F', 'D':'E'}))\nprint(est_cyclique({'A':'B', 'F':'A', 'C':'D', 'E':'C', 'B':'F', 'D':'E'}))\n
On consid\u00e8re au plus 26 personnes A, B, C, D, E, F ... qui peuvent s'envoyer des messages\navec deux r\u00e8gles \u00e0 respecter :\n\n- chaque personne ne peut envoyer des messages qu'\u00e0 une seule personne\n(\u00e9ventuellement elle-m\u00eame),\n- chaque personne ne peut recevoir des messages qu'en provenance d'une seule\npersonne (\u00e9ventuellement elle-m\u00eame).\n\n\nVoici un exemple - avec 6 personnes - de \u00ab plan d'envoi des messages \u00bb qui respecte les\nr\u00e8gles ci-dessus, puisque chaque personne est pr\u00e9sente une seule fois dans chaque\ncolonne :\n\n- A envoie ses messages \u00e0 E\n- E envoie ses messages \u00e0 B\n- B envoie ses messages \u00e0 F\n- F envoie ses messages \u00e0 A\n- C envoie ses messages \u00e0 D\n- D envoie ses messages \u00e0 C\n\nEt le dictionnaire correspondant \u00e0 ce plan d'envoi est le suivant :\n\n`plan_a = {'A':'E', 'B':'F', 'C':'D', 'D':'C', 'E':'B', 'F':'A'}`\n\nUn cycle est une suite de personnes dans laquelle la derni\u00e8re est la m\u00eame que la\npremi\u00e8re.\n\nSur le plan d'envoi `plan_a` des messages ci-dessus, il y a deux cycles distincts : un premier\ncycle avec A, E, B, F et un second cycle avec C et D.\n\nEn revanche, le plan d\u2019envoi `plan_b` ci-dessous :\n\n`plan_b = {'A':'C', 'B':'F', 'C':'E', 'D':'A', 'E':'B', 'F':'D'}`\n\ncomporte un unique cycle : A, C, E, B, F, D. Dans ce cas, lorsqu\u2019un plan d\u2019envoi comporte un\n*unique cycle*, on dit que le plan d\u2019envoi est *cyclique*.\n\nPour savoir si un plan d'envoi de messages comportant N personnes est cyclique, on peut\nutiliser l'algorithme ci-dessous :\n\n\n- on part d\u2019un exp\u00e9diteur (ici A) et on inspecte son destinataire dans le plan d'envoi,\n- chaque destinataire devient \u00e0 son tour exp\u00e9diteur, selon le plan d\u2019envoi, tant\nqu\u2019on ne \u00ab retombe \u00bb pas sur l\u2019exp\u00e9diteur initial,\n- le plan d\u2019envoi est cyclique si on l\u2019a parcouru en entier.\n\n\nCompl\u00e9ter la fonction `est_cyclique` en respectant la sp\u00e9cification.\n\n*Remarque :* la fonction python `len` permet d'obtenir la longueur d'un dictionnaire.\n\n\n```python linenums='1'\ndef est_cyclique(plan):\n '''\n Prend en param\u00e8tre un dictionnaire `plan` correspondant \u00e0 un plan d'envoi de messages (ici entre les personnes A, B, C, D, E, F).\n Renvoie True si le plan d'envoi de messages est cyclique et False sinon.\n '''\n expediteur = 'A'\n destinataire = plan[ ... ]\n nb_destinaires = 1\n\n while destinataire != ...:\n destinataire = plan[ ... ]\n nb_destinaires += ...\n\n return nb_destinaires == ...\n
Exemples :
>>> est_cyclique({'A':'E', 'F':'A', 'C':'D', 'E':'B', 'B':'F', 'D':'C'})\nFalse\n>>> est_cyclique({'A':'E', 'F':'C', 'C':'D', 'E':'B', 'B':'F', 'D':'A'})\nTrue\n>>> est_cyclique({'A':'B', 'F':'C', 'C':'D', 'E':'A', 'B':'F', 'D':'E'})\nTrue\n>>> est_cyclique({'A':'B', 'F':'A', 'C':'D', 'E':'C', 'B':'F', 'D':'E'})\nFalse\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-39","title":"\u25b6 Sujet 39","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-391","title":"Exercice 39.1","text":"Exercice 39.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn s\u2019int\u00e9resse \u00e0 la suite d\u2019entiers d\u00e9finie par :
En math\u00e9matiques, on le formule ainsi :
\\(U_1 = 1\\), \\(U_2 = 1\\) et, pour tout entier naturel non nul \\(n\\), par \\(U_{n+2} = U_{n+1} + U_n\\).
Cette suite est connue sous le nom de suite de Fibonacci. \u00c9crire en Python une fonction fibonacci
qui prend en param\u00e8tre un entier n
suppos\u00e9 strictement positif et qui renvoie le terme d\u2019indice n
de cette suite.
Exemples :
>>> fibonacci(1)\n1\n>>> fibonacci(2)\n1\n>>> fibonacci(25)\n75025\n>>> fibonacci(45)\n1134903170\n
Version r\u00e9cursive :
def fibonacci(n):\n if n == 1 :\n return 1 \n elif n == 1 :\n return 1\n else :\n return fibonacci(n-1) + fibonacci(n-2)\n
Version imp\u00e9rative :
def fibonacci(n):\n a = 1\n b = 1\n for k in range(n-2):\n t = b\n b = a + b\n a = t\n return b\n
Version programmation dynamique :
def fibonacci(n):\n d = {}\n d[1] = 1\n d[2] = 1\n for k in range(3, n+1):\n d[k] = d[k-1] + d[k-2]\n return d[n]\n
On peut constater que la version r\u00e9cursive \u00e9choue \u00e0 calculer fibonacci(45)
, alors que les deux autres versions le font quasi-imm\u00e9diatement.
On s\u2019int\u00e9resse \u00e0 la suite d\u2019entiers d\u00e9finie par :\n\n- les deux premiers termes sont \u00e9gaux \u00e0 1,\n- ensuite, chaque terme est obtenu en faisant la somme des deux termes qui le\npr\u00e9c\u00e8dent.\n\nEn math\u00e9matiques, on le formule ainsi :\n\n$U_1 = 1$, $U_2 = 1$ et, pour tout entier naturel non nul $n$, par $U_{n+2} = U_{n+1} + U_n$.\n\nCette suite est connue sous le nom de suite de Fibonacci. \n\u00c9crire en Python une fonction `fibonacci` qui prend en param\u00e8tre un entier `n` suppos\u00e9\nstrictement positif et qui renvoie le terme d\u2019indice `n` de cette suite.\n\nExemples :\n\n```python\n>>> fibonacci(1)\n1\n>>> fibonacci(2)\n1\n>>> fibonacci(25)\n75025\n>>> fibonacci(45)\n1134903170\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-392","title":"Exercice 39.2","text":"Exercice 39.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re la fonction pantheon
prenant en param\u00e8tres eleves
et notes
deux tableaux de m\u00eame longueur, le premier contenant le nom des \u00e9l\u00e8ves et le second, des entiers positifs d\u00e9signant leur note \u00e0 un contr\u00f4le de sorte que eleves[i]
a obtenu la note notes[i]
. Cette fonction renvoie le couple constitu\u00e9 de la note maximale attribu\u00e9e et des noms des \u00e9l\u00e8ves ayant obtenu cette note regroup\u00e9s dans un tableau. Ainsi, l\u2019instruction pantheon(['a', 'b', 'c', 'd'], [15, 18, 12, 18])
renvoie le couple (18, ['b', 'd'])
.
def pantheon(eleves, notes):\n note_maxi = 0\n meilleurs_eleves = ...\n\n for i in range(...) :\n if notes[i] == ... :\n meilleurs_eleves.append(...)\n elif notes[i] > note_maxi:\n note_maxi = ...\n meilleurs_eleves = [...]\n\n return (note_maxi,meilleurs_eleves)\n
Compl\u00e9ter ce code.
Exemples :
>>> eleves_nsi = ['a','b','c','d','e','f','g','h','i','j']\n>>> notes_nsi = [30, 40, 80, 60, 58, 80, 75, 80, 60, 24]\n>>> pantheon(eleves_nsi, notes_nsi)\n(80, ['c', 'f', 'h'])\n>>> pantheon([],[])\n(0, [])\n
def pantheon(eleves, notes):\n note_maxi = 0\nmeilleurs_eleves = []\nfor i in range(len(eleves)) :\nif notes[i] == note_maxi :\nmeilleurs_eleves.append(eleves[i])\nelif notes[i] > note_maxi:\nnote_maxi = notes[i]\nmeilleurs_eleves = [eleves[i]]\nreturn (note_maxi, meilleurs_eleves)\n
On consid\u00e8re la fonction `pantheon` prenant en param\u00e8tres `eleves` et `notes` deux\ntableaux de m\u00eame longueur, le premier contenant le nom des \u00e9l\u00e8ves et le second, des\nentiers positifs d\u00e9signant leur note \u00e0 un contr\u00f4le de sorte que `eleves[i]` a obtenu la\nnote `notes[i]`. \nCette fonction renvoie le couple constitu\u00e9 de la note maximale attribu\u00e9e et des noms\ndes \u00e9l\u00e8ves ayant obtenu cette note regroup\u00e9s dans un tableau. \nAinsi, l\u2019instruction `pantheon(['a', 'b', 'c', 'd'], [15, 18, 12, 18])` renvoie\nle couple `(18, ['b', 'd'])`.\n\n```python linenums='1'\ndef pantheon(eleves, notes):\n note_maxi = 0\n meilleurs_eleves = ...\n\n for i in range(...) :\n if notes[i] == ... :\n meilleurs_eleves.append(...)\n elif notes[i] > note_maxi:\n note_maxi = ...\n meilleurs_eleves = [...]\n\n return (note_maxi,meilleurs_eleves)\n
Compl\u00e9ter ce code.
Exemples :
>>> eleves_nsi = ['a','b','c','d','e','f','g','h','i','j']\n>>> notes_nsi = [30, 40, 80, 60, 58, 80, 75, 80, 60, 24]\n>>> pantheon(eleves_nsi, notes_nsi)\n(80, ['c', 'f', 'h'])\n>>> pantheon([],[])\n(0, [])\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-40","title":"\u25b6 Sujet 40","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-401","title":"Exercice 40.1","text":"Exercice 40.1
\u00c9nonc\u00e9CorrectionSource MarkdownPour cet exercice :
On appelle \u00ab mot \u00bb une cha\u00eene de caract\u00e8res compos\u00e9e avec des caract\u00e8res choisis parmi les 26 lettres minuscules ou majuscules de l'alphabet,
On appelle \u00ab phrase \u00bb une cha\u00eene de caract\u00e8res :
' '
,'.'
qui est alors coll\u00e9 au dernier mot,'!'
ou d'interrogation '?'
qui est alors s\u00e9par\u00e9 du dernier mot par un seul caract\u00e8re espace ' '
.Exemples :
Apr\u00e8s avoir remarqu\u00e9 le lien entre le nombre de mots et le nombres de caract\u00e8res espace dans une phrase, programmer une fonction nombre_de_mots
qui prend en param\u00e8tre une phrase et renvoie le nombre de mots pr\u00e9sents dans cette phrase.
>>> nombre_de_mots('Le point d exclamation est separe !')\n6\n>>> nombre_de_mots('Il y a un seul espace entre les mots !')\n9\n>>> nombre_de_mots('Combien de mots y a t il dans cette phrase ?')\n10\n>>> nombre_de_mots('Fin.')\n1\n
def nombre_de_mots(phrase):\n nb_mots = 0\n for caractere in phrase:\n if caractere == ' ' or caractere == '.':\n nb_mots += 1\n return nb_mots\n
Pour cet exercice :\n\n- On appelle \u00ab mot \u00bb une cha\u00eene de caract\u00e8res compos\u00e9e avec des caract\u00e8res choisis\nparmi les 26 lettres minuscules ou majuscules de l'alphabet,\n\n- On appelle \u00ab phrase \u00bb une cha\u00eene de caract\u00e8res :\n - compos\u00e9e avec un ou plusieurs \u00ab mots \u00bb s\u00e9par\u00e9s entre eux par un seul\ncaract\u00e8re espace `' '`,\n - se finissant :\n - soit par un point `'.'` qui est alors coll\u00e9 au dernier mot,\n - soit par un point d'exclamation `'!'` ou d'interrogation `'?'` qui est alors\ns\u00e9par\u00e9 du dernier mot par un seul caract\u00e8re espace `' '`.\n\n*Exemples :*\n\n- 'Cet exercice est simple.'\n- 'Le point d exclamation est separe !'\n\nApr\u00e8s avoir remarqu\u00e9 le lien entre le nombre de mots et le nombres de caract\u00e8res espace\ndans une phrase, programmer une fonction `nombre_de_mots` qui prend en param\u00e8tre une\nphrase et renvoie le nombre de mots pr\u00e9sents dans cette phrase.\n\n```python\n>>> nombre_de_mots('Le point d exclamation est separe !')\n6\n>>> nombre_de_mots('Il y a un seul espace entre les mots !')\n9\n>>> nombre_de_mots('Combien de mots y a t il dans cette phrase ?')\n10\n>>> nombre_de_mots('Fin.')\n1\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-402","title":"Exercice 40.2","text":"Exercice 40.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa classe ABR ci-dessous permet d'impl\u00e9menter une structure d'arbre binaire de recherche.
class Noeud:\n def __init__(self, valeur):\n'''M\u00e9thode constructeur pour la classe Noeud.\n Param\u00e8tre d'entr\u00e9e : valeur (str)'''\n self.valeur = valeur\n self.gauche = None\n self.droit = None\n\n def getValeur(self):\n'''M\u00e9thode accesseur pour obtenir la valeur du noeud\n Aucun param\u00e8tre en entr\u00e9e'''\n return self.valeur\n\n def droitExiste(self):\n'''M\u00e9thode renvoyant True si l'enfant droit existe\n Aucun param\u00e8tre en entr\u00e9e'''\n return (self.droit is not None)\n\n def gaucheExiste(self):\n'''M\u00e9thode renvoyant True si l'enfant gauche existe\n Aucun param\u00e8tre en entr\u00e9e'''\n return (self.gauche is not None)\n\n def inserer(self, cle):\n'''M\u00e9thode d'insertion de cl\u00e9 dans un arbre binaire de recherche\n Param\u00e8tre d'entr\u00e9e : cle (int)'''\n if cle < ...:\n # on ins\u00e8re \u00e0 gauche\n if self.gaucheExiste():\n # on descend \u00e0 gauche et on retente l'insertion de la cl\u00e9\n ...\n else:\n # on cr\u00e9e un fils gauche\n self.gauche = ...\n elif cle > ... :\n # on ins\u00e8re \u00e0 droite\n if ... :\n # on descend \u00e0 droite et on retente l'insertion de la cl\u00e9\n ...\n else:\n # on cr\u00e9e un fils droit\n ... = Noeud(cle)\n
Compl\u00e9ter la fonction r\u00e9cursive inserer
afin qu'elle permette d\u2019ins\u00e9rer un n\u0153ud dans l\u2019arbre binaire de recherche propos\u00e9, \u00e0 l\u2019aide de sa cl\u00e9.
Voici un exemple d'utilisation :
>>> arbre = Noeud(7)\n>>> for cle in (3, 9, 1, 6):\n arbre.inserer(cle)\n>>> arbre.gauche.getValeur()\n3\n>>> arbre.droit.getValeur()\n9\n>>> arbre.gauche.gauche.getValeur()\n1\n>>> arbre.gauche.droit.getValeur()\n6\n
class Noeud:\n def __init__(self, valeur):\n'''M\u00e9thode constructeur pour la classe Noeud.\n Param\u00e8tre d'entr\u00e9e : valeur (str)'''\n self.valeur = valeur\n self.gauche = None\n self.droit = None\n\n def getValeur(self):\n'''M\u00e9thode accesseur pour obtenir la valeur du noeud\n Aucun param\u00e8tre en entr\u00e9e'''\n return self.valeur\n\n def droitExiste(self):\n'''M\u00e9thode renvoyant True si l'enfant droit existe\n Aucun param\u00e8tre en entr\u00e9e'''\n return (self.droit is not None)\n\n def gaucheExiste(self):\n'''M\u00e9thode renvoyant True si l'enfant gauche existe\n Aucun param\u00e8tre en entr\u00e9e'''\n return (self.gauche is not None)\n\n def inserer(self, cle):\n'''M\u00e9thode d'insertion de cl\u00e9 dans un arbre binaire de recherche\n Param\u00e8tre d'entr\u00e9e : cle (int)'''\nif cle < self.valeur:\n# on ins\u00e8re \u00e0 gauche\n if self.gaucheExiste():\n # on descend \u00e0 gauche et on retente l'insertion de la cl\u00e9\nself.gauche.inserer(cle)\nelse:\n # on cr\u00e9e un fils gauche\nself.gauche = Noeud(cle)\nelif cle > self.valeur:\n# on ins\u00e8re \u00e0 droite\nif self.droitExiste():\n# on descend \u00e0 droite et on retente l'insertion de la cl\u00e9\nself.droit.inserer(cle)\nelse:\n # on cr\u00e9e un fils droit\nself.droit = Noeud(cle)\n
La classe ABR ci-dessous permet d'impl\u00e9menter une structure d'arbre binaire de recherche.\n\n```python linenums='1'\nclass Noeud:\n def __init__(self, valeur):\n '''M\u00e9thode constructeur pour la classe Noeud.\n Param\u00e8tre d'entr\u00e9e : valeur (str)'''\n self.valeur = valeur\n self.gauche = None\n self.droit = None\n\n def getValeur(self):\n '''M\u00e9thode accesseur pour obtenir la valeur du noeud\n Aucun param\u00e8tre en entr\u00e9e'''\n return self.valeur\n\n def droitExiste(self):\n '''M\u00e9thode renvoyant True si l'enfant droit existe\n Aucun param\u00e8tre en entr\u00e9e'''\n return (self.droit is not None)\n\n def gaucheExiste(self):\n '''M\u00e9thode renvoyant True si l'enfant gauche existe\n Aucun param\u00e8tre en entr\u00e9e'''\n return (self.gauche is not None)\n\n def inserer(self, cle):\n '''M\u00e9thode d'insertion de cl\u00e9 dans un arbre binaire de recherche\n Param\u00e8tre d'entr\u00e9e : cle (int)'''\n if cle < ...:\n # on ins\u00e8re \u00e0 gauche\n if self.gaucheExiste():\n # on descend \u00e0 gauche et on retente l'insertion de la cl\u00e9\n ...\n else:\n # on cr\u00e9e un fils gauche\n self.gauche = ...\n elif cle > ... :\n # on ins\u00e8re \u00e0 droite\n if ... :\n # on descend \u00e0 droite et on retente l'insertion de la cl\u00e9\n ...\n else:\n # on cr\u00e9e un fils droit\n ... = Noeud(cle)\n
Compl\u00e9ter la fonction r\u00e9cursive inserer
afin qu'elle permette d\u2019ins\u00e9rer un n\u0153ud dans l\u2019arbre binaire de recherche propos\u00e9, \u00e0 l\u2019aide de sa cl\u00e9.
Voici un exemple d'utilisation :
>>> arbre = Noeud(7)\n>>> for cle in (3, 9, 1, 6):\n arbre.inserer(cle)\n>>> arbre.gauche.getValeur()\n3\n>>> arbre.droit.getValeur()\n9\n>>> arbre.gauche.gauche.getValeur()\n1\n>>> arbre.gauche.droit.getValeur()\n6\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-41","title":"\u25b6 Sujet 41","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-411","title":"Exercice 41.1","text":"Exercice 41.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche(caractere, chaine)
qui prend en param\u00e8tres caractere
, un unique caract\u00e8re (c\u2019est-\u00e0-dire une cha\u00eene de caract\u00e8re de longueur 1), et chaine
, une cha\u00eene de caract\u00e8res. Cette fonction renvoie le nombre d\u2019occurrences de caractere
dans chaine
, c\u2019est-\u00e0-dire le nombre de fois o\u00f9 caractere
appara\u00eet dans chaine.
Exemples :
>>> recherche('e', \"sciences\")\n2\n>>> recherche('i',\"mississippi\")\n4\n>>> recherche('a',\"mississippi\")\n0\n
def recherche(caractere, chaine):\n somme = 0\n for lettre in chaine:\n if lettre == caractere:\n somme += 1\n return somme\n
\u00c9crire une fonction `recherche(caractere, chaine)` qui prend en param\u00e8tres\n`caractere`, un unique caract\u00e8re (c\u2019est-\u00e0-dire une cha\u00eene de caract\u00e8re de longueur 1),\net `chaine`, une cha\u00eene de caract\u00e8res. Cette fonction renvoie le nombre d\u2019occurrences\nde `caractere` dans `chaine`, c\u2019est-\u00e0-dire le nombre de fois o\u00f9 `caractere` appara\u00eet\ndans chaine.\n\nExemples :\n```python\n>>> recherche('e', \"sciences\")\n2\n>>> recherche('i',\"mississippi\")\n4\n>>> recherche('a',\"mississippi\")\n0\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-412","title":"Exercice 41.2","text":"Exercice 41.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn s\u2019int\u00e9resse \u00e0 un algorithme r\u00e9cursif qui permet de rendre la monnaie \u00e0 partir d\u2019une liste donn\u00e9e de valeurs de pi\u00e8ces et de billets.
Le syst\u00e8me mon\u00e9taire est donn\u00e9 sous forme d\u2019une liste valeurs = [100, 50, 20, 10, 5, 2, 1]
. On suppose que les pi\u00e8ces et billets sont disponibles sans limitation.
On cherche \u00e0 donner la liste des valeurs \u00e0 rendre pour une somme donn\u00e9e en argument. L\u2019algorithme utilis\u00e9 est de type glouton.
Compl\u00e9ter le code Python ci-dessous de la fonction rendu_glouton
qui impl\u00e9mente cet algorithme et renvoie la liste des pi\u00e8ces \u00e0 rendre.
valeurs = [100, 50, 20, 10, 5, 2, 1]\n\ndef rendu_glouton(a_rendre, rang):\n if a_rendre == 0:\n return ...\n v = valeurs[rang]\n if v <= ... :\n return ... + rendu_glouton(a_rendre - v, rang)\n else :\n return rendu_glouton(a_rendre, ...)\n
On devra obtenir :
>>>rendu_glouton(67, 0)\n[50, 10, 5, 2]\n>>>rendu_glouton(291, 0)\n[100, 100, 50, 20, 20, 1]\n>>> rendu_glouton(291,1) # si on ne dispose pas de billets de 100\n[50, 50, 50, 50, 50, 20, 20, 1]\n
valeurs = [100,50,20,10,5,2,1]\n\ndef rendu_glouton(a_rendre, rang):\n if a_rendre == 0:\nreturn []\nv = valeurs[rang]\nif v <= a_rendre :\nreturn [v] + rendu_glouton(a_rendre - v, rang)\nelse :\nreturn rendu_glouton(a_rendre, rang + 1)\n
On s\u2019int\u00e9resse \u00e0 un algorithme r\u00e9cursif qui permet de rendre la monnaie \u00e0 partir d\u2019une\nliste donn\u00e9e de valeurs de pi\u00e8ces et de billets.\n\nLe syst\u00e8me mon\u00e9taire est donn\u00e9 sous forme d\u2019une liste `valeurs = [100, 50, 20,\n10, 5, 2, 1]`. On suppose que les pi\u00e8ces et billets sont disponibles sans limitation.\n\n\nOn cherche \u00e0 donner la liste des valeurs \u00e0 rendre pour une somme donn\u00e9e en\nargument. L\u2019algorithme utilis\u00e9 est de type glouton.\n\nCompl\u00e9ter le code Python ci-dessous de la fonction `rendu_glouton` qui impl\u00e9mente cet\nalgorithme et renvoie la liste des pi\u00e8ces \u00e0 rendre.\n\n```python linenums='1'\nvaleurs = [100, 50, 20, 10, 5, 2, 1]\n\ndef rendu_glouton(a_rendre, rang):\n if a_rendre == 0:\n return ...\n v = valeurs[rang]\n if v <= ... :\n return ... + rendu_glouton(a_rendre - v, rang)\n else :\n return rendu_glouton(a_rendre, ...)\n
On devra obtenir :
>>>rendu_glouton(67, 0)\n[50, 10, 5, 2]\n>>>rendu_glouton(291, 0)\n[100, 100, 50, 20, 20, 1]\n>>> rendu_glouton(291,1) # si on ne dispose pas de billets de 100\n[50, 50, 50, 50, 50, 20, 20, 1]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-42","title":"\u25b6 Sujet 42","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-421","title":"Exercice 42.1","text":"Exercice 42.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction tri_selection
qui prend en param\u00e8tre une liste tab
de nombres entiers et qui renvoie la liste tri\u00e9e par ordre croissant. Il est demand\u00e9 de ne pas cr\u00e9er de nouvelle liste mais de modifier celle fournie.
On utilisera l\u2019algorithme suivant :
Exemple :
>>> tri_selection([1, 52, 6, -9, 12])\n[-9, 1, 6, 12, 52]\n
def tri_selection(tab):\n for i in range(len(tab)-1):\n indice_min = i\n for j in range(i+1, len(tab)):\n if tab[j] < tab[indice_min]:\n indice_min = j\n tab[i], tab[indice_min] = tab[indice_min], tab[i]\n return tab\n
\u00c9crire une fonction `tri_selection` qui prend en param\u00e8tre une liste `tab` de nombres\nentiers et qui renvoie la liste tri\u00e9e par ordre croissant. Il est demand\u00e9 de ne pas cr\u00e9er de\nnouvelle liste mais de modifier celle fournie.\n\nOn utilisera l\u2019algorithme suivant :\n\n- on recherche le plus petit \u00e9l\u00e9ment de la liste, en la parcourant du rang 0 au dernier\nrang, et on l'\u00e9change avec l'\u00e9l\u00e9ment d'indice 0 ;\n- on recherche ensuite le plus petit \u00e9l\u00e9ment de la liste restreinte du rang 1 au dernier\nrang, et on l'\u00e9change avec l'\u00e9l\u00e9ment d'indice 1 ;\n- on continue de cette fa\u00e7on jusqu'\u00e0 ce que la liste soit enti\u00e8rement tri\u00e9e.\n\nExemple :\n```python\n>>> tri_selection([1, 52, 6, -9, 12])\n[-9, 1, 6, 12, 52]\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-422","title":"Exercice 42.2","text":"Exercice 42.2
\u00c9nonc\u00e9CorrectionSources MarkdownLe jeu du \u00ab plus ou moins \u00bb consiste \u00e0 deviner un nombre entier choisi entre 1 et 99.
Un \u00e9l\u00e8ve de NSI d\u00e9cide de le coder en langage Python de la mani\u00e8re suivante :
La fonction randint
est utilis\u00e9e. Si a et b sont des entiers tels que a <= b
, randint(a,b)
renvoie un nombre entier compris entre a
et b
.
Compl\u00e9ter le code ci-dessous et le tester :
from random import randint\n\ndef plus_ou_moins():\n nb_mystere = randint(1,...)\n nb_test = int(input(\"Proposez un nombre entre 1 et 99 : \"))\n compteur = ...\n\n while nb_mystere != ... and compteur < ... :\n compteur = compteur + ...\n if nb_mystere ... nb_test:\n nb_test = int(input(\"Trop petit ! Testez encore : \"))\n else:\n nb_test = int(input(\"Trop grand ! Testez encore : \"))\n\n if nb_mystere == nb_test:\n print (\"Bravo ! Le nombre \u00e9tait \",...)\n print(\"Nombre d'essais: \",...)\n else:\n print (\"Perdu ! Le nombre \u00e9tait \",...)\n
from random import randint\n\ndef plus_ou_moins():\nnb_mystere = randint(1,99)\nnb_test = int(input('Proposez un nombre entre 1 et 99 : '))\ncompteur = 1\nwhile nb_mystere != nb_test and compteur < 10 :\ncompteur = compteur + 1\nif nb_mystere > nb_test:\nnb_test = int(input('Trop petit ! Testez encore : '))\n else:\n nb_test = int(input('Trop grand ! Testez encore : '))\n\n if nb_mystere == nb_test:\nprint ('Bravo ! Le nombre \u00e9tait ', nb_mystere)\nprint('Nombre d essais: ', compteur)\nelse:\nprint ('Perdu ! Le nombre \u00e9tait ', nb_mystere)\n
Le jeu du \u00ab plus ou moins \u00bb consiste \u00e0 deviner un nombre entier choisi entre 1 et 99.\n\nUn \u00e9l\u00e8ve de NSI d\u00e9cide de le coder en langage Python de la mani\u00e8re suivante :\n\n- le programme g\u00e9n\u00e8re un nombre entier al\u00e9atoire compris entre 1 et 99 ;\n- si la proposition de l\u2019utilisateur est plus petite que le nombre cherch\u00e9, l\u2019utilisateur en\nest averti. Il peut alors en tester un autre ;\n- si la proposition de l\u2019utilisateur est plus grande que le nombre cherch\u00e9, l\u2019utilisateur en\nest averti. Il peut alors en tester un autre ;\n- si l\u2019utilisateur trouve le bon nombre en 10 essais ou moins, il gagne ;\n- si l\u2019utilisateur a fait plus de 10 essais sans trouver le bon nombre, il perd.\n\nLa fonction `randint` est utilis\u00e9e. \nSi a et b sont des entiers tels que `a <= b`, `randint(a,b)` renvoie un\nnombre entier compris entre `a` et `b`.\n\n\nCompl\u00e9ter le code ci-dessous et le tester :\n\n```python linenums='1'\nfrom random import randint\n\ndef plus_ou_moins():\n nb_mystere = randint(1,...)\n nb_test = int(input(\"Proposez un nombre entre 1 et 99 : \"))\n compteur = ...\n\n while nb_mystere != ... and compteur < ... :\n compteur = compteur + ...\n if nb_mystere ... nb_test:\n nb_test = int(input(\"Trop petit ! Testez encore : \"))\n else:\n nb_test = int(input(\"Trop grand ! Testez encore : \"))\n\n if nb_mystere == nb_test:\n print (\"Bravo ! Le nombre \u00e9tait \",...)\n print(\"Nombre d'essais: \",...)\n else:\n print (\"Perdu ! Le nombre \u00e9tait \",...)\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-43","title":"\u25b6 Sujet 43","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-431","title":"Exercice 43.1","text":"Exercice 43.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction ecriture_binaire_entier_positif
qui prend en param\u00e8tre un entier positif n
et renvoie une liste d'entiers correspondant \u00e0 l\u2018\u00e9criture binaire de n
.
Ne pas oublier d\u2019ajouter au corps de la fonction une documentation et une ou plusieurs assertions pour v\u00e9rifier les pr\u00e9-conditions.
Exemples :
>>> ecriture_binaire_entier_positif(0)\n[0]\n>>> ecriture_binaire_entier_positif(2)\n[1, 0]\n>>> ecriture_binaire_entier_positif(105)\n[1, 1, 0, 1, 0, 0, 1]\n
Aide :
//
donne le quotient de la division euclidienne : 5//2
donne 2
;%
donne le reste de la division euclidienne :5%2
donne 1
;append
est une m\u00e9thode qui ajoute un \u00e9l\u00e9ment \u00e0 une liste existante : Soit T=[5,2,4]
, alors T.append(10)
ajoute 10
\u00e0 la liste T
. Ainsi, T
devient [5,2,4,10]
.reverse
est une m\u00e9thode qui renverse les \u00e9l\u00e9ments d'une liste. Soit T=[5,2,4,10]
. Apr\u00e8s T.reverse()
, la liste devient [10,4,2,5]
.On remarquera qu\u2019on r\u00e9cup\u00e8re la repr\u00e9sentation binaire d\u2019un entier n
en partant de la gauche en appliquant successivement les instructions :
b = n%2
n = n//2
r\u00e9p\u00e9t\u00e9es autant que n\u00e9cessaire.
def ecriture_binaire_entier_positif(n):\n # cas particulier pour n = 0\n if n == 0:\n return [0]\n # cas g\u00e9n\u00e9ral\n b = []\n while n != 0:\n b.append(n % 2)\n n = n // 2\n b.reverse()\n return b\n
\u00c9crire une fonction `ecriture_binaire_entier_positif` qui prend en param\u00e8tre un\nentier positif `n` et renvoie une liste d'entiers correspondant \u00e0 l\u2018\u00e9criture binaire de `n`.\n\nNe pas oublier d\u2019ajouter au corps de la fonction une documentation et une ou plusieurs\nassertions pour v\u00e9rifier les pr\u00e9-conditions.\n\nExemples :\n\n```python\n>>> ecriture_binaire_entier_positif(0)\n[0]\n>>> ecriture_binaire_entier_positif(2)\n[1, 0]\n>>> ecriture_binaire_entier_positif(105)\n[1, 1, 0, 1, 0, 0, 1]\n```\n\nAide :\n\n- l'op\u00e9rateur `//` donne le quotient de la division euclidienne : `5//2` donne `2` ;\n- l'op\u00e9rateur `%` donne le reste de la division euclidienne :` 5%2` donne `1` ;\n- `append` est une m\u00e9thode qui ajoute un \u00e9l\u00e9ment \u00e0 une liste existante :\nSoit `T=[5,2,4]`, alors `T.append(10)` ajoute `10` \u00e0 la liste `T`. Ainsi, `T` devient\n`[5,2,4,10]`.\n- `reverse` est une m\u00e9thode qui renverse les \u00e9l\u00e9ments d'une liste.\nSoit `T=[5,2,4,10]`. Apr\u00e8s `T.reverse()`, la liste devient `[10,4,2,5]`.\n\nOn remarquera qu\u2019on r\u00e9cup\u00e8re la repr\u00e9sentation binaire d\u2019un entier `n` en partant de la gauche en appliquant successivement les instructions :\n\n`b = n%2`\n\n`n = n//2`\n\nr\u00e9p\u00e9t\u00e9es autant que n\u00e9cessaire.\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-432","title":"Exercice 43.2","text":"Exercice 43.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa fonction tri_bulles
prend en param\u00e8tre une liste T
d\u2019entiers non tri\u00e9s et renvoie la liste tri\u00e9e par ordre croissant.
Le tri \u00e0 bulles est un tri en place qui commence par placer le plus grand \u00e9l\u00e9ment en derni\u00e8re position en parcourant la liste de gauche \u00e0 droite et en \u00e9changeant au passage les \u00e9l\u00e9ments voisins mal ordonn\u00e9s (si la valeur de l\u2019\u00e9l\u00e9ment d\u2019indice i
a une valeur strictement sup\u00e9rieure \u00e0 celle de l\u2019indice i + 1
, ils sont \u00e9chang\u00e9s). Le tri place ensuite en avant-derni\u00e8re position le plus grand \u00e9l\u00e9ment de la liste priv\u00e9e de son dernier \u00e9l\u00e9ment en proc\u00e9dant encore \u00e0 des \u00e9changes d\u2019\u00e9l\u00e9ments voisins. Ce principe est r\u00e9p\u00e9t\u00e9 jusqu\u2019\u00e0 placer le minimum en premi\u00e8re position.
Exemple : pour trier la liste [7, 9, 4, 3]
:
[7, 4, 3, 9]
[4, 3, 7, 9]
[3, 4, 7, 9]
Compl\u00e9ter le code Python ci-dessous qui impl\u00e9mente la fonction tri_bulles.
def tri_bulles(T):\n'''\n Renvoie le tableau T tri\u00e9 par ordre croissant\n '''\n n = len(T)\n for i in range(...,...,-1):\n for j in range(i):\n if T[j] > T[...]:\n ... = T[j]\n T[j] = T[...]\n T[j+1] = temp\n return T\n
Exemples :
>>> tri_bulles([])\n[]\n>>> tri_bulles([7])\n[7]\n>>> tri_bulles([9, 3, 7, 2, 3, 1, 6])\n[1, 2, 3, 3, 6, 7, 9]\n>>> tri_bulles([9, 7, 4, 3])\n[3, 4, 7, 9]\n
def tri_bulles(T):\n'''\n Renvoie le tableau T tri\u00e9 par ordre croissant\n '''\n n = len(T)\nfor i in range(n-1,-1,-1):\nfor j in range(i):\nif T[j] > T[j+1]:\ntemp = T[j]\nT[j] = T[j+1]\nT[j+1] = temp\n return T\n
La fonction `tri_bulles` prend en param\u00e8tre une liste `T` d\u2019entiers non tri\u00e9s et renvoie la\nliste tri\u00e9e par ordre croissant.\n\n\nLe tri \u00e0 bulles est un tri en place qui commence par placer le plus grand \u00e9l\u00e9ment en\nderni\u00e8re position en parcourant la liste de gauche \u00e0 droite et en \u00e9changeant au passage\nles \u00e9l\u00e9ments voisins mal ordonn\u00e9s (si la valeur de l\u2019\u00e9l\u00e9ment d\u2019indice `i` a une valeur\nstrictement sup\u00e9rieure \u00e0 celle de l\u2019indice `i + 1`, ils sont \u00e9chang\u00e9s). Le tri place ensuite\nen avant-derni\u00e8re position le plus grand \u00e9l\u00e9ment de la liste priv\u00e9e de son dernier \u00e9l\u00e9ment\nen proc\u00e9dant encore \u00e0 des \u00e9changes d\u2019\u00e9l\u00e9ments voisins. Ce principe est r\u00e9p\u00e9t\u00e9 jusqu\u2019\u00e0\nplacer le minimum en premi\u00e8re position.\n\n\nExemple : pour trier la liste `[7, 9, 4, 3]` :\n\n- premi\u00e8re \u00e9tape : 7 et 9 ne sont pas \u00e9chang\u00e9s, puis 9 et 4 sont \u00e9chang\u00e9s, puis 9 et\n3 sont \u00e9chang\u00e9s, la liste est alors `[7, 4, 3, 9]`\n- deuxi\u00e8me \u00e9tape : 7 et 4 sont \u00e9chang\u00e9s, puis 7 et 3 sont \u00e9chang\u00e9s, la liste est\nalors `[4, 3, 7, 9]`\n- troisi\u00e8me \u00e9tape : 4 et 3 sont \u00e9chang\u00e9s, la liste est alors `[3, 4, 7, 9]`\n\n\nCompl\u00e9ter le code Python ci-dessous qui impl\u00e9mente la fonction tri_bulles.\n\n```python linenums='1'\ndef tri_bulles(T):\n '''\n Renvoie le tableau T tri\u00e9 par ordre croissant\n '''\n n = len(T)\n for i in range(...,...,-1):\n for j in range(i):\n if T[j] > T[...]:\n ... = T[j]\n T[j] = T[...]\n T[j+1] = temp\n return T\n
Exemples :
>>> tri_bulles([])\n[]\n>>> tri_bulles([7])\n[7]\n>>> tri_bulles([9, 3, 7, 2, 3, 1, 6])\n[1, 2, 3, 3, 6, 7, 9]\n>>> tri_bulles([9, 7, 4, 3])\n[3, 4, 7, 9]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-44","title":"\u25b6 Sujet 44","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-441","title":"Exercice 44.1","text":"Exercice 44.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer une fonction renverse
, prenant en param\u00e8tre une cha\u00eene de caract\u00e8res non vide mot
et renvoie une cha\u00eene de caract\u00e8res en inversant ceux de la cha\u00eene mot
.
Exemple :
>>> renverse(\"informatique\")\n\"euqitamrofni\"\n
def renverse(mot):\n sol = ''\n for lettre in mot:\n sol = lettre + sol\n return sol\n
Programmer une fonction `renverse`, prenant en param\u00e8tre une cha\u00eene de caract\u00e8res non vide\n`mot` et renvoie une cha\u00eene de caract\u00e8res en inversant ceux de la cha\u00eene `mot`.\n\nExemple :\n\n```python\n>>> renverse(\"informatique\")\n\"euqitamrofni\"\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-442","title":"Exercice 44.2","text":"Exercice 44.2
\u00c9nonc\u00e9CorrectionSources MarkdownUn nombre premier est un nombre entier naturel qui admet exactement deux diviseurs distincts entiers et positifs : 1 et lui-m\u00eame.
Le crible d\u2019\u00c9ratosth\u00e8ne permet de d\u00e9terminer les nombres premiers plus petit qu\u2019un certain nombre n
fix\u00e9.
On consid\u00e8re pour cela un tableau tab
de n
bool\u00e9ens, initialement tous \u00e9gaux \u00e0 True
, sauf tab[0]
et tab[1]
qui valent False
, 0 et 1 n\u2019\u00e9tant pas des nombres premiers.
On parcourt alors ce tableau de gauche \u00e0 droite.
Pour chaque indice i
:
si tab[i]
vaut True
: le nombre i
est premier et on donne la valeur False
\u00e0 toutes les cases du tableau dont l\u2019indice est un multiple de i
, \u00e0 partir de 2*i
(c\u2019est-\u00e0-dire 2*i
, 3*i
...).
si tab[i]
vaut False
: le nombre i
n\u2019est pas premier et on n\u2019effectue aucun changement sur le tableau.
On dispose de la fonction crible
, incompl\u00e8te et donn\u00e9e ci-dessous, prenant en param\u00e8tre un entier n
strictement positif et renvoyant un tableau contenant tous les nombres premiers plus petits que n
.
def crible(n):\n\"\"\"\n Renvoie un tableau contenant tous les nombres premiers plus petits que N\n \"\"\"\n premiers = []\n tab = [True] * n\n tab[0], tab[1] = False, False\n for i in range(..., n):\n if tab[i] == ...:\n premiers.append(...)\n for multiple in range(2*i, n, ...):\n tab[multiple] = ...\n return premiers\n\nassert crible(40) == [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]\n
Compl\u00e9ter le code de cette fonction.
def crible(n):\n\"\"\"\n Renvoie un tableau contenant tous les nombres premiers plus petits que N\n \"\"\"\n premiers = []\n tab = [True] * n\n tab[0], tab[1] = False, False\nfor i in range(2, n):\nif tab[i] == True:\npremiers.append(i)\nfor multiple in range(2*i, n, i):\ntab[multiple] = False\nreturn premiers\n\nassert crible(40) == [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]\n
Un nombre premier est un nombre entier naturel qui admet exactement deux diviseurs distincts\nentiers et positifs : 1 et lui-m\u00eame. \n\nLe crible d\u2019\u00c9ratosth\u00e8ne permet de d\u00e9terminer les nombres premiers plus petit qu\u2019un certain\nnombre `n` fix\u00e9. \n\nOn consid\u00e8re pour cela un tableau `tab` de `n`bool\u00e9ens, initialement tous \u00e9gaux \u00e0 `True`, sauf\n`tab[0]` et `tab[1]` qui valent `False`, 0 et 1 n\u2019\u00e9tant pas des nombres premiers. \n\nOn parcourt alors ce tableau de gauche \u00e0 droite. \n\nPour chaque indice `i` :\n\n- si `tab[i]` vaut `True` : le nombre `i` est premier et on donne la valeur `False` \u00e0 toutes les\ncases du tableau dont l\u2019indice est un multiple de `i`, \u00e0 partir de `2*i` (c\u2019est-\u00e0-dire `2*i`, `3*i` ...).\n\n- si `tab[i]` vaut `False` : le nombre `i` n\u2019est pas premier et on n\u2019effectue aucun\nchangement sur le tableau. \n\nOn dispose de la fonction `crible`, incompl\u00e8te et donn\u00e9e ci-dessous, prenant en param\u00e8tre un\nentier `n` strictement positif et renvoyant un tableau contenant tous les nombres premiers plus\npetits que `n`.\n\n```python linenums='1'\ndef crible(n):\n \"\"\"\n Renvoie un tableau contenant tous les nombres premiers plus petits que N\n \"\"\"\n premiers = []\n tab = [True] * n\n tab[0], tab[1] = False, False\n for i in range(..., n):\n if tab[i] == ...:\n premiers.append(...)\n for multiple in range(2*i, n, ...):\n tab[multiple] = ...\n return premiers\n\nassert crible(40) == [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]\n
Compl\u00e9ter le code de cette fonction.
```
Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-45","title":"\u25b6 Sujet 45","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-451","title":"Exercice 45.1","text":"Exercice 45.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn veut trier par ordre croissant les notes d\u2019une \u00e9valuation qui sont des nombres entiers compris entre 0 et 10 (inclus).
Ces notes sont contenues dans une liste notes_eval
.
\u00c9crire une fonction rangement_valeurs
prenant en param\u00e8tre la liste notes_eval
et renvoyant une liste de longueur 11 telle que la valeur de cette liste \u00e0 chaque rang est \u00e9gale au nombre de notes valant ce rang. Ainsi le terme de rang 0 indique le nombre de note 0, le terme de rang 1 le nombre de note 1, etc.
\u00c9crire ensuite une fonction notes_triees
prenant en param\u00e8tre la liste des effectifs des notes et renvoyant une liste contenant la liste, tri\u00e9e dans l\u2019ordre croissant, des notes des \u00e9l\u00e8ves.
Exemple :
>>> notes_eval = [2, 0, 5, 9, 6, 9, 10, 5, 7, 9, 9, 5, 0, 9, 6, 5, 4]\n\n>>> effectifs_notes = rangement_valeurs(notes_eval)\n>>> effectifs_notes\n[2, 0, 1, 0, 1, 4, 2, 1, 0, 5, 1]\n\n>>> notes_triees(effectifs_notes)\n[0, 0, 2, 4, 5, 5, 5, 5, 6, 6, 7, 9, 9, 9, 9, 9, 10]\n
def rangement_valeurs(notes_eval):\n lst = [0]*11\n for note in notes_eval:\n lst[note] += 1\n return lst\n\ndef notes_triees(effectifs_notes):\n triees = []\n for i in range(11):\n if effectifs_notes[i] != 0:\n for _ in range(effectifs_notes[i]):\n triees.append(i)\n return triees\n
On veut trier par ordre croissant les notes d\u2019une \u00e9valuation qui sont des nombres entiers\ncompris entre 0 et 10 (inclus).\n\nCes notes sont contenues dans une liste `notes_eval`.\n\n\u00c9crire une fonction `rangement_valeurs` prenant en param\u00e8tre la liste `notes_eval` et\nrenvoyant une liste de longueur 11 telle que la valeur de cette liste \u00e0 chaque rang est\n\u00e9gale au nombre de notes valant ce rang. Ainsi le terme de rang 0 indique le nombre de\nnote 0, le terme de rang 1 le nombre de note 1, etc.\n\n\u00c9crire ensuite une fonction `notes_triees` prenant en param\u00e8tre la liste des effectifs\ndes notes et renvoyant une liste contenant la liste, tri\u00e9e dans l\u2019ordre croissant, des notes\ndes \u00e9l\u00e8ves.\n\nExemple :\n\n```python\n>>> notes_eval = [2, 0, 5, 9, 6, 9, 10, 5, 7, 9, 9, 5, 0, 9, 6, 5, 4]\n\n>>> effectifs_notes = rangement_valeurs(notes_eval)\n>>> effectifs_notes\n[2, 0, 1, 0, 1, 4, 2, 1, 0, 5, 1]\n\n>>> notes_triees(effectifs_notes)\n[0, 0, 2, 4, 5, 5, 5, 5, 6, 6, 7, 9, 9, 9, 9, 9, 10]\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-452","title":"Exercice 45.2","text":"Exercice 45.2
\u00c9nonc\u00e9CorrectionSources MarkdownL\u2019objectif de cet exercice est d\u2019\u00e9crire deux fonctions r\u00e9cursives dec_to_bin
et bin_to_dec
assurant respectivement la conversion de l\u2019\u00e9criture d\u00e9cimale d\u2019un nombre entier vers son \u00e9criture en binaire et, r\u00e9ciproquement, la conversion de l\u2019\u00e9criture en binaire d\u2019un nombre vers son \u00e9criture d\u00e9cimale.
Dans cet exercice, on s\u2019interdit l\u2019usage des fonctions Python bin
et int
.
On rappelle sur l\u2019exemple ci-dessous une fa\u00e7on d\u2019obtenir l\u2019\u00e9criture en binaire du nombre 25 :
\\(25 = 1 + 2 \\times 12\\) \\(\\phantom{25} = 1 + 2 \\times 12\\) \\(\\phantom{25} = 1 + 2 (0 + 2 \\times 6)\\) \\(\\phantom{25} = 1 + 2 (0 + 2 (0 + 2 \\times 3))\\) \\(\\phantom{25} = 1 + 2 (0 + 2 (0 + 2 (1 + 2 \\times 1)))\\) \\(\\phantom{25} = 1 \\times 2^0 + 0 \\times 2^1 + 0 \\times 2^2 + 1 \\times 2^3 + 1 \\times 2^4\\)
L'\u00e9criture binaire de 25 est donc 11001
.
0n rappelle \u00e9galement que :
a // 2
renvoie le quotient de la division euclidienne de a
par 2.a % 2
renvoie le reste dans la division euclidienne de a
par 2.On indique enfin qu\u2019en Python si mot = \"informatique\"
alors :
mot[-1]
renvoie 'e'
, c\u2019est-\u00e0-dire le dernier caract\u00e8re de la cha\u00eene de caract\u00e8res mot
.mot[:-1]
renvoie 'informatiqu'
, c\u2019est-\u00e0-dire l\u2019ensemble de la cha\u00eene de caract\u00e8res mot
priv\u00e9e de son dernier caract\u00e8re.Compl\u00e9ter, puis tester, les codes de deux fonctions ci-dessous. On pr\u00e9cise que la fonction r\u00e9cursive dec_to_bin
prend en param\u00e8tre un nombre entier et renvoie une cha\u00eene de caract\u00e8res contenant l\u2019\u00e9criture en binaire du nombre pass\u00e9 en param\u00e8tre.
Exemple :
>>> dec_to_bin(25)\n'11001'\n
La fonction r\u00e9cursive bin_to_dec
prend en param\u00e8tre une cha\u00eene de caract\u00e8res repr\u00e9sentant l\u2019\u00e9criture d\u2019un nombre en binaire et renvoie l\u2019\u00e9criture d\u00e9cimale de ce nombre.
>>> bin_to_dec('101010')\n42\n
def dec_to_bin(nb_dec):\n q, r = nb_dec // 2, nb_dec % 2\n if q == ...:\n return str(r)\n else:\n return dec_to_bin(...) + ...\n\ndef bin_to_dec(nb_bin):\n if nb_bin == '0':\n return 0\n elif ...:\n return 1\n else:\n if nb_bin[-1] == '0':\n bit_droit = 0\n else:\n bit_droit = ...\n return ... * bin_to_dec(nb_bin[:-1]) + ...\n
def dec_to_bin(nb_dec):\n q, r = nb_dec // 2, nb_dec % 2\nif q == 0:\nreturn str(r)\n else:\nreturn dec_to_bin(q) + str(r)\ndef bin_to_dec(nb_bin):\n if nb_bin == '0':\n return 0\nelif nb_bin == '1':\nreturn 1\n else:\n if nb_bin[-1] == '0':\n bit_droit = 0\n else:\nbit_droit = 1\nreturn 2 * bin_to_dec(nb_bin[:-1]) + bit_droit\n
L\u2019objectif de cet exercice est d\u2019\u00e9crire deux fonctions r\u00e9cursives `dec_to_bin` et\n`bin_to_dec` assurant respectivement la conversion de l\u2019\u00e9criture d\u00e9cimale d\u2019un nombre\nentier vers son \u00e9criture en binaire et, r\u00e9ciproquement, la conversion de l\u2019\u00e9criture en\nbinaire d\u2019un nombre vers son \u00e9criture d\u00e9cimale.\n\nDans cet exercice, on s\u2019interdit l\u2019usage des fonctions Python `bin` et `int`.\n\nOn rappelle sur l\u2019exemple ci-dessous une fa\u00e7on d\u2019obtenir l\u2019\u00e9criture en binaire du\nnombre 25 :\n\n$25 = 1 + 2 \\times 12$ \n$\\phantom{25} = 1 + 2 \\times 12$ \n$\\phantom{25} = 1 + 2 (0 + 2 \\times 6)$ \n$\\phantom{25} = 1 + 2 (0 + 2 (0 + 2 \\times 3))$ \n$\\phantom{25} = 1 + 2 (0 + 2 (0 + 2 (1 + 2 \\times 1)))$ \n$\\phantom{25} = 1 \\times 2^0 + 0 \\times 2^1 + 0 \\times 2^2 + 1 \\times 2^3 + 1 \\times 2^4$ \n\nL'\u00e9criture binaire de 25 est donc ```11001```.\n\n0n rappelle \u00e9galement que :\n\n- `a // 2` renvoie le quotient de la division euclidienne de `a` par 2.\n- ` a % 2` renvoie le reste dans la division euclidienne de `a` par 2.\n\nOn indique enfin qu\u2019en Python si `mot = \"informatique\"` alors :\n\n- `mot[-1]` renvoie `'e'`, c\u2019est-\u00e0-dire le dernier caract\u00e8re de la cha\u00eene de caract\u00e8res `mot`.\n- `mot[:-1]` renvoie `'informatiqu'` , c\u2019est-\u00e0-dire l\u2019ensemble de la cha\u00eene de\ncaract\u00e8res `mot` priv\u00e9e de son dernier caract\u00e8re.\n\nCompl\u00e9ter, puis tester, les codes de deux fonctions ci-dessous. \nOn pr\u00e9cise que la fonction r\u00e9cursive `dec_to_bin` prend en param\u00e8tre un nombre entier\net renvoie une cha\u00eene de caract\u00e8res contenant l\u2019\u00e9criture en binaire du nombre pass\u00e9 en\nparam\u00e8tre.\n\nExemple :\n\n```python\n>>> dec_to_bin(25)\n'11001'\n
La fonction r\u00e9cursive bin_to_dec
prend en param\u00e8tre une cha\u00eene de caract\u00e8res repr\u00e9sentant l\u2019\u00e9criture d\u2019un nombre en binaire et renvoie l\u2019\u00e9criture d\u00e9cimale de ce nombre.
>>> bin_to_dec('101010')\n42\n
def dec_to_bin(nb_dec):\n q, r = nb_dec // 2, nb_dec % 2\n if q == ...:\n return str(r)\n else:\n return dec_to_bin(...) + ...\n\ndef bin_to_dec(nb_bin):\n if nb_bin == '0':\n return 0\n elif ...:\n return 1\n else:\n if nb_bin[-1] == '0':\n bit_droit = 0\n else:\n bit_droit = ...\n return ... * bin_to_dec(nb_bin[:-1]) + ...\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_Annales/epreuve_bac/","title":"\u00c9preuves du baccalaur\u00e9at","text":""},{"location":"T6_Annales/epreuve_bac/#modalites","title":"Modalit\u00e9s","text":"L'\u00e9preuve se partage en :
Pour r\u00e9sumer, on peut donc dire que la note sur 20 au bacaccalaur\u00e9at en NSI est constitu\u00e9e de 15 points d'\u00e9preuve \u00e9crite et de 5 points d'\u00e9preuve pratique.
"},{"location":"T6_Annales/epreuve_bac/#epreuve-pratique","title":"\u00c9preuve Pratique","text":"Textes r\u00e8glementaires
La partie pratique consiste en la r\u00e9solution de deux exercices sur ordinateur, chacun \u00e9tant not\u00e9 sur 10 points.
Le candidat est \u00e9valu\u00e9 sur la base d\u2019un dialogue avec un professeur-examinateur. Un examinateur \u00e9value au maximum quatre \u00e9l\u00e8ves. L\u2019examinateur ne peut pas \u00e9valuer un \u00e9l\u00e8ve qu\u2019il a eu en classe durant l\u2019ann\u00e9e en cours. L\u2019\u00e9valuation de cette partie se d\u00e9roule au cours du deuxi\u00e8me trimestre pendant la p\u00e9riode de l\u2019\u00e9preuve \u00e9crite de sp\u00e9cialit\u00e9.
Premier exercice
Le premier exercice consiste \u00e0 programmer un algorithme figurant explicitement au programme, ne pr\u00e9sentant pas de difficult\u00e9 particuli\u00e8re, dont on fournit une sp\u00e9cification. Il s\u2019agit donc de restituer un algorithme rencontr\u00e9 et travaill\u00e9 \u00e0 plusieurs reprises en cours de formation. Le sujet peut proposer un jeu de test avec les r\u00e9ponses attendues pour permettre au candidat de v\u00e9rifier son travail.
Deuxi\u00e8me exercice
Pour le second exercice, un programme est fourni au candidat. Cet exercice ne demande pas l\u2019\u00e9criture compl\u00e8te d\u2019un programme, mais permet de valider des comp\u00e9tences de programmation suivant des modalit\u00e9s vari\u00e9es : le candidat doit, par exemple, compl\u00e9ter un programme \u00ab \u00e0 trous \u00bb afin de r\u00e9pondre \u00e0 une sp\u00e9cification donn\u00e9e, ou encore compl\u00e9ter un programme pour le documenter, ou encore compl\u00e9ter un programme en ajoutant des assertions, etc.
"},{"location":"T6_Annales/epreuve_bac/#banque-dexercices","title":"Banque d'exercices","text":"Textes r\u00e8glementaires
Une page sp\u00e9cifique consacr\u00e9e aux exercices de la BNS est disponible ici.
"},{"location":"T6_Annales/epreuve_bac/#epreuve-ecrite","title":"\u00c9preuve \u00c9crite","text":"\u00c0 compter de la session 2023, l'\u00e9preuve consiste en trois exercices qui doivent tous \u00eatre trait\u00e9s. L'\u00e9preuve \u00e9crite donne lieu \u00e0 une note sur 20 points, coefficient 0.75.
Textes r\u00e8glementaires
Les annales des sujets pass\u00e9s (2020, 2021, 2022) comportent tous 5 exercices dont seulement 3 devaient \u00eatre trait\u00e9s. Ce n'est plus le cas depuis la session 2023 o\u00f9 la totalit\u00e9 du sujet doit \u00eatre trait\u00e9.
"},{"location":"T6_Annales/liste_sujets/","title":"Annales des \u00c9preuves \u00c9crites","text":""},{"location":"T6_Annales/liste_sujets/#2023","title":"2023","text":"Sujet
"},{"location":"T6_Annales/corrections/2022/corr_AmSudJ2_2022/#exercice-1","title":"Exercice 1","text":"Correction Q1def plus_proche_voisin(t, cible) :\n dmin = distance(t[0], cible)\n idx_ppv = 0\n n = len(t)\n for idx in range(1, n) :\nif distance(t[idx], cible) < dmin:\ndmin = distance(t[idx], cible)\nidx_ppv = idx\nreturn idx_ppv\n
Correction Q2 La complexit\u00e9 est lin\u00e9aire, car le nombre d'op\u00e9rations est proportionnel \u00e0 la taille du tableau t
.
Il suffit d'ins\u00e9rer la ligne dist = distance(obj, cible)
en dessous de la boucle for
et d'utiliser cette variable dist
partout \u00e0 la place de distance(obj, cible)
.
La complexit\u00e9 (m\u00eame r\u00e9p\u00e9t\u00e9e) d'une op\u00e9ration d'insertion d'un seul \u00e9l\u00e9ment \u00e0 sa bonne place dans une liste est moindre que celle d'un tri global. (NDLR : pas s\u00fbr)
Correction Q3.cdef insertion(kppv, idx, d):\n i = 0\n while d < kppv[i][1] and i < len(kppv):\n i += 1\n kppv.insert(i, (idx, d)) \n
"},{"location":"T6_Annales/corrections/2022/corr_AmSudJ2_2022/#exercice-2","title":"Exercice 2","text":""},{"location":"T6_Annales/corrections/2022/corr_AmSudJ2_2022/#partie-a","title":"Partie A","text":"Correction Q1 ifconfig
DHCP
(NDLR : question hors-programme)
192.168.1.1
C\u2019est possible et cette adresse serait celle de la box vers Internet.
Correction Q5Oui, car les adresses 192.168.x.x ne sont pas rout\u00e9es sur Internet.
"},{"location":"T6_Annales/corrections/2022/corr_AmSudJ2_2022/#partie-b","title":"Partie B","text":"Correction Q1\\(C = \\dfrac{10^9}{50 \\times 10^6}=\\dfrac{1000}{50}=20\\)
Correction Q2.a. Correction Q2.b.Suivant le protocole OSPF, il faut minimiser le co\u00fbt total. Il faut pour cela suivre le chemin R1-R3-R6-R7-R4-R5-R8, pour un co\u00fbt total de 80.
Correction Q3.c.Pour que le protocole OSPF fasse passer par la liaison R1-R4, il faut que celle-ci ait un co\u00fbt inf\u00e9rieur \u00e0 la liaison actuelle R1-R3-R6-R7-R4, qui a un co\u00fbt de 40. Il faut donc que le co\u00fbt R1-R4 soit inf\u00e9rieur \u00e0 40, ce qui sera le cas pour une bande passante sup\u00e9rieure \u00e0 25 Mb/s (car \\(\\dfrac{10^9}{25 \\times 10^6}=40\\))
"},{"location":"T6_Annales/corrections/2022/corr_AmSudJ2_2022/#exercice-3","title":"Exercice 3","text":"Correction Q1UPDATE ModeleVelo\nSET Stock = 0\nWHERE nomModele = \"Bovelo\";\n
Correction Q2 Il faut effectuer d'abord la requ\u00eate 4 (qui d\u00e9clare le nouveau fabricant, qui aura pour idFabricant
3127), puis la requ\u00eate 2 (o\u00f9 on peut retrouver l'id 3127).
SELECT nomModele, idFabricant\nFROM ModeleVelo\nWHERE Stock = 0;\n
Correction Q3.b. SELECT COUNT(numeroCommande)\nFROM Commande\nWHERE date >= '2022-01-01';\n
Correction Q3.c. SELECT Fabricant.nom\nFROM Fabricant\nJOIN ModeleVelo ON Fabricant.idFabricant = ModeleVelo.idFabricant\nWHERE ModeleVelo.Stock > 0\n
Correction Q4. Cette requ\u00eate permet d'obtenir le nom de tous les clients ayant achet\u00e9 le mod\u00e8le de v\u00e9lo \"Bovelo\". Si certains l'ont achet\u00e9 en plusieurs exemplaires, leur nom n'apparaitra qu'une seule fois.
"},{"location":"T6_Annales/corrections/2022/corr_AmSudJ2_2022/#exercice-4","title":"Exercice 4","text":"Correction Q1.a.from math import sqrt\n
Correction Q1.b. def distance_points(a, b):\n return sqrt((b[0]-a[0])**2 + (b[1]-a[1])**2)\n
Correction Q2. def distance(p, a, b):\n if a == b:\n return distance_points(p, a)\n else:\n return distance_point_droite(p, a, b)\n
Correction Q3. def le_plus_loin(ligne):\n n = len(ligne)\n deb = ligne[0]\n fin = ligne[n-1]\n dmax = 0\n indice_max = 0\n for idx in range(1, n-1):\np = ligne[idx]\nd = distance(p, deb, fin)\nif d > dmax:\ndmax = d\nindice_max = idx\nreturn (indice_max, dmax)\n
Correction Q4. def extrait(tab, i, j):\n ext = []\n for k in range(i, j+1):\n ext.append(tab[k])\n return ext\n
Correction Q5. def simplifie(ligne, seuil):\n n = len(ligne)\n if n <= 2:\n return ligne\n else:\n indice_max, dmax = le_plus_loin(ligne)\n if dmax <= seuil:\n return [ligne[0], ligne[n-1]]\n else:\n return simplifie(extrait(ligne, 0, indice_max), seuil) + \\\n simplifie(extrait(ligne, indice_max+1, n-1), seuil)\n
"},{"location":"T6_Annales/corrections/2022/corr_AmSudJ2_2022/#mise-en-pratique-de-lalgorithme-de-douglas-peucker-exercice-4","title":"Mise en pratique de l'algorithme de Douglas-Peucker (exercice 4)","text":"T\u00e9l\u00e9chargez d'abord le fichier coord_france.txt puis placez-le dans le m\u00eame dossier que le code Python ci-dessous :
from math import sqrt\nimport matplotlib.pyplot as plt\n\ndata = open('coord_france.txt').read().splitlines()\nfrance = []\nfor couple in data:\n cpl = couple.split(',')\n france.append((int(cpl[0]), int(cpl[1])))\n\ndef distance_points(a, b):\n return sqrt((b[0]-a[0])**2 + (b[1]-a[1])**2)\n\ndef distance_point_droite(p, a, b):\n if b[0] == a[0]:\n return abs(p[0]-a[0])\n m = (b[1] - a[1]) / (b[0] - a[0])\n od = a[1] - m*a[0]\n xm = (p[0]*(b[0]-a[0])+(p[1]-od)*(b[1]-a[1])) / (b[0]-a[0] + m*(b[1]-a[1]))\n ym = m*xm + od\n return distance_points(p, (xm, ym)) \n\ndef distance(p, a, b):\n if a == b:\n return distance_points(p, a)\n else:\n return distance_point_droite(p, a, b)\n\ndef le_plus_loin(ligne):\n n = len(ligne)\n deb = ligne[0]\n fin = ligne[n-1]\n dmax = 0\n indice_max = 0\n for idx in range(1, n-1):\n p = ligne[idx]\n d = distance(p, deb, fin)\n if d > dmax:\n dmax = d\n indice_max = idx\n return (indice_max, dmax)\n\n\ndef extrait(tab, i, j):\n ext = []\n for k in range(i, j+1):\n ext.append(tab[k])\n return ext\n\ndef simplifie(ligne, seuil):\n n = len(ligne)\n if n <= 2:\n return ligne\n else:\n indice_max, dmax = le_plus_loin(ligne)\n if dmax <= seuil:\n return [ligne[0], ligne[n-1]]\n else:\n return simplifie(extrait(ligne, 0, indice_max), seuil) + \\\n simplifie(extrait(ligne, indice_max+1, n-1), seuil)\n\n\ndef trace(ligne, seuil):\n new_ligne = simplifie(ligne, seuil)\n x = [p[0] for p in new_ligne]\n y = [p[1] for p in new_ligne]\n plt.plot(x, y, 'b-', linewidth=0.5)\n plt.text(195014, 2865745, 'seuil : ' + str(seuil))\n plt.axis('equal')\n plt.axis('off')\n plt.show()\n\ntrace(france, 0)\n
Le rendu avec un seuil \u00e9gal \u00e0 0 est celui-ci :
Vous pouvez faire varier le seuil entre 0 et 5000 et observer les modifications.
"},{"location":"T6_Annales/corrections/2022/corr_AmSudJ2_2022/#exercice-5","title":"Exercice 5","text":"Correction Q1La plus grande somme est 16, via la branche 2-7-4-3.
Correction Q2.a.a = Noeud(2)\na.modifier_sag(Noeud(7))\na.modifier_sad(Noeud(5))\na.sag.modifier_sag(Noeud(4))\na.sag.modifier_sad(Noeud(1))\na.sad.modifier_sad(Noeud(8))\n
Correction Q2.b. La m\u00e9thode niveau
renvoie 2 (qui est la hauteur de cet arbre, en prenant la convention que l'arbre r\u00e9duit \u00e0 son n\u0153ud-racine a une hauteur de 0).
def pgde_somme(self):\n if self.sag != None and self.sad != None:\n pgde_g = self.sag.pgde_somme()\n pgde_d = self.sad.pgde_somme()\n return self.etiquette + max(pgde_g, pgde_d)\n\n if self.sag != None:\n return self.sag.pgde_somme() + self.etiquette\n if self.sad != None:\n return self.sad.pgde_somme() + self.etiquette\n return self.etiquette \n
Correction Q4.a. Correction Q4.b. def est_magique(self):\n if self.sag != None and self.sad != None:\n return self.sag.est_magique() and self.sad.est_magique() \\\n and self.sag.pgde_somme() == self.sad.pgde_somme()\n if self.sag != None:\n return self.sag.est_magique()\n if self.sad != None:\n return self.sad.est_magique()\n return True \n
"},{"location":"T6_Annales/corrections/2023/corr_sujet0_A/","title":"Correction du sujet 0 version A / 2023","text":"Sujet
"},{"location":"T6_Annales/corrections/2023/corr_sujet0_A/#exercice-1","title":"Exercice 1","text":"correction Q1.Les attributs de la table groupes
sont idgrp
, nom
, style
et nb_pers
.
Le musicien Charlie Parker est pr\u00e9sent 2 fois dans cette table (avec deux instruments diff\u00e9rents). L'attribut nom
ne peut donc pas \u00eatre une cl\u00e9 primaire, qui doit \u00eatre unique.
Cette requ\u00eate renvoie 'Weather Report'
et 'Return to Forever'
.
UPDATE concerts\nSET heure_fin = '22h30'\nWHERE idconc = 36;\n
Correction Q5. SELECT groupes.nom\nFROM groupes\nJOIN concerts ON concerts.idgrp = groupes.idgrp\nWHERE concerts.scene = 1;\n
Correction Q6. INSERT INTO groupes\nVALUES (15, 'Smooth Jazz Fourplay', 'Free Jazz', 4);\n
Correction Q7. def recherche_nom(tab_mus):\n lst = []\n for mus in tab_mus:\n if mus['nb_concerts'] >= 4:\n lst.append(mus['nom'])\n return lst\n
"},{"location":"T6_Annales/corrections/2023/corr_sujet0_A/#exercice-2","title":"Exercice 2","text":"correction Q1. Cet ordinateur appartient \u00e0 Alice car il fait partie du r\u00e9seau 172.16.2.0/24
. Le masque en /24
nous indique que ce r\u00e9seau contiendra des adresses de type 172.16.2.X
, ce qui est bien le cas de l'adresse 172.16.2.3
.
\\(C=\\dfrac{10000}{1000}=10\\).
Correction Q3.Table de routage du routeur R6
R1-R2-R5-R6
Le nouveau co\u00fbt de 111 correspond \u00e0 la route R1-R2-R4-R6
. Ce sera la nouvelle route la plus courte si le routeur R5
tombe en panne.
Sujet
"},{"location":"T6_Annales/corrections/2023/corr_sujet0_B/#exercice-1","title":"Exercice 1","text":"correction Q1.a.Commande 1 : cd /home/documents/collections/timbres
(chemin absolu) Commande 2 : cd ../collections/timbres
(chemin relatif)
cd /home/documents/collections/timbres
\\(C = \\dfrac{10^8}{100 \\times 10^6} = 1\\)
Correction Q2.b.La route minimale est donc A-B-C-E-F-G (co\u00fbt total de 1,04)
Correction Q3.Les descripteurs de ce fichier sont :
nom_timbre
(valeurs associ\u00e9es : Gustave Eiffel
, Marianne
, Alan Turing
)annee_fabrication
(valeurs associ\u00e9es : 1950
, 1989
, 2012
)nom_collectionneur
(valeurs associ\u00e9es : Dupont
, Durand
)Une cl\u00e9 primaire est attribut qui d\u00e9signe de mani\u00e8re unique un enregistrement.
Correction Q4.b.Non, car deux enregistrements poss\u00e8dent le nom \u00abGustave Eiffel\u00bb.
Correction Q4.c.Non, car deux enregistrements ont pour ann\u00e9e de fabrication 1989. (merci Vincent)
Correction Q4.d.On peut cr\u00e9er une cl\u00e9 primaire artificielle (un nombre entier), ou bien consid\u00e9rer le couple (nom
, annee_fabrication
) comme cl\u00e9 primaire.
Cette requ\u00eate va modifier l'attribut ref_licence
de Jean-Pierre Dupond ET de Alexandra, qui auront donc la m\u00eame r\u00e9f\u00e9rence de licence 'Ythpswz'
.
L'attribut ref_licence
ne peut plus \u00eatre une cl\u00e9 primaire car deux enregistrements diff\u00e9rents auront la m\u00eame valeur pour cet attribut.
SELECT nom, prenom, nbre_timbres\nFROM collectionneurs\nWHERE annee_naissance >= 1963;\n
"},{"location":"T6_Annales/corrections/2023/corr_sujet0_B/#exercice-2","title":"Exercice 2","text":"Correction Q1.a. Une fonction r\u00e9cursive est une fonction qui fait appel \u00e0 elle-m\u00eame dans sa propre d\u00e9finition.
Correction Q1.b.Lors du premier appel de la fonction, le param\u00e8tre n
vaut 3. Lors des appels r\u00e9cursifs, ce param\u00e8tre va d\u00e9cro\u00eetre \u00e0 2, 1 puis 0 puisque l'appel se fait sous condition que n >= 0
. Le dernier appel se fait avec la valeur n = -1
. Lors de l'ex\u00e9cution de compte_rebours(n-1)
, rien ne se passe. La derni\u00e8re valeur affich\u00e9e est donc 0.
def fact(n):\n\"\"\" renvoie le produit des nombres entiers\n strictement positifs inf\u00e9rieurs \u00e0 n \"\"\"\n if n == 0:\n return 1\n else:\n return n * fact(n-1)\n
Correction Q3.a. L'affichage en console sera :
3\n2\n1\n
Correction Q3.b. La variable res
contiendra la valeur 6.
def somme_entiers(n):\n somme = 0\n for nb in range(n+1):\n somme += nb\n return somme\n
"},{"location":"T6_Annales/corrections/2023/corr_sujet0_B/#exercice-3","title":"Exercice 3","text":"Correction Q1.a. Exemple d'attribut : valeur
Exemple de m\u00e9thode : get_valeur
Apr\u00e8s ex\u00e9cution, a
vaut 15 et b
vaut 6.
Ce n'est pas un ABR car la valeur 13 est cens\u00e9e \u00eatre plus petite que la valeur 12.
Correction Q4.La liste renvoy\u00e9e est [1, 6, 10, 15, 16, 18, 16, 25]
.
Quelles \u00e9tudes pour poursuivre dans l'informatique ?
"},{"location":"T7_Divers/10_orientation/cours/#1-les-cursus-ingenieurs-publics-post-bac","title":"1. Les cursus ing\u00e9nieurs publics post-bac","text":""},{"location":"T7_Divers/10_orientation/cours/#11-ecoles-du-reseau-geipi-polytech","title":"1.1 \u00c9coles du r\u00e9seau Geipi-Polytech","text":"BTS Syst\u00e8mes num\u00e9riques option A informatique et r\u00e9seaux
BTS Services informatiques aux organisations (SIO)
L'affectation des lyc\u00e9ens dans l'enseignement sup\u00e9rieur (par l'algorithme APB jusqu'en 2018, par l'algorithme Parcoursup depuis) fait intervenir un algorithme d'appariement.
Appariement
Action d'apparier, d'unir par couple, d'assortir par paire.
Consid\u00e9rons que les \u00e9l\u00e8ves aient fait un classement de leurs formations pr\u00e9f\u00e9r\u00e9es (ce n'est pas le cas dans Parcoursup, nous y reviendrons). Consid\u00e9rons aussi que ces formations aient class\u00e9 ces \u00e9l\u00e8ves au vu de leur dossier. L'algorithme d'appariement va avoir pour but d'associer chaque \u00e9l\u00e8ve \u00e0 une formation, avec les contraintes suivantes :
Pour illustrer les probl\u00e9matiques li\u00e9es \u00e0 l'appariement, nous allons nous placer dans la situation suivante : au lieu de parler d'\u00e9l\u00e8ves et d'\u00e9tablissements d'enseignement sup\u00e9rieur, nous allons parler d'hommes et de femmes.
Situation d'\u00e9tude
Mariages instables
Deux mariages sont dits instables si, dans chacun des deux couples, il existe la possibilit\u00e9 de quitter son conjoint actuel pour quelqu'un mieux class\u00e9 dans ses pr\u00e9f\u00e9rences.
Exemple de mariages instables
Consid\u00e9rons 4 personnes : 2 hommes (Bryce, Gregory) et 2 femmes (Trinity et Riley).
On leur a demand\u00e9 de classer les deux personnes du sexe oppos\u00e9 par ordre de pr\u00e9f\u00e9rence. Voil\u00e0 le r\u00e9sultat :
Bryce pr\u00e9f\u00e8re Riley \u00e0 Trinity, Gregory pr\u00e9f\u00e8re Riley \u00e0 Trinity, Trinity pr\u00e9f\u00e8re Bryce \u00e0 Gregory, Riley pr\u00e9f\u00e8re Bryce \u00e0 Gregory.
Consid\u00e9rons maintenant qu'un algorithme d'appariement a form\u00e9 les couples suivants : Bryce-Trinity et Gregory-Riley.
Mais alors :
le couple Bryce-Riley cr\u00e9e donc deux mariages instables, car leur int\u00e9r\u00eat est de briser leur couple actuel et de partir ensemble.
Par abus de langage, on pourra dire que le couple Bryce-Riley est un couple instable (car leurs mariages respectifs sont instables).
Exercice 1
La configuration ci-dessous contient-elle des mariages instables ?
CorrectionLe couple Christopher-Evelyn est un couple instable.
Exercice 2
\u00c0 l'adresse https://uw-cse442-wi20.github.io/FP-cs-algorithm/, allez jusqu'\u00e0 la zone \u00abIdentify Unstable Pairs\u00bb et entra\u00eenez-vous \u00e0 rep\u00e9rer les mariages instables.
1.2 Notion de mariage stable
Mariages stables
Un ensemble de mariages sera dit stable s'il n'existe aucun couple instable parmi tous les mariages.
La situation ci-dessus est stable, car aucun couple n'est instable.
Le travail des algorithmes d'appariement va \u00eatre d'essayer d'arriver \u00e0 une situation stable.
"},{"location":"T7_Divers/11_parcoursup/cours/#2-algorithme-de-gale-shapley","title":"2. Algorithme de Gale-Shapley","text":"David Gale (1921-2008) et Lloyd Shapley (1923-2016), deux universitaires am\u00e9ricains, ont pr\u00e9sent\u00e9 en 1962 un algorithme d'appariement qui porte leur nom. (lien vers la publication originale).
Cette publication vaudra le prix Nobel d'\u00e9conomie \u00e0 Lloyd Shapley en 2012 (conjointement avec Alvin Roth), David Gale \u00e9tant d\u00e9c\u00e9d\u00e9 en 2008. Leur algorithme est aujourd'hui utilis\u00e9 quotidiennement pour tous les probl\u00e8mes d'appariemment : dans le milieu universitaire (comme nous le voyons), mais aussi dans le milieu m\u00e9dical. Son application a ainsi permis une tr\u00e8s forte augmentation des greffes d'organes, en optimisant l'ad\u00e9quation donneur-receveur.
R\u00e9sultat d\u00e9montr\u00e9 par Gale-Shapley
Si les deux ensembles \u00e0 associer sont de m\u00eame taille (ici : s'il y a autant d'hommes que de femmes), alors il existe toujours au moins un appariement stable.
Gale et Shapley ont d\u00e9taill\u00e9 l'algorithme permettant de fabriquer un de ces appariements stables :
Algorithme de Gale-Shapley
\u00c0 noter qu'il n'y a pas, en r\u00e8gle g\u00e9n\u00e9rale, un seul appariement stable, mais plusieurs. L'algorithme de Gale-Shapley permet d'en trouver un en particulier.
Illustration
Vous pouvez voir le d\u00e9roulement de l'algorithme sur le site https://uw-cse442-wi20.github.io/FP-cs-algorithm/, dans la partie The solution.
"},{"location":"T7_Divers/11_parcoursup/cours/#3-implementation-en-python","title":"3. Impl\u00e9mentation en Python","text":"Nous allons partir de la situation suivante :
Exercice 3Compl\u00e9ter le code ci-dessous.
hommes = ['J', 'O', 'B', 'L']\nfemmes = ['A', 'M', 'K', 'H']\n\nprefs = {'J':['K', 'M', 'A', 'H'],\n 'O':['K', 'A', 'M', 'H'],\n 'B':['H', 'A', 'K', 'M'],\n 'L':['A', 'H', 'K', 'M'],\n 'A':['O', 'L', 'J', 'B'],\n 'M':['B', 'O', 'L', 'J'],\n 'K':['J', 'B', 'L', 'O'],\n 'H':['J', 'O', 'B', 'L']}\n\nrefus = {h:[] for h in hommes}\n\ncouple = {p:None for p in hommes + femmes}\n\nhommes_maries = []\n\nwhile len(hommes_maries) < len(hommes):\n\n for h in hommes:\n print('--------------------')\n print('Affectation de', h, \":\")\n\n if couple[h] is not None:\n print(\"d\u00e9j\u00e0 en couple\")\n\n else:\nfor f in ... :\nif couple[h] is not None:\n break\n print(h, \"propose \u00e0\", f)\n\n if f in refus[h]:\n print(f, 'a d\u00e9j\u00e0 refus\u00e9, stop')\n\n elif couple[f] is None:\n print(f, 'est libre, go')\ncouple[f] = ...\ncouple[h] = ...\nhommes_maries.append(...) \nelse:\n print(f, 'est prise, \u00e9tude...')\n h_actuel = couple[f]\n liste_prefs = prefs[f]\n if liste_prefs.index(h) < liste_prefs.index(h_actuel):\n\n print(h, \"est mieux class\u00e9 que\", h_actuel, \"dans les prefs de\", f)\n print(h_actuel, \"est vir\u00e9\")\n hommes_maries.remove(...)\ncouple[...] = None\nrefus[...].append(f)\nprint(h, \"est le nouveau mari de\", f)\n hommes_maries.append(...)\n couple[f] = h\n couple[h] = f\n\n else:\n print(h, \"est moins bien class\u00e9 que\", h_actuel, \"dans les prefs de\", f, \"il reste celibataire\")\nrefus[...].append(...)\nbreak \n\nprint('--------------------')\nprint(\"tout le monde est mari\u00e9, fin de l'algo\")\nfor h in hommes:\n print(h, '-', couple[h])\n
Correction hommes = ['J', 'O', 'B', 'L']\nfemmes = ['A', 'M', 'K', 'H']\n\nprefs = {'J':['K', 'M', 'A', 'H'],\n 'O':['K', 'A', 'M', 'H'],\n 'B':['H', 'A', 'K', 'M'],\n 'L':['A', 'H', 'K', 'M'],\n 'A':['O', 'L', 'J', 'B'],\n 'M':['B', 'O', 'L', 'J'],\n 'K':['J', 'B', 'L', 'O'],\n 'H':['J', 'O', 'B', 'L']}\n\nrefus = {h:[] for h in hommes}\n\ncouple = {p:None for p in hommes + femmes}\n\nhommes_maries = []\n\nwhile len(hommes_maries) < len(hommes):\n\n for h in hommes:\n print('--------------------')\n print('Affectation de', h, \":\")\n\n if couple[h] is not None:\n print(\"d\u00e9j\u00e0 en couple\")\n\n else:\nfor f in prefs[h]:\nif couple[h] is not None:\n break\n print(h, \"propose \u00e0\", f)\n\n if f in refus[h]:\n print(f, 'a d\u00e9j\u00e0 refus\u00e9, stop')\n\n elif couple[f] is None:\n print(f, 'est libre, go')\ncouple[f] = h\ncouple[h] = f\nhommes_maries.append(h) \nelse:\n print(f, 'est prise, \u00e9tude...')\n h_actuel = couple[f]\n liste_prefs = prefs[f]\n if liste_prefs.index(h) < liste_prefs.index(h_actuel):\n\n print(h, \"est mieux class\u00e9 que\", h_actuel, \"dans les prefs de\", f)\n print(h_actuel, \"est vir\u00e9\")\n hommes_maries.remove(h_actuel)\ncouple[h_actuel] = None\nrefus[h_actuel].append(f)\nprint(h, \"est le nouveau mari de\", f)\n hommes_maries.append(h)\n couple[f] = h\n couple[h] = f\n\n else:\n print(h, \"est moins bien class\u00e9 que\", h_actuel, \"dans les prefs de\", f, \"il reste celibataire\")\nrefus[h].append(f)\nbreak \n\nprint('--------------------')\nprint(\"tout le monde est mari\u00e9, fin de l'algo\")\nfor h in hommes:\n print(h, '-', couple[h])\n
"},{"location":"T7_Divers/11_parcoursup/cours/#4-qualite-de-la-solution-proposee-par-lalgorithme-de-gale-shapley","title":"4. Qualit\u00e9 de la solution propos\u00e9e par l'algorithme de Gale-Shapley","text":"La situation initiale est parfaitement sym\u00e9trique : les hommes ont \u00e9tabli un classement, les femmes \u00e9galement.
Mais l'algorithme de Gale-Shapley n'est pas sym\u00e9trique : ce sont les hommes qui proposent, dans l'ordre d\u00e9croissant de leur choix. La cons\u00e9quence est importante :
Optimalit\u00e9 de la solution trouv\u00e9e
L'algorithme de Gale-Shapley donne :
Le choix de \u00abqui va faire ses propositions\u00bb parmi les deux groupes est donc crucial avant de lancer l'algorithme, car le groupe qui propose est plus avantag\u00e9 dans le r\u00e9sultat final.
Nous allons l'illustrer \u00e0 partir une situation initiale identique, et les deux configurations que donne l'algorithme suivant si ce sont les hommes qui proposent (exemple 1) ou bien les femmes (exemple 2)
Exemple 1 : si les hommes proposent
Analyse de la solution :
Exemple 2 : si les femmes proposent
Analyse de la solution :
L'algorithme de Parcoursup est bas\u00e9 sur l'algorithme de Gale-Shapley. Mais il faut apporter quelques pr\u00e9cisions importantes.
Rappel : l'algorithme de Parcoursup n'est que l'algorithme global
Il r\u00e9cup\u00e8re les classements effectu\u00e9s en interne par tous les \u00e9tablissements de l'enseignement sup\u00e9rieur.
L'algorithme global de Parcoursup est public (vous pouvez le trouver ici). Les algorithmes de classement internes \u00e0 chaque \u00e9tablissement ne le sont pas forc\u00e9ment.
Dans Parcoursup, les v\u0153ux ne sont pas class\u00e9s
Mais alors, comment peut-on appliquer Gale-Shapley, qui repose sur le classement des deux parties ?
Le classement des v\u0153ux de chaque candidat se fait au moment de l'acceptation ou du refus des v\u0153ux accept\u00e9s. \u00c0 chaque tour de Parcoursup, le candidat donne une indication sur ses pr\u00e9f\u00e9rences, et l'algorithme converge donc vers sa solution d\u00e9finitive.
Si on obligeait les candidats \u00e0 classer leur v\u0153ux, on serait dans le cas d'un Gale-Shapley \u00abpur\u00bb : les r\u00e9sultats serait imm\u00e9diats. C'\u00e9tait le cas avec l'algorithme qui pr\u00e9c\u00e9dait Parcoursup, l'algorithme APB.
De plus, l'algorithme de Parcoursup doit ob\u00e9ir \u00e0 des contraintes suppl\u00e9mentaires qui ne figurent pas dans Gale-Shapley:
Dans Parcoursup, les \u00e9tablissements jouent le r\u00f4le des hommes, les candidats jouent le r\u00f4le des femmes
Ce sont les \u00e9tablissements qui proposent (en appelant le 1er de leur liste, puis le 2\u00e8me, ...). La cons\u00e9quence est importante : la solution donn\u00e9e par l'algorithme est donc optimale pour les \u00e9tablissements et non pour les candidats.
Que se passerait-il si on inversait, afin de rendre la solution optimale pour les candidats ?
Il faut se souvenir des situations rencontr\u00e9es plus haut, lorsqu'on a appari\u00e9 des hommes (qui proposaient) \u00e0 des femmes : il arrivait que des couples \u00e9tablis soient cass\u00e9s lorsqu'un homme mieux class\u00e9 se proposait \u00e0 une femme pourtant d\u00e9j\u00e0 mari\u00e9e.
Comme Parcoursup fonctionne sur plusieurs mois (\u00e0 cause de la non-hi\u00e9rachisation des v\u0153ux), cela reviendrait \u00e0 ce qu'un candidat ait une r\u00e9ponse positive d'un \u00e9tablissement, mais que cette r\u00e9ponse soit annul\u00e9e quelques jours plus tard parce qu'un meilleur candidat aura fait une proposition \u00e0 cet \u00e9tablissement... Ceci est difficilement envisageable d'un point de vue psychologique.
Dans le cas de l'affectation des \u00e9tudiants \u00e0 l'issue de la premi\u00e8re ann\u00e9e de PASS, les v\u0153ux sont hi\u00e9rarchis\u00e9s et Gale-Shapley fonctionne donc de mani\u00e8re imm\u00e9diate : ce sont donc les \u00e9tudiants qui proposent, et l'algorithme aboutit donc \u00e0 une solution optimale pour les \u00e9tudiants. (source)
Finalement, pourquoi les v\u0153ux Parcoursup des candidats ne sont-ils pas hi\u00e9rarchis\u00e9s ?
Les avantages :
Les inconv\u00e9nients :
bibliographie
Il est conseill\u00e9 de travailler avec 3 espaces:
C'est en codant qu'on apprend \u00e0 coder
Tous les exemples de code dans le cours doivent \u00eatre retap\u00e9s (r\u00e9sistez \u00e0 l'envie du copier-coller) dans Thonny, soit en fen\u00eatre de script, soit en console.
Cela permet de :
et le plus important :
Thonny, comme la grande majorit\u00e9 des IDE Python, est compos\u00e9 de deux zones distinctes :
La zone de script est asynchrone. Il ne se passera rien tant que vous n'aurez pas ex\u00e9cut\u00e9 le script (par F5 par exemple). C'est donc l'endroit o\u00f9 on va r\u00e9diger son programme.
La console est synchrone : elle r\u00e9pond d\u00e8s que vous appuyez sur la touche Entr\u00e9e. Elle sert donc aux petits tests rapides, ou bien tests post-ex\u00e9cution d'un code.
Utilisation classique du couple script / console
Pour les extraits de code pr\u00e9sents sur ce site :
Exemple :
def accueil(n):\n for k in range(n):\n print(\"bonjour\") \n
>>>
est \u00e0 taper en console.Exemple :
>>> accueil(5)\n
"},{"location":"T7_Divers/1_Conseils_generaux/cours/#dossiers-fichiers-et-versionning","title":"Dossiers, fichiers et versionning","text":"Cette ann\u00e9e en NSI nous allons manipuler un certain nombre de fichiers. Il est important de les nommer et les classer de fa\u00e7on rigoureuse pour les retrouver rapidement et les partager.
Conseils
python1.py
, python2.py
, python3.py
, etc. Mais plut\u00f4t 1NSI_T4_tri_selection.py
par exemple pour un exercice de programmation sur le tri par selection au th\u00e8me 4.1NSI_projet_morpion_v1.py
, puis 1NSI_projet_morpion_v2.py
, 1NSI_projet_morpion_v3.py
, etc.Utiliser le clavier est souvent bien plus pratique et surtout plus rapide qu'utiliser la souris. Encore faut-il apprendre \u00e0 l'apprivoiser...
La s\u00e9lection au clavier
Outre les touches DEBUT
et FIN
qui permettent d'atteindre rapidement le d\u00e9but ou la fin d'une ligne, les fl\u00e8ches directionelles servent \u00e9videmment \u00e0 se d\u00e9placer dans du texte. Mais combin\u00e9es:
CTRL
: elles permettent de se d\u00e9placer de mot en mot;MAJ
: elles permettent de s\u00e9lectionner un caract\u00e8re;MAJ
et CTRL
: elles permettent de s\u00e9lectionner une mot.De m\u00eame, en se pla\u00e7ant en d\u00e9but d'une ligne et en combinant la touche MAJ
et FIN
, on s\u00e9lectionne la ligne enti\u00e8re.
Les raccourcis clavier
Il existe de tr\u00e8s nombreux raccourcis clavier qui permettent d'ex\u00e9cuter des t\u00e2ches courantes sans passer par les menus du logiciel. Certains sont (quasi-)universels, c'est-\u00e0-dire que ce sont les m\u00eames sur tous les logiciels, d'autres sont sp\u00e9cifiques \u00e0 chaque logiciel. Il est important d'en conna\u00eetre quelques-uns pour \u00eatre plus efficace.
Les universelsIDENavigateur WebCTRL+X
, CTRL+C
, CTRL+V
pour couper, copier, coller;CTRL+O
pour ouvrir un fichierCTRL+N
pour cr\u00e9er un nouveau document;CTRL+S
pour sauvegarder le document en cours;CTRL+MAJ+S
pour sauvegarder en pr\u00e9cisant le nom du fichier;CTRL+Z
pour annuler la derni\u00e8re action, CTRL+Y
ou CTRL+MAJ+Z
pour la r\u00e9tablir;CTRL+W
pour fermer un onglet;CTRL+Q
ou ALT+F4
pour fermer le logiciel;CTRL+A
pour s\u00e9lectionner tout (All).\u00c0 chercher de suite lorsqu'on utilise un nouvel IDE, les raccourcis pour les actions suivantes (entre parenth\u00e8ses ceux de Thonny):
F5
)CTRL+M
)CTRL+T
pour ouvrir un nouvel onglet;CTRL+H
pour ouvrir l'historique;CTRL
+ clic pour forcer l'ouverture d'un lien dans un nouvel onglet;MAJ
+ clic pour forcer l'ouverture d'un lien dans une nouvelle fen\u00eatre;Afin de pouvoir travailler sous le syst\u00e8me d'exploitation libre Linux sur les machines du lyc\u00e9e (sous Windows), nous utilisons la solution de virtualisation Proxmox. De mani\u00e8re simplifi\u00e9e :
Programmation
.Proxmox NSI
. Param\u00e8tres avanc\u00e9s
puis sur Continuer vers le site 172.17.191.244
Proxmox VE Login
, renseigner ses identifiants et s\u00e9lectionner Realm Proxmox VE authentication server
. ok
pour l'ignorer.Start
pour d\u00e9marrer la VM.Console
et choisir Spice
. telechargement.vv
apparu en bas \u00e0 gauche.Remplir ses identifiants dans la fen\u00eatre de connexion :
Basculer l'affichage en plein \u00e9cran
Comme pour tous les langages de programmation, il n'existe pas un logiciel permettant de coder en Python, mais un tr\u00e8s (tr\u00e8s) grand nombre de logiciels diff\u00e9rents, qu'on regroupe sous le nom d'IDE (interfaces de d\u00e9veloppement)
Pour la NSI, nous conseillons Thonny :
"},{"location":"T7_Divers/3_Thonny/cours/#installer-thonny","title":"Installer Thonny","text":"Rendez vous sur la page https://thonny.org/
T\u00e9l\u00e9chargez et installez la version qui correspond \u00e0 votre syst\u00e8me d'exploitation (Windows, Mac, Linux).
Pyzo, PyCharm, Spyder, VisualStudioCode... impossible de toutes les citer !
"},{"location":"T7_Divers/3_Thonny/cours/#solutions-en-ligne","title":"Solutions en ligne","text":"En ligne, sans aucune installation, vous pouvez utiliser https://console.basthon.fr/
ou bien m\u00eame la console ci-dessous !
>>>ou l'IDE qui suit :
\u25b6\ufe0f \u2935\ufe0f \u2934\ufe0f "},{"location":"T7_Divers/3_Thonny/cours/#installer-la-derniere-version-de-thonny-avec-export-python-tutor","title":"Installer la derni\u00e8re version de Thonny (avec export Python Tutor !)","text":"Proc\u00e9dure sur nos VMs au lyc\u00e9e
Dans un terminal ouvert dans votre dossier eleve
mkdir thonny
cd thonny
wget https://github.com/thonny/thonny/releases/download/v4.0.1/thonny-4.0.1-x86_64.tar.gz
tar -xf thonny-4.0.1-x86_64.tar.gz
cd thonny
install
Processing est un outil de cr\u00e9ation multim\u00e9dia utilisant le code informatique. Simple de prise en main, il a \u00e9t\u00e9 cr\u00e9\u00e9 par des artistes pour des artistes. On peut utiliser le langage Python pour entrer les instructions.
Nous l'utiliserons pour ajouter du graphisme \u00e0 nos cr\u00e9ations...
Documentation"},{"location":"T7_Divers/4_Processing/cours/#les-bases-de-processing","title":"Les bases de Processing","text":""},{"location":"T7_Divers/4_Processing/cours/#repere","title":"Rep\u00e8re","text":"
\u00c0 l'ex\u00e9cution de tout script Processing, une fen\u00eatre s'affiche avec une zone de dessin. Sa taille se d\u00e9finit \u00e0 l'aide de la fonction size
. Par exemple, pour cr\u00e9er une zone de dessin de 300 pixels sur 200 pixels, on utilisera:
size(300, 200)\n
Chaque pixel de cette zone est rep\u00e9r\u00e9e par des coordonn\u00e9es dans le rep\u00e8re suivant, dont l'origine se situe en haut \u00e0 gauche et l'axe des ordonn\u00e9es est orient\u00e9 vers le bas.
"},{"location":"T7_Divers/4_Processing/cours/#traces","title":"Trac\u00e9s","text":"
Trac\u00e9s de base
point
: permet de dessiner un point (pixel). En param\u00e8tre, les coordonn\u00e9es du point.line
: permet de tracer une ligne entre deux points. En param\u00e8tres, les coordonn\u00e9es des deux points.rect
: permet de tracer un rectangle. En param\u00e8tres, les coordonn\u00e9es du sommet haut-gauche, puis la largeur et la hauteur du rectangle.ellipse
: permet de tracer une ellipse. En param\u00e8tres, les coordonn\u00e9es du centre, puis la largeur et la hauteur (mettre la m\u00eame valeur pour un cercle).Copier-coller le code suivant et faire varier les param\u00e8tres pour bien les comprendre.
size(200, 200)\npoint(10, 60)\nline(10, 10, 100, 150)\nrect(80, 10, 20, 50)\nellipse(150, 100, 80, 40)\n
"},{"location":"T7_Divers/4_Processing/cours/#couleurs","title":"Couleurs","text":"Pinceau
background
: permet de d\u00e9finir la couleur du fond de la zone de dessin. En param\u00e8tres, les trois composantes RGB de la couleur.stroke
: permet de d\u00e9finir la couleur du pinceau (noir par d\u00e9faut) pour le contour de la forme. En param\u00e8tres, les trois composantes RGB de la couleur.noStroke
: permet de dessiner une forme sans coutour (pas de param\u00e8tre).strokeWeight
: permet de d\u00e9finir la largeur du pinceau. En param\u00e8tre, le nombre de pixel.fill
: permet de d\u00e9finir la couleur de remplissage de la forme. En param\u00e8tres, les trois composantes RGB de la couleur.Copier-coller le code suivant et faire varier les param\u00e8tres pour bien les comprendre.
size(200, 200)\nbackground(255, 255, 255)\nstroke(255, 0, 0)\npoint(10, 60)\nline(10, 10, 100, 150)\nstroke(0, 127, 255)\nstrokeWeight(5)\nrect(80, 10, 20, 50)\nnoStroke()\nfill(204, 153, 204)\nellipse(150, 100, 80, 40)\n
"},{"location":"T7_Divers/4_Processing/cours/#exercices","title":"Exercices","text":"Exercice 9
\u00c9crire un programme qui affiche le drapeau fran\u00e7ais, comme ci-contre, dans une zone de 300 x 200 pixels.
Exercice 10
\u00c9crire un programme qui trace un quadrillage (espacement de 20 pixels).
Contrainte: en seulement 3 lignes (sans compter \u00e9ventuellement size
.
Exercice 11
Afficher une croix verte de longueur 50 centr\u00e9e au point (60 ; 40), et un cercle rouge de diam\u00e8tre 30 centr\u00e9 en (150 ; 100). On prendra 10 pixels comme \u00e9paisseur.
Exercice 12
Cr\u00e9ez un programme permettant d\u2019afficher 100 disques \u00e0 l\u2019\u00e9cran. La taille de chaque disque devra \u00eatre al\u00e9atoire (mais comprise entre 20 et 50). La couleur de chaque disque devra aussi \u00eatre al\u00e9atoire.
Avec Processing, il est tr\u00e8s simple d\u2019avoir un nombre al\u00e9atoire : random(a,b)
permet d\u2019obtenir un nombre al\u00e9atoire entre a
et b
.
Capytale est accessible via lyc\u00e9econnect\u00e9, il faut donc avoir ses identifiants Educonnect.
"},{"location":"T7_Divers/5_Capytale/cours/#activite-test","title":"Activit\u00e9-test :","text":"Lyc\u00e9e Connect\u00e9 (Nouvelle Aquitaine)
Pygame est un package de Python facilitant la cr\u00e9ation de jeux bas\u00e9s une interface graphique. Vous pouvez :
pip3 install pygame
.pygame
dans la liste des langages propos\u00e9s.import pygame, sys\nfrom pygame.locals import *\n\npygame.init()\n\nfenetre = pygame.display.set_mode((640, 480))\n\nfenetre.fill([10,186,181])\n\npygame.display.flip()\n\nwhile True :\n pass\n
Ce code devrait vous donner ceci :
Commentaires
sys
permettra de fermer le programme au niveau de l'OS par la commande sys.exit()
from pygame.locals import *
permettra d'utiliser des variables locales d\u00e9j\u00e0 d\u00e9finies par pygame
, comme MOUSEBUTTONDOWN
, par exemple.fenetre
, dans lequel nous viendrons coller de nouveaux \u00e9l\u00e9ments. \u00c9l\u00e9ments structurants d'un code pygame
:
pygame.init()
effectue une initialisation globale de tous les modules pygame
import\u00e9s. \u00c0 mettre au d\u00e9but du code.pygame.display.flip()
effectue un rafra\u00eechissement total de tous les \u00e9l\u00e9ments graphiques de la fen\u00eatre. \u00c0 mettre donc plut\u00f4t vers la fin du code.while True :
comme tr\u00e8s souvent dans les jeux, la structure essentielle est une boucle infinie dont on ne sortira que par une interruption syst\u00e8me (sys.exit()
) o\u00f9 lors de la bascule d'un bool\u00e9en. Pour l'instant, cette boucle est vide (pass
).Nous allons travailler avec le sprite ci-dessous, nomm\u00e9 perso.png
. Il est issu de https://openclassrooms.com/fr/courses/1399541-interface-graphique-pygame-pour-python/1399813-premieres-fenetres
T\u00e9l\u00e9chargez-le pour le mettre dans le m\u00eame dossier que votre code pygame
.
Vous pouvez trouver sur internet un grand nombre de sprites libres de droits, au format png
(donc g\u00e9rant la transparence), dans de multiples positions (ce qui permet de simuler des mouvements fluides). Ici nous travaillerons avec un sprite unique.
perso = pygame.image.load(\"perso.png\").convert_alpha()\n
La fonction convert_alpha()
est appel\u00e9e pour que soit correctement trait\u00e9 le canal de transparence (canal alpha) de notre image."},{"location":"T7_Divers/6_Pygame/05_Initiation_Pygame/#23-affichage-de-limage","title":"2.3. Affichage de l'image","text":"\u00c0 ce stade, perso
est un objet pygame
de type Surface
.
Afin de facilement pouvoir le d\u00e9placer, nous allons stocker la position de cet objet dans une variable position_perso
, qui sera de type rect
.
position_perso = perso.get_rect()\n
Pour afficher cette image, nous allons venir le superposer aux \u00e9l\u00e9ments graphiques d\u00e9j\u00e0 dessin\u00e9s (en l'occurence : rien) avec l'instruction blit()
: fenetre.blit(perso, position_perso)\n
\u25b8 r\u00e9capitulatif du code
import pygame, sys\nfrom pygame.locals import *\n\npygame.init()\n\nfenetre = pygame.display.set_mode((640, 480))\nfenetre.fill([10,186,181])\n\nperso = pygame.image.load(\"perso.png\").convert_alpha()\nposition_perso = perso.get_rect()\n\nfenetre.blit(perso, position_perso)\n\npygame.display.flip()\n\nwhile True :\n pass\n
Aper\u00e7u
"},{"location":"T7_Divers/6_Pygame/05_Initiation_Pygame/#3-gestion-des-evenements","title":"3. Gestion des \u00e9v\u00e8nements","text":"Lorsqu'un programme pygame
est lanc\u00e9, la variable interne pygame.event.get()
re\u00e7oit en continu les \u00e9v\u00e8nements des p\u00e9riph\u00e9riques g\u00e9r\u00e9s par le syst\u00e8me d'exploitation. Nous allons nous int\u00e9resser aux \u00e9v\u00e8nements de type KEYDOWN
(touche de clavier appuy\u00e9e) ou de type MOUSEBUTTONDOWN
(boutons de souris appuy\u00e9).
La structure de code pour d\u00e9tecter l'appui sur une touche de clavier est, dans le cas de la d\u00e9tection de la touche \u00abFl\u00e8che droite\u00bb :
for event in pygame.event.get(): \n if event.type == KEYDOWN:\n if event.key == K_RIGHT:\n print(\"fl\u00e8che droite appuy\u00e9e\")\n
La touche (en anglais key) \u00abFl\u00e8che Droite\u00bb est appel\u00e9e K_RIGHT
par pygame
. Le nom de toutes les touches peut \u00eatre retrouv\u00e9 \u00e0 l'adresse https://www.pygame.org/docs/ref/key.html.
Remarque : c'est gr\u00e2ce \u00e0 la ligne initiale
from pygame.locals import *\n
que la variable K_RIGHT
(et toutes les autres) est reconnue."},{"location":"T7_Divers/6_Pygame/05_Initiation_Pygame/#312-probleme-de-la-remanence","title":"3.1.2. Probl\u00e8me de la r\u00e9manence","text":"Quand une touche de clavier est appuy\u00e9e, elle le reste un certain temps. Parfois volontairement (sur un intervalle long) quand l'utilisateur d\u00e9cide de la laisser appuy\u00e9e, mais aussi involontairement (sur un intervalle tr\u00e8s court), lors d'un appui \u00abclassique\u00bb. Il existe donc toujours un intervalle de temps pendant lequel la touche reste appuy\u00e9e. Que doit faire notre programme pendant ce temps ? Deux options sont possibles :
Par d\u00e9faut,pygame
est r\u00e9gl\u00e9 sur l'option 1. N\u00e9anmoins, il est classique pour les jeux vid\u00e9os de vouloir que \u00ablaisser la touche appuy\u00e9e\u00bb continue \u00e0 faire avancer le personnage. Nous allons donc faire en sorte que toutes les 50 millisecondes, un nouvel appui soit d\u00e9tect\u00e9 si la touche est rest\u00e9e enfonc\u00e9e. Cela se fera par l'expression :
pygame.key.set_repeat(50)\n
"},{"location":"T7_Divers/6_Pygame/05_Initiation_Pygame/#32-evenements-souris","title":"3.2 \u00c9v\u00e8nements souris","text":""},{"location":"T7_Divers/6_Pygame/05_Initiation_Pygame/#321-exemple-de-code","title":"3.2.1. Exemple de code","text":"La structure de code pour d\u00e9tecter l'appui sur un bouton de la souris est, dans le cas de la d\u00e9tection du bouton de gauche (le bouton 1) :
for event in pygame.event.get(): \n if event.type == MOUSEBUTTONDOWN and event.button == 1 :\n print(\"clic gauche d\u00e9tect\u00e9\")\n
"},{"location":"T7_Divers/6_Pygame/05_Initiation_Pygame/#322-recuperation-des-coordonnees-de-la-souris","title":"3.2.2. R\u00e9cup\u00e9ration des coordonn\u00e9es de la souris","text":"Le tuple (abscisse, ordonn\u00e9e)
des coordonn\u00e9es de la souris sera r\u00e9cup\u00e9r\u00e9 avec l'instruction pygame.mouse.get_pos()
.
Le d\u00e9placement d'un personnage se fera toujours par modification de ses coordonn\u00e9es (et visuellement, par effacement de la derni\u00e8re position). Ce d\u00e9placement pourra \u00eatre : - absolu : on donne de nouvelles coordonn\u00e9es au personnage. - relatif : on indique de combien le personnage doit se d\u00e9caler par rapport \u00e0 sa position initiale.
"},{"location":"T7_Divers/6_Pygame/05_Initiation_Pygame/#41-deplacement-absolu","title":"4.1. D\u00e9placement absolu","text":"Pour afficher le personnage \u00e0 la position (100,200)
, on \u00e9crira :
position_perso.topleft = (100,200)\n
o\u00f9 position_perso
est l'objet de type rect
contenant les coordonn\u00e9es. Exercice 1 : R\u00e9aliser un d\u00e9placement al\u00e9atoire, comme l'animation ci-dessous.
Vous pourrez utiliser les instructions : - pygame.time.delay(1000)
afin de ne bouger le personnage que toutes les 1000 millisecondes. - randint(a,b)
du package random
, qui renvoie un entier pseudo-al\u00e9atoire entre a
et b
.
import pygame, sys\nfrom pygame.locals import *\nfrom random import randint\n\npygame.init()\n\nfenetre = pygame.display.set_mode((640, 480))\n\nperso = pygame.image.load(\"perso.png\").convert_alpha()\n\nposition_perso = perso.get_rect()\n\nwhile True :\n fenetre.fill([10,186,181])\n position_perso.topleft = (randint(0,540),randint(0,380))\n fenetre.blit(perso, position_perso)\n pygame.display.flip()\n pygame.time.delay(1000)\n
"},{"location":"T7_Divers/6_Pygame/05_Initiation_Pygame/#42-deplacement-relatif","title":"4.2. D\u00e9placement relatif","text":"Pour d\u00e9placer le personnage de 15 pixels vers la droite et de 10 pixels vers le haut par rapport \u00e0 sa position pr\u00e9c\u00e9dente, on \u00e9crira :
position_perso.move(15,-10)\n
o\u00f9 position_perso
est l'objet de type rect
contenant les coordonn\u00e9es. Exercice 2 : R\u00e9aliser un contr\u00f4le au clavier du personnage, comme dans l'animation ci-dessous.
Proposition de correction
import pygame, sys\nfrom pygame.locals import *\n\npygame.init()\npygame.key.set_repeat(50)\n\nfenetre = pygame.display.set_mode((640, 480))\n\nperso = pygame.image.load(\"perso.png\").convert_alpha()\n\nposition_perso = perso.get_rect()\n\npas_deplacement = 15 \n\nwhile True :\n\n for event in pygame.event.get() : \n if event.type == KEYDOWN:\n\n if event.key == K_DOWN : \n position_perso = position_perso.move(0,pas_deplacement)\n\n if event.key == K_UP :\n position_perso = position_perso.move(0,-pas_deplacement)\n\n if event.key == K_RIGHT : \n position_perso = position_perso.move(pas_deplacement,0)\n\n if event.key == K_LEFT : \n position_perso = position_perso.move(-pas_deplacement,0) \n\n fenetre.fill([10,186,181])\n fenetre.blit(perso, position_perso)\n pygame.display.flip()\n
"},{"location":"T7_Divers/6_Pygame/05_Initiation_Pygame/#5-a-vous","title":"5. \u00c0 vous !","text":"Fabriquez le jeu que vous souhaitez \u00e0 partir des informations ci-dessus. Bien d'autres aides peuvent \u00eatre trouv\u00e9es dans les liens cit\u00e9es dans la partie Bibliographie.
Exemple de r\u00e9alisation possible : un clicker avec un temps qui diminue \u00e0 progressivement, et comptage des points.
Quelques aides :
\u00e9crire du texte :
font = pygame.font.Font(pygame.font.get_default_font(), 36)\ntext = font.render(\"Game Over\", True, (255, 0, 0))\nfenetre.blit(text, dest=(550,40))\n
dessiner un rectangle :
pygame.draw.rect(fenetre,(0,255,0),(500,20,100,10))\n
dessine un rectangle vert de 100 pixels sur 10 pixels, dont le coin en haut \u00e0 gauche est \u00e0 la position (500,20). g\u00e9rer le temps:
import time\ntopchrono = time.time()\ndelai = 5\nsortir = False\nwhile sortir == False :\n if time.time() - topchrono > delai :\n print(\"5 secondes se sont \u00e9coul\u00e9es\")\n sortir = True\n
Bibliographie
\u00c0 retrouver ici
"},{"location":"T7_Divers/7_Liens/liens/#a-propos-de-la-specialite-nsi","title":"\u00c0 propos de la sp\u00e9cialit\u00e9 NSI","text":"Quelques sites de challenges/\u00e9nigmes/d\u00e9fis de programmation:
Interstices
Inria
Au cas o\u00f9 vous vous ennuieriez...
d\u00e9p\u00f4t : https://github.com/ffaure32/rugby-game-nsi
Cliquer sur Code
puis Download zip
.
ligne \u00e0 \u00e9crire dans un Terminal pour lancer les tests :
python3 -m unittest test_rugby_game.py\n
Je vous conseille de travailler avec 2 fichiers :
input.txt
qui contiendra l'input r\u00e9el qui vous permettra de trouver votre solution.input_test.txt
qui contiendra les donn\u00e9es de test (qui sont toujours propos\u00e9es au sein de l'\u00e9nigme). L'instruction suivante :
data = open('input_test.txt').read().splitlines()\n
va r\u00e9cup\u00e9rer au sein d'une liste toutes les lignes de l'input. Attention, les objets contenus dans la liste sont des cha\u00eenes de caract\u00e8res.
Exemple avec le fichier input_test.txt
1000\n2000\n3000\n\n4000\n\n5000\n6000\n\n7000\n8000\n9000\n\n10000\n
La variable data
sera alors :
>>> data\n['1000', '2000', '3000', '', '4000', '', '5000', '6000', '', '7000', '8000', '9000', '', '10000']\n
"},{"location":"T7_Divers/9_AOC/cours/#22-exploiter-ces-donnees","title":"2.2 Exploiter ces donn\u00e9es","text":"Le plus dur commence ! Suivant ce qu'il va falloir faire avec ces donn\u00e9es, vous allez devoir les triturer pour les utiliser, au sein de diff\u00e9rentes structures (listes, dictionnaires... ). Cela d\u00e9pend des situations. Ici par exemple, les donn\u00e9es sont \u00abjuste\u00bb des nombres, on peut donc parcourir la liste et effectuer un int()
pour les convertir en nombre lorsque c'est n\u00e9cessaire...
Actualit\u00e9s
Th\u00e8me en cours d'\u00e9tude
Exercice 1
\u00c9nonc\u00e9Corr. Q1Corr. Q2Corr. Q3Corr. Q4Exercice 5 du sujet Centres \u00c9trangers 1 - 2021
def maximum(P):\n if est_vide(P):\n return None\n m = depile(P)\n while not est_vide(P):\n val = depile(P)\n if val > m:\n m = val\n return m\n
Avec le code ci-dessus, la pile p
est vide \u00e0 la fin de l'ex\u00e9cution. Pour \u00e9viter cela, on peut par exemple cr\u00e9er une pile q
temporaire qui recevra les \u00e9l\u00e9ments de p
, avant de retransf\u00e9rer \u00e0 la fin du programme les \u00e9l\u00e9ments de q
dans p
.
def maximum(P):\n Q = creer_pile()\n if est_vide(P):\n return None\n m = depile(P)\n empile(Q, m)\n while not est_vide(P):\n val = depile(P)\n empile(Q, val)\n if val > m:\n m = val\n while not est_vide(Q):\n empile(P, depile(Q))\n return m\n
Q4a. On va vider la pile p
dans une pile q
tout en comptant le nombre d'\u00e9l\u00e9ments d\u00e9pil\u00e9s dans une variable t
. On redonne ensuite \u00e0 p
son \u00e9tat initial en vidant q
dans p
.
Q4b
def taille(P):\n if est_vide(P):\n return 0\n Q = creer_pile()\n t = 0\n while not est_vide(P):\n empile(Q, depile(P))\n t += 1\n while not est_vide(Q):\n empile(P, depile(Q))\n return t\n
Exercice 2
\u00c9nonc\u00e9Corr. Q1Corr. Q2aCorr. Q2bCorr. Q3Corr. Q4Exercice 1 du sujet La R\u00e9union J2 - 2022
La variable temp
contient la valeur 25.
p1
est identique, elle contient toujours les valeurs 25, 3 et 7.
def addition(p):\n nb1 = depiler(p)\n nb2 = depiler(p)\n empiler(p, nb1 + nb2)\n
p = pile_vide()\nempiler(p, 3)\nempiler(p, 5)\naddition(p)\nempiler(p, 7)\nmultiplication(p)\n
Exercice 3
\u00c9nonc\u00e9Corr. Q1aCorr. Q1bCorr. Q2aCorr. Q2bCorr. Q3Corr. Q4Exercice 2 du sujet M\u00e9tropole Candidats Libres J1 - 2021
pile1 = Pile()\npile1.empiler(7)\npile1.empiler(5)\npile1.empiler(2)\n
L'affichage produit est 7, 5, 5, 2
.
3, 2
3, 2, 5, 7
3
\u00abpile vide\u00bb
La fonction mystere
permet d'obtenir la pile retourn\u00e9e jusqu'\u00e0 un \u00e9l\u00e9ment particulier (s'il existe).
def etendre(pile1, pile2):\n while not pile2.est_vide():\n val = pile2.depiler()\n pile1.empiler(val)\n
def supprime_toutes_occurences(pile, element):\n p_temp = Pile()\n while not pile.est_vide():\n val = pile.depiler()\n if val != element:\n p_temp.empiler(val)\n while not p_temp.est_vide():\n val = p_temp.depiler()\n pile.empiler(val)\n
Exercice 4
\u00c9nonc\u00e9Corr. Q1aCorr. Q1bCorr. Q2Corr. Q3Corr. Q4Exercice 5 du sujet Am\u00e9rique du Nord J1 - 2021
Le contenu de la pile P sera
| \"rouge\" |\n| \"vert\" |\n| \"jaune\" |\n| \"rouge\" |\n| \"jaune\" |\n _________\n
def taille_file(F):\n\"\"\"File -> Int\"\"\"\n F_temp = creer_file_vide()\n n = 0\n while not est_vide(F):\n enfiler(F_temp, defiler(F))\n n += 1\n while not est_vide(F_temp):\n enfiler(F, defiler(F_temp))\n return n\n
def former_pile(F):\n\"\"\"File -> Pile\"\"\"\n P_temp = creer_pile_vide()\n P = creer_pile_vide()\n while not est_vide(F):\n empiler(P_temp, defiler(F))\n while not est_vide(P_temp):\n empiler(P, depiler(P_temp))\n return P\n
def nb_elements(F, elt):\n\"\"\"File, Int -> Int\"\"\"\n F_temp = creer_file_vide()\n n = 0\n while not est_vide(F):\n val = defiler(F)\n if val == elt:\n n += 1\n enfiler(F_temp, val)\n while not est_vide(F_temp):\n enfiler(F, deFiler(F_temp))\n return n\n
def verifier_contenu(F, nb_rouge, nb_vert, nb_jaune):\n\"\"\"File, Int, Int, Int -> Bool\"\"\"\n return nb_elements(F, \"rouge\") <= nb_rouge and \\\n nb_elements(F, \"vert\") <= nb_vert and \\\n nb_elements(F, \"jaune\") <= nb_jaune\n
Exercice 5
\u00c9nonc\u00e9Corr. Q1Corr. Q2Corr. Q3Corr. Q4Exercice 2 du sujet Centres \u00c9trangers J1 - 2022
Il faut \u00e9crire l'instruction :
panier_1.enfile((31002, \"caf\u00e9 noir\", 1.50, 50525))\n
def remplir(self, panier_temp):\n while not panier_temp.est_vide():\n article = panier_temp.defile()\n self.enfile(article)\n
def prix_total(self):\n total = 0\n panier_temp = Panier()\n while not self.est_vide():\n article = self.defile()\n total += article[2]\n panier_temp.enfile(article)\n self.remplir(panier_temp)\n return total \n
def duree_passage_en_caisse(self):\n if self.est_vide():\n return None\n horaire_premier = self.defile()[3]\n while not self.est_vide():\n horaire_dernier = self.defile()[3]\n return horaire_dernier - horaire_premier \n
Exercice 6 Cet exercice est bas\u00e9 sur l'\u00e9nigme n\u00b05 d'Advent Of Code 2018.
Le but est de r\u00e9duire le plus possible une cha\u00eene de caract\u00e8res (comme dabAcCaCBAcCcaDA
) en ob\u00e9issant \u00e0 la r\u00e8gle suivante :
R\u00e8gle de simplification
D\u00e8s que deux lettres identiques mais de casse diff\u00e9rente (majuscule-minuscule ou minuscule-majuscule) sont c\u00f4te \u00e0 c\u00f4te dans la cha\u00eene, on les supprime de la cha\u00eene.
Exemple :
dabAcCaCBAcCcaDA On enl\u00e8ve le premier 'cC'.\ndabAaCBAcCcaDA Cela donne naissance \u00e0 un 'Aa', qu'on enl\u00e8ve.\ndabCBAcCcaDA On enl\u00e8ve alors 'cC' (ou 'Cc', cela revient au m\u00eame).\ndabCBAcaDA Plus aucune simplification n'est possible.\n
La cha\u00eene de caract\u00e8res qu'il va falloir simplifier contient ... 50000 caract\u00e8res.
Exercice 7
Exercice 3 du sujet Centres Etrangers J1 - 2023
Jeu du Simon
Correction Q1.def ajout(f):\n couleurs = (\"bleu\", \"rouge\", \"jaune\", \"vert\")\nindice = randint(0, 3)\nenfiler(f, couleur[indice])\nreturn f\n
Correction Q2. def vider(f):\n while not est_vide(f):\n defiler(f)\n
Correction Q3. def affich_seq(sequence):\n stock = creer_file_vide()\n ajout(sequence)\n while not est_vide(sequence):\nc = defiler(sequence)\naffichage(c)\ntime.sleep(0.5)\nenfiler(stock, c)\nwhile not est_vide(stock):\nenfiler(sequence, defiler(stock)) \n
Correction Q4.a. def tour_de_jeu(sequence):\naffich_seq(sequence)\nstock = creer_file_vide()\n while not est_vide(sequence):\n c_joueur = saisie_joueur()\nc_seq = defiler(sequence)\nif c_joueur == c_seq:\nenfiler(stock, c_seq)\nelse:\nvider(sequence)\nwhile not est_vide(stock):\nenfiler(sequence, defiler(stock))\n
Correction Q4.b. Question bizarre...
def tour_de_jeu_modifie(sequence):\n while True:\n affich_seq(sequence)\n stock = creer_file_vide()\n while not est_vide(sequence):\n c_joueur = saisie_joueur()\n c_seq = defiler(sequence)\n if c_joueur == c_seq:\n enfiler(stock, c_seq)\n else:\n vider(sequence)\n vider(stock)\n while not est_vide(stock):\n enfiler(sequence, defiler(stock))\n
ou bien
def tour_de_jeu_modifie(sequence):\n affich_seq(sequence)\n stock = creer_file_vide()\n while not est_vide(sequence):\n c_joueur = saisie_joueur()\n c_seq = defiler(sequence)\n if c_joueur == c_seq:\n enfiler(stock, c_seq)\n else:\n vider(sequence)\n print(\"Perdu ! On rejoue !\")\n tour_de_jeu_modifie(sequence)\n while not est_vide(stock):\n enfiler(sequence, defiler(stock))\n tour_de_jeu_modifie(sequence)\n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/Exercices/#1-elaboration-dune-fonction-utile","title":"1. \u00c9laboration d'une fonction utile","text":"On rappelle que la fonction ord
renvoie le code ASCII d'une lettre. En comparant les codes ASCII de deux lettres identiques mais de casse diff\u00e9rentes, en d\u00e9duire une fonction simplifiable
qui prend en param\u00e8tres deux lettres l1
et l2
et qui renvoie un bool\u00e9en indiquant si ces deux lettres sont simplifiables.
Exemples d'utilisation :
>>> simplifiable('c', 'C')\nTrue\n>>> simplifiable('C', 'c')\nTrue\n>>> simplifiable('C', 'C')\nFalse\n
Correction def simplifiable(l1, l2):\n return abs(ord(l1) - ord(l2)) == 32\n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/Exercices/#2-une-seule-simplification-de-la-chaine-de-caracteres","title":"2. Une seule simplification de la cha\u00eene de caract\u00e8res","text":"\u00c9crire une fonction simplifie
qui prend en param\u00e8tre une cha\u00eene de caract\u00e8re s
et qui renvoie cette m\u00eame cha\u00eene de caract\u00e8res, ayant \u00e9t\u00e9 simplifi\u00e9e une fois au maximum.
Principe : on parcourt la cha\u00eene et d\u00e8s qu'on trouve une simplification \u00e0 faire, on simplifie la cha\u00eene et on la renvoie imm\u00e9diatement.
Exemples d'utilisation :
>>> simplifie('dabAcCaCBAcCcaDA')\n'dabAaCBAcCcaDA'\n>>> simplifie('dabAaCBAcCcaDA')\n'dabCBAcCcaDA'\n>>> simplifie('dabCBAcCcaDA')\n'dabCBAcaDA'\n>>> simplifie('dabCBAcaDA')\n'dabCBAcaDA'\n
Pour information, on rappelle la technique de slicing de cha\u00eene de caract\u00e8res :
>>> ch = 'abcde'\n>>> ch[:2]\n'ab'\n>>> ch[2:]\n'cde'\n
Correction def simplifie(s):\n for i in range(len(s) - 1):\n if simplifiable(s[i+1], s[i]):\n return s[:i] + s[i+2:]\n return s\n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/Exercices/#3-resolution-du-probleme","title":"3. R\u00e9solution du probl\u00e8me","text":"Apr\u00e8s vous \u00eatre demand\u00e9 comment savoir facilement qu'une cha\u00eene n'\u00e9tait plus simplifiable, proposer une fonction reduction
qui prend en param\u00e8tre une cha\u00eene s
et qui renvoie cette cha\u00eene s
une fois effectu\u00e9es toutes les simplifications possibles.
Exemple d'utilisation :
>>> reduction('dabAcCaCBAcCcaDA')\n'dabCBAcaDA'\n
Correction def reduction(s):\n fini = False\n while not fini:\n s_temp = s\n s = simplifie(s)\n if len(s_temp) == len(s):\n fini = True\n return s\n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/Exercices/#4-le-vrai-enonce-dadvent-of-code","title":"4. Le vrai \u00e9nonc\u00e9 d'Advent of Code","text":"Dans cette \u00e9nigme n\u00b05, la r\u00e9ponse \u00e0 donner est le nombre de caract\u00e8res de la cha\u00eene une fois simplifi\u00e9e. Ce qui ne devrait pas nous poser de probl\u00e8me.
Par contre, la cha\u00eene 'dabAcCaCBAcCcaDA'
sur laquellle nous avons travaill\u00e9 n'est qu'un exemple... La vraie cha\u00eene contient 50000 caract\u00e8res :
Anecdotique ? Pas vraiment...
Effectuez la r\u00e9duction de cette cha\u00eene avec votre programme pr\u00e9c\u00e9dent. Que remarquez-vous ?
Corrections = 'YyLlXxYKkbNnQqBFfxXbyYWwBhHyYTCBbCjI...'\n\ndef simplifiable(l1, l2):\n return abs(ord(l1) - ord(l2)) == 32\n\ndef simplifie(s):\n for i in range(len(s) - 1):\n if simplifiable(s[i+1], s[i]):\n return s[:i] + s[i+2:]\n return s\n\ndef reduction(s):\n fini = False\n while not fini:\n s_temp = s\n s = simplifie(s)\n if len(s_temp) == len(s):\n fini = True\n return s\n\nprint(len(reduction(s)))\n
Le r\u00e9sultat (9370) est loooong \u00e0 nous parvenir ! (30 secondes sur ma machine)
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/Exercices/#5-sauve-par-une-pile","title":"5. Sauv\u00e9 par une pile","text":"Cet exercice peut \u00eatre r\u00e9solu beaucoup plus efficacement gr\u00e2ce \u00e0 l'utilisation d'une pile... mais comment ?
Vous pouvez utiliser l'impl\u00e9mentation de pile disponible ici.
Aide \u00e0 la construction de l'algorithmePour chaque lettre de la cha\u00eene :
s = 'YyLlXxYKkbNnQqBFfxXbyYWwBhHyYTCBbCjI...'\n\np = Pile() # ne pas oublier de r\u00e9cup\u00e9rer une impl\u00e9mentation de la classe Pile()...\n\ndef simplifiable(l1, l2):\n return abs(ord(l1) - ord(l2)) == 32\n\nfor lettre in s:\n if p.est_vide():\n p.empile(lettre)\n else:\n sommet = p.depile()\n if not simplifiable(sommet, lettre):\n p.empile(sommet)\n p.empile(lettre)\n\nprint(p.taille()) \n
Le r\u00e9sultat est cette fois imm\u00e9diat : 0.04 secondes sur ma machine, soit environ 1000 fois plus rapide que le code pr\u00e9c\u00e9dent.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/","title":"Listes, piles, files","text":"Exemples de structures de donn\u00e9es lin\u00e9aires.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#0-preambule-interface-implementation","title":"0. Pr\u00e9ambule : interface \u2260 impl\u00e9mentation","text":"
Les structures que nous allons voir peuvent s'envisager sous deux aspects :
Un exemple d'interface et d'impl\u00e9mentation
Nous avons d\u00e9j\u00e0 abord\u00e9 ces deux aspects lors de la d\u00e9couverte de la Programmation Orient\u00e9e Objet. Le principe d'encapsulation fait que l'utilisateur n'a qu'\u00e0 conna\u00eetre l'existence des m\u00e9thodes disponibles, et non pas le contenu technique de celle-ci. Cela permet notamment de modifier le contenu technique (l'impl\u00e9mentation) sans que les habitudes de l'utilisateur (l'interface) ne soient chang\u00e9es.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#1-structures-de-donnees-lineaires","title":"1. Structures de donn\u00e9es lin\u00e9aires","text":""},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#11-a-chaque-donnee-sa-structure","title":"1.1 \u00c0 chaque donn\u00e9e sa structure","text":"En informatique comme dans la vie courante, il est conseill\u00e9 d'adapter sa mani\u00e8re de stocker et de traiter des donn\u00e9es en fonction de la nature de celles-ci :
De m\u00eame en informatique, pour chaque type de donn\u00e9es, pour chaque utilisation pr\u00e9vue, une structure particuli\u00e8re de donn\u00e9es se rev\u00e8lera (peut-\u00eatre) plus adapt\u00e9e qu'une autre.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#111-donnees-lineaires","title":"1.1.1 Donn\u00e9es lin\u00e9aires","text":"Int\u00e9ressons nous par exemple aux donn\u00e9es lin\u00e9aires. Ce sont des donn\u00e9es qui ne comportent pas de hi\u00e9rarchie : toutes les donn\u00e9es sont de la m\u00eame nature et ont le m\u00eame r\u00f4le. Par exemple, un relev\u00e9 mensuel de temp\u00e9ratures, la liste des \u00e9l\u00e8ves d'une classe, un historique d'op\u00e9rations bancaires...
Ces donn\u00e9es sont \u00abplates\u00bb, n'ont pas de sous-domaines : la structure de liste para\u00eet parfaitement adapt\u00e9e.
Lorsque les donn\u00e9es de cette liste sont en fait des couples (comme dans le cas d'une liste de noms/num\u00e9ros de t\u00e9l\u00e9phone), alors la structure la plus adapt\u00e9e est sans doute celle du dictionnaire.
Les listes et les dictionnaires sont donc des exemples de structures de donn\u00e9es lin\u00e9aires.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#112-donnees-non-lineaires","title":"1.1.2 Donn\u00e9es non-lin\u00e9aires","text":"M\u00eame si ce n'est pas l'objet de ce cours, donnons des exemples de structures adapt\u00e9es aux donn\u00e9es non-lin\u00e9aires :
Si une liste de courses est subdivis\u00e9e en \"rayon frais / bricolage / papeterie\" et que le rayon frais est lui-m\u00eame s\u00e9par\u00e9 en \"laitages / viandes / fruits & l\u00e9gumes\", alors une structure d'arbre sera plus adapt\u00e9e pour la repr\u00e9senter. Les structures arborescentes seront vues plus tard en Terminale.
Enfin, si nos donn\u00e9es \u00e0 \u00e9tudier sont les relations sur les r\u00e9seaux sociaux des \u00e9l\u00e8ves d'une classe, alors la structure de graphe s'imposera d'elle-m\u00eame. Cette structure sera elle-aussi \u00e9tudi\u00e9e plus tard cette ann\u00e9e.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#12-comment-seront-traitees-ces-donnees-lineaires-introduction-des-listes-des-piles-et-des-files","title":"1.2 Comment seront trait\u00e9es ces donn\u00e9es lin\u00e9aires ? Introduction des listes, des piles et des files","text":"La nature des donn\u00e9es ne fait pas tout. Il faut aussi s'int\u00e9resser \u00e0 la mani\u00e8re dont on voudra les traiter :
Lorsque ces probl\u00e9matiques d'entr\u00e9e/sortie n'interviennent pas, la structure \u00abclassique\u00bb de liste est adapt\u00e9e. Mais lorsque celle-ci est importante, il convient de diff\u00e9rencier la structure de pile de celle de file.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#121-les-piles-stack","title":"1.2.1 Les piles (stack)","text":"Une structure de pile (penser \u00e0 une pile d'assiette) est associ\u00e9e \u00e0 la m\u00e9thode LIFO (Last In, First Out) : les \u00e9l\u00e9ments sont empil\u00e9s les uns au-dessus des autres, et on ne peut toujours d\u00e9piler que l'\u00e9l\u00e9ment du haut de la pile. Le dernier \u00e9l\u00e9ment \u00e0 \u00eatre arriv\u00e9 est donc le premier \u00e0 \u00eatre sorti.
Exemples de donn\u00e9es stock\u00e9es sous forme de pile
Une structure de file (penser \u00e0 une file d'attente) est associ\u00e9e \u00e0 la m\u00e9thode FIFO (First In, First Out) : les \u00e9l\u00e9ments sont enfil\u00e9s les uns \u00e0 la suite des autres, et on ne peut toujours d\u00e9filer que l'\u00e9l\u00e9ment du haut de la file. Le premier \u00e9l\u00e9ment \u00e0 \u00eatre arriv\u00e9 est donc le premier \u00e0 en sortir. Sinon \u00e7a r\u00e2le dans la file d'attente.
Exemples de donn\u00e9es stock\u00e9es sous forme de file :
Dans les entrep\u00f4ts de stockage, comme dans les rayons d'un supermarch\u00e9, la structure naturelle est celle de la pile : les gens attrapent l'\u00e9l\u00e9ment situ\u00e9 devant eux (\u00aben haut de la pile\u00bb). Si les employ\u00e9s du supermarch\u00e9 remettent en rayon les produits plus r\u00e9cents sur le dessus de la pile, les produits au bas de la pile ne seront jamais choisis et p\u00e9rimeront. Ils doivent donc transformer la pile en file : lors de la mise en rayon de nouveaux produits, ceux-ci seront plac\u00e9s derri\u00e8re (\u00abau bas de la file\u00bb) afin que partent en priorit\u00e9 les produits \u00e0 date de p\u00e9remption plus courte. On passe donc du LIFO au FIFO.
Certains dispositifs permettent de le faire naturellement : Ci-dessous, une file... de piles (\u00e9lectriques). Le chargement par le haut du distributeur fait que celle qui sera sortie (en bas) sera celle qui aura \u00e9t\u00e9 rentr\u00e9e en premier (par le haut). Ce FIFO est donc provoqu\u00e9 naturellement par la gravit\u00e9 (et un peu d'astuce). On notera que cette probl\u00e9matique est universelle : voir par exemple ce site.
Apr\u00e8s avoir pr\u00e9sent\u00e9 rapidement ces trois types de donn\u00e9es lin\u00e9aires, nous allons maintenant les \u00e9tudier plus en d\u00e9tail, et proposer pour chacune d'elles une interface et plusieurs impl\u00e9mentations.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#2-les-listes","title":"2. Les listes","text":""},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#21-definition-generale","title":"2.1 D\u00e9finition g\u00e9n\u00e9rale","text":"Une liste est un ensemble ordonn\u00e9 d'objets. G\u00e9n\u00e9ralement, ces donn\u00e9es seront de m\u00eame type, mais ce n'est pas structurellement obligatoire.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#22-les-listes-chainees-linked-lists","title":"2.2 Les listes cha\u00een\u00e9es (linked lists)","text":"Lorsque l'impl\u00e9mentation de la liste fait appara\u00eetre une cha\u00eene de valeurs, chacune pointant vers la suivante, on dit que la liste est une liste cha\u00een\u00e9e.
Impl\u00e9mentation choisie :
x
ou bien None
sur les sch\u00e9mas)Une cons\u00e9quence de cette impl\u00e9mentation sous forme de liste cha\u00een\u00e9e est la non-constance du temps d'acc\u00e8s \u00e0 un \u00e9l\u00e9ment de liste : pour acc\u00e9der au 3\u00e8me \u00e9l\u00e9ment, il faut obligatoirement passer par les deux pr\u00e9c\u00e9dents.
\u00c0 retenir : dans une liste cha\u00een\u00e9e, le temps d'acc\u00e8s aux \u00e9l\u00e9ments n'est pas constant.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#23-exemple-dimplementation-minimale-dune-liste-chainee","title":"2.3 Exemple d'impl\u00e9mentation minimale d'une liste cha\u00een\u00e9e","text":"Exemple fondateur : impl\u00e9mentation d'une liste chain\u00e9e en POO
class Cellule :\n def __init__(self, contenu, suivante):\n self.contenu = contenu\n self.suivante = suivante\n
Cette impl\u00e9mentation rudimentaire permet bien la cr\u00e9ation d'une liste :
>>> lst = Cellule(3, Cellule(5, Cellule(1,None)))\n
La liste cr\u00e9\u00e9e est donc :
Mais plus pr\u00e9cis\u00e9ment, on a :
Exercice 1
\u00c9nonc\u00e9CorrectionRetrouvez comment acc\u00e9der aux \u00e9l\u00e9ments 3, 5 et 1.
>>> lst.contenu\n3\n>>> lst.suivante.contenu\n5\n>>> lst.suivante.suivante.contenu\n1\n
On pourra remarquer que l'interface propos\u00e9e \u00e0 l'utilisateur n'est pas des plus pratiques...
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#24-et-les-listes-de-python","title":"2.4 Et les listes de Python ???","text":"Nous connaissons d\u00e9j\u00e0 les listes de Python :
>>> maliste = [3, 1, -1, 42]\n
Et nous connaissons aussi (un peu) l'interface de ce type list
, notamment avec les m\u00e9thodes append()
ou reverse()
. N\u00e9anmoins, l'impl\u00e9mentation qui a \u00e9t\u00e9 choisie par les concepteurs de Python de ce type list
fait que le celui-ci se rapproche plus d'un tableau dynamique.
Dans un tableau dynamique :
Dans une liste cha\u00een\u00e9e :
Nous nous servirons parfois du type list
de Python dans la suite de ce cours, mais il ne faut pas oublier qu'il n'est pas un \u00abvrai\u00bb type list
.
Imaginons que nous poss\u00e9dons une interface offrant les fonctionnalit\u00e9s suivantes :
Liste()
: cr\u00e9e une liste vide.est_vide
: indique si la liste est vide. (renvoie un bool\u00e9en)ajoute_tete
: ins\u00e8re un \u00e9l\u00e9ment (pass\u00e9 en param\u00e8tre) en t\u00eate de liste. (ne renvoie rien)renvoie_tete
: renvoie la valeur de l'\u00e9l\u00e9ment en t\u00eate de liste ET le supprime de la liste.Exercice 2
\u00c9nonc\u00e9CorrectionOn consid\u00e8re l'encha\u00eenement d'op\u00e9rations ci-dessous. \u00c9crire \u00e0 chaque \u00e9tape l'\u00e9tat de la liste lst
et la valeur \u00e9ventuellement renvoy\u00e9e.
1. lst = Liste() \n2. lst.ajoute_tete(3)\n3. lst.ajoute_tete(5) \n4. lst.ajoute_tete(1) \n5. lst.renvoie_tete() \n6. lst.est_vide() \n7. lst.ajoute_tete(2) \n8. lst.renvoie_tete() \n9. lst.renvoie_tete() \n10. lst.renvoie_tete()\n11. lst.est_vide() \n
1. lst = Liste() # lst = None\n2. lst.ajoute_tete(3) # lst = 3\n3. lst.ajoute_tete(5) # lst = 3 5 \n4. lst.ajoute_tete(1) # lst = 3 5 1\n5. lst.renvoie_tete() # lst = 3 5 valeur renvoy\u00e9e : 1\n6. lst.est_vide() # valeur renvoy\u00e9e : False\n7. lst.ajoute_tete(2) # lst = 3 5 2\n8. lst.renvoie_tete() # lst = 3 5 valeur renvoy\u00e9e : 2\n9. lst.renvoie_tete() # lst = 3 valeur renvoy\u00e9e : 5\n10. lst.renvoie_tete()# lst = None valeur renvoy\u00e9e : 3\n11. lst.est_vide() # valeur renvoy\u00e9e : True\n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#3-les-piles","title":"3. Les piles","text":"Comme expliqu\u00e9 pr\u00e9c\u00e9demment, une pile travaille en mode LIFO (Last In First Out). Pour \u00eatre utilis\u00e9e, l'interface d'une pile doit permettre a minima :
Exercice 3
\u00c9nonc\u00e9CorrectionOn consid\u00e8re l'encha\u00eenement d'op\u00e9rations ci-dessous. \u00c9crire \u00e0 chaque \u00e9tape l'\u00e9tat de la pile p
et la valeur \u00e9ventuellement renvoy\u00e9e.
Bien comprendre que la classe Pile()
et ses m\u00e9thodes n'existent pas vraiment. Nous jouons avec son interface.
On prendra pour convention que la t\u00eate de la pile est \u00e0 droite.
1. p = Pile() \n2. p.empile(3) \n3. p.empile(5) \n4. p.est_vide() \n4. p.empile(1) \n5. p.depile() \n6. p.depile() \n7. p.empile(9) \n8. p.depile() \n9. p.depile() \n10. p.est_vide() \n
1. p = Pile() # p = None\n2. p.empile(3) # p = 3\n3. p.empile(5) # p = 3 5 par convention\n4. p.est_vide() # False\n4. p.empile(1) # p = 3 5 1\n5. p.depile() # p = 3 5 valeur renvoy\u00e9e : 1\n6. p.depile() # p = 3 valeur renvoy\u00e9e : 5\n7. p.empile(9) # p = 3 9\n8. p.depile() # p = 3 valeur renvoy\u00e9e :9\n9. p.depile() # p est vide valeur renvoy\u00e9e : 3\n10. p.est_vide() # True\n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#32-implementations-dune-pile","title":"3.2 Impl\u00e9mentation(s) d'une pile","text":"L'objectif est de cr\u00e9er une classe Pile
. L'instruction Pile()
cr\u00e9era une pile vide. Chaque objet Pile
disposera des m\u00e9thodes suivantes :
est_vide
: indique si la pile est vide (renvoie un bool\u00e9en)empile
: ins\u00e8re un \u00e9l\u00e9ment (pass\u00e9 en param\u00e8tre) en haut de la pile. Ne renvoie rien.depile
: renvoie la valeur de l'\u00e9l\u00e9ment en haut de la pile ET le supprime de la pile.Ces 3 m\u00e9thodes sont essentielles et se retrouveront syst\u00e9matiquement dans chaque interface. Nous y ajouterons, uniquement par commodit\u00e9, la m\u00e9thode suivante :
__repr__
: permet d'afficher la pile sous forme agr\u00e9able (par ex : |3|6|2|5|
)list
de Python","text":"Exercice 4
\u00c9nonc\u00e9CorrectionCr\u00e9er la classe Pile
ci-dessus.
Le type list
de Python est parfaitement adapt\u00e9. Des renseignements int\u00e9ressants \u00e0 son sujet peuvent \u00eatre trouv\u00e9s ici.
Correction
class Pile:\n def __init__(self):\n self.data = []\n\n def est_vide(self):\n return len(self.data) == 0 \n\n def empile(self,x):\n self.data.append(x)\n\n def depile(self):\n if self.est_vide():\n print('Vous avez essay\u00e9 de d\u00e9piler une pile vide !')\n return None\n else :\n return self.data.pop() \n
class Pile:\n def __init__(self):\n self.data = []\n\n def est_vide(self):\n return len(self.data) == 0 \n\n\n def empile(self,x):\n self.data.append(x)\n\n def depile(self):\n if self.est_vide():\n print('Vous avez essay\u00e9 de d\u00e9piler une pile vide !')\n return None\n else :\n return self.data.pop() \n\n def __repr__(self): # Hors-Programme : pour afficher \n s = '|' # convenablement la pile avec p\n for k in self.data :\n s = s + str(k) + '|'\n return s \n
Test de l'impl\u00e9mentation : >>> p = Pile()\n>>> p.empile(5)\n>>> p.empile(3)\n>>> p.empile(7)\n>>> p\n|5|3|7|\n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#322-a-laide-dune-liste-chainee-et-de-la-classe-cellule-creee-au-23","title":"3.2.2 \u00c0 l'aide d'une liste cha\u00een\u00e9e et de la classe Cellule
cr\u00e9\u00e9e au 2.3","text":"Au 2.3 nous avons cr\u00e9\u00e9 la classe Cellule
:
class Cellule :\n def __init__(self, contenu, suivante):\n self.contenu = contenu\n self.suivante = suivante\n
Exercice 5
\u00c9nonc\u00e9Correction\u00c0 l'aide cette classe, re-cr\u00e9er une classe Pile
disposant exactement de la m\u00eame interface que dans l'exercice pr\u00e9c\u00e9dent.
class Cellule :\ndef __init__(self, contenu, suivante):\n self.contenu = contenu\n self.suivante = suivante\n\nclass Pile:\n def __init__(self):\n self.data = None\n\n def est_vide(self):\n return self.data == None\n\n def empile(self, val):\n self.data = Cellule(val, self.data)\n\n def depile(self):\n v = self.data.contenu #on r\u00e9cup\u00e8re la valeur \u00e0 renvoyer\n self.data = self.data.suivante # on supprime la 1\u00e8re cellule \n return v\n\n def __repr__(self):\n s = '|'\n c = self.data\n while c != None :\n s += str(c.contenu) + '|'\n c = c.suivante\n return s\n
Test de l'impl\u00e9mentation :
>>> p = Pile()\n>>> p.empile(5)\n>>> p.empile(3)\n>>> p.empile(7)\n>>> p\n|7|3|5|\n
\u00c0 retenir : pour l'utilisateur, les interfaces du 3.2.1 et 3.2.2 sont strictement identiques. Il ne peut pas savoir, en les utilisant, l'impl\u00e9mentation qui est derri\u00e8re.
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#33-application-des-piles","title":"3.3 Application des piles","text":"Exercice 6
\u00c9nonc\u00e9CorrectionSimulez une gestion de l'historique de navigation internet, en cr\u00e9ant une classe Nav
qui utilisera une pile. Attention, il ne faut pas r\u00e9inventer la classe Pile
, mais uniquement s'en servir !
Exemple d'utilisation :
>>> n = Nav()\n>>> n.visite('lemonde.fr')\npage actuelle : lemonde.fr\n>>> n.visite('google.fr')\npage actuelle : google.fr\n>>> n.visite('lyceemauriac.fr')\npage actuelle : lyceemauriac.fr\n>>> n.back()\npage quitt\u00e9e : lyceemauriac.fr\n>>> n.back()\npage quitt\u00e9e : google.fr\n
class Nav:\n def __init__(self):\n self.pile = Pile()\n\n def visite(self, page):\n self.pile.empile(page)\n print('page actuelle :', page)\n\n def back(self):\n page_quittee = self.pile.depile()\n print('page quitt\u00e9e :', page_quittee)\n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#4-les-files","title":"4. Les files","text":"Comme expliqu\u00e9 pr\u00e9c\u00e9demment, une file travaille en mode FIFO (First In First Out). Pour \u00eatre utilis\u00e9e, une interface de file doit proposer a minima :
La repr\u00e9sentation la plus courante d'une file se fait horizontalement, en enfilant par la gauche et en d\u00e9filant par la droite :
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#41-utilisation-dune-interface-de-file","title":"4.1 Utilisation d'une interface de file","text":"Exercice 7
\u00c9nonc\u00e9CorrectionOn consid\u00e8re l'encha\u00eenement d'op\u00e9rations ci-dessous. \u00c9crire \u00e0 chaque \u00e9tape l'\u00e9tat de la file f
et la valeur \u00e9ventuellement renvoy\u00e9e. Par convention, on enfilera \u00e0 gauche et on d\u00e9filera \u00e0 droite.
1. f = File()\n2. f.enfile(3) \n3. f.enfile(5)\n4. f.est_vide()\n5. f.enfile(1) \n6. f.defile() \n7. f.defile()\n8. f.enfile(9) \n9. f.defile() \n10. f.defile()\n11. f.est_vide() \n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#42-implementation-dune-file","title":"4.2 Impl\u00e9mentation d'une file","text":"L'objectif est de cr\u00e9er une classe File
, disposant des m\u00e9thodes suivantes :
est_vide
: indique si la file est vide. (renvoie un bool\u00e9en)enfile
: ins\u00e8re un \u00e9l\u00e9ment (pass\u00e9 en param\u00e8tre) en queue de file. (ne renvoie rien)defile
: renvoie la valeur de l'\u00e9l\u00e9ment en t\u00eate de la file ET le supprime de la file.Nous y ajouterons comme pr\u00e9c\u00e9demment la m\u00e9thode facultative suivante :
__repr__
: permet d'afficher la file sous forme agr\u00e9able (par ex : |3|6|2|5|
)Exercice
\u00c9nonc\u00e9CorrectionCr\u00e9er la classe ci-dessus. L\u00e0 encore, le type list
de Python est peut \u00eatre utilis\u00e9.
Penser \u00e0 aller voir ici les m\u00e9thodes des objets de types list
, notamment la m\u00e9thode insert
.
class File:\n def __init__(self):\n self.data = []\n\n def est_vide(self):\n return len(self.data) == 0 \n\n def enfile(self, x):\n self.data.insert(0, x)\n\n def defile(self):\n if self.est_vide():\n print('Vous avez essay\u00e9 de d\u00e9filer une file vide !')\n return None\n else :\n return self.data.pop() \n\n def __repr__(self): # Hors-Programme : pour afficher \n s = '|' # convenablement la file\n for k in self.data:\n s = s + str(k) + '|'\n return s\n
>>> f = File()\n>>> f.enfile(5)\n>>> f.enfile(8)\n>>> f\n|8|5|\n>>> f.defile()\n5\n
Remarque : Notre impl\u00e9mentation r\u00e9pond parfaitement \u00e0 l'interface qui \u00e9tait demand\u00e9e. Mais si le \u00abcahier des charges\u00bb obligeait \u00e0 ce que les op\u00e9rations enfile()
et defile()
aient lieu en temps constant (en \\(O(1)\\)), notre impl\u00e9mentation ne conviendrait pas.
En cause : notre m\u00e9thode enfile()
agit en temps lin\u00e9aire (\\(O(n)\\)) et non pas en temps constant. L'utilisation de la structure de \u00abliste\u00bb de Python (les tableaux dynamiques) provoque, lors de l'instruction self.data.insert(0, x)
un redimensionnement de la liste. Le tableau doit \u00eatre agrandi et chaque \u00e9l\u00e9ment doit \u00eatre recopi\u00e9 dans la case suivante. Ceci nous co\u00fbte un temps lin\u00e9aire.
Comment cr\u00e9er une file avec 2 piles ? L'id\u00e9e est la suivante : on cr\u00e9e une pile d'entr\u00e9e et une pile de sortie.
# il est imp\u00e9ratif de comprendre qu'on peut choisir l'impl\u00e9mentation\n# de la classe Pile qu'on pr\u00e9f\u00e8re parmi les deux trait\u00e9es plus haut.\n# Comme elles ont la M\u00caME INTERFACE et qu'on ne va se servir que\n# de cette interface, leur m\u00e9canisme interne n'a aucune influence\n# sur le code de la classe File que nous ferons ensuite.\n\n# Par exemple, on choisit celle avec la liste cha\u00een\u00e9e :\n\nclass Cellule :\n def __init__(self, contenu, suivante):\n self.contenu = contenu\n self.suivante = suivante\n\n\nclass Pile:\n def __init__(self):\n self.data = None\n\n def est_vide(self):\n return self.data == None\n\n def empile(self, x):\n self.data = Cellule(x, self.data)\n\n def depile(self):\n v = self.data.contenu #on r\u00e9cup\u00e8re la valeur \u00e0 renvoyer\n self.data = self.data.suivante # on supprime la 1\u00e8re cellule \n return v\n\n def __str__(self):\n s = \"|\"\n c = self.data\n while c != None :\n s += str(c.contenu)+\"|\"\n c = c.suivante\n return s\n\n# ------------------------------------------------------- \n# Impl\u00e9mentation d'une file \u00e0 l'aide de deux piles \n\nclass File:\n def __init__(self):\n self.entree = Pile()\n self.sortie = Pile()\n\n def est_vide(self):\n return self.entree.est_vide() and self.sortie.est_vide()\n\n def enfile(self,x):\n self.entree.empile(x)\n\n def defile(self):\n if self.est_vide():\n print(\"File vide !\")\n return None\n\n if self.sortie.est_vide():\n while not self.entree.est_vide():\n self.sortie.empile(self.entree.depile())\n\n return self.sortie.depile()\n
>>> f = File()\n>>> f.enfile(5)\n>>> f.enfile(8)\n>>> f.defile()\n5\n
"},{"location":"T1_Structures_de_donnees/1.1_Listes_Piles_Files/cours/#bibliographie","title":"Bibliographie","text":"s = 'YyLlXxYKkbNnQqBFfxXbyYWwBhHyYTCBbCjIiqwtTWQJczeEauUAZDdFfmwWMccbBOojBbXxKnNkkKsSeEsxXmxlpPLXMuULlSJqnSsNQmMmMCYyXDdvVDdtTxYmBbsSNdDnyYaAOBbouUwWiIMyYzZyPptGDbpoOPBdnNtTapPeEAHhrXxRtSjJsTPpepPGgCcEfFenNEmMGUpPugCanNAnNcEzZTtQqZzRreMmpzPpzZZJbBjxXTtEcCemMPJjXxhHTtydDmIOolLiJQqHhkKMmjVeEsSWwnNQqsNgGnLkKlcCSvdVvcCDeWPpwEvVUuNnTGhHgVZEenNQqRrTtSspjJPHhcNnYyCwoOHhcFJjaAXxDdqQfTnbBNtSsyLlYCGgWEezZiufFUhHHSshkKTvVoOtIfFTbBtTyYeqQEZnNztDdNnxYytFflLTWwSgGsmsSMXzvIikeEfFpPKdDccCTtFfqlRrLQgGqxyYXQCpuUPkQqKTeEtSsXmMmMxVDdWweuUEyYtFfboOBbBbBTuBbrReEKfAaFkoeEtTYyRroOQqcCjYyYycCtTJOLVvkKWwYylukKqnFfilEeXxLgVvqQGINQZJjlnNLzVvKkpjkKJPsSBIibQmMqXQqHhrTtRayYAECczgGZeHhFfMCbBcVvfFZzRrNlLwQqZzWnjUukKxXkKFfJuUzZqQyYfPpiIOojJFNZzhHlLnVfFvwYHhyWMmOUuqtTARWwrZNnzasSzYLlyCBbcLlKkoOZZzIiKkQiqQIRiIkKrgFfpPnexXEPpNTtOobgGBEeCDdcoOQqGQCUuhoOSnNsbBWwfFwiIFfEeZzWQEIieSmMaAsFfEeSsHKkhjOoJmvVMlLGtvVTTWwtgXSsxpPIZziKHhXXCLlcxyaeEcCAYxkLlCcEefOoFLlWweEyOnNojJZzYcXxmMWwXxydXxDFfgGYGGgxOpPoUuXRrgplLPWwqLlQEQYylLqgSsjJDsSIidIVviGnNaAFfelLVvdDHsShmCcroOOoJjSsQqqQHVFfvhiqQeEWmnNzZjJJbtTBsSjGgoOMKDdfqxXQFjJmMitTIcCkcCwrRxnNFfvVXIRDdJAXxahHZzJjzZBbjjbBJhuUAaxXHMwpPfFmMcCfuUyAfFauZUuuUzRrUjJuPZzfKlLdDhsSSsAatyYaAHhTbnNBbBQqmmiFfIxOZzoXAaAaWwMWwzZaAMhrRHHsNnSBboEeXCcxOrAaZzsSRkLqzZQPplFaIiAhHZzwWMmEeWwnplLmMQXDdYsSyWwxHhRrWwoOKhoOltTLHAaDdkgGLkKlquUPpXxdnNrRpXxPbNnbVviIGgBBzFfZIiwWDCcGggJjiIGxXxQGgqQqteENwWnTiIAAaaSsNnTVPpbBFfvtXCcDuUdDdBdhHKOokiWSCcswIcCcCKkoPSspOWwUkKuAaKkoOwhAawWaALlHCcWcJYyKkMmMmhHzZjvVtThHCDYyALlNnrRGcCVvpPgvCcMmVLhwWuUmMHUupPladDHhNnpPMTtmazZvVAakUuxXKDmMZzdGgLlABbNnMmWqQRrvVeEjSsJwJMmjTwAEQqeFfRrQqQqaqQdaADWGgtFfacCaBboVvZzDdOZzTtgGOFfGgoqBWwbxXZzsBVVvDnNhHXxdvZwWzOrRosSEeyYVvUuEebWwoOXxUuQqTqQtBbiIEXxeBHQqtTiIxXRZCtTchHQqzBktTKIitTNvVnYZzysEeSMBbKAjJpPFfavxLlXVQqKkDEMmYyenNXxtTlYbFfByLIiQqKkGPhHpFaxXAfglLYySsBpPvVbyYdnNyyYYKkXzZeEeEWwRxXreEgGUusHCPpczJjZOohsSpWtTwgGPKkvVFpPVvfSsOMmnPpNoOozezNnZksMmSIiaAEeGgoOpPuUWwDYcsYySPXCcYyoUNnCcuOZzLbBlAGguxnNwWvHhVXsPaApSPpQOoKtTVvExXekOmMoOooZzOOoIihQqHCcqmzIiZMQHhqTsSQqfFtxzwWrReETtmwNsOxXovVAeJjEaSnWMSNtTnsWsSwaAvVZJrRjfFnaANDdYzlLOoQqZysrRtTwvVWSRdAkXxKarvqQVgpPGOomkPpKMHhpPlkKDdpPLSszLlZyYBbxgGUuCdDeEcaACcXCclLRLllLIigGmMrRXxBbCcOoeELnNbBKxDdXHhkmMlTtpeEPQqzZDnNIiDBhqApPaQnNcpPCiSsqQIHiqQTsLnNlWKkNnwtWwAaThHFfGuUgSLsRrSliItFfDduQqSstTwcCKkWUhHLlSoGrbBOoRgWCcwgVvGtKkhPpBbHSsKkTFfUZEekKfcCWwHhYyFbBaAzuFrRAHvrReEVlLFfhaisVvSHvVXxlLjEeJJjgGjdDcCJhWwKkmMSXPpxsKzZwAaWkttTTaSapPXKkkrRhkgzZGCcKxXHuUKZWwzZzSsxdbBDXKkxfTtIiAaFhHmxXMnNJjUuxeEXuGgUuUzuUZjJvbBVtTpUuYykKPnNfFGGKkgoOxXggFfGrJjRoOaAOodHhxnNXcPtQqAaTmMZbBzpXeEdmzZmMkTtpPKFeEedDdDEhHqubBUQYQqykKcrRCfMSsAnPzZTtpuUNWwIiuURrdDaeECgGcyYzMIimXQqqaAQnJjwWaAeEKqQBCDdeEfeEGgaPpbBAhHKKkbmMBkOouCcrlcCdDsSLRmYyNnSRgGiFfIrcOHhUugGzZTdDtVPGgpvGgXxouLlNnlLUGgwZzHWwhPptTWfiFWwfoOsSIvsZzSVsSuSsUFGgETTkKzZtteJdIiDlLlLugjTiItFfJNnwWGiIlLKkTtnNDsSdpPUeEeEJjgGPSspzZbcjJCBAaeVPpLfSsFTXxtlBbhkFkKfuUQqKNnHkKMSshQqVvOpPrRXxZzSzZsZzHhNnWWwwqQUuBLlyYrRgGfTtFrxXUuEeYyUuKvVdDkqURFfFlLfxfFXmkKMCZAaYyTgGAatzcrNOoIntTNisSnrJjUuRHTthwWwByYmMDhHqQWzOjJoZwdhHFfboOdVvNdFDdOjJoeEOoIihHfqCcQaAmMcoJjZsDAadSeEzOSsCGeEUAcCaFaAtTnNYvVUuyZzLoiIcCOlhHfVvUuIicCeEDsSdDdrREeESsejWNnWwGgOdDuUfFcClLMEHhZzemtTEvVeXxGpPgSOUudDNfFPpnyrROoYEMmeyiIYoqVvuUJNnDdjQGgofFAaOuXKklfFdDmMLAauUSwWrXxRhHBWQqwbseEeExXbnNCcBEgGVCXQqxcwWvPPHhpraARICcQqwQPpqsStTWAaDdQxDdBbXlZzLbBdtsCcOoSOoaAEeHTthlcdDCLuUTDksSKktTqQvWOowhHCkKbxVvwWXCOoDdYycPpcPpNnCIIiiulIieELCcPrRCUujJGNMmngfFTcCvVdUuDtjJtTfNniwmMmMVvNnosSVvLlOWmMHXxWpPwXxgGhaAJjvpPlLigGBbCMmHhcIkKDuUdDeOoqaAQEJKkjrRyYzZIifFkKKRruVvNneTtpPuUEkKYIiyqCpPfFpPLlFfTtnahjJHANUuhNnIidoOpPycZHhznSsYytTUujJhHNCqzZBwKkWEejJCcHDdSshRrOwWohHbCcmabBAmMMXdDcJjCtlLTUuZztBNnbxXTuUSxwWjJXsYyLlHhMmhyYKsSkBjCcJHhMZzUuvSVvZzCcehHEFEeftnIiRrNTqVvmIiugGUTSstSsVNnDdhVkKveEHwWzZvAagGXxipPaAIvVhHhDjJBbdtTWbBFfwdDQqVHhtTtkvrptTrRPRzWgGwrRjJxtbYyqQhHBePpFfELVXxeEvNnlXjJgGxGKkgoDYypPpNnPdlwCcWzNnsSZLwcCoOrvVKkJjdDdTtDiyYyYItqQTyYmMwWSYHhrDdufkJjhHWvVwpwWylPMmzZpLESsmjJMeBbaAWwJjuQqMJjXeEaAaFffFFhnNCcZdDYyzeGgESTtoKkBbmhHedDFfHhcCdDWAawlEVvXDdxlVvioOIOYyogKkbBGLHWwhWwpPWwxRrXflLPWCciTtCcNnNmMNnnSsYyqyYlpPIiBbLrfFRmMVvQIFfZzduwtJjyMmbCNnsScCmMmptSOoEeoXuUxOsKkEWuVyYuUPpQpcCPtRrcCtFfKcCfZRrzdDFkSFYyfMmsftTlEeLECMRrmcTtQGKkgqCMNnLlxYyXaPuUcCaAqQtTAEeaMmpZznvWwVTtUkKuRrIiUuJjtTwfFjJWsSjJttTTNjJqQtIiTkMKIikmyxwWXYPLgGRccCCrPpTEetNniINnpPBzZbFFffBBbaAbOFrRfXxpRZzrFfPxyWwYUVjJvuMmPpXxxXBODdoPpGmMbSIisBgejJEwWbgGXXxxoOtTJjcHsShgGxXCzFAafsSAaZUuxTBiOooOuULlUDduDdFQqfIbdjJuUrWzZiIPFVvDdiIfpwGfFsBnBtTbvVsSNJYyXFfxbyYCPtTpKHkKzxXCcZUuuUKECcyYCcZzeIoiIMOpkKPfFdDYywWouUAjJaFtTfxXjZbBzJvFfyYjJOoMmCceBbKkEkKLlxmxXMCcCcMryYRGDdOogzQFfqHEbBtOoNOCcstTNnSoDSGgseUuLlExbdDBXkKLlJuSbBbcrRCdDBaAsWaAwtTBbVZzvqiIMmuUHtTwWfFFFfKkqQxYRWwYyeEfbBVviGzZQqCRrsSXDdxXxcvTtHOotThkKPptTpZzPCcVfFnNzIiZyIMmiVvUuYwHhuUjJdDWfQXkKxMmCtTcFfhiIDdHdsSDFEefqZzKkQROorqyZVvzRtKHWwmMjbBJUuKkRPprLlfgnNpKoOMmTtaALlbBHWdDGgwhQqOqxXiIIiYyDdzZrGcaAFfhHxEeNnpqqQQTMmqmMrlLTIeGgEmGgMZzWwATtavnNsaPpGgASZzVhHOLLbBlwWkKYyiVlFfLoOtlLTFfCOoVvjJcYkKXxpJjPHhmMZzyUaAuNNnvVtTzSsbpaAPBDwWGgbBFarzZRAfBwSRrkaACcrRizZIKkiuUQqWwIXxKQqpPzzfFZZnNnNyDdVvCmbpPYkKAZzaDuUdXQdDqzJuUTVvoOteERrdDoQqcCcbBwGgdDvcCKkVEZkKzeRrdhHCcDHhkYyATtagGVvbBFBqQBbQSsUuAjTjJvGzZpGgPCbTXnNwWJjbBhtjJmMPpQqqQuUBbEWweYKkyTXxxJIivRrvhHXxRriIIqQijJVlLIOfZzlsSLQqdyYvVJIijHTBBbbmIimMlLNnMxgGXYypPTwWteUvFGgfpPVHhoOOjJohCKkcAawPpWsSeBfFJjyYbAYyKdDbJjBPJjZzUjJTtuzLeEgjJIsSiGiIbBRrMJjCcbgGJjxRrXmMgGinNfgGFxuUkKCceEMPpmXIdDBuBbUKoOkuUXgGxEexrRxQqXXodDdDWeebBEPpxXxoOXboOqQDdBhHJRPpuUQqrjJiIXxsSjaALlSsuyYUXhHHJhbBzZPplLdFfyYDwWbauYySSssUaAASBbsJjUtTulRgVvGJjeEmFYypPZzPpqTtzSuxXBbUmMVKkvRroOwVUuiIfpPVvXxbBYAaHhGIMmjJdQqqQDisVSsvUugGSyYsSPiIpsWwhHSHhciICujJUJBbyQEhHeafFWwooOOFIimMXrRxyWFfBbQqqQwNnZaAzRrwmHYmMyxXhzAaZvVbBTEetMQGgqXxWZmMZzzRrNnXzZOoxfFJjgGgGTPpgddDYyDSsIixDdXSGgsguUMiImGymMCcyYoOPCcwNnWpiIYyjEerXxAadDKkNuUQqnQuUOoqSswDdEeXeExWoOjIGCcOolqbBQEeMmmMLFHhAJjWwvVcCnNqQaqQunNrRUXxrRQOIiuBbkEecCLREenNrjDdRrDnNwWTtzlLMmuaAIqeLKcmHCsSBbFfchQqfTtFMIijDdCKXxHPvVRrWweMmLlrREqvxXVQSsSprRPPpsyYjKdkKDNzFfZnkwWlRrLnNYBbyeEjJmMvITtiAaVuUUuJFfjMePpECcepXxPGaARrdyYDiIMmgnSsIAnbBZIioODdSszNEeFBbYaAyfFiIvVvmMfjaeEcCAhHsSQqFfJFVFAaQqfCuUPpPMmBbbnNGgjfFJqTgcCqIWMmVvoOliVvIFeEzZBqkKQbQqcCfxszZpPMmYyvIiVWwSsYkKHgGGFfLlgZzKkvVOoLgGiIRrgBsSbqqZjbBXxvVaGgAJoMPpsSmOjJaAOJjIIiizuUZYylLdKxXkgrXbBLlgGKkxnNBbWwldmMuFfULlGgFfmKkQqfLlJjFuMmPpUIiHYyIcCTtYyigGdDhnNRroOkKgGMJiIMmzfFsfbBFSXdDwACJEejcnpNniIIjJicuUCnNmMWwpPPsSRrLlPpFlMmqizsSZQqiIqQRTzZtTUuRrdDJIcCcCnVJmMjvzZAagGjoMmxXSaAsiIiIOeELlNnoPpUlVvLkKuYyOoOeQeEuaANRrxXnDDiIddUXxqWXFfuSsOoUIixzSsZYyYyYaAXxNLlXxnZzKkupPfFaEeCzZABboOaQqjkKfFJvMmVvUuVPpZzMSyYPpsOoNBySsYbktTOKGgzMKksSmMacTtCSsrRAxXPwPVUuWwlvbBBbxUkKaNngiIkBbFfJIiGgjChHcMmIiXxxXKkHKlLkeMmEkOoKdDAoOoOahKBbhSfAahJhHjJwjSsJjJmbBYenNEqQUxXykKNnXxbBrRwGgWXBbjJnRhHnNOyYoOCeEmTtFfMJjeEcsSFfeEvVnNEVlrRLjmNXWPpsSeEwtTKkbmRkKsSHhrRrRgGrUMMmmzZyvVYocCOSWwVvsfFdrdCcgGDRQAaqbfrRFBwpPMmWGgdNnJjvVDKYyPpxGKkgzDmMdZPnNpWVTtvFmKkELqQtTleTtwWclLcwWUuCTtCOnNaDdMmRrAiIgdLlDaAYyGBcOZzolaEeaZmqQbpPUuBgGdDcCgGhfVvvVFGgoOsSrRxoKkOXYXxMmCpPhHlLVvcIiEefFOodDlUVuUGgQMQqHPphmOMmolLCuUASssUuVUuvdwWDaAEeTaDdVmMvCcDdjBbZnNznNMyYRrmcCnNJVvrxXtTiXxiVSsvIvVBbxDPpdPpoVvSqDdQZkKzsOXffaAYmMGgZzguUpaTxxvVWzZWwwBRhHrSoOFhHEeyYTtfoOIEeisSsZoiGPrLIimpqQzZPMhEtTeqJjGQqyFfYgEejJvGlLbBgqQVxDXxwWdVjJlaALjJjnoONmdUfFVvuTtDmMNnmMPluULSszrRLXtTOoxSNCbBCccngnNrRbBGYhHyqQibFfJSvVsTMmtzmMZZsNXxnSzugGjXxJWwjJlVvnNAIrRAavViiIUytOCXxcnNCEeckKTtjJonXxNnYyJjMmhHqQMmFmBxGWkJszMPrkSspPJrRkzZKjQnBbWQqjGTtgoOTsLlSHhDzNnJhHPpQYygkccCCPpKGjJMmDvVCGcxXTtEUwFfkKWlLurRRrESKJreVvZrMeyYNnEDdDgGnGgNdDokKOnNiCVvxXcIzEoOemvVMOoXKkbNnvVBcYvVbBgGWwmMtTNKkGiIgOoOooOHhCqQsMmSnNJsSfQWCCcGlLeEuUgZztIiTqzZQIxZzXkMThybBEAaOgnNUDdiIilLgLlGjJIuUPArJEcCoKLlkOuUbBBTrYyEeiImMSNnlBuUbwWAueEgbBZhHgdDlLOoGocCwWfEXCcAKQqkSzZegGKktTlLCCdDIiPpcuuvsSVUXxfflDdLtmuUMqQTpYyPdDVMmvXVvxJjuUxXuUmMOClYyFuRvVcpPqBPpboJjaVvADbBdfFFilWaOoAwPpLfKkvGBbKZzcCHhwBbFfmMWUbBuKkrbAaSsCclDqbBAaYDCIiEwXxWejNYEXudCcCUudalWwgGLpWwPVvWjICcZzidDxXhHzZJTtYyeEoyUurjJRYdDTtyPhkKnNHOPpJTtjELlNdxEerRHhgGiIXMmJjDJLlDqQHFrRrRmMqQotTOEevVrRWwCkGgKJRrAkqQyJPXkKxEhTtfgGFHEDdcCcCzZYNDqQdsiIMGkKvaAsCcWwSrNnPXxwqbBQHhWrsBXxgPQqpDdUGIUuwpPcCFptTtJKkNqQnolLZcCkKRsSpvVGaKkAnpPLPKkKkoJjOxXRrUukKxbBefgGAYylRrtTLbBaxXniNFbVvBeOoPpEEdDYynMOXxopjJPuUeEoOpPLlemMYEeGEegeEQqXTtDxXcCdMmnrCcRqQhEefFHiIZHBxXbdOoDuVvUpPuYwUtdDTluUxTtXRrLLzcCZAUnMmNWZzbBnNAGgbBxXpXFRrZlLeGgXxEeJQqxOGgKkMSsyxXTVvtwWAaHhyYHhsSAoOOofFfChHsScinNcCIFupPCYTtyceEprRPewWbGJjgcMBCcCBbZzcbmGjYyhTtzUuxXZHcCMUumAaYyRjUaQqAuJrLlPpKkuODdWwoGgcCUUDduzTtZwWKYyQqQqGggsIXxiSOmdDMognUuxgGHNndDwWtTOHhoLllrRrRfvVbIvVXDdooFWwfFfOnrcCUXxBbuRQqHxLWmUuxXJjxTtzZVfFXtTwWoSDdcCshzZHPpVvTtDkjYkKrWwRUukKwWyUuOzZopPQqRqvlLVQbTtqQiIYVpPEWjjJJmbBjJMEnNelLgzCcJDdAaOoJjdDdDjyYTtRwdDAaaNMmOoGCkKcWpVvPXkKqQeExwgnHhVtkdDKCcTGYlLNnRrRETlIiNdDzrGgOonpPOlLJjsGvVgtLlLlaAzaAaAZiIYZzyVvTmuUGEeizZIDLlRrtDTtdfFcCowWOdUuyYEeDgSuUKAfkKNvdDVnGaAgFaAauonNOUQqwDdHhbTtBWgGBJjtTwqQpBbFfwWPKkZBbzyiHCchRrDdWLlwEePpZzleEJjpPgGLsStHhiIiIWwPpWwTLqNpsSPQqHyYhbBVHMXxmzXJjwWRUuZzkKJAajgGNxXYsOoSAayiiOCcouUtTlLIiyAaDdXxGgYoOTtjJgGlTNnXhHBbxVvnnNpsSPNjJIyduUwnNWWwJjKkWwYFIiRPVMmHGgNrmMJZzEeHJWMqDdQeEFfySPpklLKIvVDeztTfSFfsuUFrRTwWuOHhVvoeEVvbBkKDAwWJrRwWWfFUukWORWbBEewaAnlLLSslIJXxjUuUzeEeEZwWOoujSsHpHtThOoTtlLHJOdDSJjQIigFxqHhQYyOoYNnyXWkXZzUxBznOoNnWwlgGgsSTtocPpAaEXbBGMCcmcFftTrhHunyYlzmMnzZsSNekKEsZzuUeiIpPsSlLJjRUumMrbcCVdIiHLldDtTqKkAziIZHhEOoMmCXxcVvSswWAaCMmlGTtgpPLQOQFfqzAaVvEHhzEevVnNnQqNqTtnNpPTNpfFGnNzZZpXamoODdygDqQmMdDdyIkKiSiXxSsIiRgDdGhNnHgGlTdnNDYWwyeEvVCcXxJeEpPqQoCcOPEEelLjJoOEJjeDdqQWwyIIiLEelUuyYfFQqcshHheEHSCvVOonEeNnAaAALIilpxGnOoNOjJoDoMmruURKklLOKigGuUBnNbGgbBgGFsDYydIXkKHhNnhHToOhKkeNnEzJmMhHjmpmMPdDaAEeRZTFYyyMmeEtTMXxmUuBuUbQqQnNTeEtqCcvLlVQSMBZzYyAlbFzZdDTtRZzgEeaxXAgGLcpPHhUuCghyYKkckoFuUfOKyYOoCrdDegGpcwQqJjCcVvMmPpjeENnJfZzdDozZiIALqQlAbgGGvVgfNnMmZzFoOfiIHOvINpQSvdeECtWwbBrDdQqGgRfiXxKkYyBIibIphHUoOurYQUuqyLlTjuZSszDPpULludVFQPjJlLBbIGgiCGguhIiRDdqLlQuUsSPcCpnZzNsEefoOlLoOFDdqQzmMZSsqQhHSGgTNNgGnnZejkfFbBhrRHRrniOoIrRNeEQQqqUNnitBbTfwbgGBWwkLlOmnNgGCcDdhOhHZJjzxXodDvMjJmCcrCcgcCGRashiIHSubcCiPQqrRiIimbEHhtTlLeBaAeEjJMQqcCJqQApPENeEBvVuKSskjrTtvVRTyYCcjJxcCXGYMPpmowpPjJIaAjeLlEJSqQPUSnakKlWUnNuNNpPLlnnBbhGoOCcErPIipgGcCoOQAqQGgflnNVvFjJfLfFolLVvsSiozNnPpZjkKkBkkKKbKJQqcssSxBbuUEeOobBdXxRaArCFfMbkQqCcAaNbLdQqqQDlLvRKRisSInNnjJvMmYhurrrRtTxOHaAhorJwWWwBIBoODgGMGbBgmyNaZDfFwWJjCcuUpZMEeFfRRrhHmFfsKkDdSMdDmuUFfjJWBbwrRurRXEFUuRYyroSsOiHXSyVEeeEoOqQTtkCcVHSKWwlAxzPKoOzQWCyNnYcwKruQgGuUeEcCqUuURVvkKvVuwWGVKchvoOzZyZzJRrjYjJjJVHMmOoeELlCJjoErRPsbbFyYYDdpPdDKkZGgzhnNOnNWeGgEMmWLltwWyxXGwWganNjZZzUgGCzZyYqQZgGMmzhHaAkqQKdSsIiDfFuUIiwWRrDdlljURrVviLwWNmYyMfFKkMWsSwnNEeQDjJggGmEeWJGksSlLxbBAxxeolXxLOdDEHhyyrRYYRrZvaAVzSsSsospcCYPpyCcPLlkKxjJfFkKkEKkBXxbeKCbBDdcSvfrMmFfbBNNKgGknxXyiIYaQqAnLGgEezJTtNnlLVbWwbnlLNGAEfNndDFiITgMmEegEeGMswWAaUuBOgGBboQdYOdjJJrRbBfFIieEGgwWjCcbxXnZhEepmMXQqxgGPAanoOPmOoGhHZOrCeNmMnBiKkRghHHhGfKGgIaAiPkZHhzkKiQIiFfqIKpPpdvVOoDrzpPZjJFfNSFuaASjJNkKGKkxXKPpSskKkaABaKkyYFfAwuUWREebJjnjYyInRrNdUuDUhHuMgoOGcjJCQRLlkUuKYyxTtXQqrlLqQpPLxXsSUbFSqkKNnQTtsfmSRruRWwriJjKkKkJBbdDAtbBTagWwjZzVmMSRrsHDABbXxuBbUCJjcpSsXxMTtQqmPbBqQWofUuFZOozOTpwWnygHgGOfFSsTRrtLGTBbtcCTtvsEcCiIoOeBbJjfjJFLKkrRYjJzElEeLwWhHnNYyCrTwWtWpNCcNnNnpPFfyJjKWwlJCVDdvcOojWwLEkOoIiKEeQyYCcmwWMfpWEaaaAaAAJjAsOStNybBYsZzSAaVvmIipPMmpPcCCcAtJxaAxXXOojdDyOoYqQrWSMZQqYydDzsSmpSsiSuUsIRrjkKJhtTZzMmZzIicJjQxGgbBsZWwzSUiIbQqUlbBtRraAzZTVLpaAkyhHbOohNnHrRaAizywWIsTiIteyYtTESzsDbBERakJjKArCPdEeKkhbBYyHIsSqqQVvjfFJjJezmoBDrRfFdbvVVRrRrBbGgxAaGgjJXSKSrRpwWBbPDdhHidDQqIwAanRFfgGliDdtTzZvbRwWrGlneENLgaAvqgvCWwcVqzZBJAaEuEJjNgGneUlLzZzlqkMmjPpJaIilqHhWwXxEOogGGIPJjCoOJByYYydSsVUuxslmMLKkWwQqwzZHPphTtPLlhuHhMqQdcSEYcCrRyVvVUuvgOoGLYosSORdmMWivmMyYGgEEymMYZzezZiIBzZFXWwmEVvsSYyeBbEbpPBVvEaeVvIinNEYcFnoOFfkzpPZnNKvYySsRrpsSSLlMbBqtTdDQtTYYJjkGgKLlhJjUVZELLlUnXGgxjdDgEiNNnnSFdDdDZAasSzuYyWwhsQSsXUYFflLEGZzFfnBcaZzUbGgNvlCcMmuUBTtbLVeEUhmvVCfFcoFfcCOMHuiIXbBxHQtOWDNndwDNQcXQqKlpItsXxjJcCSzyWRtTrwOwWeEJjlLIWwKBnNrxXkKVNWCcwcCNnnbBvgGbBeECcxEeNJjTTtlLtrjmMJEekKafNnxfFLQqTmMxXNnaexhHbjJPpKkwGgLmtTMiIYdDgGygrRxXGxqQXKcCLHhlAODdoaAfgPOlNpPPXrnLqQlzynWHhSJZzWLgQqjZzvVJchHNnNbNQsSuaAtTWJDdtMRbBMSLlomMZetSsSaNnCcAaptTkKSTcPpbBCcCOkKotIiwWAiILgxAaXlLWtTuwciOWwhBQuhrRuUHwWijIiTtvoOVNNnnDaouUEnNDuUnuPYSlVvHhLhRriIYgGyHmMUrRusoUaXaACgGDXxAjckKQwWKkwWzZBGvVWwhHcCWCcwWgPxgGhEeTVvRrgGKDdkBbLMmDOUuNcbBcCMmqQVZpOoxXVBbnvVgGMmCcxuGgUVviIBMeSscCEkKeWwEpmswnNcCYydQqDkKWkKjEeJijwWVvJCngGOorgyKUuktdLagGzZFfnAakKtsYfFHhXxsSIiNdDiQnNOohCvPpVoOHZFWwUumMPetTXuRrCcUNneEGgdeDBbdYyiqQIlLlLNtTpHsSttTTBbgGcADdfdDFLlSuUeBbDAadRwWvSYysZzrcMmnNCVGgFYgqibBhZzHYyIQNUhbhcvVlLCAknXceEaYyafSzZseQqEEheeMnNStTNhDdHnCceiNKkMmbOoHhYXjJJjYFOWwIiofBbZzoOpzZXxgbpfwndDVvgieESsqPhQBcCVdNnJYyAahHjPYPpyEhtHhBLjJrXxZhHfFIiQthHqQSdcbEepEeNnPRryWwhHYvVphHHyYysSdYyYyhHDgJjcNnxRrgGNndDgGXWwTnArRaQqFfVvPpLlNeEofXxiGgIRYyrSiIGgdDwDDdKlLtTyXcCnNaqBbpTtMFbvjJQhHlLEckKZzYyiIbBZUuTtIQeEqhHAtTHBbhxXnNpPcwlLgGYeAaSNZILufFbljJiILBSCPpcAabxIiLWNKUuQqHbPpAaYQqOopPwWGtKkSsTnIhqPpQuUsuUAaSHRmMrQqhPxXSsvBtAqQZxXsRrSEDdqfFPpLTtQGgjJqfAnYRYAxokKFIfFDdPpqsNLdDBHhJPpMmjSgGsYoOQqyusSUhaSNEhgGWmXXxhHdDxMhdDeESsTtYYANpSsPTfKkTGgtjRhHrJAnNasSTtaAsSdGrRrfFXxCmMIDBbDlVKkvyrRtToOzZOXkJjHGAagfFhPogLEvhZYyxXzdQhHgGTqQgjmpPMJtTRMmPVvbPyYnbBNFBbzXxhoOHoMeEUuwWtTmzGwARoIIiaXDdKkVdDeIiEdBbZAYywWIvVJjiBgGbQpwbQMgGTtmqFfBTADdqbckKCRSsHhrIzZJaOptMmTPRRrFYySssinBUubxXYNnIDdbFfTUdDqQyzClbXxTISsgXpPXwTtWAaxGlvEuUwCcPmjuUQbBqaRulLFsSVyYHIIkKihDpPxKwIibBjDdJeyGitQqQqFgGzZQqyYQqAlyMAdDabBMnNhkHPphWwkTIEeHzZhRrZZzkKZclwzZUuDVyoWwzZQqzxupPsSUWSswXxgeEuUvVsSzuUDcCVvdQqayYASxXNBbDtCcgYyJjEmMYypJjJToOtcCndDQqKkNZzOdDlLKNJpPtOeIiefFEUtTZzyYoOXhHxchSokKOsqQHCrOsSfGgFSsCRrcTaAbBtxXuYybLgoupPUSsVvojJOUdDuOQzgGDdcCZTcjjJJaWwfFmMFnNzZqZzmUuLeWlSUTfHaCUuiRriIlaAScCBaFDQFZzrRhHAjJQQCEecoOjeEkKJiDAadTttIiSwciCcIKEArUiWKBbkKXhkPpIyYrRDkjfFwWfnNFfaAehEgGeHKDeEHtTzYyiYXxMuUNvkfFXKZzkvVxMvVRkKrCibSErRLlYtFfMmKkvpPVWwmMZGgEKkJjKFfkxXBboOcjJfGgFkTtmEOUsSIVFGQqIDdTttlLTTWzZgpPrqJxXYyPnLlNpjaASwWPqwyYfagOYAhMOcBxYdDrsSRSsRrJjOLloPpmCvVUuDdrROoRrgFFflHvVxtkKTusuUYyXmMaAxSeNYyCvVcnEYcjJPuiamMgfyzQcCPpmpTxDdZatTVLeXBbAnMzqGkWKtfFfFBRUnNuLlAMmaQMkYMmPpyanADHlFfAZzGWwVMmvDxXJAajKPpkUuPoiIOmMhIEeeNKkyEGlKEekAaxXuAGXxnGgNBrVvUlzZAaFXQqBBbbDcCdsSxbBjzdDDOxQqdkKQqQqxnxiFfHrMmlWUNnuHhnWfFgGoOepHhNnaAuUtasGRIiyYAixaAXVvSsbMEemAaaFNhHvViIiZzIIipEQqcCTtNmMGRrgNiVvIgmyYoOxGNExmCcMXtKbHlrGKxXkeLlulLYbBLsSlBbCcSyYIiwmaGGEVvZzkKStTXxsZvZZmMyJjqnwYyxFAafEllGfFNngmMscCnjJbaAVnVqQvNnfRrzGIbBiQqpPThuyYUuUhHxXjJcCOoNVvEenBZzNEqQemMpuUuPpQqrmMxXhlLSMIbbBpkKPTtpPBKjjJIqQqIYyIKsScAaAabBJoKmknNerLlGpovxXhPpHzofhdpgNnxsSsYNnBbHdDhaGwWIBRrbEeixXzJjZfRrFaAAajNnjjJowWWuIiTXIJGgjWWwfLhHlFIiwJcCCcjAqjJIkKIigAaXxJhLQqUQqrREJjRrFfeHIEePpkKiplLsPphHUwaAIpPwaaAAEQgGRruHFfmpPwWsSfKswTtWVvRrkBsSXxNnuaAfdsSgLhUuHlGtTtIiTyYKWwTiIUureTlLtEmKKBboOsgCTQrZyYtiIeEUfcCcQEeRTVvkGglOttTxoKwWksCgZzYyJjXVlLsTtgGXUxQdPoOHhMVmmhHknmMkYyaHxSsXnNhtTeqwWQPpnRXuZEezEeWJjpeEEPpVvnNtOoTtKkNrReAaAlLaFfJXxSfFCciIfkVGUuvVHnqIizOlarqnNTfFtQnNuRrLEelURkBSYysbOoEeVYyvLRrXxNnxXnzeEkxuzZbBCYSoJOqBPXxpUugttTTVSyxAWhITRViIvhHeEPfpiFSsRYytDdXNiiIqQLMtTNnEeaqlUuhHHvrnNtTSVMmhHTKkzZtRNmMcCPHcQqChqVHgovVrgGRHMBbwWHZzLliIhNmMncCNnwWPpoBAabplAaUuLiiIIhhHHeEjUuTmoyfiIFYoTtvVxUuXqVPpyYJjwWlLvbBTtaAUKmMSLlskHEpmMjYXPiyJjLboNURrwYyfFgkKGldDpPLGoOKNnfFDAadGgNpPWwHCxTtOqNQqnQeEQqzepOojFUluXxUCVvgJrRjKoWJjFfwWGgGgwEVWRrwsCcMrppPNJlLQGgzNncCqTcsSCwDdvgOIiaAbPplLBKJTtEhEVvamJjpPcCLLTJgGjtYWauUAXxdDgiBbIGBcTPMwYXPMrCmepTtZbBNEeXAIibpPSFfHwWoOOoYnNMEeQKkdDYCaAcygcnBKkDoOcMmCrBnArzGldMxanlzNuUZSsHhclLgVTgdDkEAeGIBrRVvuyYdoZVvEeqQfFbBfxXeEXjJxExtzHMpcCPMLBAaUuUlwWVqQaAYaAyVvIuunNUUPptTQwBxXBbQsuUXOoxuonNOUqQEzfJdDUeEjJBbuYyjUxZTtHFfbjJCcAaKjJUuAakBesSzZScKkwWCcCsRrrVvhHUmMMoJjLlqQTVvTvexXdWIARBbGbBcBbMzogXxGOCUkPoAotTOktyYMqnNQbNqxXZzLmLNaVvhlLEeGgIwWPpAEmyYUNnqQTtuNXBbxNBbMmsSdDnFpPNnFvVcCncqQSsYykKCUsLlxxRNItGgRUurTqpwWPumwWwFTtqUctTVPpzZHVvInAadDNojJrZzRDUQqxXTtlLGlLkKRrghqQHzaASsJNvjaAoORrTjJaObBHhMmMmgQTUwWKNnoOkvVoqXeEyYaftTFlhHGrobeEdDvVvVsfrRFcAPpXtxXTxVujJvZzIielLESaKhxEtyYCcTLlQqGgeEecVvEeIRXbJjKHhpXsYUuVvRWQjrRJqfSsFNhHqQnHRRlLCcIkKooDiqCrRDbhDdsgGGJjKDgGdkRHGgXxPMmQNnwWlaHhAlRrLhHftTyDQnLbBJwWjMmoFpdDPXuUEWQjFfCcyYYzZvRWuUfFwrPpUOoufFbBAahHMMoVbFUYyCWoOLZjJXxZGqQwWypbsSwWcoMmOCnnVvNQnbahsSUKkAaJQfkvVOoiIrRvOKkpPCVbYyAkKecaACtTnGEAJaRHhjJOeEoaSvkKVxXYpPvMNniINnztTkZzMhjPpaAqQkiuvVSwWHsACckZzualLVWwoGPpgOxIigGRrlCYUtTuxmMcCXtkAFmuUBuXQqQqAUrkqQpAjWzZliCJtHhArdDRQqGOoZdBziIyfFYGhtTEeHVvflCrRqPrRkKZiDpPyYhHKkCcduJTtxPpYyTMeEnTtGgkKNixbjJIPpSGfMiImBbFbBnysSYnLDqQjJdXxlLwWrROjJVKxoOaJjBbADKkUuRmMrnPpKTfFityYyaxJtTkuMHzJHhtTFKkBiWiIqNcoYhHUutXXjJBYysSbKkFfoORTtuAaPFYyfpidyYDsSFGaAmMgSjJiaAdCkKjvVHdDhjJDJuUjdOofBbFjlkSpPsGYeEEeuNOHKknCOdcCPpUuTtDeEEegGTrlAnTtYkMhpPHqVXxNnIiMpniLhHpPYRPpMoOLJcpPeMJjDQqAomMOaEetWTmJkrDaAVvdCcSsqUOjJouQgkKGNnllGMmRNJjfTtAErsVJUulLxXEBYyIibExXqdDiuUjZxXzvVRlcCLgCctTCINmMLlmQDdSsEeRGgrRsSlbDZIiXtuUzZTeESnNxKkXsJjxzpPWRrYqSiPpfIgAOpHwWPlLpswwWWwDvVdVvLzFKkNXxwlLWnzmJjQqqhNnMWxXGmMgwnNdXLlHOgGZziUuWFfXLlIHhGcCqQgcBbbqQGaATtgBKkEJjHuUeyYVXQDdxshaAdDWsSfFQAqIbBRddDVGgqgGQclRrjnCcNLmLlNlGDdHhZcCmVZAazvtwnbBdXKkzsSlznfiZETdDMdDlKkJjLMGgmZcTjtTgGJEkKeWyYwPpxXtTjqQJWwvSsWtTwGgiLvEeVZznNlIPFfpcBbbBCAPRTcCsEehHqMxRQqNnaAaALbysaQOGOoaAOoZxXdYydDpPdpjmMPBgGbEYzZhHGFfKkDpPHhdEetuUhHYWKjOImPnAaeEITpPFffFZztNEgTetNfgHhHhGTFfPTtlLDChnZzNFdQUYqKFfZiITIfiTCInNjyrRDNWhHDriIKkyYsXXbBOoWjJrfyYUuFIeEXxhkKHiSsgGRwdcCKkXOoNnXaEeuOIiogGSNfpRUkKFVhouUOQCNnIuUXrTQNnnRrRcCWdRyFfkjpPJRMfYyKkvBcCJWcCwjsAasSwmMmVOoviFfUuoFfqQlLLgMTPzQGgqAaiIZkANWUvVwtqQYyTWEkYnRUGXWFfIijlaArRoYUHhzZGSsSLlsZaADbBfFzMmZKbBkgrRGwWVUSeEYsaWwOKkHdFfoTflvVEeyYxXoOMzQHsIYLDdZWSsVvXxgGQUkKcCEHExATBukAaKkNaeffFFcMiIYSWEewdqQqXRrnmDIxPplLJEUqQmhAVTcmMRIhARrpXyuWQdDnNwWqzZdzWEirRydVILocnNWoOtJjnCczyYlYuCNnFqQCxXJsSTvjagJgdvVtTyYcSAaeDvnNVKkQquUsAaRfgJjGFrkGFqQfmMoLFMmMAahwIIiJjnNitTfFUucRWOvVvrRpgGPreERcIiCGIiiIKOGggFfFfxqwNTjJHFosqipJqQMoSsOmfGgFIihcUuyaOoXFfKknNxhHIVoORWIYCULbKqjNjJnyYnNWwHhZzkrzQqZewXgGEeiVvImsmvVmJjjokKMuUpbuqoOQUTtdDvVyqjwWBCccCULlsSuMAyOAajJdlHSsyEwWykgGKwWNnssqnoOOlnDiIhxZzVrRvGtewxyYjJZRbLkKmqIAavTuUAMmxOoXaCWwWwcCctTPVvpwqfoOFQWPogGvVSBhEpPXxjyYbVvRrdMmNnWcxlFkKfLHzDdZqXWSsLXxlYwVCQLlyOQrRqaAuLUufFluirLmVyVvhHKwqqQQtrRZvKkNFfKeEGnOhWzXxZwWmChHEeIbOohHBQjJkKqsRrSZzYOQCcqwBTpZzxgGXrSzZsNeEaJrRYyxppKVvkOJjoqbEeNKBbvVwqZzdgGnSiIscCUvhYyUutXHaFsEuKSsHhheMAaGgsSzZhBbJMmNxCqdgGgGHfSlLsGgYysSRrYsVFftTtVvoiPpbzRpFYyezHmMwYjrdSyYfGlqRrncxihHIEeIqTQqycokyiYxZvNnxjJGgMmXeECchpXxPzZQzxNWvlLSnNKksVwjJqhHQnGpgTtGZVUjJuvzPnFEGgXxVRrNbOyYoBCwvxCONrRnNImMinoRZtTAhzQqQOoPkibBVxPpXaAadBcCbGBZzcCWdiILPuUTdYyubTSNRkhbXxBPTNntXKvApPatTMamVvMAUWGEvVWLAaiAfFUupEKZrRYRrRrdDyJCcoOLVvdjJDlLlRrmMjJjrRxNnioPCcWwRrpNnHETadDbpxTyasBoOVqECcMaiImzZSBcjPAapSsODiKiZnAKkwNncWhHPImTtVSAayYsdrnVPpZvWIioOzZfCcqNfPeorROoOOIiXuUustWpvxXUuUmxLlAaGbyteExDdQmMqIiIBGkdxfBHukiVvbQMutIiTbEeMzxXLUulMfFmQqfTtFcAtxbypPDPpdZBZzXxwpPBbqLBbaAjJfzZKkrWiNnIwRplbtXAEtSXxVOctmuoGgOHdDhlZXunQRWOIlYDSrRyYOobJiwWLliIZzIWqowriCnxXuMmUyEnCEzZyYNGysQqbBIiAEeXGPpAvVaGzZCSMMhZzHAPDdqlCcLpjnNUnMKynNJnNjvVepPaAEJjOtFfDdkKEYlLBHhbsSgaAgDdGUCvVcuPBKkVTtajJcCAznlLCSsSntTXkOaHoIAqQeEHNZFSBbMbhmcItTmMphOuxbzjJZhlIiRsfCuUHiwpPQqWAtTerEVsSvVRrYzZnvNqtFfmMTPptNKUutrHFfhjJlaACnnNBbYGgQqypgbEeZgHhwWyYZFFBubBUuUrRNQzZJtTuUDLqFJFOoqwfFJjWuUBbfbBOEGgDdvVXxeoFQRgGohDdHkKBAabMyTtjDdfxXwBbmSsDqntxXTlUDArRtgAOuiLPVBqFLuzZEeUEesKiXtdVvxXGOxlJwWBQqJjOPnNBIODdoURrtYyLUuNnTtdyYMjoOIXyYJRMmevVBYddkqQEewFnHhSvVqQMqQeEgGFfESsYmcsSCkEMfsSFzZmsOaRTtqpPQrtTMIeMdfpzUSsHFBbfhBbBbZzUnNxvAaVXFMVvhTtUXAaxnmkWwgBxzVHRrAaUCFgGpiUSORHQXYtHEfFbXRIBPgHhRrVvAEeEHUuheDdqQStzZxJVlLYOoYyLsrRXtTxwqPpHiaFlLsSsgIiVGgvyTehzyYTsjJJhLsMRrqQmkSsXnNMmfRqsSHhcgRLlVvnNIiYLOkcuUCKXIXbuwWUAKkaftucQmZMmzMIIUWwuHhiiqPpPamgCcGACQAGjbkKZzZpcEfeGbbBwtTCcnNCcBbWLXOrDhgGBahjYymuhHQJjdWnNxXmuUJcAXxamMXiIkbhXaSToOonJNnFfPOHhnNEfdutRjOHhlHhLAUuYqoQCUuWwhHxcPXxAMBQyYGgqilDplpwgGFKFQqfTtEBNqRXWbfONnoFnNMIyLxUINexRrXPiwvVmDdksrRTtaAFGjUOEyAzEJbtuYyQDdvVqTroOrgGRNmsSOovryWwYGejJEcsuUtTsLmIgGtMLlRVvXwWxAaQqddnJjZnaANwgUusqCOvMNnnNAGgaAcvjnnNnOAaUHZzwxwwktZzdDAaTKGgyYTZDcCdjGgJoOEenkimCHldkCcSDmMgmMWRXtTxQqxGpYzZVOovCpJnUufiIlgcrqQfvTDaJjUAfFaQAkQnwWcCUMSiwSJAuLloFfQUfPpZapSFdDgmfFHHfdrJcIYFfGHhUQqzPplLeHCczrcBzZjZhuDmEBqlLBfCeGgQqMqJognNVvMPpNnPGgNYyDdIiRqHhhHurRUmDjYypPBeWuUmqxahHCcAgANrRWmMoiIdaLlAiIlLsGuUgGnNgSWiILNHhnTxXmMtoqmoMlXghIlLOolYKkjvVGbBwWZzAgGdDOaKkAMmQkDHGxLlPSRrvVsHBoOEeaMmAsSctaUNuUGgxxpPaNSwIiIcCsSgYdDyVgLlXKyhYCcLOoIiKgnNhHYuCCLGVnkgGLbAaEcCfSAHhahZelYyTzPpZAatLUJdDdWwOyYoDrrsBiIbwYyroOqQlHMmhBEUqQKMtTmlArkByYyYoOiJPmMQOoqYyYwWnUugFfNcVVyfFjNXNnxRrRrMmMAZSszKYytYwAYQhJqQoOlDEemewxLtTKFfbyYsbBJjCcLJpMmjJrVYyWqBDFfdOoEeGcvGKkFfLKyYkewNnfFZCnsjJSBiIbYMboEEcCeyYAadDXhHUKIikbFUoWwqQOuvdgDmMeUoOOouvVdDtkXTsSACocOoGhHgGjYysSuQGUuGQqgGGzWwKTlLtSdvVuUoOgGfRLDtUdDVtTvuYxXuCIsSYyCKkyaMbBmuTdDnWvrDCbBYDqxSseEpcTiKyYkyFMHhDlfjJlTHnzNnZNIihjMBbguBbfwvNnOoVlKvdptTwWlLjJAwUKkzeEKStTtJKGxeyYXNJOonNWtBbXxxjTqsSKkrGjvVBbBqQGrqQmVvfiCckxiIXYAVjaeMmTLHhsIiIJRdDskKxXxYykKEqjWqQEeZTtxxWwlpPDdLXQduFzVvZyYltTfFsGOhcCHogSbBjbBobBOJaEbqvfllAUsSuZlLuUzGopPOgGgpPAKkFOcCzZBUubEeNnWwTBuUzvVBXpByobmJjGgsMmMmpDEhHAaQAEeayYPNELlIghjJHJLWcMmCIigllsSyuwHALsSlpPJxvTDdSstVbBQqGfFNnrnAaNogYyyYGDwogGdmMQqFAoncCNgoOXaaAAXkKMBMmbhEePpBnNlLffYoTNJjXVvKkPhCUurcyLVvlzrGgIgNdvwJeEjWVSsYGgqjnsShHxPpXueEwlZzHhHhLWRrmNnRrrzEsSeNHhhfdLfOoRluUwWmDazZAJvLlVeERrgGNVKtmbBMZzHuUMmbBVMmJuHYycChUjRrDbzlLguUYvzixMmxXFfFfXFmiIMWwKhGChHZehxqwWIWwYHXalVRrPpcZTqgGJzZjjQztTZBsKkRrSjNBBbPptTsSbncGgCyYTmhkaUKknNXxuAOtFRDnNzZlUKXNfKSjcvJlLmuUJjOZzBptTPCszZQqxXjYyJkYyKoAYyYvVzfFIvrRxXJZTPpUmbBXxKkFfEewqlfFgvVGtjsSEezZBbjxXeDyfFUuDrqINIieEWwAaEtOxxOSsAazrXxownNWoRPAQIiMmJdJLTtnPScCspexmMXqtOehkkeEefLlAauNnuULlNBHhjGoziIrIRrHscPpCbTtmMUPpeEtPIfFZzVvGgVIiFfNbVUubRApLWqnlaAWwMaeiRDAMmeGgEaIidumDHhKVVgGiIizDdZIvrRXxKkCcvCiIckMhHmsVvACrtjpWwfqQUgKqQyJHlmxXMAaTnNtvVbdAgLlzZrjTewyxXYGjUxXqMQeEgXHhwWxGjGgxnLYZzyWHhcBbWkKBNnbnWfvfyYnNdVIeEiWwOLzKeLlWwgdtTDGVvdYXxAMqQqbeEFHVblxoACcJLibuyYSQAxrOoVJRbBZQEetbZzBTJIdgxXGDrKXTAYyZzrRaAHhgKFarRkmMvmAWyYwrRWPAyYSDKyYfNPYyfmMXGgxudDeEGgWRkZzGghKvVYuVxYjHhXxJYKucaQBsSLYIYyEWwLEerRlLVoSsmacksSKqTZhHuUDMZODdNYHpWRGMzZgbBgYDdzcCjFsSUyDxhKYcgHhGzaaUSpPfVvqQzZbrRcCEeEuJjULFfGIypPyYPIimkMfFIRBbQLxhGAXzamyfFdDWUQwWwWPnNpDcCdvXhieEoAaOnTtRzSGCtTNaAHpdxXDyKkVQsbAaOXZCnrbGsSyyYodDyYQjgnNYyiHsXIiJvVrRuouwWKdmZPpUwNnzjJPWpPwPuUQMmquMeETtXBbBMahpPHgGCWJjFSMmBAjJPyYpavVWOMImuUMosUzqQZrRMmuiISCqQDEedKJoJEkhvVvVXMzGsiXLZhnEeNHzSYyHhWrvEeEeTKzZNzwykHdDMPpmhMSmwWoJdIUdZezZbohLlgVqZPJmYSMLlPCYXfAoVIPpCciNBbnIyPpRrNHhAXxOoTLltPhYycgqppTtKkQqJOvVoPdAHhaUvXvwLlJlLLlzLIilZzWwpaDHIitRxXkEFfZnNdHhioHeiPhwcebnNCxMmAerIiIoOezqQWHTthodDPCcXBUuTYyQXSseExqauUoOiEeIMcCmmMkKGxFJhijJIJsBwWfFRYyfmrHPyRQCcdTtJExXiPDjEfZNiAHNUuYHnXhWwTvaAHhOGgoCZzccfstbLlYfFyzmqjqQFXKKkXWIiyPPpkocFhhuveCczBRaJRpzFfZmzZgRrWyYwDdETtJvWCDdmiRKkgGtTqUuNnKkwWkKUkKecWGjaAyYyYqFxSsXfbBQieeEdDECFfSxXWwExUuEtTjJUuYETtMYlYWwrRzxGDSJjwomQqaChHbBvVSZOonYmMjJYyHzJmpdsSDuMvVmCXTvsKfPVvKlzKYyoRKTtpdRrPPamMeEcnGbLisSTtgEJjfgzZNnbBMmXxtTXgkiSlLsiIjnFhgNnVkKseEtaoOYyoTKmfFcpKPBDcLDdBVOoCFDNMmtbSwqiIlyYfFZZVCcTSpPwWhHNndDdwWiaYZgDrRHhZPEYTtXOomMrxXQaAMMfziIKMgLlpPkaAcCqhHKyYvGgXbBxKuuUaAvuUtFKkjIDXFHpBbuUmFfMPipKbshYeEyYzeWBbwjvVJYxXpmMBbqcCSCGgRmOgvSsyjQotyYHwjRPuDItNTtnkPEepfTtFkKsSkKPpkBuMkKmjJFfVTSSZzsyRxZFNfNniRrFjJJlLQwJjXxzzjUgObHfFFpxXWwPMnKkVjQqjrbHUfPpIdXJHkCrRDdsSczZKZzwuUqQfufosBbWWgGwwSOIilmzZifsLbjJKXcVvuUyYDafnyYfFNFHvBbbusEeuUSUhGZzgTPurWjMxraUGHgGqyhhyRowJtkFfeEfmMcCYFFfIvRVPBbjGgxXXxJpaNJXxaLlxhopRvqhgFPgJgKCTtBAabnMmkKbTVvOZBCQqTxDwccCCvamMQMmuMmoOUzZjdflEzyCGgRcfFCCcsSTWeEQMmuYnjFyYHgukoOUiwWWeEmtqVvtThwWkKtkKTFdDfwMmQmXxMMeEyAatTUIalXSsxbSsIbvVMSSsYRrsxQXxTSwWyYKTtvCtTTPkdIHhlLnVvlGghdSXxCTjscnmMqcCmMsSFfPHFoOgTKwCdeiHotQqgELMHgkeNKkmMnzZhHNnddGgDDUSCoCySssuUSYcOFWwfpPJrSsKPkKkKkKNOonmeEYOTtoAahGeEgHdYZzBkKkaAKwRUurAEPpueEVvVqndEHhKkinVvaAKkIsdJiInNyXMaAmxqQtaASVqTUMoSsRnfFIZyYMmqQXbBSlxVvRIPjUSTxXvVnfFJjDdOoDKkdeENJVvqYLPprRWdqUyYueEnoOuUEeNEFlXbBxPfhtTCWweEnGgokqQkKGgKBlSsdzCtTcOSmiqxFpWuLXxBRSsHuEEemLwYyGdTJjtDIiDhTtFfHdhHGGRTfFGgCeEcgCetsVxTUiiHNvXxVJgJXjJZZNBNnVounXicRrCIRnoLDjXxEcCwWMmeJmmMyHRPpqdOoRzUZzTxRpzZhUZzuFdUEsHLRUVgVvVRrCzBbcyYaNwiIaBdWwLXlqQLEexrhmhlDZUPoAFfXOUoOakKUuiEFxkZzvVHhkAaYMmSqQUpsymBbwLlqOuWKRJjXDdMmFfxUumMaArHhnlnkvmujJRrwWUDcIsSodVvvJoOjBbebBoROorKkFfMmRkoDvRDANnkKpPdQqExLzZlBbxiIQqaPphowxyJMmWeqzgGZFfystTSgRrSzzZCcRXpPRJjGgyYlsZqQuIoOWIilxYyYHgZJuTtUjTtjJbtDmgCmMcgGgydXkKJxBvYltQDdAHQqDOEYvkivVxjjuNxXBbEbBtSUlScNdNiKeECckoOoEgRAYcCmMyswWaASbqWpPRrakBtvpMwAXMdZotAsXpPAaxXEhDdHwafqQjpNniZkKzLcjkkIeQCPKtJseFDFYyNIEqEeQIiVjtYpPDfpYPOKktTEVYpPhkNwtTdNpPawXVvttUIiuZsdONtaytVvrVYyqFeeQgrRZRcCrAtkKAZdTbBtvbXlRrcXxAfrmzBbJjZrwIQqtTUuiOoWsckbKvVkBKbbXxBBuUCbRDZKREkoOJFjeKUqQKIiOoFvsBSRrGBbbvVAHdRVQcCatVvVbzpfXXVYmJmTVaCckWwKspPZHhySTjICwgGmCcMaFhHSUmSsVtTRrKoOkMEexEACdDXxsoKbBoSCrROMSsmeEyCInAaOeoOovVZZPlLBJnLlTNWvMmmuqExXebmkuIXxReDNGwssSSYUMNvsJjSKCNaUuAWUpPuqqQzqMmLlBeEkDXffpfXEdDFGHZDTTBbeGgAfmxXxHfImMdGUtTbhHBGpLlPlLgugDiFhXxcCHhwZzSsWXMFaEtkKtdzhgGgfexFEiIePFFxdKNnbMmSsQZQxXwFfnckVnpPmuyWgoOFfndErFfiUKMBaAQUMVwntyYNjbpzzOrNqQnRkKEoNiFfcSQkKqsYoWwcsOkOkKEeScaUueXSsmqQmMRrvMusNnIifAnNNnWGgciJtsYzSAvtMjMyZzqemgGMEQvGgxaAxFwaTtzZAWPZBvTAqAaQqvrDhaBgsbSVfbBkuSskETtJfjKGgerRrkzNndrBcCiIxXSRSsYyMTrEeRtRFajJCLZzxBVgMmGDoOzaTaYyzAaGqEEfQvRvVUuTYFfATnoDSzTTxWAnDuUWnKHuUyveyYtToMmpyPFrYyRXxdEbaABeyTTtUuJveiQqnrMmRfdfEswmMWSWwkKSjTkpfFcqEiJjKKJClIUuPyYXTtxJFbCcBAKkWeiIxSiIaTOLlzholLOHZzDmxaWmPVTbKAImMiwQBartTGeHnNhOoOInDxXnCsMmLusTaAexXnUJJXcCIvVKVoVJXxjvOyFhHfeodhVXxvaBIibqUvVueEJjTLSszZyHhVbXjxXoOxDYRcCtgGTrGGMdTBYyKkdbBDzGhyXLwoOiUzSdDLzZrxrZsGYMfFmQqQqQEwjYXWOnNBbHAFhHfXXeDiIaAadaArVBbdOKrOPpEMmVDODdiCLldMVKNLMmWwXxNkwUoQGgWMaAYSPusyYKkyKvVKXfeIAPpuoxiDdIaOpuzdLHMTQTtTtqBbtPpHRlxXDbAWFsSfnEpHhPeAowWdDOMmCZcvGvurlhSeuDfHiIPrXtuZoOrDQOorhMmbBbBYMRPpbBDdKkuUrdlOHhmMNrxNUOUuvbnzzdDxiIjGjNndDnSshIIsSutXgGlvVLvSEeTEcGOoQFfyYqtrggIiGggWlMeUhHhrblWwUwPfXQIMsoZNJvVjWwnDLbONEecvVtTHFprRLfeOoQDxXwlyQmMqQAajtsBbRruJpicCrXLsuUxZzziNrHhOmuKAapPkWwtQvsTYkKodDOjpPDSiYyNjJMmJxXjIBbeDNQvEyYDdeUeaWbyZzQpPqbPcCpWwBDoOeEOVvyYoyMWQqwpkRjcsuEKoeEOGhmtUuTleGTOhHhxXIEDcWlLktGfrRhpQqAapPQNNnCSJqQtcsDHLNiDKptcVkstqXSysmBimMxXBLGkKCcCcgAiLluVvYmqiImMWuUWwHQZtTzeETMwIWwuKUGhfIiDdTtJNyhHUqwtzXxSYyAasZKkhHuUcCrcYUuZeLFDJzZafFAkhSsHKqAaorRpPOAViINnnNWBbpPdXtcbzooHhOkKtDdBkKNckGnNjGpfGkKyYyYHQVrPOHXAjnLlAvQqPprVZziyYoOfAayYytTPHhpFlLKTjWOrYHHYQhgWwuARpPgGXmJyYwRUptGvVguUHBVFTLBbltfhWcCwveEVAdtTCxkBlSFIMvVLUuFUFUuWAaiqQiIIhjxNnDiFuhBRJJOovNNnmfhBoGuJZZWqjfIFnfzXrBbYstvmMUbKwWBbQqBbeEOonNKBbePpSshHETidUprzZJWEepPkKhTOqkKZyYzJYrXxRVGoMrcsLlQPydDEZycCIiYymMjJHSBkPIhfCcmMtTKkxdiJfTVqQupPUUhHkMmSDdsVkQPpKJjWwTtBbGmkPpZFmHhXxiImfFqRxHhyeHzZhMOPpojJMmHvVhmMmNGgnXxpyYwGrRYygWzZzdGzyAIrRDVvqNnQstzZvzzNnlLLcCQWsBrOoRTyYrRkKfFLlnBbdfMmhHcvxeEXblCdbgDdGpkYyYyPwWCaAMkdaADtOYCcyATSvGyYHRrfoONJvVbBiIIxXKGzZxGFBbeEesSGBbICclBgNHhCApRrPppDPkeErOkZLkdDpFkaASVtxcUrRsSPMjZheMmElLyNzscAnNMOWsdUuhHgXZySQaAqsLymCccCeybBeXekKgGscIJgwCQqECNncupPjJQrcCIbBMsScwJjVjeGvVMPrjArbqQKkZEVDaAdUHHfCOKpWwYwxkxfbPSspfFBJQMoOZBTSFhFfHCTiMmQqHhITttVtHxNhSsdDynhrRaItTnBbzFeJIiPpdpAaIHhejDqHhQqrYRPpIirphRsSFfMmMFrDdbSnNEFfeDdlLjHjfXgaRrSsJjAAtbxpTtOwTtZEiRGgEalLlrRjJHaAhaApPbBzZLhHufvVaAFCcUXcRiIgGrBECfFWHIipIEhOTtFfIaAKkEeuoOUDzeKyYrCcQqsSThdAPZjNnWwWGgVZzvVxVuDpjeEaAPPQGCHpaAanfFYivOaFxycJjvVpmEesyMoOgTtGjpzQvGHOBZYLlUJjuyzEnNzDuWwiDjOThwWwWHtJQqjMsmKYaIiAWZnktEeEeVRwslxoOiIIPpWwSgZmxwWfFHKeQqjOHhjkUuaKkAgGqVuUvQcOmYcCyMJjimmMowbsfNsSnwhHcAmbxGgqiIXxQzZmMmGgUZmMzqQppTtZvVLlWrxXpPRukKzMhHkKIiBbDkUOUWTtDdwjxqQSXxhIGJqQqOYgBnNRGgNcoEeOFfzxyYoWwBSqOovYfhHqQFyYAaPhsSncgsZrvVGgNwWWRrwQqqQIHxVkKcQqCeEquwYMALlZxaKBbkgzZSCkSsKLuUlcyYCcsHIiwWXlqrimKMpjJYigzZDdlecCBqQGoOgFsuAAZKkgGCykHvVXuUdYufJZvVMmyaAGzZlLmMVvGmgrwOoPhynoHhhHzqHhQdqzZQeEDmdoOOWwonNztQCAMUuOtTXxvleiylbqACLEeTtKklUkWaAoOcCwUuyyXvUycmMCUuXxvVkHKrwFfWwUFpnFmhHMkhlLHdsMmapXxwKkaMVDdKXxSsGghHAfkGatxkHhKkRiVvjqzrjvRXaWwqsBbPpUBIljaOXyYLBvhfBQmaGdDgyIiDtTLlEkZlTtorUuRvFVFwNsLlSuUwZzCCcTtwlNndDVvNwWXJqmQuIiJgMmaAAXxaxXWEtJRGXIixaDBXxLeESshjYqQkGQquFPJVvTRcaSYFfyuDnNdqAcCyYjJaQUFFUuffQqdDdMUDdrFkKfIVvEAmTTttZhlLHzbBWwXxekKBbELNNnQwlpVaUuAvPPUuarBvBnvwWfFipDdTuCcgGKPpkKkBHhxXSsSZcCzHhaAhijdyYDJRrRaAZOgJbnRrUFEKKHEoTQEyYNljDjMOomUuqFfaxXNnprbBOcCQqORZoXXoTeniRrNnQaARdBbYdEJPpJiITBbLQTtkKWTcCFfOoVvtJjMupPsStzjtTViZyaYyOScdDknNKboMjVCJsXxkIcCiFnxkufFLcCdrfToKHIiXxMtLlJbqJQtdDzCvLVvApPwWxSYyEeshmMyOoiBbaAQXHEzcgHkfIZVbBYNnyyDdGZzZBdRrvhTkvRrnyYLKklFfWwsSjdMLyYrFlDFVvHIikKnZRfFMnNkKUNCZzcqFfQqQJQyXxvVDduUDnGlLiNnRSZzsZYCRKkcHwWpxXxntOMmyFFbHmOoCcxlLxGOafDdnNnNJYyjolLODBbIiOWdOrRAaRguqqQGgQUXjQPpfQqFqahzZWUYLYyLGAawMjJmljlIWwiLGienpbBquUedPSxXNnPpMBOYbgGkKPNnXxxbqQZbqQtMmBbBRjJrVeEveNnEbofatTGSsgaLLFVQBeAnNsSLRrfmMpPUNnTtDHhUucCuUqXzwiIJMmMmQBbeWwXSrjiSltEAJvayKSsIgGFOomMMRgbYIZziyyYJgRQtJXUuTwjnxEXgkjTskZrRunNWajJPDdSrRsDVkLGgWFMmUiIGmqQJVZzfFvtGgLsyYoOSFLrRdmfYItCnNYygGPNnXyYQdycdKkRVMiImwNGgFfdDpvVPtUsSngGNcCnNYyHFfhAYcicUyaATdBblrFDsTtkZggDdgCcqUJgCOxXcatxQqWwKWwYyTEdGDkKVLlfBXxRGgruxXLKklOoxeOBFfmysSNcYyVvzWmMWHfFhwLlElRrglLVCiSsIgbQwvzZRPVvjSslPpkKNyYWwnSBOoklXWpPaAEMdtTLjHqyYyhHaWPpyTkLljdDJamnJYTmMtBbvvCRrhHXxndDLYylYymMGUTtuNymMVvxXrRpjIZzFfbKRaLRgGbKkBrkuHhebEUueZzmUuMLRWAaSOoWwRRjuVmMvEzHsFeBlWwqQOoKNvgMCcmlcbSsBcUydDqQGklyHYTtkxGvtTzZGidDWshHnAXpNnPXGgGgnuSmMsArRMmTCSjKkYyJjJsjJbhVvQqpXZzghdfFIiKCcqQfFOoqoagZzJyTmMtLiHGIBrRbivVxLmOEeQqMQOlLlyYwpPjJDOwiIJjnIiaGXQMwEeWwXxxXkKEFfbJcCrRdMAaNSsvEeVnvpPVQXKkxaAroOnAWwapPpmqQGOjQfFmpPUyYxXuEcFbVvUuUuQbeMdrRUuXxUHzJYyBwTtqQuUWbbCRZhEZuFfHhCcgyiCWwjRDFhhMGPpfAasPAzOoFuqOpPUaRrjswWWITtsmmMuNBbKkfFMmqKdDaquxXAdtVtTFRMmnNCGjJUuLFUUuuNjPiIcUuybBPgXsSrwGdeEsjJKvVYyDLwuUWhcMIuUKpPNpPqQsNnSztIiJfFgGQqjWILliWGgXyYLlWhwWuoSsiaAIcSsCNvVNCcJVoOCqQrRcCxXwWaXxYyTtGOogmVocQKkhHRYyrSRrGWzGgJjNDDfFrmTiMlSqQSCgIirRDqwWQdygGvGgVXxwWwWgGwJxXjWYutTURVMaAnRVtTvtUTBeLlEjeuUZeEaYqEeQeEeLlgGDdouJlLNnFfgVvfGgSKMbBWwWbxXBIpEniuXlYmMimOoBwxrdDZzQnbekXxfWOoPLlLlLPdZzDddDLIbmapCXcpPqyYOQyCVvcaPpoJrHhfnNFTNnUDFPpoKknBbNONEenQqeopHyYtbBThjyYNUuOtsAMmxHeEBHhKQqxGgZzEeCjuUMwDaAqLlUMJTtHRrUukKAbrvVRHdRoxlBpPgEFeCPpdDPMmHhzlLBJgDyYdaqcaMApCUTFBxiiIxmMolJjyrGuuUUCABbacCjJQrFmMxOhHoKiOoISHhlHNnjStUurRZHmMEtYpgGPGKkpPSfVvAIhfFQWNnKkKkSlyVXxvmMvjPpXTsaHhGpbirxAaBehQqkKKkTyxqhrostToOufFIVvVEevPiYyItTfcuOoxXJjhvZXbMmGKMNufFHtTmfuuZUaRrAuPFogGnNODyYmEiIAakPpKiejJOoEmhHhHAoSRreEeqQgGKMHhBbyYcCOKkoyemsazZAwRuUrWhHNeEfWKlLIiDkKDAmMagRrGybhHEroOjxifFJmrRDsSlTufFWwibpobjLiIXogIlLiDTxIsSAaIikOyWWwwYoSlfyYQbvplIUosSDdaGTitfFTEeYGgySsIadfFRrCcCcuLaAlLNQZzLlFfdAaSsFfsSMXxMmBbWVvFJoOjJwWYmdDOWtTPpwbBrfjjJLlmVvMfdceECDQldjkZzKqnbqQffhHzGzPpBGPNtwWTfFcbBLRTknTQIiOoaAnNkXaABbxKnugdDZTtnNzGUVNnNZzyveREaZzzZIhcFHeEhSrLHtTBgGzZXUoHRrPnNUuiCJjMHgGmMBJjuUmsfzmuUMnVvhMmHhRraixXOhAoKxsiIfFSNjcCJqQVvsclLNZUvVjJulLWwuCcUNQIiqnvwWCcSsbRroOpAaGyMmeToIiYwWkmNrRuJEePQpapPkKmmscgSHhskKgxaSYSsgnecNeYYyNcdDlLIRiIWOUuQwjBsdSsAayLiQqowrqNUxzLUMGgmMrRlLTCQqovzZsTeaxuUTBSssSLPatTuUAuUFlAaQxXWbHhzYBXDnNdWwTiRrIXxaCLdZzfFDCcdDlZmBUmMmqBKkIiIKXtTxUhbpPFXDKwWgdDbhHiXTeEYBrRVbBvpPgXMuVnNPwTSIiUxIioELlpnNBbFSslLSsNQqnnQeEkKFdDwVzvdDiINvVRDSsEevTtMiTMmZztpwCWaNiIzIkIdRroTySsYtJTOonNtCZzbsMAmEyYedDenNQvbwWSAYtXPBAtehOIrJjRXGgqQzrvVaqRrQAhBbHbBexXvVERhHcCVvkezZPfHhFGgaIljJwegwumAarRVkbBxpHKrnNnstOoBUDJjtwWpBblDwxQBbdDQBbqTDdtqXbAasSgEsSYyeDAJjxXvIuUKxwWXpqZHazrnNcXVfZzFWcoOnvefvVNgXZqHVzXxXyIqQYKOCYZzsStQiXCUfFgGuOodDNWUuwLlQLgtTNnFsDRJyQqWyYhUuWwZEfPrZBbBIOTvSyRKkrRrSsFhDQcXEjJxXenXxMmjHQqwCcWmEHovVnNOJjkAbBqQAaaUDdtTeSdDIifqQAVFfvhKWIiwkxTHuNfsSSsLYzZylFiIDRrpPPpQWknBrRQPPXjAnRPtboOaAZcCzmMrRWTtoLlkKylLiLlLlcMDdlLwHohTtmJjMHiINCcgknrRSslLFfVmMzUuTqQWpPkYvMlRfFIUUoYOcGgCoqvJjNnVnNcSsvWTtymTtMwxQAahXCwHhDYyBJeXxnNHbsXuUxOptViQMlBrzMjOgxXGoJmXphHoOgGPWEmMTgpPXHdxXkKNbBLgGtToNQUunNoOSSYSseYhLfVvFxXDoYaYbOoBXxymbJRrYyQYBPmpPDdqcCQEeOJxdVvDGgXpXxxXPpooOOPoOMPpMSMseEbBQqSrNnYyCcRxWERKicCIcCJQkdDBgGlTtucyiwPpWXxwIAadDirviAqQYCdDwWzZHBqNnbBeEQbNnjPIQSOcCfhtnWKkQXRrGJBbjokganFfNrRcCAxXMVvmVowrKxXkCnNQqWHmflDdEXxeOgKSvVaAGgdEsClLDGjOoGAJVlVvLtjcokSmMgGVvaAsKqqQQOfcUyLSsnUoOuNZNTwhHGdDgmMsSCOalDdLqQDzZdADdliFtTfvDaAYRrkKxXIeMmwZEeDwUYxPzZaHaAirCtvxXxKkXayYHMmMuejXidMdDNxQqQDcCsEeymCEAAaraRrARnhcCHKUbLlJjaAtabBXehcCeoOuqwDdEeXxzlQqyilLSDdbBhqZmUuwWLFtxLlcuUCXOqQDhoASyshHuvdpPzmpPMgGguKkkKkKyOhHdDLJyYbBwxgsSurNyXxKesJjOonRrNSXxuwnagGtTtMmTKptmbBGlOWwIcCIieEoOMOoWSscCSJjFfbmMVFPpmFfrzZKYlLrDwrNdDNnjJqtRRUurxwWicWwqHvwWfurOoPFnsnfFEejoOJNZzVvUAtvVTxlLxDBbxqQxSUuSsSeCciIEFfBbsRZEeBbzdwsQJjqSjQqWyYwJniIdRbBrYuUJiEeoOctIGqQGggFivVtGgzQqCHnNhfhHQqFdDcWwkQyuqDGgWfFwfTtHcKkSssSdAapLlElLetFnTEtGeLlTtGCceEeEgnicCNpMioJkAaXxwyvlDdLVTgyeBbpJNIinPdDDDwGgxsEegGSXKkFjJeEvnNVjJOofWzgXxoirRISsqAHhSbBYBlrXkKGgmLlUuQStrplLazZVdDTWwttCzmvVtKkeNnzIFNZJkKjDdqSdDsQxXBbuiUuIULlZzLZxDNkKWTcCNnlSsLlLuUMlIiLzgLnMlJLCnNwQqWoOvDzSkWwdDybBYKsEeZrHhiQaqaCtTcAwdWwDYKkyHSXDTtdJjqxvEhefFeElLbbBBHhClTDdtLiqsStTQxwISsohxDFfCcmXxHQMWwLlkKZfQcCuUqZlsSWShPofFBREexXSsrbaGiFIsQQqVNnvydDwBbdBEepPNnLVMmvHhsSrqMnVvicAEeaGrJsSuUIQOoeehHjTtJjNKkdDnsSrRmMvhHDOmModSReaFnrgLaAGgNnLGgQqDdRKjMtmMwTzZdmEpPYoOkKylLwWCjNnlQqmTtvRkKEeDdMmrVeErylINPZzecCEmvQpPmKyeENaUuMmuUoOLqQGgRtSsUuUXxuocNhDdonUNnxXWwdzZeyYiIEDygyYKDnNdVvLJJYycDjJIsaAbBsSeZzEfIUrxBbtTxSsTUuyOFfCFfnAnNaCxXCcHhcTtQQqQMmqpPwIbfeRrtcCrRTEjrRMmZhbfFQJQqrRXxjNgGnqBmUKsSsSjXwMmtTZzDdWApPdDLlPuUpYWwTItEekMmEKkkKeNHhoOpPdaBbVvPpYhHyAXaAkqQvolNtTdDNqQHyYhtTgWwsEeiBXRrImtXjntTNUIzpKkQqQcvVBbLFdDjJgZbDzgaTjckKILwBbJQqaKkPoOKYyRuNnaxUbMfaKJjnNDduUTrRycCcLXvQqcCAUKaShwWsUMmInNKJuxXUHmKRrhlLHZsoIiOSUTtuRrrRmVykpPMmKsAwWIiyYWwrAjEeaeXxgNMmEQZzqNnaBvyYcBboObBoVBTmGgMtbjJCcJjAaKFqjuHABNqNjTtJtHhBbTlLwWgYyGBfFtTbBPYgzzNnlbBwcujaAJFffFQqfBgjJGvOmmPpcCVJjyJJjqwLMmlextTfOlNgGqdYuUFnNJjRrbBeEjJLqxXpeRrEETtrRelLeEhrYygSHBdcbeEBQIdOOirrheEwryfFSKkKkxMmPkJiIzLlZjUiIuBAaxriCtTqQXrRHlLkAXxsmMflCcLHSshFVqCcQULWwlvyNnRrSsNnoOQFfqkKYMmaCSBZzvNnVORgLAqQxMmUAauQOWwutGHhgqxHKkFfhXGKkoAtmpPHDdhlFvVfLMJeEuUVnjZQqueETtdanLlNoUuiIzZOAOCLlcUuiiKkIHVvhhvCdDCcfBbnEeNTtCcUuSswWbBFAaupPQfWIiMUQinrIiXXeESuNfVvfJjnMeaiHcCAnynNYlMltTuUIiQntFfTBmTuURdUuDrUufFGggGQqKaOpKucZuUKkDdPpmCgrNnaiKkWwwXxDuUxXEVaMmAtBbtOmuTtRtTdDEhzKkXuJjDdFZeriOoIRuZzUoOgGHhWVvwSqiIbWqiMBbIimRrvkXxAaKhHsGgjJSsSEeLubyYYfFylzZmjJwoOWmXqQBbLlxhZRrTXxXCcewKkyYCcWFzODHhyYxXSsUbigEaeKGtvGCANnalLkQqKzKknrRPpZLuUNAXmDLckKCxXgZWwROoaNtTMmbQqRdbNPpCGwaAlLWqmgGyJjhWwsBaACcavVxnzPEMcRmFfQMmqHhckKCpxrbBdDtTrRVvkKRyWmSsptCHhbwyBbTtlAaLllgGMAeHeoOjkBbIioGDdVWDDddKDdkVvJjtQNnkKZJjnNqjsYySPdDXxhHpzZnPtTRmSxXveFfOkGcLnNufJPEZoXvZzVchnkKxXkOogWulnNLnOBlzyYZYIpxvVBbyPpJkKoOPehaAoOuQlLOdDEeORrMXxtJpoOPmMiInNfFuUTtPTtObBLlsiIFfSCcyYltTLmjJhOoOGhvQpnrIiTtNnVvcCvsAaRVhtTLQUIiuAlLmlItTnjOoJPpLljJxTraAHhLluUrRfIPFppBbPNFfnWgGwDQGgRrqzZhHdDdrlLtbBcCEeiHUuwcCaDdXYsvGDcCdbGvVfFvVMmgIiwWeHhEQLlotSbBsTkKjHhOsjJycnTtNTtUuQjJqUXKZNryYRXWwxiIlVzZvDFfpPdKrRrRANneEKkVdDvLoZNZzVvnxXtTQNhBbgGgvKMmFIcCiIiTtXxTTttsJjjoaAORrHhEnTePyYwZwWiIzlJjLpPxXcCUxcCxXrNEAKWwNSsKMMvEGgejJmGgVvpDqXcCuxlLUUuOXxoWwvVuSvxTtpMmPGcSOXYyZgMmGpPzuedDEUToLKtIiuUrqCFuwWTIiXxVfdDFvzZrRXxzRrRjUuSsJqtxXJBbGgaAjcGBPYypbSkkGgiIMhHRtkDFUbqQKSkFMhUBbqesSgGyhHYWieEWQqXxuSPhulHjGiuUpxXPQGgaAaPpTtoONEenUuixtUwOJJyFfYrRiIgrRAKCcRrkySXGPDIivFftSsTMmjJWwXxWwVEeDdAaHFOlLZVOtcWwCTPgcCREGgKMOorRbBGDdgkAarRvVOuMmUjeECpPVlLvkiiQiKkCcJkimsHoORQqUMRDvVdrmYyOhHoPFfKlLrRkiIyYzZnTtbPpHrRtgcCgAlLaGZRrPpcCFvVHhNLlXxXYyxXKuUkxvBNSLLeXWkKNRrQYzzVTWwtzepHhPgeEuUhHgAMWWhHwsybBULlEgRxXLhBkYyTengXMGnbBGgmMvVKknejgGJGgJjyYPnhGgfFHoOfjJFfEeQqfFXxAfBbFBKkIaXwBJjbgGWxuUAargNPpnSAAvVgGaTPGgEoOnNEewGgNtOoYyTwshHSrUuRzwWdDZUuqQfFDdoOsmMSQqLRhIPoeEOAapPoXBbEetTxOpXhHNXDXEeoIidDdrtTRQAaqbBZJfLuRbXxgaUIiLgeBbYqQnEiHjvxXVJbBkTtKpdBbgaeEGMmmMgLhtTdiIaoSsoOONaAGgAKmqrbsSmDdMfFdDTkwfFKlLaAgQcCZmNQqnNaxEVvlBbvvSsVjJAzXtPMqZYVvFGAifDdFIAaRrIUpGgNnCAayUqQXdDgGhpYyPLfHRGgKAakrhGnKkbBNcMObBPpopPvkbgGsSBjJKdDGgVKkyhHXbComgGHaUuyjJoFfGAFUuWryYbIiQqBRQpcCsQRGdDTtIiGgwAaNnNntigfpMmPDdviMmZfFzMmjJKkupDVvdcXxZzkKCPooOePpMKjJCzYyZHhfFQqeWwzTyMmlAaLOoeMmsUIigGMmuLlBIaAoOcCcmiIKYyVnDdmEeyeEqQIuUCcMmZgRrGhdkEMmnNXxFJKdiHFfNnhKHxTtkwWwIZzuJJjjRaeQqxuUXktTRrCWsTAaIBbqqoOafZNnzqdtTwWSsfAaAzZbsZzFKeEkfLuUIcpPAJjhFtchHCJjwmMgGxXFfWusQFfqDLXsSxwFfZzfFWwElPpMQCccCjJnNfAOoCtqGlBzZUwWIHhwWiuUCGgcsSRroRuEoTjnkMmhaAuUHlLokKTtKkjPRrOoXxSspNwWXxniIPRrPpeBbOoGTlXxLdvVUDduZznsnNlPRrbqQBSsPplLpLgGZzZmMliEeILquAajJEnNeWwUZzdDVvGgQGunPpNUwWCvVcUgGuXZOSsNTtnYvdDdWLuUFfCzMmoOaAzZvVzeHWwhEiiICctKMDdmpPHhKHmIimcCYLBbvXxVafqQjJTCcIrRgnNbBtWwZFnNjNnBbqQJfzTYEWkXdHihRnNiIrCOocXxvfUrrRAftTtTFDdaAsSPpwWJYyVoORrvbBNnMJjpmMWlsSOBboLiIeVzZAaLLwWlzZSsgxGNnitBiCcILqQccfFCZYsShyXxYIwWiHutBiyMuUOocCJIijwWmyYNIfnNOoFSLlfrpPrRQqVvoFfAgGuUjiBPpqQQawWtceEcCBbCcbBCPpqyYQlvVLWPYCcyBkgLlGFfKbziIZqLlRrYyeELlcCaiIaAzDbBvwWxAzZRrNiInOoiOraWgZwWOZBqQbNnfwWpBprNnpTtPIiGtyYqDMlLmQqHVWwqrFfRQelCcDdGNnOpXxdDKDdcVvCxopPYLdfrRFuUpHhCcPjJjJiIeEdijhVvHJcRODdogGDdgcLUnNSslLulCDXxTXxtFdDtnbVvByYaykKyHwHensAFfpvVPHBbQqRrbvrRZoOyYzTtfwWFUuVlcChHnSQpPrRifOaAXayryNEeaFYylQfFeQqukKUzaiIOoTbVpGgHiNUugyGPpgBgeEGUuhknwlnMmKkNLlvpcCPXbBxVXIiBsUlizFXxfnlLoOtTsEyWCIiGgkKhUbBuHaDdeHhEizNXxnCDdeqVBfjJYyFiaAIfsSofFOmPQAxYkdjJWsFHhOMmIitpPRrqQRrJjxXfFCNnOowOocCWGkiIKYhaAPBoOCDsTqzRlbhHTHepGgPpKkJjnNpPDviBbIrRbqHpdDQgbBJjfFrGgRGrRrRIGNvVWFpPPRrBGkKGgUupjJPkKPyCcEgGeRrCcOdDoxyBCAacTtWwHhnIqZzQLlwuUWEsmEEHeicCIFMIimlLAFfAnNCxNCcsSyYTtkKKaoPpOHPpfFfFBHuvVnGyzZkeEKtTfvRVoOrXxERrRrDdiIsDdfFaGgKkzvVQgGJjhHqZCjJhPnoOEDTtuifFhHIURrxpPxXEsSbBpsloOLeESgGfzvVhkKoOcHhXxfFHDdiIqAaISsnrRyZzSTyYyYKwWkNFGOogRrVvfsSAXxlgGDbBTqQzTtNwWnZsSIiPwWpYEeGRNcIxnNOOeMmEpPPpooXSMiIWwdDgUueEGyTtYjJvwWtTmMRnoONrTtVfFiwWnNLlIuUPBeDoOdEpPbmbXXxxXwmMWXxNvPzlLvyYkKCmeEMtTZxSGgskKwbQbBqBFkKXxmhHMpPfWXBbpPEezzZnJjLRrlmMtTXxodlOxXTZztoUKkutJjRrHlLXpbBGJjwDhHdgbyYjzZPRrpJvVqFrRjJvVfjJCJaYyddxXDcpPsSxXxAKkuHhOdDzZIIiypMuUmUNGgGgdegGOAdeENnaAWwJcCIYyUqYycCbCcHooOICkKfFQIiqsSWUwlJjLGZzYyEelGLMmlgEeaKkTUuZzbxXWwBfFtlvVMmLlLKzZkaqCcvVvqQVQMtTrRmvVFfuULlOohHAzZsPAsLlTELlzOsyYmrmkMmJjKTjZzwpPUSsDfaAsSFdUtOoTuqMmnBnpPCnNGlHhwjsAjJHInNihawNHhYZaAdDNRdXxYyDxpndKkDQqLsSaOowWMmtTAyYKkiIKkooOUupUBYyVgGvUplLPfFAaubuGFxXaFfDdLlkmMbBlWIojJOiaAJjltTLBXSsSsEGgbsTtStTliILrRBpCfFJjMmULlbnNBucPAtlXFoOLlALlRdKkCcAaDUuFfFfnvVaAXVlLvRbmMNnklLqQUuigGIiorRYZUuThvVXFfxHiPLkQvVqxaAnNqQCqkmMKgBbGnkKVUuvdBHhboTqEJjehgYyhHGOonBZzoOgGkKuKkQqACMmFiIfbIijJyAaCcEeyYYmHhMpPNgIieyeEuxsSqSHUfsIeGJNmHhMsSuleFnNfMmhHzyrcCRYvuUsSzZuYyvjaAjJJVYyFfHyqvdDVlLIiQytMmXxTmsPeEVNfgnNGCYyyAPpeFfeiOoZzJjIDdMJjxrRtTfbezmXgGxGVvgqQMZXxGgVIwDrylNnesCDmFYyfwWUHzZaAwWpgGHOohPpWqBGgbqBbQipCchHnNPIQhHSGgyHhYUuXvDSsyYbHSwWsKmMkhqQjcuUpiIiJmMDqQCcuUjJdjoOgenMbBmEevVfFxXNnNQVvLATiItKGyYgGgbmMNVvoOCMmcnBpBbPpWwPPYypQLZCczZaAqQejbQGQbBVBXxVDdIHhsSsSLgGrNeEtTjJXAaXuUFfxpSsPJMXxmjJjxWsfmMFksIivOTtpPMofFNlLnAaZzOPrHhRWwpZEapPxXAQIiiDpceaAdSiIOoeQqEhHiICcJjYyZiYZIBGgdXqQxPpDgGEeYqQWQXxqbBwgVvGgGZoOXxEezZjJkKuDdAasbBSUsSzNnKPSsTtOofFIilvjJLuBuwoOWSlLHhsEeXqCvgGlLVbuUpDdPAcCAaajJBmMHgGeELjJOolTtPswRbBAdDaTaMnTgGszZoXxSaeRrEeiIEAeEuUewWwPFiItkKTqmZzMfFeljJEeQqIElLeiLaDPpdAoOAIiaLlkYeEGguUvVKjMmJlLwvVIiWYyknPhHwRceKkPpDQqdeEjJZMIimyvVmOKkPiIpoMuKkUpPlSVcCglohGYNjJPtWwwhHwWadhxXCoOcqQzLlQDmMdqZvmSsMZzrRJrRGjzZyYIEeURruUTtBbsMpPVrRvsSBulqmyYiJNBrPAeGgEaxXpYysSNxXGgnbsSIikNnKgnsUUutTfMmsnRIikFQqXxlLrhHInNbEEecRoYyeEzcCgeEjJzZdDBSoOsbMEerRpqPphHQSsNHYyzNBDiIOooyDqeXxEGgbTtSHSshxXmGaAtipPIecCpPahHgBOoBvjvVZJRrjjJBbCclMyxXYmRUugqQGFeEVAaLlkKCcskKXSlkKqQWwVvLObGgNrRnLlzZwWdoODBHhXwWXaqQaAoyYhHzZOXKgdRruUDjwWwyYMmMGdqmOoZzmMnlQqIuJRrLLcLlSshHuBbkKzvVmMZzVvnNJxXAdyYDDdLlWIiwYfFzZTwmMOowoHUuZgGzXxYBboOyyyUjJuueElbBLSsUYfWwSsNnCcmMBBoOSpeOkvgoPpOUTWwtbBkqQErRejJdDWCcwmBbmMMQqkKqZrROokpZXaLkJjshvJXxvVjKCcvYsKkxbhHBhZzkKBbeEIeEnIUuBbiNVvOofeEexUFwWDdfMrqQmzeEPmfFMdbNnBMjJzZvVtCtTuUcEeTNnpGgMnNeEkKmPmPpxXGgzmTtGgoOMJjJjmVvpPMmMAnuUNnZAazYeEdaWwAbibjRoODdXYyRpPRIiEeUgGIVvijJHypPVqQNZzrYyxXkbBrmWwyYYyRrbBMSswWMmVQyKkDdYqLllBnDSsdpYyTtDuUvVdDdiIPfFhHSyYsKsSBpPBbmcRrDtPlHhBbLaApOoTXKkSaLljeDdGgEJrRACjJDBbdOIOFMmaqRaAlpPhHXxLeXxCcixXOoRrYybBIgHTHhtwjJLAUuNsupsiWGgqQOGgxXyQJjqgFfeEtTPptJCcsSUbneaikKIwWOojuUIpIBOoXxTtcCVvUArRtTVHFfJjMooHhOKWFmMIYyuKJQqEzUuZDdbqQBztrxXHHpPhAaUYQqnNDdpPylxXoPpOdDFdDfIiMmLcIipqfvUJHhtBeETQqtNnbEXUuLlxsSeeERPFsSTcmPEepMnXxNbWwmMPpvVBDvVGgVsjJyYqPRruUTtSsFfMmZgGzDdniVSsoPpDdhBbZznrRNFBAaaaOaAFcAaCWtThHCPjGgEeJtTvwWVURruiIERHnNGlGrfYyWGgtTwPLVvMmlpBLFfHhCcsadDAScCtTabMmbBmMmOobBXxNnskKyYXhHBbHhoOxqYfLlbBDdyYRrkKtzrVvMIimMZHMmlLHiIhtBbZzMmxnPpNzZpPiSWwfndDNVvIkHhPpbBdEegNnlxXLXPJuUjoOaUCcuoOaNZWwzJVvjYyjJXxQoOINvVnNnimMdDzZqyYiYWwegFfFfGpjtLrIBbsYnNGYMAxZUuqQzPzwWgPnLltEeDdQZeZOoOooqceuUbqQLlBaWwJjWwQhXkKiITtxDvBywWYPpESnNZKkLdeEhHDNURtTCJjiIgxVvzZRrzZuUPAapeCQpPqIigxXGOoOGLBxXbNWwrRaAZpMuUmPbXuxDdiIasSEejJAKCDdvVcwqQqpsSPNnKkaAIiQpPhHfGqskmZzMKoWHbBhwtTjDzZdhrRwWPfFhJiNeEroyYBbwKRsSRrXxroOLlxXPpwjvVaoOdUVWwvStTbBstZCcEOovVdTtirRsSsCcYjnNJgrRgGjJGpeETtPmwjNnXxmMUuJjGghjtwWYyTRJjnvVhSslLvprrwWRfQqrRykKCGgTfFXxpPtcxXDOtToYnNPMmpizAauUGlLgZATtaeEtLINndDInfFrAaQqRXxruUxZhvlLmIiDGgdMUunQlMPpmKkaUuAiwWxXIZzxXfnNFeEDdIXxYWVWwvIibksGHhgeqQEGqQGDdVvgeEXzmTtMSoOhHsZxdZwxXWzxXDTtiIHhTiOoIdsSEPXxpejJgMSorIilLpPRWUuwExXeCckKNSszZRYSsyfFZnmMcCgGiILqQyYtkKenNFmxXMrRsSRrQSsROorqzZfHhrvJjMmvVVrRygvACcWruIiwWIiiIUZGwevMKyYkmYkKaACQqceEaAyCcpXxPVvymMkKBpPNnrubBUJuUiIKBYybdOoEenNDkKVvJgGjdoOCcOxvXvHhVMFxXflXxpPLeIiJjEUzZVvFfuLoOaGgFfFlLfAjJhHlwxXyYNnlQqUuBbXiIhdDPpYEevVyNSsFfKknNOfFxiBFLZxXzsShXPcpMmPCRrpNnhHNGGkaAiIKGgkKMuUvzZVzZmNnkJYHhJjyfFfFgCBTtJjgGEDdUarRhhHEeMcmMCmGgHYmuNmgGMqQnnNuUUPpPdDpddDDodDXjdGgAaDlLxXOoaFfAEzfxPbHhCcBAuUwWLeElmMaVUuvyYEeawdDueeWwEEatTljTtJaAWwMmaAuWcCyYyGgpPMmPpuUzZCcUhtTQqUuzNtTxfFyEvVmbBEexXnRrwWNNXZzCeETtcmMKksSwWRruVvUyrRYDSsdpluUNgeElLZzBbPvVrzOlLDdLlcCRrjfFIiFfmMTdDPfTtWibBguyDdYxXdDAaGxXQoObBqbtTZzSdDRzZpRrRVIDditOoKcCkTgUumSnyzZeeDmMaAdphLlHyYjYKuuUfqQFUgGSsaxXDTtdqQjrRJjtTcDdBbfOoFfhdjzZnuUxXjJejJoTtjJTtpSslzZLYkwRrWVvSsKEeVvGgOSsoOKkfFKkwyYAuyYMmUDEexqQXgGDdeEtnNTCoOccOoDUbBjJTtiIKddDDsSZzkxqQrRZzepPynoJjPpytTIinNhHasRrmMSAOloOfFLoqQYOHEEbBeehBbmMxiIXXhKkYYyyHzeyYEZYLlvVyxmMrRJFNlEeLsSlLagGAnKkgLaAlGfghHGhkKHUDduTtcdyNFfnhHQddDaALSWwsrRBxXgGRkgiIVDwWdFIPptTfIigGOQCrJjUfLQqcyYqQoOxXwWoNnTtITtrRiDYZzydzZvVHfkKFhOSsoDdFHsSeELmMQmMqHUuhcyYCuTtUuUTtiIqpPdDQldDipPIhqQFnNVwWjJvJjvVMcLBblFfZzfHhFQqCCsScmkJGgYyAuUajKUMmFfhHcHRrhTtECcgGsaSsxeAaQyYgkAaKuUjhHJbBXxQqQqTtIyYiGqjJFOXxZzzGcCuUcCUBbBbgGXeExJjTtKiIUukMmaBbLsNnjJXxMKkEemnNBlLbRtxXGgsSbWwHBbhejRwWCcabBpZzURrmMzZuqQuGWNnaAtTzZwTtEeodlLDvVdDwWeYHtpeEPeEmidsSpPDzoOZrROMWwmoUutoOTITtmMDdKickKuKkUQeEGgqwKkqFrRjcCkKcMmeMmElLnyZaBbAzCxVwWnNvOocCgGuUOooOLlnIicCZzdpPDeENhHLlZGgIiZmMzdfFHjJgGaAhjJmRHiIrRhzgGVvECcQqvVIiHhFfLlYOqQaAoyRRrjIisSksfFlLCcKrRkqQqQehHeCjBbiPpmMIJgRrtTqQtTnNcwwWWdiSsIuUoOfMmFqgGIsSaxXFfFfUsSIiHdDhuAijrIiWhHwWGgZzSsWwkKtTMmwBbPpRZNnzZFeEaAfgGVvzZIixXdpPGqQgbBtzwWlLZeEIirRfFJvzZPpVwNiIqcCKKkRJjpmZzrRlLZHhSbBAajKqQNnwVvCcgXupPULlhHrRDdMmbMGgPZzpfeLlXxEqQNFfOnNKkvVoTYulLaLUOoHhjBCmMcIrqQoOKkRCcslZMESsegGmMmZzzZpXxaAqSsQKVvkkKZzhHCcMhbBuUHIiujJrxXRWwUgyYGJvXlLjpPQqJHhdDMcCaAIimXxbBZzKksSQnNsSqQbBRrlOoIiLHAaxXBblQdDqsfFSRUuctTCpAajgGJgSsXgkKGxINjJnBhHbrRlLMmoOOzbowWOhHxXXXnKkNtAQqPmMJjGUStTsLlQqEeEeuyFLlFjJZzIFfRAtAaJeqQEwWMmjSaVvnNoOoOGgcNndyYbBFfDaAqjJsSjJvIiEehDdHcCuLsSFfYyXxXVeEvTtuUxXxNnytwWTevcCTtVEHeyYEMzejJEAxXaKkWwAAPpLVvbBCboMPpfXxSUuswFxHhXKkSsjJfvLlCcKzZkVXwEMmnNexXWkQPplLgGXxiIgPpGqQMmahHAqDliILxXdDUuKCclpPLkPbBvVuXzZNnxhHdDUpVcCrRvuSSstTZhHzjJjfOouUVvvVwWrRFRTtrJsMQqZzIisSfFBxnMbMmVvBJhKksSaAGgHDdvKktTrCcReiAafFIhHzrRZeEHhosSrNxYuDdYySYyaAsZzySssStuUTOaAoMcCWgMmGhBZzSseLyYlrREKkbHgGDdQrRUuMmqtTjYyHuAaYjXxJyUAaFCccCBbsmMrRHYykrRDiIdgGvRrVWWbBwPpwqQeqQEkzZwWKYyJUujDlCcgGOovwWVLWwdhHpPFfKGAnNZzusSXhHoOvVGFfgVuIiOZzoZPpWwzOKkoULYTtYyVxJjXHhyGgVvUuvTtpCcsSWmMpVQqvmCcZkWwSsFfoXxKnXIixmlLLwzZLlHhLlVvIiWZzlbBeEKkYlLWwLlhHfFMmycAUpPnHhnNNeRTtrEEeFfygGwdkKDtTSMmsEBsSbNnJNijsSuUtruURAWwarIQNnTtqQPpTpPCctRrAaLxBbaAiIXfNoOwLlWZzaWOFfbBAatTBbozZxZKKGgkhHdDgGkxJjXuxXUBbVuUvtTjKwWyVcCvPkKprRYqQkCcfFJjDlLLRGZzDEIienmMcCRrNGDcCWwdgiIuUKsSkozJjtTQQsSFfXxQPpVvqGlzXxZhUueEMmMpXrxXRxGgPIibBwWOUaAuomsSSsyOdNSsnQqDoKzTxXtfFZkiISXxkKavVmMAXZzyYvvVCcMmVLmMwiQGVhHpvVvUuVPLKklUuvHhtIiqvVQzZQKkRrBEQqevVpcTtGEMmMHhmrRegkGgKWwpaBbAPiTtIfxXFNnxXDdeEfadDGgaAihHSYyzZsbZbhHBZzzBNJjUupPEsDcCRrdSJjmZzvVpPJMmyYGvVgnVvUuNpftEeTFUuhqQBbSsrRkZzVkKvcJnNjJPphYyHCkzYGgDdyuUZdCcdDgGDxsSXBblEQiqQqQUlLKkZdnNOcCMmopPEeTHhtJBbllLAanoONpPKcCeOonnNNEBbSsAaUIcCiotTqUJjuAaCcflrRLBbgiJkKPOoYypRJYGOosDhHMHhnNmdeEsRrSNnbwHhWkKlsSLBFfScGfFPpgCtAvuUVaXNnxLJHhyYjlYEefuUAqJFfvVjQqOoUuWwmMoOYabBAjxrRXBiIbgyFQPpucCUqvlLWFfsKkZQkKkYTtaAycqXxQCYOoSsxXdDpPytTKMmfMrLBxoOEeXgJLljGNnHcCmMsSjAIiaXxPpaADbBMmZzRryYJeEjdKcCkhHhiIxEwzZAaOjJodsSDjbQMmqpPBQqJOmmBbMhHlaAjcCWvVwJqQZUyYTtWKkwPptyYiITsSHnNcQqCjJhxXuHhwWpmMyYdDkmMIaAiaMpPqQmMeEmvVhHGgBbBrRBbibgGBIbEkKFlLFfPpHhyYmMfgGLlWwHuEthDFSntTfLlFNWwsoiVFfbBEevVIxXXAarRylLYjJxMlLNnPpmoOPpijXIigGjJqQCkKOopPCVvmMhYyYiIfFyeEHcctLlTHNnMmNnAapBbPNnMmxtmMmnfFNjJbBMAaYykKEeBqyYQcguUUuFwWfhHmSsSngGNsMkKVhHtjJJKkChHcaqsSIiwWAabfqyYQKWLlxXxXCOkkKfFKEtUuTejZxyLNnQqoOcCleEBfFNnlLGgMcYEeTtshIiHWtTBbbFfEedZumlLMUnXxvEeIUKnNkuyYUuloiFfiiIfFIAXCcPtTpxXvmMKkVwWxwMmWaAaADdQquCzXxZTtyYidDfFIcSsUapPFfxXbBhHfFqQWtToOIiwnNjYylLgGcCOoHhCcJeEAaKkRrtQqPpRiIjJfAaFOoMmQtPiIPNnwWVvuUpXCgRQdoOCcDYFfyEeuUeEuhHmcVUuvCMmMUobBvbBcCqVvQVGYygDaAdkMZzmOoPGIiMmpPkKFaAUuhkTWwoZzPSsAxXapUBAabudDOYyfFgGSsIiGgWwreeWwEEAzZgGaYoOLCgkKGtTQqKkGgVvclwgDdGWyYpPiRrZjJzaAfFeEmMneVvbBrVvREKkRrlFfLqAaQjJaANSsSXxsoBbOLrRlsgGSYpPyPpLzsSZZzlICcJjmMFgSrRsdDvVFfJuUOojIGgFrMoOmSsCYNnbByeEccTtIilXxLUuqQKkCGgIiSJrRjxXshHkKIicCIPpifFxXyXfIiyZzGgYBKRrkmXxRrMdDgvpPVIxXiDdGgwWqLlQDdbrRBGTnNrRtbPpIihQGgZaAcCzfFvVeEvVCzZcmmMMUjDrRqtTeERrUuQddnTeaAhCcSsPpQRrqGglfKkFLZmXVqQNnmOpPSsSsiOohHJjCcXCcxkXxJjxXzZhVvkcBjXxXxbSgGpPgSsxBbdDeEpcGgCPXRRrCbjeEtTJBAaccdDfFtbQqBTAabBCHCchZzXVRraAIiLlvwWYyUupPxDiIOoxXtCcIiQqXXbBMmaArpPRogGSseRrzZcCFfEcCkKkAaBDdoOhHKkbIiyYrRLIilKOosDUudSlQqDdyYpvMmVLxXlAaiWwIWwKoOAmceTtFkKTWwcvVCTRrhHqsSPpvUgGsSwvVeTAaPMRrRdDriISUuoOsVvjJyIiYMmJjcFRrfJxXPpjdDBbKkyYBlLYaxXTjJhHtaVvAALeElgtTcCGqiIQzZMBIibIimaAcCTWbBUvVDVLlvEeWwCcTAIiJHhjKlLkatgTtxqQXQqGKkwJMWwaAmwWjIipDdmMHhpCcufFoOUwWPqQiIPuUzZpiITttTPpXxNjdDEeAaQqJDFfdQqnaAduUZzDFOdDHNnhoeLHhrmMnNDdRcTNntHTtYyPpeEWwjOoqQJhCKmMkzbBZENzZnuBbUFfcCMwWOaIiTQqNntpPTtAeEiILIirRbKyYkzZBZvhHVzsSduUxXxXzmeEwWMZPJjQqpTtXxTtpvVuUPfFHDEedhDWwIilZvVXxzcCLlsHCeEcLlGgVvgvVGsSfAxBeEbtTmUTtUuXxeEnNmMYbfQqFBlTtLuOoOoUhHghHGdDPVvKFlLURoJjOZzZzyTteEsZzOLllLoRUubBVKkvvKkJjVrRPpVDdnNvYyzZuUrRekKEWvUuLlVOTkPpPpKXNnkKyZuUzYwWZOoxXVKHLlTtWwhXxqcYyUuCaAFfBAabQbBpReyAaYEzZrQqPgGToOxXCkXHhqQxkRrKKcbAaBTtdAaNnDvHjJdDQdDUuqnNkQqlLKNnWwMVcCmMIdDigvVGwSsTtWvfPpgGFDdKkwMmzZxZzTbaASszZvhHVBmMUutDdXsUGgygGMmYuHhSWQCfBbFcRrmMNnhoOHsSAaskKGgfFAaFlLffhHFbBVXxRrhHvuUVxXDwWTtdlLDOKkoneElLNANnhdDNKknuUNeEnJjjJDuUdRrPpHadDWwDdSsFsSfdDVvTTtTxXtbnNBgGqQtdmKkPpbeEZzAscCSaHsSxPpdaADDdoIiOqQHhYyQDdYDWwvwwgGWLnNlkiKpPkIiIKOoLlWyYVMmTWwthHEerVvRsJjSrRfZzFHGgMmzfFHhZAauURMJjmrkKcXzsrRSnVvNZxiIKcCkQekKlLEHOoLlhdDCcUkwWkKdGLlaAgJYykKjVxyYXIJjBbFaAccioOMmICpTtqPpIiaAZzQqlKkLIiYGgylLQjJssSNnSCDlLdcCcUTtBcbBVUuJwWjZAhHKkaXxBbzeEKZzWwAGPpffFUTFftuFWKkwSlLsOogjJauUvVEbBefFrRFffFnKknNNqzZcCzZRrvVAaipeEekKiIEuCuUyYcUexyYZTtzcCfhHFIiDddDeEUzxXZAfFfIiFrxXRatTYyIiaAvAavVVhHMmlLWwhHIiEvGgtTcCVTtesdgXtTRWwrJjGgxuUhyYHMmqWcfzZFEeCeOosSEVvQqwgPpGnNvSUusVjJEeQXxGOoVvgGAaeMUumESEegGTtstTYyFfDotTbBAaKbBkiIwJbBuUpPZaALlvFfEedzvVZDtTmMVtFFffyFfJjmJjMYgGTzgGhHxqQXfIiFuOogDnDWLlwWdDTFftzZBbBbJHhjOocCsjOLloJSuMmNHhnsShHQNnBhHbRQwWqEePpXprRHiIVviIAMmaEefFhQqnNAaPlLRrxbjJgGaSsAtTjROzZouUKkSgGWDdwNGgnSssQqBbdDdHMJjAOoamhKkiIDBbrfFOoPpJPjJxXsSZzGgVzZvOolLpbBxXNOoHhMmnBfFbLlHDdyYhIiNbeEBXxhRrHhHnsSoEeoORrnqQNXxcvVcCCRlLrQmMYyqHpPgNnkKgGOfFiImMoGIiMWwZtTzKuUkFfmmcCvcXxCEbKkBXxuUgGjdDCwkKWeEuUuUTtVjJVvDdvnNCcPplLqQsGXxaArRZSszuYytTUsSkKHhgEkKeJOoxXeEiIxGcCgXGgFfcCGgjMaApPQqZzBfkKKkFDdgGonNrRDdEeOMmRrLlYyqQacCuUJjAePpEuUbGgBuUdDWwUfFReErSsubGgBbtTGgcCUFfFcbjUurRJrRkMMiIZzmZzmOoNSCcKkRrsRrxZmUEeDduMbBmMoBiIsMmSOoWwMmDdyYxWkfZzFoOKwxXXbAaCXVvxcsSsStBbTRzZKkzZCrsSTjJtRcekKkKErrIiRzmFfMCzZcCcZfFtTOsUuSDRrtTxXeExEeCTcCtsSGlkKVvLkcCKgIiDKZzdDkDdQqXxXmMPqQpxnNAgGGFfrRsSeEAagUrRRhHrMmuhHkKdCcNUuKknYkAaKGhHgaAyzZslLSDMmCcLCchHhHlsQYykKqAICcNnuUffFuUMGgbBbBdDVvjJmyYOsCndLlwWDNciIhHvVlDdKlLkXhHaAMmKkFfKkkMmLlKxwgGWvVLlLIbdLlFfxXmVvBbFyYfRrAiIaMrRrCoOcrOoIinNEuUiIyYhHeRUuxXrYwWRrjJbBAakVvJjKpHOohPuUyEedDKwWMOlLoFfKknNsSBbmeEAdDakhXxeEHRXUaaPHKGgreKkEReEWwzZkhpAvyUuYDdeEVxppPCqQdDULVvtGgmMeETlPpGoeEWdDyYcCmMwTtNnxQqXEeOzZwGgWTtqQKkgUAaiVyYvuUwWIrRuuTrRtyUOouxYyXIidKkNnKnoONCoOcvVnNrbBRNVvxTYytXnRroOsSFfyYwWAayUMmeXxEueUuEKknNYEZSkuaAeExXUKoOxEHhekmOQqWrRwojjYTtTjJgGPptOoGgzZlLBbywWYyvVJJjJjJgGWwsAFfaSMGgNneEehHkKEmVvbqQrZmFfSsMVvzHhkKoOIaABbCnNefFMmEcAaiZzhqQdDbJjrRYytvVLlTCKkcLleEwQqWqQmMSrRTtEeQuURrxXQxaPpAyYAaXkKTtqIHEehmMlLqQrLlROoNoJjEJjeXxOGgnfFIxXimMKkLliXBwQqWKkpYBbyPfGgFUuzpPZjNWwnJiIOoDdbdDNnKZzkmMpvoOVbBbBPlbBLxQSsqAbjJBZxlLCcjVIiaAvJXEeCcSBfFbszAFfbrFVvfNnRGgjdDImpPMfFiuZzUJvQqSsluBbUkKCJjcpPLrRiIVcCveEVlLUulZzLOowWgxXZzGqOoQWVveEIiKkwnNnNhHoOCcAoaAOEeaLlnNcCCsScFlLkaAKEMmNnaAvPiFfIpVnExXetqQTKkNlFftTXxuUUuLLlefDzZdSsqQlLTxXSstmMYCcPpeEyPaALXxRrTMmtrXpgGPvVxcCNnQqDBbdRlNJcCjFfRrIiCcOojJRrzZutpjJRwWAaZzrlLiGgKkIeEPTUgGprrouUORYySsGgRBbVvUYsAaSJqQjdDjJrRPgGxXpCZzcFtxXTzZFDUudKXxkHhftTKkxXTVvwWtWenNEIiemZzMZxXzEDdbBuUqZzuUQvVsLwiIWlSeVvwWEktTabBAKqTtjJQaLDdlAVRruIBbTtiURrvdDCbBTcCTtSbBsEeLlRrtOpPYypPohNeEnZfFzHvmMViIMmOoQqmMqmMDJjdjPpIiRrCpPcJHznNZcIiDWwdlLpPzfFZFfNulLUpdDPpPeEsSxXgGniIHhoOmMoObBKLlkAajJlFokKOfOoLGxXIiDdgqkyYuUKxXYywWooxXpGYygwWPOtTWzZwXxLNzZOonlpEeOoGgPDdlLZzmTtCfFcZwWFfUuDnNdbNnBRqeECcEenNQrKkNnzVaABbaALhFfHDdwWlvxCcXBOouUbvTtggGGVHhrRxUudCcDUgVnNqQaAvhzZHjBbywWYIirRJhXxHLuUJjlZzUuwWrRlEQqeLQqqQlTtWwveEVLaeEAmMfbGgBFWwHhzbGgBWHhwxfxXFXZNWwdDnuUvVmMGOoTDdRrBrRbNnteGRrgcCgGWwEiIZZsSzRrCvVDdcaewWEAiIBfFbzwWjuUJUvtTLlBYybBbTQqPptTtGNnQqgMUumSstsSnNtTCcfFvBbWwXxVVvGWweUuEKkCdFfTtiIDcHhcCCcOPpAaogoOJjJoOjcCRaAIiNLTtlnpPInNircCHhloOLuUvvVVqQYxiIXyMtTsSWsSJjHhWoJjUovEeVZzOuPNjJgGnIipcCkwWKOUNUunxXvVMmRyoRrOjJYrOZzmvVrRXxMPdHhbBoOxXDEeOoKknNpHyYhcCHKkrRUlLOoupPvVuUyYhAaxXoMXxgGmuTxXtGgxXsSGgdDwyYQPpKkqwXsSxmMIiRryYFfYycCJjCcOoYyzZYQGIiPpaAGggqyYgUjRrGgJbBuPpLly'\n
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/","title":"Dictionnaires","text":"Pr\u00e9ambule : retour sur le cours de Premi\u00e8re.
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/#0-notion-de-tableau-associatif","title":"0. Notion de tableau associatif","text":"Un tableau associatif est un type abstrait de donn\u00e9es (au m\u00eame titre que les listes, piles, files, vues pr\u00e9c\u00e9demment). Ce type abstrait de donn\u00e9es a la particularit\u00e9 de ne pas \u00eatre totalement lin\u00e9aire (ou \u00abplat\u00bb) puisqu'il associe des valeurs \u00e0 des cl\u00e9s.
Il est habituellement muni des op\u00e9rations suivantes :
Un r\u00e9pertoire t\u00e9l\u00e9phonique est un exemple de tableau associatif :
En Python, le dictionnaire est une structure native de tableau associatif.
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/#1-dictionnaire-et-temps-dacces-aux-donnees","title":"1. Dictionnaire et temps d'acc\u00e8s aux donn\u00e9es","text":""},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/#11-protocole-de-mesure","title":"1.1 Protocole de mesure","text":"Observons le code suivant :
import time\n\ndef fabrique_liste(nb):\n lst = [k for k in range(nb)]\n return lst\n\ndef fabrique_dict(nb):\n dct = {}\n for k in fabrique_liste(nb):\n dct[k] = k\n return dct\n\ndef mesures(nb):\n lst = fabrique_liste(nb)\n d = fabrique_dict(nb)\n\n tps_total = 0\n for _ in range(10):\n t0 = time.time()\n test = 'a' in lst # on cherche une donn\u00e9e inexistante\n delta_t = time.time() - t0\n tps_total += delta_t\n tps_moyen_lst = tps_total / 10\n\n tps_total = 0\n for _ in range(10):\n t0 = time.time()\n test = 'a' in d # on cherche une donn\u00e9e inexistante\n delta_t = time.time() - t0\n tps_total += delta_t\n tps_moyen_d = tps_total / 10\n\n print(f\"temps pour une liste de taille {nb} : {tps_moyen_lst}\")\n print(f\"temps pour un dictionnaire de taille {nb} : {tps_moyen_d}\")\n
La fonction mesures
prend en param\u00e8tre un nombre nb
qui sera la taille de la liste ou du dictionnaire. Dans le corps de cette fonction, la liste lst
et le dictionnaire d
sont fabriqu\u00e9s avant le commencement de la mesure du temps. La liste lst
contient des nombres (de 1
\u00e0 nb
), et le dictionnaire d
associe \u00e0 un nombre (de 1
\u00e0 nb
) sa propre valeur.
Dans ces deux structures, nous allons partir \u00e0 la recherche d'une valeur qui n'a aucune chance de s'y trouver : la chaine de caract\u00e8res 'a'
.
10 fois de suite (pour avoir un temps moyen le plus juste possible), on va donc mesurer le temps mis pour chercher la chaine 'a'
, qui n'est pr\u00e9sente ni dans la liste lst
ni dans le dictionnaire d
. On mesure donc une recherche dans le pire des cas.
Nous allons effectuer 3 mesures, avec une taille de liste et de dictionnaire augmentant d'un facteur 10 \u00e0 chaque fois.
>>> mesures(10**4)\ntemps pour une liste de taille 10000 : 0.00023534297943115235\ntemps pour un dictionnaire de taille 10000 : 1.6689300537109374e-07\n>>> mesures(10**5)\ntemps pour une liste de taille 100000 : 0.0012505292892456056\ntemps pour un dictionnaire de taille 100000 : 4.5299530029296873e-07\n>>> mesures(10**6)\ntemps pour une liste de taille 1000000 : 0.012522673606872559\ntemps pour un dictionnaire de taille 1000000 : 2.384185791015625e-07\n
On remarque donc que le temps moyen de recherche dans un dictionnaire est remarquablement constant. Il ne d\u00e9pend pas du nombre d'\u00e9l\u00e9ments du dictionnaire dans lequel on cherche. On dit qu'il est en \\(O(1)\\).
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/#13-conclusion","title":"1.3 Conclusion","text":"Temps de recherche
Il y a donc une diff\u00e9rence fondamentale \u00e0 conna\u00eetre entre les temps de recherche d'un \u00e9l\u00e9ment \u00e0 l'int\u00e9rieur :
Attention : en ce qui concerne les temps d'acc\u00e8s \u00e0 un \u00e9l\u00e9ment, la structure de tableau dynamique des listes de Python fait que ce temps d'acc\u00e8s est aussi en temps constant (comme pour les dictionnaires). On voit alors que les listes Python ne sont pas des listes cha\u00een\u00e9es, o\u00f9 le temps d'acc\u00e8s \u00e0 un \u00e9l\u00e9ment est directement proportionnel \u00e0 la position de cet \u00e9l\u00e9ment dans la liste.
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/#14-one-more-thing","title":"1.4 One more thing...","text":"Int\u00e9ressons-nous maintenant \u00e0 ce qui semble \u00eatre un peu trop miraculeux : une recherche en temps constant, quelque soit la taille du dictionnaire ? Mesurons cette fois non pas la recherche dans le dictionnaire, mais la cr\u00e9ation de celui-ci :
def mesures(nb):\n tps_total = 0\n for _ in range(10):\n t0 = time.time()\n lst = fabrique_liste(nb)\n delta_t = time.time() - t0\n tps_total += delta_t\n tps_moyen_lst = tps_total / 10\n\n tps_total = 0\n for _ in range(10):\n t0 = time.time()\n d = fabrique_dict(nb)\n delta_t = time.time() - t0\n tps_total += delta_t\n tps_moyen_d = tps_total / 10\n\n print(f\"temps pour liste de taille {nb} : {tps_moyen_lst}\")\n print(f\"temps pour un dictionnaire de taille {nb} : {tps_moyen_d}\")\n
>>> mesures(10**5)\ntemps pour liste de taille 100000 : 0.004771041870117188\ntemps pour un dictionnaire de taille 100000 : 0.012260651588439942\n>>> mesures(10**6)\ntemps pour liste de taille 1000000 : 0.04549875259399414\ntemps pour un dictionnaire de taille 1000000 : 0.14215753078460694\n>>> mesures(10**7)\ntemps pour liste de taille 10000000 : 0.4727184295654297\ntemps pour un dictionnaire de taille 10000000 : 1.302360200881958\n
La cr\u00e9ation des deux structures semble de complexit\u00e9 lin\u00e9aire, mais elle est surtout bien plus grande pour un dictionnaire que pour une liste... Pourquoi ?
Parce que pour b\u00e9n\u00e9ficier plus tard d'une recherche en temps constant, la cr\u00e9ation du dictionnaire demande beaucoup de calculs...
Petit d\u00e9tour par les fonctions de hachage :
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/#2-fonctions-de-hachage-hors-programme","title":"2. Fonctions de hachage (hors-programme)","text":"Tout ce qui suit est hors-programme de Terminale, mais permet de comprendre comment Python arrive \u00e0 faire de la recherche en temps constant quelle que soit la taille du dictionnaire.
Il est important de se rappeler qu'un dictionnaire n'est pas ordonn\u00e9 (contrairement \u00e0 l'objet \u00abdictionnaire\u00bb de la vie courante, o\u00f9 chaque mot est class\u00e9 suivant l'ordre alphab\u00e9tique).
On n'acc\u00e8de pas \u00e0 une valeur suivant sa position, mais suivant sa cl\u00e9.
Dans une liste, lorsqu'on veut savoir si un \u00e9l\u00e9ment appartient \u00e0 une liste (probl\u00e8me de la recherche d'\u00e9l\u00e9ment), il n'y a pas (dans le cas g\u00e9n\u00e9ral) de meilleure m\u00e9thode que le parcours exhaustif de tous les \u00e9l\u00e9ments de la liste jusqu'\u00e0 (\u00e9ventuellement) trouver la valeur cherch\u00e9e.
Dans un dictionnaire, on pourrait s'imaginer qu'il va falloir parcourir toutes les cl\u00e9s et regarder les valeurs correspondantes. Il n'en est rien. Pour comprendre cela nous allons faire un petit d\u00e9tour par les fonctions de hachage.
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/#21-verification-de-lintegrite","title":"2.1 V\u00e9rification de l'int\u00e9grit\u00e9","text":"Lorsque vous t\u00e9l\u00e9chargez un fichier important et que vous souhaitez v\u00e9rifier qu'il n'a pas \u00e9t\u00e9 corrompu lors du t\u00e9l\u00e9chargement (ou avant), vous avez parfois la possibilit\u00e9 de v\u00e9rifier l'int\u00e9grit\u00e9 de votre fichier t\u00e9l\u00e9charg\u00e9, en calculant une \u00abempreinte\u00bb de votre fichier et en la comparant avec celle que vous \u00eates cens\u00e9e obtenir :
Voil\u00e0 par exemple ce qui appara\u00eet sur la page de t\u00e9l\u00e9chargement d'une iso d'ubuntu 18.04 :
La cl\u00e9 MD5 propos\u00e9e pour chaque fichier est le r\u00e9sultat ce que doit donner le fichier (ici une iso d'environ 1,9 Go) lorsqu'il est \u00abhach\u00e9\u00bb par la fonction MD5. Dans notre cas, si nous t\u00e9l\u00e9chargeons ubuntu-18.04.3-desktop-amd64.iso
, nous devons calculer l'empreinte du fichier t\u00e9l\u00e9charg\u00e9 et v\u00e9rifier que nous obtenons bien 72491db7ef6f3cd4b085b9fe1f232345
:
Essayons :
La cl\u00e9 calcul\u00e9e sur l'ordinateur correspond bien \u00e0 celle indiqu\u00e9e sur le site de t\u00e9l\u00e9chargement : le fichier est int\u00e8gre.
Exemple
T\u00e9l\u00e9chargez le fichier banniere.png et dans un Terminal, calculez son empreinte MD5 :
eleve@linux:~/ md5sum banniere.png\n2895bae45eb0ab36a2a8324c0208ad95 banniere.png\n
Si votre fichier banniere.png
a \u00e9t\u00e9 convenablement t\u00e9l\u00e9charg\u00e9, votre empreinte devra \u00eatre \u00e9gale \u00e0 2895bae45eb0ab36a2a8324c0208ad95
.
Quelle que soit la taille du fichier donn\u00e9 en entr\u00e9e, la fonction MD5 va le r\u00e9duire \u00e0 un mot de 128 bits. Ce mot binaire de 128 bits est repr\u00e9sent\u00e9 par une cha\u00eene de 32 caract\u00e8res (en hexad\u00e9cimal, de 0 \u00e0 f). Il y a donc \\(2^{128}\\) (de l'ordre de \\(10^{39}\\)) empreintes MD5 diff\u00e9rentes, ce qui rend quasiment impossible le fait d'avoir un mauvais fichier qui donnerait (par un tr\u00e8s tr\u00e8s mauvais hasard) la bonne empreinte.
Le m\u00e9canisme effectif de calcul de la fonction MD5 est tr\u00e8s complexe : une explication en est donn\u00e9e ici.
Il est \u00e9videmment impossible de revenir en arri\u00e8re et de recr\u00e9er le fichier original \u00e0 partir de l'empreinte MD5. Dans le cas contraire, cela voudrait dire qu'on est capable de compresser sans perte un fichier de 1,9 Go en une cha\u00eene de 128 bits. Cette impossibilit\u00e9 de trouver une fonction r\u00e9ciproque \u00e0 la fonction de hachage est tr\u00e8s importante en cryptographie.
En effet, les simples cha\u00eenes de caract\u00e8res peuvent aussi \u00eatre transform\u00e9es par une fonction de hachage :
Quel est l'int\u00e9r\u00eat de hacher une cha\u00eene de caract\u00e8re ? La conservation des mots de passe !!!
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/#23-le-stockage-des-mots-de-passe","title":"2.3 Le stockage des mots de passe","text":"Les sites qui n\u00e9cessitent une authentification par login / mot de passe ne conservent pas en clair les mots de passe sur leur serveur. La moindre compromission de leur serveur serait en effet dramatique. Ce qui est conserv\u00e9 est l'empreinte du mot de passe apr\u00e8s son passage par une fonction de hachage. Par exemple, un site o\u00f9 notre mot de passe serait vive la NSI
conserverait dans ses bases de donn\u00e9es l'empreinte e74fb2f94c052bbf16cea4a795145e35
. \u00c0 chaque saisie du mot de passe c\u00f4t\u00e9 client, l'empreinte est recalcul\u00e9e (c\u00f4t\u00e9 serveur), puis compar\u00e9e avec l'empreinte stock\u00e9e. Lors du transit du mot de passe, le chiffrement effectu\u00e9 par le protocole https
assure la protection en cas d'interception. De cette fa\u00e7on, si le serveur est compromis, la non-r\u00e9versibilit\u00e9 de la fonction de hachage assure que le mot de passe ne peut pas \u00eatre retrouv\u00e9 par les attaquants.
Prenons l'empreinte MD5 bdc87b9c894da5168059e00ebffb9077
et allons fureter du c\u00f4t\u00e9 de (par exemple) https://md5.gromweb.com/
Notre empreinte ne r\u00e9siste pas bien longtemps... Re-essayons alors avec l'empreinte e74fb2f94c052bbf16cea4a795145e35
.
Les empreintes des mots de passe les plus fr\u00e9quents sont stock\u00e9es dans des tables (qu'on appelle rainbow tables ou tables arc-en-ciel) qui rendent possibles le d\u00e9chiffrage de ces empreintes.
Pour contrer cela, les cryptographes rajoutent des caract\u00e8res avant hachage (le sel), et choisissent surtout des bonnes fonctions de hachage. MD5 et SHA-1 ne sont plus utilis\u00e9es, on pr\u00e9f\u00e8re maintenant SHA-256 (voir ici).
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/cours/#3-retour-aux-dictionnaires","title":"3. Retour aux dictionnaires","text":"Quel est le lien entre les fonctions de hachage et les dictionnaires ???
L'id\u00e9e essentielle est que chaque cl\u00e9 est hach\u00e9e pour donner une empreinte unique, qui est ensuite transform\u00e9e en un indice de positionnement dans un tableau.
Le dictionnaire :
d = {\"pommes\":3, \"poires\":0, \"bananes\":5}\n
serait donc par exemple impl\u00e9ment\u00e9 dans un tableau comme celui-ci :
On peut remarquer que ce tableau laisse beaucoup de cases vides.
Si je souhaite ensuite acc\u00e9der \u00e0 l'\u00e9l\u00e9ment d[\"kiwis\"]
:
\"kiwis\"
est calcul\u00e9. Par exemple, 4512d2202
.\"kiwis\"
dans mon dictionnaire est calcul\u00e9 \u00e0 partir de ce hash 4512d2202
. Dans notre exemple, cela pourrait donner l'indice 3.\"kiwis\"
n'est pas une cl\u00e9 existante du tableau. C'est notre cas ici car il n'y a rien \u00e0 la ligne 3.\"kiwis\"
, la valeur correspondante est renvoy\u00e9e.En r\u00e9sum\u00e9, Python sait toujours o\u00f9 aller chercher un \u00e9l\u00e9ment de son dictionnaire : soit il le trouve \u00e0 l'endroit calcul\u00e9, soit il n'y a rien \u00e0 cet endroit calcul\u00e9, ce qui veut dire que l'\u00e9l\u00e9ment ne fait pas partie du dictionnaire.
Par ce m\u00e9canisme, l'acc\u00e8s \u00e0 un \u00e9l\u00e9ment du dictionnaire se fait toujours en temps constant.
Il existe une mani\u00e8re de \u00abvoir\u00bb que Python utilise une fonction de hachage pour impl\u00e9menter un dictionnaire :
mondico = {}\n\n# un nombre peut-il \u00eatre une cl\u00e9?\nmondico[4] = \"foo\"\n\n# une cha\u00eene de caract\u00e8res peut-elle \u00eatre une cl\u00e9 ?\nmondico[\"riri\"] = \"fifi\"\n\n# une liste peut-elle \u00eatre une cl\u00e9 ?\nmondico[[2,5]] = \"loulou\"\n
---------------------------------------------------------------------------\n\nTypeError Traceback (most recent call last)\n\n<ipython-input-1-585560b5c422> in <module>\n 8 \n 9 # une liste peut-elle \u00eatre une cl\u00e9 ?\n- 10 mondico[[2,5]] = \"loulou\"\n\n\nTypeError: unhashable type: 'list'\n
Le message d'erreur est explicite : le type list
que nous avons voulu utiliser comme cl\u00e9 n'est pas hachable, car c'est un type d'objet pouvant \u00eatre modifi\u00e9 a posteriori tout en gardant la m\u00eame r\u00e9f\u00e9rence (on dit que c'est un objet mutable):
a = [3, 6, 8]\nprint(id(a))\na.append(12)\nprint(id(a))\n
139646950377032\n139646950377032\n
Ce changement de valeur tout en gardant la m\u00eame r\u00e9f\u00e9rence d\u00e9truirait le principe associant \u00e0 une cl\u00e9 unique une position unique dans le tableau impl\u00e9mentant le dictionnaire.
Ce probl\u00e8me ne se pose pas si la variable d\u00e9signe une cha\u00eene de caract\u00e8res, ou un nombre :
a = 2020\nprint(id(a))\na += 1\nprint(id(a))\n
139646916523440\n139646916523504\n
Un variable contenant un entier est donc un objet immuable car si on modifie la valeur de l'entier, la r\u00e9f\u00e9rence de la variable changera aussi. Comme un dictionnaire a besoin d'avoir des cl\u00e9s dont les r\u00e9f\u00e9rences soient d\u00e9finitives, seuls les objets immuables peuvent donc servir de cl\u00e9s dans les dictionnaires.
"},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/exercices/","title":"Exercices sur les dictionnaires","text":""},{"location":"T1_Structures_de_donnees/1.2_Dictionnaires/exercices/#exercice-1-creation-dune-rainbow-table","title":"Exercice 1 : cr\u00e9ation d'une rainbow table","text":"Objectif :
Cr\u00e9er une fonction inverse_md5()
qui va chercher dans un dictionnaire (construit pr\u00e9alablement) le mot correspondant au hash donn\u00e9 en param\u00e8tre.
Exemple :
>>> inverse_md5('0571749e2ac330a7455809c6b0e7af90')\n>>> 'sunshine'\n
Aide :
string
: lst = open(\"monfichier.txt\").read().splitlines()\n
import hashlib\nresult = hashlib.md5('azerty'.encode())\nprint(result.hexdigest())\n
Exercice 2 du sujet Centres Etrangers J1 2021
Correction Q1.a.flotte[26]
renvoie {\"type : \"classique\", \"etat\" : 1, \"station\" : \"Coliseum\"}
flotte[80][\"etat\"]
renvoie la valeur 0
.
flotte[99][\"etat\"]
renverra une erreur car la cl\u00e9 99 n'existe pas.
Les valeurs possibles pour choix
sont electrique
ou classique
.
En fonction du choix (electrique
ou classique
), cette fonction va renvoyer le nom de la premi\u00e8re station o\u00f9 un v\u00e9lo est disponible (\u00e0 l'etat
1). Seule la premi\u00e8re station sera renvoy\u00e9e, \u00e0 cause du return
. Si aucun v\u00e9lo n'est disponible, la fonction ne renverra rien.
for id_velo in flotte:\n if flotte[id_velo][\"station\"] == \"Citadelle\" and flotte[id_velo][\"etat\"] == 1:\n print(id_velo)\n
Correction Q3.b. for id_velo in flotte:\n if flotte[id_velo][\"type\"] == \"electrique\" and flotte[id_velo][\"etat\"] != -1:\n print(id_velo, flotte[id_velo][\"station\"])\n
Correction Q4. def velo_finder(coordonnees):\n velo_dispo = []\n for id_velo in flotte:\n d = distance(coordonnees, stations[flotte[id_velo][\"station\"]])\n if d < 800 and flotte[id_velo][\"etat\"] == 1:\n velo_dispo.append((flotte[id_velo][\"station\"], d, id_velo))\n return velo_dispo\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/","title":"Arbres","text":""},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#1-terminologie","title":"1. Terminologie","text":""},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#11-vocabulaire","title":"1.1 Vocabulaire","text":"Un arbre est une structure hi\u00e9rarchique de donn\u00e9es, compos\u00e9e de n\u0153uds. Si on adopte le vocabulaire des graphes, un arbre est un graphe non orient\u00e9, connexe, sans cycle, et dans lequel un n\u0153ud joue le r\u00f4le de racine.
Chaque n\u0153ud a exactement un seul n\u0153ud p\u00e8re, \u00e0 l'exception du n\u0153ud racine qui est le seul n\u0153ud \u00e0 ne pas avoir de p\u00e8re. (oui, la racine d'une arbre est en haut)
Chaque n\u0153ud peut avoir un nombre quelconque de fils, dont il est le p\u00e8re.
Exemples : dans l'arbre ci-dessus,
Redessinez de mani\u00e8re plus sch\u00e9matique cet arbre. Pour quelle raison cet arbre a-t-il \u00e9t\u00e9 modifi\u00e9 par rapport \u00e0 sa version orginale (voir ici ), qui laissait appara\u00eetre les parents de chaque enfant ?
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#122-le-dom-dune-page-web","title":"1.2.2 Le DOM d'une page web","text":"DOM : Document Object Model
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#123-larborescence-dun-disque-dur","title":"1.2.3 L'arborescence d'un disque dur","text":"Les syst\u00e8mes Unix (MacOS ou GNU/Linux) organisent leur disque dur suivant l'arborescence ci-dessous :
Exercice 1
Quelque part \u00e0 l'int\u00e9rieur des dossiers contenus dans l'archive dossiers.zip se trouve un fichier tresor.txt
. Quel secret renferme-t-il ?
Attention, cette recherche est \u00e0 faire uniquement en ligne de commande :
ls
: pour lister les dossiers et fichiers d'un r\u00e9pertoirecd Dossier
: pour se rendre dans le rep\u00e9rtoire Dossier
cd ..
: pour remonter d'un niveau dans l'arborescenceunzip monarchive.zip
: pour d\u00e9compresser une archivetree
: pour afficher l'arborescence du r\u00e9pertoire courantsudo apt install monprog
: pour installer le programme monprog
si celui-ci est manquant.D\u00e9finitions
la taille d'un arbre est son nombre total de n\u0153uds. Ici, elle vaut 8.
l'arit\u00e9 d'un n\u0153ud est son nombre de fils. Ici, l'arit\u00e9 de B vaut 2, celle de F vaut 1, celle de Z vaut 0.
la profondeur d'un n\u0153ud est le nombre de n\u0153uds de son chemin le plus court vers la racine. Ici, la profondeur de G est 3 (G-K-C), la profondeur de B est 2 (B-C), la profondeur de Z est 4 (Z-F-B-C), la profondeur de C est 1.
la hauteur d'un arbre est la profondeur de son n\u0153ud le plus profond. Ici, la hauteur de l'arbre est 4. Nous prendrons comme convention que :
Cette convention est celle adopt\u00e9e dans le sujet 0 publi\u00e9 le 15/12/2020. Attention, dans certains ouvrages, l'arbre vide a pour hauteur -1, et donc l'arbre r\u00e9duit \u00e0 un seul n\u0153ud a pour hauteur 0, donc notre arbre aurait avec cette convention une hauteur 3.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#14-arbres-binaires","title":"1.4 Arbres binaires","text":"D\u00e9finition
Un arbre binaire est un arbre dont chaque n\u0153ud poss\u00e8de au plus deux fils.
L'arbre g\u00e9n\u00e9alogique de la famille royale britannique n'est pas un arbre binaire.
L'arbre ci-dessous est lui un arbre binaire.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#141-sous-arbres-dun-arbre-binaire","title":"1.4.1 Sous-arbres d'un arbre binaire","text":"Chaque n\u0153ud d'un arbre binaire ne pouvant pas avoir plus de 2 fils, il est possible de s\u00e9parer le \u00abdessous\u00bb de chaque n\u0153ud en deux sous-arbres (\u00e9ventuellement vides) : le sous-arbre gauche et le sous-arbre droit.
On rencontre tr\u00e8s souvent des arbres binaires dits complets parce qu'aucun des fils gauche ou droit n'est manquant.
Taille d'un arbre complet de hauteur \\(h\\) : \\(1 + 2 + 2^2 + 2^3 + \\dots + 2^{h-1} = 2^{h} - 1\\)
preuve : ceci est la somme \\(S\\) des \\(h\\) premiers termes d'une suite g\u00e9om\u00e9trique de raison 2 et de premier terme 1, d'o\u00f9 \\(S= \\frac{1-2^{h}}{1-2} = 2^{h} -1\\).
Un arbre complet de hauteur \\(h\\) (en prenant la convention que l'arbre vide a pour hauteur 0) a donc une taille \u00e9gale \u00e0 \\(2^{h}-1\\).
Remarque : On en d\u00e9duit une in\u00e9galit\u00e9 classique sur l'encadrement de la taille \\(t\\) d'un arbre binaire (non n\u00e9cessairement complet) de hauteur \\(h\\) :
\\[h \\leqslant t \\leqslant 2^{h}-1\\]"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#2-parcours-darbres","title":"2. Parcours d'arbres","text":"Les arbres \u00e9tant une structure hi\u00e9rarchique, leur utilisation implique la n\u00e9cessit\u00e9 d'un parcours des valeurs stock\u00e9es. Par exemple pour toutes les r\u00e9cup\u00e9rer dans un certain ordre, ou bien pour en chercher une en particulier.
Il existe plusieurs mani\u00e8res de parcourir un arbre.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#21-parcours-en-largeur-dabord-bfs","title":"2.1 Parcours en largeur d'abord (BFS)","text":"BFS : Breadth First Search
M\u00e9thode du parcours en largeur (BFS)
Le parcours en largeur d'abord est un parcours \u00e9tage par \u00e9tage (de haut en bas) et de gauche \u00e0 droite.
L'ordre des lettres parcourues est donc T-Y-O-P-H-N.
Les trois parcours que nous allons voir maintenant sont des parcours en profondeur d'abord, ou DFS (Depth First Search). Ce qui signifie qu'un des deux sous-arbres sera totalement parcouru avant que l'exploration du deuxi\u00e8me ne commence.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#22-parcours-prefixe","title":"2.2 Parcours pr\u00e9fixe","text":"Le parcours pr\u00e9fixe est un parcours en profondeur d'abord.
M\u00e9thode du parcours pr\u00e9fixe
(parfois aussi appel\u00e9 pr\u00e9ordre)
L'ordre des lettres parcourues est donc T-Y-P-O-H-N.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#23-parcours-infixe","title":"2.3 Parcours infixe","text":"Le parcours infixe est aussi un parcours en profondeur d'abord.
M\u00e9thode du parcours infixe
(parfois aussi appel\u00e9 en ordre)
L'ordre des lettres parcourues est donc P-Y-T-H-O-N.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#24-parcours-postfixe","title":"2.4 Parcours postfixe","text":"Le parcours postfixe est aussi un parcours en profondeur d'abord.
M\u00e9thode du parcours postfixe
(parfois aussi appel\u00e9 post-ordre ou encore suffixe)
L'ordre des lettres parcourues est donc P-Y-H-N-O-T.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#25-comment-ne-pas-se-melanger-entre-le-pre-in-post-fixe","title":"2.5 Comment ne pas se m\u00e9langer entre le pr\u00e9 / in / post fixe ?","text":"Ces trois mots-cl\u00e9s parlent de la place du p\u00e8re par rapport \u00e0 ses fils. Ensuite, il faut toujours se souvenir qu'on traite le fils gauche avant le fils droit.
Un parcours pr\u00e9fixe commencera toujours par la racine, alors qu'un parcours postfixe finira toujours par la racine. Dans un parcours infixe, la racine sera \u00abau milieu\u00bb (pas n\u00e9cessairement parfaitement).
Exercice 2
\u00c9nonc\u00e9Corr. largeurCorr. pr\u00e9fixeCorr. infixeCorr. postfixeDonner le rendu de chaque parcours :
largeur : 1 2 3 4 5 6 7 8 9
pr\u00e9fixe : 1 2 4 5 7 8 3 6 9
infixe : 4 2 7 5 8 1 3 9 6
postfixe : 4 7 8 5 2 9 6 3 1
Exercice 3
\u00c9nonc\u00e9Corr. largeurCorr. pr\u00e9fixeCorr. infixeCorr. postfixeDonner le rendu de chaque parcours :
largeur : 9 8 7 6 2 5 1 4 3
pr\u00e9fixe : 9 8 6 2 1 7 5 4 3
infixe : 6 8 1 2 9 7 4 5 3
postfixe : 6 1 2 8 4 3 5 7 9
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#3-implementations-dun-arbre-binaire","title":"3. Impl\u00e9mentations d'un arbre binaire","text":""},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#31-en-utilisant-la-programmation-orientee-objet","title":"3.1 En utilisant la Programmation Orient\u00e9e Objet","text":"Le but est d'obtenir l'interface ci-dessous.
Il est \u00e0 remarquer que ce que nous allons appeler \u00abArbre\u00bb est en fait un n\u0153ud et ses deux fils gauche et droit.
interface souhait\u00e9e
>>> a = Arbre(4) # pour cr\u00e9er l'arbre dont le n\u0153ud a pour valeur 4,\n # et dont les sous-arbres gauche et droit sont None\n>>> a.left = Arbre(3) # pour donner la valeur 3 au n\u0153ud du sous-arbre gauche de a\n>>> a.right = Arbre(1) # pour donner la valeur 1 au n\u0153ud du sous-arbre droit de a\n>>> a.right.data # pour acc\u00e9der \u00e0 la valeur du fils droit de a\n
Exercice 4
\u00c9nonc\u00e9CorrectionDessinez l'arbre cr\u00e9\u00e9 par les instructions suivantes :
>>> a = Arbre(4)\n>>> a.left = Arbre(3)\n>>> a.right = Arbre(1)\n>>> a.right.left = Arbre(2)\n>>> a.right.right = Arbre(7)\n>>> a.left.left = Arbre(6)\n>>> a.right.right.left = Arbre(9)\n
Impl\u00e9mentation
\u2bc8 Principe : nous allons cr\u00e9er une classe Arbre
, qui contiendra 3 attributs :
data
: la valeur du n\u0153ud (de type Int
)left
: le sous-arbre gauche (de type Arbre
)right
: le sous-arbre droit (de type Arbre
).Par d\u00e9faut, les attributs left
et right
seront \u00e0 None
, qui repr\u00e9sentera l'arbre vide (ce qui n'est pas tr\u00e8s rigoureux, car None
n'est pas de type Arbre
...).
\u2bc8 Encapsulation ou pas ??? :
Afin de respecter le paradigme de la Programmation Orient\u00e9e Objet, nous devrions jouer totalement le jeu de l'encapsulation en nous refusant d'acc\u00e9der directement aux attributs.
Pour cela il faut construire des m\u00e9thodes permettant d'acc\u00e9der \u00e0 ces attributs (avec des getters, ou accesseurs en fran\u00e7ais) ou de les modifier (avec des setters, ou mutateurs en fran\u00e7ais) .
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#311-implementation-avec-encapsulation","title":"3.1.1 Impl\u00e9mentation avec encapsulation","text":"Classe Arbre
avec encapsulation
class Arbre:\n def __init__(self, data):\n self.data = data\n self.left = None\n self.right = None\n\n def set_left(self, sousarbre): # mutateur\n self.left = sousarbre\n\n def set_right(self, sousarbre): # mutateur\n self.right = sousarbre \n\n def get_left(self): # accesseur\n return self.left\n\n def get_right(self): # accesseur\n return self.right\n\n def get_data(self): # accesseur\n return self.data\n
L'impl\u00e9mentation pr\u00e9c\u00e9dente permet d'utiliser les instructions de l'exercice pr\u00e9c\u00e9dent et de v\u00e9rifier que l'arbre a bien \u00e9t\u00e9 cr\u00e9\u00e9.
>>> a = Arbre(4)\n>>> a.set_left(Arbre(3))\n>>> a.set_right(Arbre(1))\n>>> a.get_right().set_left(Arbre(2))\n>>> a.get_right().set_right(Arbre(7))\n>>> a.get_left().set_left(Arbre(6))\n>>> a.get_right().get_right().set_left(Arbre(9))\n
>>> a\n <__main__.Arbre at 0x7f0100361f40>\n
>>> a.get_right().get_left().get_data()\n 2\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#311-implementation-sans-encapsulation","title":"3.1.1 Impl\u00e9mentation sans encapsulation","text":"Classe Arbre
sans encapsulation
class Arbre:\n def __init__(self, data):\n self.data = data\n self.left = None\n self.right = None\n
C'est d\u00e9j\u00e0 fini !
a = Arbre(4)\na.left = Arbre(3)\na.right = Arbre(1)\na.right.left = Arbre(2)\na.right.right = Arbre(7)\na.left.left = Arbre(6)\na.right.right.left = Arbre(9)\n
>>> a\n <__main__.Arbre at 0x7f0100361f40>\n
>>> a.right.left.data\n 2\n
On voit que l'impl\u00e9mentation avec acc\u00e8s direct aux attributs est beaucoup plus simple et rapide. N\u00e9anmoins, elle peut \u00eatre consid\u00e9r\u00e9e comme incorrecte dans certains langages qui obligent \u00e0 passer par des accesseurs ou mutateurs pour lire ou modifier les attributs.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#312-representation-graphique-en-console","title":"3.1.2 Repr\u00e9sentation graphique en console","text":"La m\u00e9thode affiche
suivante (qui n'est pas \u00e0 conna\u00eetre) permet d'avoir un semblant de repr\u00e9sentation graphique de l'arbre en console :
def affiche(self, indent = 0):\n val = self.data\n s = ' '*2*indent + '|' + '_' + str(val) + '\\n'\n if self.left is not None:\n s += self.left.affiche(indent + 1)\n if self.left is None and self.right is not None:\n s += ' '*(2*indent+2) + '|' + '_' + 'None' + '\\n' \n\n if self.right is not None:\n s += self.right.affiche(indent + 1)\n if self.right is None and self.left is not None:\n s += ' '*(2*indent+2) + '|' + '_' + 'None' + '\\n' \n return s\n
La repr\u00e9sentation de cet arbre : donnera alors :
>>> print(a.affiche())\n|_4\n |_3\n |_6\n |_None\n |_1\n |_2\n |_7\n |_9\n |_None\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#32-implementation-a-partir-de-tuples-imbriques","title":"3.2 Impl\u00e9mentation \u00e0 partir de tuples imbriqu\u00e9s","text":"Arbre
sous forme de tuples imbriqu\u00e9s
Un arbre peut se repr\u00e9senter par le tuple (valeur, sous-arbre gauche, sous-arbre droit)
. L'arbre ci-dessous : est repr\u00e9sent\u00e9 par le tuple :
>>> a = (2, (8, (6,(),()), (9,(),())), (1, (7, (),()), ()))\n
Le sous-arbre gauche est alors a[1]
et le sous-arbre droit est a[2]
.
>>> a[1]\n(8, (6, (), ()), (9, (), ()))\n>>> a[2]\n(1, (7, (), ()), ())\n
Exercice 5
\u00c9nonc\u00e9Correction\u00c9crire le tuple repr\u00e9sentant l'arbre ci-dessous.
a = (T,(Y,(P,(),()),()),(O,(H,(),()),(N,(),())))\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#33-implementation-a-partir-dune-simple-liste","title":"3.3 Impl\u00e9mentation \u00e0 partir d'une \u00absimple\u00bb liste","text":"De mani\u00e8re plus surprenante, il existe une m\u00e9thode pour impl\u00e9menter un arbre binaire (qui est une structure hi\u00e9rarchique) avec une liste (qui est une structure lin\u00e9aire). Ceci peut se faire par le biais d'une astuce sur les indices :
Les fils du n\u0153ud d'indice i sont plac\u00e9s aux indice 2i+1 et 2i+2.
Cette m\u00e9thode est connue sous le nom de \u00abm\u00e9thode d'Eytzinger\u00bb, et utilis\u00e9e notamment en g\u00e9n\u00e9alogie pour num\u00e9roter facilement les individus d'un arbre g\u00e9n\u00e9alogique.
Exemple :
Pour comprendre facilement la num\u00e9rotation, il suffit de s'imaginer l'arbre complet (en rajoutant les fils vides) et de faire une num\u00e9rotation en largeur, niveau par niveau :
Exercice 6
\u00c9nonc\u00e9CorrectionSi on note \u0394 le sous-arbre vide, dessiner l'arbre repr\u00e9sent\u00e9 par la liste :
a = [3, 4, \u0394, 7, 5]\n
Remarque : parfois (comme dans le sujet 0...) la racine de l'arbre est plac\u00e9e \u00e0 l'indice 1. Dans ce cas, les fils du n\u0153ud d'indice i sont plac\u00e9s aux indice 2i et 2i+1.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#4-utilisation-de-limplementation-parcours-taille","title":"4. Utilisation de l'impl\u00e9mentation : parcours, taille...","text":"Dans toute la suite, sauf mention contraire, on utilisera l'impl\u00e9mentation en Programmation Orient\u00e9e Objet, en version sans encapsulation (la plus simple). Nous allons cr\u00e9er des fonctions renvoyant les diff\u00e9rents parcours d'un arbre, ou encore sa taille, sa hauteur, son nombre de feuilles... Toutes ses fonctions exploiteront la structure r\u00e9cursive d'un arbre.
Rappel de l'impl\u00e9mentation :
class Arbre:\n def __init__(self, data):\n self.data = data\n self.left = None\n self.right = None\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#41-parcours-prefixe-infixe-postfixe","title":"4.1 Parcours pr\u00e9fixe, infixe, postfixe","text":""},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#411-parcours-prefixe","title":"4.1.1 Parcours pr\u00e9fixe","text":"Parcours pr\u00e9fixe
def prefixe(arbre):\n if arbre is None :\n return None\n print(arbre.data, end = '-')\n prefixe(arbre.left)\n prefixe(arbre.right)\n
Exemple avec l'arbre
a = Arbre(9)\na.left = Arbre(8)\na.right = Arbre(7)\na.left.left = Arbre(6)\na.left.right = Arbre(2)\na.right.right = Arbre(5)\na.left.right.left = Arbre(1)\na.right.right.left = Arbre(4)\na.right.right.right = Arbre(3)\n
>>> prefixe(a)\n9-8-6-2-1-7-5-4-3-\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#412-parcours-infixe","title":"4.1.2 Parcours infixe","text":"Parcours infixe
def infixe(arbre):\n if arbre is None :\n return None\n infixe(arbre.left)\n print(arbre.data, end = '-')\n infixe(arbre.right)\n
>>> infixe(a)\n6-8-1-2-9-7-4-5-3-\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#413-parcours-postfixe","title":"4.1.3 Parcours postfixe","text":"Parcours postfixe
def postfixe(arbre):\n if arbre is None :\n return None\n postfixe(arbre.left)\n postfixe(arbre.right)\n print(arbre.data, end = '-')\n
>>> postfixe(a)\n6-1-2-8-4-3-5-7-9-\n
Pause vid\u00e9o
def infixe(arbre):\n parcours = []\n pile = []\n\n current = arbre\n\n while pile != [] or current is not None:\n if current is not None:\n pile.append(current)\n current = current.left\n else:\n current = pile.pop()\n parcours.append(current.data)\n current = current.right\n\n return parcours\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#42-calcul-de-la-taille-dun-arbre","title":"4.2 Calcul de la taille d'un arbre","text":"Rappel : la taille d'un arbre est le nombre de ses n\u0153uds.
Taille d'un arbre
def taille(arbre):\n if arbre is None:\n return 0\n else:\n return 1 + taille(arbre.left) + taille(arbre.right)\n
Exemple avec l'arbre
a = Arbre(9)\na.left = Arbre(8)\na.right = Arbre(7)\na.left.left = Arbre(6)\na.left.right = Arbre(2)\na.right.right = Arbre(5)\na.left.right.left = Arbre(1)\na.right.right.left = Arbre(4)\na.right.right.right = Arbre(3)\n
>>> taille(a)\n9\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#43-calcul-de-la-hauteur-dun-arbre","title":"4.3 Calcul de la hauteur d'un arbre","text":"Rappel : on prendra comme convention que l'arbre vide a pour hauteur 0.
Hauteur d'un arbre
def hauteur(arbre):\n if arbre is None:\n return 0\n else:\n return 1 + max(hauteur(arbre.left), hauteur(arbre.right))\n
>>> hauteur(a)\n4\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#44-calcul-du-nombre-de-feuilles-dun-arbre","title":"4.4 Calcul du nombre de feuilles d'un arbre","text":"Rappel : une feuille est un n\u0153ud d'arit\u00e9 0, autrement dit sans fils gauche ni fils droit.
Nombre de feuilles d'un arbre
def nb_feuilles(arbre):\n if arbre is None:\n return 0\n if (arbre.left is None) and (arbre.right is None):\n return 1\n return nb_feuilles(arbre.left) + nb_feuilles(arbre.right)\n
>>> nb_feuilles(a)\n4\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#45-recherche-dune-valeur-dans-un-arbre","title":"4.5 Recherche d'une valeur dans un arbre","text":"On renverra True
ou False
en fonction de la pr\u00e9sence ou non de la valeur dans l'arbre.
Recherche d'une valeur dans un arbre
def recherche(arbre, valeur):\n if arbre is None:\n return False\n if arbre.data == valeur:\n return True\n return recherche(arbre.left, valeur) or recherche(arbre.right, valeur)\n
>>> recherche(a, 2)\nTrue\n>>> recherche(a, 45)\nFalse\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#46-parcours-en-largeur","title":"4.6 Parcours en largeur","text":"Le parcours en largeur (BFS) est le plus simple \u00e0 faire visuellement : mais il est plus difficile \u00e0 coder que les parcours pr\u00e9fixe, infixe, postfixe. Il est n\u00e9cessaire d'utiliser une file :
On importera l'objet Queue()
du module queue
de Python, qui permet de :
file = Queue()
file.get()
a
par file.put(a)
file.empty()
# arbre-test\n# ne pas oublier de remonter plus haut dans le document pour relancer la classe Arbre\na = Arbre(8)\na.left = Arbre(4)\na.right = Arbre(5)\na.left.left = Arbre(2)\na.left.right = Arbre(1)\na.right.right = Arbre(3)\n
Parcours en largeur (BFS)
from queue import Queue\n\ndef BFS(arbre): \n file = Queue()\n file.put(arbre)\n sol = []\n while not file.empty():\n a = file.get()\n if a is not None :\n sol.append(a.data)\n file.put(a.left)\n file.put(a.right)\n return sol\n
>>> BFS(a)\n[8, 4, 5, 2, 1, 3]\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#5-arbres-binaires-de-recherche-abr","title":"5. Arbres binaires de recherche (ABR)","text":"D\u00e9finition d'un ABR
Un arbre binaire de recherche est un arbre binaire dont les valeurs des n\u0153uds (valeurs qu'on appelle \u00e9tiquettes, ou cl\u00e9s) v\u00e9rifient la propri\u00e9t\u00e9 suivante :
\u00c0 noter que l'arbre 3 (qui est bien un ABR) est appel\u00e9 arbre filiforme.
L'arbre 5 n'est pas un ABR \u00e0 cause de la feuille 9, qui fait partie du sous-arbre gauche de 3 sans lui \u00eatre inf\u00e9rieure.
Remarque : on pourrait aussi d\u00e9finir un ABR comme un arbre dont le parcours infixe est une suite croissante.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#51-determiner-si-un-arbre-est-un-abr","title":"5.1 D\u00e9terminer si un arbre est un ABR","text":"Employer une m\u00e9thode r\u00e9cursive imposerait de garder en m\u00e9moire dans l'exploration des sous-arbres la valeur maximale ou minimale. Nous allons plut\u00f4t utiliser la remarque pr\u00e9c\u00e9dente, et nous servir du parcours infixe.
M\u00e9thode : r\u00e9cup\u00e9rer le parcours infixe dans une liste, et faire un test sur cette liste.
\u00catre ou ne pas \u00eatre un ABR
def infixe(arbre, s = None):\n if s is None:\n s = []\n if arbre is None :\n return None\n infixe(arbre.left, s)\n s.append(arbre.data)\n infixe(arbre.right, s)\n return s\n\n\ndef est_ABR(arbre):\n'''renvoie un bool\u00e9en indiquant si arbre est un ABR'''\n parcours = infixe(arbre)\n return parcours == sorted(parcours) # on regarde si le parcours est \u00e9gal au parcours tri\u00e9 \n
# arbres-tests \n\n#arbre n\u00b04\na = Arbre(5)\na.left = Arbre(2)\na.right = Arbre(7)\na.left.left = Arbre(0)\na.left.right = Arbre(3)\na.right.left = Arbre(6)\na.right.right = Arbre(8)\n\n#arbre n\u00b05\nb = Arbre(3)\nb.left = Arbre(2)\nb.right = Arbre(5)\nb.left.left = Arbre(1)\nb.left.right = Arbre(9)\nb.right.left = Arbre(4)\nb.right.right = Arbre(6)\n
>>> est_ABR(a)\nTrue\n>>> est_ABR(b)\nFalse\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#52-rechercher-une-cle-dans-un-abr","title":"5.2 Rechercher une cl\u00e9 dans un ABR","text":"Un arbre binaire de taille \\(n\\) contient \\(n\\) cl\u00e9s (pas forc\u00e9ment diff\u00e9rentes). Pour savoir si une valeur particuli\u00e8re fait partie des cl\u00e9s, on peut parcourir tous les n\u0153uds de l'arbre, jusqu'\u00e0 trouver (ou pas) cette valeur dans l'arbre. Dans le pire des cas, il faut donc faire \\(n\\) comparaisons.
Mais si l'arbre est un ABR, le fait que les valeurs soient \u00abrang\u00e9es\u00bb va consid\u00e9rablement am\u00e9liorer la vitesse de recherche de cette cl\u00e9, puisque la moiti\u00e9 de l'arbre restant sera \u00e9cart\u00e9e apr\u00e8s chaque comparaison.
Recherche d'une cl\u00e9 dans un ABR
Exemple
L'arbre a
contient la valeur 8, mais l'arbre b
ne la contient pas :
>>> contient_valeur(a,8)\nTrue\n>>> contient_valeur(b,8)\nFalse\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#53-cout-de-la-recherche-dans-un-abr-equilibre","title":"5.3 Co\u00fbt de la recherche dans un ABR \u00e9quilibr\u00e9","text":"Imaginons un arbre \u00e9quilibr\u00e9 de taille \\(n\\). Combien d'\u00e9tapes faudra-t-il, dans le pire des cas, pour trouver (ou pas) une cl\u00e9 particuli\u00e8re dans cet arbre ?
Apr\u00e8s chaque n\u0153ud, le nombre de n\u0153uds restant \u00e0 explorer est divis\u00e9 par 2. On retrouve l\u00e0 le principe de recherche dichotomique, vu en classe de Premi\u00e8re (voir ici).
S'il faut parcourir tous les \u00e9tages de l'arbre avant de trouver (ou pas) la cl\u00e9 recherch\u00e9e, le nombre de n\u0153uds parcourus est donc \u00e9gal \u00e0 la hauteur \\(h\\) de l'arbre.
Pour un arbre complet, cette hauteur v\u00e9rifie la relation \\(2^h -1= n\\). et donc \\(2^h = n+1\\).
\\(h\\) est donc le \u00abnombre de puissance de 2\u00bb que l'on peut mettre dans \\(n+1\\). Cette notion s'appelle le logarithme de base 2 et se note \\(\\log_2\\).
Par exemple, \\(\\log_2(64)=6\\) car \\(2^6=64\\).
Le nombre maximal de n\u0153uds \u00e0 parcourir pour rechercher une cl\u00e9 dans un ABR \u00e9quilibr\u00e9 de taille \\(n\\) est donc de l'ordre de \\(\\log_2(n)\\), ce qui est tr\u00e8s performant !
Pour arbre contenant 1000 valeurs, 10 \u00e9tapes suffisent.
Cette complexit\u00e9 logarithmique est un atout essentiel de la structure d'arbre binaire de recherche.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#54-insertion-dans-un-abr","title":"5.4 Insertion dans un ABR","text":"L'insertion d'une cl\u00e9 va se faire au niveau d'une feuille, donc au bas de l'arbre. Dans la version r\u00e9cursive de l'algorithme d'insertion, que nous allons impl\u00e9menter, il n'est pourtant pas n\u00e9cessaire de descendre manuellement dans l'arbre jusqu'au bon endroit : il suffit de distinguer dans lequel des deux sous-arbres gauche et droit doit se trouver la future cl\u00e9, et d'appeler r\u00e9cursivement la fonction d'insertion dans le sous-arbre en question.
Algorithme :
Insertion dans un ABR
def insertion(arbre, valeur):\n if arbre is None :\n return Arbre(valeur)\n else :\n v = arbre.data\n if valeur <= v :\n arbre.left = insertion(arbre.left, valeur)\n else:\n arbre.right = insertion(arbre.right, valeur)\n return arbre\n
Exemple : Nous allons ins\u00e9rer la valeur 4 dans l'arbre a
et v\u00e9rifier par un parcours infixe (avant et apr\u00e8s l'insertion) que la valeur 4 a bien \u00e9t\u00e9 ins\u00e9r\u00e9e au bon endroit.
a = Arbre(5)\na.left = Arbre(2)\na.right = Arbre(7)\na.left.left = Arbre(0)\na.left.right = Arbre(3)\na.right.left = Arbre(6)\na.right.right = Arbre(8)\n
>>> infixe(a)\n0-2-3-5-6-7-8-\n>>> insertion(a,4)\n<__main__.Arbre at 0x7f46f0507e80>\n>>> infixe(a)\n0-2-3-4-5-6-7-8-\n
La valeur 4 a donc bien \u00e9t\u00e9 ins\u00e9r\u00e9e au bon endroit.
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/cours/#bibliographie","title":"Bibliographie","text":"Exercice 1
Exercice 2 du sujet Nouvelle-Cal\u00e9donie J2 2022
Correction 1.C'est un arbre binaire car chaque n\u0153ud poss\u00e8de au maximum deux fils.
Correction 2.aV
est un dictionnaire.
V['J']\n
Correction 2.c def somme(W):\n s = 0\n for cle in W:\n s += W[cle]\n return s\n
Correction 2.d def VMax(W):\n val_max = 0\n for cle in W:\n if W[cle] > val_max:\n val_max = W[cle]\n cle_max = cle\n return cle_max\n
Correction 3. Cet algorithme calcule le nombre total de n\u0153uds de l'arbre, donc la taille de l'arbre. C'est un algorithme r\u00e9cursif qui va renvoyer, si on n'est pas positionn\u00e9 sur un arbre vide, la valeur 1 (correspond au n\u0153ud racine sur lequel on est positionn\u00e9), plus la taille des deux sous-arbres gauche et droits.
Correction 4.aLe parcours est A-B-C-E-D-F-G-I-H-J
C'est un parcours pr\u00e9fixe.
Exercice 2
2020, sujet 0
Question 1
D\u00e9terminer la taille et la hauteur de l\u2019arbre binaire suivant :
Question 2
On d\u00e9cide de num\u00e9roter en binaire les n\u0153uds d\u2019un arbre binaire de la fa\u00e7on suivante :
Par exemple, dans l\u2019arbre ci-dessous, on a utilis\u00e9 ce proc\u00e9d\u00e9 pour num\u00e9roter les n\u0153uds A, B, C, E et F .
Question 3 Un arbre binaire est dit complet si tous les niveaux de l\u2019arbre sont remplis.
On d\u00e9cide de repr\u00e9senter un arbre binaire complet par un tableau de taille n + 1, o\u00f9 n est la taille de l\u2019arbre, de la fa\u00e7on suivante :
R\u00e9pondre aux questions suivantes :
Question 4
On se place dans le cas particulier d\u2019un arbre binaire de recherche complet o\u00f9 les n\u0153uds contiennent des entiers et pour lequel la valeur de chaque noeud est sup\u00e9rieure \u00e0 celles des noeuds de son fils gauche, et inf\u00e9rieure \u00e0 celles des noeuds de son fils droit.
\u00c9crire une fonction recherche
ayant pour param\u00e8tres un arbre arbre
et un \u00e9l\u00e9ment element
. Cette fonction renvoie True
si element
est dans l\u2019arbre et False
sinon. L\u2019arbre sera repr\u00e9sent\u00e9 par un tableau comme dans la question pr\u00e9c\u00e9dente.
Q1 La taille est 9, la hauteur est 4. Q2 1. G est associ\u00e9 \u00e0 1010. Q2 2. 13 s'\u00e9crit 1101 en binaire, c'est donc le n\u0153ud I. Q2 3. Les n\u0153uds les plus en bas sont not\u00e9s sur \\(h\\) bits. Q2 4. L'arbre de hauteur \\(h\\) de taille minimale est l'arbre filiforme, qui est de taille \\(h\\). L'arbre de hauteur \\(h\\) de taille maximale est l'arbre complet, qui est de taille \\(2^h-1\\). Si \\(n\\) est la taille d'un arbre quelconque de taille \\(h\\), on a donc bien
\\(h \\leqslant n \\leqslant 2^h-1\\).
Q3 1. Tableau : [15, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O]
. Q3 2. Le p\u00e8re du n\u0153ud d'indice i
a pour indice i//2
.
Q4 :
def recherche(arbre, element):\n i = 1\n while i < len(arbre):\n if arbre[i] == element:\n return True\n if element < arbre[i]:\n i = 2*i # on se place sur le fils gauche\n else:\n i = 2*i + 1 # on se place sur le fils droit\n return False\n
Exercice 3
2021, M\u00e9tropole sujet 1
Dans cet exercice, les arbres binaires de recherche ne peuvent pas comporter plusieurs fois la m\u00eame cl\u00e9. De plus, un arbre binaire de recherche limit\u00e9 \u00e0 un n\u0153ud a une hauteur de 1. On consid\u00e8re l\u2019arbre binaire de recherche repr\u00e9sent\u00e9 ci-dessous (figure 1), o\u00f9 val
repr\u00e9sente un entier :
1.a Donner le nombre de feuilles de cet arbre et pr\u00e9ciser leur valeur (\u00e9tiquette).
1.b Donner le sous arbre-gauche du n\u0153ud 23.
1.c Donner la hauteur et la taille de l\u2019arbre.
1.d Donner les valeurs enti\u00e8res possibles de val
pour cet arbre binaire de recherche.
On suppose, pour la suite de cet exercice, que val
est \u00e9gal \u00e0 16.
2. On rappelle qu\u2019un parcours infixe depuis un n\u0153ud consiste, dans l\u2019ordre, \u00e0 faire un parcours infixe sur le sous arbre-gauche, afficher le n\u0153ud puis faire un parcours infixe sur le sous-arbre droit. Dans le cas d\u2019un parcours suffixe, on fait un parcours suffixe sur le sous-arbre gauche puis un parcours suffixe sur le sous-arbre droit, avant d\u2019afficher le n\u0153ud.
a. Donner les valeurs d\u2019affichage des n\u0153uds dans le cas du parcours infixe de l\u2019arbre. b. Donner les valeurs d\u2019affichage des n\u0153uds dans le cas du parcours suffixe de l\u2019arbre.
3. On consid\u00e8re la classe Noeud
d\u00e9finie de la fa\u00e7on suivante en Python :
a. Repr\u00e9senter l\u2019arbre construit suite \u00e0 l\u2019ex\u00e9cution de l\u2019instruction suivante :
racine = Noeud(18)\nracine.insere_tout([12, 13, 15, 16, 19, 21, 32, 23])\n
b. \u00c9crire les deux instructions permettant de construire l\u2019arbre de la figure 1. On rappelle que le nombre val
est \u00e9gal \u00e0 16. c. On consid\u00e8re l\u2019arbre tel qu\u2019il est pr\u00e9sent\u00e9 sur la figure 1. D\u00e9terminer l\u2019ordre d\u2019ex\u00e9cution des blocs (rep\u00e9r\u00e9s de 1 \u00e0 3) suite \u00e0 l\u2019application de la m\u00e9thode insere(19)
au n\u0153ud racine de cet arbre.
4. \u00c9crire une m\u00e9thode recherche(self, v)
qui prend en argument un entier v
et renvoie la valeur True
si cet entier est une \u00e9tiquette de l\u2019arbre, False
sinon.
1.a. Il y a 4 feuilles, d'\u00e9tiquette 12, val
, 21 et 32. 1.b. Le sous-arbre gauche du n\u0153ud 23 est 19-21. 1.c. La hauteur de l'arbre est 4. Sa taille est 9. 1.d. Les valeurs possibles de val
sont 16 et 17.
2.a. Parcours infixe : 12-13-15-16-18-19-21-23-32 2.b. Parcours suffixe : 12-13-16-15-21-19-32-23-18
3.a.
3.b.
racine = Noeud(18)\nracine.insere([15, 13, 12, 16, 23, 32, 19, 21])\n
(d'autres solutions sont possibles) 3.c. Bloc 3 - Bloc 2 - Bloc 1
4.
class Noeud():\n def __init__(self, v):\n self.ag = None\n self.ad = None\n self.v = v\n\n def insere(self, v):\n n = self\n est_insere = False\n while not est_insere:\n if v == n.v:\n est_insere = True\n elif v < n.v:\n if n.ag != None:\n n = n.ag\n else:\n n.ag = Noeud(v)\n est_insere = True\n else:\n if n.ad != None:\n n = n.ad\n else:\n n.ad = Noeud(v)\n est_insere = True\n\n def insere_tout(self, vals):\n for v in vals:\n self.insere(v)\n\n def recherche(self, v):\n arbre = self\n while not arbre is None:\n if arbre.v == v:\n return True\n if v < arbre.v:\n arbre = arbre.ag\n else:\n arbre = arbre.ad\n return False\n\n\nracine = Noeud(18)\nracine.insere_tout([12, 13, 15, 14, 19, 21, 32, 23])\nprint(racine.recherche(149))\nprint(racine.recherche(12))\n
Exercice 4
2021, M\u00e9tropole Candidats Libres 2
On rappelle qu\u2019un arbre binaire est compos\u00e9 de n\u0153uds, chacun des n\u0153uds poss\u00e9dant \u00e9ventuellement un sous-arbre gauche et \u00e9ventuellement un sous-arbre droit. Un n\u0153ud sans sous-arbre est appel\u00e9 feuille. La taille d\u2019un arbre est le nombre de n\u0153uds qu\u2019il contient ; sa hauteur est le nombre de n\u0153uds du plus long chemin qui joint le n\u0153ud racine \u00e0 l\u2019une des feuilles. Ainsi la hauteur d\u2019un arbre r\u00e9duit \u00e0 un n\u0153ud, c\u2019est-\u00e0-dire la racine, est 1.
Dans un arbre binaire de recherche, chaque n\u0153ud contient une cl\u00e9, ici un nombre entier, qui est :
Un arbre binaire de recherche est dit \u00ab bien construit \u00bb s\u2019il n\u2019existe pas d\u2019arbre de hauteur inf\u00e9rieure qui pourrait contenir tous ses n\u0153uds.
On consid\u00e8re l\u2019arbre binaire de recherche ci-dessous.
1.a. Quelle est la taille de l\u2019arbre ci-dessus ?
1.b. Quelle est la hauteur de l\u2019arbre ci-dessus ?
corrig\u00e91.a. La taille de l'arbre est 7. 1.b. La hauteur de l'arbre est 4.
2. Cet arbre binaire de recherche n\u2019est pas \u00ab bien construit \u00bb. Proposer un arbre binaire de recherche contenant les m\u00eames cl\u00e9s et dont la hauteur est plus petite que celle de l\u2019arbre initial.
corrig\u00e92.
3. Les classes Noeud et Arbre ci-dessous permettent de mettre en \u0153uvre en Python la structure d\u2019arbre binaire de recherche. La m\u00e9thode insere
permet d\u2019ins\u00e9rer r\u00e9cursivement une nouvelle cl\u00e9.
class Noeud :\n\n def __init__(self, cle):\n self.cle = cle\n self.gauche = None\n self.droit = None\n\n def insere(self, cle):\n if cle < self.cle :\n if self.gauche == None :\n self.gauche = Noeud(cle)\n else :\n self.gauche.insere(cle)\n elif cle > self.cle :\n if self.droit == None :\n self.droit = Noeud(cle)\n else :\n self.droit.insere(cle)\n\nclass Arbre :\n\n def __init__(self, cle):\n self.racine = Noeud(cle)\n\n def insere(self, cle):\n self.racine.insere(cle)\n
Donner la repr\u00e9sentation de l\u2019arbre cod\u00e9 par les instructions ci-dessous.
a = Arbre(10)\na.insere(20)\na.insere(15)\na.insere(12)\na.insere(8)\na.insere(4)\na.insere(5)\n
corrig\u00e9 3.
4. Pour calculer la hauteur d\u2019un arbre non vide, on a \u00e9crit la m\u00e9thode ci-dessous dans la classe Noeud.
def hauteur(self):\n if self.gauche == None and self.droit == None:\n return 1\n if self.gauche == None:\n return 1 + self.droit.hauteur()\n elif self.droit == None:\n return 1 + self.gauche.hauteur()\n else:\n hg = self.gauche.hauteur()\n hd = self.droit.hauteur()\n if hg > hd:\n return hg + 1\n else:\n return hd + 1\n
\u00c9crire la m\u00e9thode hauteur
de la classe Arbre
qui renvoie la hauteur de l\u2019arbre. corrig\u00e9 4.
def hauteur(self):\n return self.racine.hauteur()\n
5. \u00c9crire les m\u00e9thodes taille
des classes Noeud
et Arbre
permettant de calculer la taille d\u2019un arbre.
5. M\u00e9thode taille
de la classe Noeud
:
def taille(self):\n if self.gauche is None and self.droit is None:\n return 1\n elif self.gauche is None:\n return 1 + self.droit.taille()\n elif self.droit is None:\n return 1 + self.gauche.taille()\n else:\n return 1 + self.gauche.taille() + self.droit.taille()\n
M\u00e9thode taille
de la classe Arbre
: def taille(self):\n return self.racine.taille()\n
6. On souhaite \u00e9crire une m\u00e9thode bien_construit
de la classe Arbre
qui renvoie la valeur True
si l\u2019arbre est \u00ab bien construit \u00bb et False
sinon.
On rappelle que la taille maximale d\u2019un arbre binaire de recherche de hauteur \\(\u210e\\) est \\(2^h - 1\\).
6.a Quelle est la taille minimale, not\u00e9e min
d\u2019un arbre binaire de recherche \u00ab bien construit \u00bb de hauteur \\(\u210e\\) ?
6.a. La configuration minimale d'un arbre bien construit de hauteur \\(h\\) peut \u00eatre :
La taille minimale min
est donc \u00e9gale \u00e0 \\(2^{h-1}\\).
6.b \u00c9crire la m\u00e9thode bien_construit
demand\u00e9e.
6.b. Intuitivement, un arbre est mal construit si sa hauteur est trop grande par rapport \u00e0 sa taille (trop \u00e9tir\u00e9).
Donc un arbre est mal construit si sa taille est trop petite par rapport \u00e0 sa hauteur.
Donc un arbre de taille \\(t\\) et de hauteur \\(h\\) est mal construit si \\(t < 2^{h-1}\\), puisqu'on a d\u00e9montr\u00e9 que \\(2^{h-1}\\) \u00e9tait la taille minimale.
Pour tester si un arbre est bien construit, on va donc juste v\u00e9rifier que \\(t \\geqslant 2^{h-1}\\) :
def bien_construit(self):\n h = self.taille()\n return self.taille() >= 2**(h-1)\n
Exercice 5
2021, Polyn\u00e9sie
Cet exercice traite principalement du th\u00e8me \u00ab algorithmique, langages et programmation \u00bb et en particulier les arbres binaires de recherche. La premi\u00e8re partie aborde les arbres en mode d\u00e9branch\u00e9 via l'application d'un algorithme sur un exemple. La suivante porte sur la programmation orient\u00e9e objet. La derni\u00e8re partie fait le lien avec les algorithmes de tri.
Partie A : \u00c9tude d'un exemple
Consid\u00e9rons l'arbre binaire de recherche ci-dessous :
Q1. Indiquer quelle valeur a le n\u0153ud racine et quels sont les fils de ce n\u0153ud.
corrig\u00e9Le n\u0153ud racine est 5 et ses fils sont 2 et 7.
Q2. Indiquer quels sont les n\u0153uds de la branche qui se termine par la feuille qui a pour valeur 3.
corrig\u00e9La branche qui se termine par la feuille 3 a pour n\u0153uds 5, 2 et 3.
Q3. Dessiner l\u2019arbre obtenu apr\u00e8s l\u2019ajout de la valeur 6.
corrig\u00e9Partie B : Impl\u00e9mentation en Python
Voici un extrait d\u2019une impl\u00e9mentation en Python d'une classe mod\u00e9lisant un arbre binaire de recherche.
class ABR:\n\"\"\"Impl\u00e9mentation d\u2019un arbre binaire de recherche (ABR)\"\"\"\n def __init__(self, valeur=None):\n self.valeur = valeur\n self.fg = None\n self.fd = None\n\n def estVide(self):\n return self.valeur == None\n\n def insererElement(self, e):\n if self.estVide():\n self.valeur = e\n else:\n if e < self.valeur:\n if self.fg:\n self.fg.insererElement(e)\n else:\n self.fg = ABR(e)\n if e > self.valeur:\n if self.fd:\n self.fd.insererElement(e)\n else:\n self.fd = ABR(e)\n
Q1. Expliquer le r\u00f4le de la fonction __init__
.
La fonction __init__
est appel\u00e9e \u00abm\u00e9thode constructeur\u00bb, c'est elle qui cr\u00e9e l'objet et le dote de tous les attributs n\u00e9cessaires.
Q2. Dans cette impl\u00e9mentation, expliquer ce qui se passe si on ajoute un \u00e9l\u00e9ment d\u00e9j\u00e0 pr\u00e9sent dans l\u2019arbre.
corrig\u00e9Si on ajoute un \u00e9l\u00e9ment d\u00e9j\u00e0 pr\u00e9sent dans l'arbre, la valeur e
sera \u00e9gale \u00e0 self.valeur
(\u00e9ventuellement apr\u00e8s quelques appels r\u00e9cursifs). Or ce cas d'\u00e9galit\u00e9 n'est pas pr\u00e9vu par les tests : il ne se passera donc RIEN. Ceci est le comportement souhait\u00e9 puisqu'on ne veut pas avoir deux valeurs identiques dans notre ABR, ainsi qu'il est rappel\u00e9 au d\u00e9but de l'\u00e9nonc\u00e9.
Q3. Recopier et compl\u00e9ter les pointill\u00e9s ci-dessous permettant de cr\u00e9er l\u2019arbre de la partie A.
arbre = ABR(.......... )\narbre.insererElement(2)\narbre.insererElement(.......... )\narbre.insererElement(7)\narbre.insererElement(.......... )\n
corrig\u00e9 arbre = ABR(5)\narbre.insererElement(2)\narbre.insererElement(3)\narbre.insererElement(7)\narbre.insererElement(8)\n
Partie C : Tri par arbre binaire de recherche
On souhaite trier un ensemble de valeurs enti\u00e8res distinctes gr\u00e2ce \u00e0 un arbre binaire de recherche. Pour cela, on ajoute un \u00e0 un les \u00e9l\u00e9ments de l\u2019ensemble dans un arbre initialement vide. Il ne reste plus qu\u2019\u00e0 parcourir l\u2019arbre afin de lire et de stocker dans un tableau r\u00e9sultat les valeurs dans l\u2019ordre croissant.
Q1. Donner le nom du parcours qui permet de visiter les valeurs d\u2019un arbre binaire de recherche dans l\u2019ordre croissant.
corrig\u00e9Le parcours qui permet de visiter les valeurs d'un ABR dans l'ordre croissant est le parcours infixe.
Q2. Comparer la complexit\u00e9 de cette m\u00e9thode de tri avec celle du tri par insertion ou du tri par s\u00e9lection.
corrig\u00e9question difficile Pour cr\u00e9er l'ABR, il faut d'abord ins\u00e9rer chacune des valeurs. La fonction insertion
reposant sur une division par 2 \u00e0 chaque \u00e9tape de la taille de l'espace de recherche, on peut dire qu'elle a une complexit\u00e9 logarithmique. Mais cette op\u00e9ration est \u00e0 effectuer autant de fois qu'il y a d'\u00e9l\u00e9ments \u00e0 ins\u00e9rer : il faut donc multiplier la complexit\u00e9 logarithmique par n
, ce qui fera donc une complexit\u00e9 en \\(n \\log(n)\\). L'algorithme de parcours infixe est lui aussi lin\u00e9raire, ce qui ne change pas la complexit\u00e9 totale. Cette complexit\u00e9 est meilleure que le tris par insertion ou s\u00e9lection, qui sont de complexit\u00e9 quadratique.
Exercice 6
2021, Centres \u00c9trangers, sujet 1
Un arbre binaire est soit vide, soit un n\u0153ud qui a une valeur et au plus deux fils (le sous-arbre gauche et le sous-arbre droit).
Un arbre binaire de recherche est ordonn\u00e9 de la mani\u00e8re suivante :
Pour chaque n\u0153ud X,
Ainsi, par exemple, toutes les valeurs des n\u0153uds G1, G2 et G3 sont strictement inf\u00e9rieures \u00e0 la valeur du n\u0153ud X et toutes les valeurs des n\u0153uds D1, D2 et D3 sont sup\u00e9rieures ou \u00e9gales \u00e0 la valeur du n\u0153ud X.
Voici un exemple d'arbre binaire de recherche dans lequel on a stock\u00e9 dans cet ordre les valeurs : [26, 3, 42, 15, 29, 19, 13, 1, 32, 37, 30]
L'\u00e9tiquette d'un n\u0153ud indique la valeur du n\u0153ud suivie du nom du n\u0153ud. Les n\u0153uds ont \u00e9t\u00e9 nomm\u00e9s dans l'ordre de leur insertion dans l'arbre ci-dessous.
'29, noeud04'
signifie que le n\u0153ud nomm\u00e9 noeud04
poss\u00e8de la valeur 29.
Q1. On ins\u00e8re la valeur 25 dans l'arbre, dans un nouveau n\u0153ud nomm\u00e9 n\u0153ud11.
Recopier l'arbre binaire de recherche \u00e9tudi\u00e9 et placer la valeur 25 sur cet arbre en coloriant en rouge le chemin parcouru.
Pr\u00e9ciser sous quel n\u0153ud la valeur 25 sera ins\u00e9r\u00e9e et si elle est ins\u00e9r\u00e9e en fils gauche ou en fils droit, et expliquer toutes les \u00e9tapes de la d\u00e9cision.
Correction25 \u00e9tant plus petit que 26, on part dans son sous-arbre gauche. 25 \u00e9tant plus grand que 3, on part dans son sous-arbre droit. 25 \u00e9tant plus grand que 15, on part dans son sous-arbre droit. 25 \u00e9tant plus grand que 19, on ins\u00e8re 25 en tant que fils droit de 19.
Q2. Pr\u00e9ciser toutes les valeurs enti\u00e8res que l\u2019on peut stocker dans le n\u0153ud fils gauche du n\u0153ud04 (vide pour l'instant), en respectant les r\u00e8gles sur les arbres binaires de recherche.
CorrectionLes valeurs acceptables doivent \u00eatre strictement inf\u00e9rieures \u00e0 29, et sup\u00e9rieures ou \u00e9gales \u00e0 26. Ces valeurs sont donc : 26, 27 et 28.
Q3. Voici un algorithme r\u00e9cursif permettant de parcourir et d'afficher les valeurs de l'arbre :
Parcours(A) # A est un arbre binaire de recherche\n Afficher(A.valeur)\n Parcours(A.fils_gauche)\n Parcours(A.fils_droit)\n
Q3.a. \u00c9crire la liste de toutes les valeurs dans l'ordre o\u00f9 elles seront affich\u00e9es.
Q3.b. Choisir le type de parcours d'arbres binaires de recherche r\u00e9alis\u00e9 parmi les propositions suivantes : Pr\u00e9fixe, Suffixe ou Infixe.
CorrectionOn reconnait un parcours pr\u00e9fixe.
Q4. En vous inspirant de l\u2019algorithme pr\u00e9c\u00e9dent, \u00e9crire un algorithme Parcours2 permettant de parcourir et d'afficher les valeurs de l'arbre A dans l'ordre croissant.
CorrectionPour afficher les valeurs d'un ABR dans un ordre croissant, il faut utiliser un parcours infixe. Un algorithme r\u00e9cursif de parcours infixe peut \u00eatre celui-ci:
Parcours2(A) # A est un arbre binaire de recherche\n Parcours(A.fils_gauche)\n Afficher(A.valeur)\n Parcours(A.fils_droit)\n
"},{"location":"T1_Structures_de_donnees/1.3_Arbres/exercices/#exercice","title":"Exercice","text":"Exercice 3 du sujet Centres Etrangers J2 - 2023
Correction Q1.a.'Bonjour Alan !'
Ce sont des bool\u00e9ens. x
vaut False
, y
vaut True
.
def occurences_lettre(une_chaine, une_lettre):\n nb = 0\n for lettre in une_chaine:\n if lettre == une_lettre:\n nb += 1\n return nb\n
Correction Q3.b.. def hauteur(un_abr):\n if un_abr.est_vide():\n return 0\n else:\n return 1 + max(hauteur(un_abr.sous_arbre_gauche, hauteur(un_abr.sous_arbre_droit)\n
Fichier des mots fran\u00e7ais : gutemberg.txt
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/TP_Labyrinthe/","title":"R\u00e9solution d'un labyrinthe","text":""},{"location":"T1_Structures_de_donnees/1.4_Graphes/TP_Labyrinthe/#1-presentation-du-probleme","title":"1. Pr\u00e9sentation du probl\u00e8me","text":"Consid\u00e9rons le labyrinthe suivant :
Affectons une lettre \u00e0 chaque case de ce labyrinthe.
Notre objectif est de trouver comment aller de A en P.
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/TP_Labyrinthe/#2-modelisation-par-un-graphe","title":"2. Mod\u00e9lisation par un graphe","text":"Dessiner le graphe (dont les noeuds seront des lettres) qui mod\u00e9lise ce labyrinthe.
Proposer deux \u00abformes\u00bb possibles pour ce graphe.
Correction "},{"location":"T1_Structures_de_donnees/1.4_Graphes/TP_Labyrinthe/#3-implementation-du-graphe-en-python","title":"3. Impl\u00e9mentation du graphe en Python","text":"En utilisant la classe Graphe
cr\u00e9\u00e9e en cours, impl\u00e9menter le graphe de ce labyrinthe.
class Graphe:\n def __init__(self, liste_sommets):\n self.liste_sommets = liste_sommets\n self.adjacents = {sommet : [] for sommet in liste_sommets}\n\n def ajoute_arete(self, sommetA, sommetB):\n self.adjacents[sommetA].append(sommetB)\n self.adjacents[sommetB].append(sommetA)\n\n def voisins(self, sommet):\n return self.adjacents[sommet]\n\n def sont_voisins(self, sommetA, sommetB):\n return sommetB in self.adjacents[sommetA]\n\ng = Graphe(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P'])\ng.ajoute_arete('A', 'E')\ng.ajoute_arete('E', 'F')\ng.ajoute_arete('F', 'B')\ng.ajoute_arete('B', 'C')\ng.ajoute_arete('C', 'G')\ng.ajoute_arete('G', 'H')\ng.ajoute_arete('H', 'D')\ng.ajoute_arete('G', 'K')\ng.ajoute_arete('F', 'J')\ng.ajoute_arete('J', 'I')\ng.ajoute_arete('I', 'M')\ng.ajoute_arete('M', 'N')\ng.ajoute_arete('N', 'O')\ng.ajoute_arete('O', 'K')\ng.ajoute_arete('K', 'L')\ng.ajoute_arete('L', 'P')\n
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/TP_Labyrinthe/#4-recherche-du-plus-court-chemin","title":"4. Recherche du plus court chemin","text":"En utilisant la fonction recherche_chemin
du cours, \u00e9tablir le plus court chemin pour aller de A vers P dans ce labyrinthe.
def recherche_chemin(g, depart, arrivee):\n'''\n Parcours en largeur du graphe g en partant du sommet depart,\n qui s'arr\u00eate d\u00e8s que le sommet arrivee est atteint.\n Renvoie alors le chemin du depart vers arrivee.\n '''\n traites = []\n decouverts = [depart]\n en_attente = [depart]\n parent = {}\n while en_attente != [] :\n sommet = en_attente.pop(0)\n voisins = g.voisins(sommet)\n for voisin in voisins:\n if voisin not in decouverts:\n decouverts.append(voisin)\n en_attente.append(voisin)\n parent[voisin] = sommet\n if voisin == arrivee:\n return remonte_chemin(depart, arrivee, parent)\n traites.append(sommet)\n return \"non trouv\u00e9\" \n\n\ndef remonte_chemin(depart, arrivee, parent):\n sommet = arrivee\n chemin = arrivee\n while sommet != depart:\n sommet = parent[sommet]\n chemin = sommet + chemin\n return chemin\n
>>> recherche_chemin(g, 'A', 'P')\n'AEFBCGKLP'\n
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/TP_Labyrinthe/#5-conclusion","title":"5. Conclusion","text":"Sur un labyrinthe un peu plus imposant, voici l'illustration de notre m\u00e9thode de r\u00e9solution :
parent
, et ainsi le chemin de sortie du labyrinthe est g\u00e9n\u00e9r\u00e9. Code de cette animation (en Pygame)
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/TP_Labyrinthe/#6-annexe-et-pourquoi-pas-en-dfs","title":"6. Annexe : et pourquoi pas en DFS ?","text":"Les parcours BFS et DFS ont tous deux la propri\u00e9t\u00e9 de parcourir la totalit\u00e9 du graphe (ils sont m\u00eame con\u00e7us pour cela). Cela a permis au parcours BFS de nous fournir une solution au labyrinthe (dont on a d\u00e9montr\u00e9 qu'elle \u00e9tait la plus courte).
Que penser de solution qui sera donn\u00e9e par le DFS ?
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/TP_Labyrinthe/#61-dans-un-labyrinthe-parfait","title":"6.1 Dans un labyrinthe parfait","text":"Voici un code o\u00f9 la solution est d'abord recherch\u00e9e par BFS (cases explor\u00e9es en bleu clair, chemin trouv\u00e9 marqu\u00e9 en bleu), puis en DFS (cases explor\u00e9es en rose, chemin trouv\u00e9 marqu\u00e9 en rouge).
anim_laby_DFSvsBFS_laby_parfait.py
Que remarquez-vous ???
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/TP_Labyrinthe/#62-dans-un-labyrinthe-non-parfait","title":"6.2 Dans un labyrinthe non parfait","text":"Changeons de code pour un labyrinthe d\u00e9g\u00e9n\u00e9r\u00e9 :
anim_laby_DFSvsBFS_laby_degenere.py
Que remarquez-vous ???
ExplicationsNotre labyrinthe con\u00e7u de mani\u00e8re al\u00e9atoire poss\u00e8de une propri\u00e9t\u00e9 remarquable (d\u00fb son algorithme de construction) : chaque case peut \u00eatre reli\u00e9e \u00e0 une autre par un chemin unique. On dit de ces labyrinthes qu'ils sont parfaits.
Donc, dans notre code du 6.1 (labyrinthe parfait), le DFS va lui aussi trouver le chemin le plus court... puisqu'il y en a qu'un seul ! De plus, la m\u00e9thode d'exploration en profondeur va de plus rendre le DFS plus rapide que le BFS, quasiment tout le temps. Ce qui fait que pour un labyrinthe parfait, le DFS est plus int\u00e9ressant que le BFS.
Mais si le labyrinthe n'est plus parfait (code du 6.2), le DFS va trouver une solution qui ne sera pas obligatoirement la meilleure... S'il y a plusieurs solutions possibles, absolument rien ne garantit que la premi\u00e8re solution trouv\u00e9e par le DFS (sur laquelle il s'arr\u00eatera) sera la meilleure !
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/","title":"Graphes","text":"Ce cours est int\u00e9gralement inspir\u00e9 du cours de C\u00e9dric Gouygou , du lyc\u00e9e Marguerite de Valois d'Angoul\u00eame (16)
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#1-notion-de-graphe-et-vocabulaire","title":"1. Notion de graphe et vocabulaire","text":"Le concept de graphe permet de r\u00e9soudre de nombreux probl\u00e8mes en math\u00e9matiques comme en informatique. C'est un outil de repr\u00e9sentation tr\u00e8s courant, et nous l'avons d\u00e9j\u00e0 rencontr\u00e9 \u00e0 plusieurs reprises, en particulier lors de l'\u00e9tude de r\u00e9seaux.
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#11-exemples-de-situations","title":"1.1 Exemples de situations","text":""},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#111-reseau-informatique","title":"1.1.1 R\u00e9seau informatique","text":""},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#112-reseau-de-transport","title":"1.1.2 R\u00e9seau de transport","text":""},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#113-reseau-social","title":"1.1.3 R\u00e9seau social","text":""},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#114-generalisation","title":"1.1.4 G\u00e9n\u00e9ralisation","text":"Une multitude de probl\u00e8mes concrets d'origines tr\u00e8s diverses peuvent donner lieu \u00e0 des mod\u00e9lisations par des graphes : c'est donc une structure essentielle en sciences, qui requiert un formalisme math\u00e9matique particulier que nous allons d\u00e9couvrir.
L'\u00e9tude de la th\u00e9orie des graphes est un champ tr\u00e8s vaste des math\u00e9matiques : nous allons surtout nous int\u00e9resser \u00e0 l'impl\u00e9mentation en Python d'un graphe et \u00e0 diff\u00e9rents probl\u00e8mes algorithmiques qui se posent dans les graphes.
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#12-vocabulaire","title":"1.2 Vocabulaire","text":"En g\u00e9n\u00e9ral, un graphe est un ensemble d'objets, appel\u00e9s sommets ou parfois n\u0153uds (vertex or nodes en anglais) reli\u00e9s par des ar\u00eates ou arcs ((edges en anglais)). Ce graphe peut \u00eatre non-orient\u00e9 ou orient\u00e9 .
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#121-graphe-non-oriente","title":"1.2.1 Graphe non-orient\u00e9","text":"Dans un graphe non-orient\u00e9, les ar\u00eates peuvent \u00eatre emprunt\u00e9es dans les deux sens, et une cha\u00eene est une suite de sommets reli\u00e9s par des ar\u00eates, comme C - B - A - E par exemple. La longueur de cette cha\u00eene est alors 3, soit le nombre d'ar\u00eates.
Les sommets B et E sont adjacents au sommet A, ce sont les voisins de A.
Exemple de graphe non-orient\u00e9 : le graphe des relations d'un individu sur Facebook est non-orient\u00e9, car si on est \u00abami\u00bb avec quelqu'un la r\u00e9ciproque est vraie.
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#122-graphe-oriente","title":"1.2.2 Graphe orient\u00e9","text":"Dans un graphe orient\u00e9, les arcs ne peuvent \u00eatre emprunt\u00e9s que dans le sens de la fl\u00e8che, et un chemin est une suite de sommets reli\u00e9s par des arcs, comme B \u2192 C \u2192 D \u2192 E par exemple.
Les sommets C et D sont adjacents au sommet B (mais pas A !), ce sont les voisins de B.
Exemple de graphe orient\u00e9 : le graphe des relations d'un individu sur Twitter est orient\u00e9, car on peut \u00absuivre\u00bb quelqu'un sans que cela soit r\u00e9ciproque.
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#123-graphe-pondere","title":"1.2.3 Graphe pond\u00e9r\u00e9","text":"Un graphe est pond\u00e9r\u00e9 (ou valu\u00e9) si on attribue \u00e0 chaque ar\u00eate une valeur num\u00e9rique (la plupart du temps positive), qu'on appelle mesure, poids, co\u00fbt ou valuation.
Par exemple:
Un graphe est connexe s'il est d'un seul tenant: c'est-\u00e0-dire si n'importe quelle paire de sommets peut toujours \u00eatre reli\u00e9e par une cha\u00eene. Autrement un graphe est connexe s'il est \u00aben un seul morceau\u00bb.
Par exemple, le graphe pr\u00e9c\u00e9dent est connexe. Mais le suivant ne l'est pas: il n'existe pas de cha\u00eene entre les sommets A et F par exemple.
Il poss\u00e8de cependant deux composantes connexes : le sous-graphe compos\u00e9 des sommets A, B, C, D et E d'une part et le sous-graphe compos\u00e9 des sommets F, G et H.
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#2-modelisations-dun-graphe","title":"2. Mod\u00e9lisations d'un graphe","text":"Pour mod\u00e9liser un graphe, il faut \u00e9tablir par convention une mani\u00e8re de donner les renseignements suivants :
Principe
i
et colonne j
si les sommets de rang i
et de rang j
sont voisins (dits aussi adjacents).Ce tableau s'appelle une matrice d'adjacence (on aurait tr\u00e8s bien pu l'appeler aussi matrice de voisinage).
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#211-graphe-non-oriente","title":"2.1.1 Graphe non orient\u00e9","text":"Dans ce graphe non orient\u00e9, comme B est voisin de C, C est aussi voisin de B, ce qui signifie que l'ar\u00eate qui relie B et C va donner lieu \u00e0 deux \"1\" dans la matrice, situ\u00e9 de part et d'autre de la diagonale descendante (un math\u00e9maticien parlera de matrice sym\u00e9trique).
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#212-graphe-oriente","title":"2.1.2 Graphe orient\u00e9","text":""},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#213-graphe-pondere","title":"2.1.3 Graphe pond\u00e9r\u00e9","text":""},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#214-exercices","title":"2.1.4 Exercices","text":"Exercice 1
Soit un ensemble d'amis connect\u00e9s sur un r\u00e9seau social quelconque. Voici les interactions qu'on a recens\u00e9es\u00a0:
Q1. Repr\u00e9senter le graphe des relations dans ce r\u00e9seau social (on d\u00e9signera chaque individu par l'initiale de son pr\u00e9nom). Il est possible de faire en sorte que les ar\u00eates ne se croisent pas !
Correction Q1Q2. Donner la matrice d'adjacence de ce graphe.
Correction Q2\\(\\pmatrix{ 0 & 1 & 1 & 0 & 1 & 1 & 0 & 0 \\\\ 1 & 0 & 1 & 1 & 0 & 0 & 0 & 1 \\\\ 1 & 1 & 0 & 1 & 1 & 1 & 1 & 0 \\\\ 0 & 1 & 1 & 0 & 1 & 0 & 0 & 0 \\\\ 1 & 0 & 1 & 1 & 0 & 0 & 0 & 0 \\\\ 1 & 0 & 1 & 0 & 0 & 0 & 1 & 0 \\\\ 0 & 0 & 1 & 0 & 0 & 1 & 0 & 0 \\\\ 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\\\ }\\)
Exercice 2
Construire les graphes correspondants aux matrices d'adjacence suivantes:
Q1. \\(M_1 =\\pmatrix{ 0&1&1&1&1\\\\ 1&0&1&0&0\\\\ 1&1&0&1&0\\\\ 1&0&1&0&1\\\\ 1&0&0&1&0\\\\ }\\)
CorrectionQ2. \\(M_2=\\pmatrix{ 0&1&1&0&1\\\\ 0&0&1&0&0\\\\ 0&0&0&1&0\\\\ 1&0&0&0&1\\\\ 0&0&0&0&0\\\\ }\\)
CorrectionQ3. \\(M_3=\\pmatrix{ 0&5&10&50&12\\\\ 5&0&10&0&0\\\\ 10&10&0&8&0\\\\ 50&0&8&0&100\\\\ 12&0&0&100&0\\\\ }\\)
Correction "},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#215-implementation-python-des-matrices-dadjacence","title":"2.1.5 Impl\u00e9mentation Python des matrices d'adjacence","text":"Matrices d'adjacence en Python
Une matrice se repr\u00e9sente naturellement par une liste de listes.
Exemple: La matrice \\(M_1 =\\pmatrix{ 0&1&1&1&1\\\\ 1&0&1&0&0\\\\ 1&1&0&1&0\\\\ 1&0&1&0&1\\\\ 1&0&0&1&0\\\\ }\\), associ\u00e9e au graphe
sera repr\u00e9sent\u00e9e par la variable G
suivante :
G = [[0, 1, 1, 1, 1],\n [1, 0, 1, 0, 0],\n [1, 1, 0, 1, 0],\n [1, 0, 1, 0, 1],\n [1, 0, 0, 1, 0]]\n
Complexit\u00e9 en m\u00e9moire et temps d'acc\u00e8s :
Pour un graphe \u00e0 \\(n\\) sommets, la complexit\u00e9 en m\u00e9moire (appel\u00e9e aussi complexit\u00e9 spatiale) de la repr\u00e9sentation matricielle est en \\(O(n^2)\\).
Tester si un sommet est isol\u00e9 (ou conna\u00eetre ses voisins) est en \\(O(n)\\) puisqu'il faut parcourir une ligne, mais tester si deux sommets sont adjacents (voisins) est en \\(O(1)\\), c'est un simple acc\u00e8s au tableau.
La mod\u00e9lisation d'un graphe par sa matrice d'adjacence est loin d'\u00eatre la seule mani\u00e8re de repr\u00e9senter un graphe : nous allons voir une autre mod\u00e9lisation, par liste d'adjacence.
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#22-representation-par-listes-dadjacence","title":"2.2 Repr\u00e9sentation par listes d'adjacence","text":"Principe
On associe \u00e0 chaque sommet sa liste des voisins (c'est-\u00e0-dire les sommets adjacents). On utilise pour cela un dictionnaire dont les cl\u00e9s sont les sommets et les valeurs les listes des voisins.
Dans le cas d'un graphe orient\u00e9 on associe \u00e0 chaque sommet la liste des successeurs (ou bien des pr\u00e9d\u00e9cesseurs, au choix).
Par exemple, le graphe sera repr\u00e9sent\u00e9 par le dictionnaire :
G = {'A': ['B', 'C', 'D', 'E'],\n 'B': ['A', 'C'],\n 'C': ['A', 'B', 'D'],\n 'D': ['A', 'C', 'E'],\n 'E': ['A', 'D']\n }\n
Complexit\u00e9 en m\u00e9moire et temps d'acc\u00e8s :
Pour un graphe \u00e0 \\(n\\) sommets et \\(m\\) ar\u00eates, la complexit\u00e9 spatiale de la repr\u00e9sentation en liste d'adjacence est en \\(O(n+m)\\). C'est beaucoup mieux qu'une matrice d'adjacence lorsque le graphe comporte peu d'ar\u00eates (i.e. beaucoup de 0 dans la matrice, non stock\u00e9s avec des listes).
Tester si un sommet est isol\u00e9 (ou conna\u00eetre ses voisins) est en \\(O(1)\\) puisqu'on y acc\u00e8de imm\u00e9diatement, mais tester si deux sommets sont adjacents (voisins) est en \\(O(n)\\) car il faut parcourir la liste.
Exercice 3
Construire les graphes correspondants aux listes d'adjacence suivantes.
Q1.
G1 = {\n'A': ['B', 'C'],\n'B': ['A', 'C', 'E', 'F'],\n'C': ['A', 'B', 'D'],\n'D': ['C', 'E'],\n'E': ['B', 'D', 'F'],\n'F': ['B', 'E']\n }\n
Correction Q1 Q2.
G2 = {\n'A': ['B'],\n'B': ['C', 'E'],\n'C': ['B', 'D'],\n'D': [],\n'E': ['A']\n }\n
Correction Q2 "},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#3-creation-dune-classe-graphe","title":"3. Cr\u00e9ation d'une classe Graphe
","text":"Dans cette partie, nous ne traiterons que des graphes non-orient\u00e9s.
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#31-interface-souhaitee","title":"3.1 Interface souhait\u00e9e","text":"Nous voulons que le graphe puisse \u00eatre cr\u00e9\u00e9 gr\u00e2ce aux instructions suivantes :
g = Graphe(['A', 'B', 'C', 'D', 'E'])\ng.ajoute_arete('A', 'B')\ng.ajoute_arete('A', 'C')\ng.ajoute_arete('A', 'D')\ng.ajoute_arete('A', 'E')\ng.ajoute_arete('B', 'C')\ng.ajoute_arete('C', 'D')\ng.ajoute_arete('D', 'E')\n
Nous souhaitons aussi pouvoir tester si deux sommets sont voisins avec la m\u00e9thode sont_voisins
:
>>> g.sont_voisins('E', 'A')\nTrue\n>>> g.sont_voisins('E', 'B')\nFalse\n
Enfin, nous voulons pouvoir obtenir facilement la liste de tous les voisins d'un sommet avec la m\u00e9thode voisins
:
>>> g.voisins('C')\n['A', 'B', 'D']\n
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#32-conseils-dimplementation","title":"3.2 Conseils d'impl\u00e9mentation","text":"L'objet de type Graphe
aura comme attributs :
liste_sommets
(donn\u00e9e en param\u00e8tre dans la liste liste_sommets
) adjacents
, o\u00f9 chaque sommet se verra attribuer une liste vide []
.Impl\u00e9mentation d'une classe Graphe
class Graphe:\n def __init__(self, liste_sommets):\n self.liste_sommets = liste_sommets\n self.adjacents = {sommet : [] for sommet in liste_sommets}\n\n def ajoute_arete(self, sommetA, sommetB):\n self.adjacents[sommetA].append(sommetB)\n self.adjacents[sommetB].append(sommetA)\n\n def voisins(self, sommet):\n return self.adjacents[sommet]\n\n def sont_voisins(self, sommetA, sommetB):\n return sommetB in self.adjacents[sommetA]\n
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#4-parcours-de-graphes","title":"4. Parcours de graphes","text":"Algorithme de parcours
Un parcours de graphe est un algorithme consistant \u00e0 explorer tous les sommets d'un graphe de proche en proche \u00e0 partir d'un sommet initial. Ces parcours sont notamment utilis\u00e9s pour rechercher un plus court chemin (et donc dans les GPS) ou pour trouver la sortie d'un labyrinthe...
Parcourir simplement le dictionnaire ou la matrice d\u2019un graphe n\u2019est pas consid\u00e9r\u00e9 comme un parcours de graphe.
Tous les parcours suivent plus ou moins le m\u00eame algorithme de base :
On visite un sommet A
. On cr\u00e9e une structure S
qui contiendra au d\u00e9part l\u2019ensemble des voisins de A
.
Tant que S
n\u2019est pas vide :
s
de S
s
S
tous les voisins de s
pas encore visit\u00e9sSommets visit\u00e9s
Contrairement \u00e0 un parcours d'arbre, o\u00f9 les fils d'un n\u0153ud ne peuvent pas avoir \u00e9t\u00e9 visit\u00e9s avant le n\u0153ud, un voisin d'un sommet peut avoir d\u00e9j\u00e0 \u00e9t\u00e9 visit\u00e9 en tant que voisin d'un sommet pr\u00e9c\u00e9dent...
Il est donc n\u00e9cessaire de m\u00e9moriser les sommets d\u00e9ja visit\u00e9s ou d\u00e9couverts (on dira qu'un sommet est d\u00e9couvert lorsqu'on l'ajoute \u00e0 S
).
Le choix de la structure de l'ensemble S
est pr\u00e9pond\u00e9rant:
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#41-le-parcours-en-largeur-bfs-breadth-first-search","title":"4.1 Le parcours en largeur (BFS, Breadth First Search)","text":""},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#411-principe","title":"4.1.1 Principe","text":"
Exemple de parcours en largeur, avec B comme sommet de d\u00e9part:
Codes couleur :
On utilise :
traites
qui recueille les sommets visit\u00e9s (c'est-\u00e0-dire qu'on a fini de traiter, apr\u00e8s avoir ajout\u00e9 ses voisins dans la file d'attente) et qui sera renvoy\u00e9e \u00e0 la fin de l'algorithme;decouverts
qui contient les sommets d\u00e9couverts au fur et \u00e0 mesure du parcours;en_attente
qui contient les sommets d\u00e9couverts mais non encore visit\u00e9s. On utilisera au choix une classe File
\u00e9crite plus t\u00f4t dans l'ann\u00e9e ou tout simplement une list
en utilisant pop(0)
(pour d\u00e9filer) et append()
(pour enfiler).En d\u00e9but d'algorithme, seul le sommet de d\u00e9part depart
donn\u00e9 en param\u00e8tre est d\u00e9couvert. La fonction BFS
renvoie la liste des sommets dans l'ordre de visite lors du parcours en largeur.
Parcours en largeur - BFS
def BFS(g, depart):\n'''\n Effectue un parcours en largeur du graphe g en partant du sommet depart,\n et renvoie la liste des sommets visit\u00e9s dans l'ordre du parcours.\n '''\n traites = []\n decouverts = [depart]\n en_attente = [depart]\n while en_attente != [] :\n sommet = en_attente.pop(0)\n voisins = g.voisins(sommet)\n for voisin in voisins:\n if voisin not in decouverts:\n decouverts.append(voisin)\n en_attente.append(voisin)\n traites.append(sommet)\n return traites\n
Int\u00e9r\u00eat de la liste decouverts
La liste decouverts
contient tous les sommets qui ont \u00e9t\u00e9 :
traites
)en_attente
)Le test de la ligne 13 if voisin not in decouverts:
permet donc de ne pas mettre en file d'attente un voisin qui est (ou a \u00e9t\u00e9) d\u00e9j\u00e0 en file d'attente.
Que contient la file en_attente
?
\u00c0 chaque instant, la file en_attente
contient des sommets \u00e0 la distance k+1
et \u00e0 la distance k
du point de d\u00e9part :
Exercice 4
Gr\u00e2ce \u00e0 la classe Graphe
du 3.3, ce graphe s'impl\u00e9mente par :
g = Graphe(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'])\ng.ajoute_arete('A', 'B')\ng.ajoute_arete('A', 'C')\ng.ajoute_arete('B', 'D')\ng.ajoute_arete('D', 'C')\ng.ajoute_arete('B', 'E')\ng.ajoute_arete('D', 'E')\ng.ajoute_arete('E', 'F')\ng.ajoute_arete('E', 'G')\ng.ajoute_arete('F', 'G')\ng.ajoute_arete('G', 'H')\n
Q1. Donner le parcours en largeur de g
gr\u00e2ce \u00e0 l'algorithme BFS, si le sommet de d\u00e9part est B. Cela correspond au parcours pr\u00e9sent\u00e9 par le gif de d\u00e9but de paragraphe.
>>> BFS(g, 'B')\n['B', 'A', 'D', 'E', 'C', 'F', 'G', 'H']\n
Q2. Deviner le parcours en largeur de d\u00e9part D, puis de d\u00e9part G. V\u00e9rifier gr\u00e2ce \u00e0 votre algorithme.
Correction Q2>>> BFS(g, 'D')\n['D', 'B', 'C', 'E', 'A', 'F', 'G', 'H']\n>>> BFS(g, 'G')\n['G', 'E', 'F', 'H', 'B', 'D', 'A', 'C']\n
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#413-application-du-bfs-recherche-du-plus-court-chemin","title":"4.1.3 Application du BFS : recherche du plus court chemin","text":"L'algorithme BFS d\u00e9couvre les sommets \u00abpar cercles concentriques\u00bb autour du point de d\u00e9part (ainsi que le montre la structure de la file d'attente). On d\u00e9couvre d'abord tous les sommets \u00e0 la distance 1 du point de d\u00e9part, puis \u00e0 la distance 2, puis 3, etc.
Un sommet situ\u00e9 \u00e0 la distance 5 sera d\u00e9couvert en tant que voisin d'un sommet \u00e0 la distance 4, qui lui-m\u00eame aura \u00e9t\u00e9 d\u00e9couvert gr\u00e2ce \u00e0 un sommet \u00e0 la distance 3, qui lui-m\u00eame...
On comprend donc que si on arrive \u00e0 se souvenir du sommet \u00abparent\u00bb de chaque sommet (celui qui lui a permis d'\u00eatre d\u00e9couvert), on pourra alors reconstituer un chemin permettant de remonter au point de d\u00e9part.
Nous allons pour cela nous servir d'une structure de dictionnaire pour associer \u00e0 chaque sommet son sommet-parent.
Il faudra ensuite une fonction pour recr\u00e9er le chemin.
Pourquoi le plus court chemin ?
Si le graphe est connexe, tout parcours BFS au d\u00e9part de A va parcourir l'int\u00e9gralit\u00e9 du graphe, et donc passera par B \u00e0 un moment. Un chemin sera donc forc\u00e9ment trouv\u00e9 entre A et B.
La d\u00e9couverte des sommets par cercles concentriques entre A et B nous assure qu'on ne peut pas rater le point B : s'il est \u00e0 la distance k
de A, il sera forc\u00e9ment visit\u00e9 puisque tous les sommets \u00e0 la distance k
vont passer par la liste d'attente, apr\u00e8s les sommets de distance k-1
et avant les sommets de distance k+1
.
Lorsqu'on remontera de B vers A en passant par les sommets parents successifs, il ne peut y avoir qu'un seul sommet par \u00abcouche\u00bb : le chemin sera donc exactement de longueur k
, il sera donc minimal.
Recherche du plus court chemin
def recherche_chemin(g, depart, arrivee):\n'''\n Parcours en largeur du graphe g en partant du sommet depart,\n qui s'arr\u00eate d\u00e8s que le sommet arrivee est atteint.\n Renvoie alors le chemin du depart vers arrivee.\n '''\n traites = []\n decouverts = [depart]\n en_attente = [depart]\n parent = {}\n while en_attente != [] :\n sommet = en_attente.pop(0)\n voisins = g.voisins(sommet)\n for voisin in voisins:\n if voisin not in decouverts:\n decouverts.append(voisin)\n en_attente.append(voisin)\n parent[voisin] = sommet\n if voisin == arrivee:\n return remonte_chemin(depart, arrivee, parent)\n traites.append(sommet)\n return \"non trouv\u00e9\" \n\n\ndef remonte_chemin(depart, arrivee, parent):\n sommet = arrivee\n chemin = arrivee\n while sommet != depart:\n sommet = parent[sommet]\n chemin = sommet + chemin\n return chemin\n
Exercice 5
Tester le code pr\u00e9c\u00e9dent pour trouver le plus court chemin entre A et G, entre H et C, entre B et G...
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#42-le-parcours-en-profondeur-dfs-depth-first-search","title":"4.2 Le parcours en profondeur (DFS, Depth First Search)","text":""},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#421-parcours-dfs-recursif","title":"4.2.1 Parcours DFS r\u00e9cursif","text":"Le parcours en profondeur est un parcours o\u00f9 on va aller \u00able plus loin possible\u00bb sans se pr\u00e9occuper des autres voisins non visit\u00e9s : on va visiter le premier de ses voisins non trait\u00e9s, qui va faire de m\u00eame, etc. Lorsqu'il n'y a plus de voisin, on revient en arri\u00e8re pour aller voir le dernier voisin non visit\u00e9.
Dans un labyrinthe, ce parcours s'explique tr\u00e8s bien : on prend tous les chemins sur la droite jusqu'\u00e0 rencontrer un mur, auquel cas on revient au dernier embranchement et on prend un autre chemin, puis on repart \u00e0 droite, etc.
C'est un parcours qui s'\u00e9crit naturellement de mani\u00e8re r\u00e9cursive :
Parcours en profondeur - DFS
def DFSrec(g, traites, actuel):\n traites.append(actuel)\n for voisin in g.voisins(actuel):\n if voisin not in traites:\n DFSrec(g, traites, voisin)\n return traites\n
Exercice 6
Q1. Donner (de t\u00eate) le parcours DFS de ce graphe en partant de A. Rappel : les voisins sont donn\u00e9s par ordre alphab\u00e9tique. Le premier voisin de A est donc B.
Q2. V\u00e9rifier avec le code pr\u00e9c\u00e9dent.
Correction Q2class Graphe:\n def __init__(self, liste_sommets):\n self.liste_sommets = liste_sommets\n self.adjacents = {sommet : [] for sommet in liste_sommets}\n\n def ajoute_arete(self, sommetA, sommetB):\n self.adjacents[sommetA].append(sommetB)\n self.adjacents[sommetB].append(sommetA)\n\n def voisins(self, sommet):\n return self.adjacents[sommet]\n\n def sont_voisins(self, sommetA, sommetB):\n return sommetB in self.adjacents[sommetA]\n\n\ng = Graphe(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'])\ng.ajoute_arete('A', 'B')\ng.ajoute_arete('A', 'C')\ng.ajoute_arete('B', 'D')\ng.ajoute_arete('D', 'C')\ng.ajoute_arete('B', 'E')\ng.ajoute_arete('D', 'E')\ng.ajoute_arete('E', 'F')\ng.ajoute_arete('E', 'G')\ng.ajoute_arete('F', 'G')\ng.ajoute_arete('G', 'H')\n\n\ndef DFSrec(g, traites, actuel):\n traites.append(actuel)\n for voisin in g.voisins(actuel):\n if voisin not in traites:\n DFSrec(g, traites, voisin)\n return traites\n
>>> DFSrec(g, [], 'A')\n['A', 'B', 'D', 'C', 'E', 'F', 'G', 'H']\n
Q3. Reprendre les questions pr\u00e9c\u00e9dentes en changeant le sommet de d\u00e9part.
"},{"location":"T1_Structures_de_donnees/1.4_Graphes/cours/#422-parcours-dfs-iteratif","title":"4.2.2 Parcours DFS it\u00e9ratif","text":"Il \u00absuffit\u00bb de remplacer la file du parcours BFS par une pile. Ainsi, on partira visiter le voisin tout juste ajout\u00e9 \u00e0 la file d'attente (qui porte maintenant mal son nom, puisque c'est devenu une pile).
Parcours en profondeur it\u00e9ratif - DFS
def DFS_iteratif(graphe, start):\n traites = []\n en_attente = [start]\n while en_attente != []:\n actuel = en_attente.pop()\n if actuel not in traites:\n voisins = g.voisins(actuel)[::-1]\n for voisin in voisins:\n if voisin not in traites:\n en_attente.append(voisin)\n traites.append(actuel)\n return traites\n
Remarques :
\u00c0 la ligne 7, on inverse l'ordre des voisins pour que ce code renvoie le m\u00eame parcours quele parcours r\u00e9cursif (sinon c'est le dernier voisin ajout\u00e9 qui sera d\u00e9pil\u00e9). Cela n'est pas obligatoire : il n'y a pas \u00abun seul\u00bb parcours DFS (tout comme il n'y a pas qu'un seul BFS). Ce qui les caract\u00e9rise est la m\u00e9thode de d\u00e9couverte, plus que l'impl\u00e9mentation proprement dite.
Contrairement au BFS, il est possible d'empiler un sommet d\u00e9j\u00e0 d\u00e9couvert (on v\u00e9rifie juste qu'il n'ait pas d\u00e9j\u00e0 \u00e9t\u00e9 trait\u00e9). Vous pouvez vous en apercevoir en \u00e9crivant l'\u00e9tat de la pile lors du parcours DFS it\u00e9ratif du graphe de l'exercice 6.
import pygame, sys\nimport time\nfrom pygame.locals import *\n\nLARGEUR = 640\nHAUTEUR = 480\nRAYON = 20\n\npygame.display.init()\nfenetre = pygame.display.set_mode((LARGEUR, HAUTEUR))\nfenetre.fill([0,0,0])\n\nx = 300\ny = 200\ndx = 4\ndy = -3\ncouleur = (45, 170, 250)\n\nwhile True:\n fenetre.fill([0, 0, 0])\n pygame.draw.circle(fenetre, couleur, (x, y), RAYON)\n\n x += dx\n y += dy\n\n pygame.display.update()\n\n # routine pour pouvoir fermer \u00abproprement\u00bb la fen\u00eatre Pygame\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n\n time.sleep(0.1)\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/TP/#11-rajout-dun-rebond-sur-les-parois","title":"1.1 Rajout d'un rebond sur les parois","text":"Modifiez le code pr\u00e9c\u00e9dent afin que la balle rebondisse sur chaque paroi (il suffit de modifier intelligemment les variables de vitesse dx
et dy
).
import pygame, sys\nimport time\nfrom pygame.locals import *\n\nLARGEUR = 640\nHAUTEUR = 480\nRAYON = 20\n\npygame.display.init()\nfenetre = pygame.display.set_mode((LARGEUR, HAUTEUR))\nfenetre.fill([0, 0, 0])\n\nx = 300\ny = 200\ndx = 4\ndy = -3\ncouleur = (45, 170, 250)\n\nwhile True:\n fenetre.fill([0, 0, 0])\n pygame.draw.circle(fenetre, couleur, (x, y), RAYON)\n\n x += dx\n y += dy\n\n if (y <= RAYON) or (y >= HAUTEUR - RAYON):\n dy = -dy\n if (x <= RAYON) or (x >= LARGEUR - RAYON):\n dx = -dx\n\n pygame.display.update()\n\n # routine pour pouvoir fermer \u00abproprement\u00bb la fen\u00eatre Pygame\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n\n time.sleep(0.02)\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/TP/#12-rajout-dune-deuxieme-balle","title":"1.2 Rajout d'une deuxi\u00e8me balle","text":"Attention au nommage des variables...
Correctionimport pygame, sys\nimport time\nfrom pygame.locals import *\n\nLARGEUR = 640\nHAUTEUR = 480\nRAYON = 20\n\npygame.display.init()\nfenetre = pygame.display.set_mode((LARGEUR, HAUTEUR))\nfenetre.fill([0, 0, 0])\n\n\ndxA = 7\ndyA = 4\ndxB = -5\ndyB = 3\n\n\nxA = LARGEUR // 3\nyA = HAUTEUR // 2\nxB = LARGEUR // 2\nyB = HAUTEUR // 2\n\n\ncouleurA = (45, 170, 250)\ncouleurB = (155, 17, 250)\n\nwhile True:\n fenetre.fill([0, 0, 0])\n pygame.draw.circle(fenetre, couleurA, (xA, yA), RAYON)\n pygame.draw.circle(fenetre, couleurB, (xB, yB), RAYON)\n\n xA += dxA\n yA += dyA\n\n xB += dxB\n yB += dyB\n\n # rebond en haut ou en bas\n if (yA < RAYON) or (yA > HAUTEUR - RAYON):\n dyA = -dyA\n\n # rebond \u00e0 gauche ou \u00e0 droite\n if (xA < RAYON) or (xA > LARGEUR - RAYON):\n dxA = -dxA\n\n # rebond en haut ou en bas\n if (yB < RAYON) or (yB > HAUTEUR - RAYON):\n dyB = -dyB\n\n # rebond \u00e0 gauche ou \u00e0 droite\n if (xB < RAYON) or (xB > LARGEUR - RAYON):\n dxB = -dxB\n\n pygame.display.update()\n\n # routine pour pouvoir fermer \u00abproprement\u00bb la fen\u00eatre Pygame\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n\n time.sleep(0.03)\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/TP/#13-gestion-de-la-collision-entre-les-deux-balles","title":"1.3 Gestion de la collision entre les deux balles","text":"Q1. \u00c0 l'aide d'un sch\u00e9ma (papier-crayon !), mettez en \u00e9vidence le test devant \u00eatre r\u00e9alis\u00e9 pour d\u00e9tecter une collision.
indiceQ2. Impl\u00e9mentez ce test (en cr\u00e9ant pour cela une fonction distance
) et affichez \"collision\" en console lorsque les deux balles se touchent.
import pygame, sys\nimport time\nfrom pygame.locals import *\n\nLARGEUR = 640\nHAUTEUR = 480\nRAYON = 20\n\npygame.display.init()\nfenetre = pygame.display.set_mode((LARGEUR, HAUTEUR))\nfenetre.fill([0, 0, 0])\n\n\ndxA = 7\ndyA = 4\ndxB = -5\ndyB = 3\n\n\nxA = LARGEUR // 3\nyA = HAUTEUR // 2\nxB = LARGEUR // 2\nyB = HAUTEUR // 2\n\n\ncouleurA = (45, 170, 250)\ncouleurB = (155, 17, 250)\n\n\ndef distanceAB(xA, yA, xB, yB):\n return ((xA-xB)**2 + (yA-yB)**2)**0.5\n\n\nwhile True:\n fenetre.fill([0, 0, 0])\n pygame.draw.circle(fenetre, couleurA, (xA, yA), RAYON)\n pygame.draw.circle(fenetre, couleurB, (xB, yB), RAYON)\n\n xA += dxA\n yA += dyA\n\n xB += dxB\n yB += dyB\n\n # rebond en haut ou en bas\n if (yA < RAYON) or (yA > HAUTEUR - RAYON):\n dyA = -dyA\n\n # rebond \u00e0 gauche ou \u00e0 droite\n if (xA < RAYON) or (xA > LARGEUR - RAYON):\n dxA = -dxA\n\n # rebond en haut ou en bas\n if (yB < RAYON) or (yB > HAUTEUR - RAYON):\n dyB = -dyB\n\n # rebond \u00e0 gauche ou \u00e0 droite\n if (xB < RAYON) or (xB > LARGEUR - RAYON):\n dxB = -dxB\n\n if distanceAB(xA, yA, xB, yB) < 2 * RAYON:\n print(\"collision\")\n\n pygame.display.update()\n\n # routine pour pouvoir fermer \u00abproprement\u00bb la fen\u00eatre Pygame\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n\n time.sleep(0.03)\n
Q3. Pour donner l'illusion physique du rebond, \u00e9changez les valeurs respectives de dx
et dy
pour les deux balles.
import pygame, sys\nimport time\nfrom pygame.locals import *\n\nLARGEUR = 640\nHAUTEUR = 480\nRAYON = 20\n\npygame.display.init()\nfenetre = pygame.display.set_mode((LARGEUR, HAUTEUR))\nfenetre.fill([0, 0, 0])\n\n\ndxA = 7\ndyA = 4\ndxB = -5\ndyB = 3\n\n\nxA = LARGEUR // 3\nyA = HAUTEUR // 2\nxB = LARGEUR // 2\nyB = HAUTEUR // 2\n\n\ncouleurA = (45, 170, 250)\ncouleurB = (155, 17, 250)\n\n\ndef distanceAB(xA, yA, xB, yB):\n return ((xA-xB)**2 + (yA-yB)**2)**0.5\n\n\nwhile True:\n fenetre.fill([0, 0, 0])\n pygame.draw.circle(fenetre, couleurA, (xA, yA), RAYON)\n pygame.draw.circle(fenetre, couleurB, (xB, yB), RAYON)\n\n xA += dxA\n yA += dyA\n\n xB += dxB\n yB += dyB\n\n # rebond en haut ou en bas\n if (yA < RAYON) or (yA > HAUTEUR - RAYON):\n dyA = -dyA\n\n # rebond \u00e0 gauche ou \u00e0 droite\n if (xA < RAYON) or (xA > LARGEUR - RAYON):\n dxA = -dxA\n\n # rebond en haut ou en bas\n if (yB < RAYON) or (yB > HAUTEUR - RAYON):\n dyB = -dyB\n\n # rebond \u00e0 gauche ou \u00e0 droite\n if (xB < RAYON) or (xB > LARGEUR - RAYON):\n dxB = -dxB\n\n if distanceAB(xA, yA, xB, yB) < 2 * RAYON:\n dxA, dxB = dxB, dxA\n dyA, dyB = dyB, dyA\n\n pygame.display.update()\n\n # routine pour pouvoir fermer \u00abproprement\u00bb la fen\u00eatre Pygame\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n\n time.sleep(0.03)\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/TP/#14-rajout-dune-troisieme-balle-et-gestion-du-rebond-avec-les-deux-autres","title":"1.4 Rajout d'une troisi\u00e8me balle et gestion du rebond avec les deux autres.","text":"... vraiment ? Peut-on continuer comme pr\u00e9c\u00e9demment ?
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/TP/#2-la-poo-a-la-rescousse-creation-dune-classe-balle","title":"2. La POO \u00e0 la rescousse : cr\u00e9ation d'une classe Balle","text":""},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/TP/#21-la-classe-balle","title":"2.1 la classe Balle","text":"L'objectif est que la m\u00e9thode constructeur dote chaque nouvelle balle de valeurs al\u00e9atoires : abscisse, ordonn\u00e9e, vitesse, couleur...
Pour l'al\u00e9atoire, on pourra utiliser randint(a, b)
qui renvoie un nombre pseudo-al\u00e9atoire entre a
et b
. Il faut pour cela importer la fonction, par from random import randint
Vous pouvez aussi doter votre classe Balle
d'une m\u00e9thode dessine
(qui affiche la balle), ainsi qu'une m\u00e9thode bouge
qui la fait bouger.
Cr\u00e9ez cette classe et instanciez une balle.
Correctionimport pygame, sys\nimport time\nfrom pygame.locals import *\nfrom random import randint\n\n# randint(0,10) -> nb al\u00e9atoire entre 0 et 10\n\nLARGEUR = 640\nHAUTEUR = 480\nRAYON = 20\n\npygame.display.init()\nfenetre = pygame.display.set_mode((LARGEUR, HAUTEUR))\nfenetre.fill([0, 0, 0])\n\n\nclass Balle:\n def __init__(self):\n self.x = randint(0, LARGEUR)\n self.y = randint(0, HAUTEUR)\n self.dx = randint(2, 5)\n self.dy = randint(2, 5)\n self.couleur = (randint(0, 255), randint(0, 255), randint(0, 255))\n self.taille = RAYON\n\n def dessine(self):\n pygame.draw.circle(fenetre, self.couleur, (self.x, self.y), self.taille)\n\n def bouge(self):\n self.x += self.dx\n self.y += self.dy\n\n if self.y < self.taille or self.y > HAUTEUR - self.taille:\n self.dy = -self.dy\n if self.x < self.taille or self.x > LARGEUR - self.taille:\n self.dx = -self.dx\n\n\nma_balle = Balle()\n\nwhile True:\n fenetre.fill([0, 0, 0])\n\n ma_balle.dessine()\n ma_balle.bouge()\n\n pygame.display.update()\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n\n time.sleep(0.05)\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/TP/#22-plusieurs-balles","title":"2.2 Plusieurs balles","text":"L'id\u00e9e est de stocker dans une liste sac_a_balles
un nombre d\u00e9termin\u00e9 de balles...
import pygame, sys\nimport time\nfrom pygame.locals import *\nfrom random import randint\n\n# randint(0,10) -> nb al\u00e9atoire entre 0 et 10\n\nLARGEUR = 640\nHAUTEUR = 480\nRAYON = 20\nNB_BALLES = 10\n\npygame.display.init()\nfenetre = pygame.display.set_mode((LARGEUR, HAUTEUR))\nfenetre.fill([0, 0, 0])\n\n\nclass Balle:\n def __init__(self):\n self.x = randint(0, LARGEUR)\n self.y = randint(0, HAUTEUR)\n self.dx = randint(2, 5)\n self.dy = randint(2, 5)\n self.couleur = (randint(0, 255), randint(0, 255), randint(0, 255))\n self.taille = RAYON\n\n def dessine(self):\n pygame.draw.circle(fenetre, self.couleur, (self.x, self.y), self.taille)\n\n def bouge(self):\n self.x += self.dx\n self.y += self.dy\n\n if self.y < self.taille or self.y > HAUTEUR - self.taille:\n self.dy = -self.dy\n if self.x < self.taille or self.x > LARGEUR - self.taille:\n self.dx = -self.dx\n\n\nmon_sac_a_balles = [Balle() for _ in range(NB_BALLES)]\n\nwhile True:\n fenetre.fill([0, 0, 0])\n\n for balle in mon_sac_a_balles:\n balle.dessine()\n balle.bouge()\n\n pygame.display.update()\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n\n time.sleep(0.05)\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/TP/#23-collision-de-toutes-les-balles","title":"2.3 Collision de toutes les balles","text":"Il \u00absuffit\u00bb , dans la m\u00e9thode constructeur, de tester la collision de la balle self
avec chacune des balles de notre sac_a_balles
.
import pygame, sys\nimport time\nfrom pygame.locals import *\nfrom random import randint\n\n# randint(0,10) -> nb al\u00e9atoire entre 0 et 10\n\nLARGEUR = 640\nHAUTEUR = 480\nRAYON = 20\nNB_BALLES = 10\n\npygame.display.init()\nfenetre = pygame.display.set_mode((LARGEUR, HAUTEUR))\nfenetre.fill([0, 0, 0])\n\n\nclass Balle:\n def __init__(self):\n self.x = randint(0, LARGEUR)\n self.y = randint(0, HAUTEUR)\n self.dx = randint(2, 5)\n self.dy = randint(2, 5)\n self.couleur = (randint(0, 255), randint(0, 255), randint(0, 255))\n self.taille = RAYON\n\n def dessine(self):\n pygame.draw.circle(fenetre, self.couleur, (self.x, self.y), self.taille)\n\n def bouge(self):\n self.x += self.dx\n self.y += self.dy\n\n if self.y < self.taille or self.y > HAUTEUR - self.taille:\n self.dy = -self.dy\n if self.x < self.taille or self.x > LARGEUR - self.taille:\n self.dx = -self.dx\n\n for balle in mon_sac_a_balles:\n if (\n (self.x - balle.x) ** 2 + (self.y - balle.y) ** 2\n ) ** 0.5 < self.taille + balle.taille:\n self.dx, balle.dx = balle.dx, self.dx\n self.dy, balle.dy = balle.dy, self.dy\n\n\nmon_sac_a_balles = []\nfor _ in range(NB_BALLES):\n new_ball = Balle()\n mon_sac_a_balles.append(new_ball)\n\n# ces 4 derni\u00e8re lignes peuvent s'\u00e9crire par une seule ligne en compr\u00e9hension :\n# mon_sac_a_balles = [Balle() for _ in range(NB_BALLES)]\n\nwhile True:\n fenetre.fill([0, 0, 0])\n\n for balle in mon_sac_a_balles:\n balle.dessine()\n balle.bouge()\n\n pygame.display.update()\n for event in pygame.event.get():\n if event.type == pygame.QUIT:\n pygame.display.quit()\n sys.exit()\n\n time.sleep(0.05)\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/","title":"Programmation orient\u00e9e objet","text":"abr\u00e9g\u00e9e par POO en fran\u00e7ais, OOP en anglais (ne pas confondre)
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#0-introduction","title":"0. Introduction","text":"La POO est un paradigme de programmation, au m\u00eame titre que la programmation imp\u00e9rative (que nous pratiquons d\u00e9j\u00e0) ou la programmation fonctionnelle (qui sera \u00e9tudi\u00e9e cette ann\u00e9e en Terminale), ou encore d'autres paradigmes (la liste est longue). Un paradigme de programmation pourrait se d\u00e9finir comme une philosophie dans la mani\u00e8re de programmer : c'est un parti-pris revendiqu\u00e9 dans la mani\u00e8re d'aborder le probl\u00e8me \u00e0 r\u00e9soudre. Une fois cette d\u00e9cision prise, des outils sp\u00e9cifiques au paradigme choisi sont utilis\u00e9s.
M\u00e9taphore
Imaginons 3 menuisiers qui ont pour mission de fabriquer chacun un meuble.
Pour la r\u00e9alisation de sa mission, chaque menuisier utilise un paradigme diff\u00e9rent. Qui utilise la meilleure m\u00e9thode ? Cette question n'a pas vraiment de r\u00e9ponse : certaines m\u00e9thodes sont plus rapides que d'autres, d'autres plus robustes, d'autres plus esth\u00e9tiques... Et pourquoi ne pas m\u00e9langer les paradigmes ? Rien n'interdit d'utiliser des pointes ET des vis dans la fabrication d'un meuble.
La Programmation Orient\u00e9e Objet sera (surtout \u00e0 notre niveau) m\u00e9lang\u00e9e avec de la programmation imp\u00e9rative, de la programmation fonctionnelle... d'ailleurs vous avez d\u00e9j\u00e0 manipul\u00e9 des objets sans le savoir :
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#1-des-objets-deja-autour-de-nous","title":"1. Des objets d\u00e9j\u00e0 autour de nous","text":">>> m = [4,5,2]\n>>> type(m)\nlist\n
m
est une liste, ou plus pr\u00e9cis\u00e9ment un objet de type list
. Et en tant qu'objet de type list
, il est possible de lui appliquer certaines fonctions pr\u00e9d\u00e9finies (qu'on appelera m\u00e9thodes) :
>>> m.reverse()\n
La syntaxe utilis\u00e9e (le . apr\u00e8s le nom de l'objet) est sp\u00e9cifique \u00e0 la POO. Chaque fois que vous voyez cela, c'est que vous \u00eates en train de manipuler des objets. Mais qu'a donc fait cette m\u00e9thode reverse()
?
>>> m\n[2, 5, 4]\n
Nous ne sommes pas surpris par ce r\u00e9sultat car la personne qui a programm\u00e9 la m\u00e9thode reverse()
lui a donn\u00e9 un nom explicite. Comment a-t-elle programm\u00e9 cette inversion des valeurs de la liste ? Nous n'en savons rien et cela ne nous int\u00e9resse pas. Nous sommes juste utilisateurs de cette m\u00e9thode. L'objet de type list
nous a \u00e9t\u00e9 livr\u00e9 avec sa m\u00e9thode reverse()
(et bien d'autres choses) et nous n'avons pas \u00e0 d\u00e9monter la bo\u00eete pour en observer les engrenages : on parle de principe d'encapsulation.
On peut obtenir la liste de toutes les fonctions disponibles pour un objet de type list
, par la fonction dir
:
>>> dir(m)\n['__add__',\n'__class__',\n'__contains__',\n'__delattr__',\n...\n'clear',\n'copy',\n'count',\n'extend',\n'index',\n'insert',\n'pop',\n'remove',\n'reverse',\n'sort']\n
Les m\u00e9thodes encadr\u00e9es par un double underscore __ sont des m\u00e9thodes priv\u00e9es, a priori non destin\u00e9es \u00e0 l'utilisateur. Les m\u00e9thodes publiques, utilisables pour chaque objet de type list
, sont donc append
, clear
, ...
Comment savoir ce que font les m\u00e9thodes ? Si elles ont \u00e9t\u00e9 correctement cod\u00e9es (et elles l'ont \u00e9t\u00e9), elles poss\u00e8dent une docstring, accessible par :
>>> m.append.__doc__\n'Append object to the end of the list.'\n>>> m.reverse.__doc__\n'Reverse *IN PLACE*.'\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#2-creer-son-propre-objet-sa-propre-classe","title":"2. Cr\u00e9er son propre objet sa propre classe","text":""},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#21-vocabulaire-classe-objet-instance-de-classe","title":"2.1 Vocabulaire : classe, objet, instance de classe","text":"Jusqu'ici nous avons employ\u00e9 uniquement le mot \u00abobjet\u00bb. Il convient maintenant d'\u00eatre plus pr\u00e9cis.
attrape_souris()
. Par exemple, l'objet Larry est une instance de la classe chat .
D'apr\u00e8s Wikipedia,
larry.pelage = \"blanc et tabby\"\nlarry.surnom = \"Chief Mouser to the Cabinet Office\"\n
Toujours d'apr\u00e8s Wikipedia, la m\u00e9thode larry.attrape_souris()
est plut\u00f4t efficace.
Cr\u00e9ons une classe \u00abvoiture\u00bb. Il suffit d'\u00e9crire :
class Voiture :\n pass #pass, car pour l'instant il n'y a rien dans la d\u00e9claration de la classe (et c'est mal)\n
La classe Voiture
est cr\u00e9\u00e9e. Notez que par convention, le nom d'une classe commence toujours par une majuscule. Pour cr\u00e9er une instance de cette classe, on \u00e9crit :
>>> titine = Voiture()\n
titine
est un objet, instance de la classe Voiture
.
>>> type(titine)\n__main__.Voiture\n
On peut alors donner des attributs \u00e0 cette instance :
>>> titine.annee = 2018\n>>> titine.couleur = \"verte\"\n>>> titine.vitesse_max = 162\n
Mais arr\u00eatons-l\u00e0 cette mauvaise m\u00e9thode. Si on d\u00e9sire cr\u00e9er une classe \u00abvoiture\u00bb, c'est pour cr\u00e9er un concept g\u00e9n\u00e9rique de voiture et d'en sp\u00e9cifier des caract\u00e9ristiques communes : l'ann\u00e9e, la couleur, la vitesse maximale...
L'id\u00e9e est donc qu'\u00e0 la cr\u00e9ation (on dira plut\u00f4t \u00e0 la construction) de chaque objet voiture, on va lui sp\u00e9cifier directement ses attributs :
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#222-bonne-maniere-la-methode-constructeur","title":"2.2.2 (bonne) mani\u00e8re : la m\u00e9thode constructeur","text":"La m\u00e9thode constructeur, toujours appel\u00e9e __init__()
, est une m\u00e9thode (une \u00abdef\u00bb) qui sera automatiquement appel\u00e9e \u00e0 la cr\u00e9ation de l'objet. Elle va donc le doter de tous les attributs de sa classe.
class Voiture :\n def __init__(self, annee, coul, vmax) :\n self.annee = annee\n self.couleur = coul\n self.vitesse_max = vmax\n self.age = 2023 - self.annee\n
self
, omnipr\u00e9sent en POO (d'autres langages utilisent this
), fait r\u00e9f\u00e9rence \u00e0 l'objet lui-m\u00eame, qui est en train d'\u00eatre construit.annee
, coul
et vmax
. Ils donneront respectivement leur valeur aux attributs annee
, couleur
et vitesse_max
.coul
et vmax
ont \u00e9t\u00e9 utilis\u00e9s pour abr\u00e9ger couleur
et vitesse_max
, mais il est recommand\u00e9 de garder les m\u00eames noms, m\u00eame si ce n'est pas du tout obligatoire.Construisons donc notre premi\u00e8re voiture !
>>> mon_bolide = Voiture(2012, \"rouge\", 190)\n
>>> type(mon_bolide)\n__main__.Voiture\n
mon_bolide
poss\u00e8de 4 attributs :
annee
, couleur
et vitesse_max
ont \u00e9t\u00e9 donn\u00e9s par l'utilisateur lors de la cr\u00e9ation.age
s'est cr\u00e9\u00e9 \u00abtout seul\u00bb par l'instruction self.age = 2021 - self.annee
.>>> mon_bolide.annee\n2012\n>>> mon_bolide.couleur\n'rouge'\n>>> mon_bolide.vitesse_max\n190\n>>> mon_bolide.age\n11\n
Observons les diff\u00e9rentes \u00e9tapes gr\u00e2ce \u00e0 PythonTutor :
Bien s\u00fbr, on peut cr\u00e9er une autre voiture en suivant le m\u00eame principe :
>>> batmobile = Voiture(2036, \"noire\", 325)\n>>> batmobile.couleur\n'noire'\n
Exercice 1
\u00c9nonc\u00e9CorrectionCr\u00e9er une classe Point
permettant de cr\u00e9er un objet A
, dont on r\u00e9cup\u00e8rera l'abscisse par la variable A.x
et l'ordonn\u00e9e par A.y
.
Exemple d'utilisation de la classe
>>> A = Point(3,5)\n>>> A.x\n3\n>>> A.y\n5\n
class Point :\n def __init__(self,x,y):\n self.x = x\n self.y = y\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#224-creer-une-methode-pour-notre-objet","title":"2.2.4 Cr\u00e9er une m\u00e9thode pour notre objet","text":"class Voiture :\n def __init__(self, annee, coul, vmax) :\n self.annee = annee\n self.couleur = coul\n self.vitesse_max = vmax\n self.age = 2023 - self.annee\n\n def petite_annonce(self) :\n print(\"\u00c0 vendre voiture\", self.couleur, \"de\", self.annee,\\\n \", vitesse maximale\", self.vitesse_max, \"km/h.\")\n
Remarque : le symbole \\
est utilis\u00e9 ici pour couper une ligne trop longue.
>>> batmobile = Voiture(2036, \"noire\", 325)\n>>> batmobile.petite_annonce()\n\u00c0 vendre voiture noire de 2036 , vitesse maximale 325 km/h.\n
Nous aurions pu (ou d\u00fb) en profiter pour \u00e9crire une docstring pour notre m\u00e9thode petite_annonce()
:
class Voiture :\n def __init__(self, annee, coul, vmax) :\n self.annee = annee\n self.couleur = coul\n self.vitesse_max = vmax\n self.age = 2023 - self.annee\n\n def petite_annonce(self) :\n\"\"\" R\u00e9dige automatiquement une petite annonce concernant le v\u00e9hicule\"\"\"\n print(\"\u00c0 vendre voiture\", self.couleur, \"de\", self.annee,\\\n \", vitesse maximale\", self.vitesse_max, \"km/h.\")\n
>>> batmobile = Voiture(2036, \"noire\", 325)\n>>> batmobile.petite_annonce.__doc__\n ' R\u00e9dige automatiquement une petite annonce concernant le v\u00e9hicule'\n
Que donne la commande dir
pour notre objet ?
dir(batmobile)\n
['__class__',\n '__delattr__',\n '__dict__',\n '__dir__',\n '__doc__',\n '__eq__',\n '__format__',\n '__ge__',\n '__getattribute__',\n '__gt__',\n '__hash__',\n '__init__',\n '__init_subclass__',\n '__le__',\n '__lt__',\n '__module__',\n '__ne__',\n '__new__',\n '__reduce__',\n '__reduce_ex__',\n '__repr__',\n '__setattr__',\n '__sizeof__',\n '__str__',\n '__subclasshook__',\n '__weakref__',\n 'age',\n 'annee',\n 'couleur',\n 'petite_annonce',\n 'vitesse_max']\n
On y retrouve donc \u00e0 la fois les 4 attributs et l'unique m\u00e9thode que nous avons cr\u00e9\u00e9s pour notre objet.
Exercice 2
\u00c9nonc\u00e9CorrectionReprendre la classe de l'exercice pr\u00e9c\u00e9dent et rajouter une m\u00e9thode distance()
qui renvoie la distance du point par rapport \u00e0 l'origine du rep\u00e8re (dans un rep\u00e8re orthonorm\u00e9).
Exemple d'utilisation de la classe
>>> A = Point(3,5)\n>>> A.distance()\n5.830951894845301\n
class Point:\n def __init__(self,x,y):\n self.x = x\n self.y = y\n\n def distance(self) :\n return (self.x**2+self.y**2)**0.5\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#3-complements","title":"3. Compl\u00e9ments","text":""},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#31-hors-programme-la-methode-__repr__","title":"3.1 Hors-Programme : la m\u00e9thode __repr__()
","text":"La m\u00e9thode __repr__()
(les doubles underscores traduisent le fait que la m\u00e9thode est priv\u00e9e) peut red\u00e9finir la mani\u00e8re dont l'objet doit s'afficher lors qu'on le passe en param\u00e8tre \u00e0 la fonction print()
, ou simplement lorsqu'on demande sa valeur en console.
Observons comment s'affiche un objet de type Fraction
lorsque rien n'a \u00e9t\u00e9 sp\u00e9cifi\u00e9 sur son affichage.
class Fraction:\n def __init__(self, num, den):\n self.numerateur = num\n self.denominateur = den\n
>>> a = Fraction(3,4)\n>>> print(a)\n <__main__.Fraction object at 0x7f470445c828>\n
C'est un peu d\u00e9cevant. Rajoutons donc une m\u00e9thode __repr__()
.
class Fraction:\n def __init__(self, num, den):\n self.numerateur = num\n self.denominateur = den\n\n def __repr__(self):\n return str(self.numerateur) + \"/\" + str(self.denominateur)\n
>>> a = Fraction(3,4)\n>>> print(a)\n 3/4\n>>> a\n 3/4\n
Ce qui est nettement plus agr\u00e9able ! Exercice 3
\u00c9nonc\u00e9CorrectionModifier la m\u00e9thode __repr__
afin de n'afficher que le num\u00e9rateur dans le cas o\u00f9 le d\u00e9nominateur vaut 1.
class Fraction:\n def __init__(self, num, den):\n self.numerateur = num\n self.denominateur = den\n\n def __repr__(self):\n if self.denominateur == 1:\n return str(self.numerateur)\n return str(self.numerateur) + \"/\" + str(self.denominateur)\n
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#32-lencapsulation-poussee-a-bout-les-getters-et-les-setters","title":"3.2 L'encapsulation pouss\u00e9e \u00e0 bout : les getters
et les setters
","text":"Imaginons la classe suivante :
class Joueur :\n def __init__(self, nom, club, age):\n self.nom = nom\n self.club = club\n self.age = age\n
Instancions le joueur Nans Ducuing
>>> nducuing = Joueur(\"Nans DUCUING\", \"UBB\", 31)\n
notre cobaye
"},{"location":"T2_Programmation/2.1_Programmation_Orientee_Objet/cours/#321-les-setters","title":"3.2.1 Lessetters
","text":"Supposons maintenant que ce joueur change de club, pour aller de l'UBB \u00e0 Perpignan.
Il serait naturel de faire ceci :
>>> nducuing.club = \"Perpignan\"\n
Cela marche bien, mais... C'est contraire \u00e0 l'esprit de la Programmation Orient\u00e9e Objet. Ce paradigme milite pour une encapsulation des objets, qui interdisent le plus possible l'acc\u00e8s direct \u00e0 leurs attributs.
Comment faire alors ? En proposant une m\u00e9thode dont l'unique travail est d'aller effectuer une modification sur l'attribut :
class Joueur :\n def __init__(self, nom, club, age):\n self.nom = nom\n self.club = club\n self.age = age\n\n def mutation(self, nouveau_club):\n self.club = nouveau_club\n
Le changement de club se fera maintenant par l'appel :
>>> nducuing.mutation(\"Perpignan\")\n
Ce type de m\u00e9thode s'appelle un setter
.
getters
","text":"Nous avons vu qu'aller modifier directement un attribut \u00e9tait d\u00e9fendu... mais peut-on simplement aller le consulter ?
L\u00e0 encore, le concept d'encapsulation -pouss\u00e9 \u00e0 l'extr\u00eame- peut nous l'interdire.
Mais si nducuing.club
est interdit, comment savoir dans quel club joue notre joueur pr\u00e9f\u00e9r\u00e9 ?
Une fois de plus, en construisant une m\u00e9thode qui va nous renvoyer l'\u00e9tat actuel de son attribut club
:
class Joueur :\n def __init__(self, nom, club, age):\n self.nom = nom\n self.club = club\n self.age = age\n\n def mutation(self, nouveau_club):\n self.club = nouveau_club\n\n def get_club(self):\n return self.club\n
L'acc\u00e8s \u00e0 l'attribut club
de notre instance se fera donc maintenant par :
>>> nducuing.get_club()\n
Ce type de m\u00e9thode s'appelle un getter
.
Exercice 1
\u00c9nonc\u00e9CorrectionEleve
qui contiendra les attributs nom
, classe
et note
.compare(eleve1, eleve2)
qui renvoie le nom de l'\u00e9l\u00e8ve ayant la meilleure note (on ne traitera pas \u00e0 part le cas d'\u00e9galit\u00e9).Exemple d'utilisation de la classe
>>> riri = Eleve(\"Henri\", \"TG2\", 12)\n>>> fifi = Eleve(\"Philippe\", \"TG6\", 15)\n>>> loulou = Eleve(\"Louis\", \"TG1\", 8)\n>>> compare(riri, fifi)\n'Philippe'\n
class Eleve:\n def __init__(self, nom, classe, note):\n self.nom = nom\n self.classe = classe\n self.note = note\n\ndef compare(eleve1, eleve2):\n if eleve1.note > eleve2.note:\n return eleve1.nom\n else:\n return eleve2.nom\n
Exercice 2
\u00c9nonc\u00e9Correction\u00c9crire une classe TriangleRect
qui contiendra les attributs cote1
, cote2
et hypotenuse
.
La m\u00e9thode constructeur ne prendra en param\u00e8tres que cote1
et cote2
, l'attribut hypotenuse
se calculera automatiquement.
Exemple d'utilisation de la classe
>>> mon_triangle = TriangleRect(3,4)\n>>> mon_triangle.cote1\n3\n>>> mon_triangle.cote2\n4\n>>> mon_triangle.hypotenuse\n5.0\n
class TriangleRect:\n def __init__(self, c1, c2):\n self.cote1 = c1\n self.cote2 = c2\n self.hypotenuse = (self.cote1**2 + self.cote2**2)**0.5\n
Exercice 3
\u00c9nonc\u00e9CorrectionChrono
qui contiendra les attributs heures
, minutes
et secondes
.affiche()
qui fera affichera le temps t
.avance(s)
qui fera avancer le temps t
de s
secondes.Exemple d'utilisation de la classe
>>> t = Chrono(17,25,38)\n>>> t.heures\n17\n>>> t.minutes\n25\n>>> t.secondes\n38\n>>> t.affiche()\n'Il est 17 heures, 25 minutes et 38 secondes'\n>>> t.avance(27)\n>>> t.affiche()\n'Il est 17 heures, 26 minutes et 5 secondes'\n
Aide On pourra utiliser les op\u00e9rateurs :
%
, qui calcule le reste d'une division euclidienne.//
, qui calcule le quotient d'une division euclidienne.class Chrono:\n def __init__(self, h, m, s):\n self.heures = h\n self.minutes = m\n self.secondes = s\n\n def affiche(self):\n print(\"Il est {} heures, {} minutes \\\n et {} secondes\".format(self.heures, self.minutes, self.secondes))\n\n def avance(self, s):\n self.secondes += s\n\n # il faut ajouter les minutes suppl\u00e9mentaires si les secondes\n # d\u00e9passent 60\n self.minutes += self.secondes // 60\n\n # il ne faut garder des secondes que ce qui n'a pas servi\n # \u00e0 fabriquer des minutes suppl\u00e9mentaires\n self.secondes = self.secondes % 60\n\n # il faut ajouter les heures suppl\u00e9mentaires si les minutes\n # d\u00e9passent 60\n self.heures += self.minutes // 60\n\n # il ne faut garder des minutes que ce qui n'a pas servi\n # \u00e0 fabriquer des heures suppl\u00e9mentaires\n self.minutes = self.minutes % 60\n
Exercice 4
\u00c9nonc\u00e9Correction\u00c9crire une classe Player
qui :
energie
valant 3 par d\u00e9faut. alive
valant True
par d\u00e9faut.blessure()
qui diminue l'attribut energie
de 1.soin()
qui augmente l'attribut energie
de 1.energie
passe \u00e0 0, l'attribut alive
doit passer \u00e0 False
et ne doit plus pouvoir \u00e9voluer.Exemple d'utilisation de la classe
>>> mario = Player()\n>>> mario.energie\n3\n>>> mario.soin()\n>>> mario.energie\n4\n>>> mario.blessure()\n>>> mario.blessure()\n>>> mario.blessure()\n>>> mario.alive\nTrue\n>>> mario.blessure()\n>>> mario.alive\nFalse\n>>> mario.soin()\n>>> mario.alive\nFalse\n>>> mario.energie\n0\n
class Player:\n def __init__(self):\n self.energie = 3\n self.alive = True\n\n def blessure(self):\n self.energie -= 1\n if self.energie == 0:\n self.alive = False\n\n def soin(self):\n if self.energie > 0:\n self.energie += 1\n
\u00c0 faire sur Capytale : activit\u00e9 2ef0-54279
Exercice 5
\u00c9nonc\u00e9CorrectionCr\u00e9er une classe CompteBancaire
dont la m\u00e9thode constructeur recevra en param\u00e8tres :
titulaire
stockant le nom du propri\u00e9taire.solde
contenant le solde disponible sur le compte. Cette classe contiendra deux m\u00e9thodes retrait()
et depot()
qui permettront de retirer ou de d\u00e9poser de l'argent sur le compte.
Exemple d'utilisation de la classe
>>> compteGL = CompteBancaire(\"G.Lassus\", 1000)\n>>> compteGL.retrait(50)\nVous avez retir\u00e9 50 euros\nSolde actuel du compte : 950 euros\n>>> compteGL.retrait(40000)\nRetrait impossible\n>>> compteGL.depot(10000000)\nVous avez d\u00e9pos\u00e9 10000000 euros\nSolde actuel du compte : 10000950 euros\n
class CompteBancaire:\n def __init__(self, titulaire, solde):\n self.titulaire = titulaire\n self.solde = solde\n\n def retrait(self, somme):\n if somme > self.solde:\n print(\"Retrait impossible\")\n else :\n self.solde -= somme\n print(\"Vous avez retir\u00e9 {} euros\".format(somme))\n print(\"Solde actuel du compte : {} euros\".format(self.solde))\n\n def depot(self, somme):\n self.solde += somme\n print(\"Vous avez d\u00e9pos\u00e9 {} euros\".format(somme))\n print(\"Solde actuel du compte : {} euros\".format(self.solde))\n
Exercice 6
Exercice 32.2 de la BNS 2023.
Exercice 7
Exercice 2 Partie A du sujet M\u00e9tropole Septembre 2022
Correction Q1.aLa liste v
contient 5 \u00e9l\u00e9ments.
v[1].nom()
renvoie Les go\u00e9lands
.
la classe Villa
poss\u00e8de un attribut nom
ET une m\u00e9thode nom()
. Ceci est affreux et provoquerait une erreur lors de l'appel \u00e0 la m\u00e9thode nom()
.
def surface(self):\n return self.sejour.sup + self.ch1.sup + self.ch2.sup\n
Correction Q2 for villa in v:\n if villa.eqCuis == \"eq\":\n print(villa.nom)\n
ou bien
for villa in v:\n if villa.equip() == \"eq\":\n print(villa.nom)\n
Exercice 8
Exercice 5 du sujet M\u00e9tropole J1 2022
Correction Q1Instruction 3 : joueur1 = Joueur(\"Sniper\", 319, \"A\")
def redevenir_actif(self):\n if self.est_actif == False:\n self.est_actif = True\n
ou mieux : def redevenir_actif(self):\n if not self.est_actif:\n self.est_actif = True\n
Correction Q2.b def nb_tirs_recus(self):\n return len(self.liste_id_tirs_recus)\n
Correction Q3.a Le test est le test 1.
Correction Q3.bSi un joueur a \u00e9t\u00e9 touch\u00e9 par un tir alli\u00e9, son score diminue de 20 points.
Correction Q4if participant.est_determine() == True:\n self.incremente_score(40)\n
ou mieux : if participant.est_determine():\n self.incremente_score(40)\n
Exercice 9
Exercice 2 du sujet La R\u00e9union J1 2022
Correction Q1.ai = 0\nwhile i < len(Mousse) and Mousse[i] != None:\n i += 1\nreturn i\n
Correction Q1.b def placeBulle(B):\n i = donnePremierIndiceLibre(Mousse)\n if i != 6:\n Mousse[i] = B \n
Correction Q2 def bullesEnContact(B1,B2):\n return distanceEntreBulles(B1, B2) <= B1.rayon + B2.rayon\n
Correction Q3 def collision(indPetite, indGrosse, Mousse) :\n\"\"\"\n Absorption de la plus petite bulle d\u2019indice indPetite\n par la plus grosse bulle d\u2019indice indGrosse. Aucun test\n n\u2019est r\u00e9alis\u00e9 sur les positions.\n \"\"\"\n # calcul du nouveau rayon de la grosse bulle\n surfPetite = pi * Mousse[indPetite].rayon**2\n surfGrosse = pi * Mousse[indGrosse].rayon**2\nsurfGrosseApresCollision = surfPetite + surfGrosse = pi\nrayonGrosseApresCollision = sqrt(surfGrosseApresCollision/pi)\n\n #r\u00e9duction de 50% de la vitesse de la grosse bulle\nMousse[indGrosse].dirx = 0.5 * Mousse[indGrosse].dirx\nMousse[indGrosse].diry = 0.5 * Mousse [indGrosse].diry\n#suppression de la petite bulle dans Mousse\nMousse[indPetite] = None\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite/","title":"Exercices","text":"Exercice 1
\u00c9nonc\u00e9Correction\u00c9crire une fonction r\u00e9cursive puissance(x, n)
qui calcule le nombre \\(x^n\\).
def puissance(x, n):\n if n == 0:\n return 1\n else:\n return x * puissance(x, n-1)\n
Exercice 2
\u00c9nonc\u00e9CorrectionOn rappelle que le PGCD (plus grand diviseur commun de deux nombres) v\u00e9rifie la propri\u00e9t\u00e9 suivante : si la division euclidienne de \\(a\\) par \\(b\\) s'\u00e9crit \\(a = b \\times q + r\\), alors \\(pgcd(a,b)=pgcd(b,r)\\).
Cette propri\u00e9t\u00e9 est \u00e0 la base de l'algorithme d'Euclide
Exemple : \\(pgcd(24,18)=pgcd(18,6)=pgcd(6,0)\\), donc \\(pgcd(24,18)=6\\)
\u00c9crire un algorithme r\u00e9cursif pgcd(a,b)
.
def pgcd(a, b):\n if a%b == 0:\n return b\n else:\n return pgcd(b, a%b)\n
Exercice 3
\u00c9nonc\u00e9CorrectionLa conjecture de Syracuse (ou de Collatz) postule ceci :
Prenons un nombre \\(n\\) : si \\(n\\) est pair, on le divise par 2, sinon on le multiplie par 3 puis on ajoute 1. On recommence cette op\u00e9ration tant que possible. Au bout d'un certain temps, on finira toujours par tomber sur le nombre 1.
syracuse(n)
\u00e9crivant tous les termes de la suite de Syracuse, s'arr\u00eatant (on l'esp\u00e8re) \u00e0 la valeur 1.n
.1.
def syracuse(n):\n print(n)\n if n == 1:\n return None\n if n % 2 == 0:\n return syracuse(n // 2)\n else:\n return syracuse(3*n + 1)\n
Remarque : comme notre fonction syracuse
ne renvoie pas de valeur num\u00e9rique (elle ne fait qu'afficher une valeur), le return
du test de parit\u00e9 est en fait inutile.
Mais le return
du cas de base est lui primordial pour que le code s'arr\u00eate !
def syracuse(n):\n print(n)\n if n == 1:\n return None\n if n % 2 == 0:\n syracuse(n // 2)\n else:\n syracuse(3*n + 1)\n
2. def syracuse(n, t=0):\n print(n)\n t += 1\n if n == 1:\n print('temps de vol :', t)\n return None\n if n % 2 == 0:\n syracuse(n // 2, t)\n else:\n syracuse(3*n + 1, t)\n
Exercice 4
\u00c9nonc\u00e9CorrectionReproduire le dessin suivant, \u00e0 l'aide du module turtle
.
turtle
est un hommage au langage LOGO invent\u00e9 par Seymour Papert au MIT \u00e0 la fin des ann\u00e9es 60.
from turtle import *\ndef carre(c):\n for k in range(4):\n forward(c)\n right(90)\n\ndef base(c):\n carre(c)\n forward(c/2)\n right(45)\n\ndef trace(c, n):\n if n == 0 :\n return None\n else :\n base(c)\n c = c/(2**0.5)\n trace(c, n-1)\n\ntrace(200, 5)\n
Exercice 5
\u00c9nonc\u00e9CorrectionProposer une nouvelle fonction r\u00e9cursive puissance_mod(x, n)
qui calcule le nombre \\(x^n\\). Pour optimiser la fonction d\u00e9j\u00e0 construite \u00e0 l'exercice 1, utiliser le fait que :
def puissance_mod(x, n):\n if n == 0 :\n return 1\n else :\n if n % 2 == 0:\n return puissance_mod(x*x, n//2)\n else :\n return x * puissance_mod(x*x, (n-1)//2)\n
Exercice 6
\u00c9nonc\u00e9Correction\u00c9crire un algorithme r\u00e9cursif recherche(lst, val)
qui recherche la pr\u00e9sence de la valeur val
dans une liste tri\u00e9e (par ordre croissant) lst
.
Cette fonction doit renvoyer un bool\u00e9en.
Exemple d'utilisation :
>>> lst = [2,4,5,5,7,9,11,15,16,18,19]\n>>> recherche(lst, 16)\n[2, 4, 5, 5, 7, 9, 11, 15, 16, 18, 19]\n[9, 11, 15, 16, 18, 19]\n[16, 18, 19]\n[16]\nTrue\n>>> recherche(lst, 6)\n[2, 4, 5, 5, 7, 9, 11, 15, 16, 18, 19]\n[2, 4, 5, 5, 7]\n[5, 5, 7]\n[5, 7]\n[5]\nFalse\n
Aide :
Les techniques de slicing (hors-programme) permettent de couper une liste en deux :
>>> lst = [10, 12, 15, 17, 18, 20, 22]\n>>> lst[:3]\n[10, 12, 15]\n>>> lst[3:]\n[17, 18, 20, 22]\n
def recherche(lst, val):\n print(lst) # pour voir la taille de la liste diminuer\n if len(lst) == 1: #cas de base\n if lst[0] == val:\n return True\n else:\n return False\n else : #cas r\u00e9cursif\n ind_milieu = len(lst)//2\n if lst[ind_milieu] > val:\n return recherche(lst[:ind_milieu], val)\n else:\n return recherche(lst[ind_milieu:], val)\n
Exercice 7
\u00c9nonc\u00e9CorrectionOn consid\u00e8re le jeu des Tours de Hano\u00ef. Le but est de faire passer toutes les assiettes de A vers C, sachant qu'une assiette ne peut \u00eatre d\u00e9pos\u00e9e que sur une assiette de diam\u00e8tre inf\u00e9rieur.
Une version jouable en ligne peut \u00eatre trouv\u00e9e ici.
\u00c9crire une fonction r\u00e9cursive hanoi(n, depart, inter, arrivee)
qui donnera la suite d'instructions (sous la forme \" A vers C\") pour faire passer une pile de taille n de depart
vers arrivee
en prenant inter
comme interm\u00e9diaire.
def hanoi(n, depart, inter, arrivee):\n\"\"\" n : nombre d'assiettes dans la pile\n # depart : la pile de d\u00e9part(\"A\", \"B\" ou \"C\")\n # inter : la pile interm\u00e9daire(\"A\", \"B\" ou \"C\")\n # arrivee : la pile d'arriv\u00e9e (\"A\", \"B\" ou \"C\") \"\"\"\n\n if n == 1 :\n print(depart + \" vers \" + arrivee)\n else :\n hanoi(n-1, depart, arrivee, inter) \n print(depart + \" vers \" + arrivee)\n hanoi(n-1, inter, depart, arrivee)\n\nhanoi(5, \"A\", \"B\", \"C\")\n
Exercice 8
\u00c9nonc\u00e9CorrectionCet exercice a pour objectif le trac\u00e9 du flocon de Von Koch.
L'id\u00e9e est de r\u00e9p\u00e9ter de mani\u00e8re r\u00e9cursive la transformation ci-dessous : chaque segment de longueur l
donne naissance \u00e0 4 segments de longueur l/3
, en construisant une pointe de triangle \u00e9quilat\u00e9ral sur le deuxi\u00e8me tiers du segment.
1) Cr\u00e9er une fonction r\u00e9cursive floc(n, l)
qui trace \u00e0 une \u00abprofondeur\u00bb n
un segment de longueur l
. Indications
n
vaut 0.n
fait 4 appels successifs \u00e0 l'\u00e9tape n-1
.2) Cr\u00e9er une fonction triangle(n, l)
qui trace le flocon complet.
from turtle import *\n\ndef floc(n, l):\n if n == 0:\n forward(l)\n else:\n floc(n-1,l/3)\n left(60)\n floc(n-1,l/3)\n right(120)\n floc(n-1,l/3)\n left(60)\n floc(n-1,l/3)\n\n\nspeed(0)\n\ndef triangle(n,l):\n for _ in range(3):\n floc(n,l)\n right(120)\n\ntriangle(5,400)\n
Exercice 9
\u00c9nonc\u00e9CorrectionExercice 10
Exercice 4 du sujet Am\u00e9rique du Nord J1
correction Q1.a.Proposition 3
correction Q1.b.txt[0]
vaut 'b' txt[taille-1]
vaut 'r' interieur
vaut 'onjou'
def test_palindrome():\n assert palindrome(\"kayak\") == True\n assert palindrome(\"canoe\") == False \n
On teste les deux cas possibles. correction Q3. def palindrome_imperatif(txt):\n if len(txt) < 2:\n return True\n i = 0\n j = len(txt)-1\n while i<j:\n if txt[i] != txt[j]:\n return False\n i += 1\n j -= 1\n return True\n
correction Q4.a. def complementaire(txt):\n comp = {\"A\":\"T\", \"T\":\"A\", \"G\":\"C\", \"C\":\"G\"}\n sol = \"\"\n for c in txt:\n sol += comp[c]\n return sol\n
correction Q4.b \"GATCGTCTAGCA\" n'est pas un palindrome donc \"GATCGT\" n'est pas palindromique.
correction Q4.cdef est_palindromique(txt):\n txt_total = txt + complementaire(txt)\n return palindrome(txt_total)\n
Exercice 11
Exercice 1 du sujet Centres \u00c9trangers J2 2022
correction Q1.a.f(5)
affichera : `5 4 3 2 1 Partez!
On dit que cette fonction est r\u00e9cursive car elle s'appelle elle-m\u00eame \u00e0 l'int\u00e9rieur de sa propre d\u00e9finition.
Correction Q2.a.def ajouter(s, liste):\n res = []\n for m in liste:\n res.append(s + m)\n return res\n
Correction Q2.b. La commande renvoie :
['ba', 'bb', 'bc']\n
Correction Q2.c. La commande renvoie :
['a']\n
Correction Q3.a. Comme n
vaut 0, on est dans le cas de base et donc la commande renvoie [\"\"]
.
[\"\"]
n'est pas une liste vide, car elle contient un \u00e9l\u00e9ment (une chaine de caract\u00e8res vide). La liste vide est []
.
produit(\"ab\", 1)
renvoie ['a', 'b']
.
produit(\"ab\", 2)
renvoie ['aa', 'ab', 'ba', 'bb']
.
\u00c9crire une fonction r\u00e9cursive puissance(x,n)
qui calcule le nombre \\(x^n\\).
def puissance(x,n):\n if n == 0 :\n return 1\n else :\n return x*puissance(x,n-1)\n
puissance(2,10)\n
1024\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite_corr/#exercice-2","title":"Exercice 2","text":"\u00c9crire une fonction r\u00e9cursive boucle(i,k)
qui affiche les entiers entre i
et k
. Par exemple, boucle(2,5)
doit afficher 2 3 4 5
def boucle(i,k):\n if i == k :\n print(i)\n else :\n print(i)\n boucle(i+1,k)\n
boucle(2,5)\n
2\n3\n4\n5\n
\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite_corr/#exercice-3","title":"Exercice 3","text":"On rappelle que le PGCD (plus grand diviseur commun de deux nombres) v\u00e9rifie la propri\u00e9t\u00e9 suivante : si la division euclidienne de \\(a\\) par \\(b\\) s'\u00e9crit \\(a = b \\times q + r\\), alors \\(pgcd(a,b)=pgcd(b,r)\\).
Cette propri\u00e9t\u00e9 est \u00e0 la base de l'algorithme d'Euclide
Exemple : \\(pgcd(24,18)=pgcd(18,6)=pgcd(6,0)\\), donc \\(pgcd(24,18)=6\\)
\u00c9crire un algorithme r\u00e9cursif pgcd(a,b)
.
def pgcd(a,b):\n if b == 0 :\n return a\n else :\n return pgcd(b,a%b)\n\ndef pgcd2(a,b):\n return a if b == 0 else pgcd2(b,a%b)\n\n\nprint(pgcd(18,12))\nprint(pgcd2(18,12))\n
6\n6\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite_corr/#exercice-4","title":"Exercice 4","text":"La conjecture de Syracuse (ou de Collatz) postule ceci :
Prenons un nombre \\(n\\) : si \\(n\\) est pair, on le divise par 2, sinon on le multiplie par 3 puis on ajoute 1. On recommence cette op\u00e9ration tant que possible. Au bout d'un certain temps, on finira toujours par tomber sur le nombre 1.
Proposer un programme r\u00e9cursif syracuse(n)
\u00e9crivant tous les termes de la suite de Syracuse, s'arr\u00eatant (on l'esp\u00e8re) \u00e0 la valeur 1.
def syracuse(n):\n print(n)\n if n == 1 :\n return None\n else :\n if n % 2 == 0 :\n return syracuse(n//2)\n else :\n return syracuse(3*n+1)\n
syracuse(14)\n
14\n7\n22\n11\n34\n17\n52\n26\n13\n40\n20\n10\n5\n16\n8\n4\n2\n1\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite_corr/#exercice-5","title":"Exercice 5","text":"Reproduire le dessin suivant, \u00e0 l'aide du module turtle
.
turtle
est un hommage au langage LOGO invent\u00e9 par Seymour Papert au MIT \u00e0 la fin des ann\u00e9es 60.
from turtle import *\n\n\ndef carre(c):\n for k in range(4):\n forward(c)\n right(90)\n\ndef base(c):\n carre(c)\n forward(c/2)\n right(45)\n\ndef trace(c):\n if c < 5 :\n return None\n else :\n base(c)\n return trace(c/(2**0.5))\n\ntrace(200)\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite_corr/#exercice-6","title":"Exercice 6","text":"Proposer une nouvelle fonction r\u00e9cursive puissance(x,n)
qui calcule le nombre \\(x^n\\). Pour optimiser la fonction d\u00e9j\u00e0 construite \u00e0 l'exercice 1, utiliser le fait que : - si \\(n\\) est pair, \\(a^n=(a \\times a)^{n/2}\\) - sinon \\(a^n=a \\times (a \\times a)^{(n-1)/2}\\)
def puissance(x,n):\n if n == 0 :\n return 1\n else :\n if n % 2 == 0:\n return puissance(x*x,n//2)\n else :\n return x*puissance(x*x,(n-1)//2)\n
puissance(10,3)\n
1000\n
puissance(10,6)\n
1000000\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite_corr/#exercice-7","title":"Exercice 7","text":"\u00c9crire un algorithme r\u00e9cursif recherche(lst,m)
qui recherche la pr\u00e9sence de la valeur m
dans une liste tri\u00e9e lst
. Cette fonction doit renvoyer un bool\u00e9en.
lst=[5,6,9,12,17]\n
lst[:3]\n
[5, 6, 9]\n
lst[3:]\n
[12, 17]\n
def recherche(lst,m):\n print(lst) # pour voir la taille de la liste diminuer\n if len(lst) == 1 : #cas de base\n if lst[0] == m :\n return True\n else :\n return False\n else : #cas r\u00e9cursif\n mid = len(lst)//2\n if lst[mid] > m :\n return recherche(lst[:mid],m)\n else :\n return recherche(lst[mid:],m)\nlst=[5,6,9,12,17]\n\nrecherche(lst,18)\n
[5, 6, 9, 12, 17]\n[9, 12, 17]\n[12, 17]\n[17]\n\n\n\n\n\nFalse\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite_corr/#exercice-8","title":"Exercice 8","text":"On consid\u00e8re le jeu des Tours de Hano\u00ef. Le but est de faire passer toutes les assiettes de A vers C, sachant qu'une assiette ne peut \u00eatre d\u00e9pos\u00e9e que sur une assiette de diam\u00e8tre inf\u00e9rieur.
Une version jouable en ligne peut \u00eatre trouv\u00e9e ici.
\u00c9crire une fonction r\u00e9cursive hanoi(n, A, B, C)
qui donnera la suite d'instructions (sous la forme \" A vers C\") pour faire passer une pile de taille n de A vers C en prenant B comme interm\u00e9diaire.
def hanoi(n,A,B,C):\n\"\"\" n : nombre d'assiettes dans la pile\n # A : la pile de d\u00e9part(\"A\", \"B\" ou \"C\")\n # B : la pile interm\u00e9daire(\"A\", \"B\" ou \"C\")\n # C : la pile d'arriv\u00e9e (\"A\", \"B\" ou \"C\") \"\"\"\n\n if n == 1 :\n print(A + \" vers \" + C)\n else :\n hanoi(n-1,A,C,B) #de A vers B en passant par C\n print(A + \" vers \" + C)\n hanoi(n-1,B,A,C)\n\nhanoi(5,\"Tower1\",\"Tower2\",\"Tower3\")\n
Tower1 vers Tower3\nTower1 vers Tower2\nTower3 vers Tower2\nTower1 vers Tower3\nTower2 vers Tower1\nTower2 vers Tower3\nTower1 vers Tower3\nTower1 vers Tower2\nTower3 vers Tower2\nTower3 vers Tower1\nTower2 vers Tower1\nTower3 vers Tower2\nTower1 vers Tower3\nTower1 vers Tower2\nTower3 vers Tower2\nTower1 vers Tower3\nTower2 vers Tower1\nTower2 vers Tower3\nTower1 vers Tower3\nTower2 vers Tower1\nTower3 vers Tower2\nTower3 vers Tower1\nTower2 vers Tower1\nTower2 vers Tower3\nTower1 vers Tower3\nTower1 vers Tower2\nTower3 vers Tower2\nTower1 vers Tower3\nTower2 vers Tower1\nTower2 vers Tower3\nTower1 vers Tower3\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite_corr/#exercice-9","title":"Exercice 9","text":"Cet exercice a pour objectif le trac\u00e9 du flocon de Von Koch.
L'id\u00e9e est de r\u00e9p\u00e9ter de mani\u00e8re r\u00e9cursive la transformation ci-dessous : chaque segment de longueur l
donne naissance \u00e0 4 segments de longueur l/3
, en construisant une pointe de triangle \u00e9quilat\u00e9ral sur le deuxi\u00e8me tiers du segment.
1) Cr\u00e9er une fonction r\u00e9cursive floc(n,l)
qui trace \u00e0 une \u00abprofondeur\u00bb n
un segment de longueur l
.
Indications - l'instruction de trac\u00e9 n'a lieu que quand n
vaut 0. - l'\u00e9tape n
fait 4 appels sucessifs \u00e0 l'\u00e9tape n-1
.
2) Cr\u00e9er une fonction triangle(n,l)
qui trace le flocon complet.
from turtle import *\n\ndef floc(n,l):\n if n == 0 :\n forward(l)\n else :\n floc(n-1,l/3)\n left(60)\n floc(n-1,l/3)\n right(120)\n floc(n-1,l/3)\n left(60)\n floc(n-1,l/3)\n\ndef triangle(n,l):\n for _ in range(3):\n floc(n,l)\n right(120)\n\nspeed(0)\ntriangle(4,150)\n
"},{"location":"T2_Programmation/2.2_Recursivite/2_Exercices_recursivite_corr/#bibliographie","title":"Bibliographie","text":"G.Lassus, Lyc\u00e9e Fran\u00e7ois Mauriac -- Bordeaux
"},{"location":"T2_Programmation/2.2_Recursivite/cours/","title":"R\u00e9cursivit\u00e9","text":""},{"location":"T2_Programmation/2.2_Recursivite/cours/#1-premiere-approche","title":"1. Premi\u00e8re approche","text":""},{"location":"T2_Programmation/2.2_Recursivite/cours/#11-definition","title":"1.1. D\u00e9finition","text":"Fonction r\u00e9cursive
Une fonction est dite r\u00e9cursive lorsqu'elle fait appel \u00e0 elle-m\u00eame dans sa propre d\u00e9finition.
"},{"location":"T2_Programmation/2.2_Recursivite/cours/#12-un-tres-mauvais-exemple","title":"1.2 Un tr\u00e8s mauvais exemple","text":"C'est d\u00e9j\u00e0 une premi\u00e8re chose \u00e0 comprendre : un programme peut \u00eatre appel\u00e9 par lui-m\u00eame, \u00e0 l'int\u00e9rieur de sa propre d\u00e9finition.
def prems():\n print(\"un tr\u00e8s mauvais exemple\")\n prems()\n
Si on appelle cette fonction, par la commande :
>>> prems()\n
La sortie en console sera celle-ci : un tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\nun tr\u00e8s mauvais exemple\n...\n
\u00c9videmment, comme pr\u00e9vu, ce programme ne s'arr\u00eate pas. Nous sommes oblig\u00e9s de l'arr\u00eater manuellement. Nous sommes (volontairement) tomb\u00e9s dans un pi\u00e8ge qui sera syst\u00e9matiquement pr\u00e9sent lors d'une programmation r\u00e9cursive : le pi\u00e8ge de la boucle infinie.
"},{"location":"T2_Programmation/2.2_Recursivite/cours/#13-la-mauvaise-reputation","title":"1.3 La mauvaise r\u00e9putation","text":"Dans la culture informatique, la r\u00e9cursivit\u00e9 est (trop) souvent abord\u00e9e par le biais de l'auto-r\u00e9f\u00e9rence, le puits sans fin de la boucle infinie.
On trouve d'ailleurs fr\u00e9quemment cette d\u00e9finition de la r\u00e9cursivit\u00e9 :
Fonction r\u00e9cursive : fonction qui fait appel \u00e0 la r\u00e9cursivit\u00e9. Voir fonction r\u00e9cursive.
Google fait aussi (dans toutes les langues) la m\u00eame blague lors d'une recherche sur le terme \u00abr\u00e9cursivit\u00e9\u00bb :
Les acronymes r\u00e9cursifs sont aussi tr\u00e8s fr\u00e9quents... et v\u00e9hiculent avec eux le m\u00eame pi\u00e8ge : une fonction r\u00e9cursive ne serait jamais vraiment d\u00e9finie (c'est faux, nous le verrons)
Par exemple :
Disons-le clairement : au-del\u00e0 de la blague pour initi\u00e9s (dont vous faites partie maintenant) la r\u00e9cursivit\u00e9 ne DOIT PAS \u00eatre associ\u00e9e \u00e0 une auto-r\u00e9f\u00e9rence vertigineuse : c'est en algorithmique une m\u00e9thode (parfois) tr\u00e8s efficace, \u00e0 condition de respecter une r\u00e8gle cruciale : l'existence d'un CAS DE BASE .
Ce \u00abcas de base\u00bb sera aussi appel\u00e9 \u00abcondition d'arr\u00eat\u00bb, puisque la tr\u00e8s grande majorit\u00e9 des algorithmes r\u00e9cursifs peuvent \u00eatre per\u00e7us comme des escaliers qu'on descend marche par marche, jusqu'au sol qui assure notre arr\u00eat.
"},{"location":"T2_Programmation/2.2_Recursivite/cours/#21-la-recursivite-en-bd","title":"2.1 La r\u00e9cursivit\u00e9 en BD :","text":"Observez bien la descente puis la remont\u00e9e de notre vendeur de livre. Le cas de base est ici l'\u00e9tage 0. Il emp\u00eache une descente infinie.
Nous coderons bient\u00f4t la fonction donnant le prix du livre en fonction de l'\u00e9tage.
Pour l'instant, d\u00e9couvrons enfin \u00e0 quoi ressemble une fonction r\u00e9cursive \u00abbien \u00e9crite\u00bb :
"},{"location":"T2_Programmation/2.2_Recursivite/cours/#22-enfin-un-bon-exemple","title":"2.2 Enfin un bon exemple","text":"Exemple fondateur n\u00b01
def mystere(n):\n if n == 0 :\n return 0\n else : \n return n + mystere(n-1)\n
Trois choses sont essentielles et doivent se retrouver dans tout programme r\u00e9cursif :
lignes 2 et 3
: le cas de base (si n
vaut 0 on renvoie vraiment une valeur, en l'occurence 0)ligne 5
: l'appel r\u00e9cursifligne 5
: la d\u00e9cr\u00e9mentation du param\u00e8tre d'appelUtilisation de la fonction mystere
>>> mystere(0)\n0\n>>> mystere(4)\n10\n
Analyse gr\u00e2ce \u00e0 PythonTutor
Que se passe-t-il lorsqu'on appelle mystere(4)
?
On voit que l'existence du cas de base pour \\(n=0\\) est primordiale pour \u00e9viter la r\u00e9cursion infinie.
Cette fonction mystere(n)
calcule donc la somme des entiers positifs inf\u00e9rieurs ou \u00e9gaux \u00e0 \\(n\\).
mystere(100)
est \u00e9gal \u00e0 5050. Une anecdote raconte que Carl Friedrich Gauss trouva cette valeur de 5050 en quelques secondes, devant son instituteur \u00e9bahi. Il venait pour cela d'inventer la formule : \\(1+2+3+\\dots+n=\\frac{n(n+1)}{2}\\)
Ici, \\(1+2+3+\\dots+100=\\frac{100\\times 101)}{2}=50 \\times 101=5050\\)
Exercice 1
\u00c9nonc\u00e9CorrectionCoder la fonction prix(etage)
de la BD pr\u00e9sent\u00e9e plus haut.
def prix(etage):\n if etage == 0:\n return 3\n else:\n return 2 * prix(etage - 1)\n
Exercice 2
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la fonction factorielle(n)
(not\u00e9e \\(n!\\) en math\u00e9matiques), qui calcule le produit d'un entier \\(n\\) par les entiers positifs qui lui sont inf\u00e9rieurs:
Exemple : \\(5!=5\\times4\\times3\\times2\\times1=120\\)
Par convention, \\(1!=1\\)
fact_imp
. fact_rec
.Quelle paradigme de programmation vous a sembl\u00e9 le plus naturel ?
def fact_imp(n):\n p = 1\n for k in range(1, n + 1):\n p = p * k\n return p\n\ndef fact_rec(n):\n if n == 1:\n return 1\n else:\n return n * fact_rec(n - 1)\n
"},{"location":"T2_Programmation/2.2_Recursivite/cours/#3-le-mecanisme-interne-de-la-recursivite","title":"3. Le m\u00e9canisme interne de la r\u00e9cursivit\u00e9","text":""},{"location":"T2_Programmation/2.2_Recursivite/cours/#31-notion-de-pile","title":"3.1 Notion de pile","text":"Lors d'un appel \u00e0 une fonction r\u00e9cursive, le processeur utilise une structure de pile pour stocker les contextes d'ex\u00e9cution de chaque appel. Dans la notion de pile (voir ici), seule l'instruction \u00aben haut de la pile\u00bb peut \u00eatre trait\u00e9e et enlev\u00e9e (on dit \u00abd\u00e9pil\u00e9e\u00bb).
La pile d'appels de notre fonction mystere(5)
peut donc \u00eatre sch\u00e9matis\u00e9e comme ceci :
"},{"location":"T2_Programmation/2.2_Recursivite/cours/#32-limitation-de-la-taille-de-la-pile","title":"3.2 Limitation de la taille de la pile","text":"
Nous venons de voir que notre appel \u00e0 mystere(5)
g\u00e9n\u00e9rait une pile de hauteur 6 (on parlera plut\u00f4t de profondeur 6). Cette profondeur est-elle limit\u00e9e ?
mystere(2962)\n
---------------------------------------------------------------------------\n\nRecursionError Traceback (most recent call last)\n\n<ipython-input-32-a97c4dde4ef8> in <module>\n----> 1 mystere(2962)\n\n\n<ipython-input-1-386660a434f2> in mystere(n)\n 3 return 0\n 4 else :\n----> 5 return n + mystere(n-1)\n\n\n... last 1 frames repeated, from the frame below ...\n\n\n<ipython-input-1-386660a434f2> in mystere(n)\n 3 return 0\n 4 else :\n----> 5 return n + mystere(n-1)\n\n\nRecursionError: maximum recursion depth exceeded in comparison\n
Vous venons de provoquer un \u00abd\u00e9bordement de pile\u00bb, le c\u00e9l\u00e8bre stack overflow.
De mani\u00e8re g\u00e9n\u00e9rale, les programmes r\u00e9cursifs sont souvent susceptibles de g\u00e9n\u00e9rer un trop grand nombre d'appels \u00e0 eux-m\u00eames. Il est parfois possible de les optimiser, comme nous le verrons dans le cours concernant la programmation dynamique.
Nous reparlerons aussi de r\u00e9cursivit\u00e9 lorsque nous l'inscrirons dans un paradigme plus global de programmation, qui est \u00ab diviser pour r\u00e9gner \u00bb (en anglais divide and conquer).
"},{"location":"T2_Programmation/2.2_Recursivite/cours/#4-exemples-de-recursivite-double","title":"4. Exemples de r\u00e9cursivit\u00e9 double","text":""},{"location":"T2_Programmation/2.2_Recursivite/cours/#41-la-suite-de-fibonacci","title":"4.1 La suite de Fibonacci","text":"Consid\u00e9rons la suite num\u00e9rique ainsi d\u00e9finie :
On a donc \\(F_2=0+1=1, F_3=F_2+F_1=1+1=2, F_4=F_3+F_2=2+1=3, F_5=F_4+F_3=3+2=5\\) ...
Exercice 3
\u00c9nonc\u00e9CorrectionImpl\u00e9menter de fa\u00e7on r\u00e9cursive la suite de Fibonacci.
def fibo(n):\n if n == 0 :\n return 0 \n elif n == 1 :\n return 1\n else :\n return fibo(n-1) + fibo(n-2)\n
Observation de la pile d'ex\u00e9cution
Appelons F(n)
la fonction calculant de mani\u00e8re r\u00e9cursive le n-i\u00e8me terme de la suite. Observons en d\u00e9tail la pile d'ex\u00e9cution lors du calcul de F(4)
.
Analyse gr\u00e2ce \u00e0 PythonTutor
On s'aper\u00e7oit notamment que :
Le module rcviz
permet d'observer l'arbre des appels r\u00e9cursifs : voir cette activit\u00e9 Capytale
On peut y construire par exemple l'arbre d'appel de fibo(6)
:
On y remarque (par exemple) que fibo(2)
est calcul\u00e9 5 fois...
Exercice 4
\u00c9nonc\u00e9Correction\u00c9crire une fonction fibo_imperatif(n)
qui calcule de fa\u00e7on directe (imp\u00e9rative) le n-i\u00e8me terme de la suite de Fibonacci. On pourra par exemple utiliser un dictionnaire.
Construisons une fonction comparaison
qui affichera le temps de calcul pour chacune des deux fonctions fibo_imperatif
et fibo_recursif
:
import time\n\ndef fibo_imperatif(n):\n f = {}\n f[0] = 0\n f[1] = 1\n for k in range(2, n+1):\n f[k] = f[k-1] + f[k-2]\n return f[n]\n\ndef fibo_recursif(n):\n if n == 0 :\n return 0 \n elif n == 1 :\n return 1\n else :\n return fibo_recursif(n-1) + fibo_recursif(n-2)\n\n\ndef comparaison(n):\n t0 = time.time()\n fibo_imperatif(n)\n print(\"algo imp\u00e9ratif : \", time.time() - t0)\n t0 = time.time()\n fibo_recursif(n)\n print(\"algo r\u00e9cursif : \", time.time() - t0)\n
R\u00e9sultats
>>> comparaison(10)\nalgo imp\u00e9ratif : 6.9141387939453125e-06\nalgo r\u00e9cursif : 1.7642974853515625e-05\n>>> comparaison(20)\nalgo imp\u00e9ratif : 7.62939453125e-06\nalgo r\u00e9cursif : 0.0021445751190185547\n>>> comparaison(30)\nalgo imp\u00e9ratif : 1.8596649169921875e-05\nalgo r\u00e9cursif : 0.25478553771972656\n>>> comparaison(40)\nalgo imp\u00e9ratif : 1.1920928955078125e-05\nalgo r\u00e9cursif : 31.332343339920044\n
La fonction r\u00e9cursive apparait donc beaucoup, beaucoup plus lente que l'imp\u00e9rative (ici d'un facteur 100 pour toute augmentation de 10 du param\u00e8tre n
.)
Attention : cette comparaison des vitesses d'\u00e9x\u00e9cution peut \u00eatre critiqu\u00e9e car les deux programmes n'ont pas la m\u00eame complexit\u00e9. Nous \u00e9tudierons la complexit\u00e9 au moment des algorithmes de tri. La complexit\u00e9 des fonctions r\u00e9cursives n'est pas au programme de NSI.
Peut-on r\u00e9sumer la r\u00e9cursivit\u00e9 \u00e0 une m\u00e9thode \u00e9l\u00e9gante mais inefficace ? Ce serait r\u00e9ducteur : l'efficacit\u00e9 c'est aussi avoir un code lisible et intuitif. Nous en reparlerons lors du parcours des arbres et des graphes. (cf aussi l'exercice sur les Tours de Hano\u00ef)
"},{"location":"T2_Programmation/2.2_Recursivite/cours/#5-annexe-dessins-recursifs-grace-au-module-turtle","title":"5. Annexe : dessins r\u00e9cursifs gr\u00e2ce au moduleturtle
","text":"Le module turtle
permet de faire des trac\u00e9s basiques. Mais d\u00e8s l'instant o\u00f9 on met de la r\u00e9cursivit\u00e9 dans le code, les r\u00e9sultats peuvent devenir tr\u00e8s surprenants, et aboutir \u00e0 des structures fractales.
from turtle import *\n\nang = 40\n\ndef trace(n,l):\n if n == 0 :\n return None\n else :\n forward(l)\n left(ang)\n trace(n-1, 0.7*l)\n right(2*ang)\n trace(n-1, 0.7*l)\n left(ang)\n forward(-l)\n\n\npenup() \ngoto(0,-80)\npendown()\nleft(90)\nspeed(0)\n\ntrace(5,100)\n
"},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/","title":"D\u00e9cidabilit\u00e9, calculabilit\u00e9","text":""},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/#1-un-programme-comme-parametre-dun-programme","title":"1. Un programme comme param\u00e8tre d'un programme","text":"
Les codes que nous manipulons ressemblent souvent \u00e0 cela :
def accueil(n):\n for k in range(n):\n print(\"bonjour\")\n
Le programme s'appelle accueil
, et pour fonctionner il a besoin d'un param\u00e8tre, qui sera ici un nombre entier n
.
Voici comment nous pouvons repr\u00e9senter notre machine accueil
, son param\u00e8tre d'entr\u00e9e (5) et sa sortie (les 5 \u00abbonjour\u00bb)
Maintenant, enregistrons le code suivant dans un fichier test.py
:
def accueil(n):\n for k in range(n):\n print(\"bonjour\")\n\naccueil(5)\n
Pour ex\u00e9cuter ce code, nous devons taper dans un terminal l'instruction suivante : python3 test.py
, ce qui donnera
Le programme utilis\u00e9 est alors python3
, qui prend comme param\u00e8tre le programme test.py
. Ce param\u00e8tre test.py
est un ensemble de caract\u00e8res qui contient les instructions que le programme python3
va interpr\u00e9ter.
L'illustration correspondante sera donc :
Mais nous pouvons aller encore plus loin : l'instruction python3 test.py
est tap\u00e9e dans mon Terminal Linux, qui lui-m\u00eame est un programme appel\u00e9 Terminal
.
Et donc :
Conclusion :
Il n'y a donc aucun obstacle \u00e0 consid\u00e9rer un programme comme une simple donn\u00e9e, pouvant \u00eatre re\u00e7ue en param\u00e8tre par un autre programme. (voire par lui-m\u00eame !)
\u00c0 titre anecdotique, on pourra ex\u00e9cuter avec int\u00e9r\u00eat cette instruction Python : a='a=%r;print(a%%a)';print(a%a)
Ce type de code (magique !) existe dans tous les langages et s'appelle un quine.
Consid\u00e9rons le programme suivant :
def countdown(n):\n while n != 0:\n print(n)\n n = n - 1\n print(\"fini\")\n
En l'observant attentivement, je peux pr\u00e9voir que countdown(10)
affichera les nombres de 10 \u00e0 1 avant d'\u00e9crire \"fini\". Puis le programme s'arr\u00eatera.
Mais que va provoquer countdown(10.8)
?
Comme la variable n
ne sera jamais \u00e9gale \u00e0 0, le programme va rentrer dans une boucle infinie, il ne s'arr\u00eatera jamais. Mauvaise nouvelle. J'ai pu pr\u00e9voir ceci en regardant attentivement le code de mon programme. J'ai \u00abremarqu\u00e9\u00bb qu'une variable n
non enti\u00e8re provoquerait une boucle infinie.
Question : Est-ce qu'un programme d'analyse de programmes aurait pu faire cela \u00e0 ma place ?
"},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/#22-une-machine-pour-predire-larret-ou-non-dun-programme","title":"2.2 Une machine pour pr\u00e9dire l'arr\u00eat ou non d'un programme.","text":"Apr\u00e8s tout, un programme est une suite d'instructions (le code-source), et peut donc \u00eatre, comme on l'a vu, le param\u00e8tre d'entr\u00e9e d'un autre programme qui l'analyserait. Un tel programme (appelons-le halt
) prendrait en entr\u00e9es :
prog
(le code-source du programme)x
, qui serait le param\u00e8tre d'entr\u00e9e de prog
.L'instruction halt(prog, x)
renverrait True
si prog(x)
s'arr\u00eate, et False
si prog(x)
ne s'arr\u00eate pas.
Exemple :
halt(countdown, 10)
renverrait True
.halt(countdown, 10.8)
renverrait False
. Tentative d'\u00e9criture de halt
en Python :
def halt(prog, x):\n if \"prog(x) s'arr\u00eate\": # mes excuses, je n'ai pas eu le temps de finir totalement ce code\n return True\n else :\n return False\n
Nous en resterons l\u00e0 pour l'instant dans l'\u00e9criture de ce programme. Nous allons nous en servir pour construire d'autres programmes.
"},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/#23-amusons-nous-avec-ce-programme-halt","title":"2.3 Amusons-nous avec ce programmehalt
.","text":"Consid\u00e9rons le programme :
def sym(prog):\n if halt(prog, prog) == True:\n while True:\n print(\"vers l'infini et au-del\u00e0 !\")\n else:\n return 1\n
On peut remarquer que le programme halt
est appel\u00e9 avec comme param\u00e8tres prog, prog
, ce qui signifie que prog
se prend lui-m\u00eame en param\u00e8tre. On rappelle que ce n'est pas choquant, un code-source \u00e9tant une donn\u00e9e comme une autre.
Ce programme sym
re\u00e7oit donc en param\u00e8tre un programme prog
, et :
prog(prog)
s'arr\u00eate.prog(prog)
ne s'arr\u00eate pas.Puisqu'un programme peut prendre en param\u00e8tre son propre code-source, que donnerait l'appel \u00e0 sym(sym)
?
Deux cas peuvent se pr\u00e9senter, suivant si halt(sym, sym)
renvoie True
ou False
.
cas n\u00b01 : halt(sym, sym)
renvoie True
, ce qui signifie que sym(sym)
devrait s'arr\u00eater. Mais dans ce cas-l\u00e0, l'ex\u00e9cution de sym(sym)
rentre dans une boucle infinie. C'est une contradiction.
cas n\u00b02 : halt(sym, sym)
renvoie False
, ce qui signifie que sym(sym)
rentre dans une boucle infinie. Mais dans ce cas-l\u00e0, l'ex\u00e9cution de sym(sym)
se termine correctement et renvoie la valeur 1. C'est une contradiction.
Nous venons de prouver que notre programme halt
, cens\u00e9 pr\u00e9dire si un programme prog
peut s'arr\u00eater sur une entr\u00e9e x
, NE PEUT PAS EXISTER.
Ce r\u00e9sultat th\u00e9orique, d'une importance cruciale, s'appelle le probl\u00e8me de l'arr\u00eat.
Probl\u00e8me de l'arr\u00eat
Il ne peut pas exister de programme universel qui prendrait en entr\u00e9es :
et qui d\u00e9terminerait si ce programme P, lanc\u00e9 avec l'entr\u00e9e E, va s'arr\u00eater ou non.
Ce r\u00e9sultat a \u00e9t\u00e9 d\u00e9montr\u00e9 par Alan Turing en 1936, dans un article intitul\u00e9 \u00abOn computable numbers, with an application to the Entscheidungsproblem\u00bb.
Pour sa d\u00e9monstration, il pr\u00e9sente un mod\u00e8le th\u00e9orique de machine capable d'ex\u00e9cuter des instructions basiques sur un ruban infini, les machines de Turing.
\u00c0 la m\u00eame \u00e9poque, le math\u00e9maticien Alonzo Church d\u00e9montre lui aussi ce th\u00e9or\u00e8me de l'arr\u00eat, mais par un moyen totalement diff\u00e9rent, en inventant le lambda-calcul.
Tous deux mettent ainsi un terme au r\u00eave du math\u00e9maticien allemand David Hilbert, qui avait en 1928 pos\u00e9 la question de l'existence d'un algorithme capable de r\u00e9pondre \u00aboui\u00bb ou \u00abnon\u00bb \u00e0 n'importe quel \u00e9nonc\u00e9 math\u00e9matique pos\u00e9 sous forme d\u00e9cisionnelle (\u00abun triangle rectangle peut-il \u00eatre isoc\u00e8le ?\u00bb, \u00abexiste-t-il un nombre premier pair ?\u00bb)
Cette question, appel\u00e9e \u00abprobl\u00e8me de la d\u00e9cision\u00bb, ou Entscheidungsproblem en allemand, est d\u00e9finitivement tranch\u00e9e par le probl\u00e8me de l'arr\u00eat : un tel th\u00e9or\u00e8me ne peut pas exister, puisque par exemple, aucun algorithme ne peut r\u00e9pondre \u00aboui\u00bb ou \u00abnon\u00bb \u00e0 la question \u00abce programme va-t-il s'arr\u00eater ?\u00bb.
Le th\u00e9or\u00e8me de l'arr\u00eat sera \u00e9tendu plus tard par le th\u00e9or\u00e8me de Rice.
Ce r\u00e9sultat d\u00e9montre que toutes les questions s\u00e9mantiques (non \u00e9videntes) au sujet d'un programme sont ind\u00e9cidables :
Rice d\u00e9montre que toutes ces questions peuvent \u00eatre ramen\u00e9es (on dit r\u00e9duites) au th\u00e9or\u00e8me de l'arr\u00eat, qui est ind\u00e9cidable.
"},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/#2-calculabilite","title":"2. Calculabilit\u00e9","text":"D\u00e9cidabilit\u00e9 et calculabilit\u00e9
Le probl\u00e8me de l'arr\u00eat est dit ind\u00e9cidable car la fonction qui le r\u00e9sout (notre brave programme halt
) n'est pas calculable.
Qu'y a-t-il derri\u00e8re cette notion de calculabilit\u00e9 ? Cette notion, qui jette un pont entre les math\u00e9matiques (la vision de Church, pour sch\u00e9matiser) et l'informatique (la vision de Turing) n'est pas simple \u00e0 d\u00e9finir !
Le calcul math\u00e9matique peut se r\u00e9duire \u00e0 une succession d'op\u00e9rations \u00e9l\u00e9mentaires (songez \u00e0 la multiplication enti\u00e8re comme une s\u00e9rie d'additions). Les nombres calculables sont les nombres qui sont g\u00e9n\u00e9rables en un nombre fini d'op\u00e9rations \u00e9l\u00e9mentaires. De la m\u00eame mani\u00e8re, une fonction math\u00e9matique sera dite calculable s'il existe une suite finie d'op\u00e9rations \u00e9l\u00e9mentaires permettant de passer d'un nombre x \u00e0 son image f(x).
On retrouve cette notion d'op\u00e9rations \u00e9l\u00e9mentaires dans les machines de Turing. Cette machine (th\u00e9orique) permet de simuler tout ce qu'un programme informatique (une suite d'instructions) est capable d'ex\u00e9cuter. Un algorithme peut se r\u00e9duire \u00e0 une suite d'op\u00e9rations \u00e9lementaires, comme une fonction math\u00e9matique peut se r\u00e9duire \u00e0 une suite de calculs. D\u00e8s lors, on pourra consid\u00e9rer un algorithme comme une fonction.
Turing a d\u00e9montr\u00e9 que l'ensemble des fonctions calculables, au sens de Church, \u00e9tait \u00e9quivalent \u00e0 l'ensemble des fonctions programmables sur sa machine. Certaines fonctions peuvent \u00eatre calculables, ou ne pas l'\u00eatre : c'est notamment le cas de notre fonction du probl\u00e8me de l'arr\u00eat.
"},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/#22-langages-turing-complets","title":"2.2 Langages Turing-complets","text":"Ce r\u00e9sultat ne d\u00e9pend pas du langage utilis\u00e9 : le fait que nous ayons utilis\u00e9 Python au paragraphe pr\u00e9c\u00e9dent n'a pas d'influence sur notre d\u00e9monstration. Nous savons depuis les machines de Turing que tous nos langages de programmation sont Turing-complets : ils sont tous capables de faire la m\u00eame chose (avec plus ou moins de facilit\u00e9 !). Scratch, C, Python, Java, Basic, Haskell, Brainfuck... tous ces langages sont th\u00e9oriquement \u00e9quivalents : la calculabilit\u00e9 ne d\u00e9pend pas du langage utilis\u00e9.
"},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/#23-hp-calculable-oui-mais-facilement-1-million-de-a-gagner-ci-dessous","title":"2.3 (HP) Calculable, oui, mais facilement ? -> 1 million de $ \u00e0 gagner ci-dessous.","text":"L'\u00e9tude de la calculabilit\u00e9 d'une fonction (\u00e0 prendre au sens le plus large, c'est-\u00e0-dire un algorithme) ne se limite pas \u00e0 un choix binaire : \u00abcalculable\u00bb vs \u00abnon calculable\u00bb. Parmi les fonctions calculables, certaines peuvent l'\u00eatre rapidement, et d'autre beaucoup moins.
On retrouve alors la notion bien connue de complexit\u00e9 algorithmique, qui permet de classifier les algorithmes suivant leur d\u00e9pendance \u00e0 la taille de leurs donn\u00e9es d'entr\u00e9e (voir le cours de Premi\u00e8re).
On peut regrouper les probl\u00e8mes suivant la complexit\u00e9 de l'algorithme qui permet de les r\u00e9soudre.
"},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/#231-la-classe-p","title":"2.3.1 la classe P","text":"D\u00e9finition de la classe P
On dira que sont de \u00abclasse P\u00bb tous les probl\u00e8mes dont l'algorithme de recherche de solution est de complexit\u00e9 polynomiale.
Que retrouve-t-on dans la classe P ? Tous les probl\u00e8mes dont la solution est un algorithme de complexit\u00e9 lin\u00e9raire, quadratique, logarithmique... Tout mais surtout pas un algorithme de complexit\u00e9 exponentielle.
Pour le r\u00e9sumer tr\u00e8s grossi\u00e8rement, un probl\u00e8me de classe P est un probl\u00e8me que l'on sait r\u00e9soudre en temps raisonnable (m\u00eame grand).
D\u00e9finition de la classe NP
On dira que sont de \u00abclasse NP\u00bb tous les probl\u00e8mes dont l'algorithme de recherche de solution est Non-d\u00e9terministe Polynomial.
Warning : NP ne signifie pas Non-Polynomial !!!
Que veut dire la formulation \u00abnon-d\u00e9terministe polynomial\u00bb ? Cela fait r\u00e9f\u00e9rence \u00e0 ce que serait capable de faire une machine de Turing (donc, n'importe quel ordinateur) travaillant de mani\u00e8re non-d\u00e9terministe, donc capable d'explorer simultan\u00e9ment plusieurs solutions possibles. On peut imaginer un arbre dont le parcours se ferait simultan\u00e9ment dans toutes les branches, et non en largeur ou profondeur comme nous l'avons vu.
Sur une machine non-d\u00e9terministe, si la solution \u00e0 un probl\u00e8me se trouve en temps polynomial, alors ce probl\u00e8me appartient \u00e0 la classe NP.
Tr\u00e8s bien, mais les machines non-d\u00e9terministes... cela n'existe pas r\u00e9ellement. Comment caract\u00e9riser concr\u00e8tement cette classe de probl\u00e8me ?
Si la solution peut \u00eatre trouv\u00e9e de mani\u00e8re polynomiale par une machine non-d\u00e9terministe, une machine d\u00e9terministe qui aurait de la chance en partant directement vers la bonne solution la trouverait elle aussi de mani\u00e8re polynomiale. On simplifie souvent cela en disant \u00abla v\u00e9rification de la solution est polynomiale\u00bb. Cela nous donnne cette d\u00e9finition plus accessible de la classe NP :
D\u00e9finition (plus simple) de la classe NP
On dira que sont de \u00abclasse NP\u00bb tous les probl\u00e8mes dont l'algorithme de v\u00e9rification de solution est polynomial.
Pour le r\u00e9sumer tr\u00e8s grossi\u00e8rement, un probl\u00e8me de classe NP est un probl\u00e8me dont on sait v\u00e9rifier facilement si une solution propos\u00e9e marche ou pas :
Malheureusement, aucun de ces probl\u00e8mes cit\u00e9s n'a (\u00e0 ce jour) d'algorithme de r\u00e9solution meilleur qu'exponentiel...
"},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/#223-p-np-ou-pas","title":"2.2.3 P = NP, ou pas ?","text":"Tous les probl\u00e8mes de P ont une solution qui peut \u00eatre trouv\u00e9e de mani\u00e8re polynomiale. Donc \u00e9videmment, la v\u00e9rification de cette solution est aussi polynomiale. Donc tous les probl\u00e8mes de P sont dans NP. On dit que P est inclus dans NP, que l'on \u00e9crit P \u2282 NP.
Voici une capture d'\u00e9cran de l'excellente vid\u00e9o Nos algorithmes pourraient-ils \u00eatre BEAUCOUP plus rapides ? (P=NP ?) de l'excellent David Louapre :
On y retrouve (en vert) la classe P, qui contient les algorithmes de tri. En blanc, la classe NP, qui contient les probl\u00e8mes de factorisation, du sudoku, du sac-\u00e0-dos...
Si quelqu'un trouve un jour un algorithme de polynomial de factorisation, alors le probl\u00e8me de factorisation viendra se ranger dans P. (accessoirement, le RSA sera sans doute d\u00e9truit par cette d\u00e9couverte, sauf si l'ordre de complexit\u00e9 est tr\u00e8s grand)
Mais certains de ces probl\u00e8mes dans NP ont une propri\u00e9t\u00e9 remarquable : la r\u00e9solution polynomiale d'un seul d'entre eux ferait ramener la totalit\u00e9 des probl\u00e8mes NP dans P. On dit que ces probl\u00e8mes sont NP-complets (marqu\u00e9s en rouge ci-dessus) Concr\u00e8tement, si vous trouvez une solution polynomiale de r\u00e9solution du sudoku, vous entrainez avec lui dans P tous les autres probl\u00e8mes NP, et vous aurez ainsi prouv\u00e9 que P = NP. Accessoirement, vous gagnerez aussi le prix d'un million de dollars promis par la fondation Clay \u00e0 qui tranchera cette question... (prix que vous partagerez bien \u00e9videmment avec votre professeur de NSI)
Actuellement, \u00e0 part le grand Donald Knuth, la plupart des chercheurs qui travaillent \u00e0 ce probl\u00e8me sont plut\u00f4t pessimistes, et pensent que P \u2260 NP. Cela signifie qu'ils pensent que certains probl\u00e8mes ne pourront jamais avoir une solution polynomiale.
Alors, P = NP ou P \u2260 NP ? R\u00e9ponse peut-\u00eatre un jour...
"},{"location":"T2_Programmation/2.3_Calculabilite_Decidabilite/cours/#bibliographie","title":"Bibliographie","text":"extrait du site https://realpython.com/python-pep8/
"},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#1-conventions-syntaxiques","title":"1. Conventions syntaxiques","text":"La programmation est un art d\u00e9licat : un simple caract\u00e8re en trop peut provoquer une erreur pour le code tout entier (penser \u00e0 un innocent caract\u00e8re d'espace en d\u00e9but de ligne dans un code Python).
Mais m\u00eame lorsqu'un code s'ex\u00e9cute sans erreur, il ne faut pas n\u00e9gliger l'aspect purement \u00abesth\u00e9tique\u00bb de celui-ci : il est n\u00e9cessaire de respecter autant que possible des conventions typographiques, qui vont standardiser le code et le rendre ainsi plus lisible.
Ainsi pour chaque langage, il existe une \u00abbible\u00bb de bonnes pratiques de pr\u00e9sentation du code, qui visent \u00e0 l'uniformiser. Pour Python, cette r\u00e9f\u00e9rence s'appelle la Python Enhancement Proposal 8, plus connue sous le nom de PEP8.
En voici quelques extraits :
"},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#les-espaces","title":"Les espaces","text":"\u25b6 Il faut mettre une espace (oui, en typographie, on dit \u00abune\u00bb espace et non pas \u00abun\u00bb espace) avant et apr\u00e8s chaque op\u00e9rateur de comparaison, d'affectation, ou math\u00e9matique (=, ==, >, +, *, ...
)
# PAS BIEN \na=3\n\n# BIEN \na = 3\n
# PAS BIEN\nif x>3:\n print(\"ok\")\n\n# BIEN\nif x > 3:\n print(\"ok\")\n
\u25b6 Pour les op\u00e9rateurs math\u00e9matiques, on essaie de reconstituer les groupes de priorit\u00e9 (lorsqu'il y en a) :
# PAS BIEN\nx = 3*2\n\n# BIEN\nx = 3 * 2\n
mais
# PAS BIEN\nx = 3 * 2 + 5\n\n# BIEN\nx = 3*2 + 5\n
\u25b6 On ne met pas d'espace \u00e0 int\u00e9rieur des parenth\u00e8ses, des crochets ou des accolades :
# PAS BIEN\nfor x in range( 5 ):\n print( 'bonjour' )\n\n# BIEN\nfor x in range(5):\n print('bonjour')\n
\u25b6 Pour les virgules, et les deux points : pas d'espace avant mais une espace apr\u00e8s.
# PAS BIEN\nif color == (0,255,0) :\n print('vert')\n\n# BIEN\nif color == (0, 255, 0):\n print('vert')\n
On peut contr\u00f4ler si son code v\u00e9rifie les standards de la PEP8 sur ce site http://pep8online.com/
"},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#les-conventions-de-nommage","title":"Les conventions de nommage","text":"\u25b6 Les variables \u00e0 une lettre (comme i
, j
, k
) sont r\u00e9serv\u00e9es aux indices (notamment dans les boucles).
\u25b6 Les autres variables doivent avoir des noms explicites, \u00e9ventuellement \u00e9crits en snake_case
si plusieurs mots doivent \u00eatre reli\u00e9s.
# PAS BIEN\nif d == 1:\n cep += vm\n\n# BIEN\nif date == 1:\n compte_epargne += versement_mensuel\n
Rappel des diff\u00e9rents types de casse :
snake_case
: les mots sont s\u00e9par\u00e9s par des underscores. Conseill\u00e9 en Python.camelCase
: les mots sont s\u00e9par\u00e9s par des majuscules mais la 1\u00e8re lettre est minuscule. Conseill\u00e9 en Javascript.PascalCase
: les mots sont s\u00e9par\u00e9s par des majuscules et la 1\u00e8re lettre est majuscule. Conseill\u00e9 en C.kebab-case
: les mots sont s\u00e9par\u00e9s par des tirets courts. Conseill\u00e9 en HTML - CSS.\u25b6 Cas particulier des classes en Programmation Orient\u00e9e Objet : leur nom doit commencer par une majuscule.
# PAS BIEN\nclass voiture:\n def __init__(self, annee, marque, modele):\n #pass\n\n# BIEN\nclass Voiture:\n def __init__(self, annee, marque, modele):\n #pass\n
"},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#2-commentaires-et-docstrings","title":"2. Commentaires et docstrings","text":""},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#21-commenter-son-code-ou-pas","title":"2.1 Commenter son code ? (ou pas)","text":"La n\u00e9cessit\u00e9 de commenter son code est assez controvers\u00e9e. Il est d'usage de dire qu'un code doit \u00eatre assez explicite pour que le lecteur puisse le comprendre sans avoir \u00e0 lire un commentaire.
De fait, les commentaires sont parfois (souvent) superflus :
Et s'ils sont r\u00e9ellement n\u00e9cessaires, il faut se poser la question : est-ce que ce code n'aurait pas pu \u00eatre plus simple ? (attention, la r\u00e9ponse n'est pas toujours oui)
Exemple :
Consid\u00e9rons la fonction suivante.
def f(c, t, n):\n # c est le capital de d\u00e9part, t le taux annuel et n le nombre d'ann\u00e9es\n return c * (1 + t)**n #renvoie le capital apr\u00e8s n ann\u00e9es\n
Elle est bien comment\u00e9e. Mais si on croise la fonction f()
ailleurs dans le code, se souviendra-t-on de son r\u00f4le ? Il aurait mieux valu \u00e9crire :
def capital_apres_n_annees(capital, taux, nombre_annees) :\n return capital * (1 + taux)**nombre_annees\n
Ce code est plus long, mais assez explicite pour se passer de commentaires."},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#22-le-cas-particulier-des-docstrings","title":"2.2 Le cas particulier des docstrings
","text":""},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#221-que-sont-les-docstrings","title":"2.2.1 Que sont les docstrings
?","text":"Les docstrings
sont des commentaires normalis\u00e9s pour les fonctions, qui peuvent \u00eatre consult\u00e9s en console.
Exemples :
Nous connaissons la fonction len()
qui permet par exemple de conna\u00eetre la longueur d'une liste pass\u00e9e en param\u00e8tre.
Si nous tapons en console la commande print(len.__doc__)
, nous aurons la description de cette fonction.
>>> len.__doc__\n'Return the number of items in a container.'\n
Il est aussi possible d'acc\u00e9der \u00e0 la docstring d'une fonction f
par la commande help(f)
: >>> help(len)\nHelp on built-in function len in module builtins:\n\nlen(obj, /)\n Return the number of items in a container.\n
De m\u00eame pour la fonction range
:
>>> print(range.__doc__)\nrange(stop) -> range object\nrange(start, stop[, step]) -> range object\n\nReturn an object that produces a sequence of integers from start (inclusive)\nto stop (exclusive) by step. range(i, j) produces i, i+1, i+2, ..., j-1.\nstart defaults to 0, and stop is omitted! range(4) produces 0, 1, 2, 3.\nThese are exactly the valid indices for a list of 4 elements.\nWhen step is given, it specifies the increment (or decrement).\n
Le r\u00e9sultat de la commande help(range)
est trop long pour \u00eatre repris ici, mais on y retrouve bien la docstring de la fonction range
.
Il suffit pour cela de commencer la fonction \u00e0 documenter par une ou plusieurs phrases entre triples quotes :
def capital_apres_n_annees(capital, taux, nombre_annees) :\n\"\"\"\n Renvoie le capital apr\u00e8s n ann\u00e9es.\n capital : valeur initiale\n taux : taux d'int\u00e9r\u00eat exprim\u00e9 en nombre d\u00e9cimal (ex: 0.02 pour un taux de 2 %)\n nombre_annees : nombre d'ann\u00e9es de placement du capital\n \"\"\"\n return capital * (1 + taux)**nombre_annees\n
Ainsi, un utilisateur pourra trouver en console le mode d'emploi de notre fonction : >>> help(capital_apres_n_annees)\nHelp on function capital_apres_n_annees in module __main__:\n\ncapital_apres_n_annees(capital, taux, nombre_annees)\n Renvoie le capital apr\u00e8s n ann\u00e9es.\n capital : valeur initiale\n taux : taux d'int\u00e9r\u00eat exprim\u00e9 en nombre d\u00e9cimal (ex: 0.02 pour un taux de 2 %)\n nombre_annees : nombre d'ann\u00e9es de placement du capital\n
Comme on le voit, tout cela est tr\u00e8s \u00abverbeux\u00bb. Cela peut nous para\u00eetre largement superflu puisque nos codes d\u00e9passent rarement quelques dizaines de lignes et sont lus par rarement plus de 2 personnes. Mais dans la vraie vie des d\u00e9veloppeurs, il est primordial qu'un code soit clair et document\u00e9.
"},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#3-la-programmation-defensive-des-assert-pour-securiser-le-code","title":"3. La programmation d\u00e9fensive : desassert
pour s\u00e9curiser le code","text":"La programmation d\u00e9fensive est l'art de pr\u00e9voir le pire et d'essayer de le d\u00e9tecter avant qu'il ne soit trop tard. De mani\u00e8re bien plus concr\u00e8te, il est d'usage d'essayer de r\u00e9p\u00e9rer si des donn\u00e9es (souvent des param\u00e8tres d'une fonction) sont susceptibles de cr\u00e9er des probl\u00e8mes, ou sont hors sp\u00e9cification.
Un exemple :
La fonction :
def racine_carree(x):\n assert x >= 0, 'un nombre positif ou nul est requis'\n return x ** 0.5\n
donnera, lors de l'appel \u00e0 racine_carree(-2)
, le message suivant : >>> racine_carree(-2)\nTraceback (most recent call last):\n File \"<pyshell>\", line 1, in <module>\n File \"/home/gilles/Bureau/exemples_assert.py\", line 2, in racine_carree\n assert x >= 0, 'un nombre positif ou nul est requis'\nAssertionError: un nombre positif ou nul est requis\n
Un autre exemple :
def moyenne_trimestrielle(liste_notes):\n\"\"\"\n calcule la moyenne des nombres de la liste liste_notes\n \"\"\"\n assert liste_notes != [] , 'liste vide'\n assert max(liste_notes) <= 20, 'au moins une note d\u00e9passe 20'\n assert min(liste_notes) >=0, 'au moins une note est en dessous de 0'\n\n return sum(liste_notes) / len(liste_notes)\n
\u00c0 ce stade, les assert
sont donc pour nous juste un moyen rapide de remplacer un test if ... then ... else
pour d\u00e9tecter des erreurs potentielles. Ils sont en r\u00e9alit\u00e9 plus utiles que cela : lors de la conception d'un programme, des assert
sont pos\u00e9s pour v\u00e9rifier l'int\u00e9grit\u00e9 du code, mais peuvent \u00eatre d\u00e9sactiv\u00e9s \u00e0 tout moment pour en faire un code optimis\u00e9 (par la commande -O
\u00e0 l'ex\u00e9cution). Tout ceci d\u00e9passe largement le cadre de notre cours.
Il est \u00e0 noter aussi que les erreurs peuvent \u00eatre g\u00e9r\u00e9es par le m\u00e9canisme try ... except
, qui permet de \u00ablever des exceptions\u00bb. Pour les curieux, plus de renseignements ici.
Tester une fonction est la premi\u00e8re chose que l'on fait (normalement...) lorsqu'on vient de finir de l'\u00e9crire.
Par exemple, si on vient de construire la fonction valeur_absolue(n)
, il est fort probable qu'on aille taper ceci dans la console :
>>> valeur_absolue(-3)\n3\n>>> valeur_absolue(0)\n0\n>>> valeur_absolue(7)\n7\n
test_valeur_absolue()
.test_valeur_absolue()
avant m\u00eame de commencer \u00e0 \u00e9crire la fonction valeur_absolue(n)
.Remarque : la m\u00e9thode de d\u00e9veloppement logiciel TDD (Test Driven Developement) est bas\u00e9e en partie sur ce principe :
Revenons \u00e0 nos tests sur la fonction valeur_absolue(n)
def test_valeur_absolue():\n if valeur_absolue(-3) == 3 :\n print(\"ok\")\n else:\n print(\"erreur\")\n\n if valeur_absolue(0) == 0 :\n print(\"ok\")\n else:\n print(\"erreur\")\n\n if valeur_absolue(7) == 7 :\n print(\"ok\")\n else:\n print(\"erreur\")\n
En console, il suffit maintenant d'appeler la fonction test_valeur_absolue()
:
>>> test_valeur_absolue()\nok\nok\nok\n
"},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#42-revoila-les-assert","title":"4.2 Revoil\u00e0 les assert
","text":"Utiliser des assert
permet d'\u00e9crire tr\u00e8s simplement les tests pr\u00e9c\u00e9dents.
Reprenons notre fonction valeur_absolue()
. Sa fonction test test_valeur_absolue()
peut s'\u00e9crire :
def test_valeur_absolue():\n assert valeur_absolue(-3) == 3\n assert valeur_absolue(0) == 0\n assert valeur_absolue(7) == 7\n
Exercice : \u00c9crire une fonction maxi(liste)
qui renvoie le plus grand \u00e9l\u00e9ment de la liste liste
pass\u00e9e en param\u00e8tre (de pr\u00e9f\u00e9rence sans utiliser la fonction max()
...). Vous \u00e9crirez d'abord une fonction test_maxi()
avant d'\u00e9crire la fonction maxi(liste)
doctest
","text":"Le module doctest
permet d'\u00e9crire les tests \u00e0 l'int\u00e9rieur de la docstring d'une fonction.
Consid\u00e9rons une fonction dont le but est de compter les voyelles du mot pass\u00e9 en param\u00e8tre.
def compte_voyelles(mot):\n\"\"\"\n renvoie le nombre de voyelles du mot donn\u00e9 en param\u00e8tre.\n >>> compte_voyelles(\"python\")\n 2\n >>> compte_voyelles(\"HTTP\")\n 0\n >>> compte_voyelles(\"eau\")\n 3\n \"\"\"\n voyelles = \"aeiou\"\n total = 0\n for lettre in mot:\n if lettre in voyelles:\n total += 1\n return total\n
Observez bien la docstring : elle contient explicitement ce qu'on veut que renvoie le terminal lorsqu'on appellera la fonction. On \u00e9crit donc les trois chevrons >>>
suivi de l'appel \u00e0 la fonction, et \u00e0 la ligne en dessous ce que nous esp\u00e9rons que la fonction nous renvoie. On peut \u00e9crire autant de tests que l'on veut.
Ensuite, en console :
>>> import doctest\n>>> doctest.testmod()\n
Dans notre cas, le retour sera celui-ci : >>> import doctest\n>>> doctest.testmod()\n**********************************************************************\nFile \"voyelles.py\", line 4, in __main__.compte_voyelles\nFailed example:\n compte_voyelles(\"python\")\nExpected:\n 2\nGot:\n 1\n**********************************************************************\n1 items had failures:\n 1 of 3 in __main__.compte_voyelles\n***Test Failed*** 1 failures.\nTestResults(failed=1, attempted=3)\n
On voit que le test compte_voyelles(\"python\")
a renvoy\u00e9 la valeur 1 alors qu'on attendait 2. En regardant notre fonction, on s'aper\u00e7oit donc qu'on avait oubli\u00e9 le y
dans la liste des voyelles.
En corrigeant ceci, le test devient :
>>> import doctest\n>>> doctest.testmod()\nTestResults(failed=0, attempted=3)\n
Ce qui est beaucoup plus satisfaisant."},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#43-a-propos-des-tests","title":"4.3 \u00c0 propos des tests","text":"Le comportement face aux tests en programmation doit \u00eatre le m\u00eame qu'en math\u00e9matiques : un test qui ne marche pas est plus riche d'enseignements qu'un test qui marche.
En math\u00e9matiques, seule la notion de contre-exemple est fertile : si quelqu'un vous affirme que \u00abtous les nombres impairs sont premiers\u00bb, il vous suffit d'exhiber le nombre 9 pour lui prouver qu'il a tort et achever la discussion.
Par contre, il aurait pu essayer de vous convaincre avec les nombres 3, 5 et 13, qui sont bien impairs et premiers.
De la m\u00eame mani\u00e8re, voir qu'une fonction passe les tests que vous avez \u00e9crits ne vous assurera pas que cette fonction aura toujours le bon comportement souhait\u00e9. Elle l'aura pour les valeurs de test, mais pas forc\u00e9ment pour les autres.
En revanche, si une fonction ne passe pas un des tests, vous avez la certitude qu'il y a un probl\u00e8me \u00e0 r\u00e9gler quelque part.
Tout ceci en admettant, bien s\u00fbr, que vos tests eux-m\u00eames ne comportent pas d'erreurs...
"},{"location":"T2_Programmation/2.4_Pratiques_de_programmation/cours/#bibliographie","title":"Bibliographie","text":"Nous avons vu en classe de Premi\u00e8re l'algorithme de dichotomie (du grec dikhotomia, \u00ab division en deux parties \u00bb).
Notre but ici est la recherche de la pr\u00e9sence (ou non) d'un \u00e9l\u00e9ment dans une liste tri\u00e9e. Notre fonction renverra donc un bool\u00e9en.
La recherche na\u00efve (\u00e9l\u00e9ment par \u00e9l\u00e9ment) est naturellement de complexit\u00e9 lin\u00e9aire. Nous allons voir que la m\u00e9thode dichotomique est plus efficace.
Activit\u00e9 d'introduction
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#11-version-imperative","title":"1.1 Version imp\u00e9rative","text":"Dichotomie version imp\u00e9rative
def recherche_dichotomique(tab, val) :\n'''\n renvoie True ou False suivant la pr\u00e9sence de la valeur val dans le tableau tri\u00e9 tab.\n '''\n i_debut = 0\n i_fin = len(tab) - 1\n while i_debut <= i_fin :\n i_centre = (i_debut + i_fin) // 2 # (1)\n val_centrale = tab[i_centre] # (2) \n if val_centrale == val: # (3) \n return True\n if val_centrale < val: # (4) \n i_debut = i_centre + 1 # (5) \n else :\n i_fin = i_centre - 1\n return False\n
Exemple d'utilisation :
>>> tab = [1, 5, 7, 9, 12, 13]\n>>> recherche_dichotomique(tab, 12)\nTrue\n>>> recherche_dichotomique(tab, 17)\nFalse\n
\u00c0 chaque tour de la boucle while
, la taille de la liste est divis\u00e9e par 2. Ceci conf\u00e8re \u00e0 cet algorithme une complexit\u00e9 logarithmique (bien meilleure qu'une complexit\u00e9 lin\u00e9aire).
Pour \u00e9crire simplement la version r\u00e9cursive de cet algorithme, nous allons avoir besoin de faire du slicing (d\u00e9coupage) de listes. Cette manipulation n'est pas au programme de NSI (m\u00eame si elle est tr\u00e8s simple). Attention, elle a un co\u00fbt algorithmique important, qui peut fausser notre analyse de complexit\u00e9.
Exemples de slicing :
>>> lst = ['a', 'b', 'c', 'd', 'e']\n>>> lst[:2]\n['a', 'b']\n>>> lst[2:]\n['c', 'd', 'e']\n
On comprend que :
lst[:k]
va renvoyer la sous-liste compos\u00e9e du premier \u00e9l\u00e9ment jusqu'\u00e0 celui d'indice k
non inclus.lst[k:]
va renvoyer la sous-liste compos\u00e9e du k
-i\u00e8me \u00e9l\u00e9ment (inclus) jusqu'au dernier.lst[k:p]
va renvoyer la sous-liste compos\u00e9e du k
-i\u00e8me \u00e9l\u00e9ment (inclus) jusqu'au p
-i\u00e8me (non inclus).Dichotomie version r\u00e9cursive avec slicing
def dichotomie_rec(tab, val):\n if len(tab) == 0:\n return False\n i_centre = len(tab) // 2\n if tab[i_centre] == val:\n return True\n if tab[i_centre] < val:\n return dichotomie_rec(tab[i_centre + 1:], val) # (1)\n else:\n return dichotomie_rec(tab[:i_centre], val) # (2)\n
Exemple d'utilisation :
>>> tab = [1, 5, 7, 9, 12, 13]\n>>> dichotomie_rec(tab, 12)\nTrue\n>>> dichotomie_rec(tab, 17)\nFalse\n
Visualisation gr\u00e2ce \u00e0 PythonTutor: "},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#123-dichotomie-recursive-sans-slicing","title":"1.2.3 Dichotomie r\u00e9cursive sans slicing","text":"
Il est possible de programmer de mani\u00e8re r\u00e9cursive la recherche dichotomique sans toucher \u00e0 la liste, et donc en jouant uniquement sur les indices :
Dichotomie version r\u00e9cursive sans slicing
def dicho_rec_2(tab, val, i=0, j=None): # (1)\n if j is None: # (2)\n j = len(tab)-1\n if i > j :\n return False\n m = (i + j) // 2\n if tab[m] < val :\n return dicho_rec_2(tab, val, m + 1, j)\n elif tab[m] > val :\n return dicho_rec_2(tab, val, i, m - 1 )\n else :\n return True\n
j=len(tab)-1
par d\u00e9faut (car tab
est aussi un param\u00e8tre). On passe donc par une autre valeur (ici None
) qu'on va ici intercepter.Exemple d'utilisation :
>>> tab = [1, 5, 7, 9, 12, 13]\n>>> dicho_rec_2(tab, 12)\nTrue\n>>> dicho_rec_2(tab, 17)\nFalse\n
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#2-diviser-pour-regner","title":"2. Diviser pour r\u00e9gner","text":"Les algorithmes de dichotomie pr\u00e9sent\u00e9s ci-dessous ont tous en commun de diviser par deux la taille des donn\u00e9es de travail \u00e0 chaque \u00e9tape. Cette m\u00e9thode de r\u00e9solution d'un probl\u00e8me est connue sous le nom de diviser pour r\u00e9gner, ou divide and conquer en anglais.
Une d\u00e9finition pourrait \u00eatre :
D\u00e9finition
Un probl\u00e8me peut se r\u00e9soudre en employant le paradigme diviser pour r\u00e9gner lorsque :
Remarques :
Consid\u00e9rons de l'\u00e9criture r\u00e9cursive de la fonction factorielle
ci-dessous :
def factorielle(n):\n if n == 0:\n return 1\n else:\n return n * factorielle(n-1)\n
On ne peut pas parler ici de diviser pour r\u00e9gner car la taille des donn\u00e9es \u00e0 traiter est pass\u00e9e de n \u00e0 n-1. C'est bien une diminution (qui fait que l'algorithme fonctionne) mais il n'y a pas de division de la taille des donn\u00e9es. C'est cette division (par 2 dans le cas de la dichotomie) qui donne son efficacit\u00e9 \u00e0 ce paradigme. Le paradigme diviser pour r\u00e9gner va naturellement amener \u00e0 r\u00e9diger des programmes r\u00e9cursifs.
On appelle exponentiation le fait de mettre en puissance un nombre. On va donc coder, de deux mani\u00e8res diff\u00e9rentes, la puissance d'un nombre.
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#31-algorithme-classique","title":"3.1 Algorithme classique","text":"Exponentiation classique
def puissance(a, n):\n if n == 0:\n return 1\n else:\n return a * puissance(a, n-1)\n
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#32-algorithme-utilisant-diviser-pour-regner","title":"3.2 Algorithme utilisant diviser pour r\u00e9gner","text":"Nous allons nous appuyer sur la remarque math\u00e9matique suivante : Pour tout nombre \\(a\\),
si \\(n\\) est pair, \\(a^n = (a^2)^{\\frac{n}{2}}\\)
si \\(n\\) est impair, \\(a^n = a \\times a^{n-1} = a \\times (a^2)^{\\frac{n-1}{2}}\\)
Ainsi, dans le cas o\u00f9 \\(n\\) est pair, il suffit d'\u00e9lever \\(a\\) au carr\u00e9 (une seule op\u00e9ration) pour que l'exposant diminue de moiti\u00e9. On peut donc programmer la fonction puissance
en utilisant le paradigme diviser pour r\u00e9gner :
Exponentiation rapide
def puissance_mod(a, n):\n if n == 0:\n return 1\n if n % 2 == 0:\n return puissance_mod(a*a, n//2)\n else:\n return a * puissance_mod(a*a, (n-1)//2)\n
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#33-comparaison-de-la-vitesse-dexecution-des-deux-algorithmes","title":"3.3 Comparaison de la vitesse d'ex\u00e9cution des deux algorithmes","text":"Exercice
\u00c9nonc\u00e9CorrectionRecr\u00e9er le graphique ci-dessus, qui compare les temps d'ex\u00e9cution des deux fonctions puissance
et puissance_mod
.
Aide pour Matplotlib : le code ci-dessous
import matplotlib.pyplot as plt\n\ndef carre(x):\n return x*x\n\nx = list(range(10))\ny = [carre(k) for k in x]\nplt.plot(x, y)\nplt.show()\n
donne le graphique suivant :
import matplotlib.pyplot as plt\nimport time\n\ndef puissance(a, n):\n if n == 0:\n return 1\n else:\n return a * puissance(a, n-1)\n\n\ndef puissance_mod(a, n):\n if n == 0:\n return 1\n if n % 2 == 0:\n return puissance_mod(a*a, n//2)\n else:\n return a * puissance_mod(a*a, (n-1)//2)\n\n\ndef mesure_puissance(n):\n t0 = time.time()\n p = puissance(3,n)\n return time.time()-t0\n\ndef mesure_puissance_mod(n):\n t0 = time.time()\n p = puissance_mod(3,n)\n return time.time()-t0\n
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#4-le-tri-fusion","title":"4. Le tri-fusion","text":"En anglais le merge sort.
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#41-preambule-linterclassement","title":"4.1 Preambule : l'interclassement","text":"Le m\u00e9canisme principal du tri fusion est la fusion de deux listes tri\u00e9es en une nouvelle liste elle aussi tri\u00e9e.
On appelera ce m\u00e9canisme l'interclassement.
Principe de l'interclassement de deux listes lst1
et lst2
.
lst_totale
lst1
et lst2
. Il faut pour cela g\u00e9rer s\u00e9par\u00e9ment un indice i1
pour la liste lst1
et un indice i2
pour la liste i2
.Exercice
\u00c9nonc\u00e9CorrectionCoder la fonction interclassement
.
def interclassement(lst1, lst2):\n i1 = 0\n i2 = 0\n lst_totale = []\n while i1 != len(lst1) and i2 != len(lst2):\n if lst1[i1] < lst2[i2]:\n lst_totale.append(lst1[i1])\n i1 += 1\n else:\n lst_totale.append(lst2[i2])\n i2 += 1\n return lst_totale + lst1[i1:] + lst2[i2:]\n
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#42-la-fusion","title":"4.2 La fusion","text":""},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#421-principe","title":"4.2.1 Principe","text":"L'id\u00e9e du tri fusion est le d\u00e9coupage de la liste originale en une multitude de listes ne contenant qu'un seul \u00e9l\u00e9ment. Ces listes \u00e9l\u00e9mentaires seront ensuite interclass\u00e9es avec la fonction pr\u00e9c\u00e9dente.
Principe de l'algorithme du tri fusion :
La grande force de ce tri va \u00eatre qu'il se programme simplement de mani\u00e8re r\u00e9cursive, en appelant \u00e0 chaque \u00e9tape la m\u00eame fonction mais avec une taille de liste divis\u00e9e par deux, ce qui justifie son classement parmi les algorithmes utilisants \u00abdiviser pour r\u00e9gner\u00bb.
Algorithme de tri fusion (merge sort)
def interclassement(lst1, lst2):\n lst_totale = []\n n1, n2 = len(lst1), len(lst2)\n i1, i2 = 0, 0\n while i1 < n1 and i2 < n2:\n if lst1[i1] < lst2[i2]:\n lst_totale.append(lst1[i1])\n i1 += 1\n else:\n lst_totale.append(lst2[i2])\n i2 += 1\n return lst_totale + lst1[i1:] + lst2[i2:]\n\ndef tri_fusion(lst):\n if len(lst) <= 1:\n return lst\n else:\n m = len(lst) // 2\n return interclassement(tri_fusion(lst[:m]), tri_fusion(lst[m:]))\n
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#423-visualisation","title":"4.2.3 Visualisation","text":"Une erreur classique avec les fonctions r\u00e9cursives est de consid\u00e9rer que les appels r\u00e9cursifs sont simultan\u00e9s. Ceci est faux ! L'animation suivante montre la progression du tri :
Il est aussi conseill\u00e9 d'observer l'\u00e9volution de l'algorithme gr\u00e2ce \u00e0 PythonTutor :
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/cours/#43-complexite","title":"4.3 Complexit\u00e9","text":"La division par 2 de la taille de la liste pourrait nous amener \u00e0 penser que le tri fusion est de complexit\u00e9 logarithmique, comme l'algorithme de dichotomie. Il n'en est rien.
En effet, l'instruction finale interclassement(tri_fusion(lst[:m]), tri_fusion(lst[m:]))
lance deux appels \u00e0 la fonction tri_fusion
(avec certe des donn\u00e9es d'entr\u00e9e deux fois plus petites).
On peut montrer que :
Complexit\u00e9 du tri fusion
L'algorithme de tri fusion est en \\(O(n \\log n)\\).
On dit qu'il est quasi-lin\u00e9aire. (ou lin\u00e9arithmique)
Une complexit\u00e9 quasi-lin\u00e9aire (en \\(O(n \\log n)\\)) se situe \u00abentre\u00bb une complexit\u00e9 lin\u00e9aire (en \\(O(n)\\)) et une complexit\u00e9 quadratique (en \\(O(n^2)\\)). Mais elle est plus proche de la complexit\u00e9 lin\u00e9aire.
Une jolie animation permettant de comparer les tris :
Issue de ce site
"},{"location":"T3_Algorithmique/3.1_Diviser_pour_regner/intro_dichotomie/","title":"Vers l'algorithme de dichotomie","text":"Exemple d'utilisation :
>>> tab = [1, 5, 7, 9, 12, 13]\n>>> recherche_dichotomique(tab, 12)\nTrue\n>>> recherche_dichotomique(tab, 17)\nFalse\n
Code \u00e0 trous, newbie version def recherche_dichotomique(tab, val) :\n'''\n renvoie True ou False suivant la pr\u00e9sence de la valeur val dans le tableau tri\u00e9 tab.\n '''\n i_debut = ...\n i_fin = ...\n while ... <= ... :\n i_centre = (... + ...) // 2 \n val_centrale = tab[...] \n if val_centrale == val: \n return ...\n if val_centrale < val: \n i_debut = ... + 1 \n else :\n i_fin = ... - 1\n return False\n
Code \u00e0 trous, regular version def recherche_dichotomique(tab, val) :\n'''\n renvoie True ou False suivant la pr\u00e9sence de la valeur val dans le tableau tri\u00e9 tab.\n '''\n i_debut = ...\n i_fin = ...\n while ... <= ... :\n i_centre = ... \n val_centrale = ... \n if ... == ... : \n return ...\n if ... < ...: \n i_debut = ... \n else :\n i_fin = ...\n return False\n
Code \u00e0 trous, expert version def recherche_dichotomique(tab, val) :\n'''\n renvoie True ou False suivant la pr\u00e9sence de la valeur val dans le tableau tri\u00e9 tab.\n '''\n ... = ...\n ... = ...\n while ... <= ... :\n ... = ... \n ... = ... \n if ... == ... : \n return ...\n if ... < ...: \n ... = ... \n else :\n ... = ...\n return False\n
Code \u00e0 trous, God version def recherche_dichotomique(tab, val) :\n ...\n
Pour tester :
>>> tab = [1, 5, 7, 9, 12, 13]\n>>> recherche_dichotomique(tab, 12)\nTrue\n>>> recherche_dichotomique(tab, 17)\nFalse\n
"},{"location":"T3_Algorithmique/3.2_Programmation_dynamique/cours/","title":"Programmation dynamique","text":""},{"location":"T3_Algorithmique/3.2_Programmation_dynamique/exercices/","title":"Exercices de programmation dynamique","text":""},{"location":"T3_Algorithmique/3.2_Programmation_dynamique/exercices/#exercice-1","title":"Exercice 1","text":"Exercice 5 du sujet M\u00e9tropole J2 2022
Correction Q1.cellule = Cellule(True, False, True, True)\n
Correction Q2. class Labyrinthe:\n def __init__(self, hauteur, longueur):\n self.grille = self.construire_grille(hauteur, longueur)\n\n def construire_grille(self, hauteur, longueur):\n grille = []\nfor i in range(hauteur):\nligne = []\nfor j in range(longueur):\ncellule = Cellule(True, True, True, True)\nligne.append(cellule)\ngrille.append(ligne)\n return grille\n
Correction Q3. cellule2.murs['S'] = False\n
Correction Q4. elif c1_lig == c2_lig and c1_col - c2_col == 1:\n cellule1.murs['O'] = False\n cellule2.murs['E'] = False\n
Correction Q5. def creer_labyrinthe(self, ligne, colonne, haut, long):\n if haut == 1 : # Cas de base\nfor k in range(colonne, colonne + long - 1):\nself.creer_passage(ligne, k, ligne, k + 1)\n elif long == 1: # Cas de base\nfor k in range(ligne, ligne + haut - 1):\nself.creer_passage(k, colonne, k + 1, colonne)\nelse: # Appels r\u00e9cursifs\n # Code non \u00e9tudi\u00e9 (Ne pas compl\u00e9ter)\n
Correction Q6. "},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/","title":"Recherche textuelle","text":""},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/#1-recherche-naive","title":"1. Recherche na\u00efve","text":"Illustration de l'algorithme Vous pouvez contr\u00f4ler le d\u00e9roulement de l'animation en la survolant avec la souris.
"},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/#11-premier-algorithme","title":"1.1 Premier algorithme","text":"Algorithme de recherche na\u00efve
def recherche_naive(texte, motif):\n'''\n renvoie la liste des indices (\u00e9ventuellement vide) des occurrences de\n de la cha\u00eene motif dans la cha\u00eene texte.\n '''\n indices = []\n i = 0\n while i <= len(texte) - len(motif):\n k = 0\n while k < len(motif) and texte[i+k] == motif[k]:\n k += 1\n if k == len(motif):\n indices.append(i)\n i += 1\n\n return indices\n
Exemple d'utilisation :
>>> recherche_naive(\"une magnifique maison bleue\", \"maison\")\n[15]\n>>> recherche_naive(\"une magnifique maison bleue\", \"nsi\")\n[]\n>>> recherche_naive(\"une magnifique maison bleue\", \"ma\")\n[4, 15]\n
"},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/#12-modification-de-lalgorithme","title":"1.2 Modification de l'algorithme","text":"Exercice 1
\u00c9nonc\u00e9CorrectionRe-\u00e9crire l'algorithme pr\u00e9c\u00e9dent en s'arr\u00eatant d\u00e8s qu'une occurrence de motif
est trouv\u00e9e dans texte
.
La fonction renverra uniquement un bool\u00e9en.
def recherche_naive_bool(texte, motif):\n'''\n renvoie un bool\u00e9en indiquant la pr\u00e9sence ou non de\n la cha\u00eene motif dans la cha\u00eene texte.\n '''\n trouve = False\n i = 0\n while i <= len(texte) - len(motif) and not trouve:\n k = 0\n while k < len(motif) and texte[i+k] == motif[k]:\n k += 1\n if k == len(motif):\n trouve = True\n i += 1\n\n return trouve\n
"},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/#13-application-a-la-recherche-dun-motif-dans-un-roman","title":"1.3 Application \u00e0 la recherche d'un motif dans un roman","text":"Le Projet Gutenberg permet de t\u00e9l\u00e9charger l\u00e9galement des ouvrages libres de droits dans diff\u00e9rents formats.
Nous allons travailler avec le Tome 1 du roman Les Mis\u00e9rables de Victor Hugo, \u00e0 t\u00e9l\u00e9charger ici au format txt
.
with open(\"Les_Miserables.txt\") as f:\n roman = f.read().replace('\\n', ' ')\n
"},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/#132-verification-et-mesure-du-temps-de-recherche","title":"1.3.2 V\u00e9rification et mesure du temps de recherche","text":"Exercice 2
\u00c9nonc\u00e9Correction\u00c0 l'aide du module time
, mesurer le temps de recherche dans Les Mis\u00e9rables d'un mot court, d'une longue phrase (pr\u00e9sente dans le texte), d'un mot qui n'existe pas. Que remarquez-vous ?
t0 = time.time()\nmotif = \"maison\"\nprint(recherche_naive(roman, motif))\nprint(time.time()-t0)\n\nt0 = time.time()\nmotif = \"La chandelle \u00e9tait sur la chemin\u00e9e et ne donnait que peu de clart\u00e9.\"\nprint(recherche_naive(roman, motif))\nprint(time.time()-t0)\n\nt0 = time.time()\nmotif = \"parcoursup\"\nprint(recherche_naive(roman, motif))\nprint(time.time()-t0)\n
retour console :
[7264, 9090, 9547, 9745, 10936, 17820, 23978, 38192, 41639, 41651, 41840, 42493, 48028, 48393, 51448, 53353, 70867, 72692, 72768, 75608, 77855, 108489, 115739, 130629, 132983, 138870, 143681, 144600, 153114, 155973, 158709, 160700, 163649, 169164, 169181, 171761, 171967, 182642, 186413, 190534, 219378, 220314, 224518, 225098, 227579, 296302, 345108, 345893, 346740, 349677, 359727, 362025, 389945, 395690, 434118, 438068, 457795, 457886, 464696, 469403, 501768, 514980, 520667, 520878, 520926, 520968, 522707, 529329, 598128, 601390, 645915]\n0.21963715553283691\n[651731]\n0.21761441230773926\n[]\n0.22150230407714844\n
On remarque que le temps de recherche est semblable, quel que soit le motif cherch\u00e9.
"},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/#2-vers-lalgorithme-de-boyer-moore-et-si-on-partait-a-lenvers","title":"2. Vers l'algorithme de Boyer-Moore : et si on partait \u00e0 l'envers ?","text":"Exercice 3
\u00c9nonc\u00e9CorrectionRe-\u00e9crire l'algorithme de recherche na\u00efve mais en d\u00e9marrant de la fin du motif et non du d\u00e9but. Certes, c'est pour l'instant tr\u00e8s artificiel, mais :
def presqueBMH(texte, motif):\n indices = []\n i = len(motif) -1\n while i < len(texte):\n k = 0\n while k < len(motif) and motif[len(motif)-1-k] == texte[i-k]:\n k += 1\n if k == len(motif):\n indices.append(i-len(motif)+1)\n i += 1\n return indices\n
"},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/#3-algorithme-de-boyer-moore-horspool","title":"3. Algorithme de Boyer-Moore-Horspool","text":""},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/#21-principe","title":"2.1 Principe","text":"L'id\u00e9e est d'am\u00e9liorer le code pr\u00e9c\u00e9dent (celui on parcourt le motif \u00e0 l'envers) en sautant directement au prochain endroit potentiellement valide.
Pour cela on regarde le caract\u00e8re X
du texte sur lequel on s'est arr\u00eat\u00e9 (car X
n'\u00e9tait pas \u00e9gal au caract\u00e8re de rang \u00e9quivalent dans le motif):
X
n'est pas dans le motif, il est inutile de se d\u00e9placer \"de 1\" : on retomberait tout de suite sur X
, c'est du temps perdu. On se d\u00e9cale donc juste assez pour d\u00e9passer X
, donc de la longueur du motif cherch\u00e9.X
est dans le motif (sauf \u00e0 la derni\u00e8re place du motif !), on va regarder la place de la derni\u00e8re occurence de X
dans le motif et de d\u00e9placer de ce nombre, afin de faire co\u00efncider le X
du motif et le X
du texte.Vous pouvez contr\u00f4ler le d\u00e9roulement de l'animation en la survolant avec la souris.
"},{"location":"T3_Algorithmique/3.3_Recherche_textuelle/cours/#22-implementation","title":"2.2 Impl\u00e9mentation","text":"On va d'abord coder une fonction dico_lettres
qui renvoie un dictionnaire associant \u00e0 chaque lettre de mot
(param\u00e8tre d'entr\u00e9e) son dernier rang dans le mot
. On exclut la derni\u00e8re lettre, qui poserait un probl\u00e8me lors du d\u00e9calage (on d\u00e9calerait de 0...)
Algorithme de Boyer-Moore-Horspool
def dico_lettres(mot):\n d = {}\n for i in range(len(mot)-1):\n d[mot[i]] = i\n return d\n\ndef BMH(texte, motif):\n dico = dico_lettres(motif)\n indices = []\n i = len(motif) -1\n while i < len(texte):\n k = 0\n while k < len(motif) and motif[len(motif)-1-k] == texte[i-k]: #(1)\n k += 1\n if k == len(motif): #(2)\n indices.append(i-len(motif)+1)\n i += 1 #(3)\n else:\n if texte[i-k] in dico: (#4)\n i = max(i - k + len(motif) - dico[texte[i-k]] - 1, i+1) #(5)\n else:\n i = i - k + len(motif) #(6)\n\n return indices\n
Exemple d'utilisation :
>>> BMH(\"une magnifique maison bleue\", \"maison\")\n[15]\n>>> BMH(\"une magnifique maison bleue\", \"nsi\")\n[]\n>>> BMH(\"une magnifique maison bleue\", \"ma\")\n[4, 15]\n
Exercice 4
\u00c9nonc\u00e9CorrectionReprendre les mesures effectu\u00e9es sur Les Mis\u00e9rables, mais cette fois avec l'algorithme BMH. Que remarquez-vous ?
t0 = time.time()\nmotif = \"maison\"\nprint(BMH(roman, motif))\nprint(time.time()-t0)\n\nt0 = time.time()\nmotif = \"La chandelle \u00e9tait sur la chemin\u00e9e et ne donnait que peu de clart\u00e9.\"\nprint(BMH(roman, motif))\nprint(time.time()-t0)\n\nt0 = time.time()\nmotif = \"parcoursup\"\nprint(BMH(roman, motif))\nprint(time.time()-t0)\n
retour console :
[7264, 9090, 9547, 9745, 10936, 17820, 23978, 38192, 41639, 41651, 41840, 42493, 48028, 48393, 51448, 53353, 70867, 72692, 72768, 75608, 77855, 108489, 115739, 130629, 132983, 138870, 143681, 144600, 153114, 155973, 158709, 160700, 163649, 169164, 169181, 171761, 171967, 182642, 186413, 190534, 219378, 220314, 224518, 225098, 227579, 296302, 345108, 345893, 346740, 349677, 359727, 362025, 389945, 395690, 434118, 438068, 457795, 457886, 464696, 469403, 501768, 514980, 520667, 520878, 520926, 520968, 522707, 529329, 598128, 601390, 645915]\n0.06359553337097168\n[651731]\n0.01853322982788086\n[]\n0.037064313888549805\n
On constate quelque chose de remarquable (et qui peut \u00eatre \u00e0 premi\u00e8re vue contre-intuitif) :
Plus le motif recherch\u00e9 est long, plus la recherche est rapide.
"},{"location":"T4_Bases_de_donnees/sommaire/","title":"Sommaire","text":"Lorsqu'une grande quantit\u00e9 de donn\u00e9es doit \u00eatre g\u00e9r\u00e9e, il faut savoir distinguer deux choses :
Par exemple, si je souhaite stocker toutes les temp\u00e9ratures relev\u00e9es dans mon jardin tous les matins \u00e0 07h00, je sais que mes donn\u00e9es seront des couples (date, temperature)
. \u00c9ventuellement ces dates seront regroup\u00e9es par mois, ou par saison... mais la structure des donn\u00e9es sera quand m\u00eame simple et lin\u00e9aire. Pour g\u00e9rer ces donn\u00e9es, je peux : les \u00e9crire \u00e0 la main dans mon agenda, cr\u00e9er un feuille de tableur avec Excel ou LibreOffice, utiliser une liste dans un IDE Python,... Chaque m\u00e9thode aura ses avantages et ses inconv\u00e9nients.
Si le nombre de donn\u00e9es \u00e0 stocker devient tr\u00e8s grand, est-ce que ma solution choisie pourra les g\u00e9rer ? (on peut par exemple m\u00e9diter sur le cas du Royaume-Uni dont le comptage des patients positifs au Covid est devenu faux car il a d\u00e9pass\u00e9 les limites de leur feuille Excel)
Est-ce que d'autres personnes que moi sont susceptibles de consulter ou modifier ces donn\u00e9es, \u00e9ventuellement en m\u00eame temps que moi ?
Si une donn\u00e9e se retrouve \u00e0 plusieurs endroits dans mes donn\u00e9es, devrais-je aller modifier cette donn\u00e9e partout o\u00f9 elle se trouve ou bien une seule fois ?
L'\u00e9tude des Bases de Donn\u00e9es tente d'apporter des r\u00e9ponses \u00e0 toutes ces questions.
"},{"location":"T4_Bases_de_donnees/4.1_Modele_relationnel/cours/#1-le-modele-relationnel","title":"1. Le mod\u00e8le relationnel","text":"Le programme de Terminale NSI pr\u00e9voit uniquement l'\u00e9tude du mod\u00e8le relationnel.
Th\u00e9oris\u00e9 en 1970 par le Britannique Edgard J. Codd, le mod\u00e8le relationnel est \u00e0 ce jour le mod\u00e8le de base de donn\u00e9es le plus utilis\u00e9, m\u00eame si l'\u00e8re actuelle du Big Data tend \u00e0 mettre en avant d'autres mod\u00e8les non relationnels (nous en reparlerons).
Les principes de base du mod\u00e8le relationnel
Un mod\u00e8le relationnel est donc bas\u00e9 sur des... relations.
"},{"location":"T4_Bases_de_donnees/4.1_Modele_relationnel/cours/#2-premiere-relation","title":"2. Premi\u00e8re relation","text":"Prenons l'exemple d'une biblioth\u00e8que dont la base de donn\u00e9es poss\u00e8de une relation \u00ablivres\u00bb :
Vocabulaire
Int
, Float
, String
). L'attribut \u00ab\u00c9diteur\u00bb est une cha\u00eene de caract\u00e8res, son domaine est donc String
. Par contre l'attribut \u00abISBN\u00bb est un nombre de 13 chiffres, commen\u00e7ant manifestement par 978. Son domaine est donc Int
.((Code, Entier), (Titre, Cha\u00eene de caract\u00e8res), (Auteur, Cha\u00eene de caract\u00e8res), (\u00c9diteur, Cha\u00eene de caract\u00e8res), (ISBN, Entier))
Cl\u00e9 primaire
Une cl\u00e9 primaire est un attribut (ou une r\u00e9union d'attributs) dont la connaissance suffit \u00e0 identifier avec certitude un unique enregistrement.
Par exemple, la cl\u00e9 primaire de la relation des personnes n\u00e9es en France pourrait \u00eatre leur num\u00e9ro de S\u00e9curit\u00e9 Sociale.
Observons, dans notre relation pr\u00e9c\u00e9dente, ce qui peut \u00eatre une cl\u00e9 primaire et ce qui ne peut pas l'\u00eatre.
Alors, quelle cl\u00e9 primaire choisir ? Il faut pour cela r\u00e9fl\u00e9chir \u00e0 ce que deviendrait notre relation si elle contenait 1000 livres au lieu de 10. Il est fort probable que deux livres aient alors le m\u00eame auteur : l'attribut \u00abAuteur\u00bb ne serait donc plus une cl\u00e9 primaire. Il peut arriver aussi que deux livres aient le m\u00eame titre : l'attribut \u00abTitre\u00bb n'est donc pas une bonne cl\u00e9 primaire.
Par d\u00e9finition, l'attribut \u00abISBN\u00bb pourrait jouer le r\u00f4le de cl\u00e9 primaire.
Quant \u00e0 l'attribut \u00abCode\u00bb, il s'agit sans doute d'une nomenclature \u00abmaison\u00bb correspondant \u00e0 une \u00e9tiquette coll\u00e9e sur la tranche des livres : c'est donc une cl\u00e9 primaire qu'on qualifiera d'\u00abartificielle\u00bb.
Attention Il ne peut pas y avoir deux cl\u00e9s primaires dans une table. La cl\u00e9 primaire choisie ici serait sans aucun doute l'attribut \u00abCode\u00bb.
"},{"location":"T4_Bases_de_donnees/4.1_Modele_relationnel/cours/#4-dautres-relations","title":"4. D'autres relations","text":"Ajoutons maintenant les relations ci-dessous :
Relation \u00abEmprunts\u00bb
id_emprunteur date Nom Pr\u00e9nom titre auteur code 845 12/10/2020 DURAND Michel Au revoir l\u00e0-haut Pierre LEMAITRE 942 125 13/10/2020 MARTIN Jean Pas pleurer Lydie SALVAYRE 1023 125 13/10/2020 MARTIN Jean Boussole Mathias ENARD 486Relation \u00abEmprunteurs\u00bb
id_emprunteur Nom Pr\u00e9nom 129 DULAC Marcel 845 DURAND Michel 125 MARTIN JeanL'attribut \u00abid_emprunteur\u00bb est une cl\u00e9 primaire de la relation \u00abEmprunteurs\u00bb.
Notion de cl\u00e9 \u00e9trang\u00e8re
Y-a-t-il une cl\u00e9 primaire dans la relation \u00abEmprunts\u00bb ?
\u00abid_emprunteur\u00bb est bien une cl\u00e9 primaire (d'\u00abEmprunteurs\u00bb) mais ne peut pas \u00eatre une cl\u00e9 primaire d'\u00abEmprunts\u00bb, car une personne peut prendre plusieurs livres \u00e0 la fois : on dit que c'est une cl\u00e9 \u00e9trang\u00e8re.
Cl\u00e9 \u00e9trang\u00e8re
Une cl\u00e9 \u00e9trang\u00e8re est une cl\u00e9 primaire d'une autre relation.
\u00abcode\u00bb est aussi une cl\u00e9 \u00e9trang\u00e8re : c'est une cl\u00e9 primaire (de la relation \u00ablivres\u00bb) mais elle ne peut pas jouer le r\u00f4le de cl\u00e9 primaire pour la relation emprunt, car un m\u00eame livre pourra \u00eatre pris \u00e0 diff\u00e9rentes dates.
Une cl\u00e9 primaire pourrait alors \u00eatre la combinaison (\u00abdate\u00bb, \u00abcode\u00bb). En effet, aucun livre ne pouvant \u00eatre emprunt\u00e9 deux fois le m\u00eame jour, la connaissance de \u00abdate\u00bb et \u00abcode\u00bb suffit \u00e0 identifier n'importe quel enregistrement.
"},{"location":"T4_Bases_de_donnees/4.1_Modele_relationnel/cours/#5-redondance-des-donnees","title":"5. Redondance des donn\u00e9es","text":"La relation \u00abEmprunts\u00bb contient des informations qui sont d\u00e9j\u00e0 disponibles dans d'autres relations : on dit qu'elle est redondante, et c'est quelque chose qu'il faut \u00e9viter. \u00c0 la fois pour des raisons d'espace de stockage mais aussi de coh\u00e9rence : si une modification doit \u00eatre faite (un emprunteur change de pr\u00e9nom), cette modification ne doit \u00eatre faite qu'\u00e0 un seul endroit de notre base de donn\u00e9es.
Une version non-redondante de la relation \u00abEmprunteurs\u00bb serait donc celle-ci :
Relation \u00abEmprunts\u00bb
id_emprunteur date code 845 12/10/2020 942 125 13/10/2020 1023 125 13/10/2020 486"},{"location":"T4_Bases_de_donnees/4.1_Modele_relationnel/cours/#6-les-3-contraintes-dintegrite","title":"6. Les 3 contraintes d'int\u00e9grit\u00e9","text":"Contrainte de domaine
Tout attribut d'un enregistrement doit respecter le domaine indiqu\u00e9 dans le sch\u00e9ma relationnel.
Attention, certains domaines sont subtils. Par exemple, si une relation poss\u00e8de un attribut \"Code Postal\", le domaine de cet attribut devra \u00eatre String
plut\u00f4t que Entier
. Dans le cas contraire, un enregistrement poss\u00e9dant le code postal 03150
serait converti en 3150
(car pour les entiers, 03150 = 3150). Or le code postal 3150
n'existe pas.
Contrainte de relation
Tout enregistrement est unique. Cette contrainte est assur\u00e9e par l'existence obligatoire d'une cl\u00e9 primaire.
Cette cl\u00e9 primaire est souvent cr\u00e9\u00e9e de mani\u00e8re artificielle (voir id_emprunteurs
dans la table ci-dessus par exemple).
Contrainte de r\u00e9f\u00e9rence
La coh\u00e9rence entre les diff\u00e9rentes tables d'une base de donn\u00e9es est assur\u00e9e par les cl\u00e9s \u00e9trang\u00e8res : dans une table, la valeur d'un attribut qui est cl\u00e9 \u00e9trang\u00e8re doit obligatoirement pouvoir \u00eatre retrouv\u00e9e dans la table dont cet attribut est cl\u00e9 primaire.
Par exemple, la relation \u00abEmprunts_v2\u00bb ci-dessous n'est pas valable :
Relation \u00abEmprunts_v2\u00bb
id_emprunteur date code 845 12/10/2020 942 125 13/10/2020 1023 125 13/10/2020 511En effet, le code 511 (cl\u00e9 \u00e9trang\u00e8re de ma table \u00abEmprunts_v2\u00bb) ne correspond \u00e0 aucun enregistrement dans la table dont il est cl\u00e9 primaire (la table \u00abLivres\u00bb) :
Il n'y a pas de code 511, donc ma relation \u00abEmprunts_v2\u00bb ne respecte pas la contrainte de r\u00e9f\u00e9rence, et provoquerait une erreur du SGBD.
"},{"location":"T4_Bases_de_donnees/4.1_Modele_relationnel/cours/#7-representation-usuelles-des-bases-de-donnees-en-modele-relationnel","title":"7. Repr\u00e9sentation usuelles des bases de donn\u00e9es en mod\u00e8le relationnel","text":"Consid\u00e9rons la base de donn\u00e9es Tour de France 2020, contenant les relations suivantes : (d'apr\u00e8s une id\u00e9e de Didier Boulle)
relation \u00c9quipes
codeEquipe nomEquipe ALM AG2R La Mondiale AST Astana Pro Team TBM Bahrain - McLaren BOH BORA - hansgrohe CCC CCC Team COF Cofidis, Solutions Cr\u00e9dits DQT Deceuninck - Quick Step EF1 EF Pro Cycling GFC Groupama - FDJ LTS Lotto Soudal ... ...\u00c9criture classique d'un sch\u00e9ma relationnel
Le sch\u00e9ma relationnel de cette table sera fr\u00e9quemment donn\u00e9 sous cette forme : Equipes ( codeEquipe String
, nomEquipe String
)
Notez le soulignement sous le mot \u00abcodeEquipe\u00bb, qui signifie que cet attribut est une cl\u00e9 primaire. Les cl\u00e9s \u00e9trang\u00e8res, lorsqu'elles existent, peuvent \u00eatre signal\u00e9es par une ast\u00e9risque * ou un di\u00e8se #.
relation Coureurs
dossard nomCoureur pr\u00e9nomCoureur codeEquipe 141 L\u00d3PEZ Miguel \u00c1ngel AST 142 FRAILE Omar AST 143 HOULE Hugo AST 11 ROGLI\u010c Primo\u017e TJV 12 BENNETT George TJV 41 ALAPHILIPPE Julian DQT 44 CAVAGNA R\u00e9mi DQT 45 DECLERCQ Tim DQT 121 MARTIN Guillaume COF 122 CONSONNI Simone COF 123 EDET Nicolas COF \u2026 \u2026 \u2026 \u2026Sch\u00e9ma : Equipes ( dossard Int
, nomCoureur String
, pr\u00e9nomCoureur String
, codeEquipe* String
)
relation \u00c9tapes
num\u00e9roEtape villeD\u00e9part villeArriv\u00e9e km 1 Nice Nice 156 2 Nice Nice 185 3 Nice Sisteron 198 4 Sisteron Orci\u00e8res-Merlette 160 5 Gap Privas 198 ... ... ... ...Sch\u00e9ma : \u00c9tapes ( num\u00e9roEtape Int
, villeD\u00e9part String
, villeArriv\u00e9e String
, km Int
)
relation Temps
dossard num\u00e9roEtape tempsR\u00e9alis\u00e9 41 2 04:55:27 121 4 04:07:47 11 5 04:21:22 122 5 04:21:22 41 4 04:08:24 ... ... ...Sch\u00e9ma : Temps ( dossard* Int
, num\u00e9roEtape * Int
, tempsR\u00e9alis\u00e9 String
)
Remarquez que la cl\u00e9 primaire de cette relation est le couple dossard-num\u00e9roEtape.
Diagramme relationnel
Fr\u00e9quemment, on pr\u00e9sentera l'ensemble des renseignements d'un mod\u00e8le relationnel sous forme d'un diagramme qui synth\u00e9tise la composition des diff\u00e9rentes tables et les relations entre elles.
"},{"location":"T4_Bases_de_donnees/4.1_Modele_relationnel/cours/#bibliographie","title":"Bibliographie","text":"(d'apr\u00e8s Pr\u00e9pabac NSI, Terminale, G.CONNAN, V.PETROV, G.ROZSAVOLGYI, L.SIGNAC, \u00e9ditions HATIER.)
Deux relations mod\u00e9lisent la flotte de voitures d'un r\u00e9seau de location de voitures.
Agences
id_agence ville d\u00e9partement 1 Paris 75 2 Lyon 69 3 Marseille 13 4 Aubagne 13Voitures
id_voiture marque mod\u00e8le kilom\u00e9trage couleur id_agence 1 Renault Clio 12000 Rouge 2 2 Peugeot 205 22000 Noir 3 3 Toyota Yaris 33000 Noir 3Questions
\u00c9nonc\u00e9CorrectionVoitures
comporte-t-elle d'attributs ?id_agence
dans la relation Voitures
?Agences
?Agences
?Voitures
?Voitures
?Int
)id_agence
id_voiture
id_agence
Reprenons la base Tour de France 2020 vue en cours :
relation \u00c9quipes
codeEquipe nomEquipe ALM AG2R La Mondiale AST Astana Pro Team TBM Bahrain - McLaren BOH BORA - hansgrohe CCC CCC Team COF Cofidis, Solutions Cr\u00e9dits DQT Deceuninck - Quick Step EF1 EF Pro Cycling GFC Groupama - FDJ LTS Lotto Soudal ... ...relation Coureurs
dossard nomCoureur pr\u00e9nomCoureur codeEquipe 141 L\u00d3PEZ Miguel \u00c1ngel AST 142 FRAILE Omar AST 143 HOULE Hugo AST 11 ROGLI\u010c Primo\u017e TJV 12 BENNETT George TJV 41 ALAPHILIPPE Julian DQT 44 CAVAGNA R\u00e9mi DQT 45 DECLERCQ Tim DQT 121 MARTIN Guillaume COF 122 CONSONNI Simone COF 123 EDET Nicolas COF \u2026 \u2026 \u2026 \u2026relation \u00c9tapes
num\u00e9roEtape villeD\u00e9part villeArriv\u00e9e km 1 Nice Nice 156 2 Nice Nice 185 3 Nice Sisteron 198 4 Sisteron Orci\u00e8res-Merlette 160 5 Gap Privas 198 ... ... ... ...relation Temps
dossard num\u00e9roEtape tempsR\u00e9alis\u00e9 41 2 04:55:27 121 4 04:07:47 11 5 04:21:22 122 5 04:21:22 ... ... ...Questions
\u00c9nonc\u00e9CorrectionExercice 1
(d'apr\u00e8s Pr\u00e9pabac NSI, Terminale, G.CONNAN, V.PETROV, G.ROZSAVOLGYI, L.SIGNAC, \u00e9ditions HATIER.)
On veut cr\u00e9er une base de donn\u00e9es baseHopital.db
qui contiendra les trois tables suivantes :
Int
nom Text
prenom Text
genre Text
annee_naissance Int
Ordonnances code Int
id_patient Int
matricule_medecin Int
date_ord Text
medicaments Text
Medecins matricule Int
nom_prenom Text
specialite Text
telephone Text
On suppose que les dates sont donn\u00e9es sous la forme jj-mm-aaaa
.
On donne le diagramme relationnel de cette base :
Q0. \u00c9crire le sch\u00e9ma relationnel de la table Ordonnances. On soulignera les cl\u00e9s primaires et marquera d'un # les cl\u00e9s \u00e9trang\u00e8res.
CorrectionOrdonnances ((code, Int), (id_patient#, Int), (matricule_medecin#, Int), (date_ord, Text), (medicaments, Text))
Q1. (HP) Donner les commandes SQL permettant de cr\u00e9er ces tables.
CorrectionCREATE TABLE Patients(\nid INTEGER PRIMARY KEY,\nnom TEXT,\nprenom TEXT,\ngenre TEXT,\nannee_naissance INTEGER\n);\n\nCREATE TABLE Ordonnances(\ncode INTEGER PRIMARY KEY,\nid_patient INTEGER,\nmatricule_medecin INTEGER,\ndate_ord TEXT,\nmedicaments TEXT,\nFOREIGN KEY(id_patient) REFERENCES Patients(Id),\nFOREIGN KEY(matricule_medecin) REFERENCES Medecins(matricule)\n);\n\nCREATE TABLE Medecins(\nmatricule INTEGER PRIMARY KEY,\nnom_prenom TEXT,\nspecialite TEXT,\ntelephone TEXT\n);\n
Q2. Mme Anne Wizeunid, n\u00e9e en 2000 et demeurant 3 rue des Pignons Verts 12345 Avonelit doit \u00eatre enregistr\u00e9e comme patiente num\u00e9ro 1. Donner la commande SQLite correspondante.
CorrectionINSERT INTO Patients\nVALUES (1, \"Wizeunit\", \"Anne\", \"F\", 2000);\n
Q3. Le patient num\u00e9ro 100 a chang\u00e9 de pr\u00e9nom et s'appelle maintenant \"Alice\". Donner la commande SQLite modifiant en cons\u00e9quence ses donn\u00e9es.
CorrectionUPDATE Patients\nSET prenom = 'Alice' WHERE id = 100 ;\n
Q4. Par souci d'\u00e9conomie, la direction d\u00e9cide de se passer des m\u00e9decins sp\u00e9cialis\u00e9s en \u00e9pid\u00e9miologie. Donner la commande permettant de supprimer leurs fiches.
CorrectionDELETE FROM Medecins WHERE specialite = \"\u00e9pid\u00e9miologie\";\n
Q5. Donner la liste des patient(e)s ayant \u00e9t\u00e9 examin\u00e9(e)s par un(e) psychiatre en avril 2020.
CorrectionSELECT p.nom, p.prenom\nFROM Patients AS p\nJOIN Ordonnances AS o ON p.id = o.id_patient\nJOIN Medecins AS m ON o.matricule_medecin = m.matricule\nWHERE m.specialite = \"psychiatrie\"\nAND o.date_ord LIKE \"%-04-2020\"\n
Exercice 2
bas\u00e9 sur le travail de G.Viateau (Bayonne)
On consid\u00e8re ci-dessous le sch\u00e9ma de la base de donn\u00e9es du stock d'un supermarch\u00e9 :
Q1. Quelle requ\u00eate SQL donne le prix d'achat du produit dont le nom_court
est \u00abLiq_Vaiss_1L\u00bb ?
SELECT prix_achat FROM Produits WHERE nom_court = 'Liq_Vaiss_1L'
Q2. Quelle requ\u00eate donne l'adresse, le code postal et la ville du fournisseur dont le nom est \u00abAvenir_confiseur\u00bb ?
CorrectionSELECT adresse, cp, ville FROM Fournisseurs WHERE nom = 'Avenir_confiseur';\n
Q3. Quelle requ\u00eate donne les produits \u00e9tant en rupture de stock ?
CorrectionSELECT Produits.nom FROM Produits\nJOIN Stocks ON Produits.id = Stocks.produit\nWHERE Stocks.quantite = 0;\n
Q4. Quelle requ\u00eate donne la liste de toutes les ampoules vendues en magasin ? On pourra faire l'hypoth\u00e8se que le nom du produit contient le mot \u00abampoule\u00bb
CorrectionSELECT nom FROM Produits WHERE nom LIKE \"%ampoule%\";\n
Q5. Quelle requ\u00eate permet d'avoir le prix moyen de ces ampoules ?
CorrectionSELECT AVG(prix_vente) FROM Produits WHERE nom LIKE \"%ampoule%\";\n
Q6. Quelle requ\u00eate permet d'identifier le produit le plus cher du magasin ?
CorrectionSELECT nom_court FROM Produits ORDER BY prix_vente DESC LIMIT 1;\n
ou SELECT nom FROM Produits WHERE prix_vente = (SELECT MAX(prix_vente) FROM Produits);\n
Q7. Quelle requ\u00eate renvoie les noms des produits dont la date de p\u00e9remption est d\u00e9pass\u00e9e ? (on pourra utiliser la fonction SQL NOW()
qui renvoie la date actuelle )
SELECT p.nom FROM Produits AS p\nJOIN Stocks AS s ON s.produits = p.id\nWHERE s.date_peremption < NOW();\n
Exercice 3
Exercice 1 du sujet Am\u00e9rique du Nord J1 2022
Correction Correction Q1.a.La relation Sport a pour cl\u00e9 primaire le couple NomSport et nomStation, et pour cl\u00e9 \u00e9trang\u00e8re l'attribut nomStation, cl\u00e9 primaire de la relation Station.
Correction Q1.b.Contrainte d'int\u00e9grit\u00e9 de domaine : l'attribut Prix doit \u00eatre un nombre entier.
Contrainte d'int\u00e9grit\u00e9 de relation : le couple (nomSport, nomStation) ne peut pas se retrouver deux fois dans la table (car il forme une cl\u00e9 primaire)
Contrainte d'int\u00e9grit\u00e9 de r\u00e9f\u00e9rence : l'attribut nomStation ne peut pas \u00eatre un nom n'apparaissant pas dans la relation Station.
La commande INSERT ne sert que pour ins\u00e9rer de nouveaux enregistrements, or le couple (\"planche \u00e0 voile\" , \"La tramontane catalane\") existe d\u00e9j\u00e0 dans la relation (et c'est une cl\u00e9 primaire donc on ne peut pas la retrouver deux fois). Il faut donc utiliser :
UPDATE Sports SET prix = 1350 WHERE nomSport = \"planche \u00e0 voile\" AND nomStation = \"La tramontane catalane\"
Correction Q2.b. INSERT INTO Station VALUES (\"Soleil Rouge\", \"Bastia\", \"Corse\") INSERT INTO Sport VALUES (\"plong\u00e9e\", \"Soleil Rouge\", 900)
Correction Q3.a. SELECT mail FROM Client
Correction Q3.b. SELECT nomStation FROM Sport\nWHERE nomSport = \"plongee\"
Correction Q4.a. SELECT Station.ville, Station.nomStation FROM Station\nJOIN Sport ON Sport.nomStation = Station.nomStation\nWHERE Sport.nomSport = \"plongee\"
Correction Q4.b. SELECT COUNT(*) FROM Sejour\nJOIN Station ON Station.nomStation = Sejour.nomStation\nWHERE Sejour.annee = 2020 AND Station.region = \"Corse\"\n
Exercice 4
Exercice 4 du sujet Centres \u00c9trangers J1 2022
Correction Correction Q1.a.L'attribut id_mesure
semble une cl\u00e9 primaire acceptable car elle semble sp\u00e9cifique \u00e0 chaque enregistrement.
L'attribut id_centres
semble \u00eatre une cl\u00e9 primaire de la relation Centres
. On le retrouve aussi (sous le m\u00eame nom) dans la relation Mesures
. C'est donc un attribut qui permettra de faire une jointure entre les deux relations.
Cette requ\u00eate va afficher tous les renseignements disponibles sur les centres dont l'altitude est strictement sup\u00e9rieure \u00e0 500m.
Correction Q2.b.SELECT nom_ville FROM Centres WHERE altitude >= 700 AND altitude <= 1200;\n
Correction Q2.c. SELECT longitude, nom_ville FROM Centres\nWHERE longitude > 5\nORDER BY nom_ville;\n
Correction Q3.a. Cette requ\u00eate va afficher tous les renseignements sur les mesures dat\u00e9es du 30 octobre 2021.
Correction Q3.b.INSERT INTO Mesures VALUES (3650, 138, 2021-11-08, 11, 1013, 0);\n
Correction Q4.a. Cette requ\u00eate va renvoyer tous les renseignements sur les centres dont la latitude est la latitude minimum de tous les centres.
Correction Q4.b.SELECT DISTINCT Centres.nom_ville FROM Centres\nJOIN Mesures ON Mesures.id_centre = Centres.id_centre\nWHERE Mesures.temperature < 10\nAND Mesures.date <= 2021-10-31\nAND Mesures.date >= 2021-10-01;\n
Exercice 5
Exercice 4 du sujet M\u00e9tropole J2 2022
Correction Correction Q1.a.Hey Jude\nI Want To Hold Your Hand\n
Correction Q1.b. SELECT nom FROM interpretes\nWHERE pays = 'Angleterre';\n
Correction Q1.c. I Want To Hold Your Hand, 1963\nLike a Rolling Stone, 1965\nRespect, 1967\nHey Jude, 1968\nImagine, 1970\nSmells Like Teen Spirit, 1991\n
Correction Q1.d. SELECT COUNT(*) FROM morceaux;\n
Correction Q1.e. SELECT titre FROM morceaux\nORDER BY titre;\n
Correction Q2.a. La cl\u00e9 \u00e9trang\u00e8re de la table morceaux
est l'attribut id_interprete
qui fait r\u00e9f\u00e9rence \u00e0 la cl\u00e9 primaire id_interprete
de la table interpretes
.
morceaux
: ((id_morceau, Int), (titre, Text), (annee, Int), (id_interprete#, Int)) interpretes
: ((id_interprete, Int), (nom, Text), (pays, Text))
La requ\u00eate va renvoyer une erreur car la cl\u00e9 primaire 1 est d\u00e9j\u00e0 pr\u00e9sente dans la table : il s'agit d'une violation de la contrainte de relation.
Correction Q3.a.UPDATE morceaux\nSET annee = 1971\nWHERE titre = 'Imagine'\n
Correction Q3.b. INSERT INTO interpretes\nVALUES (6, \"The Who\", \"Angleterre\")\n
Correction Q3.c. INSERT INTO morceaux\nVALUES (7, \"My Generation\", 1965, 6)\n
Correction Q4. SELECT morceaux.titre\nFROM morceaux\nJOIN interpretes ON interpretes.id_interprete = morceaux.id_interprete\nWHERE interpretes.pays = \"\u00c9tats-Unis\"\n
Exercice 6
Exercice 2 du sujet La R\u00e9union J2 2022
Correction Correction Q1.Le couple (NumClient, NumChambre)
ne pouvait pas \u00eatre une cl\u00e9 primaire car un m\u00eame client peut revenir dans l'h\u00f4tel et avoir la m\u00eame chambre qu'\u00e0 un pr\u00e9c\u00e9dent s\u00e9jour. Le couple (NumClient, NumChambre)
ne serait donc pas unique et ne peut donc pas servir de cl\u00e9 primaire pour la relation Reservations
.
SELECT Nom, Prenom FROM Clients
Correction Q2.b. SELECT Telephone FROM Clients\nWHERE Prenom = \"Grace\" AND Nom = \"Hopper\"\n
Correction Q3. SELECT NumChambre FROM Reservations\nWHERE date(DateArr) <= date('2024-12-28')\nAND date(DateDep) > date('2024-12-28')\n
Correction Q4.a. UPDATE Chambres\nSET prix = 75\nWHERE NumChambre = 404\n
Correction Q4.b SELECT Reservations.NumChambre FROM Reservations\nJOIN Clients ON Clients.NumClient = Reservations.NumClient\nWHERE Clients.Nom = 'Codd' AND Clients.Prenom = 'Edgar'\n
"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/02_exercices_inter/","title":"Exercices SQL interactifs","text":"Exercice 1
Questions interactives \u00e0 r\u00e9aliser sur le site sqlzoo.net.
Q1. Travail sur SELECT, (base de donn\u00e9es Nobel) ici.
CorrectionCorrections extraites du d\u00e9p\u00f4t https://github.com/jisaw/sqlzoo-solutions.
/*\nThird section of sqlzoo, SELECT from Nobel\n*/\n\n--#1\n/*\nChange the query shown so that it displays Nobel prizes for 1950.\n*/\nSELECT yr, subject, winner\nFROM nobel\nWHERE yr = 1950\n\n--#2\n/*\nShow who won the 1962 prize for Literature.\n*/\nSELECT winner\nFROM nobel\nWHERE yr = 1962 AND subject = 'Literature'\n\n--#3\n/*\nShow the year and subject that won 'Albert Einstein' his prize.\n*/\nSELECT yr, subject\nFROM nobel\nWHERE winner = 'Albert Einstein'\n\n--#4\n/*\nGive the name of the 'Peace' winners since the year 2000, including 2000.\n*/\nSELECT winner\nFROM nobel\nWHERE subject = 'Peace' AND yr >= 2000\n\n--#5\n/*\nShow all details (yr, subject, winner) of the Literature prize winners for 1980 to 1989 inclusive\n*/\nSELECT yr, subject, winner\nFROM nobel\nWHERE (yr >=1980 AND yr <=1989) AND subject = 'Literature'\n\n--#6\n/*\nShow all details of the presidential winners:\n\nTheodore Roosevelt\nWoodrow Wilson\nJimmy Carter\n*/\nSELECT *\nFROM nobel\nWHERE winner IN ('Theodore Roosevelt', 'Woodrow Wilson', 'Jimmy Carter')\n\n--#7\n/*\nShow the winners with first name John\n*/\nSELECT winner\nFROM nobel\nWHERE winner LIKE 'john%'\n\n--#8\n/*\nShow the Physics winners for 1980 together with the Chemistry winners for 1984.\n*/\nSELECT *\nFROM nobel\nWHERE (subject = \"Physics\" AND yr = '1980') OR (subject = 'Chemistry' AND yr = 1984)\n\n--#9\n/*\nShow the winners for 1980 excluding the Chemistry and Medicine\n*/\nSELECT *\nFROM nobel\nWHERE yr = 1980 AND subject NOT IN ('Chemistry', 'Medicine')\n\n--#10\n/*\nShow who won a 'Medicine' prize in an early year (before 1910, not including 1910) together with winners of a 'Literature' prize in a later year (after 2004, including 2004)\n*/\nSELECT *\nFROM nobel\nWHERE (subject = 'Medicine' AND yr < 1910) OR (subject = 'Literature' AND yr >= 2004)\n\n--#11\n/*\nFind all details of the prize won by PETER GR\u00dcNBERG\n*/\nSELECT *\nFROM nobel\nWHERE winner LIKE 'peter gr%nberg'\n\n--#12\n/*\nFind all details of the prize won by EUGENE O'NEILL\n*/\nSELECT *\nFROM nobel\nWHERE winner = 'Eugene O''Neill'\n\n--#13\n/*\nKnights in order\n\nList the winners, year and subject where the winner starts with Sir. Show the the most recent first, then by name order.\n*/\nSELECT winner, yr, subject\nFROM nobel\nWHERE winner LIKE 'sir%'\nORDER BY yr DESC, winner\n\n--#14\n/*\nThe expression subject IN ('Chemistry','Physics') can be used as a value - it will be 0 or 1.\n\nShow the 1984 winners ordered by subject and winner name; but list Chemistry and Physics last.\n*/\nSELECT winner, subject, subject IN ('Physics','Chemistry')\nFROM nobel\nWHERE yr=1984\nORDER BY subject IN ('Physics','Chemistry'),subject,winner\n
Q2. Travail sur SUM et COUNT, (base de donn\u00e9es World) ici. (jusqu'\u00e0 la question 5.)
CorrectionCorrections extraites du d\u00e9p\u00f4t https://github.com/jisaw/sqlzoo-solutions.
/*\nFifth section of sqlzoo, SUM and COUNT\n*/\n\n\n--#1\n/*\nShow the total population of the world.\n*/\nSELECT SUM(population)\nFROM world\n\n--#2\n/*\nList all the continents - just once each.\n*/\nSELECT DISTINCT(continent)\nFROM world\n\n--#3\n/*\nGive the total GDP of Africa\n*/\nSELECT SUM(gdp)\nFROM world\nWHERE continent = 'Africa'\n\n--#4\n/*\nHow many countries have an area of at least 1000000\n*/\nSELECT COUNT(name)\nFROM world\nWHERE area >= 1000000\n\n--#5\n/*\nWhat is the total population of ('France','Germany','Spain')\n*/\nSELECT SUM(population)\nFROM world\nWHERE name IN ('France', 'Germany', 'Spain')\n\n--#6\n/*\nFor each continent show the continent and number of countries.\n*/\nSELECT continent, COUNT(name)\nFROM world\nGROUP BY continent\n\n\n--#7\n/*\nFor each continent show the continent and number of countries with populations of at least 10 million.\n*/\nSELECT continent, COUNT(name)\nFROM world\nWHERE population >= 10000000\nGROUP BY continent\n\n--#8\n/*\nList the continents that have a total population of at least 100 million.\n*/\nSELECT continent\nFROM world\nGROUP BY continent\nHAVING SUM(population) > 100000000\n
Q3. Travail sur JOIN, (base de donn\u00e9es Euro2012) ici.
correction/*\nSixth section of sqlzoo, Join\n*/\n\n\n--#1\n/*\nThe first example shows the goal scored by 'Bender'.\n\nShow matchid and player name for all goals scored by Germany.\n*/\nSELECT matchid, player FROM goal\nWHERE teamid = 'GER'\n\n--#2\n/*\nFrom the previous query you can see that Lars Bender's goal was scored in game 1012. Notice that the column matchid in the goal table corresponds to the id column in the game table.\n\nShow id, stadium, team1, team2 for game 1012\n*/\nSELECT id,stadium,team1,team2\nFROM game\nWHERE id = 1012\n\n--#3\n/*\nYou can combine the two steps into a single query with a JOIN. You will get all the game details and all the goal details if you use\n\nSELECT *\n FROM game JOIN goal ON (id=matchid)\nShow the player, teamid and mdate and for every German goal. teamid='GER'\n*/\nSELECT player, teamid, mdate\nFROM game\nJOIN goal ON (id=matchid AND teamid='GER')\n\n--#4\n/*\nUse the same JOIN as in the previous question.\n\nShow the team1, team2 and player for every goal scored by a player called Mario player LIKE 'Mario%'\n*/\nSELECT team1, team2, player\nFROM game\nJOIN goal ON (id=matchid AND player LIKE 'Mario%')\n\n--#5\n/*\nThe table eteam gives details of every national team including the coach. You can JOIN goal to eteam using the phrase goal JOIN eteam on teamid=id\n\nShow player, teamid, coach, gtime for all goals scored in the first 10 minutes gtime<=10\n*/\nSELECT player, teamid, coach, gtime\nFROM goal\nJOIN eteam ON (teamid=id AND gtime<=10)\n\n--#6\n/*\nTo JOIN game with eteam you could use either\ngame JOIN eteam ON (team1=eteam.id) or game JOIN eteam ON (team2=eteam.id)\n\nNotice that because id is a column name in both game and eteam you must specify eteam.id instead of just id\n\nList the the dates of the matches and the name of the team in which 'Fernando Santos' was the team1 coach.\n*/\nSELECT mdate, teamname\nFROM game\nJOIN eteam ON (team1=eteam.id AND coach LIKE '%Santos')\n\n--#7\n/*\nList the player for every goal scored in a game where the stadium was 'National Stadium, Warsaw'\n*/\nSELECT player\nFROM goal\nJOIN game ON (id=matchid AND stadium = 'National Stadium, Warsaw')\n\n--#8\n/*\nThe example query shows all goals scored in the Germany-Greece quarterfinal.\nInstead show the name of all players who scored a goal against Germany.\n*/\nSELECT DISTINCT(player)\nFROM game\nJOIN goal ON matchid = id\nWHERE ((team1='GER' OR team2='GER') AND teamid != 'GER')\n\n--#9\n/*\nShow teamname and the total number of goals scored.\n*/\nSELECT teamname, COUNT(player)\nFROM eteam\nJOIN goal ON id=teamid\nGROUP BY teamname\n\n--#10\n/*\nShow the stadium and the number of goals scored in each stadium.\n*/\nSELECT stadium, COUNT(player) AS goals\nFROM game\nJOIN goal ON (id=matchid)\nGROUP BY stadium\n\n--#11\n/*\nFor every match involving 'POL', show the matchid, date and the number of goals scored.\n*/\nSELECT matchid, mdate, COUNT(player) AS goals\nFROM game\nJOIN goal ON (matchid=id AND (team1 = 'POL' OR team2 = 'POL'))\nGROUP BY matchid, mdate\n\n--#12\n/*\nFor every match where 'GER' scored, show matchid, match date and the number of goals scored by 'GER'\n*/\nSELECT id, mdate, COUNT(player)\nFROM game\nJOIN goal ON (id=matchid AND (team1 = 'GER' OR team2 = 'GER') AND teamid='GER')\nGROUP BY id, mdate\n\n--#13\n/*\nList every match with the goals scored by each team as shown. This will use \"CASE WHEN\" which has not been explained in any previous exercises.\nmdate team1 score1 team2 score2\n1 July 2012 ESP 4 ITA 0\n10 June 2012 ESP 1 ITA 1\n10 June 2012 IRL 1 CRO 3\n...\nNotice in the query given every goal is listed. If it was a team1 goal then a 1 appears in score1, otherwise there is a 0.\nYou could SUM this column to get a count of the goals scored by team1. Sort your result by mdate, matchid, team1 and team2.\n*/\nSELECT mdate,\nteam1,\nSUM(CASE WHEN teamid = team1 THEN 1 ELSE 0 END) AS score1,\nteam2,\nSUM(CASE WHEN teamid = team2 THEN 1 ELSE 0 END) AS score2 FROM\ngame LEFT JOIN goal ON (id = matchid)\nGROUP BY mdate,team1,team2\nORDER BY mdate, matchid, team1, team2\n
Exercice 2
Gestion d'un r\u00e9seau d'agences de location de voitures. D'apr\u00e8s le travail de J. Le Coupanec (Acad\u00e9mie de Rennes)
La base de donn\u00e9es locations.db contient les tables Agences
,Locations
, Vehicules
.
Agences
Q1. Visualisez toute la relation Agences
SELECT * FROM Agences\n
Q2. Listez uniquement les noms des agences et de leur ville.
CorrectionSELECT nom, ville FROM Agences\n
Q3. Listez les noms des agences de la ville de Lorient
CorrectionSELECT nom FROM Agences\nWHERE ville = 'Lorient'\n
Q4. Listez les noms des agences du d\u00e9partement du Morbihan (code postal 56***) ainsi que les codes postaux en utilisant par exemple un WHERE LIKE
.
SELECT nom FROM Agences\nWHERE code LIKE '56%'\n
Questions sur la relation Vehicules
Q5. D\u00e9terminez le nombre de voitures que vous poss\u00e9dez.
CorrectionSELECT COUNT(*) FROM Vehicules\n
Q6. D\u00e9terminez l'\u00e2ge minimum et maximum de vos v\u00e9hicules.
CorrectionSELECT MAX(age), MIN(age) FROM Vehicules\n
Q7. Quels sont la marque et le mod\u00e8le de votre derni\u00e8re acquisition qui date de trois mois ?
CorrectionSELECT nom FROM Vehicules\nWHERE age = 3\n
Q8. Quel est le kilom\u00e9trage maximum des v\u00e9hicules ?
CorrectionSELECT MAX(kilometrage) FROM Vehicules\n
Q9. Quel est le kilom\u00e9trage moyen des v\u00e9hicules ?
CorrectionSELECT AVG(kilometrage) FROM Vehicules\n
Q10. Afficher toute la flotte de v\u00e9hicules par ordre d\u00e9croissant de kilom\u00e9trage.
CorrectionSELECT * FROM Vehicules\nORDER BY kilometrage DESC\n
Questions sur la relation Locations
Q11. Visualisez toute la relation Locations.
CorrectionSELECT * FROM Locations\n
Q12. D\u00e9terminez le nombre de locations effectu\u00e9es avec changement d'agence
CorrectionSELECT COUNT(*) FROM Locations\nWHERE depart != retour\n
Q13. D\u00e9terminez le nombre total de kilom\u00e8tres effectu\u00e9s durant les locations
CorrectionSELECT SUM(distance) FROM Locations\n
Q14. Listez toutes les locations en y associant les caract\u00e9ristiques du v\u00e9hicule
CorrectionSELECT * FROM Locations\nJOIN Vehicules ON Locations.vehicule = Vehicules.immatriculation\n
Q15. Affichez le nom et l'immatriculation du v\u00e9hicule ainsi que la date de la location et le kilom\u00e9trage r\u00e9alis\u00e9 pour chacune des locations
CorrectionSELECT Vehicules.nom, Vehicules.immatriculation, Locations.date, Locations.kilometrage FROM Locations\nJOIN Vehicules ON Locations.vehicule = Vehicules.immatriculation\n
Q16. Affichez une seule fois le nom et l'immatriculation des v\u00e9hicules ayant d\u00e9j\u00e0 \u00e9t\u00e9 lou\u00e9s.
CorrectionSELECT DISTINCT nom, immatriculation FROM Locations\nJOIN Vehicules ON Locations.vehicule = Vehicules.immatriculation\n
Q17. Affichez les locations du v\u00e9hicule immatricul\u00e9 AB-224-BA en pr\u00e9cisant le nom de l'agence de d\u00e9part ainsi que la ville de d\u00e9part dans l'ordre chronologique des locations.
CorrectionSELECT Agences.nom, Agences.ville, Locations.* FROM Locations\nJOIN Agences ON Locations.depart = Agences.id\nWHERE vehicule = 'AB-224-BA'\nORDER BY Locations.date\n
Exercice 3
Championnat de France de Football 2015-2016
D'apr\u00e8s le travail de J. Le Coupanec (Acad\u00e9mie de Rennes)
La base de donn\u00e9es soccer.db contient les tables Team
,Match
, Event
, Player
.
Q1. Combien d'\u00e9quipes ont particip\u00e9 \u00e0 ce championnat ?
CorrectionSELECT COUNT(*) FROM Team\n
Q2. Listez les noms des clubs ainsi que leur date de cr\u00e9ation dans l'ordre chronologique de leur cr\u00e9ation.
CorrectionSELECT name, birthday FROM Team\nORDER BY birthday\n
Q3. Combien de p\u00e9naltys ont \u00e9t\u00e9 marqu\u00e9s ?
CorrectionSELECT COUNT(*) FROM Event\nWHERE type='penalty'\n
Q4. Combien de p\u00e9naltys ont \u00e9t\u00e9 siffl\u00e9s ?
CorrectionSELECT COUNT(*) FROM Event\nWHERE type IN ('penalty','miss')\n
Q5. Combien de cartons ont \u00e9t\u00e9 distribu\u00e9s ?
CorrectionSELECT COUNT(*) FROM Event\nWHERE type IN ('red','yellow2','yellow')\n
Q6. Combien de buts ont \u00e9t\u00e9 marqu\u00e9s ?
CorrectionSELECT COUNT(*) FROM Event\nWHERE type IN ('goal','own','penalty')\n
Q7. Affichez tous les renseignements sur les 10 cartons rouges obtenus le plus rapidement pendant un match.
CorrectionSELECT * FROM Event\nWHERE type = 'red'\nORDER BY time\nLIMIT 10\n
Q8. Donnez le nom du joueur qui a obtenu le carton rouge le plus rapidement.
CorrectionSELECT name from Player\nWHERE id=392\n
Exercice 4
Cet exercice en ligne est propos\u00e9 le Knight Lab de l'universit\u00e9 am\u00e9ricaine Northwerstern University.
Le point de d\u00e9part de l'histoire : un meurtre a \u00e9t\u00e9 commis dans la ville de SQL City le 15 janvier 2018.
\u00c0 partir de ce point de d\u00e9part et d'une base de donn\u00e9es dont le diagramme est donn\u00e9 ci-dessous, il s'agit de trouver le meurtrier.
Zone d'enqu\u00eate (\u00e0 coups de requ\u00eates)Il est conseill\u00e9 de travailler avec un Bloc-Notes ouvert \u00e0 c\u00f4t\u00e9 afin d'y coller les renseignements obtenus.
Tapez votre requ\u00eate ci-dessous Ex\u00e9cuter Vous pensez avoir trouv\u00e9 le meurtrier ?Copiez la requ\u00eate
INSERT INTO solution VALUES (1, 'nom du meurtrier');\nSELECT value FROM solution;\n
dans le champ ci-dessous : Ex\u00e9cuter Sur la page officielle, vous pouvez \u00eatre guid\u00e9s \u00e9tape par \u00e9tape jusqu'\u00e0 la recherche du meurtrier (qui n'est pas la fin de l'\u00e9nigme !)
Vous pouvez si vous le souhaitez t\u00e9l\u00e9charger la base sql-murder-mystery.db.
Vous pouvez trouver des \u00e9l\u00e9ments de correction ici...
Nous allons cr\u00e9er et interroger une base de donn\u00e9es sqlite
avec le module sqlite3
de Python.
import sqlite3\n\n#Connexion\nconnexion = sqlite3.connect('mynewbase.db')\n\n#R\u00e9cup\u00e9ration d'un curseur\nc = connexion.cursor()\n\n# ---- d\u00e9but des instructions SQL\n\n#Cr\u00e9ation de la table\nc.execute(\"\"\"\n CREATE TABLE IF NOT EXISTS bulletin(\n Nom TEXT,\n Pr\u00e9nom TEXT,\n Note INT);\n \"\"\")\n\n# ---- fin des instructions SQL\n\n#Validation\nconnexion.commit()\n\n\n#D\u00e9connexion\nconnexion.close()\n
mynewbase.db
sera cr\u00e9\u00e9 dans le m\u00eame r\u00e9pertoire que le fichier source Python. Si fichier existe d\u00e9j\u00e0, il est ouvert et peut \u00eatre modifi\u00e9.IF NOT EXISTS
assure de ne pas \u00e9craser une table existante qui porterait le m\u00eame nom. Si une telle table existe, elle n'est alors pas modifi\u00e9e.DB Browser
pour v\u00e9rifier sa structure et ses donn\u00e9es.Les morceaux de code ci-dessous sont \u00e0 positionner entre les balises # ---- d\u00e9but des instructions SQL
et # ---- fin des instructions SQL
.
c.execute('''INSERT INTO bulletin VALUES ('Simpson', 'Bart', 17)''')\n
Pensez \u00e0 v\u00e9rifier avec DB Browser
si les modifications sont effectives.
data = ('Simpson', 'Maggie', 2)\nc.execute('''INSERT INTO bulletin VALUES (?,?,?)''', data)\n
"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/03_python_et_SQL/#123-insertion-de-multiples-enregistrements","title":"1.2.3 Insertion de multiples enregistrements","text":"lst_notes = [ ('Simpson', 'Lisa', 19), ('Muntz', 'Nelson', 4), ('Van Houten', 'Milhouse', 12) ]\n\nc.executemany('''INSERT INTO bulletin VALUES (?, ?, ?)''', lst_notes)\n
Les diff\u00e9rentes valeurs sont stock\u00e9es au pr\u00e9alable dans une liste de tuples."},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/03_python_et_SQL/#13-mini-projet-1","title":"1.3 Mini-projet 1","text":"Cr\u00e9er un programme qui demande \u00e0 l'utilisateur un nom et une note, en boucle. Les r\u00e9sultats sont stock\u00e9s au fur et \u00e0 mesure dans une base de donn\u00e9es. Si le nom est \u00e9gal \u00e0 \u00abQ\u00bb ou \u00abq\u00bb, le programme s'arr\u00eate.
"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/03_python_et_SQL/#14-exemple-dinjection-sql","title":"1.4 \u2620 Exemple d'injection SQL","text":"L'injection SQL est une technique consistant \u00e0 \u00e9crire du code SQL \u00e0 un endroit qui n'est pas cens\u00e9 en recevoir.
https://xkcd.com/327/
Cr\u00e9ez un fichier contenant le code suivant :
import sqlite3\n\n#Connexion\nconnexion = sqlite3.connect('mabasecobaye.db')\n\n#R\u00e9cup\u00e9ration d'un curseur\nc = connexion.cursor()\n\nc.execute(\"\"\"\n CREATE TABLE IF NOT EXISTS notes(\n Nom TEXT,\n Note INT);\n \"\"\")\n\n\nwhile True :\n nom = input('Nom ? ')\n if nom in ['Q','q'] :\n break\n note = input('Note ? ')\n data = (nom, note)\n p = \"INSERT INTO notes VALUES ('\" + nom + \"','\" + note + \"')\"\n\n c.executescript(p)\n\n\n#Validation\nconnexion.commit()\n\n\n#D\u00e9connexion\nconnexion.close()\n
Ex\u00e9cutez ce fichier, rentrez quelques valeurs, quittez, et ouvrez dans DB Browser
la table notes
pour bien v\u00e9rifier que vos valeurs ont bien \u00e9t\u00e9 stock\u00e9es.
g','3'); DROP TABLE notes;--
notes
n'existe plus !Explication : La requ\u00eate qui a \u00e9t\u00e9 formul\u00e9e est INSERT INTO notes VALUES ('g','3'); DROP TABLE notes;--','12')
Dans un premier temps, le couple ('g','3')
a \u00e9t\u00e9 ins\u00e9r\u00e9. Puis l'ordre a \u00e9t\u00e9 donn\u00e9 de d\u00e9truire la table notes
. Le reste du code (qui n'est pas correct) est ignor\u00e9 car --
est le symbole du commentaire en SQL (l'\u00e9quivalent du # de Python).
Remarques : \u00c9videmment, ce code a \u00e9t\u00e9 fait sp\u00e9cifiquement pour \u00eatre vuln\u00e9rable \u00e0 l'injection SQL. Il suffit d'ailleurs de remplacer le c.executescript(p)
par c.execute(p)
pour que le code reste fonctionnel mais refuse l'injection SQL. Ceci dit, de nombreux serveurs sont encore attaqu\u00e9s par cette technique, au prix de manipulations bien s\u00fbr plus complexes que celles que nous venons de voir (vous pouvez par exemple regarder ici).
Rappelons enfin que ce genre de pratiques est interdit sur un serveur qui ne vous appartient pas.
"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/03_python_et_SQL/#2-lecture-des-enregistrements","title":"2. Lecture des enregistrements","text":"import sqlite3\n\n#Connexion\nconnexion = sqlite3.connect('mynewbase.db')\n\n#R\u00e9cup\u00e9ration d'un curseur\nc = connexion.cursor()\n\ndata = ('Simpson', )\n\nc.execute(\"SELECT Pr\u00e9nom FROM Bulletin WHERE Nom = ?\", data)\nprint(c.fetchall()) \n\n\n#D\u00e9connexion\nconnexion.close()\n
Ce code renvoie [('Homer',), ('Lisa',), ('Maggie',)]
, ou une liste vide s'il n'y a pas de r\u00e9sultat \u00e0 la requ\u00eate.
Reprendre le mini-projet pr\u00e9c\u00e9dent, en rendant possible \u00e0 l'utilisateur de rentrer des notes ou bien de les consulter.
Exemple :
"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/03_python_et_SQL/#23-mini-projet-3","title":"2.3 Mini-projet 3","text":"Cr\u00e9er un syst\u00e8me d'authenfication par login / mot de passe, dans le but de conserver une phrase secr\u00e8te.
Id\u00e9alement le mot de passe ne sera pas conserv\u00e9 en clair mais hach\u00e9.
Exemple :
lien vers une correction
"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/cours/","title":"Langage SQL","text":""},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/cours/#0-du-modele-relationnel-au-sgbd","title":"0. Du mod\u00e8le relationnel au SGBD","text":"Les consid\u00e9rations sur le mod\u00e8le relationnel du cours pr\u00e9c\u00e9dent traitaient plut\u00f4t de la structure math\u00e9matique des donn\u00e9es.
Il s'agissait de d\u00e9terminer la meilleure structure pour repr\u00e9senter les donn\u00e9es et les relations qui les lient.
Il convient maintenant d'aborder la partie logicielle : les SGBD (Syst\u00e8mes de Gestion de Bases de Donn\u00e9es).
Les SGBD jouent le r\u00f4le d'interface entre l'\u00eatre humain et la base de donn\u00e9es. Par l'interm\u00e9diaire de requ\u00eates, l'utilisateur va consulter ou modifier la base de donn\u00e9es. Le SGBD est garant de l'int\u00e9grit\u00e9 de cette base, et pr\u00e9vient notamment que les modifications (souvent appel\u00e9es transactions) ne soient pas pr\u00e9judiciables \u00e0 la base de donn\u00e9es.
Le langage utilis\u00e9 pour communiquer avec le SGBD est le langage SQL, pour Structured Query Langage (pour langage de requ\u00eates structur\u00e9es).
Les SGBD les plus utilis\u00e9s sont bas\u00e9s sur le mod\u00e8le relationnel. Parmi eux, citons Oracle, MySQL, Microsoft SQL Server, PostgreSQL, Microsoft Access, SQLite, MariaDB...
Mais de plus en plus de SGBD non-relationnels sont utilis\u00e9s, sp\u00e9cialement adapt\u00e9s \u00e0 des donn\u00e9es plus diverses et moins structur\u00e9es. On les retrouve sous l'appelation NoSQL (pour Not only SQL). Citons parmi eux MongoDB, Cassandra (Facebook), BigTable (Google)...
La quasi-totalit\u00e9 de ces SGBD fonctionnent avec un mod\u00e8le client-serveur.
Nous allons travailler principalement avec le langage SQLite peut lui s'utiliser directement sans d\u00e9marrer un serveur : la base de donn\u00e9es est enti\u00e8rement repr\u00e9sent\u00e9e dans le logiciel utilisant SQLite (dans notre cas, DB Browser for SQLite). Sa simplicit\u00e9 d'utilisation en fera notre choix pour illustrer cette pr\u00e9sentation du langage SQL.
"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/cours/#1-introduction-au-langage-sql","title":"1. Introduction au langage SQL","text":"Dans toute la suite, nous allons travailler avec la base de donn\u00e9es livres.db
qui provient de l'ouvrage paru chez Ellipses, cit\u00e9 en bibliographie.
Pr\u00e9-requis : t\u00e9l\u00e9chargez la base de donn\u00e9es livres.db.
1. En ligne avecsqliteonline.com
livres.db
pr\u00e9c\u00e9demment t\u00e9l\u00e9charg\u00e9.2. Avec un logiciel externe : DB Browser for SQLite
DB Browser for SQLite
, t\u00e9l\u00e9chargeable \u00e0 l'adresse https://sqlitebrowser.org/livres.db
. Dans toute la suite, les manipulations sont \u00e0 faire en interrogeant la base de donn\u00e9es livres.db
, avec l'une des m\u00e9thodes indiqu\u00e9es ci-dessus.
Voici le diagramme relationnel de cette base :
Requ\u00eate basique : SELECT, FROM
SELECT titre\nFROM livre ;\n
On veut tous les titres de la table \u00ablivre\u00bb.
Remarques
Les mots-cl\u00e9s SQL sont traditionnellement \u00e9crits en MAJUSCULES.
Le ;
signale la fin de l'instruction. Il peut donc \u00eatre omis s'il n'y a pas d'instructions encha\u00een\u00e9es (ce qui sera toujours notre cas).
L'indentation n'est pas syntaxique (pas comme en Python). On peut faire des retours \u00e0 la ligne et des indentations pour rendre le code plus lisible.
Requ\u00eate filtr\u00e9e : SELECT, FROM, WHERE
SELECT titre FROM livre WHERE annee >= 1990;\n
On veut les titres de la table \u00ablivre\u00bb qui sont parus apr\u00e8s (ou en ) 1990;
Le mot-cl\u00e9 WHERE doit \u00eatre suivi d'un bool\u00e9en. Les op\u00e9rateurs classiques =
, !=
, >
, >=
, <
, <=
peuvent \u00eatre utilis\u00e9s, mais aussi le mot-cl\u00e9 IN :
Requ\u00eate avec plusieurs possibilit\u00e9s : WHERE ... IN...
SELECT titre FROM livre WHERE annee IN (1990, 1991, 1992);\n
On veut les titres de la table \u00ablivre\u00bb qui sont parus en 1990, 1991 ou 1992.
Requ\u00eate avec bool\u00e9ens : AND - OR
SELECT titre FROM livre WHERE annee >= 1970\nAND annee <= 1980\nAND editeur = 'Dargaud';\n
On veut les titres de la table \u00ablivre\u00bb qui sont parus entre 1970 et 1980 chez l'\u00e9diteur Dargaud;
Requ\u00eate approch\u00e9e : LIKE
SELECT titre FROM livre WHERE titre LIKE '%Ast\u00e9rix%';\n
On veut les titres de la table \u00ablivre\u00bb dont le titre contient la cha\u00eene de caract\u00e8res \"Ast\u00e9rix\". Le symbole %
est un joker qui peut symboliser n'importe quelle cha\u00eene de caract\u00e8res.
Plusieurs colonnes
SELECT titre, isbn FROM livre WHERE annee >= 1990;\n
On veut les titres et les ISBN de la table \u00ablivre\u00bb qui sont parus apr\u00e8s 1990.
Toutes les colonnes : *
SELECT * FROM livre WHERE annee >= 1990;\n
On veut toutes les colonnes disponibles de la table \u00ablivre\u00bb pour les livres qui sont parus apr\u00e8s 1990. L'ast\u00e9risque *
est un joker (wildcard en anglais).
Renommer les colonnes : AS
SELECT titre AS titre_du_livre FROM livre WHERE annee >= 1990;\n
Lors de l'affichage du r\u00e9sulats et dans la suite de la requ\u00eate (important), la colonne \"titre\" est renomm\u00e9e \"titre_du_livre\".
Remarque L'alias AS
sera souvent utilis\u00e9 pour raccourcir un nom, notamment lors des jointures de plusieurs tables (voir plus loin).
Les requ\u00eates effectu\u00e9es jusqu'ici ont juste s\u00e9lectionn\u00e9 des donn\u00e9es gr\u00e2ce \u00e0 diff\u00e9rents filtres : aucune action \u00e0 partir de ces donn\u00e9es n'a \u00e9t\u00e9 effectu\u00e9e. Nous allons maintenant effectuer des op\u00e9rations \u00e0 partir des donn\u00e9es s\u00e9lectionn\u00e9es. On appelle ces op\u00e9rations des op\u00e9rations d'agr\u00e9gation.
"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/cours/#121-exemple-7","title":"1.2.1 Exemple 7","text":"Compter : COUNT
SELECT COUNT(*) AS total FROM livre\nWHERE titre LIKE \"%Ast\u00e9rix%\";\n
On veut compter le nombre d'enregistrements de la tables livres comportant le mot \"Ast\u00e9rix\". Le r\u00e9sultat sera le seul \u00e9l\u00e9ment d'une colonne nomm\u00e9e \u00abtotal\u00bb.
Additionner : SUM
SELECT SUM(annee) AS somme\nFROM livre\nWHERE titre LIKE \"%Ast\u00e9rix%\";\n
On veut additionner les ann\u00e9es des livres de la tables livres comportant le mot \"Ast\u00e9rix\". Le r\u00e9sultat sera le seul \u00e9l\u00e9ment d'une colonne nomm\u00e9e \u00absomme\u00bb. Attention : dans notre cas pr\u00e9cis, ce calcul n'a aucun sens...
Faire une moyenne : AVG
SELECT AVG(annee) AS moyenne\nFROM livre\nWHERE titre LIKE \"%Ast\u00e9rix%\";\n
On veut calculer la moyenne des ann\u00e9es de parution des livres de la table livres comportant le mot \"Ast\u00e9rix\". Le r\u00e9sultat sera le seul \u00e9l\u00e9ment d'une colonne nomm\u00e9e \u00abmoyenne\u00bb. Attention : l\u00e0 encore, ce calcul n'a aucun sens...
Trouver les extremums : MIN, MAX
SELECT MIN(annee) AS minimum\nFROM livre\nWHERE titre LIKE \"%Ast\u00e9rix%\";\n
On veut trouver la plus petite valeur de la colonne \u00abannee\u00bb parmi les livres de la tables livre comportant le mot \"Ast\u00e9rix\". Le r\u00e9sultat sera le seul \u00e9l\u00e9ment d'une colonne nomm\u00e9e minimum. Le fonctionnement est identique avec MAX pour la recherche du maximum.
Classer des valeurs : ORDER BY, ASC, DESC, LIMIT
Commande :
SELECT titre, annee FROM livre\nWHERE titre LIKE \"%Ast\u00e9rix%\"\nORDER BY annee DESC;\n
Traduction :
On veut afficher tous les albums d'Ast\u00e9rix, et leur ann\u00e9e de parution, class\u00e9s par ann\u00e9e d\u00e9croissante.
Comportement par d\u00e9faut : Si le param\u00e8tre ASC ou DESC est omis, le classement se fait par ordre croissant (donc ASC est le param\u00e8tre par d\u00e9faut).
Utilisation de LIMIT : Le mot-cl\u00e9 LIMIT (suivi d'un nombre) permet de limiter le nombre de r\u00e9sultats affich\u00e9s. Ainsi la requ\u00eate
SELECT titre, annee FROM livre\nWHERE titre LIKE \"%Ast\u00e9rix%\"\nORDER BY annee DESC\nLIMIT 1;\n
permet d'obtenir les renseignements sur l'Ast\u00e9rix le plus r\u00e9cent. Suppression des doublons : DISTINCT
SELECT DISTINCT editeur FROM livre;\n
On veut la liste de tous les \u00e9diteurs. Sans le mot-cl\u00e9 DISTINCT
, beaucoup de doublons appara\u00eetraient.
Observons le contenu de la table \u00abemprunt\u00bb :
SELECT * FROM emprunt;\n
Le contenu est peu lisible : qui a emprunt\u00e9 quel livre ? Souvenons-nous du diagramme de la base de donn\u00e9es.
Pour que la table \u00abemprunt\u00bb soit lisible, il faudrait (dans un premier temps) que l'on affiche \u00e0 la place de l'ISBN le titre de l'ouvrage. Or ce titre est disponible dans la table \u00ablivres\u00bb. On va donc proc\u00e9der \u00e0 une jointure de ces deux tables.
"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/cours/#131-exemple-13","title":"1.3.1 Exemple 13","text":"Jointure de 2 tables : JOIN
SELECT livre.titre, emprunt.code_barre, emprunt.retour FROM emprunt\nJOIN livre ON emprunt.isbn = livre.isbn;\n
L'expression
JOIN livre ON emprunt.isbn = livre.isbn\n
doit se comprendre comme ceci : on \u00abinvite\u00bb la table \u00ablivres\u00bb (dont on va afficher la colonne \u00abtitre\u00bb). La correspondance entre la table \u00ablivres\u00bb et la table \u00abemprunt\u00bb doit se faire sur l'attribut ISBN, qui est la cl\u00e9 primaire de \u00ablivres\u00bb et une cl\u00e9 \u00e9trang\u00e8re d'\u00abemprunts\u00bb. Il est donc tr\u00e8s important de sp\u00e9cifier ce sur quoi les deux tables vont se retrouver (ici, l'ISBN) Le r\u00e9sultat pr\u00e9c\u00e9dent a permis d'am\u00e9liorer la visibilit\u00e9 de la table \u00abemprunt\u00bb, mais il reste la colonne \u00abcode_barre\u00bb qui est peu lisible. Nous pouvons la remplacer par le titre du livre, en faisant une nouvelle jointure, en invitant maintenant les deux tables \u00ablivre\u00bb et \u00abusager\u00bb.
Jointure de 3 tables : JOIN
SELECT u.nom, u.prenom, l.titre, e.retour FROM emprunt AS e\nJOIN livre AS l ON e.isbn = l.isbn\nJOIN usager AS u ON e.code_barre = u.code_barre;\n
Traduction : Il faut bien comprendre que la table principale qui nous int\u00e9resse ici est \u00abemprunts\u00bb, mais qu'on modifie les valeurs affich\u00e9es en allant chercher des correspondances dans deux autres tables. Notez ici que des alias sont donn\u00e9s aux tables (par AS) afin de faciliter l'\u00e9criture.
R\u00e9sultat :
Cet exercice en ligne est propos\u00e9 le Knight Lab de l'universit\u00e9 am\u00e9ricaine Northwerstern University.
Le point de d\u00e9part de l'histoire : un meurtre a \u00e9t\u00e9 commis dans la ville de SQL City le 15 janvier 2018.
\u00c0 partir de ce point de d\u00e9part et d'une base de donn\u00e9es dont le diagramme est donn\u00e9 ci-dessous, il s'agit de trouver le meurtrier.
Rendez-vous sur cette page, et bonne enqu\u00eate \u00e0 coups de requ\u00eates !
Vous pouvez travailler en ligne ou bien dans votre SGBD pr\u00e9f\u00e9r\u00e9, avec la base sql-murder-mystery.db. Attention pour valider votre r\u00e9ponse, il faudra vous rendre en bas de la page officielle.
Vous pouvez trouver des \u00e9l\u00e9ments de correction ici...
rappel :
L'objectif est de cr\u00e9er la table suivante :
id Nom Maths Anglais NSI 1 Alice 16 11 17 2 Bob 12 15 10 3 Charles 9 11 18"},{"location":"T4_Bases_de_donnees/4.2_Langage_SQL/cours/#21-exemple-15","title":"2.1 Exemple 15","text":"La cr\u00e9ation d'une table n'est pas explicitement au programme de NSI. Personne ne sait vraiment pourquoi
Cr\u00e9ation d'une table : CREATE TABLE
CREATE TABLE Table_notes (\nId INTEGER PRIMARY KEY,\nNom TEXT,\nMaths INTEGER,\nAnglais INTEGER,\nNSI INTEGER\n);\n
Remarque : C'est l'utilisateur qui sp\u00e9cifie, \u00e9ventuellement, quel attribut sera une cl\u00e9 primaire.
R\u00e9sultat : Dans DB Browser, il faut avoir au pr\u00e9alable cr\u00e9\u00e9 une nouvelle base de donn\u00e9es.
Insertion de valeurs : INSERT INTO, VALUES
Commande :
INSERT INTO Table_notes VALUES (1, 'Alice', 16, 11, 17),\n(2, 'Bob', 12, 15, 10),\n(3, 'Charles', 9, 11, 18);\n
R\u00e9sultat :
Essayons d'ins\u00e9rer un 4\u00e8me enregistrement ayant le m\u00eame id
qu'un autre \u00e9l\u00e8ve.
Commande :
INSERT INTO Table_notes VALUES (3, 'Denis', 18, 10, 12);\n
R\u00e9sultat : La contrainte de relation est viol\u00e9e : le SGBD \u00abprot\u00e8ge\u00bb la base de donn\u00e9es en n'acceptant pas la proposition d'insertion. La base de donn\u00e9es n'est pas modifi\u00e9e.
Remarque : Il est possible de \u00abd\u00e9l\u00e9guer\u00bb la gestion des valeurs de la cl\u00e9 primaire avec l'instruction AUTOINCREMENT
. La d\u00e9claration de la table et l'insertion des valeurs serait :
CREATE TABLE Table_notes (\nId INTEGER PRIMARY KEY AUTOINCREMENT,\nNom TEXT,\nMaths INTEGER,\nAnglais INTEGER,\nNSI INTEGER\n);\n\nINSERT INTO Table_notes (Nom, Maths, Anglais, NSI) VALUES\n('Alice', 16, 11, 17),\n('Bob', 12, 15, 10),\n('Charles', 9, 11, 18);\n
et le r\u00e9sultat serait : L'attribut id
est donc g\u00e9r\u00e9 automatiquement par le SGBD.
Modification d'une valeur UPDATE, SET
Pour modifier la note de Maths d'Alice :
UPDATE Table_notes SET Maths = 18 WHERE Nom = 'Alice';\n
Suppression d'un enregistrement : DELETE
Pour supprimer totalement la ligne concernant Charles :
DELETE FROM Table_notes WHERE Nom = 'Charles';\n
Si une autre table contient par exemple l'attribut id
comme cl\u00e9 \u00e9trang\u00e8re, et si l'id
de Charles fait partie de cette table, le SGBD refusera de supprimer cette ligne, afin de ne pas violer la contrainte de r\u00e9f\u00e9rence.
Suppression totale d'une table : DROP TABLE
Pour supprimer totalement et d\u00e9fitivement la table :
DROP TABLE Table_notes;\n
L\u00e0 encore, si une autre table est reli\u00e9e \u00e0 Table_notes
par une cl\u00e9 \u00e9trang\u00e8re, la suppression sera bloqu\u00e9e par le SGBD.
\u00e0 venir...
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/","title":"Syst\u00e8mes sur puce","text":"pr\u00e9ambule : cours de Premi\u00e8re sur l'architecture Von Neumann
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#1-loi-de-moore-et-miniaturisation-progressive","title":"1. Loi de Moore et miniaturisation progressive","text":""},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#11-la-loi-de-moore","title":"1.1 La Loi de Moore","text":"En 1965, Gordon Moore postule que le nombre de transistors pr\u00e9sents sur une puce de microprocesseur doublera tous les deux ans.
Cette pr\u00e9diction s'est r\u00e9v\u00e9l\u00e9e \u00e9tonnamment juste (\u00e0 quelques approximations pr\u00e8s) et les \u00e9quipements \u00e9lectroniques n'ont depuis jamais cess\u00e9 de devenir toujours plus performants / miniatures / \u00e9conomes en \u00e9nergie.
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#12-evolution-de-la-taille-des-ordinateurs","title":"1.2 \u00c9volution de la taille des ordinateurs","text":""},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#121-ibm-650-le-premier-ordinateur-fabrique-en-serie-1955","title":"1.2.1 IBM 650, le premier ordinateur fabriqu\u00e9 en s\u00e9rie (1955)","text":"Cet ordinateur n'a pas encore de transistors mais des tubes \u00e0 vide.
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#122-ibm-7090-le-premier-ordinateur-a-transistors-1959","title":"1.2.2 IBM 7090, le premier ordinateur \u00e0 transistors (1959)","text":"Le transistor
Le transistor est un composant \u00e9lectronique essentiel : il permet de laisser (ou non) passer un courant \u00e9lectrique.
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#123-le-role-crucial-de-la-taille-des-transistors","title":"1.2.3 Le r\u00f4le crucial de la taille des transistors","text":"Ainsi que l'avait pr\u00e9dit Moore, c'est la progression du nombre de transistors gravables sur le processeur qui guidera pendant des ann\u00e9es l'\u00e9volution de l'informatique :
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#2-composition-dun-pc-actuel","title":"2. Composition d'un pc actuel","text":"Chaque composant a un r\u00f4le sp\u00e9cifique. Ils communiquent entre eux par des bus de diff\u00e9rentes vitesses. Chaque composant est rempla\u00e7able, et il est possible d'ajouter de nouveaux composants sur la carte m\u00e8re qui poss\u00e8de des slots d'extension.
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#3-tout-un-pc-sur-une-seule-puce-les-soc","title":"3. Tout un pc sur une seule puce : les SoC","text":""},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#31-lintegration-de-composants-differents-au-sein-dune-meme-puce","title":"3.1 L'int\u00e9gration de composants diff\u00e9rents au sein d'une m\u00eame puce","text":"Le principe d'un syst\u00e8me sur puce ou System On a Chip (SoC) est d'int\u00e9grer au sein d'une puce unique un ensemble de composants habituellement physiquement dissoci\u00e9s dans un ordinateur classique (ordinateur de bureau ou ordinateur portable).
On peut retrouver ainsi au sein d'une m\u00eame puce :
+ \u00e9ventuellement des composants de communication (WiFi, Bluetooth...)
Avantages et inconv\u00e9nients d'un SoC
Avantages
Inconv\u00e9nients
Observons par exemple la puce Apple A15 Bionic, qui \u00e9quipe les iPhone 13. Cette puce est fabriqu\u00e9e par TSMC.
Cette puce contient :
L'int\u00e9gration dans un SoC n'est pas totale : il reste des puces d\u00e9di\u00e9es \u00e0 des t\u00e2ches tr\u00e8s sp\u00e9cifiques qui ne sont pas forc\u00e9ment int\u00e9gr\u00e9es dans le SoC.
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#41-au-sein-dun-telephone","title":"4.1 Au sein d'un t\u00e9l\u00e9phone","text":"Ainsi, d'apr\u00e8s le site iFixit, on peut retrouver ceci dans l'iPhone Pro 13, au c\u00f4t\u00e9 de la puce A15 \u00e9voqu\u00e9e plus haut :
On voit que (par exemple) qu'il existe une puce sp\u00e9cifique pour g\u00e9rer l'audio, une puce sp\u00e9cifique pour le module WiFi, une puce sp\u00e9cifique pour le module Modem 5G...
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#42-en-electronique-grand-public","title":"4.2 En \u00e9lectronique \u00abgrand public\u00bb","text":"Ce composant (pouvant \u00eatre utilis\u00e9 dans un montage personnel, sur un Arduino par exemple) ne sert qu'\u00e0 faire des calculs cryptographiques.
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#43-un-principe-general","title":"4.3 Un principe g\u00e9n\u00e9ral","text":"Il est important de comprendre que certains processeurs sont optimis\u00e9s pour un certains types de calcul. C'est le cas par exemple d'une carte graphique, qui excelle dans le calcul de rendus de polygones.
On s'est aper\u00e7u que cette aptitude \u00e0 faire des calculs \u00abb\u00eates et r\u00e9p\u00e9titifs\u00bb \u00e9tait parfaite pour faire les calculs math\u00e9matiques (inutiles) n\u00e9cessaires au minage des cryptomonnaies. Les cartes graphiques ont donc \u00e9t\u00e9 d\u00e9tourn\u00e9es de leur usage originel, \u00e0 cause de la sp\u00e9cificit\u00e9 de l'impl\u00e9mentation de leur puce.
De m\u00eame, les calculs sur les r\u00e9seaux de neurones (essentiels en IA) n\u00e9cessitent une grande rapidit\u00e9 dans les multiplications de matrices. Pour cette raison, Apple a int\u00e9gr\u00e9 directement dans son SoC A15 une puce sp\u00e9calis\u00e9e dans ces calculs (voir plus haut).
"},{"location":"T5_Architecture_materielle/5.1_Systemes_sur_puce/cours/#44-conclusion","title":"4.4 Conclusion","text":"L'orientation actuelle de l'\u00e9lectronique est donc \u00e0 la fois :
Exercice (Polyn\u00e9sie 2021)
\u00c9nonc\u00e9CorrectionUn constructeur automobile int\u00e8gre \u00e0 ses v\u00e9hicules des syst\u00e8mes embarqu\u00e9s, comme par exemple un syst\u00e8me de guidage par satellites (GPS), un syst\u00e8me de freinage antiblocage (ABS)...
Ces dispositifs utilisent des syst\u00e8mes sur puces (SoC : System on a Chip).
Citer deux avantages \u00e0 utiliser ces syst\u00e8mes sur puces plut\u00f4t qu'une architecture classique d'ordinateur.
Bibliographie / Sitographie2021, sujet Am\u00e9rique du Nord
Un constructeur automobile utilise des ordinateurs pour la conception de ses v\u00e9hicules. Ceux-ci sont munis d'un syst\u00e8me d'exploitation ainsi que de nombreuses applications parmi lesquelles on peut citer :
Chaque ordinateur est \u00e9quip\u00e9 des p\u00e9riph\u00e9riques classiques : clavier, souris, \u00e9cran et est reli\u00e9 \u00e0 une imprimante r\u00e9seau.
La lettre M signifie que la donn\u00e9e est mobilis\u00e9e par l'application ; la lettre A signifie que l'application est en attente de cette donn\u00e9e.
Lecture du tableau : le logiciel de traitement de texte mobilise (M) la donn\u00e9e D1 et est en attente (A) de la donn\u00e9e D2.
D1 D2 D3 D4 D5 Traitement de texte M A - - - Tableur A - - - M SGBD - M A A - CAO - - A M AMontrer que les applications s'attendent mutuellement. Comment s'appelle cette situation ?
CorrectionLe cycle en pointill\u00e9s montre que les applications s'attendent mutuellement : cette situation s'appelle un interblocage.
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/Exercices/#exercice-2","title":"Exercice 2","text":"2021, M\u00e9tropole sujet 1
Partie A Cette partie est un questionnaire \u00e0 choix multiples (QCM). Pour chacune des questions, une seule des quatre r\u00e9ponses est exacte.
dir
ps
man
ls
stop
interrupt
end
kill
Partie B
Q1. Un processeur choisit \u00e0 chaque cycle d\u2019ex\u00e9cution le processus qui doit \u00eatre ex\u00e9cut\u00e9. Le tableau ci-dessous donne pour trois processus P1, P2, P3 :
Le num\u00e9ro de priorit\u00e9 est d\u2019autant plus petit que la priorit\u00e9 est grande. On suppose qu\u2019\u00e0 chaque instant, c\u2019est le processus qui a le plus petit num\u00e9ro de priorit\u00e9 qui est ex\u00e9cut\u00e9, ce qui peut provoquer la suspension d\u2019un autre processus, lequel reprendra lorsqu\u2019il sera le plus prioritaire.
Reproduire le tableau ci-dessous sur la copie et indiquer dans chacune des cases le processus ex\u00e9cut\u00e9 \u00e0 chaque cycle.
correctionQ2. On suppose maintenant que les trois processus pr\u00e9c\u00e9dents s\u2019ex\u00e9cutent et utilisent une ou plusieurs ressources parmi R1, R2 et R3. Parmi les sc\u00e9narios suivants, lequel provoque un interblocage ? Justifier.
correctionSeul le scenario 2 pr\u00e9sente un cycle d'interd\u00e9pendance : seul le sc\u00e9nario 2 va donc provoquer un interblocage.
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/Exercices/#exercice-3","title":"Exercice 3","text":"2021, M\u00e9tropole sujet 2
Partie A
Dans un bureau d\u2019architectes, on dispose de certaines ressources qui ne peuvent \u00eatre utilis\u00e9es simultan\u00e9ment par plus d\u2019un processus, comme l\u2019imprimante, la table tra\u00e7ante, le modem. Chaque programme, lorsqu\u2019il s\u2019ex\u00e9cute, demande l\u2019allocation des ressources qui lui sont n\u00e9cessaires. Lorsqu\u2019il a fini de s\u2019ex\u00e9cuter, il lib\u00e8re ses ressources.
On appelle p1, p2 et p3 les processus associ\u00e9s respectivement aux programmes 1, 2 et 3
Q1. Les processus s'ex\u00e9cutent de mani\u00e8re concurrente. Justifier qu'une situation d'interblocage peut se produire.
correctionSupposons que chaque ligne de chaque programme s'effectue cons\u00e9cutivement (d'abord la ligne 1 de P1, puis celle de P2, puis celle de P3, puis la ligne 2 de P1, etc.). Dans ce cas-l\u00e0, le diagramme de d\u00e9pendance serait : On voit appara\u00eetre un cycle d'interd\u00e9pendance : il peut donc y avoir une situation d'interblocage.
Q2. Modifier l'ordre des instructions du programme 3 pour qu'une telle situation ne puisse pas se produire. Aucune justification n'est attendue.
correctionOn peut par exemple inverser la demande d'imprimante et de table tra\u00e7ante.
Il sera \u00e0 l'\u00e9tat bloqu\u00e9.
Partie B
Avec une ligne de commande dans un terminal sous Linux, on obtient l'affichage suivant :
La documentation Linux donne la signification des diff\u00e9rents champs :
UID
: identifiant utilisateur effectif ;PID
: identifiant de processus ;PPID
: PID
du processus parent ;C
: partie enti\u00e8re du pourcentage d'utilisation du processeur par rapport au temps de vie des processus ;STIME
: l'heure de lancement du processus ;TTY
: terminal de contr\u00f4leTIME
: temps d'ex\u00e9cutionCMD
: nom de la commande du processusQ1. Parmi les quatre commandes suivantes, laquelle a permis cet affichage ?
ls -l
ps -ef
cd ..
chmod 741 processus.txt
Q2. Quel est l'identifiant du processus parent \u00e0 l'origine de tous les processus concernant le navigateur Web (chromium-browser) ?
Q3. Quel est l'identifiant du processus dont le temps d'ex\u00e9cution est le plus long ?
correctionQ1. b.
Q2. 6211
Q3. 6211
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/Exercices/#exercice-4","title":"Exercice 4","text":"2021, M\u00e9tropole Candidats Libres sujet 2
Q1. Les \u00e9tats possibles d\u2019un processus sont : pr\u00eat, \u00e9lu, termin\u00e9 et bloqu\u00e9.
Q1.a. Expliquer \u00e0 quoi correspond l\u2019\u00e9tat \u00e9lu. Q1.b. Proposer un sch\u00e9ma illustrant les passages entre les diff\u00e9rents \u00e9tats.
correctionQ1a. \u00c9lu signifie que le processus est actuellement en cours d'ex\u00e9cution par le processeur.
Q1b.
Q2. On suppose que quatre processus C\u2081, C\u2082, C\u2083 et C\u2084 sont cr\u00e9\u00e9s sur un ordinateur, et qu\u2019aucun autre processus n\u2019est lanc\u00e9 sur celui-ci, ni pr\u00e9alablement ni pendant l\u2019ex\u00e9cution des quatre processus. L\u2019ordonnanceur, pour ex\u00e9cuter les diff\u00e9rents processus pr\u00eats, les place dans une structure de donn\u00e9es de type file. Un processus pr\u00eat est enfil\u00e9 et un processus \u00e9lu est d\u00e9fil\u00e9.
Q2.a. Parmi les propositions suivantes, recopier celle qui d\u00e9crit le fonctionnement des entr\u00e9es/sorties dans une file :
Q2a. ii. Premier entr\u00e9, premier sorti
Q2.b. On suppose que les quatre processus arrivent dans la file et y sont plac\u00e9s dans l\u2019ordre C\u2081, C\u2082, C\u2083 et C\u2084.
Sur la frise chronologique ci-dessous, les \u00e9tats du processus C\u2082 sont donn\u00e9s. Compl\u00e9ter la frise avec les \u00e9tats des processus C\u2081, C\u2083 et C\u2084.
correction "},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/Exercices/#exercice-5","title":"Exercice 5","text":"Exercice 2 du sujet Am\u00e9rique du Nord J2 2022
correction Q1.a.proposition 2
correction Q1.b.cd lycee
mkdir algorithmique
rm image1.jpg
927
correction Q2.b.1058 (ou 927)
correction Q2.c.1153 et 1154
correction Q2.d.923 et 1036
correction Q3.a. correction Q3.b. correction Q4.a.Un processus peut \u00eatre Pr\u00eat, Elu, ou Bloqu\u00e9. Si chaque ligne de chaque processus est ex\u00e9cut\u00e9e \u00e0 tour de r\u00f4le, un cycle d'interd\u00e9pendance apparait, et donc un interblocage.
correction Q4.b.En inversant la demande de R3 et R1 pour le processus P3, le risque d'interblocage dispara\u00eet. Fichier svg d'explication
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/","title":"Gestion des processus","text":""},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#1-notion-de-processus","title":"1. Notion de processus","text":""},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#11-definition-dun-processus","title":"1.1 D\u00e9finition d'un processus","text":"Lorsqu'un programme est ex\u00e9cut\u00e9 sur un ordinateur, celui-ci va cr\u00e9er un (ou plusieurs) processus.
On dit que ce processus est une instance d'ex\u00e9cution de ce programme.
Un processus est caract\u00e9ris\u00e9 par :
ps
","text":"Dans un terminal, la commande ps
va permettre d'afficher la liste des processus actifs.
Plus pr\u00e9cis\u00e9ment, nous allons utiliser la commande ps -lu nom_user
. L'option l
permet d'afficher un grand nombre de renseignements et l'option u
permet de sp\u00e9cifier l'utilisateur propri\u00e9taire des processus.
On retrouve notamment dans ce tableau les colonnes :
CMD
(Command) : le nom de la commande qui a cr\u00e9\u00e9 le processus. Vous pouvez y retrouver par ordre chronologique le nom de tous les programmes actifs. Certains sont ceux que vous avez ouverts volontairement (navigateur...) mais on y trouve surtout tous les programmes n\u00e9cessaires au bon fonctionnement du syst\u00e8me d'exploitation. Le dernier processus en bas de la liste est forc\u00e9ment ps
, puisque vous venez de l'appeler.
PID
(Process Identifier) : le num\u00e9ro unique d'identification, affect\u00e9 chronologiquement par le syst\u00e8me d'exploitation. Le processus de PID \u00e9gal \u00e0 1 est systemd
, qui est le tout premier programme lanc\u00e9 par le noyau Linux au d\u00e9marrage.
PPID
(Parent PID) : certains processus vont eux-m\u00eames lancer plusieurs processus-fils, qui porteront le m\u00eame nom. C'est ainsi qu'on peut retrouver de multiples processus s'appelant chrome
:
Ici, l'instance \u00abprincipale\u00bb de Chrome (PID
1453) a g\u00e9n\u00e9r\u00e9 6 autres instances de PID
diff\u00e9rents, dont le PPID
vaut 1453.
Dans Chrome/Chromium, vous pouvez comprendre le r\u00f4le de chaque processus en le retrouvant dans le gestionnaire des t\u00e2ches (clic-droit sur une zone vide de la barre d'onglets)
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#122-la-commande-pstree","title":"1.2.2 La commandepstree
","text":"\u00c0 noter que la commande pstree
permet d'afficher les processus sous forme d'arborescence :
top
","text":"La commande top
permet de conna\u00eetre en temps r\u00e9el la liste des processus, class\u00e9s par ordre d\u00e9croissant de consommation de CPU.
On ferme top
par la combinaison de touches Ctrl-C
.
Pourcentage d'utilisation du CPU
En face de chaque processus est affich\u00e9e sa consommation de CPU. Elle est calcul\u00e9e en prenant, sur un intervalle de temps donn\u00e9, le temps qu'a pass\u00e9 le CPU \u00e0 traiter le processus en question, et en divisant ce temps par le temps total de la mesure.
\\[\\text{Pourcentage d'utilisation CPU} = \\frac{\\text{Temps d'utilisation CPU}}{\\text{Temps total \u00e9coul\u00e9}} \\times 100\\]Si on rep\u00e8re alors un processus qui consomme beaucoup trop de ressources, on peut utiliser...
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#124-la-commande-kill","title":"1.2.4 La commandekill
","text":"La commande kill
permet de fermer un processus, en donnant son PID
en argument.
Exemple : kill 1453
tuera Chrome (voir la capture du 1.2.1)
Un ordinateur donne l'illusion de r\u00e9aliser plusieurs t\u00e2ches simultan\u00e9ment. Hormis pour les processeurs fonctionnant avec plusieurs c\u0153urs, il n'en est rien.
Comme nous l'avons vu, ces processus sont lanc\u00e9s s\u00e9quentiellement par le syst\u00e8me d'exploitation, et sont ensuite en apparence tous \u00abactifs en m\u00eame temps\u00bb (les guillemets sont importants) : on parle de programmation concurrente.
Revenons sur l'expression \u00abactifs en m\u00eame temps\u00bb, car elle v\u00e9hicule une fausse id\u00e9e : ces processus sont bien vivants dans un m\u00eame laps de temps, mais ils s'ex\u00e9cutent LES UNS APR\u00c8S LES AUTRES, le processeur ne pouvant en traiter qu'un seul \u00e0 la fois.
Un cadencement extr\u00eamement rapide et efficace donne l'apparence d'une (fausse) simultan\u00e9it\u00e9. Nous allons la mettre en \u00e9vidence :
Consid\u00e9rons les fichiers progA.py
et progB.py
ci-dessous :
import time\n\nfor i in range(10):\n print(\"programme A en cours, it\u00e9ration\", i)\n time.sleep(0.02) \n
progB.pyimport time\ntime.sleep(0.01)\nfor i in range(10):\n print(\"programme B en cours, it\u00e9ration\", i)\n time.sleep(0.02) \n
Le programme progB.py
est l\u00e9g\u00e8rement retard\u00e9 au d\u00e9marrage par le time.sleep(0.01)
. Il devrait donc en r\u00e9sulter un entrelacement entre les phrases programme A en cours
et programme B en cours
.
L'ex\u00e9cution \u00abd'apparence simultan\u00e9e\u00bb de ces deux programmes peut se faire dans un Terminal via la commande python3 progA.py & python3 progB.py
.
Il en r\u00e9sulte ceci :
Nous retrouvons bien l'alternance pr\u00e9vue \u00e0 la lecture du code. Tout se passe donc comme si les deux processus avaient \u00e9t\u00e9 lanc\u00e9s et trait\u00e9s simultan\u00e9ment.
R\u00e9duisons maintenant les temporisations (en passant du centi\u00e8me de seconde \u00e0 la milliseconde):
progA.pyimport time\n\nfor i in range(10):\n print(\"programme A en cours, it\u00e9ration\", i)\n time.sleep(0.002) \n
progB.pyimport time\ntime.sleep(0.001)\nfor i in range(10):\n print(\"programme B en cours, it\u00e9ration\", i)\n time.sleep(0.002) \n
Il en r\u00e9sulte maintenant ceci :
L'alternance pr\u00e9vue n'est plus respect\u00e9e (et les r\u00e9sultats deviennent non-reproductibles).
Si la gestion des processus \u00e9tait r\u00e9ellement simultan\u00e9e, m\u00eame en consid\u00e9rant des ralentissements du processeur par des sollicitations ext\u00e9rieures, chaque processus serait ralenti de la m\u00eame mani\u00e8re : l'entrelacement des phrases serait toujours le m\u00eame.
En r\u00e9alit\u00e9, le processeur passe son temps \u00e0 alterner entre les divers processus qu'il a \u00e0 g\u00e9rer, et les met en attente quand il ne peut pas s'occuper d'eux. Il ob\u00e9it pour cela aux instructions de son ordonnanceur.
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#22-lordonnancement-des-processus","title":"2.2 L'ordonnancement des processus","text":""},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#221-differents-types-dordonnancement","title":"2.2.1 Diff\u00e9rents types d'ordonnancement","text":"Si on vous donne 4 t\u00e2ches A, B, C et D \u00e0 accomplir, vous pouvez d\u00e9cider :
Un processeur est confront\u00e9 aux m\u00eames choix : comment d\u00e9terminer quel processus doit \u00eatre trait\u00e9 \u00e0 quel moment ?
Le sch\u00e9ma ci-dessous (issu de ce site) pr\u00e9sente quelques politiques d'ordonnancement :
Sous Linux, l'ordonnancement est effectu\u00e9 par un syst\u00e8me hybride o\u00f9 les processus sont ex\u00e9cut\u00e9s \u00e0 tour de r\u00f4le (on parle de tourniquet ou de Round Robin) suivant un ordre de priorit\u00e9 dynamique.
Dans le cas (tr\u00e8s fr\u00e9quent maintenant) d'un processeur multi-c\u0153urs, le probl\u00e8me reste identique. Certes, sur 4 c\u0153urs, 4 processus pourront \u00eatre trait\u00e9s simultan\u00e9ment (une r\u00e9elle simultan\u00e9it\u00e9) mais il reste toujours beaucoup plus de processus \u00e0 traiter que de c\u0153urs dans le processeur... et un ordonnancement est donc toujours n\u00e9cessaire.
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#222-les-differents-etats-dun-processus","title":"2.2.2 Les diff\u00e9rents \u00e9tats d'un processus","text":"Selon que l'ordonnanceur aura d\u00e9cid\u00e9 de le confier ou non au processeur pour son ex\u00e9cution, un processus peut donc se trouver dans 3 \u00e9tats :
Voici les transitions possibles entre ces \u00e9tats (diagramme issu de https://info.blaisepascal.fr/nsi-processus-et-ressources) :
Ou de mani\u00e8re simplifi\u00e9e :
On peut utiliser la m\u00e9taphore suivante :
Sur le bureau d'un professeur, il y a 3 paquets de copies, correspondant aux classes A, B, et C. Ces paquets sont Pr\u00eats \u00e0 \u00eatre corrig\u00e9s.
Au cours de cette proc\u00e9dure, le professeur n'a toujours eu devant lui qu'un seul paquet de copies (soit A, soit B, soit C).
Pourquoi l'acc\u00e8s \u00e0 une ressource peut bloquer un processus ?
Pendant son ex\u00e9cution, un processus peut avoir besoin d'acc\u00e9der \u00e0 une ressource d\u00e9j\u00e0 occup\u00e9e (un fichier d\u00e9j\u00e0 ouvert, par exemple) ou \u00eatre en attente d'une entr\u00e9e-utilisateur (un input()
dans un code Python
par exemple). Dans ce cas-l\u00e0, le processeur va passer ce processus \u00e0 l'\u00e9tat Bloqu\u00e9, pour pouvoir ainsi se consacrer \u00e0 un autre processus.
Une fois d\u00e9bloqu\u00e9, le processus va repasser \u00e0 l'\u00e9tat Pr\u00eat et rejoindre (par exemple) la file d'attente des processus avant d'\u00eatre \u00e0 nouveau \u00c9lu et donc ex\u00e9cut\u00e9.
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#3-interblocage","title":"3. Interblocage","text":""},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#31-definition-et-exemple","title":"3.1 D\u00e9finition et exemple","text":"Comme nous venons de le voir, un processus peut \u00eatre dans l'\u00e9tat bloqu\u00e9 dans l'attente de la lib\u00e9ration d'une ressource.
Ces ressources (l'acc\u00e8s en \u00e9criture \u00e0 un fichier, \u00e0 un registre de la m\u00e9moire...) ne peuvent \u00eatre donn\u00e9es \u00e0 deux processus \u00e0 la fois. Des processus souhaitant acc\u00e9der \u00e0 cette ressource sont donc en concurrence sur cette ressource. Un processus peut donc devoir attendre qu'une ressource se lib\u00e8re avant de pouvoir y acc\u00e9der (et ainsi passer de l'\u00e9tat Bloqu\u00e9 \u00e0 l'\u00e9tat Pr\u00eat).
Probl\u00e8me : Et si deux processus se bloquent mutuellement la ressource dont ils ont besoin ?
Exemple : Consid\u00e9rons 2 processus A et B, et deux ressources R et S. L'action des processus A et B est d\u00e9crite ci-dessous :
D\u00e9roulement des processus A et B :
Les deux processus A et B sont donc dans l'\u00e9tat Bloqu\u00e9, chacun en attente de la lib\u00e9ration d'une ressource bloqu\u00e9e par l'autre : ils se bloquent mutuellement.
Cette situation (critique) est appel\u00e9e interblocage ou deadlock.
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#33-representation-schematique","title":"3.3 Repr\u00e9sentation sch\u00e9matique","text":"Avec ces conventions, la situation pr\u00e9c\u00e9dente peut donc se sch\u00e9matiser par :
Ce type de sch\u00e9ma fait appara\u00eetre un cycle d'interd\u00e9pendance, qui caract\u00e9rise ici la situation de deadlock.
"},{"location":"T5_Architecture_materielle/5.2_Gestion_des_processus/cours/#34-comment-sen-premunir-hp","title":"3.4 Comment s'en pr\u00e9munir ? (HP)","text":"Il existe trois strat\u00e9gies pour \u00e9viter les interblocages :
Exercice 1
Exercice 5 du sujet La R\u00e9union J1 2022
Correction Q1.a.Une adresse IPv4 se code \u00e0 l'aide de 4 octets.
Correction Q1.b.Le PC3 a pour adresse 172.150.4.30 / 24
. Cela signfie que son masque, en notation CIDR, est 24. Ses 24 premiers bits sont donc \u00e0 1. Cela correspond au masque 255.255.255.0
en notation d\u00e9cimale.
Pour \u00eatre dans le r\u00e9seau 1, il faut que le & logique entre l'IP de la machine et l'adresse du masque donne l'adresse r\u00e9seau (172.150.4.0
).
Le r\u00e9seau \u00e9tant en /24
(\u00e9quivalent au masque 255.255.255.0
), cela signifie que l'adresse IP de la machine soit de la forme 172.150.4.???
.
Attention, il faut en plus s'assurer que l'adresse ne soit pas d\u00e9j\u00e0 utilis\u00e9e, et qu'elle ne soit pas l'adresse du r\u00e9seau (172.150.4.0
) ou de broadcast (172.150.4.255
).
Il reste alors les adresses 4) et 6). (172.150.4.11
et 172.150.4.200
)
La commande permettant de conna\u00eetre son adresse IP est ifconfig
ou ip addr
sous Linux / MacOS. Ou bien ipconfig
sous Windows.
La solution de relier les switchs entre eux n'est pas satisfaisante. Les deux r\u00e9seaux ne pourront pas communiquer entre eux, \u00e0 moins d'\u00e9largir (beaucoup) leur masque de sous-r\u00e9seau.
La meilleure solution est d'installer un routeur entre les deux switchs, de lui attribuer une adresse IP dans chaque sous-r\u00e9seau, et de renseigner cette adresse IP comme adresse de passerelle sur chacun des PCs des deux sous-r\u00e9seaux.
Correction Q5.def adresse(IP, liste_IP):\n if IP in liste_IP:\n print(\"trouv\u00e9e\")\n else:\n liste_IP.append(IP)\n print(\"pas trouv\u00e9e, ajout\u00e9e\")\n
Exercice 2
\u00c9nonc\u00e9CorrectionCr\u00e9er une fonction meme_sous_reseau(ip_a, ip_b, masque)
qui renvoie un bool\u00e9en indiquant si A et B sont partie du m\u00eame sous-r\u00e9seau.
Exercice (difficile) \u00e0 r\u00e9aliser en Test Driven Developpement \u00e0 partir du squelette de code ci-dessous, en testant chaque fonction apr\u00e8s sa r\u00e9alisation, jusqu'\u00e0 la fonction finale.
def convert_ip_to_list(ip):\n\"\"\"\n entr\u00e9e : ip (string) \n sortie : liste d'entiers\n \"\"\"\n # \u00e0 vous\n\ndef test_convert_ip_to_list():\n assert convert_ip_to_list('192.168.0.1') == [192, 168, 0, 1]\n\n\ndef nb_to_binary_word(masque):\n\"\"\"\n entr\u00e9e : masque (int)\n sortie : string\n \"\"\"\n # \u00e0 vous\n\ndef test_nb_convert_to_binary_word():\n assert nb_to_binary_word(24) == '11111111111111111111111100000000'\n\n\ndef binary_word_to_list(word):\n\"\"\"\n entr\u00e9e : word (string de 32 caract\u00e8res)\n sortie : liste de 4 entiers\n \"\"\"\n # \u00e0 vous\n\n\ndef test_binary_word_to_list():\n assert binary_word_to_list('11111111111111111111111100000000') == [255, 255, 255, 0]\n\n\n\ndef meme_sous_reseau(ip_a, ip_b, masque):\n\"\"\"\n ip_a: string contenant une IP (ex \"192.168.0.1\")\n ip_b : string contenant une IP\n masque : entier du masque en notation CIDR (ex : 24)\n renvoie un bool\u00e9en indiquant si ip_a et ip_b sont dans\n le m\u00eame sous-r\u00e9seau\n \"\"\"\n # \u00e0 vous\n\n\ndef test_meme_sous_reseau():\n assert meme_sous_reseau(\"192.168.0.1\", \"192.168.1.3\", 24) == False\n assert meme_sous_reseau(\"192.168.0.1\", \"192.168.1.3\", 20) == True\n assert meme_sous_reseau(\"192.168.0.1\", \"192.168.0.3\", 30) == True\n
Exercice difficile, il n'est pas \u00e0 savoir faire mais c'est bien de le comprendre !
def convert_ip_to_list(ip):\n\"\"\"\n entr\u00e9e : ip (string) \n sortie : liste d'entiers\n \"\"\"\n return [int(k) for k in ip.split(\".\")]\n\ndef test_convert_ip_to_list():\n assert convert_ip_to_list('192.168.0.1') == [192, 168, 0, 1]\n\n\ndef nb_to_binary_word(masque):\n\"\"\"\n entr\u00e9e : masque (int)\n sortie : string\n \"\"\"\n return '1'*masque + '0'*(32-masque)\n\ndef test_nb_convert_to_binary_word():\n assert nb_to_binary_word(24) == '11111111111111111111111100000000'\n\n\ndef binary_word_to_list(word):\n\"\"\"\n entr\u00e9e : word (string de 32 caract\u00e8res)\n sortie : liste de 4 entiers\n \"\"\"\n decoupe = [word[8*i:8*(i+1)] for i in range(4)]\n return [int(k,2) for k in decoupe]\n\ndef test_binary_word_to_list():\n assert binary_word_to_list('11111111111111111111111100000000') == [255, 255, 255, 0]\n\ndef meme_sous_reseau(ip_a, ip_b, masque):\n lstA = convert_ip_to_list(ip_a)\n lstB = convert_ip_to_list(ip_b)\n mask = binary_word_to_list(nb_to_binary_word(masque))\n resA = [lstA[i] & mask[i] for i in range(4)]\n resB = [lstB[i] & mask[i] for i in range(4)]\n return resA == resB\n\ndef test_meme_sous_reseau():\n assert meme_sous_reseau(\"192.168.0.1\", \"192.168.1.3\", 24) == False\n assert meme_sous_reseau(\"192.168.0.1\", \"192.168.1.3\", 20) == True\n assert meme_sous_reseau(\"192.168.0.1\", \"192.168.0.3\", 30) == True\n
Exercice 3
\u00c9nonc\u00e9Correction2020, sujet 0
On consid\u00e8re un r\u00e9seau compos\u00e9 de plusieurs routeurs reli\u00e9s de la fa\u00e7on suivante :
Le protocole RIP permet de construire les tables de routage des diff\u00e9rents routeurs, en indiquant pour chaque routeur la distance, en nombre de sauts, qui le s\u00e9pare d\u2019un autre routeur. Pour le r\u00e9seau ci-dessus, on dispose des tables de routage suivantes :
Question 1
Question 2
Le routeur C tombe en panne. Reconstruire la table de routage du routeur A en suivant le protocole RIP.
Q1.1. Le trajet parcouru de A \u00e0 G est A-C-F-G Q1.2. Table de routage de G :
Destination Routeur suivant Distance A F 3 B E 3 C E 2 D E 2 E E 1 F F 1Q2 Nouvelle table de routage de A :
Destination Routeur suivant Distance B B 1 D D 1 E D 2 G D 3 F D 4Exercice 4
\u00c9nonc\u00e9Correction2021, sujet M\u00e9tropole 1
On repr\u00e9sente ci-dessous un r\u00e9seau dans lequel R1, R2, R3, R4, R5 et R6 sont des routeurs. Le r\u00e9seau local L1 est reli\u00e9 au routeur R1 et le r\u00e9seau local L2 au routeur R6.
Dans cet exercice, les adresses IP sont compos\u00e9es de 4 octets, soit 32 bits. Elles sont not\u00e9es X1.X2.X3.X4, o\u00f9 X1, X2, X3 et X4 sont les valeurs des 4 octets, convertis en notation d\u00e9cimale. La notation X1.X2.X3.X4/n signifie que les n premiers bits de poids forts de l\u2019adresse IP repr\u00e9sentent la partie \u00ab r\u00e9seau \u00bb, les bits suivants repr\u00e9sentent la partie \u00ab h\u00f4te \u00bb. Toutes les adresses des h\u00f4tes connect\u00e9s \u00e0 un r\u00e9seau local ont la m\u00eame partie r\u00e9seau et peuvent donc communiquer directement. L\u2019adresse IP dont tous les bits de la partie \u00ab h\u00f4te \u00bb sont \u00e0 0 est appel\u00e9e \u00ab adresse du r\u00e9seau \u00bb.
On donne \u00e9galement des extraits de la table de routage des routeurs R1 \u00e0 R5 dans le tableau suivant :
1/ Un paquet part du r\u00e9seau local L1 \u00e0 destination du r\u00e9seau local L2.
1.a. En utilisant l\u2019extrait de la table de routage de R1, vers quel routeur R1 envoie-t-il ce paquet : R2 ou R3 ? Justifier.
1.b. A l\u2019aide des extraits de tables de routage ci-dessus, nommer les routeurs travers\u00e9s par ce paquet, lorsqu\u2019il va du r\u00e9seau L1 au r\u00e9seau L2.
2/ La liaison entre R1 et R2 est rompue.
2.a. Sachant que ce r\u00e9seau utilise le protocole RIP (distance en nombre de sauts), donner l\u2019un des deux chemins possibles que pourra suivre un paquet allant de L1 vers L2.
2.b. Dans les extraits de tables de routage ci-dessus, pour le chemin de la question 2.a, quelle(s) ligne(s) sera (seront) modifi\u00e9e(s) ?
3/ On a r\u00e9tabli la liaison entre R1 et R2. Par ailleurs, pour tenir compte du d\u00e9bit des liaisons, on d\u00e9cide d\u2019utiliser le protocole OSPF (distance li\u00e9e au co\u00fbt minimal des liaisons) pour effectuer le routage. Le co\u00fbt des liaisons entre les routeurs est donn\u00e9 par le tableau suivant :
a. Le co\u00fbt C d\u2019une liaison est donn\u00e9 ici par la formule \\(C = \\frac{10^9}{BP}\\)
o\u00f9 \\(BP\\) est la bande passante de la connexion en bps (bits par seconde). Sachant que la bande passante de la liaison R2-R3 est de 10 Mbps, calculer le co\u00fbt correspondant.
b. D\u00e9terminer le chemin parcouru par un paquet partant du r\u00e9seau L1 et arrivant au r\u00e9seau L2, en utilisant le protocole OSPF.
c. Indiquer pour quel(s) routeur(s) l\u2019extrait de la table de routage sera modifi\u00e9 pour un paquet \u00e0 destination de L2, avec la m\u00e9trique OSPF.
1.a. D'apr\u00e8s la table, R1 doit passer par la passerelle 86.154.10.1 qui correspond au routeur R2. 1.b. Le paquet va traverser R1, R2, R6 avant d'arriver \u00e0 L2. 2.a. RIP doit minimiser le nombre de sauts, donc les deux chemins minimaux possibles sont R1-R3-R4-R6 et R1-R3-R2-R6. 2.b. La ligne R1 sera modifi\u00e9e, il faudra partir vers R3 (et son r\u00e9seau 112.44.65.0/24). Les autres lignes n'ont pas \u00e0 \u00eatre modifi\u00e9es puisque R3 am\u00e8ne en R4 qui am\u00e8ne en R6. 3.a \\(\\dfrac{10^9}{10 \\times 10^6}=100\\) donc le co\u00fbt R2-R3 est 100. 3.b. Avec OSPF, le chemin qui minimise le co\u00fbt est le chemin R1-R2-R4-R5-R6 (co\u00fbt 103) : 3.c. Dans la table de routage initiale, il faut modifier R2 pour qu'elle envoie sur R4 (et non sur R6), mais aussi R4 pour qu'elle envoie sur R5 (et non sur R6).
Exercice 5
\u00c9nonc\u00e9Correction2021, sujet M\u00e9tropole 2 (sujet modifi\u00e9, correction d'erreurs sur les adresses passerelles)
Figure 1La figure 1 ci-dessus repr\u00e9sente le sch\u00e9ma d\u2019un r\u00e9seau d\u2019entreprise. Il y figure deux r\u00e9seaux locaux L1 et L2. Ces deux r\u00e9seaux locaux sont interconnect\u00e9s par les routeurs R2, R3, R4 et R5. Le r\u00e9seau local L1 est constitu\u00e9 des PC portables P1 et P2 connect\u00e9s \u00e0 la passerelle R1 par le switch Sw1. Les serveurs S1 et S2 sont connect\u00e9s \u00e0 la passerelle R6 par le switch Sw2.
Le tableau 1 suivant indique les adresses IPv4 des machines constituants le r\u00e9seau de l\u2019entreprise.
Tableau 1 : adresses IPv4 des machinesRappels et notations
Rappelons qu\u2019une adresse IP est compos\u00e9e de 4 octets, soit 32 bits. Elle est not\u00e9e X1.X2.X3.X4, o\u00f9 X1, X2, X3 et X4 sont les valeurs des 4 octets. Dans le tableau 1, les valeurs des 4 octets ont \u00e9t\u00e9 converties en notation d\u00e9cimale.
La notation X1.X2.X3.X4/n signifie que les n premiers bits de poids forts de l\u2019adresse IP repr\u00e9sentent la partie \u00ab r\u00e9seau \u00bb, les bits suivants de poids faibles repr\u00e9sentent la partie \u00ab machine \u00bb.
Toutes les adresses des machines connect\u00e9es \u00e0 un r\u00e9seau local ont la m\u00eame partie r\u00e9seau. L\u2019adresse IP dont tous les bits de la partie \u00ab machine \u00bb sont \u00e0 0 est appel\u00e9e \u00ab adresse du r\u00e9seau \u00bb. L\u2019adresse IP dont tous les bits de la partie \u00ab machine \u00bb sont \u00e0 1 est appel\u00e9e \u00ab adresse de diffusion \u00bb.
1/ 1.a. Quelles sont les adresses des r\u00e9seaux locaux L1 et L2 ?
1.b. Donner la plus petite et la plus grande adresse IP valides pouvant \u00eatre attribu\u00e9es \u00e0 un ordinateur portable ou un serveur sur chacun des r\u00e9seaux L1 et L2 sachant que l\u2019adresse du r\u00e9seau et l\u2019adresse de diffusion ne peuvent pas \u00eatre attribu\u00e9es \u00e0 une machine.
1.c. Combien de machines peut-on connecter au maximum \u00e0 chacun des r\u00e9seaux locaux L1 et L2 ?
2/ 2.a. Expliquer l\u2019utilit\u00e9 d\u2019avoir plusieurs chemins possibles reliant les r\u00e9seaux L1 et L2.
2.b. Quel est le chemin le plus court en nombre de sauts pour relier R1 et R6 ? Donner le nombre de sauts de ce chemin et pr\u00e9ciser les routeurs utilis\u00e9s.
2.c. La bande passante d\u2019une liaison Ether (quantit\u00e9 d\u2019information qui peut \u00eatre transmise en bits/s) est de \\(10^7\\) bits/s et celle d\u2019une liaison FastEther est de \\(10^8\\) bits/s. Le co\u00fbt d\u2019une liaison est d\u00e9fini par \\(\\frac{10^8}{d}\\) , o\u00f9 \\(d\\) est sa bande passante en bits/s.
Tableau 2 : type des liaisons entre les routeursQuel est le chemin reliant R1 et R6 qui a le plus petit co\u00fbt ? Donner le co\u00fbt de ce chemin et pr\u00e9ciser les routeurs utilis\u00e9s.
3/ Dans l\u2019annexe A figurent les tables de routages des routeurs R1, R2, R5 et R6 au d\u00e9marrage du r\u00e9seau. Indiquer sur votre copie ce qui doit figurer dans les lignes laiss\u00e9es vides des tables de routage des routeurs R5 et R6 pour que les \u00e9changes entre les ordinateurs des r\u00e9seaux L1 et L2 se fassent en empruntant le chemin le plus court en nombre de sauts.
1.a L'adresse du r\u00e9seau L1 est 192.168.1.0/24. L'adresse de L2 est 175.6.0.0/16. 1.b Pour le r\u00e9seau L1 (192.168.1.0/24), l'adresse min est 192.168.1.1/24, l'adresse max est 192.168.1.254/24. Pour le r\u00e9seau L2 (175.6.0.0/16), l'adresse min est 175.6.0.1/16 et l'adresse max est 175.6.255.254/16 1.c. Pour le r\u00e9seau L1, il y a donc 254 adresses (256 moins les deux interdites) Pour le r\u00e9seau L2, il y en a \\(256^2-2\\), soit 65534.
2.a Il est utile d'avoir plusieurs chemins en cas de panne d'un routeur. 2.b En nombres de sauts (protocole RIP), le chemin le plus court est R1-R2-R5-R6, qui contient 3 sauts. 2.c Les liaisons Ether ont un co\u00fbt de 10, les liaisons FastEther ont un co\u00fbt de 1. Ce qui donne : Le chemin le plus court est donc R1-R2-R3-R4-R5-R6, avec un co\u00fbt total de 23.
Dans la table R6, on peut compl\u00e9ter comme ceci (il faudrait des lignes suppl\u00e9mentaires pour y inscrire tous les r\u00e9seaux)
IP destination Passerelle Interface 10.1.7.0/24 Interface 2 192.168.1.0/24 10.1.7.1 Interface 2Exercice 6
\u00c9nonc\u00e9Correction2021, sujet Am\u00e9rique du Nord
Un constructeur automobile poss\u00e8de six sites de production qui \u00e9changent des documents entre eux. Les sites de production sont reli\u00e9s entre eux par six routeurs A, B, C, D, E et F. On donne ci-dessous les tables de routage des routeurs A \u00e0 F obtenues avec le protocole RIP.
En s'appuyant sur les tables de routage, tracer les liaisons entre les routeurs.
2.
Exercice 7
Exercice 4 du sujet Nouvelle-Cal\u00e9donie J2 2022.
Correction Q1.a.195.168.1.0/24
195.168.1.17/24
Le r\u00e9seau T2 a pour adresse 172.162.1.0/24
. Sur ce r\u00e9seau, 254 adresses sont initialement disponibles (de 172.162.1.1
\u00e0 172.162.1.254
, puisque l'adresse 172.162.1.255
est r\u00e9serv\u00e9e pour le broadcast sur le r\u00e9seau). Comme le routeur R2 et le portable 5 prennent chacun une adresse IP, il en reste donc 252 pour le portable 4.
200.158.4.1
198.164.3.2
(car la 198.164.3.1
est d\u00e9j\u00e0 prise par R2)199.160.1.1
Parcours possibles : - S1-R1-R2-S2 - S1-R1-R4-R2-S2 - S1-R1-R4-R3-R2-S2
Correction Q3.b.Suivant le protocole RIP, le parcours le plus court est celui passant par R1 puis R2. Il comporte 2 sauts.
Correction Q3.cSi la liaison R1-R2 est rompue, le protocole RIP sera emprunter le chemin R1-R4-R2, qui est le nouveau meilleur chemin, comportant 3 sauts.
Correction Q4.Le c\u00e2ble utilis\u00e9 est le cable c) Ethernet.
(le c\u00e2ble \u00abInternet\u00bb n'existe, les c\u00e2bles VGA et HDMI servent \u00e0 relier un ordinateur \u00e0 un \u00e9cran).
Correction Q5.a.\\(10=\\dfrac{10^9}{d}\\) donc \\(d=\\dfrac{10^9}{10}=10^8\\).
Le d\u00e9bit de cette liaison est donc de \\(10^8\\) bits par seconde, soit 100 Mbps.
Correction Q5.b.Le parcours de co\u00fbt minimal est le parcours R1-R4-R2, qui a un co\u00fbt total de 2.
Co\u00fbt des autres parcours : - R1-R2 : 10 - R1-R4-R3-R2 : 151
Le parcours R1-R4-R2 est donc bien le parcours minimal.
Exercice 8
Parties 2, 3 et 4 de l'exercice 2 du sujet Nouvelle-Cal\u00e9donie J1 2022.
Partie 2
Correction Q1.Le r\u00e9seau services a pour adresse IP 195.168.254.0
.
Le r\u00e9seau services a pour adresse 195.168.254.0
. Comme le masque de sous-r\u00e9seau utilis\u00e9 est 255.255.255.0
, 254 adresses sont initialement disponibles (195.168.254.1
\u00e0 195.168.254.254
, puisque l'adresse 195.168.254.255
est r\u00e9serv\u00e9e pour le broadcast sur le r\u00e9seau). Comme deux adresses sont d\u00e9j\u00e0 prises par le routeur 1 et le routeur 2, il en reste 252.
Le serveur web acc\u00e8de \u00e0 internet via le routeur 2, dont l'adresse sur le r\u00e9seau services est 192.168.254.2
. C'est donc cette adresse qui joue est l'adresse de passerelle pour le serveur web.
Partie 3
Correction Q1.La ligne 2 montre que l'adresse MAC du serveur DNS est 8A:FD:54:49:D0:CC
.
La couche Transport montre que le protocole utilis\u00e9 est le protocole UDP.
Correction Q3.Le commentaire de la couche Application indique que l'adresse IP du serveur web est 192.168.254.201
.
Partie 4
Correction Q1.Table de routage du routeur R4 :
Destination Routeur suivant Distance R1 R2 2 R2 R2 1 R3 R2 2 R5 R6 2 R6 R6 1 Correction Q2.Pour minimiser le nombre de sauts (protocole RIP), le trajet sera R1-R2-R4-R6
.
Notions essentielles
Lorsqu'une machine A, d'adresse IP_A veut discuter avec une machine B, d'adresse IP_B :
Ces questions trouveront des r\u00e9ponses gr\u00e2ce \u00e0 table de routage du routeur.
"},{"location":"T5_Architecture_materielle/5.3_Protocoles_de_routage/cours/#1-tables-de-routage","title":"1. Tables de routage","text":"Les tables de routage sont des informations stock\u00e9es dans le routeur permettant d'aiguiller intelligemment les donn\u00e9es qui lui sont transmises.
Dans le r\u00e9seau ci-dessus, si l'ordinateur d'adresse 192.168.0.5
veut interroger le serveur 10.7.3.8
:
10.7.3.8
n'\u00e9tant pas dans le sous-r\u00e9seau F (d'adresse 192.168.0.0 / 24
), la requ\u00eate est confi\u00e9e au routeur via son adresse passerelle dans le r\u00e9seau F (ici 192.168.0.254
).10.7.3.8
n'appartient ni au sous-r\u00e9seau A ou E. interface et passerelle
Les tables de routage des routeurs font tr\u00e8s souvent appara\u00eetre deux colonnes, interface et passerelle, dont il ne faut pas confondre l'utilit\u00e9 :
interface : c'est l'adresse IP de la carte r\u00e9seau du routeur par o\u00f9 va sortir le paquet \u00e0 envoyer. Il y a donc toujours une adresse d'interface \u00e0 renseigner (car un paquet sort bien de quelque part !). Parfois cette interface sera juste nomm\u00e9e interface1 ou interface2.
passerelle : c'est l'adresse IP de la carte r\u00e9seau du routeur \u00e0 qui on va confier le paquet, si on n'est pas capable de le d\u00e9livrer directement (donc si l'adresse IP de destination n'est pas dans notre propre sous-r\u00e9seau). Cette adresse de passerelle n'est donc pas syst\u00e9matiquement mentionn\u00e9e. Quand elle l'est, elle donne le renseignement sur le prochain routeur \u00e0 qui le paquet est confi\u00e9.
Exemple: table de routage du routeur R1
Destination Interface Passerelle F 192.168.0.254 A 10.0.5.152 E 172.17.1.254 B 172.17.1.254 172.17.1.123 C 10.0.5.152 10.0.5.135Les trois r\u00e9seaux F, A et E sont directement accessibles au routeur R1, puisqu'il en fait partie : il n'a donc pas besoin d'adresse passerelle pour communiquer avec ces r\u00e9seaux.
Par contre, la communication avec le r\u00e9seau B n\u00e9cessite de confier le paquet au routeur R2 (c'est le choix de cette table de routage). Il faut donc mentionner l'adresse IP de ce routeur R2 (172.17.1.123), qu'on appelle adresse de passerelle.
De la m\u00eame mani\u00e8re, la communication avec le r\u00e9seau C n\u00e9cessite de confier le paquet au routeur R3 (c'est le choix de cette table de routage). Il faut donc mentionner l'adresse IP de ce routeur R3 (10.0.5.135).
"},{"location":"T5_Architecture_materielle/5.3_Protocoles_de_routage/cours/#comment-sont-construites-les-tables-de-routage","title":"Comment sont construites les tables de routage ?","text":"voir le TP d\u00e9branch\u00e9 : le jeu dont vous \u00eates le routeur
Les r\u00e8gles du protocole RIP
Le Routing Information Protocol (RIP) est bas\u00e9 sur l'\u00e9change (toutes les 30 secondes) des tables de routage de chaque routeur. Au d\u00e9but, chaque routeur ne conna\u00eet que les r\u00e9seaux auquel il est directement connect\u00e9, associ\u00e9 \u00e0 la distance 1. Ensuite, chaque routeur va recevoir p\u00e9riodiquement (toutes les 30 secondes) la table des r\u00e9seaux auquel il est connect\u00e9, et mettre \u00e0 jour sa propre table suivant les r\u00e8gles ci-dessous :
s'il d\u00e9couvre une route vers un nouveau r\u00e9seau inconnu, il l'ajoute \u00e0 sa table en augmentant de 1 la distance annonc\u00e9e par le routeur qui lui a transmis sa table.
s'il d\u00e9couvre une route vers un r\u00e9seau connu mais plus courte (en rajoutant 1) que celle qu'il poss\u00e8de dans sa table, il actualise sa table.
s'il d\u00e9couvre une route vers un r\u00e9seau connu mais plus longue que celle qu'il poss\u00e8de dans sa table, il ignore cette route.
s'il re\u00e7oit une route vers un r\u00e9seau connu en provenance d'un routeur d\u00e9j\u00e0 existant dans sa table, s'il met \u00e0 jour sa table car la topologie du r\u00e9seau a \u00e9t\u00e9 modifi\u00e9e.
si le r\u00e9seau n'\u00e9volue pas (panne ou ajout de nouveau mat\u00e9riel), les tables de routage convergent vers une valeur stable. Elles n'\u00e9voluent plus.
si un routeur ne re\u00e7oit pas pendant 3 minutes d'information de la part d'un routeur qui lui avait auparavant communiqu\u00e9 sa table de routage, ce routeur est consid\u00e9r\u00e9 comme en panne, et toutes les routes passant par lui sont affect\u00e9es de la distance infinie : 16.
Remarques et inconv\u00e9nients:
Le protocole RIP n'admet qu'une distance maximale \u00e9gale \u00e0 15 (ceci explique que 16 soit consid\u00e9r\u00e9 comme la distance infinie), ce qui le limite aux r\u00e9seaux de petite taille.
Chaque routeur n'a jamais connaissance de la topologie du r\u00e9seau tout entier : il ne le conna\u00eet que par ce que les autres routeurs lui ont racont\u00e9. On dit que ce protocole de routage est du routing by rumor.
La m\u00e9trique utilis\u00e9e (le nombre de sauts) ne tient pas compte de la qualit\u00e9 de la liaison, contrairement au protocole OSPF.
OSPF : Open Shortest Path First
Un inconv\u00e9nient majeur du protocole pr\u00e9c\u00e9dent est la non-prise en compte de la bande passante reliant les routeurs.
principe fondamental du protocole OSPF
Le chemin le plus rapide n'est pas forc\u00e9ment le plus court.
En gris, le chemin RIP. En bleu, l'OSPF.Dans le protocole OSPF, les tables de routage vont prendre en consid\u00e9ration la vitesse de communication entre les routeurs.
Dans une premi\u00e8re phase d'initialisation, chaque routeur va acqu\u00e9rir (par succession de messages envoy\u00e9s et re\u00e7us) la connaissance totale du r\u00e9seau (diff\u00e9rence fondamentale avec RIP) et de la qualit\u00e9 technique de la liaison entre chaque routeur.
"},{"location":"T5_Architecture_materielle/5.3_Protocoles_de_routage/cours/#31-les-differents-types-de-liaison-et-leur-cout","title":"3.1 Les diff\u00e9rents types de liaison et leur co\u00fbt","text":"On peut, approximativement, classer les types de liaison suivant ce tableau de d\u00e9bits th\u00e9oriques :
Technologie BP descendante BP montante Modem 56 kbit/s 48 kbit/s Bluetooth 3 Mbit/s 3 Mbit/s Ethernet 10 Mbit/s 10 Mbit/s Wi-Fi 10 Mbit/s ~ 10 Gbits/s 10 Mbit/s ~ 10 Gbits/s ADSL 13 Mbit/s 1 Mbit/s 4G 100 Mbit/s 50 Mbit/s Satellite 50 Mbit/s 1 Mbit/s Fast Ethernet 100 Mbit/s 100 Mbit/s FFTH (fibre) 10 Gbit/s 10 Gbit/s 5G 20 Gbit/s 10 Gbit/sL'id\u00e9e du protocole OSPF est de pond\u00e9rer chaque trajet entre routeurs (comptant simplement pour \u00ab1\u00bb dans le protocole RIP) par une valeur de co\u00fbt inversement proportionnelle au d\u00e9bit de transfert.
Par exemple, si le d\u00e9bit \\(d\\) est exprim\u00e9 en bits/s, on peut calculer le co\u00fbt de chaque liaison par la formule :
\\[ \\text{co\u00fbt} = \\frac{10^8}{d} \\]Cette formule de calcul peut \u00eatre diff\u00e9rente suivant les exercices, et sera syst\u00e9matiquement redonn\u00e9e. N\u00e9anmoins la valeur \\(d\\) sera toujours au d\u00e9nominateur, pour assurer la proportionnalit\u00e9 inverse du d\u00e9bit.
Avec cette convention, un route entre deux routeurs reli\u00e9s en Fast Ethernet (100 Mbits/s) aura a un poids de 1, une liaison satellite de 20 Mbits/s aura un poids de 5, etc.
"},{"location":"T5_Architecture_materielle/5.3_Protocoles_de_routage/cours/#32-exemple","title":"3.2 Exemple","text":"Reprenons le r\u00e9seau suivant :
et simplifions-le en ne gardant que les liens entre routeurs, en indiquant leur d\u00e9bit :
Notre r\u00e9seau est devenu un graphe.
Nous allons pond\u00e9rer ses ar\u00eates avec la fonction co\u00fbt introduite pr\u00e9c\u00e9demment. L'unit\u00e9 \u00e9tant le Mbit/s, l'ar\u00eate entre R1 et R3 aura un poids de \\(\\frac{100}{20}=5\\).
Le graphe pond\u00e9r\u00e9 est donc :
Le chemin le plus rapide pour aller de l'ordinateur au serveur est donc R1-R2-R4, et non plus R1-R3 comme l'aurait indiqu\u00e9 le protocole RIP.
"},{"location":"T5_Architecture_materielle/5.3_Protocoles_de_routage/cours/#33-trouver-le-plus-court-chemin-dans-un-graphe-pondere","title":"3.3 Trouver le plus court chemin dans un graphe pond\u00e9r\u00e9","text":"L'exemple pr\u00e9c\u00e9dent \u00e9tait tr\u00e8s simple et de solution intuitive. Dans le cas d'un graphe pond\u00e9r\u00e9 complexe, existe-t-il un algorithme de d\u00e9termination du plus court chemin d'un point \u00e0 un autre ?
La r\u00e9ponse est oui, depuis la d\u00e9couverte en 1959 par Edsger Dijkstra de l'algorithme qui porte son nom, l'algorithme de Dijkstra.
Pour le comprendre, vous pouvez regarder la vid\u00e9o d'un c\u00e9l\u00e8bre YouTuber :
Cet algorithme, ici ex\u00e9cut\u00e9 de mani\u00e8re manuelle, est bien s\u00fbr programmable. Et c'est donc gr\u00e2ce \u00e0 lui que chaque routeur calcule la route la plus rapide pour acheminer les donn\u00e9es qu'il re\u00e7oit.
Exercice d'application de l'algorithme de Dijkstra (HP)
Donner le plus court chemin pour aller de E \u00e0 F dans le graphe ci-dessous :
correction E A B C D F Choix 0 -- -- -- -- -- E(0) . 30vE -- 40vE 10vE -- D(10) . 20vD -- 40vE . 80vD A(20) . . 60vA 30vA . 80vD C(30) . . 50vC . . 80vD B(50) . . . . . 70vB F(70)Le meilleur trajet est donc E-D-A-C-B-F. Attention ce trajet correspond \u00e0 la colonne choix (dans l'ordre) mais c'est un hasard.
"},{"location":"T5_Architecture_materielle/5.3_Protocoles_de_routage/cours/#34-exercice","title":"3.4 Exercice","text":"(extrait du sujet 0)
On consid\u00e8re le r\u00e9seau suivant :
On rappelle que le co\u00fbt d\u2019une liaison est donn\u00e9 par la formule suivante :
\\[ \\text{co\u00fbt} = \\frac{10^8}{d} \\]Question 1
Question 2
Le routeur A doit transmettre un message au routeur G, en empruntant le chemin dont la somme des co\u00fbts sera la plus petite possible. D\u00e9terminer le chemin parcouru. On indiquera le raisonnement utilis\u00e9.
CorrectionQ1 1. \\(\\text{co\u00fbt} = \\dfrac{10^8}{10 \\times 10^9}= \\dfrac{10^8}{10^{10}}= 10^{-2}=0,01\\) 2. \\(5=\\dfrac{10^8}{d}\\) donc \\(d=\\dfrac{10^8}{5}=20 \\times 10^6\\) = 20 Mb/s
Q2 Le graphe pond\u00e9r\u00e9 par les co\u00fbts est :
On peut y deviner le chemin de co\u00fbt minimal entre A et G, qui est A-D-E-G (co\u00fbt 1,011). Pour le justifier, on peut (non obligatoire) faire un algorithme de Dijkstra :
Bibliographie
Utilisation des biblitoh\u00e8ques cryptographiques du module sympy
.
Documentation : https://docs.sympy.org/latest/modules/crypto.html
D\u00e9coder la phrase RYTVJKGCLJWRTZCVRMVTLEDFULCVHLZWRZKKFLKRMFKIVGCRTV
, sachant qu'elle a \u00e9t\u00e9 chiffr\u00e9e par d\u00e9calage (shift en anglais...)
from sympy.crypto.crypto import decipher_shift\n\nmsg = 'RYTVJKGCLJWRTZCVRMVTLEDFULCVHLZWRZKKFLKRMFKIVGCRTV'\n\nfor cle in range(26):\n phrase = decipher_shift(msg, cle)\n print(phrase)\n
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/Exercices/#exercice-2","title":"Exercice 2","text":"Chiffrage affine
Principe du chiffrage affine :
o\u00f9 \\(a\\) et \\(b\\) sont deux nombres entiers. Attention, a doit \u00eatre premier avec 26.
Q1. Codez votre fonction affine(msg, a, b)
def rang(lettre):\n return ord(lettre) - 65\n\ndef affine(msg, a, b):\n sol = \"\"\n for lettre in msg:\n rg = rang(lettre)\n nv_rg = (a*rg + b) % 26 #chiffrement affine\n nv_lettre = chr(nv_rg + 65)\n sol += nv_lettre\n return sol\n
Q2. Comparez vos r\u00e9sultats avec ceux obtenus par la fonction encipher_affine()
de sympy
.
Q3. D\u00e9codez la phrase UCGXLODCMOXPMFMSRJCFQOGTCRSUSXC
, sachant qu'elle contient le mot TRAVAIL
et que \\(a\\) et \\(b\\) sont inf\u00e9rieurs \u00e0 20.
from sympy.crypto.crypto import decipher_affine\nfrom math import gcd\n\nfor a in range(1,20):\n for b in range(1,20):\n if gcd(a,26) == 1:\n p = decipher_affine('UCGXLODCMOXPMFMSRJCFQOGTCRSUSXC', (a,b))\n if 'TRAVAIL' in p:\n print(p)\n
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/Exercices/#exercice-3","title":"Exercice 3","text":"Cryptographie RSA presque \u00e0 la main
import Crypto\nimport libnum\nfrom Crypto.Util.number import bytes_to_long, long_to_bytes\nfrom Crypto.Random import get_random_bytes \n\nbits = 256\nmsg = \"en NSI on fait de la crypto\"\n\np = Crypto.Util.number.getPrime(bits, randfunc=get_random_bytes)\nq = Crypto.Util.number.getPrime(bits, randfunc=get_random_bytes)\n\nn = p * q\nphi = (p - 1) * (q - 1)\n\ne = 65537 # 65537 est un nombre premier, donc forc\u00e9ment premier avec phi\nd = libnum.invmod(e, phi) # on calcule l'inverse de e modulo phi\n\nM = bytes_to_long(msg.encode('utf-8'))\n\nc = pow(M, e, n) # M puissance e modulo n\nres = pow(c, d, n)\n\nprint(long_to_bytes(res))\n
En vous servant du code pr\u00e9c\u00e9dent, d\u00e9chiffrez le message 58152918114477529438769495136495430966050302170947748011925859233600631318929939319619808279389222131229963717435870597641010567365311762267359794338657867540621133550787677728203831932548041236152866441194127191404729294628415184239755221703677388875259927092794165578604353985011899152968982365630138088486380827379488939561996226754182
sachant que :
module RSA dans les r\u00e8gles de l'art
from Crypto.PublicKey import RSA\nfrom Crypto.Cipher import PKCS1_OAEP\nimport binascii\n\nkeyPair = RSA.generate(1024)\n\npubKey = keyPair.publickey()\n\npubKeyPEM = pubKey.exportKey()\n\nprivKeyPEM = keyPair.exportKey()\n\n\nmsg = b'vive la crypto en NSI !'\nencryptor = PKCS1_OAEP.new(pubKey)\nencrypted = encryptor.encrypt(msg)\nprint(\"Encrypted:\", binascii.hexlify(encrypted))\n\n\ndecryptor = PKCS1_OAEP.new(keyPair)\ndecrypted = decryptor.decrypt(encrypted)\nprint('Decrypted:', decrypted)\n
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/","title":"Cryptographie","text":""},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#1-chiffrement-symetrique","title":"1. Chiffrement sym\u00e9trique","text":""},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#11-activite-du-masque-jetable","title":"1.1 Activit\u00e9 du masque jetable","text":"Exercice
\u00c9nonc\u00e9AideCorrectionOn consid\u00e8re la variable suivante :
masque = \"CETTEPHRASEESTVRAIMENTTRESTRESLONGUEMAISCESTFAITEXPRES\"\n
chiffre(message, masque)
qui chiffre message
en le XORant avec masque
.XOR
(voir ici) est une op\u00e9ration sym\u00e9trique : >>> 34 ^ 23\n53\n>>> 53 ^ 23\n34\n
ord
permet de renvoyer le code ASCII d'un caract\u00e8re. La fonction chr
fait l'op\u00e9ration inverse. >>> ord('A')\n65\n>>> chr(65)\n'A'\n
masque = \"CETTEPHRASEESTVRAIMENTTRESTRESLONGUEMAISCESTFAITEXPRES\"\n\ndef chiffre(message, masque):\n message_chiffre = \"\"\n for i in range(len(message)):\n lettre_chiffree = chr(ord(message[i]) ^ ord(masque[i]))\n message_chiffre += lettre_chiffree\n return message_chiffre\n
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#12-principe-du-chiffrement-symetrique","title":"1.2 Principe du chiffrement sym\u00e9trique","text":"Chiffrement sym\u00e9trique
Dans un chiffrement sym\u00e9trique, c'est la m\u00eame cl\u00e9 qui va servir au chiffrement et au d\u00e9chiffrement.
Illustration :
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#quappelle-t-on-une-cle","title":"Qu'appelle-t-on une cl\u00e9 ?","text":"La cl\u00e9 est un renseignement permettant de chiffrer ou d\u00e9chiffrer un message. Cela peut \u00eatre :
Un chiffrement est dit sym\u00e9trique lorsque la connaissance de la cl\u00e9 ayant servi au chiffrement permet de d\u00e9chiffrer le message. Par exemple, Alice chiffre son message en d\u00e9calant les lettres de 3 rangs vers la droite dans l'alphabet, Bob saura qu'il doit les d\u00e9caler de 3 rangs vers la gauche pour retrouver le message initial.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#quel-est-lavantage-dun-chiffrement-symetrique","title":"Quel est l'avantage d'un chiffrement sym\u00e9trique ?","text":"Les chiffrements sym\u00e9triques sont souvent rapides, consommant peu de ressources et donc adapt\u00e9s au chiffrement de flux important d'informations.
Comme nous le verrons, la s\u00e9curisation des donn\u00e9es transitant par le protocole https
est bas\u00e9e sur un chiffrement sym\u00e9trique.
La cl\u00e9 ! Si Alice et Bob ont besoin d'utiliser un chiffrement pour se parler, comment peuvent-ils \u00e9changer leurs cl\u00e9s puisque leur canal de transmission n'est pas s\u00fbr ?
Le chiffrement sym\u00e9trique impose qu'Alice et Bob aient pu se rencontrer physiquement au pr\u00e9alable pour convenir d'une cl\u00e9 secr\u00e8te, ou bien qu'ils aient r\u00e9ussi \u00e0 \u00e9tablir une connexion s\u00e9curis\u00e9e pour s'\u00e9changer cette cl\u00e9.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#un-chiffrement-symetrique-est-il-un-chiffrement-de-mauvaise-qualite","title":"Un chiffrement sym\u00e9trique est-il un chiffrement de mauvaise qualit\u00e9 ?","text":"Pas du tout ! S'il est associ\u00e9 naturellement \u00e0 des chiffrements simples et faibles (comme le d\u00e9calage de C\u00e9sar), un chiffrement sym\u00e9trique peut \u00eatre tr\u00e8s robuste... voire inviolable.
C'est le cas du masque jetable. Si le masque avec lequel on effectue le XOR sur le message est aussi long que le message, alors il est impossible de retrouver le message initial. Pourquoi ?
Imaginons qu'Alice veuille transmettre le message clair \"LUNDI\". Elle le chiffre avec un masque jetable (que connait aussi Bob), et Bob re\u00e7oit donc \"KHZOK\". Si Marc a intercept\u00e9 le message \"KHZOK\", m\u00eame s'il sait que la m\u00e9thode de chiffrement utilis\u00e9e est celle du masque jetable (principe de Kerckhoffs), il n'a pas d'autre choix que de tester tous les masques de 5 lettres possibles.
Principe de Kerckhoffs
La s\u00e9curit\u00e9 d'un syst\u00e8me de chiffrement ne doit reposer que sur le secret de la cl\u00e9, et non pas sur la connaissance de l'algorithme de chiffrement. Cet algorithme peut m\u00eame \u00eatre public (ce qui est pratiquement toujours le cas).
Ce qui lui donne \\(26^5\\) possibilit\u00e9s (plus de 11 millions) pour le masque, et par cons\u00e9quent (propri\u00e9t\u00e9 de bijectivit\u00e9 du XOR) \\(26^5\\) possibilit\u00e9s pour le message \u00abd\u00e9chiffr\u00e9\u00bb...
Cela signifie que Marc verra appara\u00eetre, dans sa tentative de d\u00e9chiffrage, les mots \"MARDI\", \"JEUDI\", \"JOUDI\", \"STYLO\", \"FSDJK\", \"LUNDI\", \"LUNDA\"... Il n'a aucune possibilit\u00e9 de savoir o\u00f9 est le bon message original parmi toutes les propositions (on parle de s\u00e9curit\u00e9 s\u00e9mantique).
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#quels-sont-les-chiffrements-symetriques-modernes","title":"Quels sont les chiffrements sym\u00e9triques modernes ?","text":"L'algorithme de chiffrement sym\u00e9trique le plus utilis\u00e9 actuellement est le chiffrement AES, pour Advanced Encryption Standard.
Invent\u00e9 par Whitfield Diffie et Martin Hellman en 1976, le chiffrement asym\u00e9trique vient r\u00e9soudre l'inconv\u00e9nient essentiel du chiffrement sym\u00e9trique : le n\u00e9cessaire partage d'un secret (la cl\u00e9) avant l'\u00e9tablissement de la communication s\u00e9curis\u00e9e.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#21-principe-du-chiffrement-asymetrique","title":"2.1 Principe du chiffrement asym\u00e9trique","text":"Le principe de base est l'existence d'une cl\u00e9 publique, appel\u00e9e \u00e0 \u00eatre distribu\u00e9e largement, et d'une cl\u00e9 priv\u00e9e, qui ne quitte jamais son propri\u00e9taire.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#22-le-role-interchangeable-des-cles-publiques-et-privees","title":"2.2 Le r\u00f4le interchangeable des cl\u00e9s publiques et priv\u00e9es","text":"L'illustration pr\u00e9c\u00e9dente associe :
Concr\u00e8tement, (nous le verrons dans l'application par le chiffrement RSA), la cl\u00e9 priv\u00e9e et la cl\u00e9 publique sont deux nombres aux r\u00f4les identiques. Appelons-les A et B :
A et B ont donc des r\u00f4les interchangeables (chacun peut \u00eatre un cadenas, chacun peut \u00eatre une cl\u00e9), et ce n'est qu'en connaissant A et B qu'on peut d\u00e9chiffrer le message.
Nous allons donc maintenant adopter une nouvelle convention infographique :
Si ce message est chiffr\u00e9 avec la cl\u00e9 publique d'Alice, le message sera :
Si on d\u00e9chiffre ce message avec la cl\u00e9 priv\u00e9e d'Alice, il deviendra et donc
puisque l'application de la cl\u00e9 priv\u00e9e sur la cl\u00e9 publique, ou bien de la cl\u00e9 publique sur la cl\u00e9 priv\u00e9e, permet de retrouver le message en clair.
De mani\u00e8re graphique, la connaissance des deux moiti\u00e9s du disque qui s'assemblent permet de les faire disparaitre, peu importe qu'on ait commenc\u00e9 par chiffrer avec la cl\u00e9 publique ou avec la cl\u00e9 priv\u00e9e.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#23-communication-authentifiee","title":"2.3 Communication authentifi\u00e9e.","text":"Dans la situation du 2.1, Alice (qui a distribu\u00e9 largement sa cl\u00e9 publique) ne peut pas s'assurer que le message vient bien de Bob. Il peut avoir \u00e9t\u00e9 cr\u00e9\u00e9 par Marc, qui signe \u00abBob\u00bb et usurpe ainsi son identit\u00e9.
Le protocole que nous allons d\u00e9crire ci-dessous permet :
En r\u00e9sum\u00e9 :
Lorsqu'en 1976 Diffie et Hellman (chercheurs \u00e0 Stanford) pr\u00e9sentent le concept de chiffrement asym\u00e9trique (souvent appel\u00e9 cryptographie \u00e0 cl\u00e9s publiques), ils en proposent uniquement un mod\u00e8le th\u00e9orique, n'ayant pas trouv\u00e9 une r\u00e9elle impl\u00e9mentation de leur protocole.
Trois chercheurs du MIT (Boston), Ron Rivest, Adi Shamir et Len Adleman se penchent alors sur ce protocole, convaincus qu'il est en effet impossible d'en trouver une impl\u00e9mentation pratique. En 1977, au cours de leurs recherches, ils d\u00e9montrent en fait l'inverse de ce qu'ils cherchaient : ils cr\u00e9ent le premier protocole concret de chiffrement asym\u00e9trique : le chiffrement RSA.
Au m\u00eame moment \u00e0 Londres, Clifford Cocks, (chercheur au tr\u00e8s secret GCHQ) apprend que Rivest Shamir et Adleman viennent de d\u00e9couvrir ce que lui-m\u00eame a d\u00e9couvert 3 ans auparavant mais qui est rest\u00e9 class\u00e9 Secret D\u00e9fense.
Il est le v\u00e9ritable inventeur du RSA... mais le reste du monde ne l'apprendra qu'en 1997 au moment de la d\u00e9classification de cette information.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#231-description","title":"2.3.1 Description","text":"Le chiffrement RSA est bas\u00e9 sur l'arithm\u00e9tique modulaire. Faire des calculs modulo un entier \\(n\\), c'est ne garder que le reste de la division euclidienne par \\(n\\).
Le fait que 15 soit \u00e9gal \u00e0 1 modulo 7 (car \\(15=2 \\times 7+1\\)) s'\u00e9crira \\(15 \\equiv 1 [7]\\).
De m\u00eame, \\(10 \\equiv 3 [7]\\), \\(25 \\equiv 4 [7]\\), \\(32 \\equiv 2 [10]\\), etc.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#etape-1","title":"\u00c9tape 1","text":"Alice choisit 2 grands nombres premiers \\(p\\) et \\(q\\). Dans la r\u00e9alit\u00e9 ces nombres seront vraiment tr\u00e8s grands (plus de 100 chiffres). Dans notre exemple, nous prendrons \\(p = 3\\) et \\(q = 11\\).
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#etape-2","title":"\u00c9tape 2","text":"Alice multiplie ces deux nombres \\(p\\) et \\(q\\) et obtient ainsi un nombre \\(n\\).
Il est tr\u00e8s facile pour Alice de calculer \\(n\\) en connaissant \\(p\\) et \\(q\\), mais il extr\u00eamement difficile pour Marc de faire le travail inverse : trouver \\(p\\) et \\(q\\) en connaissant \\(n\\) prend un temps exponentiel avec la taille de \\(n\\). C'est sur cette difficult\u00e9 (appel\u00e9e difficult\u00e9 de factorisation) que repose la robustesse du syst\u00e8me RSA.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#etape-3","title":"\u00c9tape 3","text":"Alice choisit un nombre \\(e\\) qui doit \u00eatre premier avec \\((p-1)(q-1)\\). On note \\(\\phi(n)\\) le nombre \\((p-1)(q-1)\\).
Dans notre exemple, \\((p-1)(q-1) = 20\\), Alice choisit donc \\(e = 3\\). (mais elle aurait pu aussi choisir 7, 9, 13...).
Le couple \\((e, n)\\) sera la cl\u00e9 publique d'Alice. Elle la diffuse \u00e0 qui veut lui \u00e9crire.
Dans notre exemple, la cl\u00e9 publique d'Alice est \\((3, 33)\\).
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#etape-4","title":"\u00c9tape 4","text":"Alice calcule maintenant sa cl\u00e9 priv\u00e9e : elle doit trouver un nombre d qui v\u00e9rifie l'\u00e9galit\u00e9 \\(e d \\equiv 1 [\\phi(n)]\\).
Dans notre exemple, comme \\(7 \\times 3 \\equiv 1 [20]\\), ce nombre \\(d\\) est \u00e9gal \u00e0 7.
En pratique, il existe un algorithme simple (algorithme d'Euclide \u00e9tendu) pour trouver cette valeur \\(d\\), appel\u00e9e inverse de e.
Le couple \\((d, n)\\) sera la cl\u00e9 priv\u00e9e d'Alice. Elle ne la diffuse \u00e0 personne.
Dans notre exemple, la cl\u00e9 priv\u00e9e d'Alice est \\((7, 33)\\).
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#etape-5","title":"\u00c9tape 5","text":"Supposons que Bob veuille \u00e9crire \u00e0 Alice pour lui envoyer le nombre 4. Il poss\u00e8de la cl\u00e9 publique d'Alice, qui est \\((3, 33)\\).
Il calcule donc \\(4^3\\) modulo 33, qui vaut 31. C'est cette valeur 31 qu'il transmet \u00e0 Alice.
\\[4^3 \\equiv 31 [33]\\]Si Marc intercepte cette valeur 31, m\u00eame en connaissant la cl\u00e9 publique d'Alice (3,33), il ne peut pas r\u00e9soudre l'\u00e9quation \\(x^3 \\equiv 31 [33]\\) de mani\u00e8re efficace.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#etape-6","title":"\u00c9tape 6","text":"Alice re\u00e7oit la valeur 31. Il lui suffit alors d'\u00e9lever 31 \u00e0 la puissance 7 (sa cl\u00e9 priv\u00e9e), et de calculer le reste modulo 33 :
\\(31^7 = 27512614111\\)
\\(27512614111 \\equiv 4 [33]\\)
Elle r\u00e9cup\u00e8re la valeur 4, qui est bien le message original de Bob.
Comment \u00e7a marche ? Gr\u00e2ce au Petit Th\u00e9or\u00e8me de Fermat, on d\u00e9montre (voir ici) assez facilement que \\(M^{ed} \\equiv M [n]\\).
Il faut remarquer que \\(M^{ed} = M^{de}\\). On voit que les r\u00f4les de la cl\u00e9 publique et de la cl\u00e9 priv\u00e9e sont sym\u00e9triques : un message chiffr\u00e9 avec la cl\u00e9 publique se d\u00e9chiffrera en le chiffrant avec la cl\u00e9 priv\u00e9e, tout comme un message chiffr\u00e9 avec la cl\u00e9 priv\u00e9e se d\u00e9chiffrera en le chiffrant avec la cl\u00e9 publique.
Animation interactive voir https://animations.interstices.info/interstices-rsa/rsa.html
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#rsa-un-systeme-inviolable","title":"RSA, un syst\u00e8me inviolable ?","text":"Le chiffrement RSA a des d\u00e9fauts (notamment une grande consommation des ressources, due \u00e0 la manipulation de tr\u00e8s grands nombres). Mais le choix d'une cl\u00e9 publique de grande taille (actuellement 1024 ou 2048 bits) le rend pour l'instant inviolable.
Actuellement, il n'existe pas d'algorithme efficace pour factoriser un nombre ayant plusieurs centaines de chiffres.
Deux \u00e9v\u00e8nements pourraient faire s'\u00e9crouler la s\u00e9curit\u00e9 du RSA :
Aujourd'hui, plus de 90 % du trafic sur internet est chiffr\u00e9 : les donn\u00e9es ne transitent plus en clair (protocole http
) mais de mani\u00e8re chiffr\u00e9e (protocole https
), ce qui emp\u00eache la lecture de paquets \u00e9ventuellements intercept\u00e9s.
Le protocole https
est la r\u00e9union de deux protocoles :
TLS
(Transport Layer Security, qui a succ\u00e9d\u00e9 au SSL) : ce protocole, bas\u00e9 sur du chiffrement asym\u00e9trique, va conduire \u00e0 la g\u00e9n\u00e9ration d'une cl\u00e9 identique chez le client et chez le serveur.http
, mais qui convoiera maintenant des donn\u00e9es chiffr\u00e9es avec la cl\u00e9 g\u00e9n\u00e9r\u00e9e \u00e0 l'\u00e9tape pr\u00e9c\u00e9dente. Les donn\u00e9es peuvent toujours \u00eatre intercept\u00e9es, mais sont illisibles. Le chiffrement sym\u00e9trique utilis\u00e9 est actuellement le chiffrement AES.Pourquoi ne pas utiliser que le chiffrement asym\u00e9trique, RSA par exemple ? Car il est tr\u00e8s gourmand en ressources ! Le chiffrement/d\u00e9chiffrement doit \u00eatre rapide pour ne pas ralentir les communications ou l'exploitation des donn\u00e9es. Le chiffrement asym\u00e9trique est donc r\u00e9serv\u00e9 \u00e0 l'\u00e9change de cl\u00e9s (au d\u00e9but de la communication). Le chiffrement sym\u00e9trique, bien plus rapide, prend ensuite le relais pour l'ensemble de la communication.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#32-hp-fonctionnement-du-tls-explication-du-handshake","title":"3.2 (HP) Fonctionnement du TLS : explication du handshake","text":"Observons en d\u00e9tail le fonctionnement du protocole TLS
, dont le r\u00f4le est de g\u00e9n\u00e9rer de mani\u00e8re s\u00e9curis\u00e9e une cl\u00e9 dont disposeront \u00e0 la fois le client et le serveur, leur permettant ainsi d'appliquer un chiffrement sym\u00e9trique \u00e0 leurs \u00e9changes.
\u00e9tape 1 : le \u00abclient Hello\u00bb. Le client envoie sa version de TLS utilis\u00e9e.
\u00e9tape 2 : le \u00abserver Hello\u00bb. Le serveur r\u00e9pond en renvoyant son certificat prouvant son identit\u00e9, ainsi que sa cl\u00e9 publique.
\u00e9tape 3 : le client interroge l'autorit\u00e9 de certification pour valider le fait que le certificat est bien valide et que le serveur est bien celui qu'il pr\u00e9tend \u00eatre. Cette v\u00e9rification est faite gr\u00e2ce \u00e0 un m\u00e9canisme de chiffrement asym\u00e9trique.
La pr\u00e9sentation du certificat \u00e0 l'autorit\u00e9 de certification peut se repr\u00e9senter comme le scan d'une pi\u00e8ce d'identit\u00e9 dans un a\u00e9roport. L'autorit\u00e9 de certification est alors l'\u00c9tat (dont la base de donn\u00e9es est interrog\u00e9e par un logiciel) qui valide que la pi\u00e8ce d'identit\u00e9 est bien un document officiel.
Le transmission par protocole http
de donn\u00e9es chiffr\u00e9es au pr\u00e9alable avec la cl\u00e9 AES peut commencer.
Remarque : en r\u00e9alit\u00e9, ce n'est pas la cl\u00e9 AES qui est transmise \u00e0 l'\u00e9tape 4, mais un nombre choisi par le client, qui permettra, avec deux autres nombres choisis par le client (\u00e9tape 1) et le serveur (\u00e9tape 2) de reconstituer la cl\u00e9 AES, qui sera donc identique c\u00f4t\u00e9 client et c\u00f4t\u00e9 serveur.
"},{"location":"T5_Architecture_materielle/5.4_Cryptographie/cours/#bibliographie","title":"Bibliographie","text":"Vous pouvez consulter le cours de Premi\u00e8re \u00e0 l'adresse https://glassus.github.io/premiere_nsi/.
Penser \u00e0 utiliser la barre de recherche pour vous aider dans votre navigation.
"},{"location":"T6_5_algos_coeur/cours/","title":"Algorithmes de r\u00e9f\u00e9rence","text":""},{"location":"T6_5_algos_coeur/cours/#1-factorielle-recursive","title":"1. Factorielle r\u00e9cursive","text":"def factorielle(n):\n if n == 1:\n return 1\n else:\n return n * factorielle(n - 1)\n
"},{"location":"T6_5_algos_coeur/cours/#2-pgcd-recursif","title":"2. PGCD r\u00e9cursif","text":"def pgcd(a, b):\n if b == 0:\n return a\n else:\n return pgcd(b, a%b)\n
"},{"location":"T6_5_algos_coeur/cours/#3-puissance-recursive-simple","title":"3. Puissance r\u00e9cursive (simple)","text":"def puissance(x, n):\n if n == 0:\n return 1\n else:\n return x * puissance(x, n-1)\n
"},{"location":"T6_5_algos_coeur/cours/#4-puissance-recursive-optimisee","title":"4. Puissance r\u00e9cursive (optimis\u00e9e)","text":"def puissance(x, n):\n if n == 0:\n return 1\n else:\n if n % 2 == 0:\n return puissance(x*x, n//2)\n else :\n return x*puissance(x*x, (n-1)//2)\n
"},{"location":"T6_5_algos_coeur/cours/#5-recherche-dichotomique-recursive-avec-slicing","title":"5. Recherche dichotomique r\u00e9cursive (avec slicing)","text":"Note : le slicing de liste n'est pas au programme de NSI.
def recherche(lst, m):\n if len(lst) == 1: \n if lst[0] == m:\n return True\n else :\n return False\n else: \n mid = len(lst)//2\n if lst[mid] > m:\n return recherche(lst[:mid], m)\n else :\n return recherche(lst[mid:], m)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/","title":"\u00c9preuve pratique \ud83d\udcbb","text":"Vous trouverez ci-dessous l'int\u00e9gralit\u00e9 des sujets de l'\u00e9preuve pratique, disponibles publiquement sur la Banque Nationale des Sujets (novembre 2021).
Une nouvelle version (qui sera a priori en grande partie semblable \u00e0 celle-ci) sera publi\u00e9e en janvier 2022 sur le site Eduscol.
update : les sujets sont disponibles, une premi\u00e8re version centralis\u00e9e se trouve ici
Rappel des conditions de passation sur cette page.
Pdf de l'int\u00e9gralit\u00e9 des exercices.
Exercice 01.1
\u00c9nonc\u00e9CorrectionProgrammer la fonction recherche
, prenant en param\u00e8tre un tableau non vide tab
(type list
) d'entiers et un entier n
, et qui renvoie l'indice de la derni\u00e8re occurrence de l'\u00e9l\u00e9ment cherch\u00e9. Si l'\u00e9l\u00e9ment n'est pas pr\u00e9sent, la fonction renvoie la longueur du tableau.
Exemples
>>> recherche([5, 3],1)\n2\n>>> recherche([2,4],2)\n0\n>>> recherche([2,3,5,2,4],2)\n3\n
def recherche(tab, n):\n indice_solution = len(tab)\n for i in range(len(tab)):\n if tab[i] == n:\n indice_solution = i\n return indice_solution\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-012","title":"Exercice 01.2 \u25a1","text":"Exercice 01.2
\u00c9nonc\u00e9CorrectionOn souhaite programmer une fonction donnant la distance la plus courte entre un point de d\u00e9part et une liste de points. Les points sont tous \u00e0 coordonn\u00e9es enti\u00e8res. Les points sont donn\u00e9s sous la forme d'un tuple de deux entiers. La liste des points \u00e0 traiter est donc un tableau de tuples.
On rappelle que la distance entre deux points du plan de coordonn\u00e9es \\((x;y)\\) et \\((x';y')\\) est donn\u00e9e par la formule :
\\[d=\\sqrt{(x-x')^2+(y-y')^2}\\]On importe pour cela la fonction racine carr\u00e9e (sqrt
) du module math
de Python.
On dispose d'une fonction distance
et d'une fonction plus_courte_distance
:
from math import sqrt # import de la fonction racine carr\u00e9e\n\ndef distance(point1, point2):\n\"\"\" Calcule et renvoie la distance entre deux points. \"\"\"\n return sqrt((...)**2 + (...)**2)\n\nassert distance((1, 0), (5, 3)) == 5.0, \"erreur de calcul\"\n\ndef plus_courte_distance(tab, depart):\n\"\"\" Renvoie le point du tableau tab se trouvant \u00e0 la plus courte distance du point depart.\"\"\"\n point = tab[0]\n min_dist = ...\n for i in range (1, ...):\n if distance(tab[i], depart)...:\n point = ...\n min_dist = ...\n return point\n\nassert plus_courte_distance([(7, 9), (2, 5), (5, 2)], (0, 0)) == (2, 5), \"erreur\"\n
Recopier sous Python (sans les commentaires) ces deux fonctions puis compl\u00e9ter leur code et ajouter une ou des d\u00e9clarations (assert
) \u00e0 la fonction distance
permettant de v\u00e9rifier la ou les pr\u00e9conditions. from math import sqrt\n\ndef distance(point1, point2):\n\"\"\" Calcule et renvoie la distance entre deux points. \"\"\"\n return sqrt((point1[0] - point2[0])**2 + ((point1[1] - point2[1]))**2)\n\nassert distance((1, 0), (5, 3)) == 5.0, \"erreur de calcul\"\n\n\ndef plus_courte_distance(tab, depart):\n\"\"\" Renvoie le point du tableau tab se trouvant \u00e0 la plus courte distance du point depart.\"\"\"\n point = tab[0]\n min_dist = distance(point, depart)\n for i in range (1, len(tab)):\n if distance(tab[i], depart) < min_dist:\n point = tab[i]\n min_dist = distance(tab[i], depart)\n return point\n\nassert plus_courte_distance([(7, 9), (2, 5), (5, 2)], (0, 0)) == (2, 5), \"erreur\"\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-021","title":"Exercice 02.1 \u25a1","text":"Exercice 02.1
\u00c9nonc\u00e9CorrectionProgrammer la fonction moyenne
prenant en param\u00e8tre un tableau d'entiers tab
(type list
) qui renvoie la moyenne de ses \u00e9l\u00e9ments si le tableau est non vide et affiche 'erreur' si le tableau est vide.
Exemples :
>>> moyenne([5,3,8])\n5.333333333333333\n>>> moyenne([1,2,3,4,5,6,7,8,9,10])\n5.5\n>>> moyenne([])\n'erreur'\n
L'\u00e9nonc\u00e9 n'est pas tr\u00e8s clair quand il dit \u00abd'afficher 'erreur'\u00bb (ce qui suppose un print
et non un return
). Nous choississons donc dans ce cas de renvoyer None
.
def moyenne(tab):\n if tab == []:\n print('erreur')\n return None\n else:\n somme = 0\n for elt in tab:\n somme += elt\n return somme / len(tab)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-022","title":"Exercice 02.2 \u25a1","text":"Exercice 02.2
\u00c9nonc\u00e9CorrectionOn consid\u00e8re un tableau d'entiers tab
(type list
dont les \u00e9l\u00e9ments sont des 0
ou des 1
). On se propose de trier ce tableau selon l'algorithme suivant : \u00e0 chaque \u00e9tape du tri,le tableau est constitu\u00e9 de trois zones cons\u00e9cutives, la premi\u00e8re ne contenant que des 0
, la seconde n'\u00e9tant pas tri\u00e9e et la derni\u00e8re ne contenant que des 1
.
Zone de 0Zone non tri\u00e9eZone de 1
Tant que la zone non tri\u00e9e n'est pas r\u00e9duite \u00e0 un seul \u00e9l\u00e9ment, on regarde son premier \u00e9l\u00e9ment :
Dans tous les cas, la longueur de la zone non tri\u00e9e diminue de 1.
Recopier sous Python en la compl\u00e9tant la fonction tri
suivante :
def tri(tab):\n #i est le premier indice de la zone non triee, j le dernier indice.\n #Au debut, la zone non triee est le tableau entier.\n i = ...\n j = ...\n while i != j :\n if tab[i]== 0:\n i = ...\n else :\n valeur = tab[j]\n tab[j] = ...\n ...\n j = ...\n ...\n
Exemple :
>>> tri([0,1,0,1,0,1,0,1,0])\n[0, 0, 0, 0, 0, 1, 1, 1, 1] \n
def tri(tab):\n #i est le premier indice de la zone non triee, j le dernier indice.\n #Au debut, la zone non triee est le tableau entier.\n i = 0\n j = len(tab) - 1\n while i != j :\n if tab[i]== 0:\n i = i + 1\n else :\n valeur = tab[j]\n tab[j] = tab[i]\n tab[i] = valeur\n j = j - 1\n return tab\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-031","title":"Exercice 03.1 \u25a1","text":"Exercice 03.1
\u00c9nonc\u00e9CorrectionProgrammer la fonction multiplication
, prenant en param\u00e8tres deux nombres entiers n1
et n2
, et qui renvoie le produit de ces deux nombres. Les seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.
\u00c9nonc\u00e9 peu clair, on ne sait pas si n1
et n2
sont entiers naturels ou relatifs. Nous d\u00e9cidons qu'ils sont relatifs et donc qu'ils peuvent \u00eatre n\u00e9gatifs, auquel cas on utilise le fait que \\(5 \\times (-6)= - (5 \\times 6)\\).
def multiplication(n1, n2):\n if n1 < 0:\n return -multiplication(-n1, n2)\n if n2 < 0:\n return -multiplication(n1, -n2)\n resultat = 0\n for _ in range(n2):\n resultat += n1\n return resultat\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-032","title":"Exercice 03.2 \u25a1","text":"Exercice 03.2
\u00c9nonc\u00e9CorrectionRecopier et compl\u00e9ter sous Python la fonction suivante en respectant la sp\u00e9cification. On ne recopiera pas les commentaires.
def dichotomie(tab, x):\n\"\"\"\n tab : tableau d\u2019entiers tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\nFalse\n
def dichotomie(tab, x):\n\"\"\"\n tab : tableau d\u2019entiers tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = (debut + fin) // 2\n if x == tab[m]:\n return True\n if x > tab[m]:\n debut = m + 1\n else:\n fin = m - 1\n return False\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-041","title":"Exercice 04.1 \u25a1","text":"Exercice 04.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction qui prend en param\u00e8tre un tableau d'entiers non vide et qui renvoie la moyenne de ces entiers. La fonction est sp\u00e9cifi\u00e9e ci-apr\u00e8s et doit passer les assertions fournies.
def moyenne (tab):\n'''\n moyenne(list) -> float\n Entr\u00e9e : un tableau non vide d'entiers\n Sortie : nombre de type float\n Correspondant \u00e0 la moyenne des valeurs pr\u00e9sentes dans le\n tableau\n '''\n\nassert moyenne([1]) == 1\nassert moyenne([1,2,3,4,5,6,7] == 4\nassert moyenne([1,2]) == 1.5\n
def moyenne(tab):\n'''\n moyenne(list) -> float\n Entr\u00e9e : un tableau non vide d'entiers\n Sortie : nombre de type float\n Correspondant \u00e0 la moyenne des valeurs pr\u00e9sentes dans le\n tableau\n '''\n somme = 0\n for elt in tab:\n somme += elt\n return somme / len(tab)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-042","title":"Exercice 04.2 \u25a1","text":"Exercice 04.2
\u00c9nonc\u00e9CorrectionLe but de l'exercice est de compl\u00e9ter une fonction qui d\u00e9termine si une valeur est pr\u00e9sente dans un tableau de valeurs tri\u00e9es dans l'ordre croissant.
L'algorithme traite le cas du tableau vide.
L'algorithme est \u00e9crit pour que la recherche dichotomique ne se fasse que dans le cas o\u00f9 la valeur est comprise entre les valeurs extr\u00eames du tableau.
On distingue les trois cas qui renvoient False
en renvoyant False,1
, False,2
et False,3
.
Compl\u00e9ter l'algorithme de dichotomie donn\u00e9 ci-apr\u00e8s.
def dichotomie(tab, x):\n\"\"\"\n tab : tableau tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n # cas du tableau vide\n if ...:\n return False,1\n # cas o\u00f9 x n'est pas compris entre les valeurs extr\u00eames\n if (x < tab[0]) or ...:\n return False,2\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\n(False, 3)\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],1)\n(False, 2)\n>>> dichotomie([],28)\n(False, 1)\n
def dichotomie(tab, x):\n\"\"\"\n tab : tableau tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n # cas du tableau vide\n if tab = []:\n return False,1\n # cas o\u00f9 x n'est pas compris entre les valeurs extr\u00eames\n if (x < tab[0]) or (x > tab[-1]):\n return False,2\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = (debut + fin) // 2\n if x == tab[m]:\n return True\n if x > tab[m]:\n debut = m + 1\n else:\n fin = m - 1\n return False\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-051","title":"Exercice 05.1 \u25a1","text":"Exercice 05.1
\u00c9nonc\u00e9CorrectionOn mod\u00e9lise la repr\u00e9sentation binaire d'un entier non sign\u00e9 par un tableau d'entiers dont les \u00e9l\u00e9ments sont 0 ou 1. Par exemple, le tableau [1, 0, 1, 0, 0, 1, 1]
repr\u00e9sente l'\u00e9criture binaire de l'entier dont l'\u00e9criture d\u00e9cimale est 2**6 + 2**4 + 2**1 + 2**0 = 83
.
\u00c0 l'aide d'un parcours s\u00e9quentiel, \u00e9crire la fonction convertir r\u00e9pondant aux sp\u00e9cifications suivantes :
def convertir(T):\n\"\"\"\n T est un tableau d'entiers, dont les \u00e9l\u00e9ments sont 0 ou 1 et\n repr\u00e9sentant un entier \u00e9crit en binaire. Renvoie l'\u00e9criture\n d\u00e9cimale de l'entier positif dont la repr\u00e9sentation binaire\n est donn\u00e9e par le tableau T\n \"\"\"\n
Exemple : >>> convertir([1, 0, 1, 0, 0, 1, 1])\n83\n>>> convertir([1, 0, 0, 0, 0, 0, 1, 0])\n130\n
def convertir(T):\n puissance = 0\n total = 0\n for i in range(len(T)-1, -1, -1):\n total += T[i]*(2**puissance)\n puissance += 1\n return total\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-052","title":"Exercice 05.2 \u25a1","text":"Exercice 05.2
\u00c9nonc\u00e9CorrectionLa fonction tri_insertion
suivante prend en argument une liste L
et trie cette liste en utilisant la m\u00e9thode du tri par insertion. Compl\u00e9ter cette fonction pour qu'elle r\u00e9ponde \u00e0 la sp\u00e9cification demand\u00e9e.
def tri_insertion(L):\n n = len(L)\n\n # cas du tableau vide\n if ...:\n return L\n for j in range(1,n):\n e = L[j]\n i = j\n\n # A l'\u00e9tape j, le sous-tableau L[0,j-1] est tri\u00e9\n # et on ins\u00e8re L[j] dans ce sous-tableau en d\u00e9terminant\n # le plus petit i tel que 0 <= i <= j et L[i-1] > L[j].\n\n while i > 0 and L[i-1] > ...:\n i = ...\n\n # si i != j, on d\u00e9cale le sous tableau L[i,j-1] d\u2019un cran\n # vers la droite et on place L[j] en position i\n\n if i != j:\n for k in range(j,i,...):\n L[k] = L[...]\n L[i] = ...\n return L\n
Exemples :
>>> tri_insertion([2,5,-1,7,0,28])\n[-1, 0, 2, 5, 7, 28]\n>>> tri_insertion([10,9,8,7,6,5,4,3,2,1,0])\n[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n
def tri_insertion(L):\n n = len(L)\n\n # cas du tableau vide\n if L == []:\n return L\n\n for j in range(1,n):\n e = L[j]\n i = j\n\n # A l'\u00e9tape j, le sous-tableau L[0,j-1] est tri\u00e9\n # et on ins\u00e8re L[j] dans ce sous-tableau en d\u00e9terminant\n # le plus petit i tel que 0 <= i <= j et L[i-1] > L[j].\n\n while i > 0 and L[i-1] > e:\n i = i - 1\n\n # si i != j, on d\u00e9cale le sous tableau L[i,j-1] d\u2019un cran\n # vers la droite et on place L[j] en position i\n\n if i != j:\n for k in range(j,i,-1):\n L[k] = L[k-1]\n L[i] = e\n return L\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-061","title":"Exercice 06.1 \u25a1","text":"Exercice 06.1
\u00c9nonc\u00e9CorrectionOn s\u2019int\u00e9resse au probl\u00e8me du rendu de monnaie. On suppose qu\u2019on dispose d\u2019un nombre infini de billets de 5 euros, de pi\u00e8ces de 2 euros et de pi\u00e8ces de 1 euro. Le but est d\u2019\u00e9crire une fonction nomm\u00e9e rendu
dont le param\u00e8tre est un entier positif non nul somme_a_rendre
et qui retourne une liste de trois entiers n1
, n2
et n3
qui correspondent aux nombres de billets de 5 euros (n1
) de pi\u00e8ces de 2 euros (n2
) et de pi\u00e8ces de 1 euro (n3
) \u00e0 rendre afin que le total rendu soit \u00e9gal \u00e0 somme_a_rendre
.
On utilisera un algorithme glouton : on commencera par rendre le nombre maximal de billets de 5 euros, puis celui des pi\u00e8ces de 2 euros et enfin celui des pi\u00e8ces de 1 euros.
Exemples :
>>> rendu(13)\n[2,1,1]\n>>> rendu(64)\n[12,2,0]\n>>> rendu(89)\n[17,2,0]\n
def rendu(somme_a_rendre):\n pieces = [5, 2, 1]\n retour = [0, 0, 0]\n reste_a_rendre = somme_a_rendre\n for i in range(3):\n retour[i] = reste_a_rendre // pieces[i]\n reste_a_rendre = reste_a_rendre % pieces[i]\n return retour\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-062","title":"Exercice 06.2 \u25a1","text":"\u00e0 noter une erreur dans la version officielle, sur la m\u00e9thode enfile()
Exercice 06.2
\u00c9nonc\u00e9CorrectionOn veut \u00e9crire une classe pour g\u00e9rer une file \u00e0 l\u2019aide d\u2019une liste cha\u00een\u00e9e. On dispose d\u2019une classe Maillon
permettant la cr\u00e9ation d\u2019un maillon de la cha\u00eene, celui-ci \u00e9tant constitu\u00e9 d\u2019une valeur et d\u2019une r\u00e9f\u00e9rence au maillon suivant de la cha\u00eene :
class Maillon :\n def __init__(self,v) :\n self.valeur = v\n self.suivant = None\n
Compl\u00e9ter la classe File suivante
o\u00f9 l\u2019attribut dernier_file
contient le maillon correspondant \u00e0 l\u2019\u00e9l\u00e9ment arriv\u00e9 en dernier dans la file : class File :\n def __init__(self) :\n self.dernier_file = None\n\n def enfile(self,element) :\n nouveau_maillon = Maillon(...)\n nouveau_maillon.suivant = self.dernier_file\n self.dernier_file = ...\n\n def est_vide(self) :\n return self.dernier_file == None\n\n def affiche(self) :\n maillon = self.dernier_file\n while maillon != ... :\n print(maillon.valeur)\n maillon = ...\n\n def defile(self) :\n if not self.est_vide() :\n if self.dernier_file.suivant == None :\n resultat = self.dernier_file.valeur\n self.dernier_file = None\n return resultat\n maillon = ...\n while maillon.suivant.suivant != None :\n maillon = maillon.suivant\n resultat = ...\n maillon.suivant = None\n return resultat\n return None\n
On pourra tester le fonctionnement de la classe en utilisant les commandes suivantes dans la console Python : >>> F = File()\n>>> F.est_vide()\nTrue\n>>> F.enfile(2)\n>>> F.affiche()\n2\n>>> F.est_vide()\nFalse\n>>> F.enfile(5)\n>>> F.enfile(7)\n>>> F.affiche()\n7\n5\n2\n>>> F.defile()\n2\n>>> F.defile()\n5\n>>> F.affiche()\n7\n
class Maillon :\n def __init__(self,v) :\n self.valeur = v\n self.suivant = None\n\nclass File :\n def __init__(self) :\n self.dernier_file = None\n\n def enfile(self,element) :\n nouveau_maillon = Maillon(element)\n nouveau_maillon.suivant = self.dernier_file\n self.dernier_file = nouveau_maillon\n\n def est_vide(self) :\n return self.dernier_file == None\n\n def affiche(self) :\n maillon = self.dernier_file\n while maillon != None :\n print(maillon.valeur)\n maillon = maillon.suivant\n\n def defile(self) :\n if not self.est_vide() :\n if self.dernier_file.suivant == None :\n resultat = self.dernier_file.valeur\n self.dernier_file = None\n return resultat\n maillon = self.dernier_file\n while maillon.suivant.suivant != None :\n maillon = maillon.suivant\n resultat = maillon.suivant.valeur\n maillon.suivant = None\n return resultat\n return None\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-071","title":"Exercice 07.1 \ud83d\uddf9","text":"Exercice 07.1
\u00c9nonc\u00e9CorrectionOn s\u2019int\u00e9resse \u00e0 la suite d\u2019entiers d\u00e9finie par U1 = 1
, U2 = 1
et, pour tout entier naturel n
, par Un+2 = Un+1 + Un
.
Elle s\u2019appelle la suite de Fibonacci.
\u00c9crire la fonction fibonacci
qui prend un entier n > 0
et qui renvoie l\u2019\u00e9l\u00e9ment d\u2019indice n
de cette suite.
On utilisera une programmation dynamique (pas de r\u00e9cursivit\u00e9).
Exemple :
>>> fibonacci(1)\n1\n>>> fibonacci(2)\n1\n>>> fibonacci(25)\n75025\n>>> fibonacci(45)\n1134903170\n
On utilise un dictionnaire pour stocker au fur et \u00e0 mesure les valeurs.
def fibonnaci(n):\n d = {}\n d[1] = 1\n d[2] = 1\n for k in range(3, n+1):\n d[k] = d[k-1] + d[k-2]\n return d[n]\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-072","title":"Exercice 07.2 \u25a1","text":"Exercice 07.2
\u00c9nonc\u00e9CorrectionLes variables liste_eleves
et liste_notes
ayant \u00e9t\u00e9 pr\u00e9alablement d\u00e9finies et \u00e9tant de m\u00eame longueur, la fonction meilleures_notes
renvoie la note maximale qui a \u00e9t\u00e9 attribu\u00e9e, le nombre d\u2019\u00e9l\u00e8ves ayant obtenu cette note et la liste des noms de ces \u00e9l\u00e8ves.
Compl\u00e9ter le code Python de la fonction meilleures_notes
ci-dessous.
liste_eleves = ['a','b','c','d','e','f','g','h','i','j']\nliste_notes = [1, 40, 80, 60, 58, 80, 75, 80, 60, 24]\n\ndef meilleures_notes():\n note_maxi = 0\n nb_eleves_note_maxi = ...\n liste_maxi = ...\n\n for compteur in range(...):\n if liste_notes[compteur] == ...:\n nb_eleves_note_maxi = nb_eleves_note_maxi + 1\n liste_maxi.append(liste_eleves[...])\n if liste_notes[compteur] > note_maxi:\n note_maxi = liste_notes[compteur]\n nb_eleves_note_maxi = ...\n liste_maxi = [...]\n\n return (note_maxi,nb_eleves_note_maxi,liste_maxi)\n
Une fois compl\u00e9t\u00e9, le code ci-dessus donne
>>> meilleures_notes()\n(80, 3, ['c', 'f', 'h'])\n
liste_eleves = ['a','b','c','d','e','f','g','h','i','j']\nliste_notes = [1, 40, 80, 60, 58, 80, 75, 80, 60, 24]\n\ndef meilleures_notes():\n note_maxi = 0\n nb_eleves_note_maxi = 0\n liste_maxi = []\n\n for compteur in range(len(liste_eleves)):\n if liste_notes[compteur] == note_maxi:\n nb_eleves_note_maxi = nb_eleves_note_maxi + 1\n liste_maxi.append(liste_eleves[compteur])\n if liste_notes[compteur] > note_maxi:\n note_maxi = liste_notes[compteur]\n nb_eleves_note_maxi = 1\n liste_maxi = [liste_eleves[compteur]]\n\n return (note_maxi,nb_eleves_note_maxi,liste_maxi)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-081","title":"Exercice 08.1 \ud83d\uddf9","text":"Exercice 08.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction recherche
qui prend en param\u00e8tres caractere
, un caract\u00e8re, et mot
, une cha\u00eene de caract\u00e8res, et qui renvoie le nombre d\u2019occurrences de caractere
dans mot
, c\u2019est-\u00e0-dire le nombre de fois o\u00f9 caractere
appara\u00eet dans mot
.
Exemples :
>>> recherche('e', \"sciences\")\n2\n>>> recherche('i',\"mississippi\")\n4\n>>> recherche('a',\"mississippi\")\n0\n
def recherche(caractere, mot):\n somme = 0\n for lettre in mot:\n if lettre == caractere:\n somme += 1\n return somme\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-082","title":"Exercice 08.2 \u25a1","text":"Exercice 08.2
\u00c9nonc\u00e9CorrectionOn s\u2019int\u00e9resse \u00e0 un algorithme r\u00e9cursif qui permet de rendre la monnaie \u00e0 partir d\u2019une liste donn\u00e9e de valeurs de pi\u00e8ces et de billets - le syst\u00e8me mon\u00e9taire est donn\u00e9 sous forme d\u2019une liste pieces=[100, 50, 20, 10, 5, 2, 1]
- (on supposera qu\u2019il n\u2019y a pas de limitation quant \u00e0 leur nombre), on cherche \u00e0 donner la liste de pi\u00e8ces \u00e0 rendre pour une somme donn\u00e9e en argument. Compl\u00e9ter le code Python ci-dessous de la fonction rendu_glouton
qui impl\u00e9mente cet algorithme et renvoie la liste des pi\u00e8ces \u00e0 rendre.
pieces = [100,50,20,10,5,2,1]\n\ndef rendu_glouton(arendre, solution=[], i=0):\n if arendre == 0:\n return ...\n p = pieces[i]\n if p <= ... :\n solution.append(...)\n return rendu_glouton(arendre - p, solution,i)\n else :\n return rendu_glouton(arendre, solution, ...)\n
On devra obtenir : >>>rendu_glouton(68,[],0)\n[50, 10, 5, 2, 1]\n>>>rendu_glouton(291,[],0)\n[100, 100, 50, 20, 20, 1]\n
pieces = [100,50,20,10,5,2,1]\n\ndef rendu_glouton(arendre, solution=[], i=0):\n if arendre == 0:\n return solution\n p = pieces[i]\n if p <= arendre :\n solution.append(p)\n return rendu_glouton(arendre - p, solution,i)\n else :\n return rendu_glouton(arendre, solution, i+1)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-091","title":"Exercice 09.1 \u25a1","text":"Exercice 09.1
\u00c9nonc\u00e9CorrectionSoit le couple (note
,coefficient
):
note
est un nombre de type flottant (float
) compris entre 0 et 20 ;coefficient
est un nombre entier positif.Les r\u00e9sultats aux \u00e9valuations d'un \u00e9l\u00e8ve sont regroup\u00e9s dans une liste compos\u00e9e de couples (note
,coefficient
).
\u00c9crire une fonction moyenne qui renvoie la moyenne pond\u00e9r\u00e9e de cette liste donn\u00e9e en param\u00e8tre.
Par exemple, l\u2019expression moyenne([(15,2),(9,1),(12,3)])
devra renvoyer le r\u00e9sultat du calcul suivant :
\\(\\dfrac{2 \\times 15 + 1 \\times 9 + 3 \\times 12 }{2+1+3}=12,5\\)
def moyenne(tab):\n somme_notes = 0\n somme_coeffs = 0\n for devoir in tab:\n note = devoir[0]\n coeff = devoir[1]\n somme_notes += note * coeff\n somme_coeffs += coeff\n return somme_notes / somme_coeffs\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-092","title":"Exercice 09.2 \u25a1","text":"Exercice 09.2
\u00c9nonc\u00e9CorrectionOn cherche \u00e0 d\u00e9terminer les valeurs du triangle de Pascal. Dans ce tableau de forme triangulaire, chaque ligne commence et se termine par le nombre 1. Par ailleurs, la valeur qui occupe une case situ\u00e9e \u00e0 l\u2019int\u00e9rieur du tableau s\u2019obtient en ajoutant les valeurs des deux cases situ\u00e9es juste au-dessus, comme l\u2019indique la figure suivante :
Compl\u00e9ter la fonction pascal
ci-apr\u00e8s. Elle doit renvoyer une liste correspondant au triangle de Pascal de la ligne 1
\u00e0 la ligne n
o\u00f9 n
est un nombre entier sup\u00e9rieur ou \u00e9gal \u00e0 2
(le tableau sera contenu dans la variable C
). La variable Ck
doit, quant \u00e0 elle, contenir, \u00e0 l\u2019\u00e9tape num\u00e9ro k
, la k
-i\u00e8me ligne du tableau.
def pascal(n):\n C= [[1]]\n for k in range(1,...):\n Ck = [...]\n for i in range(1,k):\n Ck.append(C[...][i-1]+C[...][...] )\n Ck.append(...)\n C.append(Ck)\n return C\n
Pour n = 4
, voici ce qu'on devra obtenir :
>>> pascal(4)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]\n
Pour n = 5
, voici ce qu'on devra obtenir : >>> pascal(5)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1]]\n
def pascal(n):\n C = [[1]]\n for k in range(1,n+1):\n Ck = [1]\n for i in range(1,k):\n Ck.append(C[k-1][i-1]+C[k-1][i] )\n Ck.append(1)\n C.append(Ck)\n return C\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-101","title":"Exercice 10.1 \ud83d\uddf9","text":"Exercice 10.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction maxi
qui prend en param\u00e8tre une liste tab
de nombres entiers et renvoie un couple donnant le plus grand \u00e9l\u00e9ment de cette liste, ainsi que l\u2019indice de la premi\u00e8re apparition de ce maximum dans la liste.
Exemple :
>>> maxi([1,5,6,9,1,2,3,7,9,8])\n(9,3)\n
def maxi(tab):\n val_max = tab[0]\n pos_max = 0\n for i in range(len(tab)):\n if tab[i] > val_max:\n val_max = tab[i]\n pos_max = i\n return (val_max, pos_max)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-102","title":"Exercice 10.2 \ud83d\uddf9","text":"Exercice 10.2
\u00c9nonc\u00e9CorrectionCet exercice utilise des piles qui seront repr\u00e9sent\u00e9es en Python par des listes (type list
).
On rappelle que l\u2019expression T1 = list(T)
fait une copie de T
ind\u00e9pendante de T
, que l\u2019expression x = T.pop()
enl\u00e8ve le sommet de la pile T
et le place dans la variable x
et, enfin, que l\u2019expression T.append(v)
place la valeur v
au sommet de la pile T
.
Compl\u00e9ter le code Python de la fonction positif
ci-dessous qui prend une pile T
de nombres entiers en param\u00e8tre et qui renvoie la pile des entiers positifs dans le m\u00eame ordre, sans modifier la variable T
.
def positif(T):\n T2 = ...(T)\n T3 = ...\n while T2 != []:\n x = ...\n if ... >= 0:\n T3.append(...)\n T2 = []\n while T3 != ...:\n x = T3.pop()\n ...\n print('T = ',T)\n return T2\n
Exemple :
>>> positif([-1,0,5,-3,4,-6,10,9,-8 ])\nT = [-1, 0, 5, -3, 4, -6, 10, 9, -8]\n[0, 5, 4, 10, 9]\n
def positif(T):\n T2 = list(T)\n T3 = []\n while T2 != []:\n x = T2.pop()\n if x >= 0:\n T3.append(x)\n T2 = [] # <- NB : cette ligne est inutile\n while T3 != []:\n x = T3.pop()\n T2.append(x)\n print('T = ',T)\n return T2\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-111","title":"Exercice 11.1 \u25a1","text":"Exercice 11.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction conv_bin
qui prend en param\u00e8tre un entier positif n
et renvoie un couple (b,bit)
o\u00f9 :
b
est une liste d'entiers correspondant \u00e0 la repr\u00e9sentation binaire de n
;bit
correspond aux nombre de bits qui constituent b
.Exemple :
>>> conv_bin(9)\n([1,0,0,1],4)\n
Aide :
//
donne le quotient de la division euclidienne : 5//2
donne 2
;%
donne le reste de la division euclidienne :5%2
donne 1
;append
est une m\u00e9thode qui ajoute un \u00e9l\u00e9ment \u00e0 une liste existante : Soit T=[5,2,4]
, alors T.append(10)
ajoute 10
\u00e0 la liste T
. Ainsi, T
devient [5,2,4,10]
.reverse
est une m\u00e9thode qui renverse les \u00e9l\u00e9ments d'une liste. Soit T=[5,2,4,10]
. Apr\u00e8s T.reverse()
, la liste devient [10,4,2,5]
.On remarquera qu\u2019on r\u00e9cup\u00e8re la repr\u00e9sentation binaire d\u2019un entier n
en partant de la gauche en appliquant successivement les instructions :
b = n%2
n = n//2
r\u00e9p\u00e9t\u00e9es autant que n\u00e9cessaire.
def conv_bin(n):\n b = []\n bits = 0\n while n != 0:\n b.append(n % 2)\n bits += 1\n n = n // 2\n b.reverse()\n return (b, bits)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-112","title":"Exercice 11.2 \u25a1","text":"Exercice 11.2
\u00c9nonc\u00e9CorrectionLa fonction tri_bulles
prend en param\u00e8tre une liste T
d\u2019entiers non tri\u00e9s et renvoie la liste tri\u00e9e par ordre croissant. Compl\u00e9ter le code Python ci-dessous qui impl\u00e9mente la fonction tri_bulles
.
def tri_bulles(T):\n n = len(T)\n for i in range(...,...,-1):\n for j in range(i):\n if T[j] > T[...]:\n ... = T[j]\n T[j] = T[...]\n T[j+1] = temp\n return T\n
\u00c9crire une autre version de l\u2019algorithme avec for i in range(n-1):\n
en lieu et place de la troisi\u00e8me ligne du code pr\u00e9c\u00e9dent. def tri_bulles(T):\n n = len(T)\n for i in range(n-1,0,-1):\n for j in range(i):\n if T[j] > T[j+1]:\n temp = T[j]\n T[j] = T[j+1]\n T[j+1] = temp\n return T\n\n#version 2\n\ndef tri_bulles(T):\n n = len(T)\n for i in range(n-1):\n for j in range(n-1,i,-1):\n if T[j] < T[j-1]:\n temp = T[j]\n T[j] = T[j-1]\n T[j-1] = temp\n return T\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-121","title":"Exercice 12.1 \u25a1","text":"Ce sujet est le m\u00eame que le 10.1... \u00af\\_(\u30c4)_/\u00af
Exercice 12.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction maxi
qui prend en param\u00e8tre une liste tab
de nombres entiers et renvoie un couple donnant le plus grand \u00e9l\u00e9ment de cette liste, ainsi que l\u2019indice de la premi\u00e8re apparition de ce maximum dans la liste.
Exemple :
>>> maxi([1,5,6,9,1,2,3,7,9,8])\n(9,3)\n
def maxi(tab):\n val_max = tab[0]\n pos_max = 0\n for i in range(len(tab)):\n if tab[i] > val_max:\n val_max = tab[i]\n pos_max = i\n return (val_max, pos_max)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-122","title":"Exercice 12.2 \ud83d\uddf9","text":"Exercice 12.2
\u00c9nonc\u00e9CorrectionLa fonction recherche
prend en param\u00e8tres deux chaines de caract\u00e8res gene
et seq_adn
et renvoie True
si on retrouve gene
dans seq_adn
et False
sinon. Compl\u00e9ter le code Python ci-dessous pour qu\u2019il impl\u00e9mente la fonction recherche
.
def recherche(gene, seq_adn):\n n = len(seq_adn)\n g = len(gene)\n i = ...\n trouve = False\n while i < ... and trouve == ... :\n j = 0\n while j < g and gene[j] == seq_adn[i+j]:\n ...\n if j == g:\n trouve = True\n ...\n return trouve\n
Exemples :
>>> recherche(\"AATC\", \"GTACAAATCTTGCC\")\nTrue\n>>> recherche(\"AGTC\", \"GTACAAATCTTGCC\")\nFalse\n
def recherche(gene, seq_adn):\n n = len(seq_adn)\n g = len(gene)\n i = 0\n trouve = False\n while i < n-g and trouve == False :\n j = 0\n while j < g and gene[j] == seq_adn[i+j]:\n j += 1\n if j == g:\n trouve = True\n i += 1\n return trouve\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-131","title":"Exercice 13.1 \u25a1","text":"Exercice 13.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction tri_selection
qui prend en param\u00e8tre une liste tab
de nombres entiers et qui renvoie le tableau tri\u00e9 par ordre croissant.
On utilisera l\u2019algorithme suivant :
Exemple :
>>> tri_selection([1,52,6,-9,12])\n[-9, 1, 6, 12, 52]\n
def tri_selection(tab):\n for i in range(len(tab)-1):\n indice_min = i\n for j in range(i+1, len(tab)):\n if tab[j] < tab[indice_min]:\n indice_min = j\n tab[i], tab[indice_min] = tab[indice_min], tab[i]\n return tab\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-132","title":"Exercice 13.2 \u25a1","text":"Exercice 13.2
\u00c9nonc\u00e9CorrectionLe jeu du \u00ab plus ou moins \u00bb consiste \u00e0 deviner un nombre entier choisi entre 1 et 99. Un \u00e9l\u00e8ve de NSI d\u00e9cide de le coder en langage Python de la mani\u00e8re suivante :
La fonction randint
est utilis\u00e9e. Si a et b sont des entiers, randint(a,b)
renvoie un nombre entier compris entre a
et b
. Compl\u00e9ter le code ci-dessous et le tester :
from random import randint\n\ndef plus_ou_moins():\n nb_mystere = randint(1,...)\n nb_test = int(input(\"Proposez un nombre entre 1 et 99 : \"))\n compteur = ...\n\n while nb_mystere != ... and compteur < ... :\n compteur = compteur + ...\n if nb_mystere ... nb_test:\n nb_test = int(input(\"Trop petit ! Testez encore : \"))\n else:\n nb_test = int(input(\"Trop grand ! Testez encore : \"))\n\n if nb_mystere == nb_test:\n print (\"Bravo ! Le nombre \u00e9tait \",...)\n print(\"Nombre d'essais: \",...)\n else:\n print (\"Perdu ! Le nombre \u00e9tait \",...)\n
from random import randint\n\ndef plus_ou_moins():\n nb_mystere = randint(1,100)\n nb_test = int(input('Proposez un nombre entre 1 et 99 : '))\n compteur = 0\n\n while nb_mystere != nb_test and compteur < 10 :\n compteur = compteur + 1\n if nb_mystere > nb_test:\n nb_test = int(input('Trop petit ! Testez encore : '))\n else:\n nb_test = int(input('Trop grand ! Testez encore : '))\n\n if nb_mystere == nb_test:\n print ('Bravo ! Le nombre \u00e9tait ', nb_mystere)\n print('Nombre d essais: ', compteur)\n else:\n print ('Perdu ! Le nombre \u00e9tait ', nb_mystere)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-141","title":"Exercice 14.1 \u25a1","text":"Exercice 14.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction recherche
qui prend en param\u00e8tres elt
un nombre et tab
un tableau de nombres, et qui renvoie le tableau des indices de elt
dans tab
si elt
est dans tab
et le tableau vide []
sinon.
Exemples :
>>> recherche(3, [3, 2, 1, 3, 2, 1])\n[0, 3]\n>>> recherche(4, [1, 2, 3])\n[]\n
def recherche(elt, tab):\n tab_indices = []\n for i in range(len(tab)):\n if tab[i] == elt:\n tab_indices.append(i)\n return tab_indices \n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-142","title":"Exercice 14.2 \u25a1","text":"Exercice 14.2
\u00c9nonc\u00e9CorrectionUn professeur de NSI d\u00e9cide de g\u00e9rer les r\u00e9sultats de sa classe sous la forme d\u2019un dictionnaire :
Avec :
resultats = {'Dupont':{ 'DS1' : [15.5, 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [13, 4],\n 'PROJET1' : [16, 3],\n 'DS3' : [14, 4]},\n 'Durand':{ 'DS1' : [6 , 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [8, 4],\n 'PROJET1' : [9, 3],\n 'IE1' : [7, 2],\n 'DS3' : [8, 4],\n 'DS4' :[15, 4]}}\n
L\u2019\u00e9l\u00e8ve dont le nom est Durand a ainsi obtenu au DS2 la note de 8 avec un coefficient 4. Le professeur cr\u00e9e une fonction moyenne
qui prend en param\u00e8tre le nom d\u2019un de ces \u00e9l\u00e8ves et lui renvoie sa moyenne arrondie au dixi\u00e8me.
Compl\u00e9ter le code du professeur ci-dessous :
def moyenne(nom):\n if nom in ...:\n notes = resultats[nom]\n total_points = ...\n total_coefficients = ...\n for ... in notes.values():\n note , coefficient = valeurs\n total_points = total_points + ... * coefficient\n total_coefficients = ... + coefficient\n return round( ... / total_coefficients , 1 )\n else:\n return -1\n
resultats = {'Dupont':{ 'DS1' : [15.5, 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [13, 4],\n 'PROJET1' : [16, 3],\n 'DS3' : [14, 4]},\n 'Durand':{ 'DS1' : [6 , 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [8, 4],\n 'PROJET1' : [9, 3],\n 'IE1' : [7, 2],\n 'DS3' : [8, 4],\n 'DS4' :[15, 4]}}\n\ndef moyenne(nom):\n if nom in resultats:\n notes = resultats[nom]\n total_points = 0\n total_coefficients = 0\n for valeurs in notes.values():\n note , coefficient = valeurs\n total_points = total_points + note * coefficient\n total_coefficients = total_coefficients + coefficient\n return round( total_points / total_coefficients , 1 )\n else:\n return -1\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-151","title":"Exercice 15.1 \u25a1","text":"Exercice 15.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction rechercheMinMax
qui prend en param\u00e8tre un tableau de nombres non tri\u00e9s tab
, et qui renvoie la plus petite et la plus grande valeur du tableau sous la forme d\u2019un dictionnaire \u00e0 deux cl\u00e9s \u2018min\u2019 et \u2018max\u2019. Les tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.
Exemples :
>>> tableau = [0, 1, 4, 2, -2, 9, 3, 1, 7, 1]\n>>> resultat = rechercheMinMax(tableau)\n>>> resultat\n{'min': -2, 'max': 9}\n>>> tableau = []\n>>> resultat = rechercheMinMax(tableau)\n>>> resultat\n{'min': None, 'max': None}\n
def rechercheMinMax(tab):\n if tab == []:\n return {'min': None, 'max': None}\n d = {}\n d['min'] = None\n d['max'] = None\n for val in tab:\n if val < d['min']:\n d['min'] = val\n if val > d['max']:\n d['max'] = val\n return d\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-152","title":"Exercice 15.2 \u25a1","text":"Exercice 15.2
\u00c9nonc\u00e9CorrectionOn dispose d\u2019un programme permettant de cr\u00e9er un objet de type PaquetDeCarte
, selon les \u00e9l\u00e9ments indiqu\u00e9s dans le code ci-dessous. Compl\u00e9ter ce code aux endroits indiqu\u00e9s par #A compl\u00e9ter
, puis ajouter des assertions dans l\u2019initialiseur de Carte
, ainsi que dans la m\u00e9thode getCarteAt()
.
class Carte:\n\"\"\"Initialise Couleur (entre 1 \u00e0 4), et Valeur (entre 1 \u00e0 13)\"\"\"\n def __init__(self, c, v):\n self.Couleur = c\n self.Valeur = v\n\n\"\"\"Renvoie le nom de la Carte As, 2, ... 10, Valet, Dame, Roi\"\"\"\n def getNom(self):\n if (self.Valeur > 1 and self.Valeur < 11):\n return str(self.Valeur)\n elif self.Valeur == 11:\n return \"Valet\"\n elif self.Valeur == 12:\n return \"Dame\"\n elif self.Valeur == 13:\n return \"Roi\"\n else:\n return \"As\"\n\n\"\"\"Renvoie la couleur de la Carte (parmi pique, coeur, carreau, trefle\"\"\"\n def getCouleur(self):\n return ['pique', 'coeur', 'carreau', 'trefle'][self.Couleur - 1]\n\nclass PaquetDeCarte:\n def __init__(self):\n self.contenu = []\n\n\"\"\"Remplit le paquet de cartes\"\"\"\n def remplir(self):\n #A compl\u00e9ter\n\n\"\"\"Renvoie la Carte qui se trouve \u00e0 la position donn\u00e9e\"\"\"\n def getCarteAt(self, pos):\n #A compl\u00e9ter\n
Exemple : >>> unPaquet = PaquetDeCarte()\n>>> unPaquet.remplir()\n>>> uneCarte = unPaquet.getCarteAt(20)\n>>> print(uneCarte.getNom() + \" de \" + uneCarte.getCouleur())\n
Attention, le code propos\u00e9 ne respecte pas les standards de notation :
class Carte:\n\"\"\"Initialise Couleur (entre 1 \u00e0 4), et Valeur (entre 1 \u00e0 13)\"\"\"\n def __init__(self, c, v):\n assert c in range(1,5)\n assert v in range(1,14)\n self.Couleur = c\n self.Valeur = v\n\n\"\"\"Renvoie le nom de la Carte As, 2, ... 10, Valet, Dame, Roi\"\"\"\n def getNom(self):\n if (self.Valeur > 1 and self.Valeur < 11):\n return str( self.Valeur)\n elif self.Valeur == 11:\n return \"Valet\"\n elif self.Valeur == 12:\n return \"Dame\"\n elif self.Valeur == 13:\n return \"Roi\"\n else:\n return \"As\"\n\n\"\"\"Renvoie la couleur de la Carte (parmi pique, coeur, carreau, trefle\"\"\"\n def getCouleur(self):\n return ['pique', 'coeur', 'carreau', 'trefle'][self.Couleur]\n\nclass PaquetDeCarte:\n def __init__(self):\n self.contenu = []\n\n\"\"\"Remplit le paquet de cartes\"\"\"\n def remplir(self):\n for nb_coul in range(1,5):\n for val in range(1,14):\n self.contenu.append(Carte(nb_coul, val))\n\n\"\"\"Renvoie la Carte qui se trouve \u00e0 la position donn\u00e9e\"\"\"\n def getCarteAt(self, pos):\n assert pos in range(56)\n return self.contenu[pos]\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-161","title":"Exercice 16.1 \u25a1","text":"Exercice 16.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction moyenne
qui prend en param\u00e8tre un tableau non vide de nombres flottants et qui renvoie la moyenne des valeurs du tableau. Les tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.
Exemples :
>>> moyenne([1.0])\n1.0\n>>> moyenne([1.0, 2.0, 4.0])\n2.3333333333333335\n
def moyenne(tab):\n somme = 0\n for val in tab:\n somme += val\n return somme / len(tab)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-162","title":"Exercice 16.2 \u25a1","text":"Exercice 16.2
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la fonction dec_to_bin
ci-dessous qui prend en param\u00e8tre un entier positif a
en \u00e9criture d\u00e9cimale et qui renvoie son \u00e9criture binaire sous la forme d'une chaine de caract\u00e8res.
def dec_to_bin(a):\n bin_a = ...\n a = a//2\n while a ... :\n bin_a = ... + bin_a\n a = ...\n return bin_a\n
Compl\u00e9ter la fonction dec_to_bin
. Exemples :
>>> dec_to_bin(83)\n'1010011'\n>>> dec_to_bin(127)\n'1111111'\n
def dec_to_bin(a):\n bin_a = ''\n a = a // 2\n while a != 0 :\n bin_a = str(a%2) + bin_a\n a = a // 2\n return bin_a\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-171","title":"Exercice 17.1 \ud83d\uddf9","text":"Exercice 17.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction indice_du_min
qui prend en param\u00e8tre un tableau de nombres non tri\u00e9 tab
, et qui renvoie l'indice de la premi\u00e8re occurrence du minimum de ce tableau. Les tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.
Exemples :
>>> indice_du_min([5])\n0\n>>> indice_du_min([2, 4, 1])\n2\n>>> indice_du_min([5, 3, 2, 2, 4])\n2\n
def indice_du_min(tab):\n indice_min = 0\n for i in range(len(tab)):\n if tab[i] < tab[indice_min]:\n indice_min = i\n return indice_min\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-172","title":"Exercice 17.2 \ud83d\uddf9","text":"Exercice 17.2
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la fonction separe
ci-dessous qui prend en argument un tableau tab
dont les \u00e9l\u00e9ments sont des 0
et des 1
et qui s\u00e9pare les 0
des 1
en pla\u00e7ant les 0
en d\u00e9but de tableau et les 1
\u00e0 la suite.
def separe(tab):\n i = 0\n j = ...\n while i < j :\n if tab[i] == 0 :\n i = ...\n else :\n tab[i], tab[j] = ...\n j = ...\n return tab\n
Compl\u00e9ter la fonction separe
ci-dessus.
Exemples :
>>> separe([1, 0, 1, 0, 1, 0, 1, 0])\n[0, 0, 0, 0, 1, 1, 1, 1]\n>>> separe([1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0])\n[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\n
def separe(tab):\n i = 0\n j = len(tab) - 1\n while i < j :\n if tab[i] == 0 :\n i = i + 1\n else :\n tab[i], tab[j] = tab[j], tab[i]\n j = j - 1\n return tab\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-181","title":"Exercice 18.1 \u25a1","text":"Exercice 18.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction recherche
qui prend en param\u00e8tres elt
un nombre entier et tab
un tableau de nombres entiers, et qui renvoie l\u2019indice de la premi\u00e8re occurrence de elt
dans tab
si elt
est dans tab
et -1
sinon.
Exemples :
>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(50, [1, 50, 1])\n1\n>>> recherche(15, [8, 9, 10, 15])\n3\n
def recherche(elt, tab):\n for i in range(len(tab)):\n if tab[i] == elt:\n return i \n return -1 \n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-182","title":"Exercice 18.2 \u25a1","text":"Exercice 18.2
\u00c9nonc\u00e9CorrectionOn consid\u00e8re la fonction insere
ci-dessous qui prend en argument un entier a
et un tableau tab
d'entiers tri\u00e9s par ordre croissant. Cette fonction ins\u00e8re la valeur a
dans le tableau et renvoie le nouveau tableau. Les tableaux seront repr\u00e9sent\u00e9s sous la forme de listes python.
Sujet l\u00e9g\u00e8rement modifi\u00e9
def insere(a, tab):\n l = list(tab) #l contient les m\u00eames \u00e9l\u00e9ments que tab\n l.append(a)\n i = ...\n while a < ... and i >= ...:\n l[i+1] = ...\n l[i] = a\n i = ...\n return l\n
Compl\u00e9ter la fonction insere
ci-dessus.
Exemples :
>>> insere(3,[1,2,4,5])\n[1, 2, 3, 4, 5]\n>>> insere(10,[1,2,7,12,14,25])\n[1, 2, 7, 10, 12, 14, 25]\n>>> insere(1,[2,3,4])\n[1, 2, 3, 4]\n
def insere(a, tab):\n l = list(tab) #l contient les m\u00eames \u00e9l\u00e9ments que tab\n l.append(a)\n i = len(l) - 2\n while a < l[i] and i >= 0:\n l[i+1] = l[i]\n l[i] = a\n i = i - 1\n return l\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-191","title":"Exercice 19.1 \u25a1","text":"Exercice 19.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction recherche
qui prend en param\u00e8tres un tableau tab
de nombres entiers tri\u00e9s par ordre croissant et un nombre entier n
, et qui effectue une recherche dichotomique du nombre entier n
dans le tableau non vide tab
. Cette fonction doit renvoyer un indice correspondant au nombre cherch\u00e9 s\u2019il est dans le tableau, -1
sinon.
Exemples :
>>> recherche([2, 3, 4, 5, 6], 5)\n3\n>>> recherche([2, 3, 4, 6, 7], 5)\n-1\n
def recherche(tab, n):\n ind_debut = 0\n ind_fin = len(tab) - 1\n while ind_debut <= ind_fin:\n ind_milieu = (ind_debut + ind_fin) // 2\n if tab[ind_milieu] == n:\n return ind_milieu\n elif tab[ind_milieu] < n:\n ind_debut = ind_milieu + 1\n else:\n ind_fin = ind_milieu - 1\n return -1\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-192","title":"Exercice 19.2 \u25a1","text":"Exercice 19.2
\u00c9nonc\u00e9CorrectionLe codage de C\u00e9sar transforme un message en changeant chaque lettre en la d\u00e9calant dans l\u2019alphabet. Par exemple, avec un d\u00e9calage de 3, le A se transforme en D, le B en E, ..., le X en A, le Y en B et le Z en C. Les autres caract\u00e8res (\u2018!\u2019,\u2019 ?\u2019\u2026) ne sont pas cod\u00e9s.
La fonction position_alphabet
ci-dessous prend en param\u00e8tre un caract\u00e8re lettre
et renvoie la position de lettre
dans la cha\u00eene de caract\u00e8res ALPHABET
s\u2019il s\u2019y trouve et -1
sinon. La fonction cesar
prend en param\u00e8tre une cha\u00eene de caract\u00e8res message
et un nombre entier decalage
et renvoie le nouveau message cod\u00e9 avec le codage de C\u00e9sar utilisant le d\u00e9calage decalage
.
ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\ndef position_alphabet(lettre):\n return ALPHABET.find(lettre)\n\ndef cesar(message, decalage):\n resultat = ''\n for ... in message:\n if lettre in ALPHABET:\n indice = ( ... ) % 26\n resultat = resultat + ALPHABET[indice]\n else:\n resultat = ...\n return resultat\n
Compl\u00e9ter la fonction cesar
.
Exemples :
>>> cesar('BONJOUR A TOUS. VIVE LA MATIERE NSI !',4)\n'FSRNSYV E XSYW. ZMZI PE QEXMIVI RWM !'\n>>> cesar('GTSOTZW F YTZX. ANAJ QF RFYNJWJ SXN !',-5)\n'BONJOUR A TOUS. VIVE LA MATIERE NSI !'\n
ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\ndef position_alphabet(lettre):\n return ALPHABET.find(lettre)\n\ndef cesar(message, decalage):\n resultat = ''\n for lettre in message:\n if lettre in ALPHABET:\n indice = (position_alphabet(lettre) + decalage) % 26\n resultat = resultat + ALPHABET[indice]\n else:\n resultat = resultat + lettre\n return resultat\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-201","title":"Exercice 20.1 \ud83d\uddf9","text":"Exercice 20.1
\u00c9nonc\u00e9CorrectionOn a relev\u00e9 les valeurs moyennes annuelles des temp\u00e9ratures \u00e0 Paris pour la p\u00e9riode allant de 2013 \u00e0 2019. Les r\u00e9sultats ont \u00e9t\u00e9 r\u00e9cup\u00e9r\u00e9s sous la forme de deux listes : l\u2019une pour les temp\u00e9ratures, l\u2019autre pour les ann\u00e9es :
t_moy = [14.9, 13.3, 13.1, 12.5, 13.0, 13.6, 13.7]\nannees = [2013, 2014, 2015, 2016, 2017, 2018, 2019]\n
\u00c9crire la fonction mini
qui prend en param\u00e8tres le tableau releve
des relev\u00e9s et le tableau date
des dates et qui renvoie la plus petite valeur relev\u00e9e au cours de la p\u00e9riode et l\u2019ann\u00e9e correspondante.
Exemple :
>>> mini(t_moy, annees)\n(12.5, 2016)\n
t_moy = [14.9, 13.3, 13.1, 12.5, 13.0, 13.6, 13.7]\nannees = [2013, 2014, 2015, 2016, 2017, 2018, 2019]\n\ndef mini(releve, date):\n temp_mini = releve[0]\n date_mini = date[0]\n for i in range(len(releve)):\n if releve[i] < temp_mini:\n temp_mini = releve[i]\n date_mini = date[i]\n return temp_mini, date_mini\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-202","title":"Exercice 20.2 \ud83d\uddf9","text":"Exercice 20.2
\u00c9nonc\u00e9CorrectionUn mot palindrome peut se lire de la m\u00eame fa\u00e7on de gauche \u00e0 droite ou de droite \u00e0 gauche : bob, radar, et non sont des mots palindromes.
De m\u00eame certains nombres sont eux aussi des palindromes : 33, 121, 345543.
L\u2019objectif de cet exercice est d\u2019obtenir un programme Python permettant de tester si un nombre est un nombre palindrome.
Pour remplir cette t\u00e2che, on vous demande de compl\u00e9ter le code des trois fonctions ci- dessous sachant que la fonction est_nbre_palindrome
s\u2019appuiera sur la fonction est_palindrome
qui elle-m\u00eame s\u2019appuiera sur la fonction inverse_chaine
.
La fonction inverse_chaine
inverse l'ordre des caract\u00e8res d'une cha\u00eene de caract\u00e8res chaine
et renvoie la cha\u00eene invers\u00e9e.
La fonction est_palindrome
teste si une chaine de caract\u00e8res chaine
est un palindrome. Elle renvoie True
si c\u2019est le cas et False
sinon. Cette fonction s\u2019appuie sur la fonction pr\u00e9c\u00e9dente.
La fonction est_nbre_palindrome
teste si un nombre nbre
est un palindrome. Elle renvoie True
si c\u2019est le cas et False
sinon. Cette fonction s\u2019appuie sur la fonction pr\u00e9c\u00e9dente.
Compl\u00e9ter le code des trois fonctions ci-dessous.
def inverse_chaine(chaine):\n result = ...\n for caractere in chaine:\n result = ...\n return result\n\ndef est_palindrome(chaine):\n inverse = inverse_chaine(chaine)\n return ...\n\ndef est_nbre_palindrome(nbre):\n chaine = ...\n return est_palindrome(chaine)\n
Exemples : >>> inverse_chaine('bac')\n'cab'\n>>> est_palindrome('NSI')\nFalse\n>>> est_palindrome('ISN-NSI')\nTrue\n>>> est_nbre_palindrome(214312)\nFalse\n>>> est_nbre_palindrome(213312)\nTrue\n
def inverse_chaine(chaine):\n result = ''\n for caractere in chaine:\n result = caractere + result\n return result\n\ndef est_palindrome(chaine):\n inverse = inverse_chaine(chaine)\n return chaine == inverse\n\ndef est_nbre_palindrome(nbre):\n chaine = str(nbre)\n return est_palindrome(chaine)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-211","title":"Exercice 21.1 \u25a1","text":"Exercice 21.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction python appel\u00e9e nb_repetitions
qui prend en param\u00e8tres un \u00e9l\u00e9ment elt
et une liste tab
et renvoie le nombre de fois o\u00f9 l\u2019\u00e9l\u00e9ment appara\u00eet dans la liste.
Exemples :
>>> nb_repetitions(5,[2,5,3,5,6,9,5])\n3\n>>> nb_repetitions('A',[ 'B', 'A', 'B', 'A', 'R'])\n2\n>>> nb_repetitions(12,[1, '! ',7,21,36,44])\n0\n
def nb_repetitions(elt, tab):\n nb = 0\n for element in tab:\n if element == elt:\n nb += 1\n return nb\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-212","title":"Exercice 21.2 \u25a1","text":"Exercice 21.2
\u00c9nonc\u00e9CorrectionPour rappel, la conversion d\u2019un nombre entier positif en binaire peut s\u2019effectuer \u00e0 l\u2019aide des divisions successives comme illustr\u00e9 ici :
Voici une fonction Python bas\u00e9e sur la m\u00e9thode des divisions successives permettant de convertir un nombre entier positif en binaire :
def binaire(a):\n bin_a = str(...)\n a = a // 2\n while a ... :\n bin_a = ...(a%2) + ...\n a = ...\n return bin_a\n
Compl\u00e9ter la fonction binaire
. Exemples :
>>> binaire(0)\n'0'\n>>> binaire(77)\n'1001101'\n
def binaire(a):\n bin_a = str(a%2)\n a = a // 2\n while a != 0 :\n bin_a = str(a%2) + bin_a\n a = a // 2\n return bin_a\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-221","title":"Exercice 22.1 \u25a1","text":"Exercice 22.1
\u00c9nonc\u00e9Correction\u00c9crire en langage Python une fonction recherche
prenant comme param\u00e8tres une variable a
de type num\u00e9rique (float
ou int
) et un tableau t
(type list
) et qui renvoie le nombre d'occurrences de a
dans t
.
Exemples :
>>> recherche(5,[])\n0\n>>> recherche(5,[-2, 3, 4, 8])\n0\n>>> recherche(5,[-2, 3, 1, 5, 3, 7, 4])\n1\n>>> recherche(5,[-2, 5, 3, 5, 4, 5])\n3\n
def recherche(a, t):\n nb = 0\n for element in t:\n if element == a:\n nb += 1\n return nb\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-222","title":"Exercice 22.2 \u25a1","text":"Exercice 22.2
\u00c9nonc\u00e9CorrectionLa fonction rendu_monnaie_centimes
prend en param\u00e8tres deux nombres entiers positifs s_due
ets_versee
et elle permet de proc\u00e9der au rendu de monnaie de la diff\u00e9rence s_versee \u2013 s_due
pour des achats effectu\u00e9s avec le syst\u00e8me de pi\u00e8ces de la zone Euro. On utilise pour cela un algorithme qui commence par rendre le maximum de pi\u00e8ces de plus grandes valeurs et ainsi de suite. La fonction renvoie la liste des pi\u00e8ces qui composent le rendu.
Toutes les sommes sont exprim\u00e9es en centimes d\u2019euros. Les valeurs possibles pour les pi\u00e8ces sont donc [1, 2, 5, 10, 20, 50, 100, 200]
.
Ainsi, l\u2019instruction rendu_monnaie_centimes(452, 500)
renverra [20, 20, 5, 2, 1]
.
En effet, la somme \u00e0 rendre est de 48
centimes soit 20 + 20 + 5 + 2 + 1
. Le code de la fonction est donn\u00e9 ci-dessous :
def rendu_monnaie_centimes(s_due, s_versee):\n pieces = [1, 2, 5, 10, 20, 50, 100, 200]\n rendu = ...\n a_rendre = ...\n i = len(pieces) - 1\n while a_rendre > ... :\n if pieces[i] <= a_rendre :\n rendu.append(...)\n a_rendre = ...\n else :\n i = ...\n return rendu\n
Compl\u00e9ter ce code pour qu'il donne :
>>> rendu_monnaie_centimes(700,700)\n[]\n>>> rendu_monnaie_centimes(112,500)\n[200, 100, 50, 20, 10, 5, 2, 1]\n
def rendu_monnaie_centimes(s_due, s_versee):\n pieces = [1, 2, 5, 10, 20, 50, 100, 200]\n rendu = []\n a_rendre = s_versee - s_due\n i = len(pieces) - 1\n while a_rendre > 0 :\n if pieces[i] <= a_rendre :\n rendu.append(pieces[i])\n a_rendre = a_rendre - pieces[i]\n else :\n i = i - 1\n return rendu\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-231","title":"Exercice 23.1 \u25a1","text":"Exercice 23.1
\u00c9nonc\u00e9CorrectionL\u2019occurrence d\u2019un caract\u00e8re dans un phrase est le nombre de fois o\u00f9 ce caract\u00e8re est pr\u00e9sent.
Exemples :
On cherche les occurrences des caract\u00e8res dans une phrase. On souhaite stocker ces occurrences dans un dictionnaire dont les clefs seraient les caract\u00e8res de la phrase et les valeurs l\u2019occurrence de ces caract\u00e8res.
Par exemple : avec la phrase 'Hello world !' le dictionnaire est le suivant :
{'H': 1,'e': 1,'l': 3,'o': 2,' ': 2,'w': 1,'r': 1,'d': 1,'!': 1}
\u00c9crire une fonction occurence_lettres
prenant comme param\u00e8tre une variable phrase
de type str
. Cette fonction doit renvoyer un dictionnaire de type constitu\u00e9 des occurrences des caract\u00e8res pr\u00e9sents dans la phrase.
def occurence_lettres(phrase):\n occ = {}\n for caractere in phrase:\n if caractere in occ:\n occ[caractere] += 1\n else:\n occ[caractere] = 1\n return occ\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-232","title":"Exercice 23.2 \u25a1","text":"Exercice 23.2
\u00c9nonc\u00e9CorrectionLa fonction fusion
prend deux listes L1
, L2
d\u2019entiers tri\u00e9es par ordre croissant et les fusionne en une liste tri\u00e9e L12
qu\u2019elle renvoie.
Le code Python de la fonction est
def fusion(L1,L2):\n n1 = len(L1)\n n2 = len(L2)\n L12 = [0]*(n1+n2)\n i1 = 0\n i2 = 0\n i = 0\n while i1 < n1 and ... :\n if L1[i1] < L2[i2]:\n L12[i] = ...\n i1 = ...\n else:\n L12[i] = L2[i2]\n i2 = ...\n i += 1\n while i1 < n1:\n L12[i] = ...\n i1 = i1 + 1\n i = ...\n while i2 < n2:\n L12[i] = ...\n i2 = i2 + 1\n i = ...\n return L12\n
Compl\u00e9ter le code.
Exemple :
>>> fusion([1,6,10],[0,7,8,9])\n[0, 1, 6, 7, 8, 9, 10]\n
def fusion(L1,L2):\n n1 = len(L1)\n n2 = len(L2)\n L12 = [0]*(n1+n2)\n i1 = 0\n i2 = 0\n i = 0\n while i1 < n1 and i2 < n2 :\n if L1[i1] < L2[i2]:\n L12[i] = L1[i1]\n i1 = i1 + 1\n else:\n L12[i] = L2[i2]\n i2 = i2 + 1\n i += 1\n while i1 < n1:\n L12[i] = L1[i1]\n i1 = i1 + 1\n i = i + 1\n while i2 < n2:\n L12[i] = L2[i2]\n i2 = i2 + 1\n i = i + 1\n return L12\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-241","title":"Exercice 24.1 \u25a1","text":"identique au 18.1
Exercice 24.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction recherche
qui prend en param\u00e8tres elt
un nombre entier et tab
un tableau de nombres entiers, et qui renvoie l\u2019indice de la premi\u00e8re occurrence de elt
dans tab
si elt
est dans tab
et -1
sinon.
Exemples :
>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(50, [1, 50, 1])\n1\n>>> recherche(15, [8, 9, 10, 15])\n3\n
def recherche(tab, n):\n ind_debut = 0\n ind_fin = len(tab) - 1\n while ind_debut <= ind_fin:\n ind_milieu = (ind_debut + ind_fin) // 2\n if tab[ind_milieu] == n:\n return ind_milieu\n elif tab[ind_milieu] < n:\n ind_debut = ind_milieu + 1\n else:\n ind_fin = ind_milieu - 1\n return -1\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-242","title":"Exercice 24.2 \u25a1","text":"Exercice 24.2
\u00c9nonc\u00e9CorrectionOn d\u00e9finit une classe g\u00e9rant une adresse IPv4. On rappelle qu\u2019une adresse IPv4 est une adresse de longueur 4 octets, not\u00e9e en d\u00e9cimale \u00e0 point, en s\u00e9parant chacun des octets par un point. On consid\u00e8re un r\u00e9seau priv\u00e9 avec une plage d\u2019adresses IP de 192.168.0.0
\u00e0 192.168.0.255
.
On consid\u00e8re que les adresses IP saisies sont valides.
Les adresses IP 192.168.0.0
et 192.168.0.255
sont des adresses r\u00e9serv\u00e9es.
Le code ci-dessous impl\u00e9mente la classe AdresseIP
.
class AdresseIP:\n def __init__(self, adresse):\n self.adresse = ...\n\n def liste_octet(self):\n\"\"\"renvoie une liste de nombres entiers,\n la liste des octets de l'adresse IP\"\"\"\n return [int(i) for i in self.adresse.split(\".\")]\n\n def est_reservee(self):\n\"\"\"renvoie True si l'adresse IP est une adresse\n r\u00e9serv\u00e9e, False sinon\"\"\"\n return ... or ...\n\n def adresse_suivante(self):\n\"\"\"renvoie un objet de AdresseIP avec l'adresse\n IP qui suit l\u2019adresse self\n si elle existe et False sinon\"\"\"\n if ... < 254:\n octet_nouveau = ... + ...\n return AdresseIP('192.168.0.' + ...)\n else:\n return False\n
Compl\u00e9ter le code ci-dessus et instancier trois objets : adresse1
, adresse2
, adresse3
avec respectivement les arguments suivants : '192.168.0.1'
, '192.168.0.2'
, '192.168.0.0'
V\u00e9rifier que :
>>> adresse1.est_reservee()\nFalse\n>>> adresse3.est_reservee()\nTrue\n>>> adresse2.adresse_suivante().adresse\n'192.168.0.3'\n
class AdresseIP:\n def __init__(self, adresse):\n self.adresse = adresse\n\n def liste_octet(self):\n\"\"\"renvoie une liste de nombres entiers,\n la liste des octets de l'adresse IP\"\"\"\n return [int(i) for i in self.adresse.split(\".\")]\n\n def est_reservee(self):\n\"\"\"renvoie True si l'adresse IP est une adresse\n r\u00e9serv\u00e9e, False sinon\"\"\"\n return self.liste_octet()[3] == 0 or self.liste_octet()[3] == 255\n\n def adresse_suivante(self):\n\"\"\"renvoie un objet de AdresseIP avec l'adresse\n IP qui suit l\u2019adresse self\n si elle existe et False sinon\"\"\"\n if self.liste_octet()[3] < 254:\n octet_nouveau = self.liste_octet()[3] + 1\n return AdresseIP('192.168.0.' + str(octet_nouveau))\n else:\n return False\n\nadresse1 = AdresseIP('192.168.0.1')\nadresse2 = AdresseIP('192.168.0.2')\nadresse3 = AdresseIP('192.168.0.0')\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-251","title":"Exercice 25.1 \u25a1","text":"Exercice 25.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction recherche
qui prend en param\u00e8tre un tableau de nombres entiers tab
, et qui renvoie la liste (\u00e9ventuellement vide) des couples d'entiers cons\u00e9cutifs successifs qu'il peut y avoir dans tab
.
Exemples :
>>> recherche([1, 4, 3, 5])\n[]\n>>> recherche([1, 4, 5, 3])\n[(4, 5)]\n>>> recherche([7, 1, 2, 5, 3, 4])\n[(1, 2), (3, 4)]\n>>> recherche([5, 1, 2, 3, 8, -5, -4, 7])\n[(1, 2), (2, 3), (-5, -4)]\n
def recherche(tab):\n solution = []\n for i in range(len(tab)-1):\n if tab[i] + 1 == tab[i+1]:\n solution.append((tab[i], tab[i+1]))\n return solution\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-252","title":"Exercice 25.2 \u25a1","text":"Exercice 25.2
\u00c9nonc\u00e9CorrectionSoit une image binaire repr\u00e9sent\u00e9e dans un tableau \u00e0 2 dimensions. Les \u00e9l\u00e9ments M[i][j]
, appel\u00e9s pixels, sont \u00e9gaux soit \u00e0 0
soit \u00e0 1
.
Une composante d\u2019une image est un sous-ensemble de l\u2019image constitu\u00e9 uniquement de 1
et de 0
qui sont c\u00f4te \u00e0 c\u00f4te, soit horizontalement soit verticalement.
Par exemple, les composantes de sont
On souhaite, \u00e0 partir d\u2019un pixel \u00e9gal \u00e0 1
dans une image M
, donner la valeur val
\u00e0 tous les pixels de la composante \u00e0 laquelle appartient ce pixel.
La fonction propager
prend pour param\u00e8tre une image M
, deux entiers i
et j
et une valeur enti\u00e8re val
. Elle met \u00e0 la valeur val
tous les pixels de la composante du pixel M[i][j]
s\u2019il vaut 1
et ne fait rien s\u2019il vaut 0
.
Par exemple, propager(M,2,1,3)
donne
Compl\u00e9ter le code r\u00e9cursif de la fonction propager
donn\u00e9 ci-dessous :
def propager(M, i, j, val):\n if M[i][j]== ...:\n return None\n\n M[i][j] = val\n\n # l'\u00e9l\u00e9ment en haut fait partie de la composante\n if ((i-1) >= 0 and M[i-1][j] == ...):\n propager(M, i-1, j, val)\n\n # l'\u00e9l\u00e9ment en bas fait partie de la composante\n if ((...) < len(M) and M[i+1][j] == 1):\n propager(M, ..., j, val)\n\n # l'\u00e9l\u00e9ment \u00e0 gauche fait partie de la composante\n if ((...) >= 0 and M[i][j-1] == 1):\n propager(M, i, ..., val)\n\n # l'\u00e9l\u00e9ment \u00e0 droite fait partie de la composante\n if ((...) < len(M) and M[i][j+1] == 1):\n propager(M, i, ..., val)\n
Exemple : >>> M = [[0,0,1,0],[0,1,0,1],[1,1,1,0],[0,1,1,0]]\n>>> propager(M,2,1,3)\n>>> M\n[[0, 0, 1, 0], [0, 3, 0, 1], [3, 3, 3, 0], [0, 3, 3, 0]]\n
def propager(M, i, j, val):\n if M[i][j]== 0 :\n return None\n\n M[i][j] = val\n\n # l'\u00e9l\u00e9ment en haut fait partie de la composante\n if ((i-1) >= 0 and M[i-1][j] == 1):\n propager(M, i-1, j, val)\n\n # l'\u00e9l\u00e9ment en bas fait partie de la composante\n if ((i+1) < len(M) and M[i+1][j] == 1):\n propager(M, i+1, j, val)\n\n # l'\u00e9l\u00e9ment \u00e0 gauche fait partie de la composante\n if ((j-1) >= 0 and M[i][j-1] == 1):\n propager(M, i, j-1, val)\n\n # l'\u00e9l\u00e9ment \u00e0 droite fait partie de la composante\n if ((j+1) < len(M) and M[i][j+1] == 1):\n propager(M, i, j+1, val)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-261","title":"Exercice 26.1 \u25a1","text":"Exercice 26.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction occurrence_max
prenant en param\u00e8tres une cha\u00eene de caract\u00e8res chaine
et qui renvoie le caract\u00e8re le plus fr\u00e9quent de la cha\u00eene. La chaine ne contient que des lettres en minuscules sans accent. On pourra s\u2019aider du tableau
alphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o,','p','q','r','s','t','u','v','w','x','y','z']
et du tableau occurrence
de 26 \u00e9l\u00e9ments o\u00f9 l\u2019on mettra dans occurrence[i]
le nombre d\u2019apparitions de alphabet[i]
dans la chaine. Puis on calculera l\u2019indice k
d\u2019un maximum du tableau occurrence
et on affichera alphabet[k]
.
Exemple :
>>> ch = 'je suis en terminale et je passe le bac et je souhaite poursuivre des etudes pour devenir expert en informatique'\n>>> occurrence_max(ch)\n\u2018e\u2019\n
alphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o,','p','q','r','s','t','u','v','w','x','y','z']\n\ndef occurrence_max(chaine):\n occurence = [0] * 26\n for i in range(26):\n compteur = 0\n for caractere in chaine:\n if caractere == alphabet[i]:\n compteur += 1\n occurence[i] = compteur\n ind_max = 0\n for i in range(26):\n if occurence[i] > occurence[ind_max]:\n ind_max = i\n return alphabet[ind_max]\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-262","title":"Exercice 26.2 \u25a1","text":"Exercice 26.2
\u00c9nonc\u00e9CorrectionOn consid\u00e8re une image en 256 niveaux de gris que l\u2019on repr\u00e9sente par une grille de nombres, c\u2019est-\u00e0-dire une liste compos\u00e9e de sous-listes toutes de longueurs identiques. La largeur de l\u2019image est donc la longueur d\u2019une sous-liste et la hauteur de l\u2019image est le nombre de sous-listes.
Chaque sous-liste repr\u00e9sente une ligne de l\u2019image et chaque \u00e9l\u00e9ment des sous-listes est un entier compris entre 0 et 255, repr\u00e9sentant l\u2019intensit\u00e9 lumineuse du pixel.
Compl\u00e9ter le programme ci-dessous :
def nbLig(image):\n'''renvoie le nombre de lignes de l'image'''\n return ...\n\ndef nbCol(image):\n'''renvoie la largeur de l'image'''\n return ...\n\ndef negatif(image):\n'''renvoie le n\u00e9gatif de l'image sous la forme d'une liste de listes'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9\u00e9 une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(...):\n L[i][j] = ...\n return L\n\ndef binaire(image, seuil):\n'''renvoie une image binaris\u00e9e de l'image sous la forme\n d'une liste de listes contenant des 0 si la valeur\n du pixel est strictement inf\u00e9rieure au seuil\n et 1 sinon'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9e une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(...):\n if image[i][j] < ... :\n L[i][j] = ...\n else:\n L[i][j] = ...\n return L \n
Exemple :
>>> img = [[20, 34, 254, 145, 6], [23, 124, 287, 225, 69], [197, 174, 207, 25, 87], [255, 0, 24, 197, 189]]\n>>> nbLig(img)\n4\n>>> nbCol(img)\n5\n>>> negatif(img)\n[[235, 221, 1, 110, 249], [232, 131, -32, 30, 186], [58, 81, 48, 230, 168], [0, 255, 231, 58, 66]]\n>>> binaire(negatif(img),120)\n[[1, 1, 0, 0, 1], [1, 1, 0, 0, 1], [0, 0, 0, 1, 1], [0, 1, 1, 0, 0]]\n
def nbLig(image):\n'''renvoie le nombre de lignes de l'image'''\n return len(image)\n\ndef nbCol(image):\n'''renvoie la largeur de l'image'''\n return len(image[0])\n\ndef negatif(image):\n'''renvoie le n\u00e9gatif de l'image sous la forme d'une liste de listes'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9\u00e9 une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(nbCol(image)):\n L[i][j] = 255-image[i][j]\n return L\n\ndef binaire(image, seuil):\n'''renvoie une image binaris\u00e9e de l'image sous la forme\n d'une liste de listes contenant des 0 si la valeur\n du pixel est strictement inf\u00e9rieure au seuil\n et 1 sinon'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9e une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(nbCol(image)):\n if image[i][j] < seuil :\n L[i][j] = 0\n else:\n L[i][j] = 1\n return L \n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-271","title":"Exercice 27.1 \u25a1","text":"Exercice 27.1
\u00c9nonc\u00e9Correction\u00c9crire une fonction moyenne
prenant en param\u00e8tres une liste d\u2019entiers et qui renvoie la moyenne des valeurs de cette liste.
Exemple :
>>> moyenne([10,20,30,40,60,110])\n45.0\n
def moyenne(tab):\n somme = 0\n for val in tab:\n somme += val\n return somme / len(tab)\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-272","title":"Exercice 27.2 \u25a1","text":"Exercice 27.2
\u00c9nonc\u00e9CorrectionOn travaille sur des dessins en noir et blanc obtenu \u00e0 partir de pixels noirs et blancs : La figure \u00ab c\u0153ur \u00bb ci-dessus va servir d\u2019exemple. On la repr\u00e9sente par une grille de nombres, c\u2019est-\u00e0-dire par une liste compos\u00e9e de sous-listes de m\u00eame longueurs. Chaque sous-liste repr\u00e9sentera donc une ligne du dessin.
Dans le code ci-dessous, la fonction affiche
permet d\u2019afficher le dessin. Les pixels noirs (1 dans la grille) seront repr\u00e9sent\u00e9s par le caract\u00e8re \"*\" et les blancs (0 dans la grille) par deux espaces.
La fonction zoomListe
prend en argument une liste liste_depart
et un entier k
. Elle renvoie une liste o\u00f9 chaque \u00e9l\u00e9ment de liste_depart
est dupliqu\u00e9 k
fois.
La fonction zoomDessin
prend en argument la grille dessin
et renvoie une grille o\u00f9 toutes les lignes de dessin
sont zoom\u00e9es k
fois et r\u00e9p\u00e9t\u00e9es k
fois.
Soit le code ci-dessous :
coeur = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], \\\n [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0], \\\n [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \\\n [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0], \\\n [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n\ndef affiche(dessin):\n''' affichage d'une grille : les 1 sont repr\u00e9sent\u00e9s par \n des \" *\" , les 0 par deux espaces \" \" '''\n for ligne in dessin:\n for col in ligne:\n if col == 1:\n print(\" *\", end=\"\")\n else:\n print(\" \", end=\"\")\n print()\n\n\ndef zoomListe(liste_depart,k):\n'''renvoie une liste contenant k fois chaque \n \u00e9l\u00e9ment de liste_depart'''\n liste_zoom = ...\n for elt in ... :\n for i in range(k):\n ...\n return liste_zoom\n\ndef zoomDessin(grille,k):\n'''renvoie une grille o\u00f9 les lignes sont zoom\u00e9es k fois \n ET r\u00e9p\u00e9t\u00e9es k fois'''\n grille_zoom=[]\n for elt in grille:\n liste_zoom = ...\n for i in range(k):\n ... .append(...)\n return grille_zoom\n
R\u00e9sultats \u00e0 obtenir :
>>> affiche(coeur)\n
>>> affiche(zoomDessin(coeur,3))\n
* * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * \n * * * \n * * *\n
coeur = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], \\\n [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0], \\\n [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \\\n [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0], \\\n [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n\ndef affiche(dessin):\n for ligne in dessin:\n for col in ligne:\n if col == 1:\n print(' *',end='')\n else:\n print(' ',end='')\n print()\n\n\ndef zoomListe(liste_depart, k):\n liste_zoom = []\n for elt in liste_depart:\n for i in range(k):\n liste_zoom.append(elt)\n return liste_zoom\n\ndef zoomDessin(grille, k):\n grille_zoom = []\n for elt in grille:\n liste_zoom = zoomListe(elt, k)\n for i in range(k):\n grille_zoom.append(liste_zoom)\n return grille_zoom\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-281","title":"Exercice 28.1 \u25a1","text":"Exercice 28.1
\u00c9nonc\u00e9CorrectionDans cet exercice, un arbre binaire de caract\u00e8res est stock\u00e9 sous la forme d\u2019un dictionnaire o\u00f9 les clefs sont les caract\u00e8res des n\u0153uds de l\u2019arbre et les valeurs, pour chaque clef, la liste des caract\u00e8res des fils gauche et droit du n\u0153ud.
Par exemple, l\u2019arbre
est stock\u00e9 dans
a = {'F':['B','G'], 'B':['A','D'], 'A':['',''], 'D':['C','E'], \\\n'C':['',''], 'E':['',''], 'G':['','I'], 'I':['','H'], \\\n'H':['','']}\n
\u00c9crire une fonction r\u00e9cursive taille
prenant en param\u00e8tres un arbre binaire arbre
sous la forme d\u2019un dictionnaire et un caract\u00e8re lettre
qui est la valeur du sommet de l\u2019arbre, et qui renvoie la taille de l\u2019arbre \u00e0 savoir le nombre total de n\u0153ud. On pourra distinguer les 4 cas o\u00f9 les deux \u00ab fils \u00bb du n\u0153ud sont ''
, le fils gauche seulement est ''
, le fils droit seulement est ''
, aucun des deux fils n\u2019est ''
.
Exemple :
>>> taille(a, \u2019F\u2019)\n9\n
a = {'F':['B','G'], 'B':['A','D'], 'A':['',''], 'D':['C','E'], 'C':['',''], 'E':['',''], 'G':['','I'], 'I':['','H'], 'H':['','']}\n\ndef taille(arbre, lettre):\n fils_gauche = arbre[lettre][0]\n fils_droit = arbre[lettre][1]\n\n if fils_gauche != '' and fils_droit != '':\n return 1 + taille(arbre, fils_gauche) + taille(arbre, fils_droit)\n\n if fils_gauche != '' and fils_droit == '':\n return 1 + taille(arbre, fils_gauche)\n\n if fils_gauche == '' and fils_droit != '':\n return 1 + taille(arbre, fils_droit)\n\n else:\n return 1\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-282","title":"Exercice 28.2 \u25a1","text":"Exercice 28.2
\u00c9nonc\u00e9CorrectionOn consid\u00e8re l'algorithme de tri de tableau suivant : \u00e0 chaque \u00e9tape, on parcourt depuis le d\u00e9but du tableau tous les \u00e9l\u00e9ments non rang\u00e9s et on place en derni\u00e8re position le plus grand \u00e9l\u00e9ment.
Exemple avec le tableau : t = [41, 55, 21, 18, 12, 6, 25]
Le tableau devient t = [41, 25, 21, 18, 12, 6, 55]
Le tableau devient : t = [6, 25, 21, 18, 12, 41, 55]
Et ainsi de suite. La code de la fonction tri_iteratif
qui impl\u00e9mente cet algorithme est donn\u00e9 ci- dessous.
def tri_iteratif(tab):\n for k in range(..., 0 ,-1):\n imax = ...\n for i in range(0, ...):\n if tab[i] > ... :\n imax = i\n if tab[max] > ... :\n ..., tab[imax] = tab[imax], ...\n return tab\n
Compl\u00e9ter le code qui doit donner :
>>> tri_iteratif([41, 55, 21, 18, 12, 6, 25])\n[6, 12, 18, 21, 25, 41, 55]\n
On rappelle que l'instruction a, b = b, a
\u00e9change les contenus de a
et b
.
def tri_iteratif(tab):\n for k in range(len(tab)-1, 0, -1):\n imax = 0\n for i in range(0, k):\n if tab[i] > tab[imax] :\n imax = i\n if tab[imax] > tab[k] :\n tab[k], tab[imax] = tab[imax], tab[k] \n return tab\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-291","title":"Exercice 29.1 \u25a1","text":"Exercice 29.1
\u00c9nonc\u00e9CorrectionSoit un nombre entier sup\u00e9rieur ou \u00e9gal \u00e0 1 :
Puis on recommence ces \u00e9tapes avec le nombre entier obtenu, jusqu\u2019\u00e0 ce que l\u2019on obtienne la valeur 1.
On d\u00e9finit ainsi la suite \\((U_n)\\) par :
On admet que, quel que soit l'entier k
choisi au d\u00e9part, la suite finit toujours sur la valeur 1.
\u00c9crire une fonction calcul
prenant en param\u00e8tres un entier n
strictement positif et qui renvoie la liste des valeurs de la suite, en partant de n
et jusqu'\u00e0 atteindre 1.
Exemple :
>>> calcul(7)\n[7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-292","title":"Exercice 29.2 \u25a1","text":"Exercice 29.2
\u00c9nonc\u00e9CorrectionOn affecte \u00e0 chaque lettre de l'alphabet un code selon le tableau ci-dessous :
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26Pour un mot donn\u00e9, on d\u00e9termine d\u2019une part son code alphab\u00e9tique concat\u00e9n\u00e9, obtenu par la juxtaposition des codes de chacun de ses caract\u00e8res, et d\u2019autre part, son code additionn\u00e9, qui est la somme des codes de chacun de ses caract\u00e8res.
Par ailleurs, on dit que ce mot est \u00ab parfait \u00bb si le code additionn\u00e9 divise le code concat\u00e9n\u00e9.
Exemples :
Pour le mot \"PAUL\"
, le code concat\u00e9n\u00e9 est la cha\u00eene '1612112'
, soit l\u2019entier 1 612 112. Son code additionn\u00e9 est l\u2019entier 50 car 16 + 1 + 21 + 12 = 50. 50 ne divise pas l\u2019entier 1 612 112 ; par cons\u00e9quent, le mot \"PAUL\"
n\u2019est pas parfait.
Pour le mot \"ALAIN\"
, le code concat\u00e9n\u00e9 est la cha\u00eene '1121914'
, soit l\u2019entier 1 121 914. Le code additionn\u00e9 est l\u2019entier 37 car 1 + 12 + 1 + 9 + 14 = 37. 37 divise l\u2019entier 1 121 914 ; par cons\u00e9quent, le mot \"ALAIN\"
est parfait.
Compl\u00e9ter la fonction est_parfait
ci-dessous qui prend comme argument une cha\u00eene de caract\u00e8res mot
(en lettres majuscules) et qui renvoie le code alphab\u00e9tique concat\u00e9n\u00e9, le code additionn\u00e9 de mot
, ainsi qu\u2019un bool\u00e9en qui indique si mot
est parfait ou pas.
dico = {\"A\":1, \"B\":2, \"C\":3, \"D\":4, \"E\":5, \"F\":6, \"G\":7, \\\n\"H\":8, \"I\":9, \"J\":10, \"K\":11, \"L\":12, \"M\":13, \\\n\"N\":14, \"O\":15, \"P\":16, \"Q\":17, \"R\":18, \"S\":19, \\\n\"T\":20, \"U\":21,\"V\":22, \"W\":23, \"X\":24, \"Y\":25, \"Z\":26}\n\ndef est_parfait(mot) :\n #mot est une cha\u00eene de caract\u00e8res (en lettres majuscules)\n code_c = \"\"\n code_a = ???\n for c in mot :\n code_c = code_c + ???\n code_a = ???\n code_c = int(code_c)\n if ??? :\n mot_est_parfait = True\n else :\n mot_est_parfait = False\n return [code_a, code_c, mot_est_parfait]\n
Exemples :
>>> est_parfait(\"PAUL\")\n[50, 1612112, False]\n>>> est_parfait(\"ALAIN\")\n[37, 1121914, True]\n
dico = {\"A\":1, \"B\":2, \"C\":3, \"D\":4, \"E\":5, \"F\":6, \"G\":7, \\\n\"H\":8, \"I\":9, \"J\":10, \"K\":11, \"L\":12, \"M\":13, \\\n\"N\":14, \"O\":15, \"P\":16, \"Q\":17, \"R\":18, \"S\":19, \\\n\"T\":20, \"U\":21,\"V\":22, \"W\":23, \"X\":24, \"Y\":25, \"Z\":26}\n\ndef est_parfait(mot) :\n #mot est une cha\u00eene de caract\u00e8res (en lettres majuscules)\n code_c = \"\"\n code_a = 0\n for c in mot :\n code_c = code_c + str(dico[c])\n code_a = code_a + dico[c]\n code_c = int(code_c)\n if code_c % code_a == 0:\n mot_est_parfait = True\n else :\n mot_est_parfait = False\n return [code_a, code_c, mot_est_parfait]\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-301","title":"Exercice 30.1 \u25a1","text":"Exercice 30.1
\u00c9nonc\u00e9CorrectionProgrammer la fonction multiplication
, prenant en param\u00e8tres deux nombres entiers n1
et n2
, et qui renvoie le produit de ces deux nombres. Les seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.
Exemples :
>>> multiplication(3,5)\n15\n>>> multiplication(-4,-8)\n32\n>>> multiplication(-2,6)\n-12\n>>> multiplication(-2,0)\n0\n
def multiplication(n1, n2):\n if n1 < 0:\n return -multiplication(-n1, n2)\n if n2 < 0:\n return -multiplication(n1, -n2)\n resultat = 0\n for _ in range(n2):\n resultat += n1\n return resultat\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2021/#exercice-302","title":"Exercice 30.2 \u25a1","text":"Exercice 30.2
\u00c9nonc\u00e9CorrectionSources en MarkdownSoit T
un tableau non vide d'entiers tri\u00e9s dans l'ordre croissant et n
un entier. La fonction chercher
, donn\u00e9e \u00e0 la page suivante, doit renvoyer un indice o\u00f9 la valeur n
appara\u00eet \u00e9ventuellement dans T
, et None
sinon.
Les param\u00e8tres de la fonction sont :
T
, le tableau dans lequel s'effectue la recherche ;n
, l'entier \u00e0 chercher dans le tableau ;i
, l'indice de d\u00e9but de la partie du tableau o\u00f9 s'effectue la recherche ;j
, l'indice de fin de la partie du tableau o\u00f9 s'effectue la recherche.La fonction chercher
est une fonction r\u00e9cursive bas\u00e9e sur le principe \u00ab diviser pour r\u00e9gner \u00bb.
Le code de la fonction commence par v\u00e9rifier si 0 <= i
et j < len(T)
. Si cette condition n\u2019est pas v\u00e9rifi\u00e9e, elle affiche \"Erreur\"
puis renvoie None
.
Recopier et compl\u00e9ter le code de la fonction chercher
propos\u00e9e ci-dessous :
def chercher(T, n, i, j):\n if i < 0 or ??? :\n print(\"Erreur\")\n return None\n if i > j :\n return None\n m = (i + j) // ???\n if T[m] < ??? :\n return chercher(T, n, ??? , ???)\n elif ??? :\n return chercher(T, n, ??? , ??? )\n else :\n return ???\n
L'ex\u00e9cution du code doit donner :
>>> chercher([1,5,6,6,9,12],7,0,10)\nErreur\n>>> chercher([1,5,6,6,9,12],7,0,5)\n>>> chercher([1,5,6,6,9,12],9,0,5)\n4\n>>> chercher([1,5,6,6,9,12],6,0,5)\n2\n
def chercher(T, n, i, j):\n if i < 0 or j >= len(T) :\n print('Erreur')\n return None\n if i > j :\n return None\n m = (i + j) // 2\n if T[m] < n :\n return chercher(T, n, m + 1, j)\n elif T[m] > n :\n return chercher(T, n, i, m - 1 )\n else :\n return m\n
Soit `T` un tableau non vide d'entiers tri\u00e9s dans l'ordre croissant et `n` un entier.\nLa fonction `chercher`, donn\u00e9e \u00e0 la page suivante, doit renvoyer un indice o\u00f9 la valeur `n`\nappara\u00eet \u00e9ventuellement dans `T`, et `None` sinon. \n\nLes param\u00e8tres de la fonction sont :\n\n- `T`, le tableau dans lequel s'effectue la recherche ;\n- `n`, l'entier \u00e0 chercher dans le tableau ;\n- `i`, l'indice de d\u00e9but de la partie du tableau o\u00f9 s'effectue la recherche ;\n- `j`, l'indice de fin de la partie du tableau o\u00f9 s'effectue la recherche.\n\nLa fonction `chercher` est une fonction r\u00e9cursive bas\u00e9e sur le principe \u00ab diviser pour\nr\u00e9gner \u00bb.\n\n\nLe code de la fonction commence par v\u00e9rifier si `0 <= i` et `j < len(T)`. \nSi cette\ncondition n\u2019est pas v\u00e9rifi\u00e9e, elle affiche `\"Erreur\"` puis renvoie `None`.\n\nRecopier et compl\u00e9ter le code de la fonction `chercher` propos\u00e9e ci-dessous :\n\n```python linenums='1'\ndef chercher(T, n, i, j):\n if i < 0 or ??? :\n print(\"Erreur\")\n return None\n if i > j :\n return None\n m = (i + j) // ???\n if T[m] < ??? :\n return chercher(T, n, ??? , ???)\n elif ??? :\n return chercher(T, n, ??? , ??? )\n else :\n return ???\n```\n\nL'ex\u00e9cution du code doit donner :\n```python\n>>> chercher([1,5,6,6,9,12],7,0,10)\nErreur\n>>> chercher([1,5,6,6,9,12],7,0,5)\n>>> chercher([1,5,6,6,9,12],9,0,5)\n4\n>>> chercher([1,5,6,6,9,12],6,0,5)\n2\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/","title":"\u00c9preuve Pratique BNS 2022","text":"\u00c0 lire
Pourquoi proposer une correction ?
Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-011","title":"Exercice 01.1 \u25a1","text":"Exercice 01.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche
qui prend en param\u00e8tres caractere
, un caract\u00e8re, et mot
, une cha\u00eene de caract\u00e8res, et qui renvoie le nombre d\u2019occurrences de caractere
dans mot
, c\u2019est-\u00e0-dire le nombre de fois o\u00f9 caractere
appara\u00eet dans mot
.
Exemples :
>>> recherche('e', \"sciences\")\n2\n>>> recherche('i',\"mississippi\")\n4\n>>> recherche('a',\"mississippi\")\n0\n
def recherche(caractere, mot):\n somme = 0\n for lettre in mot:\n if lettre == caractere:\n somme += 1\n return somme\n
\u00c9crire une fonction `recherche` qui prend en param\u00e8tres `caractere`, un caract\u00e8re, et\n`mot`, une cha\u00eene de caract\u00e8res, et qui renvoie le nombre d\u2019occurrences de `caractere`\ndans `mot`, c\u2019est-\u00e0-dire le nombre de fois o\u00f9 `caractere` appara\u00eet dans `mot`.\n\nExemples :\n```python\n>>> recherche('e', \"sciences\")\n2\n>>> recherche('i',\"mississippi\")\n4\n>>> recherche('a',\"mississippi\")\n0\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-012","title":"Exercice 01.2 \u25a1","text":"Exercice 01.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn s\u2019int\u00e9resse \u00e0 un algorithme r\u00e9cursif qui permet de rendre la monnaie \u00e0 partir d\u2019une liste donn\u00e9e de valeurs de pi\u00e8ces et de billets.
Le syst\u00e8me mon\u00e9taire est donn\u00e9 sous forme d\u2019une liste pieces=[100, 50, 20, 10, 5, 2, 1]
. (on supposera qu\u2019il n\u2019y a pas de limitation quant \u00e0 leur nombre).
On cherche \u00e0 donner la liste de pi\u00e8ces \u00e0 rendre pour une somme donn\u00e9e en argument. Compl\u00e9ter le code Python ci-dessous de la fonction rendu_glouton
qui impl\u00e9mente cet algorithme et renvoie la liste des pi\u00e8ces \u00e0 rendre.
pieces = [100,50,20,10,5,2,1] # (1)\n\ndef rendu_glouton(arendre, solution=[], i=0):\n if arendre == 0:\n return ...\n p = pieces[i]\n if p <= ... :\n solution.append(...)\n return rendu_glouton(arendre - p, solution,i)\n else :\n return rendu_glouton(arendre, solution, ...)\n
Pieces
On devra obtenir :
>>> rendu_glouton(68, [], 0) \n[50, 10, 5, 2, 1]\n>>> rendu_glouton(291, [], 0) \n[100, 100, 50, 20, 20, 1]\n
pieces = [100,50,20,10,5,2,1]\n\ndef rendu_glouton(arendre, solution=[], i=0):\n if arendre == 0:\n return solution\n p = pieces[i]\n if p <= arendre :\n solution.append(p)\n return rendu_glouton(arendre - p, solution,i)\n else :\n return rendu_glouton(arendre, solution, i+1)\n
On s\u2019int\u00e9resse \u00e0 un algorithme r\u00e9cursif qui permet de rendre la monnaie \u00e0 partir d\u2019une\nliste donn\u00e9e de valeurs de pi\u00e8ces et de billets.\n\nLe syst\u00e8me mon\u00e9taire est donn\u00e9 sous\nforme d\u2019une liste `pieces=[100, 50, 20, 10, 5, 2, 1]`.\n(on supposera qu\u2019il n\u2019y a\npas de limitation quant \u00e0 leur nombre).\n\nOn cherche \u00e0 donner la liste de pi\u00e8ces \u00e0 rendre\npour une somme donn\u00e9e en argument.\nCompl\u00e9ter le code Python ci-dessous de la fonction `rendu_glouton` qui impl\u00e9mente cet\nalgorithme et renvoie la liste des pi\u00e8ces \u00e0 rendre.\n\n```python linenums='1'\npieces = [100,50,20,10,5,2,1] # (1)\n\ndef rendu_glouton(arendre, solution=[], i=0):\n if arendre == 0:\n return ...\n p = pieces[i]\n if p <= ... :\n solution.append(...)\n return rendu_glouton(arendre - p, solution,i)\n else :\n return rendu_glouton(arendre, solution, ...)\n
Pieces
On devra obtenir :
>>> rendu_glouton(68, [], 0) \n[50, 10, 5, 2, 1]\n>>> rendu_glouton(291, [], 0) \n[100, 100, 50, 20, 20, 1]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-02","title":"\u25b6 Sujet 02","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-021","title":"Exercice 02.1 \u25a1","text":"Exercice 02.1
\u00c9nonc\u00e9CorrectionSource MarkdownSoit le couple (note
,coefficient
):
note
est un nombre de type flottant (float
) compris entre 0 et 20 ;coefficient
est un nombre entier positif.Les r\u00e9sultats aux \u00e9valuations d'un \u00e9l\u00e8ve sont regroup\u00e9s dans une liste compos\u00e9e de couples (note
,coefficient
).
\u00c9crire une fonction moyenne qui renvoie la moyenne pond\u00e9r\u00e9e de cette liste donn\u00e9e en param\u00e8tre.
Par exemple, l\u2019expression moyenne([(15,2),(9,1),(12,3)])
devra renvoyer le r\u00e9sultat du calcul suivant :
\\(\\dfrac{2 \\times 15 + 1 \\times 9 + 3 \\times 12 }{2+1+3}=12,5\\)
def moyenne(tab):\n somme_notes = 0\n somme_coeffs = 0\n for devoir in tab:\n note = devoir[0]\n coeff = devoir[1]\n somme_notes += note * coeff\n somme_coeffs += coeff\n return somme_notes / somme_coeffs\n
Soit le couple (`note`,`coefficient`):\n\n- `note` est un nombre de type flottant (`float`) compris entre 0 et 20 ;\n- `coefficient` est un nombre entier positif.\n\nLes r\u00e9sultats aux \u00e9valuations d'un \u00e9l\u00e8ve sont regroup\u00e9s dans une liste compos\u00e9e de\ncouples (`note`,`coefficient`).\n\n\u00c9crire une fonction moyenne qui renvoie la moyenne pond\u00e9r\u00e9e de cette liste donn\u00e9e en\nparam\u00e8tre.\n\nPar exemple, l\u2019expression `moyenne([(15,2),(9,1),(12,3)])` devra renvoyer le\nr\u00e9sultat du calcul suivant :\n\n$\\dfrac{2 \\times 15 + 1 \\times 9 + 3 \\times 12 }{2+1+3}=12,5$\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-022","title":"Exercice 02.2 \u25a1","text":"Exercice 02.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn cherche \u00e0 d\u00e9terminer les valeurs du triangle de Pascal. Dans ce tableau de forme triangulaire, chaque ligne commence et se termine par le nombre 1. Par ailleurs, la valeur qui occupe une case situ\u00e9e \u00e0 l\u2019int\u00e9rieur du tableau s\u2019obtient en ajoutant les valeurs des deux cases situ\u00e9es juste au-dessus, comme l\u2019indique la figure suivante :
Compl\u00e9ter la fonction pascal
ci-apr\u00e8s. Elle doit renvoyer une liste correspondant au triangle de Pascal de la ligne 1
\u00e0 la ligne n
o\u00f9 n
est un nombre entier sup\u00e9rieur ou \u00e9gal \u00e0 2
(le tableau sera contenu dans la variable C
). La variable Ck
doit, quant \u00e0 elle, contenir, \u00e0 l\u2019\u00e9tape num\u00e9ro k
, la k
-i\u00e8me ligne du tableau.
def pascal(n):\n C= [[1]]\n for k in range(1,...):\n Ck = [...]\n for i in range(1,k):\n Ck.append(C[...][i-1]+C[...][...] )\n Ck.append(...)\n C.append(Ck)\n return C\n
Pour n = 4
, voici ce qu'on devra obtenir :
>>> pascal(4)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]\n
Pour n = 5
, voici ce qu'on devra obtenir : >>> pascal(5)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1]]\n
def pascal(n):\n C = [[1]]\n for k in range(1,n+1):\n Ck = [1]\n for i in range(1,k):\n Ck.append(C[k-1][i-1]+C[k-1][i] )\n Ck.append(1)\n C.append(Ck)\n return C\n
On cherche \u00e0 d\u00e9terminer les valeurs du triangle de Pascal. Dans ce tableau de forme\ntriangulaire, chaque ligne commence et se termine par le nombre 1. Par ailleurs, la valeur\nqui occupe une case situ\u00e9e \u00e0 l\u2019int\u00e9rieur du tableau s\u2019obtient en ajoutant les valeurs des\ndeux cases situ\u00e9es juste au-dessus, comme l\u2019indique la figure suivante :\n\n![image](data/img9_2t.png){: .center width=60%}\n\nCompl\u00e9ter la fonction `pascal` ci-apr\u00e8s. Elle doit renvoyer une liste correspondant au\ntriangle de Pascal de la ligne `1` \u00e0 la ligne `n` o\u00f9 `n` est un nombre entier sup\u00e9rieur ou \u00e9gal \u00e0\n`2` (le tableau sera contenu dans la variable `C`). La variable `Ck` doit, quant \u00e0 elle, contenir,\n\u00e0 l\u2019\u00e9tape num\u00e9ro `k`, la `k`-i\u00e8me ligne du tableau.\n\n```python linenums='1'\ndef pascal(n):\n C= [[1]]\n for k in range(1,...):\n Ck = [...]\n for i in range(1,k):\n Ck.append(C[...][i-1]+C[...][...] )\n Ck.append(...)\n C.append(Ck)\n return C\n
Pour n = 4
, voici ce qu'on devra obtenir :
>>> pascal(4)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]\n
Pour n = 5
, voici ce qu'on devra obtenir : >>> pascal(5)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1]]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-03","title":"\u25b6 Sujet 03","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-031","title":"Exercice 03.1 \u25a1","text":"Exercice 03.1
\u00c9nonc\u00e9CorrectionSource MarkdownLe codage par diff\u00e9rence (delta encoding en anglais) permet de compresser un tableau de donn\u00e9es en indiquant pour chaque donn\u00e9e, sa diff\u00e9rence avec la pr\u00e9c\u00e9dente (plut\u00f4t que la donn\u00e9e elle-m\u00eame). On se retrouve alors avec un tableau de donn\u00e9es assez petites n\u00e9cessitant moins de place en m\u00e9moire. Cette m\u00e9thode se r\u00e9v\u00e8le efficace lorsque les valeurs cons\u00e9cutives sont proches.
Programmer la fonction delta
qui prend en param\u00e8tre un tableau non vide de nombres entiers et qui renvoie un tableau contenant les valeurs enti\u00e8res compress\u00e9es \u00e0 l\u2019aide cette technique.
Exemples :
>>> delta([1000, 800, 802, 1000, 1003])\n[1000, -200, 2, 198, 3]\n>>> delta([42])\n[42] \n
def delta(tab):\n diff = [tab[0]]\n for i in range(1, len(tab)):\n diff.append(tab[i] - tab[i-1])\n return diff\n
Le codage par diff\u00e9rence (delta encoding en anglais) permet de compresser un tableau de\ndonn\u00e9es en indiquant pour chaque donn\u00e9e, sa diff\u00e9rence avec la pr\u00e9c\u00e9dente (plut\u00f4t que la\ndonn\u00e9e elle-m\u00eame). On se retrouve alors avec un tableau de donn\u00e9es assez petites n\u00e9cessitant\nmoins de place en m\u00e9moire. Cette m\u00e9thode se r\u00e9v\u00e8le efficace lorsque les valeurs cons\u00e9cutives\nsont proches.\n\nProgrammer la fonction `delta` qui prend en param\u00e8tre un tableau non vide de nombres entiers\net qui renvoie un tableau contenant les valeurs enti\u00e8res compress\u00e9es \u00e0 l\u2019aide cette technique.\n\nExemples :\n\n```python\n>>> delta([1000, 800, 802, 1000, 1003])\n[1000, -200, 2, 198, 3]\n>>> delta([42])\n[42] \n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-032","title":"Exercice 03.2 \u25a1","text":"Exercice 03.2
\u00c9nonc\u00e9CorrectionSources MarkdownUne expression arithm\u00e9tique ne comportant que les quatre op\u00e9rations +, \u2212,\u00d7,\u00f7 peut \u00eatre repr\u00e9sent\u00e9e sous forme d\u2019arbre binaire. Les n\u0153uds internes sont des op\u00e9rateurs et les feuilles sont des nombres. Dans un tel arbre, la disposition des n\u0153uds joue le r\u00f4le des parenth\u00e8ses que nous connaissons bien.
En parcourant en profondeur infixe l\u2019arbre binaire ci-dessus, on retrouve l\u2019expression not\u00e9e habituellement :
\\[3 \\times (8 + 7) \u2212 (2 + 1)\\]La classe Noeud
ci-apr\u00e8s permet d\u2019impl\u00e9menter une structure d\u2019arbre binaire. Compl\u00e9ter la fonction r\u00e9cursive expression_infixe
qui prend en param\u00e8tre un objet de la classe Noeud
et qui renvoie l\u2019expression arithm\u00e9tique repr\u00e9sent\u00e9e par l\u2019arbre binaire pass\u00e9 en param\u00e8tre, sous forme d\u2019une cha\u00eene de caract\u00e8res contenant des parenth\u00e8ses.
R\u00e9sultat attendu avec l\u2019arbre ci-dessus :
>>> e = Noeud(Noeud(Noeud(None, 3, None), '*', Noeud(Noeud(None, 8, None),\n'+', Noeud(None, 7, None))), '-', Noeud(Noeud(None, 2, None), '+',\nNoeud(None, 1, None)))\n\n>>> expression_infixe(e)\n'((3*(8+7))-(2+1))'\n
class Noeud:\n'''\n Classe impl\u00e9mentant un noeud d'arbre binaire disposant de 3\n attributs :\n - valeur : la valeur de l'\u00e9tiquette,\n - gauche : le sous-arbre gauche.\n - droit : le sous-arbre droit.\n '''\n def __init__(self, g, v, d):\n self.gauche = g\n self.valeur = v\n self.droit = d\n\n def est_une_feuille(self):\n'''Renvoie True si et seulement si le noeud est une feuille'''\n return self.gauche is None and self.droit is None\n\ndef expression_infixe(e):\n s = ...\n if e.gauche is not None:\n s = '(' + s + expression_infixe(...)\n s = s + ...\n if ... is not None:\n s = s + ... + ...\n return s # (1)\n
return
d'un if ...
qui a \u00e9t\u00e9 supprim\u00e9 ici. Il faudrait \u00e9crire if True:
, ce qui est inutile... class Noeud:\n'''\n Classe impl\u00e9mentant un noeud d'arbre binaire disposant de 3\n attributs :\n - valeur : la valeur de l'\u00e9tiquette,\n - gauche : le sous-arbre gauche.\n - droit : le sous-arbre droit.\n '''\n def __init__(self, g, v, d):\n self.gauche = g\n self.valeur = v\n self.droit = d\n\n def est_une_feuille(self):\n'''Renvoie True si et seulement si le noeud est une feuille'''\n return self.gauche is None and self.droit is None\n\ne = Noeud(Noeud(Noeud(None, 3, None), '*', Noeud(Noeud(None, 8, None),\n'+', Noeud(None, 7, None))), '-', Noeud(Noeud(None, 2, None), '+',\nNoeud(None, 1, None)))\n\ndef expression_infixe(e):\n s = ''\n if e.gauche is not None:\n s = '(' + s + expression_infixe(e.gauche)\n s = s + str(e.valeur)\n if e.droit is not None:\n s = s + expression_infixe(e.droit) + ')'\n return s\n
Une expression arithm\u00e9tique ne comportant que les quatre op\u00e9rations +, \u2212,\u00d7,\u00f7 peut \u00eatre\nrepr\u00e9sent\u00e9e sous forme d\u2019arbre binaire. Les n\u0153uds internes sont des op\u00e9rateurs et les feuilles\nsont des nombres. Dans un tel arbre, la disposition des n\u0153uds joue le r\u00f4le des parenth\u00e8ses que\nnous connaissons bien. \n\n![image](data/img3_2.png){: .center width=30%}\n\nEn parcourant en profondeur infixe l\u2019arbre binaire ci-dessus, on\nretrouve l\u2019expression not\u00e9e habituellement : \n\n\n$$3 \\times (8 + 7) \u2212 (2 + 1)$$\n\n\nLa classe `Noeud` ci-apr\u00e8s permet d\u2019impl\u00e9menter une structure\nd\u2019arbre binaire.\nCompl\u00e9ter la fonction r\u00e9cursive `expression_infixe` qui prend\nen param\u00e8tre un objet de la classe `Noeud` et qui renvoie\nl\u2019expression arithm\u00e9tique repr\u00e9sent\u00e9e par l\u2019arbre binaire pass\u00e9\nen param\u00e8tre, sous forme d\u2019une cha\u00eene de caract\u00e8res contenant\ndes parenth\u00e8ses. \n\nR\u00e9sultat attendu avec l\u2019arbre ci-dessus :\n\n```python\n>>> e = Noeud(Noeud(Noeud(None, 3, None), '*', Noeud(Noeud(None, 8, None),\n'+', Noeud(None, 7, None))), '-', Noeud(Noeud(None, 2, None), '+',\nNoeud(None, 1, None)))\n\n>>> expression_infixe(e)\n'((3*(8+7))-(2+1))'\n
class Noeud:\n'''\n Classe impl\u00e9mentant un noeud d'arbre binaire disposant de 3\n attributs :\n - valeur : la valeur de l'\u00e9tiquette,\n - gauche : le sous-arbre gauche.\n - droit : le sous-arbre droit.\n '''\n def __init__(self, g, v, d):\n self.gauche = g\n self.valeur = v\n self.droit = d\n\n def est_une_feuille(self):\n'''Renvoie True si et seulement si le noeud est une feuille'''\n return self.gauche is None and self.droit is None\n\ndef expression_infixe(e):\n s = ...\n if e.gauche is not None:\n s = '(' + s + expression_infixe(...)\n s = s + ...\n if ... is not None:\n s = s + ... + ...\n return s # (1)\n
return
d'un if ...
qui a \u00e9t\u00e9 supprim\u00e9 ici. Il faudrait \u00e9crire if True:
, ce qui est inutile... ``` Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-041","title":"Exercice 04.1 \u25a1","text":"Exercice 04.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche
qui prend en param\u00e8tre un tableau de nombres entiers tab
, et qui renvoie la liste (\u00e9ventuellement vide) des couples d'entiers cons\u00e9cutifs successifs qu'il peut y avoir dans tab
.
Exemples :
>>> recherche([1, 4, 3, 5])\n[]\n>>> recherche([1, 4, 5, 3])\n[(4, 5)]\n>>> recherche([7, 1, 2, 5, 3, 4])\n[(1, 2), (3, 4)]\n>>> recherche([5, 1, 2, 3, 8, -5, -4, 7])\n[(1, 2), (2, 3), (-5, -4)]\n
def recherche(tab):\n solution = []\n for i in range(len(tab)-1):\n if tab[i] + 1 == tab[i+1]:\n solution.append((tab[i], tab[i+1]))\n return solution\n
\u00c9crire une fonction `recherche` qui prend en param\u00e8tre un tableau de nombres entiers\n`tab`, et qui renvoie la liste (\u00e9ventuellement vide) des couples d'entiers cons\u00e9cutifs\nsuccessifs qu'il peut y avoir dans `tab`.\n\nExemples :\n```python\n>>> recherche([1, 4, 3, 5])\n[]\n>>> recherche([1, 4, 5, 3])\n[(4, 5)]\n>>> recherche([7, 1, 2, 5, 3, 4])\n[(1, 2), (3, 4)]\n>>> recherche([5, 1, 2, 3, 8, -5, -4, 7])\n[(1, 2), (2, 3), (-5, -4)]\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-042","title":"Exercice 04.2 \u25a1","text":"Exercice 04.2
\u00c9nonc\u00e9CorrectionSources MarkdownSoit une image binaire repr\u00e9sent\u00e9e dans un tableau \u00e0 2 dimensions. Les \u00e9l\u00e9ments M[i][j]
, appel\u00e9s pixels, sont \u00e9gaux soit \u00e0 0
soit \u00e0 1
.
Une composante d\u2019une image est un sous-ensemble de l\u2019image constitu\u00e9 uniquement de 1
et de 0
qui sont c\u00f4te \u00e0 c\u00f4te, soit horizontalement soit verticalement.
Par exemple, les composantes de sont
On souhaite, \u00e0 partir d\u2019un pixel \u00e9gal \u00e0 1
dans une image M
, donner la valeur val
\u00e0 tous les pixels de la composante \u00e0 laquelle appartient ce pixel.
La fonction propager
prend pour param\u00e8tre une image M
, deux entiers i
et j
et une valeur enti\u00e8re val
. Elle met \u00e0 la valeur val
tous les pixels de la composante du pixel M[i][j]
s\u2019il vaut 1
et ne fait rien s\u2019il vaut 0
.
Par exemple, propager(M,2,1,3)
donne
Compl\u00e9ter le code r\u00e9cursif de la fonction propager
donn\u00e9 ci-dessous :
def propager(M, i, j, val):\n if M[i][j]== ...:\n return None # (1)\n\n M[i][j] = val\n\n # l'\u00e9l\u00e9ment en haut fait partie de la composante\n if ((i-1) >= 0 and M[i-1][j] == ...):\n propager(M, i-1, j, val)\n\n # l'\u00e9l\u00e9ment en bas fait partie de la composante\n if ((...) < len(M) and M[i+1][j] == 1):\n propager(M, ..., j, val)\n\n # l'\u00e9l\u00e9ment \u00e0 gauche fait partie de la composante\n if ((...) >= 0 and M[i][j-1] == 1):\n propager(M, i, ..., val)\n\n # l'\u00e9l\u00e9ment \u00e0 droite fait partie de la composante\n if ((...) < len(M) and M[i][j+1] == 1): # (2)\n propager(M, i, ..., val)\n
return
. len(M[0])
plut\u00f4t que len(M)
. (\u00e9quivalent ici car l'image est carr\u00e9e...)Exemple :
>>> M = [[0,0,1,0],[0,1,0,1],[1,1,1,0],[0,1,1,0]]\n>>> propager(M,2,1,3)\n>>> M\n[[0, 0, 1, 0], [0, 3, 0, 1], [3, 3, 3, 0], [0, 3, 3, 0]]\n
def propager(M, i, j, val):\n if M[i][j]== 0 :\n return None\n\n M[i][j] = val\n\n # l'\u00e9l\u00e9ment en haut fait partie de la composante\n if ((i-1) >= 0 and M[i-1][j] == 1):\n propager(M, i-1, j, val)\n\n # l'\u00e9l\u00e9ment en bas fait partie de la composante\n if ((i+1) < len(M) and M[i+1][j] == 1):\n propager(M, i+1, j, val)\n\n # l'\u00e9l\u00e9ment \u00e0 gauche fait partie de la composante\n if ((j-1) >= 0 and M[i][j-1] == 1):\n propager(M, i, j-1, val)\n\n # l'\u00e9l\u00e9ment \u00e0 droite fait partie de la composante\n if ((j+1) < len(M) and M[i][j+1] == 1):\n propager(M, i, j+1, val)\n
Soit une image binaire repr\u00e9sent\u00e9e dans un tableau \u00e0 2 dimensions. Les \u00e9l\u00e9ments\n`M[i][j]`, appel\u00e9s pixels, sont \u00e9gaux soit \u00e0 `0` soit \u00e0 `1`.\n\nUne composante d\u2019une image est un sous-ensemble de l\u2019image constitu\u00e9 uniquement de\n`1` et de `0` qui sont c\u00f4te \u00e0 c\u00f4te, soit horizontalement soit verticalement.\n\nPar exemple, les composantes de\n![image](data/252a.png){: .center width=30%}\nsont\n![image](data/252b.png){: .center width=30%}\n\nOn souhaite, \u00e0 partir d\u2019un pixel \u00e9gal \u00e0 `1` dans une image `M`, donner la valeur `val` \u00e0 tous\nles pixels de la composante \u00e0 laquelle appartient ce pixel.\n\nLa fonction `propager` prend pour param\u00e8tre une image `M`, deux entiers `i` et `j` et une\nvaleur enti\u00e8re `val`. Elle met \u00e0 la valeur `val` tous les pixels de la composante du pixel\n`M[i][j]` s\u2019il vaut `1` et ne fait rien s\u2019il vaut `0`.\n\nPar exemple, `propager(M,2,1,3)` donne\n![image](data/252c.png){: .center width=30%}\n\nCompl\u00e9ter le code r\u00e9cursif de la fonction `propager` donn\u00e9 ci-dessous :\n\n```python linenums='1'\ndef propager(M, i, j, val):\n if M[i][j]== ...:\n return None # (1)\n\n M[i][j] = val\n\n # l'\u00e9l\u00e9ment en haut fait partie de la composante\n if ((i-1) >= 0 and M[i-1][j] == ...):\n propager(M, i-1, j, val)\n\n # l'\u00e9l\u00e9ment en bas fait partie de la composante\n if ((...) < len(M) and M[i+1][j] == 1):\n propager(M, ..., j, val)\n\n # l'\u00e9l\u00e9ment \u00e0 gauche fait partie de la composante\n if ((...) >= 0 and M[i][j-1] == 1):\n propager(M, i, ..., val)\n\n # l'\u00e9l\u00e9ment \u00e0 droite fait partie de la composante\n if ((...) < len(M) and M[i][j+1] == 1): # (2)\n propager(M, i, ..., val)\n
return
. len(M[0])
plut\u00f4t que len(M)
. (\u00e9quivalent ici car l'image est carr\u00e9e...)Exemple :
>>> M = [[0,0,1,0],[0,1,0,1],[1,1,1,0],[0,1,1,0]]\n>>> propager(M,2,1,3)\n>>> M\n[[0, 0, 1, 0], [0, 3, 0, 1], [3, 3, 3, 0], [0, 3, 3, 0]]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-05","title":"\u25b6 Sujet 05","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-051","title":"Exercice 05.1 \u25a1","text":"Exercice 05.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction rechercheMinMax
qui prend en param\u00e8tre un tableau de nombres non tri\u00e9s tab
, et qui renvoie la plus petite et la plus grande valeur du tableau sous la forme d\u2019un dictionnaire \u00e0 deux cl\u00e9s \u2018min\u2019 et \u2018max\u2019. Les tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.
Exemples :
>>> tableau = [0, 1, 4, 2, -2, 9, 3, 1, 7, 1]\n>>> resultat = rechercheMinMax(tableau)\n>>> resultat\n{'min': -2, 'max': 9}\n>>> tableau = []\n>>> resultat = rechercheMinMax(tableau)\n>>> resultat\n{'min': None, 'max': None}\n
def rechercheMinMax(tab):\n if tab == []:\n return {'min': None, 'max': None}\n d = {}\n d['min'] = tab[0]\n d['max'] = tab[0]\n for val in tab:\n if val < d['min']:\n d['min'] = val\n if val > d['max']:\n d['max'] = val\n return d\n
\u00c9crire une fonction `rechercheMinMax` qui prend en param\u00e8tre un tableau de nombres\nnon tri\u00e9s `tab`, et qui renvoie la plus petite et la plus grande valeur du tableau sous la\nforme d\u2019un dictionnaire \u00e0 deux cl\u00e9s \u2018min\u2019 et \u2018max\u2019. Les tableaux seront repr\u00e9sent\u00e9s sous\nforme de liste Python.\n\nExemples :\n```python\n>>> tableau = [0, 1, 4, 2, -2, 9, 3, 1, 7, 1]\n>>> resultat = rechercheMinMax(tableau)\n>>> resultat\n{'min': -2, 'max': 9}\n>>> tableau = []\n>>> resultat = rechercheMinMax(tableau)\n>>> resultat\n{'min': None, 'max': None}\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-052","title":"Exercice 05.2 \u25a1","text":"Exercice 05.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn dispose d\u2019un programme permettant de cr\u00e9er un objet de type PaquetDeCarte
, selon les \u00e9l\u00e9ments indiqu\u00e9s dans le code ci-dessous. Compl\u00e9ter ce code aux endroits indiqu\u00e9s par #A compl\u00e9ter
, puis ajouter des assertions dans l\u2019initialiseur de Carte
, ainsi que dans la m\u00e9thode getCarteAt()
.
class Carte:\n\"\"\"Initialise Couleur (entre 1 a 4), et Valeur (entre 1 a 13)\"\"\"\n def __init__(self, c, v):\n self.Couleur = c\n self.Valeur = v\n\n\"\"\"Renvoie le nom de la Carte As, 2, ... 10, \n Valet, Dame, Roi\"\"\"\n def getNom(self):\n if ( self.Valeur > 1 and self.Valeur < 11):\n return str( self.Valeur)\n elif self.Valeur == 11:\n return \"Valet\"\n elif self.Valeur == 12:\n return \"Dame\"\n elif self.Valeur == 13:\n return \"Roi\"\n else:\n return \"As\"\n\n\"\"\"Renvoie la couleur de la Carte (parmi pique, coeur, carreau, trefle\"\"\"\n def getCouleur(self):\n return ['pique', 'coeur', 'carreau', 'trefle' ][self.Couleur - 1]\n\nclass PaquetDeCarte:\n def __init__(self):\n self.contenu = []\n\n\"\"\"Remplit le paquet de cartes\"\"\"\n def remplir(self):\n ??? = [ ??? for couleur in range(1, ???) for valeur in range( 1, ???)]\n\n\"\"\"Renvoie la Carte qui se trouve a\u00a0 la position donnee\"\"\"\n def getCarteAt(self, pos):\n if 0 <= pos < ??? :\n return ???\n
Exemple : >>> unPaquet = PaquetDeCarte()\n>>> unPaquet.remplir()\n>>> uneCarte = unPaquet.getCarteAt(20)\n>>> print(uneCarte.getNom() + \" de \" + uneCarte.getCouleur())\n 8 de coeur\n
Attention, le code propos\u00e9 ne respecte pas les standards de notation :
class Carte:\n\"\"\"Initialise Couleur (entre 1 \u00e0 4), et Valeur (entre 1 \u00e0 13)\"\"\"\n def __init__(self, c, v):\n assert c in range(1, 5)\n assert v in range(1, 14)\n self.Couleur = c\n self.Valeur = v\n\n\"\"\"Renvoie le nom de la Carte As, 2, ... 10, Valet, Dame, Roi\"\"\"\n def getNom(self):\n if (self.Valeur > 1 and self.Valeur < 11):\n return str( self.Valeur)\n elif self.Valeur == 11:\n return \"Valet\"\n elif self.Valeur == 12:\n return \"Dame\"\n elif self.Valeur == 13:\n return \"Roi\"\n else:\n return \"As\"\n\n\"\"\"Renvoie la couleur de la Carte (parmi pique, coeur, carreau, trefle\"\"\"\n def getCouleur(self):\n return ['pique', 'coeur', 'carreau', 'trefle'][self.Couleur - 1]\n\nclass PaquetDeCarte:\n def __init__(self):\n self.contenu = []\n\n\"\"\"Remplit le paquet de cartes\"\"\"\n def remplir(self):\n self.contenu = [Carte(couleur, valeur) for couleur in range(1, 5) for valeur in range(1, 14)]\n\n\"\"\"Renvoie la Carte qui se trouve \u00e0 la position donn\u00e9e\"\"\"\n def getCarteAt(self, pos):\n assert pos in range(0, 52)\n if 0 <= pos < len(self.contenu) :\n return self.contenu[pos]\n
On dispose d\u2019un programme permettant de cr\u00e9er un objet de type `PaquetDeCarte`,\nselon les \u00e9l\u00e9ments indiqu\u00e9s dans le code ci-dessous.\nCompl\u00e9ter ce code aux endroits indiqu\u00e9s par `#A compl\u00e9ter`, puis ajouter des\nassertions dans l\u2019initialiseur de `Carte`, ainsi que dans la m\u00e9thode `getCarteAt()`.\n\n```python linenums='1'\nclass Carte:\n \"\"\"Initialise Couleur (entre 1 a 4), et Valeur (entre 1 a 13)\"\"\"\n def __init__(self, c, v):\n self.Couleur = c\n self.Valeur = v\n\n \"\"\"Renvoie le nom de la Carte As, 2, ... 10, \n Valet, Dame, Roi\"\"\"\n def getNom(self):\n if ( self.Valeur > 1 and self.Valeur < 11):\n return str( self.Valeur)\n elif self.Valeur == 11:\n return \"Valet\"\n elif self.Valeur == 12:\n return \"Dame\"\n elif self.Valeur == 13:\n return \"Roi\"\n else:\n return \"As\"\n\n \"\"\"Renvoie la couleur de la Carte (parmi pique, coeur, carreau, trefle\"\"\"\n def getCouleur(self):\n return ['pique', 'coeur', 'carreau', 'trefle' ][self.Couleur - 1]\n\nclass PaquetDeCarte:\n def __init__(self):\n self.contenu = []\n\n \"\"\"Remplit le paquet de cartes\"\"\"\n def remplir(self):\n ??? = [ ??? for couleur in range(1, ???) for valeur in range( 1, ???)]\n\n \"\"\"Renvoie la Carte qui se trouve a\u00a0 la position donnee\"\"\"\n def getCarteAt(self, pos):\n if 0 <= pos < ??? :\n return ???\n
Exemple : >>> unPaquet = PaquetDeCarte()\n>>> unPaquet.remplir()\n>>> uneCarte = unPaquet.getCarteAt(20)\n>>> print(uneCarte.getNom() + \" de \" + uneCarte.getCouleur())\n 8 de coeur\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-06","title":"\u25b6 Sujet 06","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-061","title":"Exercice 06.1 \u25a1","text":"Exercice 06.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction maxi
qui prend en param\u00e8tre une liste tab
de nombres entiers et renvoie un couple donnant le plus grand \u00e9l\u00e9ment de cette liste, ainsi que l\u2019indice de la premi\u00e8re apparition de ce maximum dans la liste.
Exemple :
>>> maxi([1,5,6,9,1,2,3,7,9,8])\n(9,3)\n
def maxi(tab):\n val_max = tab[0]\n pos_max = 0\n for i in range(len(tab)):\n if tab[i] > val_max:\n val_max = tab[i]\n pos_max = i\n return (val_max, pos_max)\n
\u00c9crire une fonction `maxi` qui prend en param\u00e8tre une liste `tab` de nombres entiers et renvoie un couple donnant le plus grand \u00e9l\u00e9ment de cette liste, ainsi que l\u2019indice de la premi\u00e8re apparition de ce maximum dans la liste.\n\nExemple :\n```python\n>>> maxi([1,5,6,9,1,2,3,7,9,8])\n(9,3)\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-062","title":"Exercice 06.2 \u25a1","text":"Exercice 06.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa fonction recherche
prend en param\u00e8tres deux chaines de caract\u00e8res gene
et seq_adn
et renvoie True
si on retrouve gene
dans seq_adn
et False
sinon. Compl\u00e9ter le code Python ci-dessous pour qu\u2019il impl\u00e9mente la fonction recherche
.
def recherche(gene, seq_adn):\n n = len(seq_adn)\n g = len(gene)\n i = ...\n trouve = False\n while i < ... and trouve == ... :\n j = 0\n while j < g and gene[j] == seq_adn[i+j]:\n ...\n if j == g:\n trouve = True\n ...\n return trouve\n
Exemples :
>>> recherche(\"AATC\", \"GTACAAATCTTGCC\")\nTrue\n>>> recherche(\"AGTC\", \"GTACAAATCTTGCC\")\nFalse\n
def recherche(gene, seq_adn):\n n = len(seq_adn)\n g = len(gene)\n i = 0\n trouve = False\n while i < n-g+1 and trouve == False :\n j = 0\n while j < g and gene[j] == seq_adn[i+j]:\n j += 1\n if j == g:\n trouve = True\n i += 1\n return trouve\n
La fonction `recherche` prend en param\u00e8tres deux chaines de caract\u00e8res `gene` et\n`seq_adn` et renvoie `True` si on retrouve `gene` dans `seq_adn` et `False` sinon.\nCompl\u00e9ter le code Python ci-dessous pour qu\u2019il impl\u00e9mente la fonction `recherche`.\n\n```python linenums='1'\ndef recherche(gene, seq_adn):\n n = len(seq_adn)\n g = len(gene)\n i = ...\n trouve = False\n while i < ... and trouve == ... :\n j = 0\n while j < g and gene[j] == seq_adn[i+j]:\n ...\n if j == g:\n trouve = True\n ...\n return trouve\n
Exemples :
>>> recherche(\"AATC\", \"GTACAAATCTTGCC\")\nTrue\n>>> recherche(\"AGTC\", \"GTACAAATCTTGCC\")\nFalse\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-07","title":"\u25b6 Sujet 07","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-071","title":"Exercice 07.1 \u25a1","text":"Exercice 07.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction conv_bin
qui prend en param\u00e8tre un entier positif n
et renvoie un couple (b,bit)
o\u00f9 :
b
est une liste d'entiers correspondant \u00e0 la repr\u00e9sentation binaire de n
;bit
correspond aux nombre de bits qui constituent b
.Exemple :
>>> conv_bin(9)\n([1,0,0,1],4)\n
Aide :
//
donne le quotient de la division euclidienne : 5//2
donne 2
;%
donne le reste de la division euclidienne :5%2
donne 1
;append
est une m\u00e9thode qui ajoute un \u00e9l\u00e9ment \u00e0 une liste existante : Soit T=[5,2,4]
, alors T.append(10)
ajoute 10
\u00e0 la liste T
. Ainsi, T
devient [5,2,4,10]
.reverse
est une m\u00e9thode qui renverse les \u00e9l\u00e9ments d'une liste. Soit T=[5,2,4,10]
. Apr\u00e8s T.reverse()
, la liste devient [10,4,2,5]
.On remarquera qu\u2019on r\u00e9cup\u00e8re la repr\u00e9sentation binaire d\u2019un entier n
en partant de la gauche en appliquant successivement les instructions :
b = n%2
n = n//2
r\u00e9p\u00e9t\u00e9es autant que n\u00e9cessaire.
def conv_bin(n):\n # cas particulier pour n = 0\n if n == 0:\n return ([0], 1)\n # cas g\u00e9n\u00e9ral\n b = []\n bits = 0\n while n != 0:\n b.append(n % 2)\n bits += 1\n n = n // 2\n b.reverse()\n return (b, bits)\n
\u00c9crire une fonction `conv_bin` qui prend en param\u00e8tre un entier positif `n` et renvoie un\ncouple (`b,bit)` o\u00f9 :\n\n- `b` est une liste d'entiers correspondant \u00e0 la repr\u00e9sentation binaire de `n`;\n- `bit` correspond aux nombre de bits qui constituent `b`.\n\nExemple :\n```python\n>>> conv_bin(9)\n([1,0,0,1],4)\n```\n\nAide :\n\n- l'op\u00e9rateur `//` donne le quotient de la division euclidienne : `5//2` donne `2` ;\n- l'op\u00e9rateur `%` donne le reste de la division euclidienne :` 5%2` donne `1` ;\n- `append` est une m\u00e9thode qui ajoute un \u00e9l\u00e9ment \u00e0 une liste existante :\nSoit `T=[5,2,4]`, alors `T.append(10)` ajoute `10` \u00e0 la liste `T`. Ainsi, `T` devient\n`[5,2,4,10]`.\n- `reverse` est une m\u00e9thode qui renverse les \u00e9l\u00e9ments d'une liste.\nSoit `T=[5,2,4,10]`. Apr\u00e8s `T.reverse()`, la liste devient `[10,4,2,5]`.\n\nOn remarquera qu\u2019on r\u00e9cup\u00e8re la repr\u00e9sentation binaire d\u2019un entier `n` en partant de la gauche en appliquant successivement les instructions :\n\n`b = n%2`\n\n`n = n//2`\n\nr\u00e9p\u00e9t\u00e9es autant que n\u00e9cessaire.\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-072","title":"Exercice 07.2 \u25a1","text":"Exercice 07.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa fonction tri_bulles
prend en param\u00e8tre une liste T
d\u2019entiers non tri\u00e9s et renvoie la liste tri\u00e9e par ordre croissant. Compl\u00e9ter le code Python ci-dessous qui impl\u00e9mente la fonction tri_bulles
.
def tri_bulles(T):\n n = len(T)\n for i in range(...,...,-1):\n for j in range(i):\n if T[j] > T[...]:\n ... = T[j]\n T[j] = T[...]\n T[j+1] = temp\n return T\n
def tri_bulles(T):\n n = len(T)\n for i in range(n-1,0,-1):\n for j in range(i):\n if T[j] > T[j+1]:\n temp = T[j]\n T[j] = T[j+1]\n T[j+1] = temp\n return T\n
La fonction `tri_bulles` prend en param\u00e8tre une liste `T` d\u2019entiers non tri\u00e9s et renvoie la liste tri\u00e9e par ordre croissant.\nCompl\u00e9ter le code Python ci-dessous qui impl\u00e9mente la fonction `tri_bulles`.\n\n```python linenums='1'\ndef tri_bulles(T):\n n = len(T)\n for i in range(...,...,-1):\n for j in range(i):\n if T[j] > T[...]:\n ... = T[j]\n T[j] = T[...]\n T[j+1] = temp\n return T\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-08","title":"\u25b6 Sujet 08","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-081","title":"Exercice 08.1 \u25a1","text":"Exercice 08.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche
qui prend en param\u00e8tres elt
un nombre entier et tab
un tableau de nombres entiers, et qui renvoie l\u2019indice de la premi\u00e8re occurrence de elt
dans tab
si elt
est dans tab
et -1
sinon.
Exemples :
>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(50, [1, 50, 1])\n1\n>>> recherche(15, [8, 9, 10, 15])\n3\n
def recherche(elt, tab):\n for i in range(len(tab)):\n if tab[i] == elt:\n return i \n return -1 \n
\u00c9crire une fonction `recherche` qui prend en param\u00e8tres `elt` un nombre entier et `tab`\nun tableau de nombres entiers, et qui renvoie l\u2019indice de la premi\u00e8re occurrence de `elt`\ndans `tab` si `elt` est dans `tab` et `-1` sinon.\n\nExemples :\n```python\n>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(50, [1, 50, 1])\n1\n>>> recherche(15, [8, 9, 10, 15])\n3\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-082","title":"Exercice 08.2 \u25a1","text":"Exercice 08.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re la fonction insere
ci-dessous qui prend en argument un entier a
et un tableau tab
d'entiers tri\u00e9s par ordre croissant. Cette fonction ins\u00e8re la valeur a
dans le tableau et renvoie le nouveau tableau. Les tableaux seront repr\u00e9sent\u00e9s sous la forme de listes python.
def insere(a, tab):\n l = list(tab) #l contient les m\u00eames \u00e9l\u00e9ments que tab\n l.append(a)\n i = ...\n while a < ... and i >= 0:\n l[i+1] = ...\n l[i] = a\n i = ...\n return l\n
Compl\u00e9ter la fonction insere
ci-dessus.
Exemples :
>>> insere(3,[1,2,4,5])\n[1, 2, 3, 4, 5]\n>>> insere(10,[1,2,7,12,14,25])\n[1, 2, 7, 10, 12, 14, 25]\n>>> insere(1,[2,3,4])\n[1, 2, 3, 4]\n
def insere(a, tab):\n l = list(tab) #l contient les m\u00eames \u00e9l\u00e9ments que tab\n l.append(a)\n i = len(l) - 2\n while a < l[i] and i >= 0:\n l[i+1] = l[i]\n l[i] = a\n i = i - 1\n return l\n
On consid\u00e8re la fonction `insere` ci-dessous qui prend en argument un entier `a` et un\ntableau `tab` d'entiers tri\u00e9s par ordre croissant. Cette fonction ins\u00e8re la valeur `a` dans le\ntableau et renvoie le nouveau tableau. Les tableaux seront repr\u00e9sent\u00e9s sous la forme de\nlistes python.\n\n\n```python linenums='1'\ndef insere(a, tab):\n l = list(tab) #l contient les m\u00eames \u00e9l\u00e9ments que tab\n l.append(a)\n i = ...\n while a < ... and i >= 0:\n l[i+1] = ...\n l[i] = a\n i = ...\n return l\n
Compl\u00e9ter la fonction insere
ci-dessus.
Exemples :
>>> insere(3,[1,2,4,5])\n[1, 2, 3, 4, 5]\n>>> insere(10,[1,2,7,12,14,25])\n[1, 2, 7, 10, 12, 14, 25]\n>>> insere(1,[2,3,4])\n[1, 2, 3, 4]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-09","title":"\u25b6 Sujet 09","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-091","title":"Exercice 09.1 \u25a1","text":"Exercice 09.1
\u00c9nonc\u00e9CorrectionSource MarkdownSoit un nombre entier sup\u00e9rieur ou \u00e9gal \u00e0 1 :
Puis on recommence ces \u00e9tapes avec le nombre entier obtenu, jusqu\u2019\u00e0 ce que l\u2019on obtienne la valeur 1.
On d\u00e9finit ainsi la suite \\((U_n)\\) par :
On admet que, quel que soit l'entier k
choisi au d\u00e9part, la suite finit toujours sur la valeur 1.
\u00c9crire une fonction calcul
prenant en param\u00e8tres un entier k
strictement positif et qui renvoie la liste des valeurs de la suite, en partant de k
et jusqu'\u00e0 atteindre 1.
Exemple :
>>> calcul(7)\n[7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]\n
def calcul(k):\n valeurs = []\n n = k\n valeurs.append(n)\n while n != 1:\n if n % 2 == 0:\n n = n // 2\n else:\n n = 3*n + 1\n valeurs.append(n)\n return valeurs\n
Soit un nombre entier sup\u00e9rieur ou \u00e9gal \u00e0 1 :\n\n- s'il est pair, on le divise par 2 ;\n- s\u2019il est impair, on le multiplie par 3 et on ajoute 1.\n\nPuis on recommence ces \u00e9tapes avec le nombre entier obtenu, jusqu\u2019\u00e0 ce que l\u2019on\nobtienne la valeur 1.\n\nOn d\u00e9finit ainsi la suite $(U_n)$ par :\n\n- $U_0=k$, o\u00f9 $k$ est un entier choisi initialement;\n- $U_{n+1} = \\dfrac{U_n}{2}$ si $U_n$ est pair;\n- $U_{n+1} = 3 \\times U_n + 1$ si $U_n$ est impair.\n\n**On admet que, quel que soit l'entier ```k``` choisi au d\u00e9part, la suite finit toujours sur la valeur 1.**\n\n\u00c9crire une fonction ```calcul``` prenant en param\u00e8tres un entier ```k``` strictement positif et qui renvoie la liste des valeurs de la suite, en partant de ```k``` et jusqu'\u00e0 atteindre 1.\n\nExemple :\n```python\n>>> calcul(7)\n[7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-092","title":"Exercice 09.2 \u25a1","text":"Exercice 09.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn affecte \u00e0 chaque lettre de l'alphabet un code selon le tableau ci-dessous :
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26Pour un mot donn\u00e9, on d\u00e9termine d\u2019une part son code alphab\u00e9tique concat\u00e9n\u00e9, obtenu par la juxtaposition des codes de chacun de ses caract\u00e8res, et d\u2019autre part, son code additionn\u00e9, qui est la somme des codes de chacun de ses caract\u00e8res.
Par ailleurs, on dit que ce mot est \u00ab parfait \u00bb si le code additionn\u00e9 divise le code concat\u00e9n\u00e9.
Exemples :
Pour le mot \"PAUL\"
, le code concat\u00e9n\u00e9 est la cha\u00eene '1612112'
, soit l\u2019entier 1 612 112. Son code additionn\u00e9 est l\u2019entier 50 car 16 + 1 + 21 + 12 = 50. 50 ne divise pas l\u2019entier 1 612 112 ; par cons\u00e9quent, le mot \"PAUL\"
n\u2019est pas parfait.
Pour le mot \"ALAIN\"
, le code concat\u00e9n\u00e9 est la cha\u00eene '1121914'
, soit l\u2019entier 1 121 914. Le code additionn\u00e9 est l\u2019entier 37 car 1 + 12 + 1 + 9 + 14 = 37. 37 divise l\u2019entier 1 121 914 ; par cons\u00e9quent, le mot \"ALAIN\"
est parfait.
Compl\u00e9ter la fonction est_parfait
ci-dessous qui prend comme argument une cha\u00eene de caract\u00e8res mot
(en lettres majuscules) et qui renvoie le code alphab\u00e9tique concat\u00e9n\u00e9, le code additionn\u00e9 de mot
, ainsi qu\u2019un bool\u00e9en qui indique si mot
est parfait ou pas.
dico = {\"A\":1, \"B\":2, \"C\":3, \"D\":4, \"E\":5, \"F\":6, \"G\":7, \\\n\"H\":8, \"I\":9, \"J\":10, \"K\":11, \"L\":12, \"M\":13, \\\n\"N\":14, \"O\":15, \"P\":16, \"Q\":17, \"R\":18, \"S\":19, \\\n\"T\":20, \"U\":21,\"V\":22, \"W\":23, \"X\":24, \"Y\":25, \"Z\":26}\n\ndef est_parfait(mot) :\n #mot est une cha\u00eene de caract\u00e8res (en lettres majuscules)\n code_c = \"\"\n code_a = ???\n for c in mot :\n code_c = code_c + ???\n code_a = ???\n code_c = int(code_c)\n if ??? :\n mot_est_parfait = True\n else :\n mot_est_parfait = False\n return [code_a, code_c, mot_est_parfait]\n
Exemples :
>>> est_parfait(\"PAUL\")\n[50, 1612112, False]\n>>> est_parfait(\"ALAIN\")\n[37, 1121914, True]\n
dico = {\"A\":1, \"B\":2, \"C\":3, \"D\":4, \"E\":5, \"F\":6, \"G\":7, \\\n\"H\":8, \"I\":9, \"J\":10, \"K\":11, \"L\":12, \"M\":13, \\\n\"N\":14, \"O\":15, \"P\":16, \"Q\":17, \"R\":18, \"S\":19, \\\n\"T\":20, \"U\":21,\"V\":22, \"W\":23, \"X\":24, \"Y\":25, \"Z\":26}\n\ndef est_parfait(mot) :\n #mot est une cha\u00eene de caract\u00e8res (en lettres majuscules)\n code_c = \"\"\n code_a = 0\n for c in mot :\n code_c = code_c + str(dico[c])\n code_a = code_a + dico[c]\n code_c = int(code_c)\n if code_c % code_a == 0:\n mot_est_parfait = True\n else :\n mot_est_parfait = False\n return [code_a, code_c, mot_est_parfait]\n
On affecte \u00e0 chaque lettre de l'alphabet un code selon le tableau ci-dessous :\n\n| A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z | \n|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|\n| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | \n\n\nPour un mot donn\u00e9, on d\u00e9termine d\u2019une part son *code alphab\u00e9tique concat\u00e9n\u00e9*, obtenu\npar la juxtaposition des codes de chacun de ses caract\u00e8res, et d\u2019autre part, *son code\nadditionn\u00e9*, qui est la somme des codes de chacun de ses caract\u00e8res.\n\nPar ailleurs, on dit que ce mot est \u00ab *parfait* \u00bb si le code additionn\u00e9 divise le code concat\u00e9n\u00e9.\n\nExemples :\n\n- Pour le mot `\"PAUL\"`, le code concat\u00e9n\u00e9 est la cha\u00eene `'1612112'`, soit l\u2019entier 1 612 112.\nSon code additionn\u00e9 est l\u2019entier 50 car 16 + 1 + 21 + 12 = 50.\n50 ne divise pas l\u2019entier 1 612 112 ; par cons\u00e9quent, le mot `\"PAUL\"` n\u2019est pas\nparfait.\n\n- Pour le mot `\"ALAIN\"`, le code concat\u00e9n\u00e9 est la cha\u00eene `'1121914'`, soit l\u2019entier\n1 121 914. Le code additionn\u00e9 est l\u2019entier 37 car 1 + 12 + 1 + 9 + 14 = 37.\n37 divise l\u2019entier 1 121 914 ; par cons\u00e9quent, le mot `\"ALAIN\"` est parfait.\n\n\nCompl\u00e9ter la fonction `est_parfait` ci-dessous qui prend comme argument une cha\u00eene\nde caract\u00e8res `mot` (en lettres majuscules) et qui renvoie le code alphab\u00e9tique concat\u00e9n\u00e9,\nle code additionn\u00e9 de `mot`, ainsi qu\u2019un bool\u00e9en qui indique si `mot` est parfait ou pas.\n\n```python linenums='1'\ndico = {\"A\":1, \"B\":2, \"C\":3, \"D\":4, \"E\":5, \"F\":6, \"G\":7, \\\n\"H\":8, \"I\":9, \"J\":10, \"K\":11, \"L\":12, \"M\":13, \\\n\"N\":14, \"O\":15, \"P\":16, \"Q\":17, \"R\":18, \"S\":19, \\\n\"T\":20, \"U\":21,\"V\":22, \"W\":23, \"X\":24, \"Y\":25, \"Z\":26}\n\ndef est_parfait(mot) :\n #mot est une cha\u00eene de caract\u00e8res (en lettres majuscules)\n code_c = \"\"\n code_a = ???\n for c in mot :\n code_c = code_c + ???\n code_a = ???\n code_c = int(code_c)\n if ??? :\n mot_est_parfait = True\n else :\n mot_est_parfait = False\n return [code_a, code_c, mot_est_parfait]\n
Exemples :
>>> est_parfait(\"PAUL\")\n[50, 1612112, False]\n>>> est_parfait(\"ALAIN\")\n[37, 1121914, True]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-10","title":"\u25b6 Sujet 10","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-101","title":"Exercice 10.1 \u25a1","text":"Exercice 10.1
\u00c9nonc\u00e9CorrectionSource MarkdownL\u2019occurrence d\u2019un caract\u00e8re dans un phrase est le nombre de fois o\u00f9 ce caract\u00e8re est pr\u00e9sent.
Exemples :
On cherche les occurrences des caract\u00e8res dans une phrase. On souhaite stocker ces occurrences dans un dictionnaire dont les clefs seraient les caract\u00e8res de la phrase et les valeurs l\u2019occurrence de ces caract\u00e8res.
Par exemple : avec la phrase 'Hello world !' le dictionnaire est le suivant :
{'H': 1,'e': 1,'l': 3,'o': 2,' ': 2,'w': 1,'r': 1,'d': 1,'!': 1}
\u00c9crire une fonction occurrence_lettres
prenant comme param\u00e8tre une variable phrase
de type str
. Cette fonction doit renvoyer un dictionnaire de type constitu\u00e9 des occurrences des caract\u00e8res pr\u00e9sents dans la phrase.
def occurrence_lettres(phrase):\n occ = {}\n for caractere in phrase:\n if caractere in occ:\n occ[caractere] += 1\n else:\n occ[caractere] = 1\n return occ\n
L\u2019occurrence d\u2019un caract\u00e8re dans un phrase est le nombre de fois o\u00f9 ce caract\u00e8re est\npr\u00e9sent.\n\nExemples :\n\n- l\u2019occurrence du caract\u00e8re \u2018o\u2019 dans \u2018bonjour\u2019 est 2 ;\n- l\u2019occurrence du caract\u00e8re \u2018b\u2019 dans \u2018B\u00e9b\u00e9\u2019 est 1 ;\n- l\u2019occurrence du caract\u00e8re \u2018B\u2019 dans \u2018B\u00e9b\u00e9\u2019 est 1 ;\n- l\u2019occurrence du caract\u00e8re \u2018 \u2018 dans \u2018Hello world !\u2019 est 2.\n\nOn cherche les occurrences des caract\u00e8res dans une phrase. On souhaite stocker ces\noccurrences dans un dictionnaire dont les clefs seraient les caract\u00e8res de la phrase et\nles valeurs l\u2019occurrence de ces caract\u00e8res.\n\nPar exemple : avec la phrase 'Hello world !' le dictionnaire est le suivant :\n\n`{'H': 1,'e': 1,'l': 3,'o': 2,' ': 2,'w': 1,'r': 1,'d': 1,'!': 1}`\n\n\u00c9crire une fonction `occurrence_lettres` prenant comme param\u00e8tre une variable\n`phrase` de type `str`. Cette fonction doit renvoyer un dictionnaire de type constitu\u00e9 des\noccurrences des caract\u00e8res pr\u00e9sents dans la phrase.\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-102","title":"Exercice 10.2 \u25a1","text":"Exercice 10.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa fonction fusion
prend deux listes L1
, L2
d\u2019entiers tri\u00e9es par ordre croissant et les fusionne en une liste tri\u00e9e L12
qu\u2019elle renvoie.
Le code Python de la fonction est
def fusion(L1,L2):\n n1 = len(L1)\n n2 = len(L2)\n L12 = [0]*(n1+n2)\n i1 = 0\n i2 = 0\n i = 0\n while i1 < n1 and ... :\n if L1[i1] < L2[i2]:\n L12[i] = ...\n i1 = ...\n else:\n L12[i] = L2[i2]\n i2 = ...\n i += 1\n while i1 < n1:\n L12[i] = ...\n i1 = i1 + 1\n i = ...\n while i2 < n2:\n L12[i] = ...\n i2 = i2 + 1\n i = ...\n return L12\n
Compl\u00e9ter le code.
Exemple :
>>> fusion([1,6,10],[0,7,8,9])\n[0, 1, 6, 7, 8, 9, 10]\n
def fusion(L1,L2):\n n1 = len(L1)\n n2 = len(L2)\n L12 = [0]*(n1+n2)\n i1 = 0\n i2 = 0\n i = 0\n while i1 < n1 and i2 < n2 :\n if L1[i1] < L2[i2]:\n L12[i] = L1[i1]\n i1 = i1 + 1\n else:\n L12[i] = L2[i2]\n i2 = i2 + 1\n i += 1\n while i1 < n1:\n L12[i] = L1[i1]\n i1 = i1 + 1\n i = i + 1\n while i2 < n2:\n L12[i] = L2[i2]\n i2 = i2 + 1\n i = i + 1\n return L12\n
La fonction `fusion` prend deux listes `L1`, `L2` d\u2019entiers tri\u00e9es par ordre croissant et les\nfusionne en une liste tri\u00e9e `L12` qu\u2019elle renvoie.\n\nLe code Python de la fonction est\n\n```python linenums='1'\ndef fusion(L1,L2):\n n1 = len(L1)\n n2 = len(L2)\n L12 = [0]*(n1+n2)\n i1 = 0\n i2 = 0\n i = 0\n while i1 < n1 and ... :\n if L1[i1] < L2[i2]:\n L12[i] = ...\n i1 = ...\n else:\n L12[i] = L2[i2]\n i2 = ...\n i += 1\n while i1 < n1:\n L12[i] = ...\n i1 = i1 + 1\n i = ...\n while i2 < n2:\n L12[i] = ...\n i2 = i2 + 1\n i = ...\n return L12\n
Compl\u00e9ter le code.
Exemple :
>>> fusion([1,6,10],[0,7,8,9])\n[0, 1, 6, 7, 8, 9, 10]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-11","title":"\u25b6 Sujet 11","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-111","title":"Exercice 11.1 \u25a1","text":"Exercice 11.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche
qui prend en param\u00e8tres un tableau tab
de nombres entiers tri\u00e9s par ordre croissant et un nombre entier n
, et qui effectue une recherche dichotomique du nombre entier n
dans le tableau non vide tab
. Cette fonction doit renvoyer un indice correspondant au nombre cherch\u00e9 s\u2019il est dans le tableau, -1
sinon.
Exemples :
>>> recherche([2, 3, 4, 5, 6], 5)\n3\n>>> recherche([2, 3, 4, 6, 7], 5)\n-1\n
def recherche(tab, n):\n ind_debut = 0\n ind_fin = len(tab) - 1\n while ind_debut <= ind_fin:\n ind_milieu = (ind_debut + ind_fin) // 2\n if tab[ind_milieu] == n:\n return ind_milieu\n elif tab[ind_milieu] < n:\n ind_debut = ind_milieu + 1\n else:\n ind_fin = ind_milieu - 1\n return -1\n
\u00c9crire une fonction `recherche` qui prend en param\u00e8tres un tableau `tab` de nombres\nentiers tri\u00e9s par ordre croissant et un nombre entier `n`, et qui effectue une recherche\ndichotomique du nombre entier `n` dans le tableau non vide `tab`.\nCette fonction doit renvoyer un indice correspondant au nombre cherch\u00e9 s\u2019il est dans le\ntableau, `-1` sinon.\n\nExemples :\n```python\n>>> recherche([2, 3, 4, 5, 6], 5)\n3\n>>> recherche([2, 3, 4, 6, 7], 5)\n-1\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-112","title":"Exercice 11.2 \u25a1","text":"Exercice 11.2
\u00c9nonc\u00e9CorrectionSources MarkdownLe codage de C\u00e9sar transforme un message en changeant chaque lettre en la d\u00e9calant dans l\u2019alphabet. Par exemple, avec un d\u00e9calage de 3, le A se transforme en D, le B en E, ..., le X en A, le Y en B et le Z en C. Les autres caract\u00e8res (\u2018!\u2019,\u2019 ?\u2019\u2026) ne sont pas cod\u00e9s.
La fonction position_alphabet
ci-dessous prend en param\u00e8tre un caract\u00e8re lettre
et renvoie la position de lettre
dans la cha\u00eene de caract\u00e8res ALPHABET
s\u2019il s\u2019y trouve et -1
sinon. La fonction cesar
prend en param\u00e8tre une cha\u00eene de caract\u00e8res message
et un nombre entier decalage
et renvoie le nouveau message cod\u00e9 avec le codage de C\u00e9sar utilisant le d\u00e9calage decalage
.
ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\ndef position_alphabet(lettre):\n return ALPHABET.find(lettre)\n\ndef cesar(message, decalage):\n resultat = ''\n for ... in message:\n if lettre in ALPHABET:\n indice = ( ... ) % 26\n resultat = resultat + ALPHABET[indice]\n else:\n resultat = ...\n return resultat\n
Compl\u00e9ter la fonction cesar
.
Exemples :
>>> cesar('BONJOUR A TOUS. VIVE LA MATIERE NSI !',4)\n'FSRNSYV E XSYW. ZMZI PE QEXMIVI RWM !'\n>>> cesar('GTSOTZW F YTZX. ANAJ QF RFYNJWJ SXN !',-5)\n'BONJOUR A TOUS. VIVE LA MATIERE NSI !'\n
ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\ndef position_alphabet(lettre):\n return ALPHABET.find(lettre)\n\ndef cesar(message, decalage):\n resultat = ''\n for lettre in message:\n if lettre in ALPHABET:\n indice = (position_alphabet(lettre) + decalage) % 26\n resultat = resultat + ALPHABET[indice]\n else:\n resultat = resultat + lettre\n return resultat\n
Le codage de C\u00e9sar transforme un message en changeant chaque lettre en la d\u00e9calant\ndans l\u2019alphabet.\nPar exemple, avec un d\u00e9calage de 3, le A se transforme en D, le B en E, ..., le X en A,\nle Y en B et le Z en C. Les autres caract\u00e8res (\u2018!\u2019,\u2019 ?\u2019\u2026) ne sont pas cod\u00e9s.\n\nLa fonction `position_alphabet` ci-dessous prend en param\u00e8tre un caract\u00e8re `lettre`\net renvoie la position de `lettre` dans la cha\u00eene de caract\u00e8res `ALPHABET` s\u2019il s\u2019y trouve\net `-1` sinon.\nLa fonction `cesar` prend en param\u00e8tre une cha\u00eene de caract\u00e8res `message` et un nombre\nentier `decalage` et renvoie le nouveau message cod\u00e9 avec le codage de C\u00e9sar utilisant\nle d\u00e9calage `decalage`.\n\n```python linenums='1'\nALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\ndef position_alphabet(lettre):\n return ALPHABET.find(lettre)\n\ndef cesar(message, decalage):\n resultat = ''\n for ... in message:\n if lettre in ALPHABET:\n indice = ( ... ) % 26\n resultat = resultat + ALPHABET[indice]\n else:\n resultat = ...\n return resultat\n
Compl\u00e9ter la fonction cesar
.
Exemples :
>>> cesar('BONJOUR A TOUS. VIVE LA MATIERE NSI !',4)\n'FSRNSYV E XSYW. ZMZI PE QEXMIVI RWM !'\n>>> cesar('GTSOTZW F YTZX. ANAJ QF RFYNJWJ SXN !',-5)\n'BONJOUR A TOUS. VIVE LA MATIERE NSI !'\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-12","title":"\u25b6 Sujet 12","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-121","title":"Exercice 12.1 \u25a1","text":"Exercice 12.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction moyenne
prenant en param\u00e8tre un tableau d'entiers tab
(type list
) qui renvoie la moyenne de ses \u00e9l\u00e9ments si le tableau est non vide et affiche 'erreur' si le tableau est vide.
Exemples :
>>> moyenne([5,3,8])\n5.333333333333333\n>>> moyenne([1,2,3,4,5,6,7,8,9,10])\n5.5\n>>> moyenne([])\n'erreur'\n
L'\u00e9nonc\u00e9 n'est pas tr\u00e8s clair quand il dit \u00abd'afficher 'erreur'\u00bb (ce qui suppose un print
et non un return
). Nous choississons donc dans ce cas de renvoyer None
.
def moyenne(tab):\n if tab == []:\n print('erreur')\n return None\n else:\n somme = 0\n for elt in tab:\n somme += elt\n return somme / len(tab)\n
Programmer la fonction ```moyenne``` prenant en param\u00e8tre un tableau d'entiers ```tab``` (type\n`list`) qui renvoie la moyenne de ses \u00e9l\u00e9ments si le tableau est non vide et affiche\n'erreur' si le tableau est vide.\n\nExemples :\n```python\n>>> moyenne([5,3,8])\n5.333333333333333\n>>> moyenne([1,2,3,4,5,6,7,8,9,10])\n5.5\n>>> moyenne([])\n'erreur'\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-122","title":"Exercice 12.2 \u25a1","text":"Exercice 12.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re un tableau d'entiers tab
(type list
dont les \u00e9l\u00e9ments sont des 0
ou des 1
). On se propose de trier ce tableau selon l'algorithme suivant : \u00e0 chaque \u00e9tape du tri,le tableau est constitu\u00e9 de trois zones cons\u00e9cutives, la premi\u00e8re ne contenant que des 0
, la seconde n'\u00e9tant pas tri\u00e9e et la derni\u00e8re ne contenant que des 1
.
Zone de 0Zone non tri\u00e9eZone de 1
Tant que la zone non tri\u00e9e n'est pas r\u00e9duite \u00e0 un seul \u00e9l\u00e9ment, on regarde son premier \u00e9l\u00e9ment :
Dans tous les cas, la longueur de la zone non tri\u00e9e diminue de 1.
Recopier sous Python en la compl\u00e9tant la fonction tri
suivante :
def tri(tab):\n #i est le premier indice de la zone non triee, j le dernier indice.\n #Au debut, la zone non triee est le tableau entier.\n i = ...\n j = ...\n while i != j :\n if tab[i]== 0:\n i = ...\n else :\n valeur = tab[j]\n tab[j] = ...\n ...\n j = ...\n ...\n
Exemple :
>>> tri([0,1,0,1,0,1,0,1,0])\n[0, 0, 0, 0, 0, 1, 1, 1, 1] \n
def tri(tab):\n #i est le premier indice de la zone non triee, j le dernier indice.\n #Au debut, la zone non triee est le tableau entier.\n i = 0\n j = len(tab) - 1\n while i != j :\n if tab[i]== 0:\n i = i + 1\n else :\n valeur = tab[j]\n tab[j] = tab[i]\n tab[i] = valeur\n j = j - 1\n return tab\n
On consid\u00e8re un tableau d'entiers `tab` (type `list` dont les \u00e9l\u00e9ments sont des `0` ou des `1`). On se propose de trier ce tableau selon l'algorithme suivant : \u00e0 chaque \u00e9tape du tri,le tableau est constitu\u00e9 de trois zones cons\u00e9cutives, la premi\u00e8re ne contenant que des `0`,\nla seconde n'\u00e9tant pas tri\u00e9e et la derni\u00e8re ne contenant que des `1`.\n\n<table>\n<tr>\n<td>Zone de 0</td><td>Zone non tri\u00e9e</td><td>Zone de 1</td>\n</tr>\n</table>\n\nTant que la zone non tri\u00e9e n'est pas r\u00e9duite \u00e0 un seul \u00e9l\u00e9ment, on regarde son premier\n\u00e9l\u00e9ment :\n\n- si cet \u00e9l\u00e9ment vaut 0, on consid\u00e8re qu'il appartient d\u00e9sormais \u00e0 la zone ne contenant\nque des 0 ;\n- si cet \u00e9l\u00e9ment vaut 1, il est \u00e9chang\u00e9 avec le dernier \u00e9l\u00e9ment de la zone non tri\u00e9e et on\nconsid\u00e8re alors qu\u2019il appartient \u00e0 la zone ne contenant que des 1.\n\nDans tous les cas, la longueur de la zone non tri\u00e9e diminue de 1.\n\nRecopier sous Python en la compl\u00e9tant la fonction `tri` suivante :\n\n```python linenums='1'\ndef tri(tab):\n #i est le premier indice de la zone non triee, j le dernier indice.\n #Au debut, la zone non triee est le tableau entier.\n i = ...\n j = ...\n while i != j :\n if tab[i]== 0:\n i = ...\n else :\n valeur = tab[j]\n tab[j] = ...\n ...\n j = ...\n ...\n
Exemple :
>>> tri([0,1,0,1,0,1,0,1,0])\n[0, 0, 0, 0, 0, 1, 1, 1, 1] \n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-13","title":"\u25b6 Sujet 13","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-131","title":"Exercice 13.1 \u25a1","text":"Exercice 13.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn s\u2019int\u00e9resse au probl\u00e8me du rendu de monnaie. On suppose qu\u2019on dispose d\u2019un nombre infini de billets de 5 euros, de pi\u00e8ces de 2 euros et de pi\u00e8ces de 1 euro. Le but est d\u2019\u00e9crire une fonction nomm\u00e9e rendu
dont le param\u00e8tre est un entier positif non nul somme_a_rendre
et qui retourne une liste de trois entiers n1
, n2
et n3
qui correspondent aux nombres de billets de 5 euros (n1
) de pi\u00e8ces de 2 euros (n2
) et de pi\u00e8ces de 1 euro (n3
) \u00e0 rendre afin que le total rendu soit \u00e9gal \u00e0 somme_a_rendre
.
On utilisera un algorithme glouton : on commencera par rendre le nombre maximal de billets de 5 euros, puis celui des pi\u00e8ces de 2 euros et enfin celui des pi\u00e8ces de 1 euros.
Exemples :
>>> rendu(13)\n[2,1,1]\n>>> rendu(64)\n[12,2,0]\n>>> rendu(89)\n[17,2,0]\n
def rendu(somme_a_rendre):\n pieces = [5, 2, 1]\n retour = [0, 0, 0]\n reste_a_rendre = somme_a_rendre\n for i in range(3):\n retour[i] = reste_a_rendre // pieces[i]\n reste_a_rendre = reste_a_rendre % pieces[i]\n return retour\n
On s\u2019int\u00e9resse au probl\u00e8me du rendu de monnaie. On suppose qu\u2019on dispose d\u2019un\nnombre infini de billets de 5 euros, de pi\u00e8ces de 2 euros et de pi\u00e8ces de 1 euro.\nLe but est d\u2019\u00e9crire une fonction nomm\u00e9e `rendu` dont le param\u00e8tre est un entier positif non\nnul `somme_a_rendre` et qui retourne une liste de trois entiers `n1`, `n2` et `n3` qui\ncorrespondent aux nombres de billets de 5 euros (`n1`) de pi\u00e8ces de 2 euros (`n2`) et de\npi\u00e8ces de 1 euro (`n3`) \u00e0 rendre afin que le total rendu soit \u00e9gal \u00e0 `somme_a_rendre`.\n\nOn utilisera un algorithme glouton : on commencera par rendre le nombre maximal de\nbillets de 5 euros, puis celui des pi\u00e8ces de 2 euros et enfin celui des pi\u00e8ces de 1 euros.\n\nExemples :\n```python\n>>> rendu(13)\n[2,1,1]\n>>> rendu(64)\n[12,2,0]\n>>> rendu(89)\n[17,2,0]\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-132","title":"Exercice 13.2 \u25a1","text":"Exercice 13.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn veut \u00e9crire une classe pour g\u00e9rer une file \u00e0 l\u2019aide d\u2019une liste cha\u00een\u00e9e. On dispose d\u2019une classe Maillon
permettant la cr\u00e9ation d\u2019un maillon de la cha\u00eene, celui-ci \u00e9tant constitu\u00e9 d\u2019une valeur et d\u2019une r\u00e9f\u00e9rence au maillon suivant de la cha\u00eene :
class Maillon :\n def __init__(self,v) :\n self.valeur = v\n self.suivant = None\n
Compl\u00e9ter la classe File suivante
o\u00f9 l\u2019attribut dernier_file
contient le maillon correspondant \u00e0 l\u2019\u00e9l\u00e9ment arriv\u00e9 en dernier dans la file : class File :\n def __init__(self) :\n self.dernier_file = None\n\n def enfile(self,element) :\n nouveau_maillon = Maillon(...)\n nouveau_maillon.suivant = self.dernier_file\n self.dernier_file = ...\n\n def est_vide(self) :\n return self.dernier_file == None\n\n def affiche(self) :\n maillon = self.dernier_file\n while maillon != ... :\n print(maillon.valeur)\n maillon = ...\n\n def defile(self) :\n if not self.est_vide() :\n if self.dernier_file.suivant == None :\n resultat = self.dernier_file.valeur\n self.dernier_file = None\n return resultat\n maillon = ...\n while maillon.suivant.suivant != None :\n maillon = maillon.suivant\n resultat = ...\n maillon.suivant = None\n return resultat\n return None\n
On pourra tester le fonctionnement de la classe en utilisant les commandes suivantes dans la console Python : >>> F = File()\n>>> F.est_vide()\nTrue\n>>> F.enfile(2)\n>>> F.affiche()\n2\n>>> F.est_vide()\nFalse\n>>> F.enfile(5)\n>>> F.enfile(7)\n>>> F.affiche()\n7\n5\n2\n>>> F.defile()\n2\n>>> F.defile()\n5\n>>> F.affiche()\n7\n
class Maillon :\n def __init__(self,v) :\n self.valeur = v\n self.suivant = None\n\nclass File :\n def __init__(self) :\n self.dernier_file = None\n\n def enfile(self,element) :\n nouveau_maillon = Maillon(element)\n nouveau_maillon.suivant = self.dernier_file\n self.dernier_file = nouveau_maillon\n\n def est_vide(self) :\n return self.dernier_file == None\n\n def affiche(self) :\n maillon = self.dernier_file\n while maillon != None :\n print(maillon.valeur)\n maillon = maillon.suivant\n\n def defile(self) :\n if not self.est_vide() :\n if self.dernier_file.suivant == None :\n resultat = self.dernier_file.valeur\n self.dernier_file = None\n return resultat\n maillon = self.dernier_file\n while maillon.suivant.suivant != None :\n maillon = maillon.suivant\n resultat = maillon.suivant.valeur\n maillon.suivant = None\n return resultat\n return None\n
On veut \u00e9crire une classe pour g\u00e9rer une file \u00e0 l\u2019aide d\u2019une liste cha\u00een\u00e9e. On dispose d\u2019une\nclasse ```Maillon``` permettant la cr\u00e9ation d\u2019un maillon de la cha\u00eene, celui-ci \u00e9tant constitu\u00e9\nd\u2019une valeur et d\u2019une r\u00e9f\u00e9rence au maillon suivant de la cha\u00eene :\n\n```python linenums='1'\nclass Maillon :\n def __init__(self,v) :\n self.valeur = v\n self.suivant = None\n
Compl\u00e9ter la classe File suivante
o\u00f9 l\u2019attribut dernier_file
contient le maillon correspondant \u00e0 l\u2019\u00e9l\u00e9ment arriv\u00e9 en dernier dans la file : class File :\n def __init__(self) :\n self.dernier_file = None\n\n def enfile(self,element) :\n nouveau_maillon = Maillon(...)\n nouveau_maillon.suivant = self.dernier_file\n self.dernier_file = ...\n\n def est_vide(self) :\n return self.dernier_file == None\n\n def affiche(self) :\n maillon = self.dernier_file\n while maillon != ... :\n print(maillon.valeur)\n maillon = ...\n\n def defile(self) :\n if not self.est_vide() :\n if self.dernier_file.suivant == None :\n resultat = self.dernier_file.valeur\n self.dernier_file = None\n return resultat\n maillon = ...\n while maillon.suivant.suivant != None :\n maillon = maillon.suivant\n resultat = ...\n maillon.suivant = None\n return resultat\n return None\n
On pourra tester le fonctionnement de la classe en utilisant les commandes suivantes dans la console Python : >>> F = File()\n>>> F.est_vide()\nTrue\n>>> F.enfile(2)\n>>> F.affiche()\n2\n>>> F.est_vide()\nFalse\n>>> F.enfile(5)\n>>> F.enfile(7)\n>>> F.affiche()\n7\n5\n2\n>>> F.defile()\n2\n>>> F.defile()\n5\n>>> F.affiche()\n7\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-14","title":"\u25b6 Sujet 14","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-141","title":"Exercice 14.1 \u25a1","text":"Exercice 14.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn consid\u00e8re des mots \u00e0 trous : ce sont des cha\u00eenes de caract\u00e8res contenant uniquement des majuscules et des caract\u00e8res *
. Par exemple INFO*MA*IQUE
, ***I***E**
et *S*
sont des mots \u00e0 trous. Programmer une fonction correspond qui :
mot
et mot_a_trous
o\u00f9 mot_a_trous
est un mot \u00e0 trous comme indiqu\u00e9 ci-dessus, True
si on peut obtenir mot
en rempla\u00e7ant convenablement les caract\u00e8res '*'
de mot_a_trous
.False
sinon.Exemple :
>>> correspond('INFORMATIQUE', 'INFO*MA*IQUE')\nTrue\n>>> correspond('AUTOMATIQUE', 'INFO*MA*IQUE')\nFalse\n
def correspond(mot, mot_a_trous):\n if len(mot) != len(mot_a_trous):\n return False\n for i in range(len(mot)):\n if mot[i] != mot_a_trous[i] and mot_a_trous[i] != '*':\n return False\n return True\n
On consid\u00e8re des mots \u00e0 trous : ce sont des cha\u00eenes de caract\u00e8res contenant uniquement\ndes majuscules et des caract\u00e8res `*`. Par exemple `INFO*MA*IQUE`, `***I***E**` et\n`*S*` sont des mots \u00e0 trous. \nProgrammer une fonction correspond qui :\n\n- prend en param\u00e8tres deux cha\u00eenes de caract\u00e8res `mot` et `mot_a_trous` o\u00f9\n`mot_a_trous` est un mot \u00e0 trous comme indiqu\u00e9 ci-dessus, \n- renvoie :\n - `True` si on peut obtenir `mot` en rempla\u00e7ant convenablement les caract\u00e8res\n`'*'` de `mot_a_trous`.\n - `False` sinon.\n\nExemple :\n\n```python\n>>> correspond('INFORMATIQUE', 'INFO*MA*IQUE')\nTrue\n>>> correspond('AUTOMATIQUE', 'INFO*MA*IQUE')\nFalse\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-142","title":"Exercice 14.2 \u25a1","text":"Exercice 14.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re au plus 26 personnes A, B, C, D, E, F ... qui peuvent s'envoyer des messages avec deux r\u00e8gles \u00e0 respecter :
Voici un exemple - avec 6 personnes - de \u00ab plan d'envoi des messages \u00bb qui respecte les r\u00e8gles ci-dessus, puisque chaque personne est pr\u00e9sente une seule fois dans chaque colonne :
Et le dictionnaire correspondant \u00e0 ce plan d'envoi est le suivant :
plan_a = {'A':'E', 'B':'F', 'C':'D', 'D':'C', 'E':'B', 'F':'A'}
Sur le plan d'envoi plan_a des messages ci-dessus, il y a deux cycles distincts : un premier cycle avec A, E, B, F et un second cycle avec C et D.
En revanche, le plan d\u2019envoi plan_b ci-dessous :
plan_b = {'A':'C', 'B':'F', 'C':'E', 'D':'A', 'E':'B', 'F':'D'}
comporte un unique cycle : A, C, E, B, F, D. Dans ce cas, lorsqu\u2019un plan d\u2019envoi comporte un unique cycle, on dit que le plan d\u2019envoi est cyclique.
Pour savoir si un plan d'envoi de messages comportant N personnes est cyclique, on peut utiliser l'algorithme ci-dessous :
On part de la personne A et on inspecte les N \u2013 1 successeurs dans le plan d'envoi :
Si un de ces N \u2013 1 successeurs est A lui-m\u00eame, on a trouv\u00e9 un cycle de taille inf\u00e9rieure ou \u00e9gale \u00e0 N \u2013 1. Il y a donc au moins deux cycles et le plan d'envoi n'est pas cyclique.
Si on ne retombe pas sur A lors de cette inspection, on a un unique cycle qui passe par toutes les personnes : le plan d'envoi est cyclique.
Compl\u00e9ter la fonction suivante en respectant la sp\u00e9cification.
Remarque : la fonction python len
permet d'obtenir la longueur d'un dictionnaire.
def est_cyclique(plan):\n'''\n Prend en param\u00e8tre un dictionnaire plan correspondant\n \u00e0 un plan d'envoi de messages entre N personnes A, B, C,\n D, E, F ...(avec N <= 26).\n Renvoie True si le plan d'envoi de messages est cyclique\n et False sinon.\n '''\n personne = 'A'\n N = len(...)\n for i in range(...):\n if plan[...] == ...:\n return ...\n else:\n personne = ...\n return ...\n
Exemples :
>>> est_cyclique({'A':'E', 'F':'A', 'C':'D', 'E':'B', 'B':'F', 'D':'C'})\nFalse\n>>> est_cyclique({'A':'E', 'F':'C', 'C':'D', 'E':'B', 'B':'F', 'D':'A'})\nTrue\n>>> est_cyclique({'A':'B', 'F':'C', 'C':'D', 'E':'A', 'B':'F', 'D':'E'})\nTrue\n>>> est_cyclique({'A':'B', 'F':'A', 'C':'D', 'E':'C', 'B':'F', 'D':'E'})\nFalse\n
def est_cyclique(plan):\n'''\n Prend en param\u00e8tre un dictionnaire plan correspondant\n \u00e0 un plan d'envoi de messages entre N personnes A, B, C,\n D, E, F ...(avec N <= 26).\n Renvoie True si le plan d'envoi de messages est cyclique\n et False sinon.\n '''\n personne = 'A'\n N = len(plan)\n for i in range(N-1):\n if plan[personne] == 'A':\n return False\n else:\n personne = plan[personne]\n return True\n\nprint(est_cyclique({'A':'E', 'F':'A', 'C':'D', 'E':'B', 'B':'F', 'D':'C'}))\n\nprint(est_cyclique({'A':'E', 'F':'C', 'C':'D', 'E':'B', 'B':'F', 'D':'A'}))\n\nprint(est_cyclique({'A':'B', 'F':'C', 'C':'D', 'E':'A', 'B':'F', 'D':'E'}))\n\nprint(est_cyclique({'A':'B', 'F':'A', 'C':'D', 'E':'C', 'B':'F', 'D':'E'}))\n
On consid\u00e8re au plus 26 personnes A, B, C, D, E, F ... qui peuvent s'envoyer des messages\navec deux r\u00e8gles \u00e0 respecter :\n\n- chaque personne ne peut envoyer des messages qu'\u00e0 la m\u00eame personne\n(\u00e9ventuellement elle-m\u00eame),\n- chaque personne ne peut recevoir des messages qu'en provenance d'une seule\npersonne (\u00e9ventuellement elle-m\u00eame).\n\n\nVoici un exemple - avec 6 personnes - de \u00ab plan d'envoi des messages \u00bb qui respecte les\nr\u00e8gles ci-dessus, puisque chaque personne est pr\u00e9sente une seule fois dans chaque\ncolonne :\n\n- A envoie ses messages \u00e0 E\n- E envoie ses messages \u00e0 B\n- B envoie ses messages \u00e0 F\n- F envoie ses messages \u00e0 A\n- C envoie ses messages \u00e0 D\n- D envoie ses messages \u00e0 C\n\nEt le dictionnaire correspondant \u00e0 ce plan d'envoi est le suivant :\n\n`plan_a = {'A':'E', 'B':'F', 'C':'D', 'D':'C', 'E':'B', 'F':'A'}`\n\nSur le plan d'envoi plan_a des messages ci-dessus, il y a deux cycles distincts : un premier\ncycle avec A, E, B, F et un second cycle avec C et D.\n\nEn revanche, le plan d\u2019envoi plan_b ci-dessous :\n\n`plan_b = {'A':'C', 'B':'F', 'C':'E', 'D':'A', 'E':'B', 'F':'D'}`\n\ncomporte un unique cycle : A, C, E, B, F, D. Dans ce cas, lorsqu\u2019un plan d\u2019envoi comporte un\nunique cycle, on dit que le plan d\u2019envoi est *cyclique*.\n\nPour savoir si un plan d'envoi de messages comportant N personnes est cyclique, on peut\nutiliser l'algorithme ci-dessous :\n\n\nOn part de la personne A et on inspecte les N \u2013 1 successeurs dans le plan d'envoi :\n\n- Si un de ces N \u2013 1 successeurs est A lui-m\u00eame, on a trouv\u00e9 un cycle de taille\ninf\u00e9rieure ou \u00e9gale \u00e0 N \u2013 1. Il y a donc au moins deux cycles et le plan d'envoi n'est\npas cyclique.\n\n- Si on ne retombe pas sur A lors de cette inspection, on a un unique cycle qui passe\npar toutes les personnes : le plan d'envoi est cyclique.\n\n\nCompl\u00e9ter la fonction suivante en respectant la sp\u00e9cification.\n\n*Remarque :* la fonction python `len` permet d'obtenir la longueur d'un dictionnaire.\n\n\n```python linenums='1'\ndef est_cyclique(plan):\n '''\n Prend en param\u00e8tre un dictionnaire plan correspondant\n \u00e0 un plan d'envoi de messages entre N personnes A, B, C,\n D, E, F ...(avec N <= 26).\n Renvoie True si le plan d'envoi de messages est cyclique\n et False sinon.\n '''\n personne = 'A'\n N = len(...)\n for i in range(...):\n if plan[...] == ...:\n return ...\n else:\n personne = ...\n return ...\n
Exemples :
>>> est_cyclique({'A':'E', 'F':'A', 'C':'D', 'E':'B', 'B':'F', 'D':'C'})\nFalse\n>>> est_cyclique({'A':'E', 'F':'C', 'C':'D', 'E':'B', 'B':'F', 'D':'A'})\nTrue\n>>> est_cyclique({'A':'B', 'F':'C', 'C':'D', 'E':'A', 'B':'F', 'D':'E'})\nTrue\n>>> est_cyclique({'A':'B', 'F':'A', 'C':'D', 'E':'C', 'B':'F', 'D':'E'})\nFalse\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-15","title":"\u25b6 Sujet 15","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-151","title":"Exercice 15.1 \u25a1","text":"Exercice 15.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction python appel\u00e9e nb_repetitions
qui prend en param\u00e8tres un \u00e9l\u00e9ment elt
et une liste tab
et renvoie le nombre de fois o\u00f9 l\u2019\u00e9l\u00e9ment appara\u00eet dans la liste.
Exemples :
>>> nb_repetitions(5, [2, 5, 3, 5, 6, 9, 5])\n3\n>>> nb_repetitions('A', ['B', 'A', 'B', 'A', 'R'])\n2\n>>> nb_repetitions(12, [1, '!', 7, 21, 36, 44])\n0\n
def nb_repetitions(elt, tab):\n nb = 0\n for element in tab:\n if element == elt:\n nb += 1\n return nb\n
\u00c9crire une fonction python appel\u00e9e `nb_repetitions` qui prend en param\u00e8tres un\n\u00e9l\u00e9ment `elt` et une liste `tab` et renvoie le nombre de fois o\u00f9 l\u2019\u00e9l\u00e9ment appara\u00eet dans la\nliste.\n\nExemples :\n```python\n>>> nb_repetitions(5, [2, 5, 3, 5, 6, 9, 5])\n3\n>>> nb_repetitions('A', ['B', 'A', 'B', 'A', 'R'])\n2\n>>> nb_repetitions(12, [1, '!', 7, 21, 36, 44])\n0\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-152","title":"Exercice 15.2 \u25a1","text":"Exercice 15.2
\u00c9nonc\u00e9CorrectionSources MarkdownPour rappel, la conversion d\u2019un nombre entier positif en binaire peut s\u2019effectuer \u00e0 l\u2019aide des divisions successives comme illustr\u00e9 ici :
Voici une fonction Python bas\u00e9e sur la m\u00e9thode des divisions successives permettant de convertir un nombre entier positif en binaire :
def binaire(a):\n bin_a = str(...)\n a = a // 2\n while a ... :\n bin_a = ...(a%2) + ...\n a = ...\n return bin_a\n
Compl\u00e9ter la fonction binaire
. Exemples :
>>> binaire(0)\n'0'\n>>> binaire(77)\n'1001101'\n
def binaire(a):\n bin_a = str(a%2)\n a = a // 2\n while a != 0 :\n bin_a = str(a%2) + bin_a\n a = a // 2\n return bin_a\n
Pour rappel, la conversion d\u2019un nombre entier positif en binaire peut s\u2019effectuer \u00e0 l\u2019aide\ndes divisions successives comme illustr\u00e9 ici :\n\n![image](data/img21_2.png){: .center}\n\nVoici une fonction Python bas\u00e9e sur la m\u00e9thode des divisions successives permettant de\nconvertir un nombre entier positif en binaire :\n```python linenums='1'\ndef binaire(a):\n bin_a = str(...)\n a = a // 2\n while a ... :\n bin_a = ...(a%2) + ...\n a = ...\n return bin_a\n
Compl\u00e9ter la fonction binaire
. Exemples :
>>> binaire(0)\n'0'\n>>> binaire(77)\n'1001101'\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-16","title":"\u25b6 Sujet 16","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-161","title":"Exercice 16.1 \u25a1","text":"Exercice 16.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction maxi
qui prend en param\u00e8tre une liste tab
de nombres entiers et renvoie un couple donnant le plus grand \u00e9l\u00e9ment de cette liste, ainsi que l\u2019indice de la premi\u00e8re apparition de ce maximum dans la liste.
Exemple :
>>> maxi([1,5,6,9,1,2,3,7,9,8])\n(9,3)\n
def maxi(tab):\n val_max = tab[0]\n pos_max = 0\n for i in range(len(tab)):\n if tab[i] > val_max:\n val_max = tab[i]\n pos_max = i\n return (val_max, pos_max)\n
\u00c9crire une fonction `maxi` qui prend en param\u00e8tre une liste `tab` de nombres entiers et renvoie un couple donnant le plus grand \u00e9l\u00e9ment de cette liste, ainsi que l\u2019indice de la premi\u00e8re apparition de ce maximum dans la liste.\n\nExemple :\n```python\n>>> maxi([1,5,6,9,1,2,3,7,9,8])\n(9,3)\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-162","title":"Exercice 16.2 \u25a1","text":"Exercice 16.2
\u00c9nonc\u00e9CorrectionSources MarkdownCet exercice utilise des piles qui seront repr\u00e9sent\u00e9es en Python par des listes (type list
).
On rappelle que l\u2019expression T1 = list(T)
fait une copie de T
ind\u00e9pendante de T
, que l\u2019expression x = T.pop()
enl\u00e8ve le sommet de la pile T
et le place dans la variable x
et, enfin, que l\u2019expression T.append(v)
place la valeur v
au sommet de la pile T
.
Compl\u00e9ter le code Python de la fonction positif
ci-dessous qui prend une pile T
de nombres entiers en param\u00e8tre et qui renvoie la pile des entiers positifs dans le m\u00eame ordre, sans modifier la variable T
.
def positif(T):\n T2 = ...(T)\n T3 = ...\n while T2 != []:\n x = ...\n if ... >= 0:\n T3.append(...)\n T2 = []\n while T3 != ...:\n x = T3.pop()\n ...\n print('T = ',T)\n return T2\n
Exemple :
>>> positif([-1, 0, 5, -3, 4, -6, 10, 9, -8])\nT = [-1, 0, 5, -3, 4, -6, 10, 9, -8]\n[0, 5, 4, 10, 9]\n
def positif(T):\n T2 = list(T)\n T3 = []\n while T2 != []:\n x = T2.pop()\n if x >= 0:\n T3.append(x)\n T2 = [] # <- NB : cette ligne est inutile\n while T3 != []:\n x = T3.pop()\n T2.append(x)\n print('T = ',T)\n return T2\n
Cet exercice utilise des piles qui seront repr\u00e9sent\u00e9es en Python par des listes (type `list`).\n\nOn rappelle que l\u2019expression `T1 = list(T)` fait une copie de `T `ind\u00e9pendante de `T`, que\nl\u2019expression `x = T.pop()` enl\u00e8ve le sommet de la pile `T` et le place dans la variable `x` et,\nenfin, que l\u2019expression `T.append(v)` place la valeur `v` au sommet de la pile `T`.\n\nCompl\u00e9ter le code Python de la fonction `positif` ci-dessous qui prend une pile `T` de\nnombres entiers en param\u00e8tre et qui renvoie la pile des entiers positifs dans le m\u00eame\nordre, sans modifier la variable `T`.\n\n```python linenums='1'\ndef positif(T):\n T2 = ...(T)\n T3 = ...\n while T2 != []:\n x = ...\n if ... >= 0:\n T3.append(...)\n T2 = []\n while T3 != ...:\n x = T3.pop()\n ...\n print('T = ',T)\n return T2\n
Exemple :
>>> positif([-1, 0, 5, -3, 4, -6, 10, 9, -8])\nT = [-1, 0, 5, -3, 4, -6, 10, 9, -8]\n[0, 5, 4, 10, 9]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-17","title":"\u25b6 Sujet 17","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-171","title":"Exercice 17.1 \u25a1","text":"Exercice 17.1
\u00c9nonc\u00e9CorrectionSource MarkdownPour cet exercice :
On appelle \u00ab mot \u00bb une cha\u00eene de caract\u00e8res compos\u00e9e avec des caract\u00e8res choisis parmi les 26 lettres minuscules ou majuscules de l'alphabet,
On appelle \u00ab phrase \u00bb une cha\u00eene de caract\u00e8res :
' '
,'.'
qui est alors coll\u00e9 au dernier mot,'!'
ou d'interrogation '?'
qui est alors s\u00e9par\u00e9 du dernier mot par un seul caract\u00e8re espace ' '
.Exemples :
Apr\u00e8s avoir remarqu\u00e9 le lien entre le nombre de mots et le nombres de caract\u00e8res espace dans une phrase, programmer une fonction nombre_de_mots
qui prend en param\u00e8tre une phrase et renvoie le nombre de mots pr\u00e9sents dans cette phrase.
>>> nombre_de_mots('Le point d exclamation est separe !')\n6\n>>> nombre_de_mots('Il y a un seul espace entre les mots !')\n9\n
def nombre_de_mots(phrase):\n nb_mots = 0\n for caractere in phrase:\n if caractere == ' ' or caractere == '.':\n nb_mots += 1\n return nb_mots\n
Pour cet exercice :\n\n- On appelle \u00ab mot \u00bb une cha\u00eene de caract\u00e8res compos\u00e9e avec des caract\u00e8res choisis\nparmi les 26 lettres minuscules ou majuscules de l'alphabet,\n\n- On appelle \u00ab phrase \u00bb une cha\u00eene de caract\u00e8res :\n - compos\u00e9e avec un ou plusieurs \u00ab mots \u00bb s\u00e9par\u00e9s entre eux par un seul\ncaract\u00e8re espace `' '`,\n - se finissant :\n - soit par un point `'.'` qui est alors coll\u00e9 au dernier mot,\n - soit par un point d'exclamation `'!'` ou d'interrogation `'?'` qui est alors\ns\u00e9par\u00e9 du dernier mot par un seul caract\u00e8re espace `' '`.\n\n*Exemples :*\n\nApr\u00e8s avoir remarqu\u00e9 le lien entre le nombre de mots et le nombres de caract\u00e8res espace\ndans une phrase, programmer une fonction `nombre_de_mots` qui prend en param\u00e8tre une\nphrase et renvoie le nombre de mots pr\u00e9sents dans cette phrase.\n\n```python\n>>> nombre_de_mots('Le point d exclamation est separe !')\n6\n>>> nombre_de_mots('Il y a un seul espace entre les mots !')\n9\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-172","title":"Exercice 17.2 \u25a1","text":"Exercice 17.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa classe ABR ci-dessous permet d'impl\u00e9menter une structure d'arbre binaire de recherche.
class Noeud:\n''' Classe impl\u00e9mentant un noeud d'arbre binaire\n disposant de 3 attributs :\n - valeur : la valeur de l'\u00e9tiquette,\n - gauche : le sous-arbre gauche.\n - droit : le sous-arbre droit. '''\n def __init__(self, v, g, d):\n self.valeur = v\n self.gauche = g\n self.droite = d\n\nclass ABR:\n''' Classe impl\u00e9mentant une structure\n d'arbre binaire de recherche. '''\n def __init__(self):\n'''Cr\u00e9e un arbre binaire de recherche vide'''\n self.racine = None\n\n def est_vide(self):\n'''Renvoie True si l'ABR est vide et False sinon.'''\n return self.racine is None\n\n def parcours(self, tab = []):\n''' Renvoie la liste tab compl\u00e9t\u00e9e avec tous les\n \u00e9l\u00e9ments de l'ABR tri\u00e9s par ordre croissant. '''\n\n if self.est_vide():\n return tab\n else:\n self.racine.gauche.parcours(tab)\n tab.append(...)\n ...\n return tab\n\n def insere(self, element):\n'''Ins\u00e8re un \u00e9l\u00e9ment dans l'arbre binaire de recherche.'''\n if self.est_vide():\n self.racine = Noeud(element, ABR(), ABR())\n else:\n if element < self.racine.valeur:\n self.racine.gauche.insere(element)\n else :\n self.racine.droite.insere(element)\n\n def recherche(self, element):\n'''\n Renvoie True si element est pr\u00e9sent dans l'arbre\n binaire et False sinon.\n '''\n if self.est_vide():\n return ...\n else:\n if element < self.racine.valeur:\n return ...\n elif element > self.racine.valeur:\n return ...\n else:\n return ...\n
Compl\u00e9ter les fonctions r\u00e9cursives parcours et recherche afin qu'elles respectent leurs sp\u00e9cifications.
Voici un exemple d'utilisation :
>>> a = ABR()\n>>> a.insere(7)\n>>> a.insere(3)\n>>> a.insere(9)\n>>> a.insere(1)\n>>> a.insere(9)\n>>> a.parcours()\n[1,3, 7, 9, 9]\n\n>>> a.recherche(4)\nFalse\n>>> a.recherche(3)\nTrue\n
class Noeud:\n''' Classe impl\u00e9mentant un noeud d'arbre binaire\n disposant de 3 attributs :\n - valeur : la valeur de l'\u00e9tiquette,\n - gauche : le sous-arbre gauche.\n - droit : le sous-arbre droit. '''\n def __init__(self, v, g, d):\n self.valeur = v\n self.gauche = g\n self.droite = d\n\nclass ABR:\n''' Classe impl\u00e9mentant une structure\n d'arbre binaire de recherche. '''\n def __init__(self):\n'''Cr\u00e9e un arbre binaire de recherche vide'''\n self.racine = None\n\n def est_vide(self):\n'''Renvoie True si l'ABR est vide et False sinon.'''\n return self.racine is None\n\n def parcours(self, tab = []):\n''' Renvoie la liste tab compl\u00e9t\u00e9e avec tous les\n \u00e9l\u00e9ments de l'ABR tri\u00e9s par ordre croissant. '''\n\n if self.est_vide():\n return tab\n else:\n self.racine.gauche.parcours(tab)\n tab.append(self.racine.valeur)\n self.racine.droite.parcours(tab)\n return tab\n\n def insere(self, element):\n'''Ins\u00e8re un \u00e9l\u00e9ment dans l'arbre binaire de recherche.'''\n if self.est_vide():\n self.racine = Noeud(element, ABR(), ABR())\n else:\n if element < self.racine.valeur:\n self.racine.gauche.insere(element)\n else :\n self.racine.droite.insere(element)\n\n def recherche(self, element):\n'''\n Renvoie True si element est pr\u00e9sent dans l'arbre\n binaire et False sinon.\n '''\n if self.est_vide():\n return False\n else:\n if element < self.racine.valeur:\n return self.racine.gauche.recherche(element)\n elif element > self.racine.valeur:\n return self.racine.droite.recherche(element)\n else:\n return True\n
Cette mani\u00e8re de coder le parcours est maladroite car elle conduit \u00e0 ceci :
>>> a.parcours()\n[1, 3, 7, 9, 9]\n>>> a.parcours()\n[1, 3, 7, 9, 9, 1, 3, 7, 9, 9]\n
Comme le param\u00e8tre optionnel tab
est un \u00e9l\u00e9ment mutable (de type list
), Python ne le r\u00e9initialise pas avant chaque appel de la fonction. Vous pouvez constater les cons\u00e9quences f\u00e2cheuses.
Une solution pourrait \u00eatre d'\u00e9crire ceci :
def parcours(self, tab = None):\n''' Renvoie la liste tab compl\u00e9t\u00e9e avec tous les\n \u00e9l\u00e9ments de l'ABR tri\u00e9s par ordre croissant. '''\n if tab is None:\n tab = []\n if self.est_vide():\n return tab\n else:\n self.racine.gauche.parcours(tab)\n tab.append(self.racine.valeur)\n self.racine.droite.parcours(tab)\n return tab\n
La classe ABR ci-dessous permet d'impl\u00e9menter une structure d'arbre binaire de recherche.\n\n```python linenums='1'\nclass Noeud:\n ''' Classe impl\u00e9mentant un noeud d'arbre binaire\n disposant de 3 attributs :\n - valeur : la valeur de l'\u00e9tiquette,\n - gauche : le sous-arbre gauche.\n - droit : le sous-arbre droit. '''\n def __init__(self, v, g, d):\n self.valeur = v\n self.gauche = g\n self.droite = d\n\nclass ABR:\n ''' Classe impl\u00e9mentant une structure\n d'arbre binaire de recherche. '''\n def __init__(self):\n '''Cr\u00e9e un arbre binaire de recherche vide'''\n self.racine = None\n\n def est_vide(self):\n '''Renvoie True si l'ABR est vide et False sinon.'''\n return self.racine is None\n\n def parcours(self, tab = []):\n ''' Renvoie la liste tab compl\u00e9t\u00e9e avec tous les\n \u00e9l\u00e9ments de l'ABR tri\u00e9s par ordre croissant. '''\n\n if self.est_vide():\n return tab\n else:\n self.racine.gauche.parcours(tab)\n tab.append(...)\n ...\n return tab\n\n def insere(self, element):\n '''Ins\u00e8re un \u00e9l\u00e9ment dans l'arbre binaire de recherche.'''\n if self.est_vide():\n self.racine = Noeud(element, ABR(), ABR())\n else:\n if element < self.racine.valeur:\n self.racine.gauche.insere(element)\n else :\n self.racine.droite.insere(element)\n\n def recherche(self, element):\n '''\n Renvoie True si element est pr\u00e9sent dans l'arbre\n binaire et False sinon.\n '''\n if self.est_vide():\n return ...\n else:\n if element < self.racine.valeur:\n return ...\n elif element > self.racine.valeur:\n return ...\n else:\n return ...\n
Compl\u00e9ter les fonctions r\u00e9cursives parcours et recherche afin qu'elles respectent leurs sp\u00e9cifications.
Voici un exemple d'utilisation :
>>> a = ABR()\n>>> a.insere(7)\n>>> a.insere(3)\n>>> a.insere(9)\n>>> a.insere(1)\n>>> a.insere(9)\n>>> a.parcours()\n[1,3, 7, 9, 9]\n\n>>> a.recherche(4)\nFalse\n>>> a.recherche(3)\nTrue\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-18","title":"\u25b6 Sujet 18","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-181","title":"Exercice 18.1 \u25a1","text":"Exercice 18.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn a relev\u00e9 les valeurs moyennes annuelles des temp\u00e9ratures \u00e0 Paris pour la p\u00e9riode allant de 2013 \u00e0 2019. Les r\u00e9sultats ont \u00e9t\u00e9 r\u00e9cup\u00e9r\u00e9s sous la forme de deux listes : l\u2019une pour les temp\u00e9ratures, l\u2019autre pour les ann\u00e9es :
t_moy = [14.9, 13.3, 13.1, 12.5, 13.0, 13.6, 13.7]\nannees = [2013, 2014, 2015, 2016, 2017, 2018, 2019]\n
\u00c9crire la fonction mini
qui prend en param\u00e8tres le tableau releve
des relev\u00e9s et le tableau date
des dates et qui renvoie la plus petite valeur relev\u00e9e au cours de la p\u00e9riode et l\u2019ann\u00e9e correspondante.
Exemple :
>>> mini(t_moy, annees)\n(12.5, 2016)\n
t_moy = [14.9, 13.3, 13.1, 12.5, 13.0, 13.6, 13.7]\nannees = [2013, 2014, 2015, 2016, 2017, 2018, 2019]\n\ndef mini(releve, date):\n temp_mini = releve[0]\n date_mini = date[0]\n for i in range(len(releve)):\n if releve[i] < temp_mini:\n temp_mini = releve[i]\n date_mini = date[i]\n return temp_mini, date_mini\n
On a relev\u00e9 les valeurs moyennes annuelles des temp\u00e9ratures \u00e0 Paris pour la p\u00e9riode\nallant de 2013 \u00e0 2019. Les r\u00e9sultats ont \u00e9t\u00e9 r\u00e9cup\u00e9r\u00e9s sous la forme de deux listes : l\u2019une pour les temp\u00e9ratures, l\u2019autre pour les ann\u00e9es :\n```python\nt_moy = [14.9, 13.3, 13.1, 12.5, 13.0, 13.6, 13.7]\nannees = [2013, 2014, 2015, 2016, 2017, 2018, 2019]\n```\n\n\u00c9crire la fonction `mini` qui prend en param\u00e8tres le tableau `releve` des relev\u00e9s et le\ntableau `date` des dates et qui renvoie la plus petite valeur relev\u00e9e au cours de la\np\u00e9riode et l\u2019ann\u00e9e correspondante.\n\nExemple :\n```python\n>>> mini(t_moy, annees)\n(12.5, 2016)\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-182","title":"Exercice 18.2 \u25a1","text":"Exercice 18.2
\u00c9nonc\u00e9CorrectionSources MarkdownUn mot palindrome peut se lire de la m\u00eame fa\u00e7on de gauche \u00e0 droite ou de droite \u00e0 gauche : bob, radar, et non sont des mots palindromes.
De m\u00eame certains nombres sont eux aussi des palindromes : 33, 121, 345543.
L\u2019objectif de cet exercice est d\u2019obtenir un programme Python permettant de tester si un nombre est un nombre palindrome.
Pour remplir cette t\u00e2che, on vous demande de compl\u00e9ter le code des trois fonctions ci- dessous sachant que la fonction est_nbre_palindrome
s\u2019appuiera sur la fonction est_palindrome
qui elle-m\u00eame s\u2019appuiera sur la fonction inverse_chaine
.
La fonction inverse_chaine
inverse l'ordre des caract\u00e8res d'une cha\u00eene de caract\u00e8res chaine
et renvoie la cha\u00eene invers\u00e9e.
La fonction est_palindrome
teste si une chaine de caract\u00e8res chaine
est un palindrome. Elle renvoie True
si c\u2019est le cas et False
sinon. Cette fonction s\u2019appuie sur la fonction pr\u00e9c\u00e9dente.
La fonction est_nbre_palindrome
teste si un nombre nbre
est un palindrome. Elle renvoie True
si c\u2019est le cas et False
sinon. Cette fonction s\u2019appuie sur la fonction pr\u00e9c\u00e9dente.
Compl\u00e9ter le code des trois fonctions ci-dessous.
def inverse_chaine(chaine):\n result = ...\n for caractere in chaine:\n result = ...\n return result\n\ndef est_palindrome(chaine):\n inverse = inverse_chaine(chaine)\n return ...\n\ndef est_nbre_palindrome(nbre):\n chaine = ...\n return est_palindrome(chaine)\n
Exemples : >>> inverse_chaine('bac')\n'cab'\n>>> est_palindrome('NSI')\nFalse\n>>> est_palindrome('ISN-NSI')\nTrue\n>>> est_nbre_palindrome(214312)\nFalse\n>>> est_nbre_palindrome(213312)\nTrue\n
def inverse_chaine(chaine):\n result = ''\n for caractere in chaine:\n result = caractere + result\n return result\n\ndef est_palindrome(chaine):\n inverse = inverse_chaine(chaine)\n return chaine == inverse\n\ndef est_nbre_palindrome(nbre):\n chaine = str(nbre)\n return est_palindrome(chaine)\n
Un mot palindrome peut se lire de la m\u00eame fa\u00e7on de gauche \u00e0 droite ou de droite \u00e0\ngauche : *bob*, *radar*, et *non* sont des mots palindromes.\n\nDe m\u00eame certains nombres sont eux aussi des palindromes : 33, 121, 345543.\n\nL\u2019objectif de cet exercice est d\u2019obtenir un programme Python permettant de tester si un\nnombre est un nombre palindrome.\n\nPour remplir cette t\u00e2che, on vous demande de compl\u00e9ter le code des trois fonctions ci-\ndessous sachant que la fonction `est_nbre_palindrome` s\u2019appuiera sur la fonction\n`est_palindrome` qui elle-m\u00eame s\u2019appuiera sur la fonction `inverse_chaine`.\n\nLa fonction `inverse_chaine` inverse l'ordre des caract\u00e8res d'une cha\u00eene de caract\u00e8res\n`chaine` et renvoie la cha\u00eene invers\u00e9e.\n\nLa fonction `est_palindrome` teste si une chaine de caract\u00e8res `chaine` est un\npalindrome. Elle renvoie `True` si c\u2019est le cas et `False` sinon. Cette fonction s\u2019appuie sur\nla fonction pr\u00e9c\u00e9dente.\n\nLa fonction `est_nbre_palindrome` teste si un nombre `nbre` est un palindrome. Elle\nrenvoie `True` si c\u2019est le cas et `False` sinon. Cette fonction s\u2019appuie sur la fonction\npr\u00e9c\u00e9dente.\n\nCompl\u00e9ter le code des trois fonctions ci-dessous.\n\n```python\ndef inverse_chaine(chaine):\n result = ...\n for caractere in chaine:\n result = ...\n return result\n\ndef est_palindrome(chaine):\n inverse = inverse_chaine(chaine)\n return ...\n\ndef est_nbre_palindrome(nbre):\n chaine = ...\n return est_palindrome(chaine)\n
Exemples : >>> inverse_chaine('bac')\n'cab'\n>>> est_palindrome('NSI')\nFalse\n>>> est_palindrome('ISN-NSI')\nTrue\n>>> est_nbre_palindrome(214312)\nFalse\n>>> est_nbre_palindrome(213312)\nTrue\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-19","title":"\u25b6 Sujet 19","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-191","title":"Exercice 19.1 \u25a1","text":"Exercice 19.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction multiplication
, prenant en param\u00e8tres deux nombres entiers n1
et n2
, et qui renvoie le produit de ces deux nombres. Les seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.
Exemples :
>>> multiplication(3,5)\n15\n>>> multiplication(-4,-8)\n32\n>>> multiplication(-2,6)\n-12\n>>> multiplication(-2,0)\n0\n
def multiplication(n1, n2):\n if n1 < 0:\n return -multiplication(-n1, n2)\n if n2 < 0:\n return -multiplication(n1, -n2)\n resultat = 0\n for _ in range(n2):\n resultat += n1\n return resultat\n
Programmer la fonction `multiplication`, prenant en param\u00e8tres deux nombres entiers\n`n1` et `n2`, et qui renvoie le produit de ces deux nombres.\nLes seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.\n\nExemples :\n```python\n>>> multiplication(3,5)\n15\n>>> multiplication(-4,-8)\n32\n>>> multiplication(-2,6)\n-12\n>>> multiplication(-2,0)\n0\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-192","title":"Exercice 19.2 \u25a1","text":"Exercice 19.2
\u00c9nonc\u00e9CorrectionSources MarkdownSoit T
un tableau non vide d'entiers tri\u00e9s dans l'ordre croissant et n
un entier. La fonction chercher
, donn\u00e9e \u00e0 la page suivante, doit renvoyer un indice o\u00f9 la valeur n
appara\u00eet \u00e9ventuellement dans T
, et None
sinon.
Les param\u00e8tres de la fonction sont :
T
, le tableau dans lequel s'effectue la recherche ;n
, l'entier \u00e0 chercher dans le tableau ;i
, l'indice de d\u00e9but de la partie du tableau o\u00f9 s'effectue la recherche ;j
, l'indice de fin de la partie du tableau o\u00f9 s'effectue la recherche.La fonction chercher
est une fonction r\u00e9cursive bas\u00e9e sur le principe \u00ab diviser pour r\u00e9gner \u00bb.
Le code de la fonction commence par v\u00e9rifier si 0 <= i
et j < len(T)
. Si cette condition n\u2019est pas v\u00e9rifi\u00e9e, elle affiche \"Erreur\"
puis renvoie None
.
Recopier et compl\u00e9ter le code de la fonction chercher
propos\u00e9e ci-dessous :
def chercher(T, n, i, j):\n if i < 0 or ??? :\n print(\"Erreur\")\n return None\n if i > j :\n return None\n m = (i + j) // ???\n if T[m] < ??? :\n return chercher(T, n, ??? , ???)\n elif ??? :\n return chercher(T, n, ??? , ??? )\n else :\n return ???\n
L'ex\u00e9cution du code doit donner :
>>> chercher([1,5,6,6,9,12],7,0,10)\nErreur\n>>> chercher([1,5,6,6,9,12],7,0,5)\n>>> chercher([1,5,6,6,9,12],9,0,5)\n4\n>>> chercher([1,5,6,6,9,12],6,0,5)\n2\n
def chercher(T, n, i, j):\n if i < 0 or j >= len(T) :\n print('Erreur')\n return None\n if i > j :\n return None\n m = (i + j) // 2\n if T[m] < n :\n return chercher(T, n, m + 1, j)\n elif T[m] > n :\n return chercher(T, n, i, m - 1 )\n else :\n return m\n
Soit `T` un tableau non vide d'entiers tri\u00e9s dans l'ordre croissant et `n` un entier.\nLa fonction `chercher`, donn\u00e9e \u00e0 la page suivante, doit renvoyer un indice o\u00f9 la valeur `n`\nappara\u00eet \u00e9ventuellement dans `T`, et `None` sinon. \n\nLes param\u00e8tres de la fonction sont :\n\n- `T`, le tableau dans lequel s'effectue la recherche ;\n- `n`, l'entier \u00e0 chercher dans le tableau ;\n- `i`, l'indice de d\u00e9but de la partie du tableau o\u00f9 s'effectue la recherche ;\n- `j`, l'indice de fin de la partie du tableau o\u00f9 s'effectue la recherche.\n\nLa fonction `chercher` est une fonction r\u00e9cursive bas\u00e9e sur le principe \u00ab diviser pour\nr\u00e9gner \u00bb.\n\n\nLe code de la fonction commence par v\u00e9rifier si `0 <= i` et `j < len(T)`. \nSi cette\ncondition n\u2019est pas v\u00e9rifi\u00e9e, elle affiche `\"Erreur\"` puis renvoie `None`.\n\nRecopier et compl\u00e9ter le code de la fonction `chercher` propos\u00e9e ci-dessous :\n\n```python linenums='1'\ndef chercher(T, n, i, j):\n if i < 0 or ??? :\n print(\"Erreur\")\n return None\n if i > j :\n return None\n m = (i + j) // ???\n if T[m] < ??? :\n return chercher(T, n, ??? , ???)\n elif ??? :\n return chercher(T, n, ??? , ??? )\n else :\n return ???\n
L'ex\u00e9cution du code doit donner :
>>> chercher([1,5,6,6,9,12],7,0,10)\nErreur\n>>> chercher([1,5,6,6,9,12],7,0,5)\n>>> chercher([1,5,6,6,9,12],9,0,5)\n4\n>>> chercher([1,5,6,6,9,12],6,0,5)\n2\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-20","title":"\u25b6 Sujet 20","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-201","title":"Exercice 20.1 \u25a1","text":"Exercice 20.1
\u00c9nonc\u00e9CorrectionSource MarkdownL'op\u00e9rateur \u00ab ou exclusif \u00bb entre deux bits renvoie 0 si les deux bits sont \u00e9gaux et 1 s'ils sont diff\u00e9rents : 0 \u2295 0 = 0 , 0 \u2295 1 = 1 , 1 \u2295 0 = 1 , 1 \u2295 1 = 0
On repr\u00e9sente ici une suite de bits par un tableau contenant des 0 et des 1.
Exemples :
a = [1, 0, 1, 0, 1, 1, 0, 1]\nb = [0, 1, 1, 1, 0, 1, 0, 0]\nc = [1, 1, 0, 1]\nd = [0, 0, 1, 1]\n
\u00c9crire la fonction xor
qui prend en param\u00e8tres deux tableaux de m\u00eame longueur et qui renvoie un tableau o\u00f9 l\u2019\u00e9l\u00e9ment situ\u00e9 \u00e0 position i
est le r\u00e9sultat, par l\u2019op\u00e9rateur \u00ab ou exclusif \u00bb, des \u00e9l\u00e9ments \u00e0 la position i
des tableaux pass\u00e9s en param\u00e8tres.
En consid\u00e9rant les quatre exemples ci-dessus, cette fonction doit passer les tests suivants :
assert(xor(a, b) == [1, 1, 0, 1, 1, 0, 0, 1])\nassert(xor(c, d) == [1, 1, 1, 0])\n
Correction propos\u00e9e par Yves Laurent
def xor(tab1, tab2):\n\"\"\"\n\n Parameters\n ----------\n tab1 : type(tab1) = list\n Binaire 1\n tab2 : type(tab1) = list\n Binaire 2\n\n Returns\n -------\n resultat : list\n tab1 xor tab2.\n\n \"\"\"\n assert len(tab1) == len(tab2), \"pas la m\u00eame taille\"\n\n resultat = []\n\n taille = len(tab1)\n\n for compteur in range(taille):\n resultat.append(tab1[compteur]^tab2[compteur])\n\n return resultat\n
L'op\u00e9rateur \u00ab ou exclusif \u00bb entre deux bits renvoie 0 si les deux bits sont \u00e9gaux et 1 s'ils sont\ndiff\u00e9rents : \n0 \u2295 0 = 0 , 0 \u2295 1 = 1 , 1 \u2295 0 = 1 , 1 \u2295 1 = 0\n\nOn repr\u00e9sente ici une suite de bits par un tableau contenant des 0 et des 1.\n\nExemples :\n\n```python\na = [1, 0, 1, 0, 1, 1, 0, 1]\nb = [0, 1, 1, 1, 0, 1, 0, 0]\nc = [1, 1, 0, 1]\nd = [0, 0, 1, 1]\n```\n\n\u00c9crire la fonction ```xor``` qui prend en param\u00e8tres deux tableaux de m\u00eame longueur et qui renvoie\nun tableau o\u00f9 l\u2019\u00e9l\u00e9ment situ\u00e9 \u00e0 position `i` est le r\u00e9sultat, par l\u2019op\u00e9rateur \u00ab ou exclusif \u00bb, des\n\u00e9l\u00e9ments \u00e0 la position `i` des tableaux pass\u00e9s en param\u00e8tres.\n\nEn consid\u00e9rant les quatre exemples ci-dessus, cette fonction doit passer les tests suivants :\n\n```python\nassert(xor(a, b) == [1, 1, 0, 1, 1, 0, 0, 1])\nassert(xor(c, d) == [1, 1, 1, 0])\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-202","title":"Exercice 20.2 \u25a1","text":"Exercice 20.2
\u00c9nonc\u00e9CorrectionSources MarkdownDans cet exercice, on appelle carr\u00e9 d\u2019ordre \\(n\\) un tableau de \\(n\\) lignes et \\(n\\) colonnes dont chaque case contient un entier naturel.
Exemples :
Un carr\u00e9 est dit magique lorsque les sommes des \u00e9l\u00e9ments situ\u00e9s sur chaque ligne, chaque colonne et chaque diagonale sont \u00e9gales. Ainsi c2 et c3 sont magiques car la somme de chaque ligne, chaque colonne et chaque diagonale est \u00e9gale \u00e0 2 pour c2 et 15 pour c3. c4 n\u2019est pas magique car la somme de la premi\u00e8re ligne est \u00e9gale \u00e0 34 alors que celle de la derni\u00e8re colonne est \u00e9gale \u00e0 27.
La classe Carre
ci-apr\u00e8s contient des m\u00e9thodes qui permettent de manipuler des carr\u00e9s.
Compl\u00e9ter la fonction est_magique
qui prend en param\u00e8tre un carr\u00e9 et qui renvoie la valeur de la somme si ce carr\u00e9 est magique, False
sinon.
class Carre:\n def __init__(self, tableau = [[]]):\n self.ordre = len(tableau)\n self.valeurs = tableau\n\n def affiche(self):\n'''Affiche un carr\u00e9'''\n for i in range(self.ordre):\n print(self.valeurs[i])\n\n def somme_ligne(self, i):\n'''Calcule la somme des valeurs de la ligne i'''\n return sum(self.valeurs[i])\n\n def somme_col(self, j):\n'''Calcule la somme des valeurs de la colonne j'''\n return sum([self.valeurs[i][j] for i in range(self.ordre)])\n\ndef est_magique(carre):\n n = carre.ordre\n s = carre.somme_ligne(0)\n\n #test de la somme de chaque ligne\n for i in range(..., ...):\n if carre.somme_ligne(i) != s:\n return ...\n\n #test de la somme de chaque colonne\n for j in range(n):\n if ... != s:\n return False\n\n #test de la somme de chaque diagonale\n if sum([carre.valeurs[...][...] for k in range(n)]) != s:\n return False\n if sum([carre.valeurs[k][n-1-k] for k in range(n)]) != s:\n return False\n return ...\n
Tester la fonction est_magique
sur les carr\u00e9s c2, c3 et c4.
class Carre:\n def __init__(self, tableau = [[]]):\n self.ordre = len(tableau)\n self.valeurs = tableau\n\n def affiche(self):\n'''Affiche un carr\u00e9'''\n for i in range(self.ordre):\n print(self.valeurs[i])\n\n def somme_ligne(self, i):\n'''Calcule la somme des valeurs de la ligne i'''\n return sum(self.valeurs[i])\n\n def somme_col(self, j):\n'''Calcule la somme des valeurs de la colonne j'''\n return sum([self.valeurs[i][j] for i in range(self.ordre)])\n\ndef est_magique(carre):\n n = carre.ordre\n s = carre.somme_ligne(0)\n\n #test de la somme de chaque ligne\n for i in range(1, n):\n if carre.somme_ligne(i) != s:\n return False\n\n #test de la somme de chaque colonne\n for j in range(n):\n if carre.somme_col(j) != s:\n return False\n\n #test de la somme de chaque diagonale\n if sum([carre.valeurs[k][k] for k in range(n)]) != s:\n return False\n if sum([carre.valeurs[k][n-1-k] for k in range(n)]) != s:\n return False\n return s\n\nc1 = Carre([[1, 1],\n [1, 1]])\n\nc2 = Carre([[2, 9, 4],\n [7, 5, 3],\n [6, 1, 8]])\n\nc3 = Carre([[4, 5, 16, 9],\n [14, 7, 2, 11],\n [3, 10, 15, 6],\n [13, 12, 8, 1]])\n\nassert est_magique(c1) == 2\nassert est_magique(c2) == 15\nassert est_magique(c3) == False\n
Dans cet exercice, on appelle carr\u00e9 d\u2019ordre $n$ un tableau de $n$ lignes et $n$ colonnes dont chaque case contient un entier naturel.\n\nExemples :\n![image](data/img20_2.png){: .center width=70%}\n\nUn carr\u00e9 est dit magique lorsque les sommes des \u00e9l\u00e9ments situ\u00e9s sur chaque ligne, chaque\ncolonne et chaque diagonale sont \u00e9gales. Ainsi c2 et c3 sont magiques car la somme de chaque\nligne, chaque colonne et chaque diagonale est \u00e9gale \u00e0 2 pour c2 et 15 pour c3. c4 n\u2019est pas\nmagique car la somme de la premi\u00e8re ligne est \u00e9gale \u00e0 34 alors que celle de la derni\u00e8re colonne\nest \u00e9gale \u00e0 27.\n\nLa classe `Carre` ci-apr\u00e8s contient des m\u00e9thodes qui permettent de manipuler des carr\u00e9s.\n\nCompl\u00e9ter la fonction `est_magique` qui prend en param\u00e8tre un carr\u00e9 et qui renvoie la valeur de\nla somme si ce carr\u00e9 est magique, `False` sinon.\n\n```python linenums='1'\nclass Carre:\n def __init__(self, tableau = [[]]):\n self.ordre = len(tableau)\n self.valeurs = tableau\n\n def affiche(self):\n '''Affiche un carr\u00e9'''\n for i in range(self.ordre):\n print(self.valeurs[i])\n\n def somme_ligne(self, i):\n '''Calcule la somme des valeurs de la ligne i'''\n return sum(self.valeurs[i])\n\n def somme_col(self, j):\n '''Calcule la somme des valeurs de la colonne j'''\n return sum([self.valeurs[i][j] for i in range(self.ordre)])\n\ndef est_magique(carre):\n n = carre.ordre\n s = carre.somme_ligne(0)\n\n #test de la somme de chaque ligne\n for i in range(..., ...):\n if carre.somme_ligne(i) != s:\n return ...\n\n #test de la somme de chaque colonne\n for j in range(n):\n if ... != s:\n return False\n\n #test de la somme de chaque diagonale\n if sum([carre.valeurs[...][...] for k in range(n)]) != s:\n return False\n if sum([carre.valeurs[k][n-1-k] for k in range(n)]) != s:\n return False\n return ...\n
Tester la fonction est_magique
sur les carr\u00e9s c2, c3 et c4. ```
Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-211","title":"Exercice 21.1 \u25a1","text":"Exercice 21.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction multiplication
, prenant en param\u00e8tres deux nombres entiers n1
et n2
, et qui renvoie le produit de ces deux nombres. Les seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.
\u00c9nonc\u00e9 peu clair, on ne sait pas si n1
et n2
sont entiers naturels ou relatifs. Nous d\u00e9cidons qu'ils sont relatifs et donc qu'ils peuvent \u00eatre n\u00e9gatifs, auquel cas on utilise le fait que \\(5 \\times (-6)= - (5 \\times 6)\\).
def multiplication(n1, n2):\n if n1 < 0:\n return -multiplication(-n1, n2)\n if n2 < 0:\n return -multiplication(n1, -n2)\n resultat = 0\n for _ in range(n2):\n resultat += n1\n return resultat\n
Programmer la fonction `multiplication`, prenant en param\u00e8tres deux nombres entiers\n`n1` et `n2`, et qui renvoie le produit de ces deux nombres.\nLes seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-212","title":"Exercice 21.2 \u25a1","text":"Exercice 21.2
\u00c9nonc\u00e9CorrectionSources MarkdownRecopier et compl\u00e9ter sous Python la fonction suivante en respectant la sp\u00e9cification. On ne recopiera pas les commentaires.
def dichotomie(tab, x):\n\"\"\"\n tab : tableau d\u2019entiers tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\nFalse\n
def dichotomie(tab, x):\n\"\"\"\n tab : tableau d\u2019entiers tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = (debut + fin) // 2\n if x == tab[m]:\n return True\n if x > tab[m]:\n debut = m + 1\n else:\n fin = m - 1\n return False\n
Recopier et compl\u00e9ter sous Python la fonction suivante en respectant la sp\u00e9cification. On\nne recopiera pas les commentaires.\n\n```python linenums='1'\ndef dichotomie(tab, x):\n \"\"\"\n tab : tableau d\u2019entiers tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\nFalse\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-22","title":"\u25b6 Sujet 22","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-221","title":"Exercice 22.1 \u25a1","text":"Exercice 22.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer une fonction renverse
, prenant en param\u00e8tre une cha\u00eene de caract\u00e8res non vide mot
et renvoie une cha\u00eene de caract\u00e8res en inversant ceux de la cha\u00eene mot
.
Exemple :
>>> renverse(\"informatique\")\n\"euqitamrofni\"\n
def renverse(mot):\n sol = ''\n for lettre in mot:\n sol = lettre + sol\n return sol\n
Programmer une fonction `renverse`, prenant en param\u00e8tre une cha\u00eene de caract\u00e8res non vide\n`mot` et renvoie une cha\u00eene de caract\u00e8res en inversant ceux de la cha\u00eene `mot`.\n\nExemple :\n\n```python\n>>> renverse(\"informatique\")\n\"euqitamrofni\"\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-222","title":"Exercice 22.2 \u25a1","text":"Exercice 22.2
\u00c9nonc\u00e9CorrectionSources MarkdownUn nombre premier est un nombre entier naturel qui admet exactement deux diviseurs distincts entiers et positifs : 1 et lui-m\u00eame.
Le crible d\u2019\u00c9ratosth\u00e8ne permet de d\u00e9terminer les nombres premiers plus petit qu\u2019un certain nombre N fix\u00e9.
On consid\u00e8re pour cela un tableau tab
de N bool\u00e9ens, initialement tous \u00e9gaux \u00e0 True
, sauf tab[0]
et tab[1]
qui valent False
, 0 et 1 n\u2019\u00e9tant pas des nombres premiers.
On parcourt alors ce tableau de gauche \u00e0 droite.
Pour chaque indice i
:
si tab[i]
vaut True
: le nombre i
est premier et on donne la valeur False
\u00e0 toutes les cases du tableau dont l\u2019indice est un multiple de i
, \u00e0 partir de 2*i
(c\u2019est-\u00e0-dire 2*i
, 3*i
...).
si tab[i]
vaut False
: le nombre i
n\u2019est pas premier et on n\u2019effectue aucun changement sur le tableau.
On dispose de la fonction crible
, incompl\u00e8te et donn\u00e9e ci-dessous, prenant en param\u00e8tre un entier N strictement positif et renvoyant un tableau contenant tous les nombres premiers plus petits que N.
def crible(N):\n\"\"\"\n Renvoie un tableau contenant tous les nombres premiers plus petits que N\n \"\"\"\n premiers = []\n tab = [True] * N\n tab[0], tab[1] = False, False\n for i in range(..., N):\n if tab[i] == ...:\n premiers.append(...)\n for multiple in range(2*i, N, ...):\n tab[multiple] = ...\n return premiers\n\nassert crible(40) == [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]\n
Compl\u00e9ter le code de cette fonction.
def crible(N):\n\"\"\"\n Renvoie un tableau contenant tous les nombres premiers plus petits que N\n \"\"\"\n premiers = []\n tab = [True] * N\n tab[0], tab[1] = False, False\n for i in range(2, N):\n if tab[i] == True:\n premiers.append(i)\n for multiple in range(2*i, N, i):\n tab[multiple] = False\n return premiers\n\nassert crible(40) == [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]\n
Un nombre premier est un nombre entier naturel qui admet exactement deux diviseurs distincts\nentiers et positifs : 1 et lui-m\u00eame. \n\nLe crible d\u2019\u00c9ratosth\u00e8ne permet de d\u00e9terminer les nombres premiers plus petit qu\u2019un certain\nnombre N fix\u00e9. \n\nOn consid\u00e8re pour cela un tableau `tab` de N bool\u00e9ens, initialement tous \u00e9gaux \u00e0 `True`, sauf\n`tab[0]` et `tab[1]` qui valent `False`, 0 et 1 n\u2019\u00e9tant pas des nombres premiers. \n\nOn parcourt alors ce tableau de gauche \u00e0 droite. \n\nPour chaque indice `i` :\n\n- si `tab[i]` vaut `True` : le nombre `i` est premier et on donne la valeur `False` \u00e0 toutes les\ncases du tableau dont l\u2019indice est un multiple de `i`, \u00e0 partir de `2*i` (c\u2019est-\u00e0-dire `2*i`, `3*i` ...).\n\n- si `tab[i]` vaut `False` : le nombre `i` n\u2019est pas premier et on n\u2019effectue aucun\nchangement sur le tableau. \n\nOn dispose de la fonction `crible`, incompl\u00e8te et donn\u00e9e ci-dessous, prenant en param\u00e8tre un\nentier N strictement positif et renvoyant un tableau contenant tous les nombres premiers plus\npetits que N.\n\n```python linenums='1'\ndef crible(N):\n \"\"\"\n Renvoie un tableau contenant tous les nombres premiers plus petits que N\n \"\"\"\n premiers = []\n tab = [True] * N\n tab[0], tab[1] = False, False\n for i in range(..., N):\n if tab[i] == ...:\n premiers.append(...)\n for multiple in range(2*i, N, ...):\n tab[multiple] = ...\n return premiers\n\nassert crible(40) == [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]\n
Compl\u00e9ter le code de cette fonction.
```
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-23","title":"\u25b6 Sujet 23","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-231","title":"Exercice 23.1 \u25a1","text":"Exercice 23.1
\u00c9nonc\u00e9CorrectionSource MarkdownSur le r\u00e9seau social TipTop, on s\u2019int\u00e9resse au nombre de \u00ab like \u00bb des abonn\u00e9s. Les donn\u00e9es sont stock\u00e9es dans des dictionnaires o\u00f9 les cl\u00e9s sont les pseudos et les valeurs correspondantes sont les nombres de \u00ab like \u00bb comme ci-dessous :
{'Bob': 102, 'Ada': 201, 'Alice': 103, 'Tim': 50}
\u00c9crire une fonction max_dico
qui :
dico
non vide dont les cl\u00e9s sont des cha\u00eenes de caract\u00e8res et les valeurs associ\u00e9es sont des entiers ;Exemples :
>>> max_dico({'Bob': 102, 'Ada': 201, 'Alice': 103, 'Tim': 50})\n('Ada', 201)\n>>> max_dico({'Alan': 222, 'Ada': 201, 'Eve': 220, 'Tim': 50})\n('Alan', 222)\n
def max_dico(dico):\n cle_max = ''\n val_max = 0\n for cle in dico:\n if dico[cle] > val_max:\n val_max = dico[cle]\n cle_max = cle\n return (cle_max, val_max)\n
Sur le r\u00e9seau social TipTop, on s\u2019int\u00e9resse au nombre de \u00ab like \u00bb des abonn\u00e9s.\nLes donn\u00e9es sont stock\u00e9es dans des dictionnaires o\u00f9 les cl\u00e9s sont les pseudos et les valeurs\ncorrespondantes sont les nombres de \u00ab like \u00bb comme ci-dessous :\n\n`{'Bob': 102, 'Ada': 201, 'Alice': 103, 'Tim': 50}`\n\n\u00c9crire une fonction `max_dico` qui :\n\n- Prend en param\u00e8tre un dictionnaire `dico` non vide dont les cl\u00e9s sont des cha\u00eenes de\ncaract\u00e8res et les valeurs associ\u00e9es sont des entiers ;\n- Renvoie un tuple dont :\n - La premi\u00e8re valeur est la cl\u00e9 du dictionnaire associ\u00e9e \u00e0 la valeur maximale ;\n - La seconde valeur est la premi\u00e8re valeur maximale pr\u00e9sente dans le\ndictionnaire.\n\nExemples :\n\n```python\n>>> max_dico({'Bob': 102, 'Ada': 201, 'Alice': 103, 'Tim': 50})\n('Ada', 201)\n>>> max_dico({'Alan': 222, 'Ada': 201, 'Eve': 220, 'Tim': 50})\n('Alan', 222)\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-232","title":"Exercice 23.2 \u25a1","text":"Exercice 23.2
\u00c9nonc\u00e9CorrectionSources MarkdownNous avons l\u2019habitude de noter les expressions arithm\u00e9tiques avec des parenth\u00e8ses comme par exemple : (2 + 3) \u00d7 5.
Il existe une autre notation utilis\u00e9e par certaines calculatrices, appel\u00e9e notation postfixe, qui n\u2019utilise pas de parenth\u00e8ses. L\u2019expression arithm\u00e9tique pr\u00e9c\u00e9dente est alors obtenue en saisissant successivement 2, puis 3, puis l\u2019op\u00e9rateur +, puis 5, et enfin l\u2019op\u00e9rateur \u00d7. On mod\u00e9lise cette saisie par le tableau [2, 3, '+', 5, '*'].
Autre exemple, la notation postfixe de 3 \u00d7 2 + 5 est mod\u00e9lis\u00e9e par le tableau :
[3, 2, '*', 5, '+'].
D\u2019une mani\u00e8re plus g\u00e9n\u00e9rale, la valeur associ\u00e9e \u00e0 une expression arithm\u00e9tique en notation postfixe est d\u00e9termin\u00e9e \u00e0 l\u2019aide d\u2019une pile en parcourant l\u2019expression arithm\u00e9tique de gauche \u00e0 droite de la fa\u00e7on suivante :
Dans le cadre de cet exercice, on se limitera aux op\u00e9rations \u00d7 et +.
Pour cet exercice, on dispose d\u2019une classe Pile
qui impl\u00e9mente les m\u00e9thodes de base sur la structure de pile.
Compl\u00e9ter le script de la fonction eval_expression
qui re\u00e7oit en param\u00e8tre une liste python repr\u00e9sentant la notation postfixe d\u2019une expression arithm\u00e9tique et qui renvoie sa valeur associ\u00e9e.
Exemple :
>>> eval_expression([2, 3, '+', 5, '*'])\n25\n
class Pile:\n\"\"\"Classe d\u00e9finissant une structure de pile.\"\"\"\n def __init__(self):\n self.contenu = []\n\n def est_vide(self):\n\"\"\"Renvoie le bool\u00e9en True si la pile est vide, False sinon.\"\"\"\n return self.contenu == []\n\n def empiler(self, v):\n\"\"\"Place l'\u00e9l\u00e9ment v au sommet de la pile\"\"\"\n self.contenu.append(v)\n\n def depiler(self):\n\"\"\"\n Retire et renvoie l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile,\n si la pile n\u2019est pas vide.\n \"\"\"\n if not self.est_vide():\n return self.contenu.pop()\n\n\ndef eval_expression(tab):\n p = Pile()\n for ... in tab:\n if element != '+' ... element != '*':\n p.empiler(...)\n else:\n if element == ...:\n resultat = p.depiler() + ...\n else:\n resultat = ...\n p.empiler(...)\n return ...\n
class Pile:\n\"\"\"Classe d\u00e9finissant une structure de pile.\"\"\"\n def __init__(self):\n self.contenu = []\n\n def est_vide(self):\n\"\"\"Renvoie le bool\u00e9en True si la pile est vide, False sinon.\"\"\"\n return self.contenu == []\n\n def empiler(self, v):\n\"\"\"Place l'\u00e9l\u00e9ment v au sommet de la pile\"\"\"\n self.contenu.append(v)\n\n def depiler(self):\n\"\"\"\n Retire et renvoie l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile,\n si la pile n\u2019est pas vide.\n \"\"\"\n if not self.est_vide():\n return self.contenu.pop()\n\n\ndef eval_expression(tab):\n p = Pile()\n for element in tab:\n print(element)\n if element != '+' and element != '*':\n p.empiler(element)\n else:\n if element == '+':\n resultat = p.depiler() + p.depiler()\n else:\n resultat = p.depiler() * p.depiler()\n p.empiler(resultat)\n return p.depiler()\n
Nous avons l\u2019habitude de noter les expressions arithm\u00e9tiques avec des parenth\u00e8ses comme\npar exemple : (2 + 3) \u00d7 5. \n\nIl existe une autre notation utilis\u00e9e par certaines calculatrices, appel\u00e9e notation postfixe, qui n\u2019utilise pas de parenth\u00e8ses. L\u2019expression arithm\u00e9tique pr\u00e9c\u00e9dente est alors obtenue en\nsaisissant successivement 2, puis 3, puis l\u2019op\u00e9rateur +, puis 5, et enfin l\u2019op\u00e9rateur \u00d7. On\nmod\u00e9lise cette saisie par le tableau [2, 3, '+', 5, '*']. \n\nAutre exemple, la notation postfixe de 3 \u00d7 2 + 5 est mod\u00e9lis\u00e9e par le tableau : \n\n[3, 2, '*', 5, '+']. \n\n\nD\u2019une mani\u00e8re plus g\u00e9n\u00e9rale, la valeur associ\u00e9e \u00e0 une expression arithm\u00e9tique en notation\npostfixe est d\u00e9termin\u00e9e \u00e0 l\u2019aide d\u2019une pile en parcourant l\u2019expression arithm\u00e9tique de gauche\n\u00e0 droite de la fa\u00e7on suivante :\n\n- Si l\u2019\u00e9l\u00e9ment parcouru est un nombre, on le place au sommet de la pile ;\n- Si l\u2019\u00e9l\u00e9ment parcouru est un op\u00e9rateur, on r\u00e9cup\u00e8re les deux \u00e9l\u00e9ments situ\u00e9s au\nsommet de la pile et on leur applique l\u2019op\u00e9rateur. On place alors le r\u00e9sultat au sommet\nde la pile.\n- \u00c0 la fin du parcours, il reste alors un seul \u00e9l\u00e9ment dans la pile qui est le r\u00e9sultat de\nl\u2019expression arithm\u00e9tique.\n\n\nDans le cadre de cet exercice, on se limitera aux op\u00e9rations \u00d7 et +.\n\n\nPour cet exercice, on dispose d\u2019une classe `Pile` qui impl\u00e9mente les m\u00e9thodes de base sur la\nstructure de pile.\n\nCompl\u00e9ter le script de la fonction `eval_expression` qui re\u00e7oit en param\u00e8tre une liste python\nrepr\u00e9sentant la notation postfixe d\u2019une expression arithm\u00e9tique et qui renvoie sa valeur\nassoci\u00e9e.\n\nExemple :\n\n```python\n>>> eval_expression([2, 3, '+', 5, '*'])\n25\n
class Pile:\n\"\"\"Classe d\u00e9finissant une structure de pile.\"\"\"\n def __init__(self):\n self.contenu = []\n\n def est_vide(self):\n\"\"\"Renvoie le bool\u00e9en True si la pile est vide, False sinon.\"\"\"\n return self.contenu == []\n\n def empiler(self, v):\n\"\"\"Place l'\u00e9l\u00e9ment v au sommet de la pile\"\"\"\n self.contenu.append(v)\n\n def depiler(self):\n\"\"\"\n Retire et renvoie l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile,\n si la pile n\u2019est pas vide.\n \"\"\"\n if not self.est_vide():\n return self.contenu.pop()\n\n\ndef eval_expression(tab):\n p = Pile()\n for ... in tab:\n if element != '+' ... element != '*':\n p.empiler(...)\n else:\n if element == ...:\n resultat = p.depiler() + ...\n else:\n resultat = ...\n p.empiler(...)\n return ...\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-24","title":"\u25b6 Sujet 24","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-241","title":"Exercice 24.1 \u25a1","text":"Exercice 24.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire la fonction maxliste
, prenant en param\u00e8tre un tableau non vide de nombres tab
(type list
) et renvoyant le plus grand \u00e9l\u00e9ment de ce tableau.
Exemples :
>>> maxliste([98, 12, 104, 23, 131, 9])\n131\n>>> maxliste([-27, 24, -3, 15])\n24\n
def maxliste(tab):\n maximum = tab[0]\n for element in tab:\n if element > maximum:\n maximum = element\n return maximum\n
\u00c9crire la fonction `maxliste`, prenant en param\u00e8tre un tableau non vide de nombres `tab` (type\n`list`) et renvoyant le plus grand \u00e9l\u00e9ment de ce tableau.\n\nExemples :\n\n```python\n>>> maxliste([98, 12, 104, 23, 131, 9])\n131\n>>> maxliste([-27, 24, -3, 15])\n24\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-242","title":"Exercice 24.2 \u25a1","text":"Exercice 24.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn dispose de cha\u00eenes de caract\u00e8res contenant uniquement des parenth\u00e8ses ouvrantes et fermantes.
Un parenth\u00e9sage est correct si :
Ainsi, ((()())(()))
est un parenth\u00e9sage correct.
Les parenth\u00e9sages ())(()
et (())(()
sont, eux, incorrects.
On dispose du code de la classe Pile
suivant :
class Pile:\n\"\"\" Classe d\u00e9finissant une pile \"\"\"\n def __init__(self, valeurs=[]):\n self.valeurs = valeurs\n\n def est_vide(self):\n\"\"\"Renvoie True si la pile est vide, False sinon\"\"\"\n return self.valeurs == []\n\n def empiler(self, c):\n\"\"\"Place l\u2019\u00e9l\u00e9ment c au sommet de la pile\"\"\"\n self.valeurs.append(c)\n\n def depiler(self):\n\"\"\"Supprime l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile, \u00e0 condition qu\u2019elle soit non vide\"\"\"\n if self.est_vide() == False:\n self.valeurs.pop()\n
On souhaite programmer une fonction parenthesage qui prend en param\u00e8tre une cha\u00eene ch de parenth\u00e8ses et renvoie True
si la cha\u00eene est bien parenth\u00e9s\u00e9e et False
sinon. Cette fonction utilise une pile et suit le principe suivant : en parcourant la cha\u00eene de gauche \u00e0 droite, si on trouve une parenth\u00e8se ouvrante, on l\u2019empile au sommet de la pile et si on trouve une parenth\u00e8se fermante, on d\u00e9pile (si possible !) la parenth\u00e8se ouvrante stock\u00e9e au sommet de la pile.
La cha\u00eene est alors bien parenth\u00e9s\u00e9e si, \u00e0 la fin du parcours, la pile est vide.
Elle est, par contre, mal parenth\u00e9s\u00e9e :
def parenthesage(ch):\n\"\"\"Renvoie True si la cha\u00eene ch est bien parenth\u00e9s\u00e9e et False sinon\"\"\"\n p = Pile()\n for c in ch:\n if c == ...:\n p.empiler(c)\n elif c == ...:\n if p.est_vide():\n return ...\n else:\n ...\n return p.est_vide()\n\nassert parenthesage(\"((()())(()))\") == True\nassert parenthesage(\"())(()\") == False\nassert parenthesage(\"(())(()\") == False\n
Compl\u00e9ter le code de la fonction parenthesage
.
class Pile:\n\"\"\" Classe d\u00e9finissant une pile \"\"\"\n def __init__(self, valeurs=[]):\n self.valeurs = valeurs\n\n def est_vide(self):\n\"\"\"Renvoie True si la pile est vide, False sinon\"\"\"\n return self.valeurs == []\n\n def empiler(self, c):\n\"\"\"Place l\u2019\u00e9l\u00e9ment c au sommet de la pile\"\"\"\n self.valeurs.append(c)\n\n def depiler(self):\n\"\"\"Supprime l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile, \u00e0 condition qu\u2019elle soit non vide\"\"\"\n if self.est_vide() == False:\n self.valeurs.pop()\n\ndef parenthesage(ch):\n\"\"\"Renvoie True si la cha\u00eene ch est bien parenth\u00e9s\u00e9e et False sinon\"\"\"\n p = Pile()\n for c in ch:\n if c == '(':\n p.empiler(c)\n elif c == ')':\n if p.est_vide():\n return False\n else:\n p.depiler()\n return p.est_vide()\n\n\nprint(parenthesage(\"((()())(()))\"))\nassert parenthesage(\"((()())(()))\") == True\nassert parenthesage(\"())(()\") == False\nassert parenthesage(\"(())(()\") == False\n
On dispose de cha\u00eenes de caract\u00e8res contenant uniquement des parenth\u00e8ses ouvrantes et\nfermantes. \n\nUn parenth\u00e9sage est correct si :\n\n- le nombre de parenth\u00e8ses ouvrantes de la cha\u00eene est \u00e9gal au nombre de parenth\u00e8ses\nfermantes.\n- en parcourant la cha\u00eene de gauche \u00e0 droite, le nombre de parenth\u00e8ses d\u00e9j\u00e0 ouvertes doit\n\u00eatre, \u00e0 tout moment, sup\u00e9rieur ou \u00e9gal au nombre de parenth\u00e8ses d\u00e9j\u00e0 ferm\u00e9es.\n\n\nAinsi, `((()())(()))` est un parenth\u00e9sage correct. \n\nLes parenth\u00e9sages `())(()` et `(())(()` sont, eux, incorrects.\n\n\nOn dispose du code de la classe `Pile` suivant :\n\n```python linenums='1'\nclass Pile:\n \"\"\" Classe d\u00e9finissant une pile \"\"\"\n def __init__(self, valeurs=[]):\n self.valeurs = valeurs\n\n def est_vide(self):\n \"\"\"Renvoie True si la pile est vide, False sinon\"\"\"\n return self.valeurs == []\n\n def empiler(self, c):\n \"\"\"Place l\u2019\u00e9l\u00e9ment c au sommet de la pile\"\"\"\n self.valeurs.append(c)\n\n def depiler(self):\n \"\"\"Supprime l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile, \u00e0 condition qu\u2019elle soit non vide\"\"\"\n if self.est_vide() == False:\n self.valeurs.pop()\n
On souhaite programmer une fonction parenthesage qui prend en param\u00e8tre une cha\u00eene ch de parenth\u00e8ses et renvoie True
si la cha\u00eene est bien parenth\u00e9s\u00e9e et False
sinon. Cette fonction utilise une pile et suit le principe suivant : en parcourant la cha\u00eene de gauche \u00e0 droite, si on trouve une parenth\u00e8se ouvrante, on l\u2019empile au sommet de la pile et si on trouve une parenth\u00e8se fermante, on d\u00e9pile (si possible !) la parenth\u00e8se ouvrante stock\u00e9e au sommet de la pile.
La cha\u00eene est alors bien parenth\u00e9s\u00e9e si, \u00e0 la fin du parcours, la pile est vide.
Elle est, par contre, mal parenth\u00e9s\u00e9e :
def parenthesage(ch):\n\"\"\"Renvoie True si la cha\u00eene ch est bien parenth\u00e9s\u00e9e et False sinon\"\"\"\n p = Pile()\n for c in ch:\n if c == ...:\n p.empiler(c)\n elif c == ...:\n if p.est_vide():\n return ...\n else:\n ...\n return p.est_vide()\n\nassert parenthesage(\"((()())(()))\") == True\nassert parenthesage(\"())(()\") == False\nassert parenthesage(\"(())(()\") == False\n
Compl\u00e9ter le code de la fonction parenthesage
. ```
Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-251","title":"Exercice 25.1 \u25a1","text":"Exercice 25.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn consid\u00e8re des tables (des tableaux de dictionnaires) qui contiennent des enregistrements relatifs \u00e0 des animaux h\u00e9berg\u00e9s dans un refuge. Les attributs des enregistrements sont 'nom'
, 'espece'
, 'age'
, 'enclos'
. Voici un exemple d'une telle table :
animaux = [ {'nom':'Medor', 'espece':'chien', 'age':5, 'enclos':2},\n {'nom':'Titine', 'espece':'chat', 'age':2, 'enclos':5},\n {'nom':'Tom', 'espece':'chat', 'age':7, 'enclos':4},\n {'nom':'Belle', 'espece':'chien', 'age':6, 'enclos':3},\n {'nom':'Mirza', 'espece':'chat', 'age':6, 'enclos':5}]\n
Programmer une fonction selection_enclos
qui :
table_animaux
contenant des enregistrements relatifs \u00e0 des animaux (comme dans l'exemple ci-dessus),num_enclos
;table_animaux
dont l'attribut 'enclos'
est num_enclos
.Exemples avec la table animaux ci-dessus :
>>> selection_enclos(animaux, 5)\n[{'nom':'Titine', 'espece':'chat', 'age':2, 'enclos':5},\n {'nom':'Mirza', 'espece':'chat', 'age':6, 'enclos':5}]\n\n>>> selection_enclos(animaux, 2)\n[{'nom':'Medor', 'espece':'chien', 'age':5, 'enclos':2}]\n\n>>> selection_enclos(animaux, 7)\n[]\n
def selection_enclos(table_animaux, num_enclos):\n table = []\n for animal in table_animaux:\n if animal['enclos'] == num_enclos:\n table.append(animal)\n return table\n
On consid\u00e8re des tables (des tableaux de dictionnaires) qui contiennent des enregistrements\nrelatifs \u00e0 des animaux h\u00e9berg\u00e9s dans un refuge. Les attributs des enregistrements sont\n`'nom'`, `'espece'`, `'age'`, `'enclos'`. Voici un exemple d'une telle table :\n\n```python\nanimaux = [ {'nom':'Medor', 'espece':'chien', 'age':5, 'enclos':2},\n {'nom':'Titine', 'espece':'chat', 'age':2, 'enclos':5},\n {'nom':'Tom', 'espece':'chat', 'age':7, 'enclos':4},\n {'nom':'Belle', 'espece':'chien', 'age':6, 'enclos':3},\n {'nom':'Mirza', 'espece':'chat', 'age':6, 'enclos':5}]\n```\n\nProgrammer une fonction `selection_enclos` qui :\n\n- prend en param\u00e8tres :\n - une table `table_animaux` contenant des enregistrements relatifs \u00e0 des\nanimaux (comme dans l'exemple ci-dessus),\n - un num\u00e9ro d'enclos `num_enclos` ;\n- renvoie une table contenant les enregistrements de `table_animaux` dont l'attribut\n`'enclos'` est `num_enclos`.\n\nExemples avec la table animaux ci-dessus :\n\n```python\n>>> selection_enclos(animaux, 5)\n[{'nom':'Titine', 'espece':'chat', 'age':2, 'enclos':5},\n {'nom':'Mirza', 'espece':'chat', 'age':6, 'enclos':5}]\n\n>>> selection_enclos(animaux, 2)\n[{'nom':'Medor', 'espece':'chien', 'age':5, 'enclos':2}]\n\n>>> selection_enclos(animaux, 7)\n[]\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-252","title":"Exercice 25.2 \u25a1","text":"Exercice 25.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re des tableaux de nombres dont tous les \u00e9l\u00e9ments sont pr\u00e9sents exactement trois fois et \u00e0 suivre, sauf un \u00e9l\u00e9ment qui est pr\u00e9sent une unique fois et que l'on appelle \u00ab l'intrus \u00bb. Voici quelques exemples :
tab_a = [3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5, 5, 5]\n#l'intrus est 7\n\ntab_b = [8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3]\n#l'intrus est 8\n\ntab_c = [5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8, 8, 8]\n#l'intrus est 3\n
On remarque qu'avec de tels tableaux : Ce que l'on peut observer ci-dessous en observant les valeurs des paires de voisins marqu\u00e9es par des caract\u00e8res ^ :
[3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5, 5, 5]\n ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^\n 0 3 6 9 12 15 18 21\n
Dans des listes comme celles ci-dessus, un algorithme r\u00e9cursif pour trouver l'intrus consiste alors \u00e0 choisir un indice i
multiple de 3 situ\u00e9 approximativement au milieu des indices parmi lesquels se trouve l'intrus.
Puis, en fonction des valeurs de l'\u00e9l\u00e9ment d'indice i
et de son voisin de droite, \u00e0 appliquer r\u00e9cursivement l'algorithme \u00e0 la moiti\u00e9 droite ou \u00e0 la moiti\u00e9 gauche des indices parmi lesquels se trouve l'intrus.
Compl\u00e9ter la fonction ci-dessous qui met en \u0153uvre cet algorithme.
def trouver_intrus(tab, g, d):\n'''\n Renvoie la valeur de l'intrus situ\u00e9 entre les indices g et d \n dans la liste tab o\u00f9 \n tab v\u00e9rifie les conditions de l'exercice,\n g et d sont des multiples de 3.\n '''\n if g == d:\n return ...\n\n else:\n nombre_de_triplets = (d - g) // ...\n indice = g + 3 * (nombre_de_triplets // 2)\n if ... :\n return ...\n else:\n return ...\n
Exemples :
>>> trouver_intrus([3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8,\n8, 5, 5, 5], 0, 21)\n7\n\n>>> trouver_intrus([8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3], 0, 12)\n8\n\n>>> trouver_intrus([5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8, 8, 8], 0, 15)\n3\n
def trouver_intrus(tab, g, d):\n'''\n Renvoie la valeur de l'intrus situ\u00e9 entre les indices g et d \n dans la liste tab o\u00f9 tab v\u00e9rifie les conditions de l'exercice,\n g et d sont des multiples de 3.\n '''\n if g == d:\n return tab[g]\n\n else:\n nombre_de_triplets = (d - g) // 3\n indice = g + 3 * (nombre_de_triplets // 2)\n if tab[indice] != tab[indice + 1] :\n return trouver_intrus(tab, g, indice)\n else:\n return trouver_intrus(tab, indice + 3, d)\n
On consid\u00e8re des tableaux de nombres dont tous les \u00e9l\u00e9ments sont pr\u00e9sents exactement\ntrois fois et \u00e0 suivre, sauf un \u00e9l\u00e9ment qui est pr\u00e9sent une unique fois et que l'on appelle \u00ab\nl'intrus \u00bb. Voici quelques exemples :\n\n```python\ntab_a = [3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5, 5, 5]\n#l'intrus est 7\n\ntab_b = [8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3]\n#l'intrus est 8\n\ntab_c = [5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8, 8, 8]\n#l'intrus est 3\n
On remarque qu'avec de tels tableaux : Ce que l'on peut observer ci-dessous en observant les valeurs des paires de voisins marqu\u00e9es par des caract\u00e8res ^ :
[3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5, 5, 5]\n ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^\n 0 3 6 9 12 15 18 21\n
Dans des listes comme celles ci-dessus, un algorithme r\u00e9cursif pour trouver l'intrus consiste alors \u00e0 choisir un indice i
multiple de 3 situ\u00e9 approximativement au milieu des indices parmi lesquels se trouve l'intrus.
Puis, en fonction des valeurs de l'\u00e9l\u00e9ment d'indice i
et de son voisin de droite, \u00e0 appliquer r\u00e9cursivement l'algorithme \u00e0 la moiti\u00e9 droite ou \u00e0 la moiti\u00e9 gauche des indices parmi lesquels se trouve l'intrus.
Compl\u00e9ter la fonction ci-dessous qui met en \u0153uvre cet algorithme.
def trouver_intrus(tab, g, d):\n'''\n Renvoie la valeur de l'intrus situ\u00e9 entre les indices g et d \n dans la liste tab o\u00f9 \n tab v\u00e9rifie les conditions de l'exercice,\n g et d sont des multiples de 3.\n '''\n if g == d:\n return ...\n\n else:\n nombre_de_triplets = (d - g) // ...\n indice = g + 3 * (nombre_de_triplets // 2)\n if ... :\n return ...\n else:\n return ...\n
Exemples :
>>> trouver_intrus([3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8,\n8, 5, 5, 5], 0, 21)\n7\n\n>>> trouver_intrus([8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3], 0, 12)\n8\n\n>>> trouver_intrus([5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8, 8, 8], 0, 15)\n3\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-26","title":"\u25b6 Sujet 26","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-261","title":"Exercice 26.1 \u25a1","text":"Exercice 26.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction RechercheMin
qui prend en param\u00e8tre un tableau de nombres non tri\u00e9 tab
, et qui renvoie l'indice de la premi\u00e8re occurrence du minimum de ce tableau. Les tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.
Exemples :
>>> RechercheMin([5])\n0\n>>> RechercheMin([2, 4, 1])\n2\n>>> RechercheMin([5, 3, 2, 2, 4])\n2\n
def RechercheMin(tab):\n indice_min = 0\n for i in range(len(tab)):\n if tab[i] < tab[indice_min]:\n indice_min = i\n return indice_min\n
\u00c9crire une fonction `RechercheMin` qui prend en param\u00e8tre un tableau de nombres non\ntri\u00e9 `tab`, et qui renvoie l'indice de la premi\u00e8re occurrence du minimum de ce tableau. Les\ntableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.\n\nExemples :\n```python\n>>> RechercheMin([5])\n0\n>>> RechercheMin([2, 4, 1])\n2\n>>> RechercheMin([5, 3, 2, 2, 4])\n2\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-262","title":"Exercice 26.2 \u25a1","text":"Exercice 26.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re la fonction separe
ci-dessous qui prend en argument un tableau tab
dont les \u00e9l\u00e9ments sont des 0
et des 1
et qui s\u00e9pare les 0
des 1
en pla\u00e7ant les 0
en d\u00e9but de tableau et les 1
\u00e0 la suite.
def separe(tab):\n i = 0\n j = ...\n while i < j :\n if tab[i] == 0 :\n i = ...\n else :\n tab[i], tab[j] = ...\n j = ...\n return tab\n
Compl\u00e9ter la fonction separe
ci-dessus.
Exemples :
>>> separe([1, 0, 1, 0, 1, 0, 1, 0])\n[0, 0, 0, 0, 1, 1, 1, 1]\n>>> separe([1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0])\n[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\n
def separe(tab):\n i = 0\n j = len(tab) - 1\n while i < j :\n if tab[i] == 0 :\n i = i + 1\n else :\n tab[i], tab[j] = tab[j], tab[i]\n j = j - 1\n return tab\n
On consid\u00e8re la fonction `separe` ci-dessous qui prend en argument un tableau `tab` dont\nles \u00e9l\u00e9ments sont des `0` et des `1` et qui s\u00e9pare les `0` des `1` en pla\u00e7ant les `0` en d\u00e9but de\ntableau et les `1` \u00e0 la suite.\n\n```python linenums='1'\ndef separe(tab):\n i = 0\n j = ...\n while i < j :\n if tab[i] == 0 :\n i = ...\n else :\n tab[i], tab[j] = ...\n j = ...\n return tab\n
Compl\u00e9ter la fonction separe
ci-dessus.
Exemples :
>>> separe([1, 0, 1, 0, 1, 0, 1, 0])\n[0, 0, 0, 0, 1, 1, 1, 1]\n>>> separe([1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0])\n[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-27","title":"\u25b6 Sujet 27","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-271","title":"Exercice 27.1 \u25a1","text":"Exercice 27.1
\u00c9nonc\u00e9CorrectionSource MarkdownDans cet exercice, un arbre binaire de caract\u00e8res est stock\u00e9 sous la forme d\u2019un dictionnaire o\u00f9 les clefs sont les caract\u00e8res des n\u0153uds de l\u2019arbre et les valeurs, pour chaque clef, la liste des caract\u00e8res des fils gauche et droit du n\u0153ud.
Par exemple, l\u2019arbre
est stock\u00e9 dans
a = {'F':['B','G'], 'B':['A','D'], 'A':['',''], 'D':['C','E'], \\\n'C':['',''], 'E':['',''], 'G':['','I'], 'I':['','H'], \\\n'H':['','']}\n
\u00c9crire une fonction r\u00e9cursive taille
prenant en param\u00e8tres un arbre binaire arbre
sous la forme d\u2019un dictionnaire et un caract\u00e8re lettre
qui est la valeur du sommet de l\u2019arbre, et qui renvoie la taille de l\u2019arbre \u00e0 savoir le nombre total de n\u0153ud. On pourra distinguer les 4 cas o\u00f9 les deux \u00ab fils \u00bb du n\u0153ud sont ''
, le fils gauche seulement est ''
, le fils droit seulement est ''
, aucun des deux fils n\u2019est ''
.
Exemple :
>>> taille(a, \u2019F\u2019)\n9\n
a = {'F':['B','G'], 'B':['A','D'], 'A':['',''], 'D':['C','E'], 'C':['',''], 'E':['',''], 'G':['','I'], 'I':['','H'], 'H':['','']}\n\ndef taille(arbre, lettre):\n fils_gauche = arbre[lettre][0]\n fils_droit = arbre[lettre][1]\n\n if fils_gauche != '' and fils_droit != '':\n return 1 + taille(arbre, fils_gauche) + taille(arbre, fils_droit)\n\n if fils_gauche != '' and fils_droit == '':\n return 1 + taille(arbre, fils_gauche)\n\n if fils_gauche == '' and fils_droit != '':\n return 1 + taille(arbre, fils_droit)\n\n else:\n return 1\n
Dans cet exercice, un arbre binaire de caract\u00e8res est stock\u00e9 sous la forme d\u2019un\ndictionnaire o\u00f9 les clefs sont les caract\u00e8res des n\u0153uds de l\u2019arbre et les valeurs, pour\nchaque clef, la liste des caract\u00e8res des fils gauche et droit du n\u0153ud.\n\nPar exemple, l\u2019arbre\n\n![image](data/img28_1.png){: .center width=40%}\n\nest stock\u00e9 dans\n\n```python\na = {'F':['B','G'], 'B':['A','D'], 'A':['',''], 'D':['C','E'], \\\n'C':['',''], 'E':['',''], 'G':['','I'], 'I':['','H'], \\\n'H':['','']}\n```\n\n\u00c9crire une fonction r\u00e9cursive `taille` prenant en param\u00e8tres un arbre binaire `arbre`\nsous la forme d\u2019un dictionnaire et un caract\u00e8re `lettre` qui est la valeur du sommet de\nl\u2019arbre, et qui renvoie la taille de l\u2019arbre \u00e0 savoir le nombre total de n\u0153ud.\nOn pourra distinguer les 4 cas o\u00f9 les deux \u00ab fils \u00bb du n\u0153ud sont `''`, le fils gauche\nseulement est `''`, le fils droit seulement est `''`, aucun des deux fils n\u2019est `''`.\n\nExemple :\n```python\n>>> taille(a, \u2019F\u2019)\n9\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-272","title":"Exercice 27.2 \u25a1","text":"Exercice 27.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re l'algorithme de tri de tableau suivant : \u00e0 chaque \u00e9tape, on parcourt depuis le d\u00e9but du tableau tous les \u00e9l\u00e9ments non rang\u00e9s et on place en derni\u00e8re position le plus grand \u00e9l\u00e9ment.
Exemple avec le tableau : t = [41, 55, 21, 18, 12, 6, 25]
Le tableau devient t = [41, 25, 21, 18, 12, 6, 55]
Le tableau devient : t = [6, 25, 21, 18, 12, 41, 55]
Et ainsi de suite. La code de la fonction tri_iteratif
qui impl\u00e9mente cet algorithme est donn\u00e9 ci- dessous.
def tri_iteratif(tab):\n for k in range(..., 0 ,-1):\n imax = ...\n for i in range(0, ...):\n if tab[i] > ... :\n imax = i\n if tab[imax] > ... :\n ..., tab[imax] = tab[imax], ...\n return tab\n
Compl\u00e9ter le code qui doit donner :
>>> tri_iteratif([41, 55, 21, 18, 12, 6, 25])\n[6, 12, 18, 21, 25, 41, 55]\n
On rappelle que l'instruction a, b = b, a
\u00e9change les contenus de a
et b
.
def tri_iteratif(tab):\n for k in range(len(tab)-1, 0, -1):\n imax = 0\n for i in range(0, k):\n if tab[i] > tab[imax] :\n imax = i\n if tab[imax] > tab[k] :\n tab[k], tab[imax] = tab[imax], tab[k] \n return tab\n
On consid\u00e8re l'algorithme de tri de tableau suivant : \u00e0 chaque \u00e9tape, on parcourt depuis\nle d\u00e9but du tableau tous les \u00e9l\u00e9ments non rang\u00e9s et on place en derni\u00e8re position le plus\ngrand \u00e9l\u00e9ment.\n\nExemple avec le tableau : ```t = [41, 55, 21, 18, 12, 6, 25]``` \n\n- \u00c9tape 1 : on parcourt tous les \u00e9l\u00e9ments du tableau, on permute le plus grand \u00e9l\u00e9ment avec le dernier.\n\nLe tableau devient `t = [41, 25, 21, 18, 12, 6, 55]`\n\n- \u00c9tape 2 : on parcourt tous les \u00e9l\u00e9ments **sauf le dernier**, on permute le plus grand \u00e9l\u00e9ment trouv\u00e9 avec l'avant dernier.\n\nLe tableau devient : ```t = [6, 25, 21, 18, 12, 41, 55]``` \n\nEt ainsi de suite. La code de la fonction `tri_iteratif` qui impl\u00e9mente cet algorithme est donn\u00e9 ci-\ndessous.\n\n```python linenums='1'\ndef tri_iteratif(tab):\n for k in range(..., 0 ,-1):\n imax = ...\n for i in range(0, ...):\n if tab[i] > ... :\n imax = i\n if tab[imax] > ... :\n ..., tab[imax] = tab[imax], ...\n return tab\n
Compl\u00e9ter le code qui doit donner :
>>> tri_iteratif([41, 55, 21, 18, 12, 6, 25])\n[6, 12, 18, 21, 25, 41, 55]\n
On rappelle que l'instruction a, b = b, a
\u00e9change les contenus de a
et b
. ```
Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-281","title":"Exercice 28.1 \u25a1","text":"Exercice 28.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction moyenne
qui prend en param\u00e8tre un tableau non vide de nombres flottants et qui renvoie la moyenne des valeurs du tableau. Les tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.
Exemples :
>>> moyenne([1.0])\n1.0\n>>> moyenne([1.0, 2.0, 4.0])\n2.3333333333333335\n
def moyenne(tab):\n somme = 0\n for val in tab:\n somme += val\n return somme / len(tab)\n
\u00c9crire une fonction `moyenne` qui prend en param\u00e8tre un tableau non vide de nombres\nflottants et qui renvoie la moyenne des valeurs du tableau. Les tableaux seront\nrepr\u00e9sent\u00e9s sous forme de liste Python.\n\nExemples :\n```python\n>>> moyenne([1.0])\n1.0\n>>> moyenne([1.0, 2.0, 4.0])\n2.3333333333333335\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-282","title":"Exercice 28.2 \u25a1","text":"Exercice 28.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re la fonction dec_to_bin
ci-dessous qui prend en param\u00e8tre un entier positif a
en \u00e9criture d\u00e9cimale et qui renvoie son \u00e9criture binaire sous la forme d'une chaine de caract\u00e8res.
def dec_to_bin(a):\n bin_a = ...\n a = a//2\n while a ... :\n bin_a = ... + bin_a\n a = ...\n return bin_a\n
Compl\u00e9ter la fonction dec_to_bin
. Exemples :
>>> dec_to_bin(83)\n'1010011'\n>>> dec_to_bin(127)\n'1111111'\n
def dec_to_bin(a):\n bin_a = str(a%2)\n a = a // 2\n while a != 0 :\n bin_a = str(a%2) + bin_a\n a = a // 2\n return bin_a\n
On consid\u00e8re la fonction `dec_to_bin` ci-dessous qui prend en param\u00e8tre un entier positif `a` en \u00e9criture d\u00e9cimale et qui renvoie son \u00e9criture binaire sous la forme d'une chaine de caract\u00e8res.\n\n```python linenums='1'\ndef dec_to_bin(a):\n bin_a = ...\n a = a//2\n while a ... :\n bin_a = ... + bin_a\n a = ...\n return bin_a\n
Compl\u00e9ter la fonction dec_to_bin
. Exemples :
>>> dec_to_bin(83)\n'1010011'\n>>> dec_to_bin(127)\n'1111111'\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-29","title":"\u25b6 Sujet 29","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-291","title":"Exercice 29.1 \u25a1","text":"Exercice 29.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn s\u2019int\u00e9resse \u00e0 la suite d\u2019entiers d\u00e9finie par U1 = 1
, U2 = 1
et, pour tout entier naturel n
, par Un+2 = Un+1 + Un
.
Elle s\u2019appelle la suite de Fibonacci.
\u00c9crire la fonction fibonacci
qui prend un entier n > 0
et qui renvoie l\u2019\u00e9l\u00e9ment d\u2019indice n
de cette suite.
On utilisera une programmation dynamique (pas de r\u00e9cursivit\u00e9).
Exemple :
>>> fibonacci(1)\n1\n>>> fibonacci(2)\n1\n>>> fibonacci(25)\n75025\n>>> fibonacci(45)\n1134903170\n
On utilise un dictionnaire pour stocker au fur et \u00e0 mesure les valeurs.
def fibonnaci(n):\n d = {}\n d[1] = 1\n d[2] = 1\n for k in range(3, n+1):\n d[k] = d[k-1] + d[k-2]\n return d[n]\n
On s\u2019int\u00e9resse \u00e0 la suite d\u2019entiers d\u00e9finie par\n`U1 = 1`, `U2 = 1` et, pour tout entier naturel `n`, par `Un+2 = Un+1 + Un`.\n\nElle s\u2019appelle la suite de Fibonacci.\n\n\u00c9crire la fonction `fibonacci` qui prend un entier `n > 0` et qui renvoie l\u2019\u00e9l\u00e9ment d\u2019indice\n`n` de cette suite.\n\nOn utilisera une programmation dynamique (pas de r\u00e9cursivit\u00e9).\n\nExemple :\n\n```python\n>>> fibonacci(1)\n1\n>>> fibonacci(2)\n1\n>>> fibonacci(25)\n75025\n>>> fibonacci(45)\n1134903170\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-292","title":"Exercice 29.2 \u25a1","text":"Exercice 29.2
\u00c9nonc\u00e9CorrectionSources MarkdownLes variables liste_eleves
et liste_notes
ayant \u00e9t\u00e9 pr\u00e9alablement d\u00e9finies et \u00e9tant de m\u00eame longueur, la fonction meilleures_notes
renvoie la note maximale qui a \u00e9t\u00e9 attribu\u00e9e, le nombre d\u2019\u00e9l\u00e8ves ayant obtenu cette note et la liste des noms de ces \u00e9l\u00e8ves.
Compl\u00e9ter le code Python de la fonction meilleures_notes
ci-dessous.
liste_eleves = ['a','b','c','d','e','f','g','h','i','j']\nliste_notes = [1, 40, 80, 60, 58, 80, 75, 80, 60, 24]\n\ndef meilleures_notes():\n note_maxi = 0\n nb_eleves_note_maxi = ...\n liste_maxi = ...\n\n for compteur in range(...):\n if liste_notes[compteur] == ...:\n nb_eleves_note_maxi = nb_eleves_note_maxi + 1\n liste_maxi.append(liste_eleves[...])\n if liste_notes[compteur] > note_maxi:\n note_maxi = liste_notes[compteur]\n nb_eleves_note_maxi = ...\n liste_maxi = [...]\n\n return (note_maxi,nb_eleves_note_maxi,liste_maxi)\n
Une fois compl\u00e9t\u00e9, le code ci-dessus donne
>>> meilleures_notes()\n(80, 3, ['c', 'f', 'h'])\n
liste_eleves = ['a','b','c','d','e','f','g','h','i','j']\nliste_notes = [1, 40, 80, 60, 58, 80, 75, 80, 60, 24]\n\ndef meilleures_notes():\n note_maxi = 0\n nb_eleves_note_maxi = 0\n liste_maxi = []\n\n for compteur in range(len(liste_eleves)):\n if liste_notes[compteur] == note_maxi:\n nb_eleves_note_maxi = nb_eleves_note_maxi + 1\n liste_maxi.append(liste_eleves[compteur])\n if liste_notes[compteur] > note_maxi:\n note_maxi = liste_notes[compteur]\n nb_eleves_note_maxi = 1\n liste_maxi = [liste_eleves[compteur]]\n\n return (note_maxi,nb_eleves_note_maxi,liste_maxi)\n
Les variables `liste_eleves` et `liste_notes` ayant \u00e9t\u00e9 pr\u00e9alablement d\u00e9finies et \u00e9tant\nde m\u00eame longueur, la fonction `meilleures_notes` renvoie la note maximale qui a \u00e9t\u00e9\nattribu\u00e9e, le nombre d\u2019\u00e9l\u00e8ves ayant obtenu cette note et la liste des noms de ces \u00e9l\u00e8ves.\n\nCompl\u00e9ter le code Python de la fonction `meilleures_notes` ci-dessous.\n\n```python linenums='1'\nliste_eleves = ['a','b','c','d','e','f','g','h','i','j']\nliste_notes = [1, 40, 80, 60, 58, 80, 75, 80, 60, 24]\n\ndef meilleures_notes():\n note_maxi = 0\n nb_eleves_note_maxi = ...\n liste_maxi = ...\n\n for compteur in range(...):\n if liste_notes[compteur] == ...:\n nb_eleves_note_maxi = nb_eleves_note_maxi + 1\n liste_maxi.append(liste_eleves[...])\n if liste_notes[compteur] > note_maxi:\n note_maxi = liste_notes[compteur]\n nb_eleves_note_maxi = ...\n liste_maxi = [...]\n\n return (note_maxi,nb_eleves_note_maxi,liste_maxi)\n
Une fois compl\u00e9t\u00e9, le code ci-dessus donne
>>> meilleures_notes()\n(80, 3, ['c', 'f', 'h'])\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-30","title":"\u25b6 Sujet 30","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-301","title":"Exercice 30.1 \u25a1","text":"Exercice 30.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction fusion
prenant en param\u00e8tres deux tableaux non vides tab1
et tab2
(type list
) d'entiers, chacun dans l\u2019ordre croissant, et renvoyant un tableau tri\u00e9 dans l\u2019ordre croissant et contenant l\u2019ensemble des valeurs de tab1
et tab2
.
Exemples :
>>> fusion([3, 5], [2, 5])\n[2, 3, 5, 5]\n>>> fusion([-2, 4], [-3, 5, 10])\n[-3, -2, 4, 5, 10]\n>>> fusion([4], [2, 6])\n[2, 4, 6]\n
def fusion(tab1, tab2):\n tab_fusion = []\n i1 = 0\n i2 = 0\n while i1 < len(tab1) and i2 < len(tab2):\n if tab1[i1] < tab2[i2]:\n tab_fusion.append(tab1[i1])\n i1 += 1\n else:\n tab_fusion.append(tab2[i2])\n i2 += 1\n\n if i1 == len(tab1):\n while i2 < len(tab2):\n tab_fusion.append(tab2[i2])\n i2 += 1\n else:\n while i1 < len(tab1):\n tab_fusion.append(tab1[i1])\n i1 += 1 \n\n return tab_fusion\n
Programmer la fonction `fusion` prenant en param\u00e8tres deux tableaux non vides `tab1` et `tab2`\n(type `list`) d'entiers, chacun dans l\u2019ordre croissant, et renvoyant un tableau tri\u00e9 dans l\u2019ordre\ncroissant et contenant l\u2019ensemble des valeurs de `tab1` et `tab2`.\n\nExemples :\n\n```python\n>>> fusion([3, 5], [2, 5])\n[2, 3, 5, 5]\n>>> fusion([-2, 4], [-3, 5, 10])\n[-3, -2, 4, 5, 10]\n>>> fusion([4], [2, 6])\n[2, 4, 6]\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-302","title":"Exercice 30.2 \u25a1","text":"Exercice 30.2
\u00c9nonc\u00e9CorrectionSources MarkdownLes chiffres romains sont un syst\u00e8me ancien d\u2019\u00e9criture des nombres.
Les chiffres romains sont: I, V, X, L, C, D, et M. Ces symboles repr\u00e9sentent respectivement 1, 5, 10, 50, 100, 500, et 1000 en base dix.
Lorsque deux caract\u00e8res successifs sont tels que le caract\u00e8re plac\u00e9 \u00e0 gauche poss\u00e8de une valeur sup\u00e9rieure ou \u00e9gale \u00e0 celui de droite, le nombre s\u2019obtient en additionnant le caract\u00e8re de gauche \u00e0 la valeur de la cha\u00eene situ\u00e9e \u00e0 droite.
Ainsi, \"XVI\" est le nombre 16 car X + VI = 10 + 6.
Lorsque deux caract\u00e8res successifs sont tels que le caract\u00e8re plac\u00e9 \u00e0 gauche poss\u00e8de une valeur strictement inf\u00e9rieure \u00e0 celui de droite, le nombre s\u2019obtient en retranchant le caract\u00e8re de gauche \u00e0 la valeur de la cha\u00eene situ\u00e9e \u00e0 droite.
Ainsi, \"CDIII\" est le nombre 403 car DIII \u2013 C = 503 \u2013 100.
On dispose d\u2019un dictionnaire dico
, \u00e0 compl\u00e9ter, o\u00f9 les cl\u00e9s sont les caract\u00e8res apparaissant dans l\u2019\u00e9criture en chiffres romains et o\u00f9 les valeurs sont les nombres entiers associ\u00e9s en \u00e9criture d\u00e9cimale.
On souhaite cr\u00e9er une fonction r\u00e9cursive rom_to_dec
qui prend en param\u00e8tre une cha\u00eene de caract\u00e8res (non vide) repr\u00e9sentant un nombre \u00e9crit en chiffres romains et renvoyant le nombre associ\u00e9 en \u00e9criture d\u00e9cimale :
def rom_to_dec(nombre):\n\n\"\"\" Renvoie l\u2019\u00e9criture d\u00e9cimale du nombre donn\u00e9 en chiffres romains \"\"\"\n\n dico = {\"I\":1, \"V\":5, ...}\n if len(nombre) == 1:\n return ...\n\n else:\n ### on supprime le premier caract\u00e8re de la cha\u00eene contenue dans la variable nombre\n ### et cette nouvelle cha\u00eene est enregistr\u00e9e dans la variable nombre_droite\n nombre_droite = nombre[1:]\n\n\n if dico[nombre[0]] >= dico[nombre[1]]:\n return dico[nombre[0]] + ...\n else:\n return ...\n\nassert rom_to_dec(\"CXLII\") == 142\n
def rom_to_dec(nombre):\n\n\"\"\" Renvoie l\u2019\u00e9criture d\u00e9cimale du nombre donn\u00e9 en chiffres romains \"\"\"\n\n dico = {\"I\":1, \"V\":5, \"X\":10, \"L\":50, \"C\":100, \"D\":500, \"M\":1000}\n if len(nombre) == 1:\n return dico[nombre]\n\n else:\n ### on supprime le premier caract\u00e8re de la cha\u00eene contenue dans la variable nombre\n ### et cette nouvelle cha\u00eene est enregistr\u00e9e dans la variable nombre_droite\n nombre_droite = nombre[1:] # (1)\n\n\n if dico[nombre[0]] >= dico[nombre[1]]:\n return dico[nombre[0]] + rom_to_dec(nombre_droite)\n else:\n return rom_to_dec(nombre_droite) - dico[nombre[0]]\n\nassert rom_to_dec(\"CXLII\") == 142\n
Les chiffres romains sont un syst\u00e8me ancien d\u2019\u00e9criture des nombres.\n\n\nLes chiffres romains sont: I, V, X, L, C, D, et M.\nCes symboles repr\u00e9sentent respectivement 1, 5, 10, 50, 100, 500, et 1000 en base dix.\n\n\nLorsque deux caract\u00e8res successifs sont tels que le caract\u00e8re plac\u00e9 \u00e0 gauche poss\u00e8de une\nvaleur sup\u00e9rieure ou \u00e9gale \u00e0 celui de droite, le nombre s\u2019obtient en additionnant le caract\u00e8re de\ngauche \u00e0 la valeur de la cha\u00eene situ\u00e9e \u00e0 droite.\n\nAinsi, \"XVI\" est le nombre 16 car X + VI = 10 + 6.\n\n\nLorsque deux caract\u00e8res successifs sont tels que le caract\u00e8re plac\u00e9 \u00e0 gauche poss\u00e8de une\nvaleur strictement inf\u00e9rieure \u00e0 celui de droite, le nombre s\u2019obtient en retranchant le caract\u00e8re de\ngauche \u00e0 la valeur de la cha\u00eene situ\u00e9e \u00e0 droite.\n\n\nAinsi, \"CDIII\" est le nombre 403 car DIII \u2013 C = 503 \u2013 100.\n\n\nOn dispose d\u2019un dictionnaire `dico`, \u00e0 compl\u00e9ter, o\u00f9 les cl\u00e9s sont les caract\u00e8res apparaissant\ndans l\u2019\u00e9criture en chiffres romains et o\u00f9 les valeurs sont les nombres entiers associ\u00e9s en\n\u00e9criture d\u00e9cimale.\n\n\nOn souhaite cr\u00e9er une fonction r\u00e9cursive `rom_to_dec` qui prend en param\u00e8tre une cha\u00eene de\ncaract\u00e8res (non vide) repr\u00e9sentant un nombre \u00e9crit en chiffres romains et renvoyant le nombre\nassoci\u00e9 en \u00e9criture d\u00e9cimale :\n\n```python linenums='1'\ndef rom_to_dec(nombre):\n\n \"\"\" Renvoie l\u2019\u00e9criture d\u00e9cimale du nombre donn\u00e9 en chiffres romains \"\"\"\n\n dico = {\"I\":1, \"V\":5, ...}\n if len(nombre) == 1:\n return ...\n\n else:\n ### on supprime le premier caract\u00e8re de la cha\u00eene contenue dans la variable nombre\n ### et cette nouvelle cha\u00eene est enregistr\u00e9e dans la variable nombre_droite\n nombre_droite = nombre[1:]\n\n\n if dico[nombre[0]] >= dico[nombre[1]]:\n return dico[nombre[0]] + ...\n else:\n return ...\n\nassert rom_to_dec(\"CXLII\") == 142\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-31","title":"\u25b6 Sujet 31","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-311","title":"Exercice 31.1 \u25a1","text":"Exercice 31.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire en langage Python une fonction recherche
prenant comme param\u00e8tres une variable a
de type num\u00e9rique (float
ou int
) et un tableau t
(type list
) et qui renvoie le nombre d'occurrences de a
dans t
.
Exemples :
>>> recherche(5,[])\n0\n>>> recherche(5,[-2, 3, 4, 8])\n0\n>>> recherche(5,[-2, 3, 1, 5, 3, 7, 4])\n1\n>>> recherche(5,[-2, 5, 3, 5, 4, 5])\n3\n
def recherche(a, t):\n nb = 0\n for element in t:\n if element == a:\n nb += 1\n return nb\n
\u00c9crire en langage Python une fonction `recherche` prenant comme param\u00e8tres une\nvariable `a` de type num\u00e9rique (`float` ou `int`) et un tableau `t` (type `list`) et qui\nrenvoie le nombre d'occurrences de `a` dans `t`.\n\nExemples :\n```python\n>>> recherche(5,[])\n0\n>>> recherche(5,[-2, 3, 4, 8])\n0\n>>> recherche(5,[-2, 3, 1, 5, 3, 7, 4])\n1\n>>> recherche(5,[-2, 5, 3, 5, 4, 5])\n3\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-312","title":"Exercice 31.2 \u25a1","text":"Exercice 31.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa fonction rendu_monnaie_centimes
prend en param\u00e8tres deux nombres entiers positifs s_due
ets_versee
et elle permet de proc\u00e9der au rendu de monnaie de la diff\u00e9rence s_versee \u2013 s_due
pour des achats effectu\u00e9s avec le syst\u00e8me de pi\u00e8ces de la zone Euro. On utilise pour cela un algorithme qui commence par rendre le maximum de pi\u00e8ces de plus grandes valeurs et ainsi de suite. La fonction renvoie la liste des pi\u00e8ces qui composent le rendu.
Toutes les sommes sont exprim\u00e9es en centimes d\u2019euros. Les valeurs possibles pour les pi\u00e8ces sont donc [1, 2, 5, 10, 20, 50, 100, 200]
.
Ainsi, l\u2019instruction rendu_monnaie_centimes(452, 500)
renverra [20, 20, 5, 2, 1]
.
En effet, la somme \u00e0 rendre est de 48
centimes soit 20 + 20 + 5 + 2 + 1
. Le code de la fonction est donn\u00e9 ci-dessous :
def rendu_monnaie_centimes(s_due, s_versee):\n pieces = [1, 2, 5, 10, 20, 50, 100, 200]\n rendu = ...\n a_rendre = ...\n i = len(pieces) - 1\n while a_rendre > ... :\n if pieces[i] <= a_rendre :\n rendu.append(...)\n a_rendre = ...\n else :\n i = ...\n return rendu\n
Compl\u00e9ter ce code pour qu'il donne :
>>> rendu_monnaie_centimes(700,700)\n[]\n>>> rendu_monnaie_centimes(112,500)\n[200, 100, 50, 20, 10, 5, 2, 1]\n
def rendu_monnaie_centimes(s_due, s_versee):\n pieces = [1, 2, 5, 10, 20, 50, 100, 200]\n rendu = []\n a_rendre = s_versee - s_due\n i = len(pieces) - 1\n while a_rendre > 0 :\n if pieces[i] <= a_rendre :\n rendu.append(pieces[i])\n a_rendre = a_rendre - pieces[i]\n else :\n i = i - 1\n return rendu\n
La fonction `rendu_monnaie_centimes` prend en param\u00e8tres deux nombres entiers\npositifs `s_due` et` s_versee` et elle permet de proc\u00e9der au rendu de monnaie de la\ndiff\u00e9rence `s_versee \u2013 s_due` pour des achats effectu\u00e9s avec le syst\u00e8me de pi\u00e8ces de\nla zone Euro. On utilise pour cela un algorithme qui commence par rendre le maximum de\npi\u00e8ces de plus grandes valeurs et ainsi de suite. La fonction renvoie la liste des pi\u00e8ces qui\ncomposent le rendu.\n\nToutes les sommes sont exprim\u00e9es en centimes d\u2019euros. Les valeurs possibles pour les\npi\u00e8ces sont donc `[1, 2, 5, 10, 20, 50, 100, 200]`.\n\nAinsi, l\u2019instruction `rendu_monnaie_centimes(452, 500)`\nrenverra\n`[20, 20, 5, 2, 1]`.\n\nEn effet, la somme \u00e0 rendre est de `48` centimes soit `20 + 20 + 5 + 2 + 1`.\nLe code de la fonction est donn\u00e9 ci-dessous :\n\n```python linenums='1'\ndef rendu_monnaie_centimes(s_due, s_versee):\n pieces = [1, 2, 5, 10, 20, 50, 100, 200]\n rendu = ...\n a_rendre = ...\n i = len(pieces) - 1\n while a_rendre > ... :\n if pieces[i] <= a_rendre :\n rendu.append(...)\n a_rendre = ...\n else :\n i = ...\n return rendu\n
Compl\u00e9ter ce code pour qu'il donne :
>>> rendu_monnaie_centimes(700,700)\n[]\n>>> rendu_monnaie_centimes(112,500)\n[200, 100, 50, 20, 10, 5, 2, 1]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-32","title":"\u25b6 Sujet 32","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-321","title":"Exercice 32.1 \u25a1","text":"Exercice 32.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche
qui prend en param\u00e8tres elt
un nombre entier et tab
un tableau de nombres entiers, et qui renvoie l\u2019indice de la premi\u00e8re occurrence de elt
dans tab
si elt
est dans tab
et -1
sinon.
Exemples :
>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(50, [1, 50, 1])\n1\n>>> recherche(15, [8, 9, 10, 15])\n3\n
def recherche(elt, tab):\n for i in range(len(tab)):\n if tab[i] == elt:\n return i\n return -1\n
\u00c9crire une fonction `recherche` qui prend en param\u00e8tres `elt` un nombre entier et `tab`\nun tableau de nombres entiers, et qui renvoie l\u2019indice de la premi\u00e8re occurrence de `elt`\ndans `tab` si `elt` est dans `tab` et `-1` sinon.\n\nExemples :\n```python\n>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(50, [1, 50, 1])\n1\n>>> recherche(15, [8, 9, 10, 15])\n3\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-322","title":"Exercice 32.2 \u25a1","text":"Exercice 32.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn d\u00e9finit une classe g\u00e9rant une adresse IPv4. On rappelle qu\u2019une adresse IPv4 est une adresse de longueur 4 octets, not\u00e9e en d\u00e9cimale \u00e0 point, en s\u00e9parant chacun des octets par un point. On consid\u00e8re un r\u00e9seau priv\u00e9 avec une plage d\u2019adresses IP de 192.168.0.0
\u00e0 192.168.0.255
.
On consid\u00e8re que les adresses IP saisies sont valides.
Les adresses IP 192.168.0.0
et 192.168.0.255
sont des adresses r\u00e9serv\u00e9es.
Le code ci-dessous impl\u00e9mente la classe AdresseIP
.
class AdresseIP:\n def __init__(self, adresse):\n self.adresse = ...\n\n def liste_octet(self):\n\"\"\"renvoie une liste de nombres entiers,\n la liste des octets de l'adresse IP\"\"\"\n return [int(i) for i in self.adresse.split(\".\")]\n\n def est_reservee(self):\n\"\"\"renvoie True si l'adresse IP est une adresse\n r\u00e9serv\u00e9e, False sinon\"\"\"\n return ... or ...\n\n def adresse_suivante(self):\n\"\"\"renvoie un objet de AdresseIP avec l'adresse\n IP qui suit l\u2019adresse self\n si elle existe et False sinon\"\"\"\n if ... < 254:\n octet_nouveau = ... + ...\n return AdresseIP('192.168.0.' + ...)\n else:\n return False\n
Compl\u00e9ter le code ci-dessus et instancier trois objets : adresse1
, adresse2
, adresse3
avec respectivement les arguments suivants : '192.168.0.1'
, '192.168.0.2'
, '192.168.0.0'
V\u00e9rifier que :
>>> adresse1.est_reservee()\nFalse\n>>> adresse3.est_reservee()\nTrue\n>>> adresse2.adresse_suivante().adresse\n'192.168.0.3'\n
class AdresseIP:\n def __init__(self, adresse):\n self.adresse = adresse\n\n def liste_octet(self):\n\"\"\"renvoie une liste de nombres entiers,\n la liste des octets de l'adresse IP\"\"\"\n return [int(i) for i in self.adresse.split(\".\")]\n\n def est_reservee(self):\n\"\"\"renvoie True si l'adresse IP est une adresse\n r\u00e9serv\u00e9e, False sinon\"\"\"\n return self.liste_octet()[3] == 0 or self.liste_octet()[3] == 255\n\n def adresse_suivante(self):\n\"\"\"renvoie un objet de AdresseIP avec l'adresse\n IP qui suit l\u2019adresse self\n si elle existe et False sinon\"\"\"\n if self.liste_octet()[3] < 254:\n octet_nouveau = self.liste_octet()[3] + 1\n return AdresseIP('192.168.0.' + str(octet_nouveau))\n else:\n return False\n\nadresse1 = AdresseIP('192.168.0.1')\nadresse2 = AdresseIP('192.168.0.2')\nadresse3 = AdresseIP('192.168.0.0')\n
On d\u00e9finit une classe g\u00e9rant une adresse IPv4.\nOn rappelle qu\u2019une adresse IPv4 est une adresse de longueur 4 octets, not\u00e9e en d\u00e9cimale\n\u00e0 point, en s\u00e9parant chacun des octets par un point. On consid\u00e8re un r\u00e9seau priv\u00e9 avec\nune plage d\u2019adresses IP de `192.168.0.0` \u00e0 `192.168.0.255`.\n\nOn consid\u00e8re que les adresses IP saisies sont valides.\n\nLes adresses IP `192.168.0.0` et `192.168.0.255` sont des adresses r\u00e9serv\u00e9es.\n\nLe code ci-dessous impl\u00e9mente la classe `AdresseIP`.\n\n```python linenums='1'\nclass AdresseIP:\n def __init__(self, adresse):\n self.adresse = ...\n\n def liste_octet(self):\n \"\"\"renvoie une liste de nombres entiers,\n la liste des octets de l'adresse IP\"\"\"\n return [int(i) for i in self.adresse.split(\".\")]\n\n def est_reservee(self):\n \"\"\"renvoie True si l'adresse IP est une adresse\n r\u00e9serv\u00e9e, False sinon\"\"\"\n return ... or ...\n\n def adresse_suivante(self):\n \"\"\"renvoie un objet de AdresseIP avec l'adresse\n IP qui suit l\u2019adresse self\n si elle existe et False sinon\"\"\"\n if ... < 254:\n octet_nouveau = ... + ...\n return AdresseIP('192.168.0.' + ...)\n else:\n return False\n
Compl\u00e9ter le code ci-dessus et instancier trois objets : adresse1
, adresse2
, adresse3
avec respectivement les arguments suivants : '192.168.0.1'
, '192.168.0.2'
, '192.168.0.0'
V\u00e9rifier que :
>>> adresse1.est_reservee()\nFalse\n>>> adresse3.est_reservee()\nTrue\n>>> adresse2.adresse_suivante().adresse\n'192.168.0.3'\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-33","title":"\u25b6 Sujet 33","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-331","title":"Exercice 33.1 \u25a1","text":"Exercice 33.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn mod\u00e9lise la repr\u00e9sentation binaire d'un entier non sign\u00e9 par un tableau d'entiers dont les \u00e9l\u00e9ments sont 0 ou 1. Par exemple, le tableau [1, 0, 1, 0, 0, 1, 1]
repr\u00e9sente l'\u00e9criture binaire de l'entier dont l'\u00e9criture d\u00e9cimale est 2**6 + 2**4 + 2**1 + 2**0 = 83
.
\u00c0 l'aide d'un parcours s\u00e9quentiel, \u00e9crire la fonction convertir r\u00e9pondant aux sp\u00e9cifications suivantes :
def convertir(T):\n\"\"\"\n T est un tableau d'entiers, dont les \u00e9l\u00e9ments sont 0 ou 1 et\n repr\u00e9sentant un entier \u00e9crit en binaire. Renvoie l'\u00e9criture\n d\u00e9cimale de l'entier positif dont la repr\u00e9sentation binaire\n est donn\u00e9e par le tableau T\n \"\"\"\n
Exemple : >>> convertir([1, 0, 1, 0, 0, 1, 1])\n83\n>>> convertir([1, 0, 0, 0, 0, 0, 1, 0])\n130\n
def convertir(T):\n puissance = 0\n total = 0\n for i in range(len(T)-1, -1, -1):\n total += T[i]*(2**puissance)\n puissance += 1\n return total\n
On mod\u00e9lise la repr\u00e9sentation binaire d'un entier non sign\u00e9 par un tableau d'entiers dont\nles \u00e9l\u00e9ments sont 0 ou 1. Par exemple, le tableau `[1, 0, 1, 0, 0, 1, 1]` repr\u00e9sente\nl'\u00e9criture binaire de l'entier dont l'\u00e9criture d\u00e9cimale est\n`2**6 + 2**4 + 2**1 + 2**0 = 83`.\n\n\u00c0 l'aide d'un parcours s\u00e9quentiel, \u00e9crire la fonction convertir r\u00e9pondant aux\nsp\u00e9cifications suivantes :\n\n```python\ndef convertir(T):\n \"\"\"\n T est un tableau d'entiers, dont les \u00e9l\u00e9ments sont 0 ou 1 et\n repr\u00e9sentant un entier \u00e9crit en binaire. Renvoie l'\u00e9criture\n d\u00e9cimale de l'entier positif dont la repr\u00e9sentation binaire\n est donn\u00e9e par le tableau T\n \"\"\"\n```\nExemple :\n```python\n>>> convertir([1, 0, 1, 0, 0, 1, 1])\n83\n>>> convertir([1, 0, 0, 0, 0, 0, 1, 0])\n130\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-332","title":"Exercice 33.2 \u25a1","text":"Exercice 33.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa fonction tri_insertion
suivante prend en argument une liste L
et trie cette liste en utilisant la m\u00e9thode du tri par insertion. Compl\u00e9ter cette fonction pour qu'elle r\u00e9ponde \u00e0 la sp\u00e9cification demand\u00e9e.
def tri_insertion(L):\n n = len(L)\n\n # cas du tableau vide\n if ...:\n return L\n for j in range(1,n):\n e = L[j]\n i = j\n\n # A l'\u00e9tape j, le sous-tableau L[0,j-1] est tri\u00e9\n # et on ins\u00e8re L[j] dans ce sous-tableau en d\u00e9terminant\n # le plus petit i tel que 0 <= i <= j et L[i-1] > L[j].\n\n while i > 0 and L[i-1] > ...:\n i = ...\n\n # si i != j, on d\u00e9cale le sous tableau L[i,j-1] d\u2019un cran\n # vers la droite et on place L[j] en position i\n\n if i != j:\n for k in range(j,i,...):\n L[k] = L[...]\n L[i] = ...\n return L\n
Exemples :
>>> tri_insertion([2,5,-1,7,0,28])\n[-1, 0, 2, 5, 7, 28]\n>>> tri_insertion([10,9,8,7,6,5,4,3,2,1,0])\n[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n
def tri_insertion(L):\n n = len(L)\n\n # cas du tableau vide\n if L == []:\n return L\n\n for j in range(1,n):\n e = L[j]\n i = j\n\n # A l'\u00e9tape j, le sous-tableau L[0,j-1] est tri\u00e9\n # et on ins\u00e8re L[j] dans ce sous-tableau en d\u00e9terminant\n # le plus petit i tel que 0 <= i <= j et L[i-1] > L[j].\n\n while i > 0 and L[i-1] > e:\n i = i - 1\n\n # si i != j, on d\u00e9cale le sous tableau L[i,j-1] d\u2019un cran\n # vers la droite et on place L[j] en position i\n\n if i != j:\n for k in range(j,i,-1):\n L[k] = L[k-1]\n L[i] = e\n return L\n
La fonction `tri_insertion` suivante prend en argument une liste `L` et trie cette liste en\nutilisant la m\u00e9thode du tri par insertion. Compl\u00e9ter cette fonction pour qu'elle r\u00e9ponde \u00e0 la\nsp\u00e9cification demand\u00e9e.\n\n```python linenums='1'\ndef tri_insertion(L):\n n = len(L)\n\n # cas du tableau vide\n if ...:\n return L\n for j in range(1,n):\n e = L[j]\n i = j\n\n # A l'\u00e9tape j, le sous-tableau L[0,j-1] est tri\u00e9\n # et on ins\u00e8re L[j] dans ce sous-tableau en d\u00e9terminant\n # le plus petit i tel que 0 <= i <= j et L[i-1] > L[j].\n\n while i > 0 and L[i-1] > ...:\n i = ...\n\n # si i != j, on d\u00e9cale le sous tableau L[i,j-1] d\u2019un cran\n # vers la droite et on place L[j] en position i\n\n if i != j:\n for k in range(j,i,...):\n L[k] = L[...]\n L[i] = ...\n return L\n
Exemples :
>>> tri_insertion([2,5,-1,7,0,28])\n[-1, 0, 2, 5, 7, 28]\n>>> tri_insertion([10,9,8,7,6,5,4,3,2,1,0])\n[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-34","title":"\u25b6 Sujet 34","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-341","title":"Exercice 34.1 \u25a1","text":"Exercice 34.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction occurrence_max
prenant en param\u00e8tres une cha\u00eene de caract\u00e8res chaine
et qui renvoie le caract\u00e8re le plus fr\u00e9quent de la cha\u00eene. La chaine ne contient que des lettres en minuscules sans accent. On pourra s\u2019aider du tableau
alphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']
et du tableau occurrence
de 26 \u00e9l\u00e9ments o\u00f9 l\u2019on mettra dans occurrence[i]
le nombre d\u2019apparitions de alphabet[i]
dans la chaine. Puis on calculera l\u2019indice k
d\u2019un maximum du tableau occurrence
et on affichera alphabet[k]
.
Exemple :
>>> ch = 'je suis en terminale et je passe le bac et je souhaite poursuivre des etudes pour devenir expert en informatique'\n>>> occurrence_max(ch)\n\u2018e\u2019\n
alphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o,','p','q','r','s','t','u','v','w','x','y','z']\n\ndef occurrence_max(chaine):\n occurence = [0] * 26\n for i in range(26):\n compteur = 0\n for caractere in chaine:\n if caractere == alphabet[i]:\n compteur += 1\n occurence[i] = compteur\n ind_max = 0\n for i in range(26):\n if occurence[i] > occurence[ind_max]:\n ind_max = i\n return alphabet[ind_max]\n
\u00c9crire une fonction `occurrence_max` prenant en param\u00e8tres une cha\u00eene de caract\u00e8res\n`chaine` et qui renvoie le caract\u00e8re le plus fr\u00e9quent de la cha\u00eene. La chaine ne contient\nque des lettres en minuscules sans accent.\nOn pourra s\u2019aider du tableau\n\n`alphabet = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']`\n\net du tableau `occurrence` de 26 \u00e9l\u00e9ments o\u00f9 l\u2019on mettra dans `occurrence[i]` le\nnombre d\u2019apparitions de `alphabet[i]` dans la chaine. \nPuis on calculera l\u2019indice `k` d\u2019un maximum du tableau `occurrence` et on affichera `alphabet[k]`.\n\nExemple :\n```python\n>>> ch = 'je suis en terminale et je passe le bac et je souhaite poursuivre des etudes pour devenir expert en informatique'\n>>> occurrence_max(ch)\n\u2018e\u2019\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-342","title":"Exercice 34.2 \u25a1","text":"Exercice 34.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re une image en 256 niveaux de gris que l\u2019on repr\u00e9sente par une grille de nombres, c\u2019est-\u00e0-dire une liste compos\u00e9e de sous-listes toutes de longueurs identiques. La largeur de l\u2019image est donc la longueur d\u2019une sous-liste et la hauteur de l\u2019image est le nombre de sous-listes.
Chaque sous-liste repr\u00e9sente une ligne de l\u2019image et chaque \u00e9l\u00e9ment des sous-listes est un entier compris entre 0 et 255, repr\u00e9sentant l\u2019intensit\u00e9 lumineuse du pixel.
Compl\u00e9ter le programme ci-dessous :
def nbLig(image):\n'''renvoie le nombre de lignes de l'image'''\n return ...\n\ndef nbCol(image):\n'''renvoie la largeur de l'image'''\n return ...\n\ndef negatif(image):\n'''renvoie le n\u00e9gatif de l'image sous la forme d'une liste de listes'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9\u00e9 une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(...):\n L[i][j] = ...\n return L\n\ndef binaire(image, seuil):\n'''renvoie une image binaris\u00e9e de l'image sous la forme\n d'une liste de listes contenant des 0 si la valeur\n du pixel est strictement inf\u00e9rieure au seuil\n et 1 sinon'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9e une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(...):\n if image[i][j] < ... :\n L[i][j] = ...\n else:\n L[i][j] = ...\n return L \n
Exemple :
>>> img = [[20, 34, 254, 145, 6], [23, 124, 287, 225, 69], [197, 174, 207, 25, 87], [255, 0, 24, 197, 189]]\n>>> nbLig(img)\n4\n>>> nbCol(img)\n5\n>>> negatif(img)\n[[235, 221, 1, 110, 249], [232, 131, -32, 30, 186], [58, 81, 48, 230, 168], [0, 255, 231, 58, 66]]\n>>> binaire(negatif(img),120)\n[[1, 1, 0, 0, 1], [1, 1, 0, 0, 1], [0, 0, 0, 1, 1], [0, 1, 1, 0, 0]]\n
def nbLig(image):\n'''renvoie le nombre de lignes de l'image'''\n return len(image)\n\ndef nbCol(image):\n'''renvoie la largeur de l'image'''\n return len(image[0])\n\ndef negatif(image):\n'''renvoie le n\u00e9gatif de l'image sous la forme d'une liste de listes'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9\u00e9 une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(nbCol(image)):\n L[i][j] = 255-image[i][j]\n return L\n\ndef binaire(image, seuil):\n'''renvoie une image binaris\u00e9e de l'image sous la forme\n d'une liste de listes contenant des 0 si la valeur\n du pixel est strictement inf\u00e9rieure au seuil\n et 1 sinon'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9e une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(nbCol(image)):\n if image[i][j] < seuil :\n L[i][j] = 0\n else:\n L[i][j] = 1\n return L \n
On consid\u00e8re une image en 256 niveaux de gris que l\u2019on repr\u00e9sente par une grille de\nnombres, c\u2019est-\u00e0-dire une liste compos\u00e9e de sous-listes toutes de longueurs identiques.\nLa largeur de l\u2019image est donc la longueur d\u2019une sous-liste et la hauteur de l\u2019image est le\nnombre de sous-listes.\n\nChaque sous-liste repr\u00e9sente une ligne de l\u2019image et chaque \u00e9l\u00e9ment des sous-listes est\nun entier compris entre 0 et 255, repr\u00e9sentant l\u2019intensit\u00e9 lumineuse du pixel.\n\nCompl\u00e9ter le programme ci-dessous :\n\n```python linenums='1'\ndef nbLig(image):\n '''renvoie le nombre de lignes de l'image'''\n return ...\n\ndef nbCol(image):\n '''renvoie la largeur de l'image'''\n return ...\n\ndef negatif(image):\n '''renvoie le n\u00e9gatif de l'image sous la forme d'une liste de listes'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9\u00e9 une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(...):\n L[i][j] = ...\n return L\n\ndef binaire(image, seuil):\n '''renvoie une image binaris\u00e9e de l'image sous la forme\n d'une liste de listes contenant des 0 si la valeur\n du pixel est strictement inf\u00e9rieure au seuil\n et 1 sinon'''\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))] # on cr\u00e9e une image de 0 aux m\u00eames dimensions que le param\u00e8tre image\n for i in range(len(image)):\n for j in range(...):\n if image[i][j] < ... :\n L[i][j] = ...\n else:\n L[i][j] = ...\n return L \n
Exemple :
>>> img = [[20, 34, 254, 145, 6], [23, 124, 287, 225, 69], [197, 174, 207, 25, 87], [255, 0, 24, 197, 189]]\n>>> nbLig(img)\n4\n>>> nbCol(img)\n5\n>>> negatif(img)\n[[235, 221, 1, 110, 249], [232, 131, -32, 30, 186], [58, 81, 48, 230, 168], [0, 255, 231, 58, 66]]\n>>> binaire(negatif(img),120)\n[[1, 1, 0, 0, 1], [1, 1, 0, 0, 1], [0, 0, 0, 1, 1], [0, 1, 1, 0, 0]]\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-35","title":"\u25b6 Sujet 35","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-351","title":"Exercice 35.1 \u25a1","text":"Exercice 35.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction qui prend en param\u00e8tre un tableau d'entiers non vide et qui renvoie la moyenne de ces entiers. La fonction est sp\u00e9cifi\u00e9e ci-apr\u00e8s et doit passer les assertions fournies.
def moyenne (tab):\n'''\n moyenne(list) -> float\n Entr\u00e9e : un tableau non vide d'entiers\n Sortie : nombre de type float\n Correspondant \u00e0 la moyenne des valeurs pr\u00e9sentes dans le\n tableau\n '''\n\nassert moyenne([1]) == 1\nassert moyenne([1, 2, 3, 4, 5, 6, 7] == 4\nassert moyenne([1, 2]) == 1.5\n
def moyenne(tab):\n'''\n moyenne(list) -> float\n Entr\u00e9e : un tableau non vide d'entiers\n Sortie : nombre de type float\n Correspondant \u00e0 la moyenne des valeurs pr\u00e9sentes dans le\n tableau\n '''\n somme = 0\n for elt in tab:\n somme += elt\n return somme / len(tab)\n
\u00c9crire une fonction qui prend en param\u00e8tre un tableau d'entiers non vide et qui renvoie la\nmoyenne de ces entiers. La fonction est sp\u00e9cifi\u00e9e ci-apr\u00e8s et doit passer les assertions\nfournies.\n```python\ndef moyenne (tab):\n '''\n moyenne(list) -> float\n Entr\u00e9e : un tableau non vide d'entiers\n Sortie : nombre de type float\n Correspondant \u00e0 la moyenne des valeurs pr\u00e9sentes dans le\n tableau\n '''\n\nassert moyenne([1]) == 1\nassert moyenne([1, 2, 3, 4, 5, 6, 7] == 4\nassert moyenne([1, 2]) == 1.5\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-352","title":"Exercice 35.2 \u25a1","text":"Exercice 35.2
\u00c9nonc\u00e9CorrectionSources MarkdownLe but de l'exercice est de compl\u00e9ter une fonction qui d\u00e9termine si une valeur est pr\u00e9sente dans un tableau de valeurs tri\u00e9es dans l'ordre croissant.
L'algorithme traite le cas du tableau vide.
L'algorithme est \u00e9crit pour que la recherche dichotomique ne se fasse que dans le cas o\u00f9 la valeur est comprise entre les valeurs extr\u00eames du tableau.
On distingue les trois cas qui renvoient False
en renvoyant False, 1
, False, 2
et False, 3
.
Compl\u00e9ter l'algorithme de dichotomie donn\u00e9 ci-apr\u00e8s.
def dichotomie(tab, x):\n\"\"\"\n tab : tableau tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n # cas du tableau vide\n if ...:\n return False,1\n # cas o\u00f9 x n'est pas compris entre les valeurs extr\u00eames\n if (x < tab[0]) or ...:\n return False, 2\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\n(False, 3)\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],1)\n(False, 2)\n>>> dichotomie([],28)\n(False, 1)\n
def dichotomie(tab, x):\n\"\"\"\n tab : tableau tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n # cas du tableau vide\n if tab = []:\n return False, 1\n # cas o\u00f9 x n'est pas compris entre les valeurs extr\u00eames\n if (x < tab[0]) or (x > tab[-1]):\n return False, 2\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = (debut + fin) // 2\n if x == tab[m]:\n return True\n if x > tab[m]:\n debut = m + 1\n else:\n fin = m - 1\n return False, 3\n
Le but de l'exercice est de compl\u00e9ter une fonction qui d\u00e9termine si une valeur est pr\u00e9sente\ndans un tableau de valeurs tri\u00e9es dans l'ordre croissant.\n\nL'algorithme traite le cas du tableau vide.\n\nL'algorithme est \u00e9crit pour que la recherche dichotomique ne se fasse que dans le cas o\u00f9\nla valeur est comprise entre les valeurs extr\u00eames du tableau.\n\nOn distingue les trois cas qui renvoient `False` en renvoyant `False, 1` , `False, 2` et\n`False, 3`.\n\nCompl\u00e9ter l'algorithme de dichotomie donn\u00e9 ci-apr\u00e8s.\n\n```python linenums='1'\ndef dichotomie(tab, x):\n \"\"\"\n tab : tableau tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n # cas du tableau vide\n if ...:\n return False,1\n # cas o\u00f9 x n'est pas compris entre les valeurs extr\u00eames\n if (x < tab[0]) or ...:\n return False, 2\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\n(False, 3)\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],1)\n(False, 2)\n>>> dichotomie([],28)\n(False, 1)\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-36","title":"\u25b6 Sujet 36","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-361","title":"Exercice 36.1 \u25a1","text":"Exercice 36.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction recherche
, prenant en param\u00e8tre un tableau non vide tab
(type list
) d'entiers et un entier n
, et qui renvoie l'indice de la derni\u00e8re occurrence de l'\u00e9l\u00e9ment cherch\u00e9. Si l'\u00e9l\u00e9ment n'est pas pr\u00e9sent, la fonction renvoie la longueur du tableau.
Exemples
>>> recherche([5, 3],1)\n2\n>>> recherche([2,4],2)\n0\n>>> recherche([2,3,5,2,4],2)\n3\n
def recherche(tab, n):\n indice_solution = len(tab)\n for i in range(len(tab)):\n if tab[i] == n:\n indice_solution = i\n return indice_solution\n
Programmer la fonction `recherche`, prenant en param\u00e8tre un tableau non vide `tab` (type `list`) d'entiers et un entier `n`, et qui renvoie l'indice de la **derni\u00e8re** occurrence de l'\u00e9l\u00e9ment cherch\u00e9. Si l'\u00e9l\u00e9ment n'est pas pr\u00e9sent, la fonction renvoie la longueur du tableau.\n\nExemples\n```python\n>>> recherche([5, 3],1)\n2\n>>> recherche([2,4],2)\n0\n>>> recherche([2,3,5,2,4],2)\n3\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-362","title":"Exercice 36.2 \u25a1","text":"Exercice 36.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn souhaite programmer une fonction donnant la distance la plus courte entre un point de d\u00e9part et une liste de points. Les points sont tous \u00e0 coordonn\u00e9es enti\u00e8res. Les points sont donn\u00e9s sous la forme d'un tuple de deux entiers. La liste des points \u00e0 traiter est donc un tableau de tuples.
On rappelle que la distance entre deux points du plan de coordonn\u00e9es \\((x;y)\\) et \\((x';y')\\) est donn\u00e9e par la formule :
\\[d=\\sqrt{(x-x')^2+(y-y')^2}\\]On importe pour cela la fonction racine carr\u00e9e (sqrt
) du module math
de Python.
On dispose d'une fonction distance
et d'une fonction plus_courte_distance
:
from math import sqrt # import de la fonction racine carr\u00e9e\n\ndef distance(point1, point2):\n\"\"\" Calcule et renvoie la distance entre deux points. \"\"\"\n return sqrt((...)**2 + (...)**2)\n\nassert distance((1, 0), (5, 3)) == 5.0, \"erreur de calcul\"\n\ndef plus_courte_distance(tab, depart):\n\"\"\" Renvoie le point du tableau tab se trouvant \u00e0 la plus courte distance du point depart.\"\"\"\n point = tab[0]\n min_dist = ...\n for i in range (1, ...):\n if distance(tab[i], depart)...:\n point = ...\n min_dist = ...\n return point\n\nassert plus_courte_distance([(7, 9), (2, 5), (5, 2)], (0, 0)) == (2, 5), \"erreur\"\n
Recopier sous Python (sans les commentaires) ces deux fonctions puis compl\u00e9ter leur code et ajouter une ou des d\u00e9clarations (assert
) \u00e0 la fonction distance
permettant de v\u00e9rifier la ou les pr\u00e9conditions. from math import sqrt\n\ndef distance(point1, point2):\n\"\"\" Calcule et renvoie la distance entre deux points. \"\"\"\n assert int(point1[0]) == point1[0], \"coordonn\u00e9e non enti\u00e8re\"\n assert int(point1[1]) == point1[1], \"coordonn\u00e9e non enti\u00e8re\"\n assert int(point2[0]) == point2[0], \"coordonn\u00e9e non enti\u00e8re\"\n assert int(point2[1]) == point2[1], \"coordonn\u00e9e non enti\u00e8re\"\n return sqrt((point1[0] - point2[0])**2 + ((point1[1] - point2[1]))**2)\n\nassert distance((1, 0), (5, 3)) == 5.0, \"erreur de calcul\"\n\n\ndef plus_courte_distance(tab, depart):\n\"\"\" Renvoie le point du tableau tab se trouvant \u00e0 la plus courte distance du point depart.\"\"\"\n point = tab[0]\n min_dist = distance(point, depart)\n for i in range (1, len(tab)):\n if distance(tab[i], depart) < min_dist:\n point = tab[i]\n min_dist = distance(tab[i], depart)\n return point\n\nassert plus_courte_distance([(7, 9), (2, 5), (5, 2)], (0, 0)) == (2, 5), \"erreur\"\n
On souhaite programmer une fonction donnant la distance la plus courte entre un point\nde d\u00e9part et une liste de points. Les points sont tous \u00e0 coordonn\u00e9es enti\u00e8res.\nLes points sont donn\u00e9s sous la forme d'un tuple de deux entiers.\nLa liste des points \u00e0 traiter est donc un tableau de tuples.\n\nOn rappelle que la distance entre deux points du plan de coordonn\u00e9es $(x;y)$ et $(x';y')$\nest donn\u00e9e par la formule :\n\n$$d=\\sqrt{(x-x')^2+(y-y')^2}$$\n\nOn importe pour cela la fonction racine carr\u00e9e (`sqrt`) du module `math` de Python.\n\nOn dispose d'une fonction `distance` et d'une fonction `plus_courte_distance` :\n\n```python\nfrom math import sqrt # import de la fonction racine carr\u00e9e\n\ndef distance(point1, point2):\n \"\"\" Calcule et renvoie la distance entre deux points. \"\"\"\n return sqrt((...)**2 + (...)**2)\n\nassert distance((1, 0), (5, 3)) == 5.0, \"erreur de calcul\"\n\ndef plus_courte_distance(tab, depart):\n \"\"\" Renvoie le point du tableau tab se trouvant \u00e0 la plus courte distance du point depart.\"\"\"\n point = tab[0]\n min_dist = ...\n for i in range (1, ...):\n if distance(tab[i], depart)...:\n point = ...\n min_dist = ...\n return point\n\nassert plus_courte_distance([(7, 9), (2, 5), (5, 2)], (0, 0)) == (2, 5), \"erreur\"\n
Recopier sous Python (sans les commentaires) ces deux fonctions puis compl\u00e9ter leur code et ajouter une ou des d\u00e9clarations (assert
) \u00e0 la fonction distance
permettant de v\u00e9rifier la ou les pr\u00e9conditions. ``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-37","title":"\u25b6 Sujet 37","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-371","title":"Exercice 37.1 \u25a1","text":"Exercice 37.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction verifie
qui prend en param\u00e8tre un tableau de valeurs num\u00e9riques non vide et qui renvoie True
si ce tableau est tri\u00e9 dans l\u2019ordre croissant, False
sinon.
Exemples :
Exemples :\n>>> verifie([0, 5, 8, 8, 9])\nTrue\n>>> verifie([8, 12, 4])\nFalse\n>>> verifie([-1, 4])\nTrue\n>>> verifie([5])\nTrue\n
def verifie(tab):\n for i in range(1, len(tab)):\n if tab[i] < tab[i-1]:\n return False\n return True\n
Programmer la fonction `verifie` qui prend en param\u00e8tre un tableau de valeurs num\u00e9riques non\nvide et qui renvoie `True` si ce tableau est tri\u00e9 dans l\u2019ordre croissant, `False` sinon.\n\nExemples :\n\n```python\nExemples :\n>>> verifie([0, 5, 8, 8, 9])\nTrue\n>>> verifie([8, 12, 4])\nFalse\n>>> verifie([-1, 4])\nTrue\n>>> verifie([5])\nTrue\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-372","title":"Exercice 37.2 \u25a1","text":"Exercice 37.2
\u00c9nonc\u00e9CorrectionSources MarkdownChaque soir, les auditeurs d\u2019une radio votent en ligne pour leur artiste favori. Ces votes sont stock\u00e9s dans un tableau.
Exemple :
urne = ['A', 'A', 'A', 'B', 'C', 'B', 'C', 'B', 'C', 'B']\n
La fonction depouille
doit permettre de compter le nombre de votes exprim\u00e9s pour chaque artiste. Elle prend en param\u00e8tre un tableau et renvoie le r\u00e9sultat dans un dictionnaire dont les cl\u00e9s sont les noms des artistes et les valeurs le nombre de votes en leur faveur.
La fonction vainqueur doit d\u00e9signer le nom du ou des gagnants. Elle prend en param\u00e8tre un dictionnaire dont la structure est celle du dictionnaire renvoy\u00e9 par la fonction depouille
et renvoie un tableau. Ce tableau peut donc contenir plusieurs \u00e9l\u00e9ments s\u2019il y a des artistes ex- aequo. Compl\u00e9ter les fonctions depouille
et vainqueur ci-apr\u00e8s pour qu\u2019elles renvoient les r\u00e9sultats attendus.
urne = ['A', 'A', 'A','B', 'C', 'B', 'C','B', 'C', 'B']\n\ndef depouille(urne):\n resultat = ...\n for bulletin in urne:\n if ...:\n resultat[bulletin] = resultat[bulletin] + 1\n else:\n ...\n return resultat\n\ndef vainqueur(election):\n vainqueur = ''\n nmax = 0\n for candidat in election:\n if ... > ... :\n nmax = ...\n vainqueur = candidat\n liste_finale = [nom for nom in election if election[nom] == ...]\n return ...\n
Exemples d\u2019utilisation :
>>> election = depouille(urne)\n>>> election\n{'A': 3, 'B': 4, 'C': 3} # (1)\n>>> vainqueur(election)\n['B']\n
urne = ['A', 'A', 'A', 'B', 'C', 'B', 'C', 'B', 'C', 'B']\n\ndef depouille(urne):\n resultat = {}\n for bulletin in urne:\n if bulletin in resultat:\n resultat[bulletin] = resultat[bulletin] + 1\n else:\n resultat[bulletin] = 1\n return resultat\n\ndef vainqueur(election):\n vainqueur = '' #(1)\n nmax = 0\n for candidat in election:\n if election[candidat] > nmax :\n nmax = election[candidat]\n vainqueur = candidat #(2)\n liste_finale = [nom for nom in election if election[nom] == nmax]\n return liste_finale\n
vainqueur
est inutile, on ne s'en sert pas dans l'\u00e9laboration de la liste finale.Chaque soir, les auditeurs d\u2019une radio votent en ligne pour leur artiste favori. Ces votes sont\nstock\u00e9s dans un tableau.\n\nExemple :\n\n```python\nurne = ['A', 'A', 'A', 'B', 'C', 'B', 'C', 'B', 'C', 'B']\n
La fonction depouille
doit permettre de compter le nombre de votes exprim\u00e9s pour chaque artiste. Elle prend en param\u00e8tre un tableau et renvoie le r\u00e9sultat dans un dictionnaire dont les cl\u00e9s sont les noms des artistes et les valeurs le nombre de votes en leur faveur.
La fonction vainqueur doit d\u00e9signer le nom du ou des gagnants. Elle prend en param\u00e8tre un dictionnaire dont la structure est celle du dictionnaire renvoy\u00e9 par la fonction depouille
et renvoie un tableau. Ce tableau peut donc contenir plusieurs \u00e9l\u00e9ments s\u2019il y a des artistes ex- aequo. Compl\u00e9ter les fonctions depouille
et vainqueur ci-apr\u00e8s pour qu\u2019elles renvoient les r\u00e9sultats attendus.
urne = ['A', 'A', 'A','B', 'C', 'B', 'C','B', 'C', 'B']\n\ndef depouille(urne):\n resultat = ...\n for bulletin in urne:\n if ...:\n resultat[bulletin] = resultat[bulletin] + 1\n else:\n ...\n return resultat\n\ndef vainqueur(election):\n vainqueur = ''\n nmax = 0\n for candidat in election:\n if ... > ... :\n nmax = ...\n vainqueur = candidat\n liste_finale = [nom for nom in election if election[nom] == ...]\n return ...\n
Exemples d\u2019utilisation :
>>> election = depouille(urne)\n>>> election\n{'A': 3, 'B': 4, 'C': 3} # (1)\n>>> vainqueur(election)\n['B']\n
Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-381","title":"Exercice 38.1 \u25a1","text":"Exercice 38.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction tri_selection
qui prend en param\u00e8tre une liste tab
de nombres entiers et qui renvoie le tableau tri\u00e9 par ordre croissant.
On utilisera l\u2019algorithme suivant :
Exemple :
>>> tri_selection([1,52,6,-9,12])\n[-9, 1, 6, 12, 52]\n
def tri_selection(tab):\n for i in range(len(tab)-1):\n indice_min = i\n for j in range(i+1, len(tab)):\n if tab[j] < tab[indice_min]:\n indice_min = j\n tab[i], tab[indice_min] = tab[indice_min], tab[i]\n return tab\n
\u00c9crire une fonction `tri_selection` qui prend en param\u00e8tre une liste `tab` de nombres\nentiers et qui renvoie le tableau tri\u00e9 par ordre croissant.\n\nOn utilisera l\u2019algorithme suivant :\n\n- on recherche le plus petit \u00e9l\u00e9ment du tableau, et on l'\u00e9change avec l'\u00e9l\u00e9ment d'indice 0 ;\n- on recherche le second plus petit \u00e9l\u00e9ment du tableau, et on l'\u00e9change avec l'\u00e9l\u00e9ment\nd'indice 1 ;\n- on continue de cette fa\u00e7on jusqu'\u00e0 ce que le tableau soit enti\u00e8rement tri\u00e9.\n\nExemple :\n```python\n>>> tri_selection([1,52,6,-9,12])\n[-9, 1, 6, 12, 52]\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-382","title":"Exercice 38.2 \u25a1","text":"Exercice 38.2
\u00c9nonc\u00e9CorrectionSources MarkdownLe jeu du \u00ab plus ou moins \u00bb consiste \u00e0 deviner un nombre entier choisi entre 1 et 99. Un \u00e9l\u00e8ve de NSI d\u00e9cide de le coder en langage Python de la mani\u00e8re suivante :
La fonction randint
est utilis\u00e9e. Si a et b sont des entiers, randint(a,b)
renvoie un nombre entier compris entre a
et b
. Compl\u00e9ter le code ci-dessous et le tester :
from random import randint\n\ndef plus_ou_moins():\n nb_mystere = randint(1,...)\n nb_test = int(input(\"Proposez un nombre entre 1 et 99 : \"))\n compteur = ...\n\n while nb_mystere != ... and compteur < ... :\n compteur = compteur + ...\n if nb_mystere ... nb_test:\n nb_test = int(input(\"Trop petit ! Testez encore : \"))\n else:\n nb_test = int(input(\"Trop grand ! Testez encore : \"))\n\n if nb_mystere == nb_test:\n print (\"Bravo ! Le nombre \u00e9tait \",...)\n print(\"Nombre d'essais: \",...)\n else:\n print (\"Perdu ! Le nombre \u00e9tait \",...)\n
from random import randint\n\ndef plus_ou_moins():\n nb_mystere = randint(1,99)\n nb_test = int(input('Proposez un nombre entre 1 et 99 : '))\n compteur = 1\n\n while nb_mystere != nb_test and compteur < 10 :\n compteur = compteur + 1\n if nb_mystere > nb_test:\n nb_test = int(input('Trop petit ! Testez encore : '))\n else:\n nb_test = int(input('Trop grand ! Testez encore : '))\n\n if nb_mystere == nb_test:\n print ('Bravo ! Le nombre \u00e9tait ', nb_mystere)\n print('Nombre d essais: ', compteur)\n else:\n print ('Perdu ! Le nombre \u00e9tait ', nb_mystere)\n
Le jeu du \u00ab plus ou moins \u00bb consiste \u00e0 deviner un nombre entier choisi entre 1 et 99.\nUn \u00e9l\u00e8ve de NSI d\u00e9cide de le coder en langage Python de la mani\u00e8re suivante :\n\n- le programme g\u00e9n\u00e8re un nombre entier al\u00e9atoire compris entre 1 et 99 ;\n- si la proposition de l\u2019utilisateur est plus petite que le nombre cherch\u00e9, l\u2019utilisateur en\nest averti. Il peut alors en tester un autre ;\n- si la proposition de l\u2019utilisateur est plus grande que le nombre cherch\u00e9, l\u2019utilisateur en\nest averti. Il peut alors en tester un autre ;\n- si l\u2019utilisateur trouve le bon nombre en 10 essais ou moins, il gagne ;\n- si l\u2019utilisateur a fait plus de 10 essais sans trouver le bon nombre, il perd.\n\nLa fonction `randint` est utilis\u00e9e. Si a et b sont des entiers, `randint(a,b)` renvoie un\nnombre entier compris entre `a` et `b`.\nCompl\u00e9ter le code ci-dessous et le tester :\n\n```python linenums='1'\nfrom random import randint\n\ndef plus_ou_moins():\n nb_mystere = randint(1,...)\n nb_test = int(input(\"Proposez un nombre entre 1 et 99 : \"))\n compteur = ...\n\n while nb_mystere != ... and compteur < ... :\n compteur = compteur + ...\n if nb_mystere ... nb_test:\n nb_test = int(input(\"Trop petit ! Testez encore : \"))\n else:\n nb_test = int(input(\"Trop grand ! Testez encore : \"))\n\n if nb_mystere == nb_test:\n print (\"Bravo ! Le nombre \u00e9tait \",...)\n print(\"Nombre d'essais: \",...)\n else:\n print (\"Perdu ! Le nombre \u00e9tait \",...)\n
``` "},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-39","title":"\u25b6 Sujet 39","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-391","title":"Exercice 39.1 \u25a1","text":"Exercice 39.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction moyenne
prenant en param\u00e8tres une liste d\u2019entiers et qui renvoie la moyenne des valeurs de cette liste.
Exemple :
>>> moyenne([10,20,30,40,60,110])\n45.0\n
def moyenne(tab):\n somme = 0\n for val in tab:\n somme += val\n return somme / len(tab)\n
\u00c9crire une fonction `moyenne` prenant en param\u00e8tres une liste d\u2019entiers et qui renvoie la\nmoyenne des valeurs de cette liste.\n\nExemple :\n```python\n>>> moyenne([10,20,30,40,60,110])\n45.0\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-392","title":"Exercice 39.2 \u25a1","text":"Exercice 39.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn travaille sur des dessins en noir et blanc obtenu \u00e0 partir de pixels noirs et blancs : La figure \u00ab c\u0153ur \u00bb ci-dessus va servir d\u2019exemple. On la repr\u00e9sente par une grille de nombres, c\u2019est-\u00e0-dire par une liste compos\u00e9e de sous-listes de m\u00eame longueurs. Chaque sous-liste repr\u00e9sentera donc une ligne du dessin.
Dans le code ci-dessous, la fonction affiche
permet d\u2019afficher le dessin. Les pixels noirs (1 dans la grille) seront repr\u00e9sent\u00e9s par le caract\u00e8re \"*\" et les blancs (0 dans la grille) par deux espaces.
La fonction zoomListe
prend en argument une liste liste_depart
et un entier k
. Elle renvoie une liste o\u00f9 chaque \u00e9l\u00e9ment de liste_depart
est dupliqu\u00e9 k
fois.
La fonction zoomDessin
prend en argument la grille dessin
et renvoie une grille o\u00f9 toutes les lignes de dessin
sont zoom\u00e9es k
fois et r\u00e9p\u00e9t\u00e9es k
fois.
Soit le code ci-dessous :
coeur = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], \\\n [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0], \\\n [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \\\n [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0], \\\n [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n\ndef affiche(dessin):\n''' affichage d'une grille : les 1 sont repr\u00e9sent\u00e9s par \n des \" *\" , les 0 par deux espaces \" \" '''\n for ligne in dessin:\n for col in ligne:\n if col == 1:\n print(\" *\", end=\"\")\n else:\n print(\" \", end=\"\")\n print()\n\n\ndef zoomListe(liste_depart,k):\n'''renvoie une liste contenant k fois chaque \n \u00e9l\u00e9ment de liste_depart'''\n liste_zoom = ...\n for elt in ... :\n for i in range(k):\n ...\n return liste_zoom\n\ndef zoomDessin(grille,k):\n'''renvoie une grille o\u00f9 les lignes sont zoom\u00e9es k fois \n ET r\u00e9p\u00e9t\u00e9es k fois'''\n grille_zoom=[]\n for elt in grille:\n liste_zoom = ...\n for i in range(k):\n ... .append(...)\n return grille_zoom\n
R\u00e9sultats \u00e0 obtenir :
>>> affiche(coeur)\n
>>> affiche(zoomDessin(coeur,3))\n
* * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * \n * * * \n * * *\n
coeur = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], \\\n [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0], \\\n [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \\\n [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0], \\\n [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n\ndef affiche(dessin):\n for ligne in dessin:\n for col in ligne:\n if col == 1:\n print(' *',end='')\n else:\n print(' ',end='')\n print()\n\n\ndef zoomListe(liste_depart, k):\n liste_zoom = []\n for elt in liste_depart:\n for i in range(k):\n liste_zoom.append(elt)\n return liste_zoom\n\ndef zoomDessin(grille, k):\n grille_zoom = []\n for elt in grille:\n liste_zoom = zoomListe(elt, k)\n for i in range(k):\n grille_zoom.append(liste_zoom)\n return grille_zoom\n
![image](data/272a.png){: .center width=30%}\nOn travaille sur des dessins en noir et blanc obtenu \u00e0 partir de pixels noirs et blancs :\nLa figure \u00ab c\u0153ur \u00bb ci-dessus va servir d\u2019exemple.\nOn la repr\u00e9sente par une grille de nombres, c\u2019est-\u00e0-dire par une liste compos\u00e9e de sous-listes de m\u00eame longueurs.\nChaque sous-liste repr\u00e9sentera donc une ligne du dessin.\n\nDans le code ci-dessous, la fonction `affiche` permet d\u2019afficher le dessin. Les pixels noirs\n(1 dans la grille) seront repr\u00e9sent\u00e9s par le caract\u00e8re \"*\" et les blancs (0 dans la grille) par\ndeux espaces.\n\nLa fonction `zoomListe` prend en argument une liste `liste_depart` et un entier `k`. Elle\nrenvoie une liste o\u00f9 chaque \u00e9l\u00e9ment de `liste_depart` est dupliqu\u00e9 `k` fois.\n\nLa fonction `zoomDessin` prend en argument la grille `dessin` et renvoie une grille o\u00f9\ntoutes les lignes de `dessin` sont zoom\u00e9es `k` fois et r\u00e9p\u00e9t\u00e9es `k` fois.\n\nSoit le code ci-dessous :\n\n```python linenums='1'\ncoeur = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], \\\n [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0], \\\n [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \\\n [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0], \\\n [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n\ndef affiche(dessin):\n ''' affichage d'une grille : les 1 sont repr\u00e9sent\u00e9s par \n des \" *\" , les 0 par deux espaces \" \" '''\n for ligne in dessin:\n for col in ligne:\n if col == 1:\n print(\" *\", end=\"\")\n else:\n print(\" \", end=\"\")\n print()\n\n\ndef zoomListe(liste_depart,k):\n '''renvoie une liste contenant k fois chaque \n \u00e9l\u00e9ment de liste_depart'''\n liste_zoom = ...\n for elt in ... :\n for i in range(k):\n ...\n return liste_zoom\n\ndef zoomDessin(grille,k):\n '''renvoie une grille o\u00f9 les lignes sont zoom\u00e9es k fois \n ET r\u00e9p\u00e9t\u00e9es k fois'''\n grille_zoom=[]\n for elt in grille:\n liste_zoom = ...\n for i in range(k):\n ... .append(...)\n return grille_zoom\n
R\u00e9sultats \u00e0 obtenir :
>>> affiche(coeur)\n
>>> affiche(zoomDessin(coeur,3))\n
* * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * \n * * * \n * * *\n
```
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#sujet-40","title":"\u25b6 Sujet 40","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-401","title":"Exercice 40.1 \u25a1","text":"Exercice 40.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche
qui prend en param\u00e8tres elt
un nombre et tab
un tableau de nombres, et qui renvoie le tableau des indices de elt
dans tab
si elt
est dans tab
et le tableau vide []
sinon.
Exemples :
>>> recherche(3, [3, 2, 1, 3, 2, 1])\n[0, 3]\n>>> recherche(4, [1, 2, 3])\n[]\n
def recherche(elt, tab):\n tab_indices = []\n for i in range(len(tab)):\n if tab[i] == elt:\n tab_indices.append(i)\n return tab_indices \n
\u00c9crire une fonction `recherche` qui prend en param\u00e8tres `elt` un nombre et `tab` un\ntableau de nombres, et qui renvoie le tableau des indices de `elt` dans `tab` si `elt` est dans `tab` et le tableau vide `[]` sinon.\n\nExemples :\n```python\n>>> recherche(3, [3, 2, 1, 3, 2, 1])\n[0, 3]\n>>> recherche(4, [1, 2, 3])\n[]\n```\n
"},{"location":"T6_6_Epreuve_pratique/BNS_2022/#exercice-402","title":"Exercice 40.2 \u25a1","text":"Exercice 40.2
\u00c9nonc\u00e9CorrectionSources MarkdownUn professeur de NSI d\u00e9cide de g\u00e9rer les r\u00e9sultats de sa classe sous la forme d\u2019un dictionnaire :
Avec :
resultats = {'Dupont':{ 'DS1' : [15.5, 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [13, 4],\n 'PROJET1' : [16, 3],\n 'DS3' : [14, 4]},\n 'Durand':{ 'DS1' : [6 , 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [8, 4],\n 'PROJET1' : [9, 3],\n 'IE1' : [7, 2],\n 'DS3' : [8, 4],\n 'DS4' :[15, 4]}}\n
L\u2019\u00e9l\u00e8ve dont le nom est Durand a ainsi obtenu au DS2 la note de 8 avec un coefficient 4. Le professeur cr\u00e9e une fonction moyenne
qui prend en param\u00e8tre le nom d\u2019un de ces \u00e9l\u00e8ves et lui renvoie sa moyenne arrondie au dixi\u00e8me.
Compl\u00e9ter le code du professeur ci-dessous :
def moyenne(nom):\n if nom in ...:\n notes = resultats[nom]\n total_points = ...\n total_coefficients = ...\n for ... in notes.values():\n note , coefficient = valeurs\n total_points = total_points + ... * coefficient\n total_coefficients = ... + coefficient\n return round( ... / total_coefficients , 1 )\n else:\n return -1\n
resultats = {'Dupont':{ 'DS1' : [15.5, 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [13, 4],\n 'PROJET1' : [16, 3],\n 'DS3' : [14, 4]},\n 'Durand':{ 'DS1' : [6 , 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [8, 4],\n 'PROJET1' : [9, 3],\n 'IE1' : [7, 2],\n 'DS3' : [8, 4],\n 'DS4' :[15, 4]}}\n\ndef moyenne(nom):\n if nom in resultats:\n notes = resultats[nom]\n total_points = 0\n total_coefficients = 0\n for valeurs in notes.values():\n note , coefficient = valeurs\n total_points = total_points + note * coefficient\n total_coefficients = total_coefficients + coefficient\n return round( total_points / total_coefficients , 1 )\n else:\n return -1\n
Un professeur de NSI d\u00e9cide de g\u00e9rer les r\u00e9sultats de sa classe sous la forme d\u2019un\ndictionnaire :\n\n- les clefs sont les noms des \u00e9l\u00e8ves ;\n- les valeurs sont des dictionnaires dont les clefs sont les types d\u2019\u00e9preuves et les\nvaleurs sont les notes obtenues associ\u00e9es \u00e0 leurs coefficients.\n\nAvec :\n\n```python\nresultats = {'Dupont':{ 'DS1' : [15.5, 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [13, 4],\n 'PROJET1' : [16, 3],\n 'DS3' : [14, 4]},\n 'Durand':{ 'DS1' : [6 , 4],\n 'DM1' : [14.5, 1],\n 'DS2' : [8, 4],\n 'PROJET1' : [9, 3],\n 'IE1' : [7, 2],\n 'DS3' : [8, 4],\n 'DS4' :[15, 4]}}\n
L\u2019\u00e9l\u00e8ve dont le nom est Durand a ainsi obtenu au DS2 la note de 8 avec un coefficient 4. Le professeur cr\u00e9e une fonction moyenne
qui prend en param\u00e8tre le nom d\u2019un de ces \u00e9l\u00e8ves et lui renvoie sa moyenne arrondie au dixi\u00e8me.
Compl\u00e9ter le code du professeur ci-dessous :
def moyenne(nom):\n if nom in ...:\n notes = resultats[nom]\n total_points = ...\n total_coefficients = ...\n for ... in notes.values():\n note , coefficient = valeurs\n total_points = total_points + ... * coefficient\n total_coefficients = ... + coefficient\n return round( ... / total_coefficients , 1 )\n else:\n return -1\n
``` Remerciements pour le signalement et la correction des nombreuses erreurs : Alexandre Hainaut, No\u00e9 Pierre, Cyrille Jochault, S\u00e9bastien Rivillon, Cl\u00e9mentine et Laorine (AEFE Montr\u00e9al), Th\u00e9o EwzZer, Laurent Briend, Matteo Gaillard, Pierre Mouries.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/","title":"\u00c9preuve Pratique BNS 2023","text":"Les sujets ci-dessous correspondent \u00e0 la derni\u00e8re version officielle, publi\u00e9e le 25/01/2023. Pour signaler des erreurs \u00e9ventuelles : gilles.lassus@ac-bordeaux.fr
(merci \u00e0 R\u00e9mi Vanicat, Pierre Mouri\u00e8s, Cyrille Jochault, Vincent Bruneau, Tristan Bringuier, Mireille Coilhac)
T\u00e9l\u00e9chargements
.pdf
et .py
) : BNS_2023.zip (2,9 Mo)Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-011","title":"Exercice 01.1","text":"Exercice 01.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction verifie
qui prend en param\u00e8tre un tableau de valeurs num\u00e9riques non vide et qui renvoie True
si ce tableau est tri\u00e9 dans l\u2019ordre croissant, False
sinon.
Exemples :
Exemples :\n>>> verifie([0, 5, 8, 8, 9])\nTrue\n>>> verifie([8, 12, 4])\nFalse\n>>> verifie([-1, 4])\nTrue\n>>> verifie([5])\nTrue\n
def verifie(tab):\n for i in range(1, len(tab)):\n if tab[i] < tab[i-1]:\n return False\n return True\n
Programmer la fonction `verifie` qui prend en param\u00e8tre un tableau de valeurs num\u00e9riques non\nvide et qui renvoie `True` si ce tableau est tri\u00e9 dans l\u2019ordre croissant, `False` sinon.\n\nExemples :\n\n```python\nExemples :\n>>> verifie([0, 5, 8, 8, 9])\nTrue\n>>> verifie([8, 12, 4])\nFalse\n>>> verifie([-1, 4])\nTrue\n>>> verifie([5])\nTrue\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-012","title":"Exercice 01.2","text":"Exercice 01.2
\u00c9nonc\u00e9CorrectionSources MarkdownLes r\u00e9sultats d'un vote ayant trois issues possibles 'A', 'B' et 'C' sont stock\u00e9s dans un tableau.
Exemple :
urne = ['A', 'A', 'A', 'B', 'C', 'B', 'C', 'B', 'C', 'B']\n
La fonction depouille
doit permettre de compter le nombre de votes exprim\u00e9s pour chaque artiste. Elle prend en param\u00e8tre un tableau et renvoie le r\u00e9sultat dans un dictionnaire dont les cl\u00e9s sont les noms des artistes et les valeurs le nombre de votes en leur faveur.
La fonction vainqueur doit d\u00e9signer le nom du ou des gagnants. Elle prend en param\u00e8tre un dictionnaire dont la structure est celle du dictionnaire renvoy\u00e9 par la fonction depouille
et renvoie un tableau. Ce tableau peut donc contenir plusieurs \u00e9l\u00e9ments s\u2019il y a des artistes ex- aequo. Compl\u00e9ter les fonctions depouille
et vainqueur ci-apr\u00e8s pour qu\u2019elles renvoient les r\u00e9sultats attendus.
urne = ['A', 'A', 'A','B', 'C', 'B', 'C','B', 'C', 'B']\n\ndef depouille(urne):\n resultat = ...\n for bulletin in urne:\n if ...:\n resultat[bulletin] = resultat[bulletin] + 1\n else:\n ...\n return resultat\n\ndef vainqueur(election):\n vainqueur = ''\n nmax = 0\n for candidat in election:\n if ... > ... :\n nmax = ...\n vainqueur = candidat\n liste_finale = [nom for nom in election if election[nom] == ...]\n return ...\n
Exemples d\u2019utilisation :
>>> election = depouille(urne)\n>>> election\n{'A': 3, 'B': 4, 'C': 3}\n>>> vainqueur(election)\n['B']\n
urne = ['A', 'A', 'A', 'B', 'C', 'B', 'C', 'B', 'C', 'B']\n\ndef depouille(urne):\nresultat = {}\nfor bulletin in urne:\nif bulletin in resultat:\nresultat[bulletin] = resultat[bulletin] + 1\n else:\nresultat[bulletin] = 1\nreturn resultat\n\ndef vainqueur(election):\n vainqueur = '' #(1)\n nmax = 0\n for candidat in election:\nif election[candidat] > nmax :\nnmax = election[candidat]\nvainqueur = candidat #(2)\nliste_finale = [nom for nom in election if election[nom] == nmax]\nreturn liste_finale\n
vainqueur
est inutile, on ne s'en sert pas dans l'\u00e9laboration de la liste finale.Les r\u00e9sultats d'un vote ayant trois issues possibles 'A', 'B' et 'C' sont stock\u00e9s dans un tableau.\n\nExemple :\n\n```python\nurne = ['A', 'A', 'A', 'B', 'C', 'B', 'C', 'B', 'C', 'B']\n
La fonction depouille
doit permettre de compter le nombre de votes exprim\u00e9s pour chaque artiste. Elle prend en param\u00e8tre un tableau et renvoie le r\u00e9sultat dans un dictionnaire dont les cl\u00e9s sont les noms des artistes et les valeurs le nombre de votes en leur faveur.
La fonction vainqueur doit d\u00e9signer le nom du ou des gagnants. Elle prend en param\u00e8tre un dictionnaire dont la structure est celle du dictionnaire renvoy\u00e9 par la fonction depouille
et renvoie un tableau. Ce tableau peut donc contenir plusieurs \u00e9l\u00e9ments s\u2019il y a des artistes ex- aequo. Compl\u00e9ter les fonctions depouille
et vainqueur ci-apr\u00e8s pour qu\u2019elles renvoient les r\u00e9sultats attendus.
urne = ['A', 'A', 'A','B', 'C', 'B', 'C','B', 'C', 'B']\n\ndef depouille(urne):\n resultat = ...\n for bulletin in urne:\n if ...:\n resultat[bulletin] = resultat[bulletin] + 1\n else:\n ...\n return resultat\n\ndef vainqueur(election):\n vainqueur = ''\n nmax = 0\n for candidat in election:\n if ... > ... :\n nmax = ...\n vainqueur = candidat\n liste_finale = [nom for nom in election if election[nom] == ...]\n return ...\n
Exemples d\u2019utilisation :
>>> election = depouille(urne)\n>>> election\n{'A': 3, 'B': 4, 'C': 3}\n>>> vainqueur(election)\n['B']\n
```
Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-02","title":"\u25b6 Sujet 02","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-021","title":"Exercice 02.1","text":"Exercice 02.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction indices_maxi
qui prend en param\u00e8tre une liste tab
, non vide, de nombres entiers et renvoie un couple donnant d\u2019une part le plus grand \u00e9l\u00e9ment de cette liste et d\u2019autre part la liste des indices de la liste tab
o\u00f9 appara\u00eet ce plus grand \u00e9l\u00e9ment.
Exemple :
>>> indices_maxi([1, 5, 6, 9, 1, 2, 3, 7, 9, 8])\n(9, [3, 8])\n>>> indices_maxi([7])\n(7, [0])\n
def indices_maxi(tab):\n val_max = tab[0]\n ind_max = []\n for i in range(len(tab)):\n if tab[i] > val_max:\n val_max = tab[i]\n for i in range(len(tab)):\n if tab[i] == val_max:\n ind_max.append(i)\n return (val_max, ind_max)\n
\u00c9crire une fonction `indices_maxi` qui prend en param\u00e8tre une liste `tab`, non vide, de\nnombres entiers et renvoie un couple donnant d\u2019une part le plus grand \u00e9l\u00e9ment de cette\nliste et d\u2019autre part la liste des indices de la liste `tab` o\u00f9 appara\u00eet ce plus grand \u00e9l\u00e9ment.\n\nExemple :\n```python\n>>> indices_maxi([1, 5, 6, 9, 1, 2, 3, 7, 9, 8])\n(9, [3, 8])\n>>> indices_maxi([7])\n(7, [0])\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-022","title":"Exercice 02.2","text":"Exercice 02.2
\u00c9nonc\u00e9CorrectionSources MarkdownCet exercice utilise des piles qui seront repr\u00e9sent\u00e9es en Python par des listes (type list
).
On rappelle que l\u2019expression liste_1 = list(liste)
fait une copie de liste
ind\u00e9pendante de liste
, que l\u2019expression x = liste.pop()
enl\u00e8ve le sommet de la pile liste
et le place dans la variable x
et, enfin, que l\u2019expression liste.append(v)
place la valeur v
au sommet de la pile liste
.
Compl\u00e9ter le code Python de la fonction positif
ci-dessous qui prend une pile liste
de nombres entiers en param\u00e8tre et qui renvoie la pile des entiers positifs dans le m\u00eame ordre, sans modifier la variable liste
.
def positif(pile):\n pile_1 = ...(pile)\n pile_2 = ...\n while pile_1 != []:\n x = ...\n if ... >= 0:\n pile_2.append(...)\n while pile_2 != ...:\n x = pile_2.pop()\n ...\n return pile_1\n
Exemple :
>>> positif([-1, 0, 5, -3, 4, -6, 10, 9, -8])\n[0, 5, 4, 10, 9]\n>>> positif([-2])\n[]\n
def positif(pile):\npile_1 = list(pile)\npile_2 = []\nwhile pile_1 != []:\nx = pile_1.pop()\nif x >= 0:\npile_2.append(x)\nwhile pile_2 != []:\nx = pile_2.pop()\npile_1.append(x)\nreturn pile_1\n
Cet exercice utilise des piles qui seront repr\u00e9sent\u00e9es en Python par des listes (type `list`).\n\nOn rappelle que l\u2019expression `liste_1 = list(liste)` fait une copie de `liste `ind\u00e9pendante de `liste`, que\nl\u2019expression `x = liste.pop()` enl\u00e8ve le sommet de la pile `liste` et le place dans la variable `x` et,\nenfin, que l\u2019expression `liste.append(v)` place la valeur `v` au sommet de la pile `liste`.\n\nCompl\u00e9ter le code Python de la fonction `positif` ci-dessous qui prend une pile `liste` de\nnombres entiers en param\u00e8tre et qui renvoie la pile des entiers positifs dans le m\u00eame\nordre, sans modifier la variable `liste`.\n\n```python linenums='1'\ndef positif(pile):\n pile_1 = ...(pile)\n pile_2 = ...\n while pile_1 != []:\n x = ...\n if ... >= 0:\n pile_2.append(...)\n while pile_2 != ...:\n x = pile_2.pop()\n ...\n return pile_1\n
Exemple :
>>> positif([-1, 0, 5, -3, 4, -6, 10, 9, -8])\n[0, 5, 4, 10, 9]\n>>> positif([-2])\n[]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-03","title":"\u25b6 Sujet 03","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-031","title":"Exercice 03.1","text":"Exercice 03.1
\u00c9nonc\u00e9CorrectionSource MarkdownDans cet exercice, les nombres sont des entiers ou des flottants.
\u00c9crire une fonction moyenne
renvoyant la moyenne pond\u00e9r\u00e9e d\u2019une liste non vide, pass\u00e9e en param\u00e8tre, de tuples \u00e0 deux \u00e9l\u00e9ments de la forme (valeur
, coefficient
) o\u00f9 valeur
et coefficient
sont des nombres positifs ou nuls. Si la somme des coefficients est nulle, la fonction renvoie None
, si la somme des coefficients est non nulle, la fonction renvoie, sous forme de flottant, la moyenne des valeurs affect\u00e9es de leur coefficient.
Exemple :
>>> moyenne([(8, 2), (12, 0), (13.5, 1), (5, 0.5)])\n9.142857142857142\n>>> moyenne([(3, 0), (5, 0)])\nNone\n
Dans le premier exemple la moyenne est calcul\u00e9e par la formule :
\\(\\dfrac{8 \\times 2 + 12 \\times 0 + 13,5 \\times 1 + 5 \\times 0,5}{2+0+1+0,5}\\)
def moyenne(tab):\n somme = 0\n coeffs = 0\n for couple in tab:\n somme += couple[0] * couple[1]\n coeffs += couple[1]\n if coeffs == 0:\n return None\n return somme / coeffs\n
Dans cet exercice, les nombres sont des entiers ou des flottants.\n\n\u00c9crire une fonction `moyenne` renvoyant la moyenne pond\u00e9r\u00e9e d\u2019une liste non vide,\npass\u00e9e en param\u00e8tre, de tuples \u00e0 deux \u00e9l\u00e9ments de la forme (`valeur`,\n`coefficient`) o\u00f9 `valeur` et `coefficient` sont des nombres positifs ou nuls.\nSi la somme des coefficients est nulle, la fonction renvoie `None`, si la somme des\ncoefficients est non nulle, la fonction renvoie, sous forme de flottant, la moyenne des\nvaleurs affect\u00e9es de leur coefficient.\n\nExemple :\n```python\n>>> moyenne([(8, 2), (12, 0), (13.5, 1), (5, 0.5)])\n9.142857142857142\n>>> moyenne([(3, 0), (5, 0)])\nNone\n```\n\nDans le premier exemple la moyenne est calcul\u00e9e par la formule :\n\n$\\dfrac{8 \\times 2 + 12 \\times 0 + 13,5 \\times 1 + 5 \\times 0,5}{2+0+1+0,5}$\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-032","title":"Exercice 03.2","text":"Exercice 03.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn travaille sur des dessins en noir et blanc obtenu \u00e0 partir de pixels noirs et blancs : La figure \u00ab c\u0153ur \u00bb ci-dessus va servir d\u2019exemple. On la repr\u00e9sente par une grille de nombres, c\u2019est-\u00e0-dire par une liste compos\u00e9e de sous-listes de m\u00eame longueurs. Chaque sous-liste repr\u00e9sentera donc une ligne du dessin.
Dans le code ci-dessous, la fonction affiche
permet d\u2019afficher le dessin. Les pixels noirs (1 dans la grille) seront repr\u00e9sent\u00e9s par le caract\u00e8re \"*\" et les blancs (0 dans la grille) par deux espaces.
La fonction zoomListe
prend en argument une liste liste_depart
et un entier k
. Elle renvoie une liste o\u00f9 chaque \u00e9l\u00e9ment de liste_depart
est dupliqu\u00e9 k
fois.
La fonction zoomDessin
prend en argument la grille dessin
et renvoie une grille o\u00f9 toutes les lignes de dessin
sont zoom\u00e9es k
fois et r\u00e9p\u00e9t\u00e9es k
fois.
Soit le code ci-dessous :
coeur = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], \\\n [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0], \\\n [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \\\n [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0], \\\n [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n\ndef affiche(dessin):\n''' affichage d'une grille : les 1 sont repr\u00e9sent\u00e9s par \n des \" *\" , les 0 par deux espaces \" \" '''\n for ligne in dessin:\n for col in ligne:\n if col == 1:\n print(\" *\", end=\"\")\n else:\n print(\" \", end=\"\")\n print()\n\n\ndef zoomListe(liste_depart,k):\n'''renvoie une liste contenant k fois chaque \n \u00e9l\u00e9ment de liste_depart'''\n liste_zoom = ...\n for elt in ... :\n for i in range(k):\n ...\n return liste_zoom\n\ndef zoomDessin(grille,k):\n'''renvoie une grille o\u00f9 les lignes sont zoom\u00e9es k fois \n ET r\u00e9p\u00e9t\u00e9es k fois'''\n grille_zoom=[]\n for elt in grille:\n liste_zoom = ...\n for i in range(k):\n ... .append(...)\n return grille_zoom\n
R\u00e9sultats \u00e0 obtenir :
>>> affiche(coeur)\n
>>> affiche(zoomDessin(coeur,3))\n
* * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * \n * * * \n * * *\n
coeur = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], \\\n [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0], \\\n [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \\\n [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0], \\\n [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n\ndef affiche(dessin):\n''' affichage d'une grille : les 1 sont repr\u00e9sent\u00e9s par \n des \" *\" , les 0 par deux espaces \" \" '''\n for ligne in dessin:\n for col in ligne:\n if col == 1:\n print(' *',end='')\n else:\n print(' ',end='')\n print()\n\n\ndef zoomListe(liste_depart, k):\n'''renvoie une liste contenant k fois chaque \n \u00e9l\u00e9ment de liste_depart'''\nliste_zoom = []\nfor elt in liste_depart:\nfor i in range(k):\nliste_zoom.append(elt)\nreturn liste_zoom\n\ndef zoomDessin(grille, k):\n'''renvoie une grille o\u00f9 les lignes sont zoom\u00e9es k fois \n ET r\u00e9p\u00e9t\u00e9es k fois'''\n grille_zoom = []\n for elt in grille:\nliste_zoom = zoomListe(elt, k)\nfor i in range(k):\ngrille_zoom.append(liste_zoom)\nreturn grille_zoom\n
![image](data2023/03_coeur.png){: .center width=30%}\nOn travaille sur des dessins en noir et blanc obtenu \u00e0 partir de pixels noirs et blancs :\nLa figure \u00ab c\u0153ur \u00bb ci-dessus va servir d\u2019exemple.\nOn la repr\u00e9sente par une grille de nombres, c\u2019est-\u00e0-dire par une liste compos\u00e9e de sous-listes de m\u00eame longueurs.\nChaque sous-liste repr\u00e9sentera donc une ligne du dessin.\n\nDans le code ci-dessous, la fonction `affiche` permet d\u2019afficher le dessin. Les pixels noirs\n(1 dans la grille) seront repr\u00e9sent\u00e9s par le caract\u00e8re \"*\" et les blancs (0 dans la grille) par\ndeux espaces.\n\nLa fonction `zoomListe` prend en argument une liste `liste_depart` et un entier `k`. Elle\nrenvoie une liste o\u00f9 chaque \u00e9l\u00e9ment de `liste_depart` est dupliqu\u00e9 `k` fois.\n\nLa fonction `zoomDessin` prend en argument la grille `dessin` et renvoie une grille o\u00f9\ntoutes les lignes de `dessin` sont zoom\u00e9es `k` fois et r\u00e9p\u00e9t\u00e9es `k` fois.\n\nSoit le code ci-dessous :\n\n```python linenums='1'\ncoeur = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0], \\\n [0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0], \\\n [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], \\\n [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \\\n [0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0], \\\n [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], \\\n [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]\n\ndef affiche(dessin):\n ''' affichage d'une grille : les 1 sont repr\u00e9sent\u00e9s par \n des \" *\" , les 0 par deux espaces \" \" '''\n for ligne in dessin:\n for col in ligne:\n if col == 1:\n print(\" *\", end=\"\")\n else:\n print(\" \", end=\"\")\n print()\n\n\ndef zoomListe(liste_depart,k):\n '''renvoie une liste contenant k fois chaque \n \u00e9l\u00e9ment de liste_depart'''\n liste_zoom = ...\n for elt in ... :\n for i in range(k):\n ...\n return liste_zoom\n\ndef zoomDessin(grille,k):\n '''renvoie une grille o\u00f9 les lignes sont zoom\u00e9es k fois \n ET r\u00e9p\u00e9t\u00e9es k fois'''\n grille_zoom=[]\n for elt in grille:\n liste_zoom = ...\n for i in range(k):\n ... .append(...)\n return grille_zoom\n
R\u00e9sultats \u00e0 obtenir :
>>> affiche(coeur)\n
>>> affiche(zoomDessin(coeur,3))\n
* * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n * * * * * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n* * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * * * * \n * * * \n * * * \n * * *\n
```
Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-04","title":"\u25b6 Sujet 04","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-041","title":"Exercice 04.1","text":"Exercice 04.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction a_doublon
qui prend en param\u00e8tre une liste tri\u00e9e de nombres et renvoie True
si la liste contient au moins deux nombres identiques, False
sinon.
Par exemple :
>>> a_doublon([])\nFalse\n>>> a_doublon([1])\nFalse\n>>> a_doublon([1, 2, 4, 6, 6])\nTrue\n>>> a_doublon([2, 5, 7, 7, 7, 9])\nTrue\n>>> a_doublon([0, 2, 3])\nFalse\n
def a_doublon(lst):\n for i in range(len(lst)-1):\n if lst[i] == lst[i+1]:\n return True\n return False\n
\u00c9crire une fonction `a_doublon` qui prend en param\u00e8tre une liste **tri\u00e9e** de nombres et\nrenvoie `True` si la liste contient au moins deux nombres identiques, `False` sinon.\n\nPar exemple :\n\n```python\n>>> a_doublon([])\nFalse\n>>> a_doublon([1])\nFalse\n>>> a_doublon([1, 2, 4, 6, 6])\nTrue\n>>> a_doublon([2, 5, 7, 7, 7, 9])\nTrue\n>>> a_doublon([0, 2, 3])\nFalse\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-042","title":"Exercice 04.2","text":"Exercice 04.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn souhaite g\u00e9n\u00e9rer des grilles du jeu de d\u00e9mineur \u00e0 partir de la position des bombes \u00e0 placer. On se limite \u00e0 la g\u00e9n\u00e9ration de grilles carr\u00e9es de taille \\(n \\times n\\) o\u00f9 \\(n\\) est le nombre de bombes du jeu.
Dans le jeu du d\u00e9mineur, chaque case de la grille contient soit une bombe, soit une valeur qui correspond aux nombres de bombes situ\u00e9es dans le voisinage direct de la case (au- dessus, en dessous, \u00e0 droite, \u00e0 gauche ou en diagonale : chaque case a donc 8 voisins si elle n'est pas situ\u00e9e au bord de la grille).
Voici un exemple de grille \\(5 \\times 5\\) de d\u00e9mineur dans laquelle la bombe est repr\u00e9sent\u00e9e par une \u00e9toile :
On utilise une liste de listes pour repr\u00e9senter la grille et on choisit de coder une bombe par la valeur -1.
L'exemple ci-contre sera donc cod\u00e9 par la liste :
[[1, 1, 1, 0, 0],\n[1, -1, 1, 1, 1],\n[2, 2, 3, 2, -1],\n[1, -1, 2, -1, 3],\n[1, 1, 2, 2, -1]]\n
Compl\u00e9ter le code suivant afin de g\u00e9n\u00e9rer des grilles de d\u00e9mineur, on pourra v\u00e9rifier que l\u2019instruction genere_grille([(1, 1), (2, 4), (3, 1), (3, 3), (4, 4)])
produit bien la liste donn\u00e9e en exemple.
def voisinage(n, ligne, colonne):\n\"\"\" Renvoie la liste des coordonn\u00e9es des voisins de la case\n (ligne, colonne) en g\u00e9rant les cases sur les bords. \"\"\"\n voisins = []\n for l in range(max(0,ligne-1), min(n, ligne+2)):\n for c in range(max(0, colonne-1), min(n, colonne+2)):\n if (l, c) != (ligne, colonne):\n voisins.append((l,c))\n return voisins\n\n\ndef incremente_voisins(grille, ligne, colonne):\n\"\"\" Incr\u00e9mente de 1 toutes les cases voisines d'une bombe.\"\"\"\n voisins = ...\n for l, c in voisins:\n if grille[l][c] != ...: # si ce n'est pas une bombe\n ... # on ajoute 1 \u00e0 sa valeur\n\n\n\ndef genere_grille(bombes):\n\"\"\" Renvoie une grille de d\u00e9mineur de taille nxn o\u00f9 n est\n le nombre de bombes, en pla\u00e7ant les bombes \u00e0 l'aide de\n la liste bombes de coordonn\u00e9es (tuples) pass\u00e9e en\n param\u00e8tre. \"\"\"\n n = len(bombes)\n # Initialisation d'une grille nxn remplie de 0\n grille = [[0 for colonne in range(n)] for ligne in range(n)]\n # Place les bombes et calcule les valeurs des autres cases\n for ligne, colonne in bombes:\n grille[ligne][colonne] = ... # place la bombe\n ... # incr\u00e9mente ses voisins\n\n return grille\n
def voisinage(n, ligne, colonne):\n\"\"\" Renvoie la liste des coordonn\u00e9es des voisins de la case\n (ligne, colonne) en g\u00e9rant les cases sur les bords. \"\"\"\n voisins = []\n for l in range(max(0,ligne-1), min(n, ligne+2)):\n for c in range(max(0, colonne-1), min(n, colonne+2)):\n if (l, c) != (ligne, colonne):\n voisins.append((l,c))\n return voisins\n\n\ndef incremente_voisins(grille, ligne, colonne):\n\"\"\" Incr\u00e9mente de 1 toutes les cases voisines d'une bombe.\"\"\"\nvoisins = voisinage(len(grille), ligne, colonne)\nfor l, c in voisins:\nif grille[l][c] != -1: # si ce n'est pas une bombe\ngrille[l][c] += 1 # on ajoute 1 \u00e0 sa valeur\ndef genere_grille(bombes):\n\"\"\" Renvoie une grille de d\u00e9mineur de taille nxn o\u00f9 n est\n le nombre de bombes, en pla\u00e7ant les bombes \u00e0 l'aide de\n la liste bombes de coordonn\u00e9es (tuples) pass\u00e9e en\n param\u00e8tre. \"\"\"\n n = len(bombes)\n # Initialisation d'une grille nxn remplie de 0\n grille = [[0 for colonne in range(n)] for ligne in range(n)]\n # Place les bombes et calcule les valeurs des autres cases\n for ligne, colonne in bombes:\ngrille[ligne][colonne] = -1 # place la bombe\nincremente_voisins(grille, ligne, colonne) # incr\u00e9mente ses voisins\nreturn grille\n
On souhaite g\u00e9n\u00e9rer des grilles du jeu de d\u00e9mineur \u00e0 partir de la position des bombes \u00e0\nplacer. \nOn se limite \u00e0 la g\u00e9n\u00e9ration de grilles carr\u00e9es de taille $n \\times n$ o\u00f9 $n$ est le nombre de bombes du jeu. \n\nDans le jeu du d\u00e9mineur, chaque case de la grille contient soit une bombe, soit une valeur\nqui correspond aux nombres de bombes situ\u00e9es dans le voisinage direct de la case (au-\ndessus, en dessous, \u00e0 droite, \u00e0 gauche ou en diagonale : chaque case a donc 8 voisins si\nelle n'est pas situ\u00e9e au bord de la grille).\n\nVoici un exemple de grille $5 \\times 5$ de d\u00e9mineur dans laquelle la bombe est repr\u00e9sent\u00e9e par une \u00e9toile :\n\n![image](data2023/04grille.png){: .center}\n\n\nOn utilise une liste de listes pour repr\u00e9senter la grille et on choisit de coder une bombe par la valeur -1.\n\nL'exemple ci-contre sera donc cod\u00e9 par la liste :\n\n```python\n[[1, 1, 1, 0, 0],\n[1, -1, 1, 1, 1],\n[2, 2, 3, 2, -1],\n[1, -1, 2, -1, 3],\n[1, 1, 2, 2, -1]]\n
Compl\u00e9ter le code suivant afin de g\u00e9n\u00e9rer des grilles de d\u00e9mineur, on pourra v\u00e9rifier que l\u2019instruction genere_grille([(1, 1), (2, 4), (3, 1), (3, 3), (4, 4)])
produit bien la liste donn\u00e9e en exemple.
def voisinage(n, ligne, colonne):\n\"\"\" Renvoie la liste des coordonn\u00e9es des voisins de la case\n (ligne, colonne) en g\u00e9rant les cases sur les bords. \"\"\"\n voisins = []\n for l in range(max(0,ligne-1), min(n, ligne+2)):\n for c in range(max(0, colonne-1), min(n, colonne+2)):\n if (l, c) != (ligne, colonne):\n voisins.append((l,c))\n return voisins\n\n\ndef incremente_voisins(grille, ligne, colonne):\n\"\"\" Incr\u00e9mente de 1 toutes les cases voisines d'une bombe.\"\"\"\n voisins = ...\n for l, c in voisins:\n if grille[l][c] != ...: # si ce n'est pas une bombe\n ... # on ajoute 1 \u00e0 sa valeur\n\n\n\ndef genere_grille(bombes):\n\"\"\" Renvoie une grille de d\u00e9mineur de taille nxn o\u00f9 n est\n le nombre de bombes, en pla\u00e7ant les bombes \u00e0 l'aide de\n la liste bombes de coordonn\u00e9es (tuples) pass\u00e9e en\n param\u00e8tre. \"\"\"\n n = len(bombes)\n # Initialisation d'une grille nxn remplie de 0\n grille = [[0 for colonne in range(n)] for ligne in range(n)]\n # Place les bombes et calcule les valeurs des autres cases\n for ligne, colonne in bombes:\n grille[ligne][colonne] = ... # place la bombe\n ... # incr\u00e9mente ses voisins\n\n return grille\n
```
Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-05","title":"\u25b6 Sujet 05","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-051","title":"Exercice 05.1","text":"Exercice 05.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire en python deux fonctions :
lancer
de param\u00e8tre n
, un entier positif, qui renvoie un tableau de type list
de n
entiers obtenus al\u00e9atoirement entre 1 et 6 (1 et 6 inclus) ;
paire_6
de param\u00e8tre tab
, un tableau de type list
de n
entiers entre 1 et 6 obtenus al\u00e9atoirement, qui renvoie un bool\u00e9en \u00e9gal \u00e0 True
si le nombre de 6 est sup\u00e9rieur ou \u00e9gal \u00e0 2, False
sinon.
On pourra utiliser la fonction randint(a,b)
du module random
pour laquelle la documentation officielle est la suivante :
Renvoie un entier al\u00e9atoire N tel que a <=N <= b.
Exemples :
>>> lancer1 = lancer(5)\n[5, 6, 6, 2, 2]\n>>> paire_6(lancer1)\nTrue\n>>> lancer2 = lancer(5)\n[6, 5, 1, 6, 6]\n>>> paire_6(lancer2)\nTrue\n>>> lancer3 = lancer(3)\n[2, 2, 6]\n>>> paire_6(lancer3)\nFalse\n>>> lancer4 = lancer(0)\n[]\n>>> paire_6(lancer4)\nFalse\n
from random import randint\n\ndef lancer(n):\n return [randint(1,6) for _ in range(n)]\n\ndef paire_6(tab):\n nb = 0\n for elt in tab:\n if elt == 6:\n nb += 1\n if nb >=2 :\n return True\n else:\n return False\n
\u00c9crire en python deux fonctions :\n\n- `lancer` de param\u00e8tre `n`, un entier positif, qui renvoie un tableau de type `list` de\n`n` entiers obtenus al\u00e9atoirement entre 1 et 6 (1 et 6 inclus) ;\n\n- `paire_6` de param\u00e8tre `tab`, un tableau de type `list` de `n` entiers entre 1 et\n6 obtenus al\u00e9atoirement, qui renvoie un bool\u00e9en \u00e9gal \u00e0 `True` si le nombre de 6\nest sup\u00e9rieur ou \u00e9gal \u00e0 2, `False` sinon.\n\nOn pourra utiliser la fonction `randint(a,b)` du module `random` pour laquelle la\ndocumentation officielle est la suivante :\n\n`Renvoie un entier al\u00e9atoire N tel que a <=N <= b.`\n\nExemples :\n\n```python\n>>> lancer1 = lancer(5)\n[5, 6, 6, 2, 2]\n>>> paire_6(lancer1)\nTrue\n>>> lancer2 = lancer(5)\n[6, 5, 1, 6, 6]\n>>> paire_6(lancer2)\nTrue\n>>> lancer3 = lancer(3)\n[2, 2, 6]\n>>> paire_6(lancer3)\nFalse\n>>> lancer4 = lancer(0)\n[]\n>>> paire_6(lancer4)\nFalse\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-052","title":"Exercice 05.2","text":"Exercice 05.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re une image en 256 niveaux de gris que l\u2019on repr\u00e9sente par une grille de nombres, c\u2019est-\u00e0-dire une liste compos\u00e9e de sous-listes toutes de longueurs identiques.
La largeur de l\u2019image est donc la longueur d\u2019une sous-liste et la hauteur de l\u2019image est le nombre de sous-listes.
Chaque sous-liste repr\u00e9sente une ligne de l\u2019image et chaque \u00e9l\u00e9ment des sous-listes est un entier compris entre 0 et 255, repr\u00e9sentant l\u2019intensit\u00e9 lumineuse du pixel.
Le n\u00e9gatif d\u2019une image est l\u2019image constitu\u00e9e des pixels x_n
tels que x_n + x_i = 255
o\u00f9 x_i
est le pixel correspondant de l\u2019image initiale.
Compl\u00e9ter le programme suivant :
def nbLig(image):\n'''renvoie le nombre de lignes de l'image'''\n return ...\n\ndef nbCol(image):\n'''renvoie la largeur de l'image'''\n return ...\n\ndef negatif(image):\n'''renvoie le negatif de l'image sous la forme\n d'une liste de listes'''\n\n # on cree une image de 0 aux memes dimensions que le parametre image\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))]\n\n for i in range(nbLig(image)):\n for j in range(...):\n L[i][j] = ...\n return L\n\ndef binaire(image, seuil):\n'''renvoie une image binarisee de l'image sous la forme\n d'une liste de listes contenant des 0 si la valeur\n du pixel est strictement inferieure au seuil\n et 1 sinon'''\n\n # on cree une image de 0 aux memes dimensions que le parametre image\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))]\n\n for i in range(nbLig(image)):\n for j in range(...):\n if image[i][j] < ... :\n L[i][j] = ...\n else:\n L[i][j] = ...\n return L\n
Exemples :
>>> img=[[20, 34, 254, 145, 6], [23, 124, 237, 225, 69], [197, 174,\n207, 25, 87], [255, 0, 24, 197, 189]]\n>>> nbLig(img)\n4\n>>> nbCol(img)\n5\n>>> negatif(img)\n[[235, 221, 1, 110, 249], [232, 131, 18, 30, 186], [58, 81, 48, 230,\n168], [0, 255, 231, 58, 66]]\n>>> binaire(img,120)\n[[0, 0, 1, 1, 0], [0, 1, 1, 1, 0], [1, 1, 1, 0, 0], [1, 0, 0, 1, 1]]\n
def nbLig(image):\n'''renvoie le nombre de lignes de l'image'''\nreturn len(image)\ndef nbCol(image):\n'''renvoie la largeur de l'image'''\nreturn len(image[0])\ndef negatif(image):\n'''renvoie le negatif de l'image sous la forme\n d'une liste de listes'''\n\n # on cree une image de 0 aux memes dimensions que le parametre image\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))]\n\n for i in range(nbLig(image)):\nfor j in range(nbCol(image)):\nL[i][j] = 255 - image[i][j]\nreturn L\n\ndef binaire(image, seuil):\n'''renvoie une image binarisee de l'image sous la forme\n d'une liste de listes contenant des 0 si la valeur\n du pixel est strictement inferieure au seuil\n et 1 sinon'''\n\n # on cree une image de 0 aux memes dimensions que le parametre image\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))]\n\n for i in range(nbLig(image)):\nfor j in range(nbCol(image)):\nif image[i][j] < seuil :\nL[i][j] = 0\nelse:\nL[i][j] = 1\nreturn L\n
On consid\u00e8re une image en 256 niveaux de gris que l\u2019on repr\u00e9sente par une grille de\nnombres, c\u2019est-\u00e0-dire une liste compos\u00e9e de sous-listes toutes de longueurs identiques.\n\n\nLa largeur de l\u2019image est donc la longueur d\u2019une sous-liste et la hauteur de l\u2019image est le\nnombre de sous-listes.\n\n\nChaque sous-liste repr\u00e9sente une ligne de l\u2019image et chaque \u00e9l\u00e9ment des sous-listes est\nun entier compris entre 0 et 255, repr\u00e9sentant l\u2019intensit\u00e9 lumineuse du pixel.\n\n\nLe n\u00e9gatif d\u2019une image est l\u2019image constitu\u00e9e des pixels `x_n` tels que\n`x_n + x_i = 255` o\u00f9 `x_i` est le pixel correspondant de l\u2019image initiale.\n\nCompl\u00e9ter le programme suivant :\n```python linenums='1'\ndef nbLig(image):\n '''renvoie le nombre de lignes de l'image'''\n return ...\n\ndef nbCol(image):\n '''renvoie la largeur de l'image'''\n return ...\n\ndef negatif(image):\n '''renvoie le negatif de l'image sous la forme\n d'une liste de listes'''\n\n # on cree une image de 0 aux memes dimensions que le parametre image\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))]\n\n for i in range(nbLig(image)):\n for j in range(...):\n L[i][j] = ...\n return L\n\ndef binaire(image, seuil):\n '''renvoie une image binarisee de l'image sous la forme\n d'une liste de listes contenant des 0 si la valeur\n du pixel est strictement inferieure au seuil\n et 1 sinon'''\n\n # on cree une image de 0 aux memes dimensions que le parametre image\n L = [[0 for k in range(nbCol(image))] for i in range(nbLig(image))]\n\n for i in range(nbLig(image)):\n for j in range(...):\n if image[i][j] < ... :\n L[i][j] = ...\n else:\n L[i][j] = ...\n return L\n
Exemples :
>>> img=[[20, 34, 254, 145, 6], [23, 124, 237, 225, 69], [197, 174,\n207, 25, 87], [255, 0, 24, 197, 189]]\n>>> nbLig(img)\n4\n>>> nbCol(img)\n5\n>>> negatif(img)\n[[235, 221, 1, 110, 249], [232, 131, 18, 30, 186], [58, 81, 48, 230,\n168], [0, 255, 231, 58, 66]]\n>>> binaire(img,120)\n[[0, 0, 1, 1, 0], [0, 1, 1, 1, 0], [1, 1, 1, 0, 0], [1, 0, 0, 1, 1]]\n
```
Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-06","title":"\u25b6 Sujet 06","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-061","title":"Exercice 06.1","text":"Exercice 06.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction recherche
, prenant en param\u00e8tre un tableau non vide tab
(type list
) d'entiers et un entier n
, et qui renvoie l'indice de la derni\u00e8re occurrence de l'\u00e9l\u00e9ment cherch\u00e9. Si l'\u00e9l\u00e9ment n'est pas pr\u00e9sent, la fonction renvoie la longueur du tableau.
Exemples
>>> recherche([5, 3],1)\n2\n>>> recherche([2,4],2)\n0\n>>> recherche([2,3,5,2,4],2)\n3\n
def recherche(tab, n):\n indice_solution = len(tab)\n for i in range(len(tab)):\n if tab[i] == n:\n indice_solution = i\n return indice_solution\n
Programmer la fonction `recherche`, prenant en param\u00e8tre un tableau non vide `tab` (type `list`) d'entiers et un entier `n`, et qui renvoie l'indice de la **derni\u00e8re** occurrence de l'\u00e9l\u00e9ment cherch\u00e9. Si l'\u00e9l\u00e9ment n'est pas pr\u00e9sent, la fonction renvoie la longueur du tableau.\n\nExemples\n```python\n>>> recherche([5, 3],1)\n2\n>>> recherche([2,4],2)\n0\n>>> recherche([2,3,5,2,4],2)\n3\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-062","title":"Exercice 06.2","text":"Exercice 06.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn souhaite programmer une fonction donnant la distance la plus courte entre un point de d\u00e9part et une liste de points. Les points sont tous \u00e0 coordonn\u00e9es enti\u00e8res. Les points sont donn\u00e9s sous la forme d'un tuple de deux entiers. La liste des points \u00e0 traiter est donc un tableau de tuples.
On rappelle que la distance entre deux points du plan de coordonn\u00e9es \\((x;y)\\) et \\((x';y')\\) est donn\u00e9e par la formule :
\\[d=\\sqrt{(x-x')^2+(y-y')^2}\\]On importe pour cela la fonction racine carr\u00e9e (sqrt
) du module math
de Python.
Compl\u00e9ter le code des fonctions distance
et plus_courte_distance
fournies ci-dessous pour qu\u2019elles r\u00e9pondent \u00e0 leurs sp\u00e9cifications.
from math import sqrt # import de la fonction racine carr\u00e9e\n\ndef distance(point1, point2):\n\"\"\" Calcule et renvoie la distance entre deux points. \"\"\"\n return sqrt((...)**2 + (...)**2)\n\ndef plus_courte_distance(tab, depart):\n\"\"\" Renvoie le point du tableau tab se trouvant \u00e0 la plus courte distance du point depart.\"\"\"\n point = tab[0]\n min_dist = ...\n for i in range (1, ...):\n if distance(tab[i], depart)...:\n point = ...\n min_dist = ...\n return point\n
Exemples :
>>> distance((1, 0), (5, 3))\n5.0\n>>> distance((1, 0), (0, 1))\n1.4142135623730951\n>>> plus_courte_distance([(7, 9), (2, 5), (5, 2)], (0, 0))\n(2, 5)\n>>> plus_courte_distance([(7, 9), (2, 5), (5, 2)], (5, 2))\n(5, 2)\n
from math import sqrt\n\ndef distance(point1, point2):\n\"\"\" Calcule et renvoie la distance entre deux points. \"\"\"\nreturn sqrt((point1[0] - point2[0])**2 + ((point1[1] - point2[1]))**2)\ndef plus_courte_distance(tab, depart):\n\"\"\" Renvoie le point du tableau tab se trouvant \u00e0 la plus courte distance du point depart.\"\"\"\n point = tab[0]\nmin_dist = distance(point, depart)\nfor i in range (1, len(tab)):\nif distance(tab[i], depart) < min_dist:\npoint = tab[i]\nmin_dist = distance(tab[i], depart)\nreturn point\n
On souhaite programmer une fonction donnant la distance la plus courte entre un point\nde d\u00e9part et une liste de points. Les points sont tous \u00e0 coordonn\u00e9es enti\u00e8res.\nLes points sont donn\u00e9s sous la forme d'un tuple de deux entiers.\nLa liste des points \u00e0 traiter est donc un tableau de tuples.\n\nOn rappelle que la distance entre deux points du plan de coordonn\u00e9es $(x;y)$ et $(x';y')$\nest donn\u00e9e par la formule :\n\n$$d=\\sqrt{(x-x')^2+(y-y')^2}$$\n\nOn importe pour cela la fonction racine carr\u00e9e (`sqrt`) du module `math` de Python.\n\n\nCompl\u00e9ter le code des fonctions `distance` et `plus_courte_distance` fournies ci-dessous pour qu\u2019elles r\u00e9pondent \u00e0 leurs sp\u00e9cifications.\n\n```python linenums='1'\nfrom math import sqrt # import de la fonction racine carr\u00e9e\n\ndef distance(point1, point2):\n \"\"\" Calcule et renvoie la distance entre deux points. \"\"\"\n return sqrt((...)**2 + (...)**2)\n\ndef plus_courte_distance(tab, depart):\n \"\"\" Renvoie le point du tableau tab se trouvant \u00e0 la plus courte distance du point depart.\"\"\"\n point = tab[0]\n min_dist = ...\n for i in range (1, ...):\n if distance(tab[i], depart)...:\n point = ...\n min_dist = ...\n return point\n
Exemples :
>>> distance((1, 0), (5, 3))\n5.0\n>>> distance((1, 0), (0, 1))\n1.4142135623730951\n>>> plus_courte_distance([(7, 9), (2, 5), (5, 2)], (0, 0))\n(2, 5)\n>>> plus_courte_distance([(7, 9), (2, 5), (5, 2)], (5, 2))\n(5, 2)\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-07","title":"\u25b6 Sujet 07","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-071","title":"Exercice 07.1","text":"Exercice 07.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction fusion
prenant en param\u00e8tres deux tableaux non vides tab1
et tab2
(type list
) d'entiers, chacun dans l\u2019ordre croissant, et renvoyant un tableau tri\u00e9 dans l\u2019ordre croissant et contenant l\u2019ensemble des valeurs de tab1
et tab2
.
Exemples :
>>> fusion([3, 5], [2, 5])\n[2, 3, 5, 5]\n>>> fusion([-2, 4], [-3, 5, 10])\n[-3, -2, 4, 5, 10]\n>>> fusion([4], [2, 6])\n[2, 4, 6]\n
def fusion(tab1, tab2):\n tab_fusion = []\n i1 = 0\n i2 = 0\n while i1 < len(tab1) and i2 < len(tab2):\n if tab1[i1] < tab2[i2]:\n tab_fusion.append(tab1[i1])\n i1 += 1\n else:\n tab_fusion.append(tab2[i2])\n i2 += 1\n\n if i1 == len(tab1):\n while i2 < len(tab2):\n tab_fusion.append(tab2[i2])\n i2 += 1\n else:\n while i1 < len(tab1):\n tab_fusion.append(tab1[i1])\n i1 += 1 \n\n return tab_fusion\n
Programmer la fonction `fusion` prenant en param\u00e8tres deux tableaux non vides `tab1` et `tab2`\n(type `list`) d'entiers, chacun dans l\u2019ordre croissant, et renvoyant un tableau tri\u00e9 dans l\u2019ordre\ncroissant et contenant l\u2019ensemble des valeurs de `tab1` et `tab2`.\n\nExemples :\n\n```python\n>>> fusion([3, 5], [2, 5])\n[2, 3, 5, 5]\n>>> fusion([-2, 4], [-3, 5, 10])\n[-3, -2, 4, 5, 10]\n>>> fusion([4], [2, 6])\n[2, 4, 6]\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-072","title":"Exercice 07.2","text":"Exercice 07.2
\u00c9nonc\u00e9CorrectionSources MarkdownLe but de cet exercice est d\u2019\u00e9crire une fonction r\u00e9cursive traduire_romain
qui prend en param\u00e8tre une cha\u00eene de caract\u00e8res, non vide, repr\u00e9sentant un nombre \u00e9crit en chiffres romains et qui renvoie son \u00e9criture d\u00e9cimale.
Les chiffres romains consid\u00e9r\u00e9s sont : I, V, X, L, C, D et M. Ils repr\u00e9sentent respectivement les nombres 1, 5, 10, 50, 100, 500, et 1000 en base dix.
On dispose d\u2019un dictionnaire romains
dont les cl\u00e9s sont les caract\u00e8res apparaissant dans l\u2019\u00e9criture en chiffres romains et les valeurs sont les nombres entiers associ\u00e9s en \u00e9criture d\u00e9cimale :
romains = {\"I\":1, \"V\":5, \"X\":10, \"L\":50, \"C\":100, \"D\":500, \"M\":1000}
Le code de la fonction traduire_romain
fournie repose sur le principe suivant :
la valeur d\u2019un caract\u00e8re est ajout\u00e9e \u00e0 la valeur du reste de la cha\u00eene si ce caract\u00e8re a une valeur sup\u00e9rieure (ou \u00e9gale) \u00e0 celle du caract\u00e8re qui le suit ;
la valeur d\u2019un caract\u00e8re est retranch\u00e9e \u00e0 la valeur du reste de la cha\u00eene si ce caract\u00e8re a une valeur strictement inf\u00e9rieure \u00e0 celle du caract\u00e8re qui le suit.
Ainsi, XIV correspond au nombre 10 + 5 - 1 puisque :
la valeur de X (10) est sup\u00e9rieure \u00e0 celle de I (1), on ajoute donc 10 \u00e0 la valeur du reste de la cha\u00eene, c\u2019est-\u00e0-dire IV ;
la valeur de I (1) est strictement inf\u00e9rieure \u00e0 celle de V (5), on soustrait donc 1 \u00e0 la valeur du reste de la cha\u00eene, c\u2019est-\u00e0-dire V.
On rappelle que pour priver une cha\u00eene de caract\u00e8res de son premier caract\u00e8re, on utilisera l\u2019instruction :
nom_de_variable[1:]
Par exemple, si la variable mot
contient la cha\u00eene \"CDI\"
, mot[1:]
renvoie \"DI\"
.
romains = {\"I\":1, \"V\":5, \"X\":10, \"L\":50, \"C\":100, \"D\":500, \"M\":1000}\n\ndef traduire_romain(nombre):\n\"\"\" Renvoie l\u2019\u00e9criture d\u00e9cimale du nombre donn\u00e9 en chiffres\n romains \"\"\"\n if len(nombre) == 1:\n return ...\n elif romains[nombre[0]] >= ...\n return romains[nombre[0]] + ...\n else:\n return ...\n
Compl\u00e9ter le code de la fonction traduire_romain
et le tester.
Exemples :
>>> traduire_romain(\"XIV\")\n14\n>>> traduire_romain(\"CXLII\")\n142\n>>> traduire_romain(\"MMXXIII\")\n2023\n
romains = {\"I\":1, \"V\":5, \"X\":10, \"L\":50, \"C\":100, \"D\":500, \"M\":1000}\n\ndef traduire_romain(nombre):\n\"\"\" Renvoie l\u2019\u00e9criture d\u00e9cimale du nombre donn\u00e9 en chiffres\n romains \"\"\"\n if len(nombre) == 1:\nreturn romains[nombre]\nelif romains[nombre[0]] >= romains[nombre[1]]:\nreturn romains[nombre[0]] + traduire_romain(nombre[1:])\nelse:\nreturn traduire_romain(nombre[1:]) - romains[nombre[0]]\n
Le but de cet exercice est d\u2019\u00e9crire une fonction r\u00e9cursive `traduire_romain` qui prend\nen param\u00e8tre une cha\u00eene de caract\u00e8res, non vide, repr\u00e9sentant un nombre \u00e9crit en\nchiffres romains et qui renvoie son \u00e9criture d\u00e9cimale.\n\n\nLes chiffres romains consid\u00e9r\u00e9s sont : I, V, X, L, C, D et M. Ils repr\u00e9sentent\nrespectivement les nombres 1, 5, 10, 50, 100, 500, et 1000 en base dix.\n\n\nOn dispose d\u2019un dictionnaire `romains` dont les cl\u00e9s sont les caract\u00e8res apparaissant\ndans l\u2019\u00e9criture en chiffres romains et les valeurs sont les nombres entiers associ\u00e9s en\n\u00e9criture d\u00e9cimale :\n\n\n`romains = {\"I\":1, \"V\":5, \"X\":10, \"L\":50, \"C\":100, \"D\":500, \"M\":1000}`\n\n\nLe code de la fonction `traduire_romain` fournie repose sur le\nprincipe suivant :\n\n- la valeur d\u2019un caract\u00e8re est ajout\u00e9e \u00e0 la valeur du reste de la cha\u00eene si ce\ncaract\u00e8re a une valeur sup\u00e9rieure (ou \u00e9gale) \u00e0 celle du caract\u00e8re qui le suit ;\n\n- la valeur d\u2019un caract\u00e8re est retranch\u00e9e \u00e0 la valeur du reste de la cha\u00eene si ce\ncaract\u00e8re a une valeur strictement inf\u00e9rieure \u00e0 celle du caract\u00e8re qui le suit.\n\nAinsi, XIV correspond au nombre 10 + 5 - 1 puisque :\n\n- la valeur de X (10) est sup\u00e9rieure \u00e0 celle de I (1), on ajoute donc 10 \u00e0 la valeur du\nreste de la cha\u00eene, c\u2019est-\u00e0-dire IV ;\n\n- la valeur de I (1) est strictement inf\u00e9rieure \u00e0 celle de V (5), on soustrait donc 1 \u00e0\nla valeur du reste de la cha\u00eene, c\u2019est-\u00e0-dire V.\n\nOn rappelle que pour priver une cha\u00eene de caract\u00e8res de son premier caract\u00e8re, on\nutilisera l\u2019instruction :\n\n`nom_de_variable[1:]`\n\nPar exemple, si la variable `mot` contient la cha\u00eene `\"CDI\"`, `mot[1:]` renvoie `\"DI\"`.\n\n```python linenums='1'\nromains = {\"I\":1, \"V\":5, \"X\":10, \"L\":50, \"C\":100, \"D\":500, \"M\":1000}\n\ndef traduire_romain(nombre):\n \"\"\" Renvoie l\u2019\u00e9criture d\u00e9cimale du nombre donn\u00e9 en chiffres\n romains \"\"\"\n if len(nombre) == 1:\n return ...\n elif romains[nombre[0]] >= ...\n return romains[nombre[0]] + ...\n else:\n return ...\n
Compl\u00e9ter le code de la fonction traduire_romain
et le tester.
Exemples :
>>> traduire_romain(\"XIV\")\n14\n>>> traduire_romain(\"CXLII\")\n142\n>>> traduire_romain(\"MMXXIII\")\n2023\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-08","title":"\u25b6 Sujet 08","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-081","title":"Exercice 08.1","text":"Exercice 08.1
\u00c9nonc\u00e9CorrectionSource MarkdownSur le r\u00e9seau social TipTop, on s\u2019int\u00e9resse au nombre de \u00ab like \u00bb des abonn\u00e9s. Les donn\u00e9es sont stock\u00e9es dans des dictionnaires o\u00f9 les cl\u00e9s sont les pseudos et les valeurs correspondantes sont les nombres de \u00ab like \u00bb comme ci-dessous :
{'Bob': 102, 'Ada': 201, 'Alice': 103, 'Tim': 50}
\u00c9crire une fonction max_dico
qui :
dico
non vide dont les cl\u00e9s sont des cha\u00eenes de caract\u00e8res et les valeurs associ\u00e9es sont des entiers ;Exemples :
>>> max_dico({'Bob': 102, 'Ada': 201, 'Alice': 103, 'Tim': 50})\n('Ada', 201)\n>>> max_dico({'Alan': 222, 'Ada': 201, 'Eve': 220, 'Tim': 50})\n('Alan', 222)\n
def max_dico(dico):\n cle_max = ''\n val_max = 0\n for cle in dico:\n if dico[cle] > val_max:\n val_max = dico[cle]\n cle_max = cle\n return (cle_max, val_max)\n
Sur le r\u00e9seau social TipTop, on s\u2019int\u00e9resse au nombre de \u00ab like \u00bb des abonn\u00e9s.\nLes donn\u00e9es sont stock\u00e9es dans des dictionnaires o\u00f9 les cl\u00e9s sont les pseudos et les valeurs\ncorrespondantes sont les nombres de \u00ab like \u00bb comme ci-dessous :\n\n`{'Bob': 102, 'Ada': 201, 'Alice': 103, 'Tim': 50}`\n\n\u00c9crire une fonction `max_dico` qui :\n\n- Prend en param\u00e8tre un dictionnaire `dico` non vide dont les cl\u00e9s sont des cha\u00eenes de\ncaract\u00e8res et les valeurs associ\u00e9es sont des entiers ;\n- Renvoie un tuple dont :\n - La premi\u00e8re valeur est la cl\u00e9 du dictionnaire associ\u00e9e \u00e0 la valeur maximale ;\n - La seconde valeur est la premi\u00e8re valeur maximale pr\u00e9sente dans le\ndictionnaire.\n\nExemples :\n\n```python\n>>> max_dico({'Bob': 102, 'Ada': 201, 'Alice': 103, 'Tim': 50})\n('Ada', 201)\n>>> max_dico({'Alan': 222, 'Ada': 201, 'Eve': 220, 'Tim': 50})\n('Alan', 222)\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-082","title":"Exercice 08.2","text":"Exercice 08.2
\u00c9nonc\u00e9CorrectionSources MarkdownNous avons l\u2019habitude de noter les expressions arithm\u00e9tiques avec des parenth\u00e8ses comme par exemple : (2 + 3) \u00d7 5.
Il existe une autre notation utilis\u00e9e par certaines calculatrices, appel\u00e9e notation postfixe, qui n\u2019utilise pas de parenth\u00e8ses. L\u2019expression arithm\u00e9tique pr\u00e9c\u00e9dente est alors obtenue en saisissant successivement 2, puis 3, puis l\u2019op\u00e9rateur +, puis 5, et enfin l\u2019op\u00e9rateur \u00d7. On mod\u00e9lise cette saisie par le tableau [2, 3, '+', 5, '*'].
Autre exemple, la notation postfixe de 3 \u00d7 2 + 5 est mod\u00e9lis\u00e9e par le tableau :
[3, 2, '*', 5, '+'].
D\u2019une mani\u00e8re plus g\u00e9n\u00e9rale, la valeur associ\u00e9e \u00e0 une expression arithm\u00e9tique en notation postfixe est d\u00e9termin\u00e9e \u00e0 l\u2019aide d\u2019une pile en parcourant l\u2019expression arithm\u00e9tique de gauche \u00e0 droite de la fa\u00e7on suivante :
Dans le cadre de cet exercice, on se limitera aux op\u00e9rations \u00d7 et +.
Pour cet exercice, on dispose d\u2019une classe Pile
qui impl\u00e9mente les m\u00e9thodes de base sur la structure de pile.
Compl\u00e9ter le script de la fonction eval_expression
qui re\u00e7oit en param\u00e8tre une liste python repr\u00e9sentant la notation postfixe d\u2019une expression arithm\u00e9tique et qui renvoie sa valeur associ\u00e9e.
class Pile:\n\"\"\"Classe d\u00e9finissant une structure de pile.\"\"\"\n def __init__(self):\n self.contenu = []\n\n def est_vide(self):\n\"\"\"Renvoie le bool\u00e9en True si la pile est vide, False sinon.\"\"\"\n return self.contenu == []\n\n def empiler(self, v):\n\"\"\"Place l'\u00e9l\u00e9ment v au sommet de la pile\"\"\"\n self.contenu.append(v)\n\n def depiler(self):\n\"\"\"\n Retire et renvoie l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile,\n si la pile n\u2019est pas vide.\n \"\"\"\n if not self.est_vide():\n return self.contenu.pop()\n\n\ndef eval_expression(tab):\n p = Pile()\n for ... in tab:\n if element != '+' ... element != '*':\n p.empiler(...)\n else:\n if element == ...:\n resultat = p.depiler() + ...\n else:\n resultat = ...\n p.empiler(...)\n return ...\n
Exemple :
>>> eval_expression([2, 3, '+', 5, '*'])\n25\n
class Pile:\n\"\"\"Classe d\u00e9finissant une structure de pile.\"\"\"\n def __init__(self):\n self.contenu = []\n\n def est_vide(self):\n\"\"\"Renvoie le bool\u00e9en True si la pile est vide, False sinon.\"\"\"\n return self.contenu == []\n\n def empiler(self, v):\n\"\"\"Place l'\u00e9l\u00e9ment v au sommet de la pile\"\"\"\n self.contenu.append(v)\n\n def depiler(self):\n\"\"\"\n Retire et renvoie l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile,\n si la pile n\u2019est pas vide.\n \"\"\"\n if not self.est_vide():\n return self.contenu.pop()\n\n\ndef eval_expression(tab):\n p = Pile()\nfor element in tab:\nif element != '+' and element != '*':\np.empiler(element)\nelse:\nif element == '+':\nresultat = p.depiler() + p.depiler()\nelse:\nresultat = p.depiler() * p.depiler()\np.empiler(resultat)\nreturn p.depiler()\n
Nous avons l\u2019habitude de noter les expressions arithm\u00e9tiques avec des parenth\u00e8ses comme\npar exemple : (2 + 3) \u00d7 5. \n\nIl existe une autre notation utilis\u00e9e par certaines calculatrices, appel\u00e9e notation postfixe, qui n\u2019utilise pas de parenth\u00e8ses. L\u2019expression arithm\u00e9tique pr\u00e9c\u00e9dente est alors obtenue en\nsaisissant successivement 2, puis 3, puis l\u2019op\u00e9rateur +, puis 5, et enfin l\u2019op\u00e9rateur \u00d7. On\nmod\u00e9lise cette saisie par le tableau [2, 3, '+', 5, '*']. \n\nAutre exemple, la notation postfixe de 3 \u00d7 2 + 5 est mod\u00e9lis\u00e9e par le tableau : \n\n[3, 2, '*', 5, '+']. \n\n\nD\u2019une mani\u00e8re plus g\u00e9n\u00e9rale, la valeur associ\u00e9e \u00e0 une expression arithm\u00e9tique en notation\npostfixe est d\u00e9termin\u00e9e \u00e0 l\u2019aide d\u2019une pile en parcourant l\u2019expression arithm\u00e9tique de gauche\n\u00e0 droite de la fa\u00e7on suivante :\n\n- Si l\u2019\u00e9l\u00e9ment parcouru est un nombre, on le place au sommet de la pile ;\n- Si l\u2019\u00e9l\u00e9ment parcouru est un op\u00e9rateur, on r\u00e9cup\u00e8re les deux \u00e9l\u00e9ments situ\u00e9s au\nsommet de la pile et on leur applique l\u2019op\u00e9rateur. On place alors le r\u00e9sultat au sommet\nde la pile.\n- \u00c0 la fin du parcours, il reste alors un seul \u00e9l\u00e9ment dans la pile qui est le r\u00e9sultat de\nl\u2019expression arithm\u00e9tique.\n\n\nDans le cadre de cet exercice, on se limitera aux op\u00e9rations \u00d7 et +.\n\n\nPour cet exercice, on dispose d\u2019une classe `Pile` qui impl\u00e9mente les m\u00e9thodes de base sur la\nstructure de pile.\n\nCompl\u00e9ter le script de la fonction `eval_expression` qui re\u00e7oit en param\u00e8tre une liste python\nrepr\u00e9sentant la notation postfixe d\u2019une expression arithm\u00e9tique et qui renvoie sa valeur\nassoci\u00e9e.\n\n```python linenums='1'\nclass Pile:\n \"\"\"Classe d\u00e9finissant une structure de pile.\"\"\"\n def __init__(self):\n self.contenu = []\n\n def est_vide(self):\n \"\"\"Renvoie le bool\u00e9en True si la pile est vide, False sinon.\"\"\"\n return self.contenu == []\n\n def empiler(self, v):\n \"\"\"Place l'\u00e9l\u00e9ment v au sommet de la pile\"\"\"\n self.contenu.append(v)\n\n def depiler(self):\n \"\"\"\n Retire et renvoie l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile,\n si la pile n\u2019est pas vide.\n \"\"\"\n if not self.est_vide():\n return self.contenu.pop()\n\n\ndef eval_expression(tab):\n p = Pile()\n for ... in tab:\n if element != '+' ... element != '*':\n p.empiler(...)\n else:\n if element == ...:\n resultat = p.depiler() + ...\n else:\n resultat = ...\n p.empiler(...)\n return ...\n
Exemple :
>>> eval_expression([2, 3, '+', 5, '*'])\n25\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-09","title":"\u25b6 Sujet 09","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-091","title":"Exercice 09.1","text":"Exercice 09.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction multiplication
, prenant en param\u00e8tres deux nombres entiers n1
et n2
, et qui renvoie le produit de ces deux nombres. Les seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.
Exemples :
>>> multiplication(3,5)\n15\n>>> multiplication(-4,-8)\n32\n>>> multiplication(-2,6)\n-12\n>>> multiplication(-2,0)\n0\n
def multiplication(n1, n2):\n if n1 < 0:\n return -multiplication(-n1, n2)\n if n2 < 0:\n return -multiplication(n1, -n2)\n resultat = 0\n for _ in range(n2):\n resultat += n1\n return resultat\n
Programmer la fonction `multiplication`, prenant en param\u00e8tres deux nombres entiers\n`n1` et `n2`, et qui renvoie le produit de ces deux nombres.\nLes seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.\n\nExemples :\n```python\n>>> multiplication(3,5)\n15\n>>> multiplication(-4,-8)\n32\n>>> multiplication(-2,6)\n-12\n>>> multiplication(-2,0)\n0\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-092","title":"Exercice 09.2","text":"Exercice 09.2
\u00c9nonc\u00e9CorrectionSources MarkdownSoit tab
un tableau non vide d'entiers tri\u00e9s dans l'ordre croissant et n
un entier.
La fonction chercher
ci-dessous doit renvoyer un indice o\u00f9 la valeur n
appara\u00eet dans tab
si cette valeur y figure et None
sinon.
Les param\u00e8tres de la fonction sont :
tab
, le tableau dans lequel s'effectue la recherche ;n
, l'entier \u00e0 chercher dans le tableau ;i
, l'indice de d\u00e9but de la partie du tableau o\u00f9 s'effectue la recherche ;j
, l'indice de fin de la partie du tableau o\u00f9 s'effectue la recherche.L\u2019algorithme demand\u00e9 est une recherche dichotomique r\u00e9cursive.
Recopier et compl\u00e9ter le code de la fonction chercher
suivante :
def chercher(tab, n, i, j):\n if i < 0 or j > len(tab) :\n return None\n if i > j :\n return None\n m = (i + j) // ...\n if ... < n :\n return chercher(tab, n, ... , ...)\n elif ... > n :\n return chercher(tab, n, ... , ... )\n else :\n return ...\n
L'ex\u00e9cution du code doit donner :
>>> chercher([1, 5, 6, 6, 9, 12], 7, 0, 10)\n\n>>> chercher([1, 5, 6, 6, 9, 12], 7, 0, 5)\n\n>>> chercher([1, 5, 6, 6, 9, 12], 9, 0, 5)\n4\n>>> chercher([1, 5, 6, 6, 9, 12], 6, 0, 5)\n2\n
def chercher(tab, n, i, j):\n if i < 0 or j > len(tab) :\n return None\n if i > j :\n return None\nm = (i + j) // 2\nif tab[m] < n :\nreturn chercher(tab, n, m+1 , j)\nelif tab[m] > n :\nreturn chercher(tab, n, i , m-1 )\nelse :\nreturn m\n
Soit `tab` un tableau non vide d'entiers tri\u00e9s dans l'ordre croissant et `n` un entier.\n\nLa fonction `chercher` ci-dessous doit renvoyer un indice o\u00f9 la valeur `n`\nappara\u00eet dans `tab` si cette valeur y figure et `None` sinon. \n\nLes param\u00e8tres de la fonction sont :\n\n- `tab`, le tableau dans lequel s'effectue la recherche ;\n- `n`, l'entier \u00e0 chercher dans le tableau ;\n- `i`, l'indice de d\u00e9but de la partie du tableau o\u00f9 s'effectue la recherche ;\n- `j`, l'indice de fin de la partie du tableau o\u00f9 s'effectue la recherche.\n\nL\u2019algorithme demand\u00e9 est une recherche dichotomique r\u00e9cursive.\n\nRecopier et compl\u00e9ter le code de la fonction `chercher` suivante :\n\n```python linenums='1'\ndef chercher(tab, n, i, j):\n if i < 0 or j > len(tab) :\n return None\n if i > j :\n return None\n m = (i + j) // ...\n if ... < n :\n return chercher(tab, n, ... , ...)\n elif ... > n :\n return chercher(tab, n, ... , ... )\n else :\n return ...\n
L'ex\u00e9cution du code doit donner :
>>> chercher([1, 5, 6, 6, 9, 12], 7, 0, 10)\n\n>>> chercher([1, 5, 6, 6, 9, 12], 7, 0, 5)\n\n>>> chercher([1, 5, 6, 6, 9, 12], 9, 0, 5)\n4\n>>> chercher([1, 5, 6, 6, 9, 12], 6, 0, 5)\n2\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-10","title":"\u25b6 Sujet 10","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-101","title":"Exercice 10.1","text":"Exercice 10.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire la fonction maxliste
, prenant en param\u00e8tre un tableau non vide de nombres tab
(de type list
) et renvoyant le plus grand \u00e9l\u00e9ment de ce tableau.
Exemples :
>>> maxliste([98, 12, 104, 23, 131, 9])\n131\n>>> maxliste([-27, 24, -3, 15])\n24\n
def maxliste(tab):\n maximum = tab[0]\n for element in tab:\n if element > maximum:\n maximum = element\n return maximum\n
\u00c9crire la fonction `maxliste`, prenant en param\u00e8tre un tableau non vide de nombres `tab` (de type\n`list`) et renvoyant le plus grand \u00e9l\u00e9ment de ce tableau.\n\nExemples :\n\n```python\n>>> maxliste([98, 12, 104, 23, 131, 9])\n131\n>>> maxliste([-27, 24, -3, 15])\n24\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-102","title":"Exercice 10.2","text":"Exercice 10.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn dispose de cha\u00eenes de caract\u00e8res contenant uniquement des parenth\u00e8ses ouvrantes et fermantes.
Un parenth\u00e9sage est correct si :
Ainsi, ((()())(()))
est un parenth\u00e9sage correct.
Les parenth\u00e9sages ())(()
et (())(()
sont, eux, incorrects.
On dispose du code de la classe Pile
suivant :
class Pile:\n\"\"\" Classe d\u00e9finissant une pile \"\"\"\n def __init__(self):\n self.valeurs = []\n\n def est_vide(self):\n\"\"\"Renvoie True si la pile est vide, False sinon\"\"\"\n return self.valeurs == []\n\n def empiler(self, c):\n\"\"\"Place l\u2019\u00e9l\u00e9ment c au sommet de la pile\"\"\"\n self.valeurs.append(c)\n\n def depiler(self):\n\"\"\"Supprime l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile, \u00e0 condition qu\u2019elle soit non vide\"\"\"\n if self.est_vide() == False:\n self.valeurs.pop()\n
On souhaite programmer une fonction parenthesage qui prend en param\u00e8tre une cha\u00eene de caract\u00e8res ch
form\u00e9e de parenth\u00e8ses et renvoie True
si la cha\u00eene est bien parenth\u00e9s\u00e9e et False
sinon.
Cette fonction utilise une pile et suit le principe suivant : en parcourant la cha\u00eene de gauche \u00e0 droite, si on trouve une parenth\u00e8se ouvrante, on l\u2019empile au sommet de la pile et si on trouve une parenth\u00e8se fermante, on d\u00e9pile (si possible) la parenth\u00e8se ouvrante stock\u00e9e au sommet de la pile.
La cha\u00eene est alors bien parenth\u00e9s\u00e9e si, \u00e0 la fin du parcours, la pile est vide.
Elle est, par contre, mal parenth\u00e9s\u00e9e :
def parenthesage(ch):\n\"\"\"Renvoie True si la cha\u00eene ch est bien parenth\u00e9s\u00e9e et False sinon\"\"\"\n p = Pile()\n for c in ch:\n if c == ...:\n p.empiler(c)\n elif c == ...:\n if p.est_vide():\n return ...\n else:\n ...\n return p.est_vide()\n
Compl\u00e9ter le code de la fonction parenthesage
.
Exemples :
>>> parenthesage(\"((()())(()))\")\nTrue\n>>> parenthesage(\"())(()\")\nFalse\n>>> parenthesage(\"(())(()\")\nFalse\n
class Pile:\n\"\"\" Classe d\u00e9finissant une pile \"\"\"\n def __init__(self):\n self.valeurs = []\n\n def est_vide(self):\n\"\"\"Renvoie True si la pile est vide, False sinon\"\"\"\n return self.valeurs == []\n\n def empiler(self, c):\n\"\"\"Place l\u2019\u00e9l\u00e9ment c au sommet de la pile\"\"\"\n self.valeurs.append(c)\n\n def depiler(self):\n\"\"\"Supprime l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile, \u00e0 condition qu\u2019elle soit non vide\"\"\"\n if self.est_vide() == False:\n self.valeurs.pop()\n\ndef parenthesage(ch):\n\"\"\"Renvoie True si la cha\u00eene ch est bien parenth\u00e9s\u00e9e et False sinon\"\"\"\n p = Pile()\n for c in ch:\nif c == '(':\np.empiler(c)\nelif c == ')':\nif p.est_vide():\nreturn False\nelse:\np.depiler()\nreturn p.est_vide()\n
On dispose de cha\u00eenes de caract\u00e8res contenant uniquement des parenth\u00e8ses ouvrantes et\nfermantes. \n\nUn parenth\u00e9sage est correct si :\n\n- le nombre de parenth\u00e8ses ouvrantes de la cha\u00eene est \u00e9gal au nombre de parenth\u00e8ses\nfermantes.\n- en parcourant la cha\u00eene de gauche \u00e0 droite, le nombre de parenth\u00e8ses d\u00e9j\u00e0 ouvertes doit\n\u00eatre, \u00e0 tout moment, sup\u00e9rieur ou \u00e9gal au nombre de parenth\u00e8ses d\u00e9j\u00e0 ferm\u00e9es.\n\n\nAinsi, `((()())(()))` est un parenth\u00e9sage correct. \n\nLes parenth\u00e9sages `())(()` et `(())(()` sont, eux, incorrects.\n\n\nOn dispose du code de la classe `Pile` suivant :\n\n```python linenums='1'\nclass Pile:\n \"\"\" Classe d\u00e9finissant une pile \"\"\"\n def __init__(self):\n self.valeurs = []\n\n def est_vide(self):\n \"\"\"Renvoie True si la pile est vide, False sinon\"\"\"\n return self.valeurs == []\n\n def empiler(self, c):\n \"\"\"Place l\u2019\u00e9l\u00e9ment c au sommet de la pile\"\"\"\n self.valeurs.append(c)\n\n def depiler(self):\n \"\"\"Supprime l\u2019\u00e9l\u00e9ment plac\u00e9 au sommet de la pile, \u00e0 condition qu\u2019elle soit non vide\"\"\"\n if self.est_vide() == False:\n self.valeurs.pop()\n
On souhaite programmer une fonction parenthesage qui prend en param\u00e8tre une cha\u00eene de caract\u00e8res ch
form\u00e9e de parenth\u00e8ses et renvoie True
si la cha\u00eene est bien parenth\u00e9s\u00e9e et False
sinon.
Cette fonction utilise une pile et suit le principe suivant : en parcourant la cha\u00eene de gauche \u00e0 droite, si on trouve une parenth\u00e8se ouvrante, on l\u2019empile au sommet de la pile et si on trouve une parenth\u00e8se fermante, on d\u00e9pile (si possible) la parenth\u00e8se ouvrante stock\u00e9e au sommet de la pile.
La cha\u00eene est alors bien parenth\u00e9s\u00e9e si, \u00e0 la fin du parcours, la pile est vide.
Elle est, par contre, mal parenth\u00e9s\u00e9e :
def parenthesage(ch):\n\"\"\"Renvoie True si la cha\u00eene ch est bien parenth\u00e9s\u00e9e et False sinon\"\"\"\n p = Pile()\n for c in ch:\n if c == ...:\n p.empiler(c)\n elif c == ...:\n if p.est_vide():\n return ...\n else:\n ...\n return p.est_vide()\n
Compl\u00e9ter le code de la fonction parenthesage
.
Exemples :
>>> parenthesage(\"((()())(()))\")\nTrue\n>>> parenthesage(\"())(()\")\nFalse\n>>> parenthesage(\"(())(()\")\nFalse\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-11","title":"\u25b6 Sujet 11","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-111","title":"Exercice 11.1","text":"Exercice 11.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn mod\u00e9lise la repr\u00e9sentation binaire d'un entier non sign\u00e9 par un tableau d'entiers dont les \u00e9l\u00e9ments sont 0 ou 1. Par exemple, le tableau [1, 0, 1, 0, 0, 1, 1]
repr\u00e9sente l'\u00e9criture binaire de l'entier dont l'\u00e9criture d\u00e9cimale est 2**6 + 2**4 + 2**1 + 2**0 = 83
.
\u00c0 l'aide d'un parcours s\u00e9quentiel, \u00e9crire la fonction convertir
r\u00e9pondant aux sp\u00e9cifications suivantes :
def convertir(tab):\n\"\"\"\n tab est un tableau d'entiers, dont les \u00e9l\u00e9ments sont 0 ou 1 et\n repr\u00e9sentant un entier \u00e9crit en binaire. Renvoie l'\u00e9criture\n d\u00e9cimale de l'entier positif dont la repr\u00e9sentation binaire\n est donn\u00e9e par le tableau tab\n \"\"\"\n
Exemple : >>> convertir([1, 0, 1, 0, 0, 1, 1])\n83\n>>> convertir([1, 0, 0, 0, 0, 0, 1, 0])\n130\n
def convertir(tab):\n puissance = 0\n total = 0\n for i in range(len(tab)-1, -1, -1):\n total += tab[i]*(2**puissance)\n puissance += 1\n return total\n
On mod\u00e9lise la repr\u00e9sentation binaire d'un entier non sign\u00e9 par un tableau d'entiers dont\nles \u00e9l\u00e9ments sont 0 ou 1. Par exemple, le tableau `[1, 0, 1, 0, 0, 1, 1]` repr\u00e9sente\nl'\u00e9criture binaire de l'entier dont l'\u00e9criture d\u00e9cimale est\n`2**6 + 2**4 + 2**1 + 2**0 = 83`.\n\n\u00c0 l'aide d'un parcours s\u00e9quentiel, \u00e9crire la fonction `convertir` r\u00e9pondant aux\nsp\u00e9cifications suivantes :\n\n```python\ndef convertir(tab):\n \"\"\"\n tab est un tableau d'entiers, dont les \u00e9l\u00e9ments sont 0 ou 1 et\n repr\u00e9sentant un entier \u00e9crit en binaire. Renvoie l'\u00e9criture\n d\u00e9cimale de l'entier positif dont la repr\u00e9sentation binaire\n est donn\u00e9e par le tableau tab\n \"\"\"\n```\nExemple :\n```python\n>>> convertir([1, 0, 1, 0, 0, 1, 1])\n83\n>>> convertir([1, 0, 0, 0, 0, 0, 1, 0])\n130\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-112","title":"Exercice 11.2","text":"Exercice 11.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa fonction tri_insertion
suivante prend en argument une liste tab
et trie cette liste en utilisant la m\u00e9thode du tri par insertion. Compl\u00e9ter cette fonction pour qu'elle r\u00e9ponde \u00e0 la sp\u00e9cification demand\u00e9e.
On rappelle le principe du tri par insertion : on consid\u00e8re les \u00e9l\u00e9ments \u00e0 trier un par un, le premier \u00e9l\u00e9ment constituant, \u00e0 lui tout seul, une liste tri\u00e9e de longueur 1. On range ensuite le second \u00e9l\u00e9ment pour constituer une liste tri\u00e9e de longueur 2, puis on range le troisi\u00e8me \u00e9l\u00e9ment pour avoir une liste tri\u00e9e de longueur 3 et ainsi de suite\u2026 A chaque \u00e9tape, le premier \u00e9l\u00e9ment de la sous-liste non tri\u00e9e est plac\u00e9 dans la sous-liste des \u00e9l\u00e9ments d\u00e9j\u00e0 tri\u00e9s de sorte que cette sous-liste demeure tri\u00e9e.
Le principe du tri par insertion est donc d'ins\u00e9rer \u00e0 la n-i\u00e8me it\u00e9ration, le n-i\u00e8me \u00e9l\u00e9ment \u00e0 la bonne place.
def tri_insertion(tab):\n n = len(tab)\n for i in range(1, n):\n valeur_insertion = tab[...]\n # la variable j sert \u00e0 d\u00e9terminer o\u00f9 placer la valeur \u00e0 ranger\n j = ...\n # tant qu'on a pas trouv\u00e9 la place de l'\u00e9l\u00e9ment \u00e0 ins\u00e9rer\n # on d\u00e9cale les valeurs du tableau vers la droite\n while j > ... and valeur_insertion < tab[...]:\n tab[j] = tab[j-1]\n j = ...\n tab[j] = ...\n
Exemples :
>>> liste = [9, 5, 8, 4, 0, 2, 7, 1, 10, 3, 6]\n>>> tri_insertion(liste)\n>>> liste\n[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n
def tri_insertion(tab):\n n = len(tab)\n for i in range(1, n):\nvaleur_insertion = tab[i]\n# la variable j sert \u00e0 d\u00e9terminer o\u00f9 placer la valeur \u00e0 ranger\nj = i\n# tant qu'on a pas trouv\u00e9 la place de l'\u00e9l\u00e9ment \u00e0 ins\u00e9rer\n # on d\u00e9cale les valeurs du tableau vers la droite\nwhile j > 0 and valeur_insertion < tab[j-1]:\ntab[j] = tab[j-1]\nj = j - 1\ntab[j] = valeur_insertion\n
La fonction `tri_insertion` suivante prend en argument une liste `tab` et trie cette liste en\nutilisant la m\u00e9thode du tri par insertion. Compl\u00e9ter cette fonction pour qu'elle r\u00e9ponde \u00e0 la\nsp\u00e9cification demand\u00e9e.\n\nOn rappelle le principe du tri par insertion : on consid\u00e8re les \u00e9l\u00e9ments \u00e0 trier un par un,\nle premier \u00e9l\u00e9ment constituant, \u00e0 lui tout seul, une liste tri\u00e9e de longueur 1. On range\nensuite le second \u00e9l\u00e9ment pour constituer une liste tri\u00e9e de longueur 2, puis on range le\ntroisi\u00e8me \u00e9l\u00e9ment pour avoir une liste tri\u00e9e de longueur 3 et ainsi de suite\u2026 A chaque\n\u00e9tape, le premier \u00e9l\u00e9ment de la sous-liste non tri\u00e9e est plac\u00e9 dans la sous-liste des\n\u00e9l\u00e9ments d\u00e9j\u00e0 tri\u00e9s de sorte que cette sous-liste demeure tri\u00e9e. \n\nLe principe du tri par insertion est donc d'ins\u00e9rer \u00e0 la n-i\u00e8me it\u00e9ration, le n-i\u00e8me \u00e9l\u00e9ment\n\u00e0 la bonne place.\n\n\n```python linenums='1'\ndef tri_insertion(tab):\n n = len(tab)\n for i in range(1, n):\n valeur_insertion = tab[...]\n # la variable j sert \u00e0 d\u00e9terminer o\u00f9 placer la valeur \u00e0 ranger\n j = ...\n # tant qu'on a pas trouv\u00e9 la place de l'\u00e9l\u00e9ment \u00e0 ins\u00e9rer\n # on d\u00e9cale les valeurs du tableau vers la droite\n while j > ... and valeur_insertion < tab[...]:\n tab[j] = tab[j-1]\n j = ...\n tab[j] = ...\n
Exemples :
>>> liste = [9, 5, 8, 4, 0, 2, 7, 1, 10, 3, 6]\n>>> tri_insertion(liste)\n>>> liste\n[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-12","title":"\u25b6 Sujet 12","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-121","title":"Exercice 12.1","text":"Exercice 12.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn consid\u00e8re la classe ABR
, dont le constructeur est le suivant :
class ABR:\n def __init__(self, g0, v0, d0):\n self.gauche = g0\n self.cle = v0\n self.droit = d0\n\n def __repr__(self):\n if self is None:\n return ''\n else:\n return '(' + (self.gauche).__repr__() + ',' + str(self.cle) + ',' +(self.droit).__repr__() + ')'\n
Ainsi, l\u2019arbre binaire de recherche abr1
ci- contre est cr\u00e9\u00e9 par le code python ci- dessous
n0 = ABR(None, 0, None)\nn3 = ABR(None, 3, None)\nn2 = ABR(None, 2, n3)\nn3 = ABR(n0, 1, n2)\n
Dans tout le code, None
correspondra \u00e0 un arbre vide.
La classe ABR
dispose aussi d\u2019une m\u00e9thode de repr\u00e9sentation (__repr__
), qui affiche entre parenth\u00e8ses le contenu du sous arbre gauche, puis la cl\u00e9 de l\u2019arbre, et enfin le contenu du sous arbre droit. Elle s\u2019utilise en console de la mani\u00e8re suivante :
>>> abr1\n((None,0,None),1,(None,2,(None,3,None)))\n
\u00c9crire une fonction r\u00e9cursive ajoute(cle, a)
qui prend en param\u00e8tres une cl\u00e9 cle
et un arbre binaire de recherche a
, et qui renvoie un arbre binaire de recherche dans lequel cle
a \u00e9t\u00e9 ins\u00e9r\u00e9e. Dans le cas o\u00f9 cle
est d\u00e9j\u00e0 pr\u00e9sente dans a
, la fonction renvoie l\u2019arbre a
inchang\u00e9.
R\u00e9sultats \u00e0 obtenir :
>>> a = ajoute(4, abr1)\n>>> a\n((None,0,None),1,(None,2,(None,3,(None,4,None))))\n\n>>> ajoute(-5, abr1)\n(((None,-5,None),0,None),1,(None,2,(None,3,None)))\n\n>>> ajoute(2, abr1)\n((None,0,None),1,(None,2,(None,3,None)))\n
def ajoute(cle, a): \n if a is None:\n a = ABR(None, cle, None)\n elif cle > a.cle:\n a.droit = ajoute(cle, a.droit)\n elif cle < a.cle:\n a.gauche = ajoute(cle, a.gauche)\n return a\n
On consid\u00e8re la classe `ABR`, dont le constructeur est le suivant :\n\n```python\nclass ABR:\n def __init__(self, g0, v0, d0):\n self.gauche = g0\n self.cle = v0\n self.droit = d0\n\n def __repr__(self):\n if self is None:\n return ''\n else:\n return '(' + (self.gauche).__repr__() + ',' + str(self.cle) + ',' +(self.droit).__repr__() + ')'\n\n```\n\n![image](data2023/12_arbre.png){: .center width=30%}\n\nAinsi, l\u2019arbre binaire de recherche `abr1` ci-\ncontre est cr\u00e9\u00e9 par le code python ci-\ndessous\n\n```python\nn0 = ABR(None, 0, None)\nn3 = ABR(None, 3, None)\nn2 = ABR(None, 2, n3)\nn3 = ABR(n0, 1, n2)\n```\n\nDans tout le code, `None` correspondra \u00e0 un arbre vide.\n\nLa classe `ABR` dispose aussi d\u2019une m\u00e9thode de repr\u00e9sentation (```__repr__``` ), qui affiche entre\nparenth\u00e8ses le contenu du sous arbre gauche, puis la cl\u00e9 de l\u2019arbre, et enfin le\ncontenu du sous arbre droit. Elle s\u2019utilise en console de la mani\u00e8re suivante :\n\n```python\n>>> abr1\n((None,0,None),1,(None,2,(None,3,None)))\n```\n\n\u00c9crire une fonction r\u00e9cursive `ajoute(cle, a)` qui prend en param\u00e8tres une cl\u00e9 `cle`\net un arbre binaire de recherche ```a``` , et qui renvoie un arbre binaire de recherche dans\nlequel `cle` a \u00e9t\u00e9 ins\u00e9r\u00e9e.\nDans le cas o\u00f9 `cle` est d\u00e9j\u00e0 pr\u00e9sente dans `a`, la fonction renvoie l\u2019arbre `a` inchang\u00e9.\n\nR\u00e9sultats \u00e0 obtenir :\n\n```python\n>>> a = ajoute(4, abr1)\n>>> a\n((None,0,None),1,(None,2,(None,3,(None,4,None))))\n\n>>> ajoute(-5, abr1)\n(((None,-5,None),0,None),1,(None,2,(None,3,None)))\n\n>>> ajoute(2, abr1)\n((None,0,None),1,(None,2,(None,3,None)))\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-122","title":"Exercice 12.2","text":"Exercice 12.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn dispose d\u2019un ensemble d\u2019objets dont on conna\u00eet, pour chacun, la masse. On souhaite ranger l\u2019ensemble de ces objets dans des boites identiques de telle mani\u00e8re que la somme des masses des objets contenus dans une bo\u00eete ne d\u00e9passe pas la capacit\u00e9 c
de la bo\u00eete. On souhaite utiliser le moins de bo\u00eetes possibles pour ranger cet ensemble d\u2019objets.
Pour r\u00e9soudre ce probl\u00e8me, on utilisera un algorithme glouton consistant \u00e0 placer chacun des objets dans la premi\u00e8re bo\u00eete o\u00f9 cela est possible.
Par exemple, pour ranger dans des bo\u00eetes de capacit\u00e9 c = 5
un ensemble de trois objets dont les masses sont repr\u00e9sent\u00e9es en Python par la liste [1, 5, 2]
, on proc\u00e8de de la fa\u00e7on suivante :
On a donc utilis\u00e9 deux bo\u00eetes de capacit\u00e9 c = 5
pour ranger les 3 objets.
Compl\u00e9ter la fonction Python empaqueter(liste_masses, c)
suivante pour qu\u2019elle renvoie le nombre de bo\u00eetes de capacit\u00e9 c n\u00e9cessaires pour empaqueter un ensemble d\u2019objets dont les masses sont contenues dans la liste liste_masses
.
def empaqueter(liste_masses, c):\n n = len(liste_masses)\n nb_boites = 0\n boites = [0]*n\n for masse in ... :\n i = 0\n while i <= nb_boites and boites[i] + ... > C:\n i = i + 1\n if i == nb_boites + 1:\n ...\n boites[i] = ...\n return ...\n
Tester ensuite votre fonction :
>>> empaqueter([7, 6, 3, 4, 8, 5, 9, 2], 11)\n5\n
def empaqueterR(liste_masses, c):\n n = len(liste_masses)\n nb_boites = 0\n boites = [0]*n\nfor masse in liste_masses :\ni = 0\nwhile i <= nb_boites and boites[i] + masse > c:\ni = i + 1\n if i == nb_boites + 1:\nnb_boites = nb_boites + 1\nboites[i] = boites[i] + masse\nreturn nb_boites + 1\n
On dispose d\u2019un ensemble d\u2019objets dont on conna\u00eet, pour chacun, la masse. On\nsouhaite ranger l\u2019ensemble de ces objets dans des boites identiques de telle\nmani\u00e8re que la somme des masses des objets contenus dans une bo\u00eete ne d\u00e9passe\npas la capacit\u00e9 `c` de la bo\u00eete. On souhaite utiliser le moins de bo\u00eetes possibles pour\nranger cet ensemble d\u2019objets.\n\n\nPour r\u00e9soudre ce probl\u00e8me, on utilisera un algorithme glouton consistant \u00e0 placer\nchacun des objets dans la premi\u00e8re bo\u00eete o\u00f9 cela est possible.\n\nPar exemple, pour ranger dans des bo\u00eetes de capacit\u00e9 `c = 5` un ensemble de trois\nobjets dont les masses sont repr\u00e9sent\u00e9es en Python par la liste `[1, 5, 2]`, on\nproc\u00e8de de la fa\u00e7on suivante :\n\n- Le premier objet, de masse 1, va dans une premi\u00e8re boite.\n- Le deuxi\u00e8me objet, de masse 5, ne peut pas aller dans la m\u00eame boite que le\npremier objet car cela d\u00e9passerait la capacit\u00e9 de la boite. On place donc cet\nobjet dans une deuxi\u00e8me bo\u00eete.\n- Le troisi\u00e8me objet, de masse 2, va dans la premi\u00e8re bo\u00eete.\n\nOn a donc utilis\u00e9 deux bo\u00eetes de capacit\u00e9 `c = 5` pour ranger les 3 objets.\n\nCompl\u00e9ter la fonction Python `empaqueter(liste_masses, c)` suivante pour\nqu\u2019elle renvoie le nombre de bo\u00eetes de capacit\u00e9 c n\u00e9cessaires pour empaqueter un\nensemble d\u2019objets dont les masses sont contenues dans la liste `liste_masses`.\n\n```python linenums='1'\ndef empaqueter(liste_masses, c):\n n = len(liste_masses)\n nb_boites = 0\n boites = [0]*n\n for masse in ... :\n i = 0\n while i <= nb_boites and boites[i] + ... > C:\n i = i + 1\n if i == nb_boites + 1:\n ...\n boites[i] = ...\n return ...\n
Tester ensuite votre fonction :
>>> empaqueter([7, 6, 3, 4, 8, 5, 9, 2], 11)\n5\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-13","title":"\u25b6 Sujet 13","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-131","title":"Exercice 13.1","text":"Exercice 13.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire en langage Python une fonction recherche
prenant comme param\u00e8tres une variable a
de type num\u00e9rique (float
ou int
) et un tableau tab
(type list
) et qui renvoie le nombre d'occurrences de a
dans tab
.
Exemples :
>>> recherche(5, [])\n0\n>>> recherche(5, [-2, 3, 4, 8])\n0\n>>> recherche(5, [-2, 3, 1, 5, 3, 7, 4])\n1\n>>> recherche(5, [-2, 5, 3, 5, 4, 5])\n3\n
def recherche(a, tab):\n nb = 0\n for element in tab:\n if element == a:\n nb += 1\n return nb\n
\u00c9crire en langage Python une fonction `recherche` prenant comme param\u00e8tres une\nvariable `a` de type num\u00e9rique (`float` ou `int`) et un tableau `tab` (type `list`) et qui\nrenvoie le nombre d'occurrences de `a` dans `tab`.\n\nExemples :\n```python\n>>> recherche(5, [])\n0\n>>> recherche(5, [-2, 3, 4, 8])\n0\n>>> recherche(5, [-2, 3, 1, 5, 3, 7, 4])\n1\n>>> recherche(5, [-2, 5, 3, 5, 4, 5])\n3\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-132","title":"Exercice 13.2","text":"Exercice 13.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa fonction rendu_monnaie
prend en param\u00e8tres deux nombres entiers positifs somme_due
et somme_versee
et elle permet de proc\u00e9der au rendu de monnaie de la diff\u00e9rence somme_versee \u2013 somme_due
pour des achats effectu\u00e9s avec le syst\u00e8me de pi\u00e8ces de la zone Euro. On utilise pour cela un algorithme glouton qui commence par rendre le maximum de pi\u00e8ces de plus grandes valeurs et ainsi de suite. Par la suite, on assimilera les billets \u00e0 des pi\u00e8ces.
La fonction rendu_monnaie
renvoie un tableau de type list
contenant les pi\u00e8ces qui composent le rendu.
Toutes les sommes sont exprim\u00e9es en euros. Les valeurs possibles pour les pi\u00e8ces sont donc [1, 2, 5, 10, 20, 50, 100, 200]
.
Ainsi, l\u2019instruction rendu_monnaie(452, 500)
renvoie le tableau [20, 20, 5, 2, 1]
.
En effet, la somme \u00e0 rendre est de 48
euros soit 20 + 20 + 5 + 2 + 1
.
Le code de la fonction rendu_monnaie
est donn\u00e9 ci-dessous :
def rendu_monnaie(somme_due, somme_versee):\n pieces = [1, 2, 5, 10, 20, 50, 100, 200]\n rendu = ...\n a_rendre = ...\n i = len(pieces) - 1\n while a_rendre > ... :\n if pieces[i] <= a_rendre :\n rendu.append(...)\n a_rendre = ...\n else :\n i = ...\n return rendu\n
Compl\u00e9ter ce code et le tester :
>>> rendu_monnaie(700,700)\n[]\n>>> rendu_monnaie(102,500)\n[200, 100, 50, 20, 20, 5, 2, 1]\n
def rendu_monnaie(somme_due, somme_versee):\n pieces = [1, 2, 5, 10, 20, 50, 100, 200]\nrendu = []\na_rendre = somme_versee - somme_due\ni = len(pieces) - 1\nwhile a_rendre > 0 :\nif pieces[i] <= a_rendre :\nrendu.append(pieces[i])\na_rendre = a_rendre - pieces[i]\nelse :\ni = i - 1\nreturn rendu\n
La fonction `rendu_monnaie` prend en param\u00e8tres deux nombres entiers\npositifs `somme_due` et `somme_versee` et elle permet de proc\u00e9der au rendu de monnaie de la\ndiff\u00e9rence `somme_versee \u2013 somme_due` pour des achats effectu\u00e9s avec le syst\u00e8me de pi\u00e8ces de\nla zone Euro. On utilise pour cela un algorithme glouton qui commence par rendre le maximum de\npi\u00e8ces de plus grandes valeurs et ainsi de suite. Par la suite, on\nassimilera les billets \u00e0 des pi\u00e8ces.\n\n\nLa fonction `rendu_monnaie` renvoie un tableau de type `list` contenant les pi\u00e8ces qui\ncomposent le rendu.\n\nToutes les sommes sont exprim\u00e9es en euros. Les valeurs possibles pour les\npi\u00e8ces sont donc `[1, 2, 5, 10, 20, 50, 100, 200]`.\n\nAinsi, l\u2019instruction `rendu_monnaie(452, 500)`\nrenvoie le tableau\n`[20, 20, 5, 2, 1]`.\n\nEn effet, la somme \u00e0 rendre est de `48` euros soit `20 + 20 + 5 + 2 + 1`.\n\nLe code de la fonction `rendu_monnaie` est donn\u00e9 ci-dessous :\n\n```python linenums='1'\ndef rendu_monnaie(somme_due, somme_versee):\n pieces = [1, 2, 5, 10, 20, 50, 100, 200]\n rendu = ...\n a_rendre = ...\n i = len(pieces) - 1\n while a_rendre > ... :\n if pieces[i] <= a_rendre :\n rendu.append(...)\n a_rendre = ...\n else :\n i = ...\n return rendu\n
Compl\u00e9ter ce code et le tester :
>>> rendu_monnaie(700,700)\n[]\n>>> rendu_monnaie(102,500)\n[200, 100, 50, 20, 20, 5, 2, 1]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-14","title":"\u25b6 Sujet 14","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-141","title":"Exercice 14.1","text":"Exercice 14.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche
qui prend en param\u00e8tres elt
un nombre entier et tab
un tableau de nombres entiers, et qui renvoie l\u2019indice de la premi\u00e8re occurrence de elt
dans tab
si elt
est dans tab
et -1
sinon.
Ne pas oublier d\u2019ajouter au corps de la fonction une documentation et une ou plusieurs assertions pour v\u00e9rifier les pr\u00e9-conditions.
Exemples :
>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(50, [1, 50, 1])\n1\n>>> recherche(15, [8, 9, 10, 15])\n3\n
def recherche(elt, tab):\n'''\n renvoie l\u2019indice de la premi\u00e8re occurrence de\n elt dans tab si elt est dans tab et -1 sinon. \n '''\n assert tab != [], \"le tableau est vide\"\n for i in range(len(tab)):\n if tab[i] == elt:\n return i \n return -1 \n
\u00c9crire une fonction `recherche` qui prend en param\u00e8tres `elt` un nombre entier et `tab`\nun tableau de nombres entiers, et qui renvoie l\u2019indice de la premi\u00e8re occurrence de `elt`\ndans `tab` si `elt` est dans `tab` et `-1` sinon.\n\nNe pas oublier d\u2019ajouter au corps de la fonction une documentation et une ou plusieurs\nassertions pour v\u00e9rifier les pr\u00e9-conditions.\n\nExemples :\n```python\n>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(50, [1, 50, 1])\n1\n>>> recherche(15, [8, 9, 10, 15])\n3\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-142","title":"Exercice 14.2","text":"Exercice 14.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re la fonction insere
ci-dessous qui prend en argument un entier a
et un tableau tab
d'entiers tri\u00e9s par ordre croissant. Cette fonction cr\u00e9e et renvoie un nouveau tableau \u00e0 partir de celui fourni en param\u00e8tre en y ins\u00e9rant la valeur a
de sorte que le tableau renvoy\u00e9 soit encore tri\u00e9 par ordre croissant. Les tableaux seront repr\u00e9sent\u00e9s sous la forme de listes Python.
def insere(a, tab):\n\"\"\"\n Ins\u00e8re l'\u00e9l\u00e9ment a (int) dans le tableau tab (list)\n tri\u00e9 par ordre croissant \u00e0 sa place et renvoie le\n nouveau tableau.\n \"\"\"\n l = list(tab) #l contient les m\u00eames \u00e9l\u00e9ments que tab\n l.append(a)\n i = ...\n while a < ... and i >= 0:\n l[i+1] = ...\n l[i] = a\n i = ...\n return l\n
Compl\u00e9ter la fonction insere
ci-dessus.
Exemples :
>>> insere(3, [1, 2, 4, 5])\n[1, 2, 3, 4, 5]\n>>> insere(30, [1, 2, 7, 12, 14, 25])\n[1, 2, 7, 12, 14, 25, 30]\n>>> insere(1, [2, 3, 4])\n[1, 2, 3, 4]\n>>> insere(1, [])\n[1]\n
def insere(a, tab):\n\"\"\"\n Ins\u00e8re l'\u00e9l\u00e9ment a (int) dans le tableau tab (list)\n tri\u00e9 par ordre croissant \u00e0 sa place et renvoie le\n nouveau tableau.\n \"\"\"\n l = list(tab) #l contient les m\u00eames \u00e9l\u00e9ments que tab\n l.append(a)\ni = len(l) - 2\nwhile a < l[i] and i >= 0:\nl[i+1] = l[i]\nl[i] = a\ni = i - 1\nreturn l\n
On consid\u00e8re la fonction `insere` ci-dessous qui prend en argument un entier `a` et un\ntableau `tab` d'entiers tri\u00e9s par ordre croissant. Cette fonction cr\u00e9e et renvoie un nouveau\ntableau \u00e0 partir de celui fourni en param\u00e8tre en y ins\u00e9rant la valeur `a` de sorte que le\ntableau renvoy\u00e9 soit encore tri\u00e9 par ordre croissant. Les tableaux seront repr\u00e9sent\u00e9s sous\nla forme de listes Python.\n\n\n```python linenums='1'\ndef insere(a, tab):\n \"\"\"\n Ins\u00e8re l'\u00e9l\u00e9ment a (int) dans le tableau tab (list)\n tri\u00e9 par ordre croissant \u00e0 sa place et renvoie le\n nouveau tableau.\n \"\"\"\n l = list(tab) #l contient les m\u00eames \u00e9l\u00e9ments que tab\n l.append(a)\n i = ...\n while a < ... and i >= 0:\n l[i+1] = ...\n l[i] = a\n i = ...\n return l\n
Compl\u00e9ter la fonction insere
ci-dessus.
Exemples :
>>> insere(3, [1, 2, 4, 5])\n[1, 2, 3, 4, 5]\n>>> insere(30, [1, 2, 7, 12, 14, 25])\n[1, 2, 7, 12, 14, 25, 30]\n>>> insere(1, [2, 3, 4])\n[1, 2, 3, 4]\n>>> insere(1, [])\n[1]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-15","title":"\u25b6 Sujet 15","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-151","title":"Exercice 15.1","text":"Exercice 15.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn a relev\u00e9 les valeurs moyennes annuelles des temp\u00e9ratures \u00e0 Paris pour la p\u00e9riode allant de 2013 \u00e0 2019. Les r\u00e9sultats ont \u00e9t\u00e9 r\u00e9cup\u00e9r\u00e9s sous la forme de deux listes : l\u2019une pour les temp\u00e9ratures, l\u2019autre pour les ann\u00e9es :
t_moy = [14.9, 13.3, 13.1, 12.5, 13.0, 13.6, 13.7]\nannees = [2013, 2014, 2015, 2016, 2017, 2018, 2019]\n
\u00c9crire la fonction mini
qui prend en param\u00e8tres un tableau releve
des relev\u00e9s et un tableau date
des dates et qui renvoie la plus petite valeur relev\u00e9e au cours de la p\u00e9riode et l\u2019ann\u00e9e correspondante. On suppose que la temp\u00e9rature minimale est atteinte une seule fois.
Exemple :
>>> mini(t_moy, annees)\n(12.5, 2016)\n
t_moy = [14.9, 13.3, 13.1, 12.5, 13.0, 13.6, 13.7]\nannees = [2013, 2014, 2015, 2016, 2017, 2018, 2019]\n\ndef mini(releve, date):\n temp_mini = releve[0]\n date_mini = date[0]\n for i in range(len(releve)):\n if releve[i] < temp_mini:\n temp_mini = releve[i]\n date_mini = date[i]\n return temp_mini, date_mini\n
On a relev\u00e9 les valeurs moyennes annuelles des temp\u00e9ratures \u00e0 Paris pour la p\u00e9riode\nallant de 2013 \u00e0 2019. Les r\u00e9sultats ont \u00e9t\u00e9 r\u00e9cup\u00e9r\u00e9s sous la forme de deux listes : l\u2019une pour les temp\u00e9ratures, l\u2019autre pour les ann\u00e9es :\n```python\nt_moy = [14.9, 13.3, 13.1, 12.5, 13.0, 13.6, 13.7]\nannees = [2013, 2014, 2015, 2016, 2017, 2018, 2019]\n```\n\n\u00c9crire la fonction `mini` qui prend en param\u00e8tres un tableau `releve` des relev\u00e9s et un\ntableau `date` des dates et qui renvoie la plus petite valeur relev\u00e9e au cours de la\np\u00e9riode et l\u2019ann\u00e9e correspondante. On suppose que la temp\u00e9rature minimale est atteinte\nune seule fois.\n\nExemple :\n```python\n>>> mini(t_moy, annees)\n(12.5, 2016)\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-152","title":"Exercice 15.2","text":"Exercice 15.2
\u00c9nonc\u00e9CorrectionSources MarkdownUn mot palindrome peut se lire de la m\u00eame fa\u00e7on de gauche \u00e0 droite ou de droite \u00e0 gauche : bob, radar, et non sont des mots palindromes.
De m\u00eame certains nombres sont eux aussi des palindromes : 33, 121, 345543.
L\u2019objectif de cet exercice est d\u2019obtenir un programme Python permettant de tester si un nombre est un nombre palindrome.
Pour remplir cette t\u00e2che, on vous demande de compl\u00e9ter le code des trois fonctions ci- dessous sachant que la fonction est_nbre_palindrome
s\u2019appuiera sur la fonction est_palindrome
qui elle-m\u00eame s\u2019appuiera sur la fonction inverse_chaine
.
La fonction inverse_chaine
inverse l'ordre des caract\u00e8res d'une cha\u00eene de caract\u00e8res chaine
et renvoie la cha\u00eene invers\u00e9e.
La fonction est_palindrome
teste si une chaine de caract\u00e8res chaine
est un palindrome. Elle renvoie True
si c\u2019est le cas et False
sinon. Cette fonction s\u2019appuie sur la fonction pr\u00e9c\u00e9dente.
La fonction est_nbre_palindrome
teste si un nombre nbre
est un palindrome. Elle renvoie True
si c\u2019est le cas et False
sinon. Cette fonction s\u2019appuie sur la fonction pr\u00e9c\u00e9dente.
Compl\u00e9ter le code des trois fonctions ci-dessous.
def inverse_chaine(chaine):\n result = ...\n for caractere in chaine:\n result = ...\n return result\n\ndef est_palindrome(chaine):\n inverse = inverse_chaine(chaine)\n return ...\n\ndef est_nbre_palindrome(nbre):\n chaine = ...\n return est_palindrome(chaine)\n
Exemples : >>> inverse_chaine('bac')\n'cab'\n>>> est_palindrome('NSI')\nFalse\n>>> est_palindrome('ISN-NSI')\nTrue\n>>> est_nbre_palindrome(214312)\nFalse\n>>> est_nbre_palindrome(213312)\nTrue\n
def inverse_chaine(chaine):\nresult = ''\nfor caractere in chaine:\nresult = caractere + result\nreturn result\n\ndef est_palindrome(chaine):\n inverse = inverse_chaine(chaine)\nreturn chaine == inverse\ndef est_nbre_palindrome(nbre):\nchaine = str(nbre)\nreturn est_palindrome(chaine)\n
Un mot palindrome peut se lire de la m\u00eame fa\u00e7on de gauche \u00e0 droite ou de droite \u00e0\ngauche : *bob*, *radar*, et *non* sont des mots palindromes.\n\nDe m\u00eame certains nombres sont eux aussi des palindromes : 33, 121, 345543.\n\nL\u2019objectif de cet exercice est d\u2019obtenir un programme Python permettant de tester si un\nnombre est un nombre palindrome.\n\nPour remplir cette t\u00e2che, on vous demande de compl\u00e9ter le code des trois fonctions ci-\ndessous sachant que la fonction `est_nbre_palindrome` s\u2019appuiera sur la fonction\n`est_palindrome` qui elle-m\u00eame s\u2019appuiera sur la fonction `inverse_chaine`.\n\nLa fonction `inverse_chaine` inverse l'ordre des caract\u00e8res d'une cha\u00eene de caract\u00e8res\n`chaine` et renvoie la cha\u00eene invers\u00e9e.\n\nLa fonction `est_palindrome` teste si une chaine de caract\u00e8res `chaine` est un\npalindrome. Elle renvoie `True` si c\u2019est le cas et `False` sinon. Cette fonction s\u2019appuie sur\nla fonction pr\u00e9c\u00e9dente.\n\nLa fonction `est_nbre_palindrome` teste si un nombre `nbre` est un palindrome. Elle\nrenvoie `True` si c\u2019est le cas et `False` sinon. Cette fonction s\u2019appuie sur la fonction\npr\u00e9c\u00e9dente.\n\nCompl\u00e9ter le code des trois fonctions ci-dessous.\n\n```python linenums='1'\ndef inverse_chaine(chaine):\n result = ...\n for caractere in chaine:\n result = ...\n return result\n\ndef est_palindrome(chaine):\n inverse = inverse_chaine(chaine)\n return ...\n\ndef est_nbre_palindrome(nbre):\n chaine = ...\n return est_palindrome(chaine)\n
Exemples : >>> inverse_chaine('bac')\n'cab'\n>>> est_palindrome('NSI')\nFalse\n>>> est_palindrome('ISN-NSI')\nTrue\n>>> est_nbre_palindrome(214312)\nFalse\n>>> est_nbre_palindrome(213312)\nTrue\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-16","title":"\u25b6 Sujet 16","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-161","title":"Exercice 16.1","text":"Exercice 16.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche_indices_classement
qui prend en param\u00e8tres un entier elt
et une liste d\u2019entiers tab
, et qui renvoie trois listes :
tab
strictement inf\u00e9rieures \u00e0 elt
;tab
\u00e9gales \u00e0 elt
;tab
strictement sup\u00e9rieures \u00e0 elt
.Exemples :
>>> recherche_indices_classement(3, [1, 3, 4, 2, 4, 6, 3, 0])\n([0, 3, 7], [1, 6], [2, 4, 5])\n>>> recherche_indices_classement(3, [1, 4, 2, 4, 6, 0])\n([0, 2, 5], [], [1, 3, 4])\n>>>recherche_indices_classement(3, [1, 1, 1, 1])\n([0, 1, 2, 3], [], [])\n>>> recherche_indices_classement(3, [])\n([], [], [])\n
def recherche_indices_classement(elt, tab):\n ind_inf = []\n ind_egal = []\n ind_sup = [] \n for i in range(len(tab)):\n if tab[i] < elt:\n ind_inf.append(i)\n elif tab[i] > elt:\n ind_sup.append(i)\n else:\n ind_egal.append(i)\n return (ind_inf, ind_egal, ind_sup)\n
\u00c9crire une fonction `recherche_indices_classement` qui prend en param\u00e8tres un\nentier `elt` et une liste d\u2019entiers `tab`, et qui renvoie trois listes :\n\n- la premi\u00e8re liste contient les indices des valeurs de la liste `tab` strictement\ninf\u00e9rieures \u00e0 `elt` ;\n- la deuxi\u00e8me liste contient les indices des valeurs de la liste `tab` \u00e9gales \u00e0 `elt` ;\n- la troisi\u00e8me liste contient les indices des valeurs de la liste `tab` strictement\nsup\u00e9rieures \u00e0 `elt`.\n\nExemples :\n\n```python\n>>> recherche_indices_classement(3, [1, 3, 4, 2, 4, 6, 3, 0])\n([0, 3, 7], [1, 6], [2, 4, 5])\n>>> recherche_indices_classement(3, [1, 4, 2, 4, 6, 0])\n([0, 2, 5], [], [1, 3, 4])\n>>>recherche_indices_classement(3, [1, 1, 1, 1])\n([0, 1, 2, 3], [], [])\n>>> recherche_indices_classement(3, [])\n([], [], [])\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-162","title":"Exercice 16.2","text":"Exercice 16.2
\u00c9nonc\u00e9CorrectionSources MarkdownUn professeur de NSI d\u00e9cide de g\u00e9rer les r\u00e9sultats de sa classe sous la forme d\u2019un dictionnaire :
Avec :
resultats = {'Dupont': {\n 'DS1': [15.5, 4],\n 'DM1': [14.5, 1],\n 'DS2': [13, 4],\n 'PROJET1': [16, 3],\n 'DS3': [14, 4]\n },\n 'Durand': {\n 'DS1': [6 , 4],\n 'DM1': [14.5, 1],\n 'DS2': [8, 4],\n 'PROJET1': [9, 3],\n 'IE1': [7, 2],\n 'DS3': [8, 4],\n 'DS4':[15, 4]\n }\n }\n
L\u2019\u00e9l\u00e8ve dont le nom est Durand a ainsi obtenu au DS2 la note de 8 avec un coefficient 4.
Le professeur cr\u00e9e une fonction moyenne
qui prend en param\u00e8tre le nom d\u2019un de ses \u00e9l\u00e8ves et renvoie sa moyenne arrondie au dixi\u00e8me.
Compl\u00e9ter le code du professeur ci-dessous :
def moyenne(nom, dico_result):\n if nom in ...:\n notes = dico_result[nom]\n total_points = ...\n total_coefficients = ...\n for ... in notes.values():\n note, coefficient = valeurs\n total_points = total_points + ... * coefficient\n total_coefficients = ... + coefficient\n return round( ... / total_coefficients, 1 )\n else:\n return -1\n
def moyenne(nom, dico_result):\nif nom in dico_result:\nnotes = dico_result[nom]\ntotal_points = 0.\ntotal_coefficients = 0\nfor valeurs in notes.values():\nnote, coefficient = valeurs\ntotal_points = total_points + note * coefficient\ntotal_coefficients = total_coefficients + coefficient\nreturn round( total_points / total_coefficients, 1 )\nelse:\n return -1\n
Un professeur de NSI d\u00e9cide de g\u00e9rer les r\u00e9sultats de sa classe sous la forme d\u2019un\ndictionnaire :\n\n- les clefs sont les noms des \u00e9l\u00e8ves ;\n- les valeurs sont des dictionnaires dont les clefs sont les types d\u2019\u00e9preuves sous\nforme de cha\u00eene de caract\u00e8res et les valeurs sont les notes obtenues associ\u00e9es \u00e0\nleurs coefficients dans une liste.\n\nAvec :\n\n```python\nresultats = {'Dupont': {\n 'DS1': [15.5, 4],\n 'DM1': [14.5, 1],\n 'DS2': [13, 4],\n 'PROJET1': [16, 3],\n 'DS3': [14, 4]\n },\n 'Durand': {\n 'DS1': [6 , 4],\n 'DM1': [14.5, 1],\n 'DS2': [8, 4],\n 'PROJET1': [9, 3],\n 'IE1': [7, 2],\n 'DS3': [8, 4],\n 'DS4':[15, 4]\n }\n }\n
L\u2019\u00e9l\u00e8ve dont le nom est Durand a ainsi obtenu au DS2 la note de 8 avec un coefficient 4.
Le professeur cr\u00e9e une fonction moyenne
qui prend en param\u00e8tre le nom d\u2019un de ses \u00e9l\u00e8ves et renvoie sa moyenne arrondie au dixi\u00e8me.
Compl\u00e9ter le code du professeur ci-dessous :
def moyenne(nom, dico_result):\n if nom in ...:\n notes = dico_result[nom]\n total_points = ...\n total_coefficients = ...\n for ... in notes.values():\n note, coefficient = valeurs\n total_points = total_points + ... * coefficient\n total_coefficients = ... + coefficient\n return round( ... / total_coefficients, 1 )\n else:\n return -1\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-17","title":"\u25b6 Sujet 17","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-171","title":"Exercice 17.1","text":"Exercice 17.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction moyenne(liste_notes)
qui renvoie la moyenne pond\u00e9r\u00e9e des r\u00e9sultats contenus dans la liste liste_notes
, non vide, donn\u00e9e en param\u00e8tre. Cette liste contient des couples (note, coefficient)
dans lesquels :
note
est un nombre de type flottant (float
) compris entre 0 et 20 ;coefficient
est un nombre entier strictement positif.Ainsi l\u2019expression moyenne([(15,2),(9,1),(12,3)])
devra renvoyer 12.5
.
\\(\\dfrac{2 \\times 15 + 1 \\times 9 + 3 \\times 12 }{2+1+3}=12,5\\)
def moyenne(liste_notes):\n somme_notes = 0\n somme_coeffs = 0\n for devoir in liste_notes:\n note = devoir[0]\n coeff = devoir[1]\n somme_notes += note * coeff\n somme_coeffs += coeff\n return somme_notes / somme_coeffs\n
\u00c9crire une fonction `moyenne(liste_notes)` qui renvoie la moyenne pond\u00e9r\u00e9e des\nr\u00e9sultats contenus dans la liste `liste_notes`, non vide, donn\u00e9e en param\u00e8tre. Cette\nliste contient des couples `(note, coefficient)` dans lesquels :\n\n- `note` est un nombre de type flottant (`float`) compris entre 0 et 20 ;\n- `coefficient` est un nombre entier strictement positif.\n\nAinsi l\u2019expression `moyenne([(15,2),(9,1),(12,3)])` devra renvoyer `12.5`.\n\n$\\dfrac{2 \\times 15 + 1 \\times 9 + 3 \\times 12 }{2+1+3}=12,5$\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-172","title":"Exercice 17.2","text":"Exercice 17.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn cherche \u00e0 d\u00e9terminer les valeurs du triangle de Pascal (Figure 1).
Dans le triangle de Pascal, chaque ligne commence et se termine par le nombre 1. Comme l\u2019illustre la Figure 2, on additionne deux valeurs successives d\u2019une ligne pour obtenir la valeur qui se situe sous la deuxi\u00e8me valeur.
Compl\u00e9ter la fonction pascal
ci-apr\u00e8s prenant en param\u00e8tre un entier n
sup\u00e9rieur ou \u00e9gal \u00e0 2. Cette fonction doit renvoyer une liste correspondant au triangle de Pascal de la ligne 0 \u00e0 la ligne n
. Le tableau repr\u00e9sentant le triangle de Pascal sera contenu dans la variable triangle
.
def pascal(n):\n triangle = [[1]]\n for k in range(1,...):\n ligne_k = [...]\n for i in range(1,k):\n ligne_k.append(triangle[...][i-1]+triangle[...][...])\n ligne_k.append(...)\n triangle.append(ligne_k)\n return triangle\n
Pour n = 4
, voici ce qu'on devra obtenir :
>>> pascal(4)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]\n
Pour n = 5
, voici ce qu'on devra obtenir : >>> pascal(5)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1]]\n
def pascal(n):\n triangle = [[1]]\nfor k in range(1, n+1):\nligne_k = [1]\nfor i in range(1, k):\nligne_k.append(triangle[k-1][i-1] + triangle[k-1][i])\nligne_k.append(1)\ntriangle.append(ligne_k)\n return triangle\n
On cherche \u00e0 d\u00e9terminer les valeurs du triangle de Pascal (Figure 1).\n\nDans le triangle de Pascal, chaque ligne commence et se termine par le nombre 1.\nComme l\u2019illustre la Figure 2, on additionne deux valeurs successives d\u2019une ligne pour\nobtenir la valeur qui se situe sous la deuxi\u00e8me valeur.\n\n![image](data2023/17_triangle.png){: .center width=60%}\n\nCompl\u00e9ter la fonction `pascal` ci-apr\u00e8s prenant en param\u00e8tre un entier `n` sup\u00e9rieur ou\n\u00e9gal \u00e0 2. Cette fonction doit renvoyer une liste correspondant au triangle de Pascal de la\nligne 0 \u00e0 la ligne `n`. Le tableau repr\u00e9sentant le triangle de Pascal sera contenu dans la\nvariable `triangle`.\n\n```python linenums='1'\ndef pascal(n):\n triangle = [[1]]\n for k in range(1,...):\n ligne_k = [...]\n for i in range(1,k):\n ligne_k.append(triangle[...][i-1]+triangle[...][...])\n ligne_k.append(...)\n triangle.append(ligne_k)\n return triangle\n
Pour n = 4
, voici ce qu'on devra obtenir :
>>> pascal(4)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]]\n
Pour n = 5
, voici ce qu'on devra obtenir : >>> pascal(5)\n[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1]]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-18","title":"\u25b6 Sujet 18","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-181","title":"Exercice 18.1","text":"Exercice 18.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction max_et_indice
qui prend en param\u00e8tre une liste non vide tab
de nombres entiers et qui renvoie la valeur du plus grand \u00e9l\u00e9ment de cette liste ainsi que l\u2019indice de sa premi\u00e8re apparition dans cette liste.
L\u2019utilisation de la fonction native max
n\u2019est pas autoris\u00e9e.
Ne pas oublier d\u2019ajouter au corps de la fonction une documentation et une ou plusieurs assertions pour v\u00e9rifier les pr\u00e9-conditions.
Exemples :
>>> max_et_indice([1, 5, 6, 9, 1, 2, 3, 7, 9, 8])\n(9, 3)\n>>> max_et_indice([-2])\n(-2, 0)\n>>> max_et_indice([-1, -1, 3, 3, 3])\n(3, 2)\n>>> max_et_indice([1, 1, 1, 1])\n(1, 0)\n
def max_et_indice(tab):\n'''\n renvoie la valeur du plus grand \u00e9l\u00e9ment de cette liste ainsi\n que l\u2019indice de sa premi\u00e8re apparition dans cette liste.\n '''\n assert tab != [], 'le tableau est vide'\n\n val_max = tab[0]\n ind_max = 0\n for i in range(len(tab)):\n if tab[i] > val_max:\n val_max = tab[i]\n ind_max = i\n return (val_max, ind_max)\n
\u00c9crire une fonction `max_et_indice` qui prend en param\u00e8tre une liste non vide `tab` de\nnombres entiers et qui renvoie la valeur du plus grand \u00e9l\u00e9ment de cette liste ainsi que\nl\u2019indice de sa premi\u00e8re apparition dans cette liste.\n\nL\u2019utilisation de la fonction native `max` n\u2019est pas autoris\u00e9e.\n\nNe pas oublier d\u2019ajouter au corps de la fonction une documentation et une ou plusieurs\nassertions pour v\u00e9rifier les pr\u00e9-conditions.\n\nExemples :\n\n```python\n>>> max_et_indice([1, 5, 6, 9, 1, 2, 3, 7, 9, 8])\n(9, 3)\n>>> max_et_indice([-2])\n(-2, 0)\n>>> max_et_indice([-1, -1, 3, 3, 3])\n(3, 2)\n>>> max_et_indice([1, 1, 1, 1])\n(1, 0)\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-182","title":"Exercice 18.2","text":"Exercice 18.2
\u00c9nonc\u00e9CorrectionSources MarkdownL\u2019ordre des g\u00e8nes sur un chromosome est repr\u00e9sent\u00e9 par un tableau ordre
de n
cases d\u2019entiers distincts deux \u00e0 deux et compris entre 1 et n
.
Par exemple, ordre = [5, 4, 3, 6, 7, 2, 1, 8, 9]
dans le cas n = 9
.
On dit qu\u2019il y a un point de rupture dans ordre
dans chacune des situations suivantes :
ordre
n\u2019est pas 1 ;ordre
n\u2019est pas n.Par exemple, si ordre = [5, 4, 3, 6, 7, 2, 1, 8, 9]
avec n = 9
, on a
Il y a donc 4 points de rupture.
Compl\u00e9ter les fonctions Python est_un_ordre
et nombre_points_rupture
propos\u00e9es \u00e0 la page suivante pour que :
la fonction est_un_ordre
renvoie True
si le tableau pass\u00e9 en param\u00e8tre repr\u00e9sente bien un ordre de g\u00e8nes de chromosome et False
sinon ;
la fonction nombre_points_rupture
renvoie le nombre de points de rupture d\u2019un tableau pass\u00e9 en param\u00e8tre repr\u00e9sentant l\u2019ordre de g\u00e8nes d\u2019un chromosome.
def est_un_ordre(tab):\n'''\n Renvoie True si tab est de longueur n et contient tous les entiers\n de 1 \u00e0 n, False sinon\n '''\n for i in range(1,...):\n if ...:\n return False\n return True\n\n\ndef nombre_points_rupture(ordre):\n'''\n Renvoie le nombre de point de rupture de ordre qui repr\u00e9sente un ordre\n de g\u00e8nes de chromosome\n '''\n assert ... # ordre n'est pas un ordre de g\u00e8nes\n n = len(ordre)\n nb = 0\n if ordre[...] != 1: # le premier n'est pas 1\n nb = nb + 1\n i = 0\n while i < ...:\n if ... not in [-1, 1]: # l'\u00e9cart n'est pas 1\n nb = nb + 1\n i = i + 1\n if ordre[...] != n: # le dernier n'est pas n\n nb = nb + 1\n return nb\n
Exemples :
>>> est_un_ordre([1, 6, 2, 8, 3, 7])\nFalse\n>>> est_un_ordre([5, 4, 3, 6, 7, 2, 1, 8, 9])\nTrue\n>>> nombre_points_rupture([5, 4, 3, 6, 7, 2, 1, 8, 9])\n4\n>>> nombre_points_rupture([1, 2, 3, 4, 5])\n0\n>>> nombre_points_rupture([1, 6, 2, 8, 3, 7, 4, 5])\n7\n>>> nombre_points_rupture([2, 1, 3, 4])\n2\n
def est_un_ordre(tab):\n'''\n Renvoie True si tab est de longueur n et contient tous les entiers\n de 1 \u00e0 n, False sinon\n '''\nfor i in range(1, len(tab)+1):\nif i not in tab:\nreturn False\n return True\n\n\ndef nombre_points_rupture(ordre):\n'''\n Renvoie le nombre de point de rupture de ordre qui repr\u00e9sente un ordre\n de g\u00e8nes de chromosome\n '''\n assert est_un_ordre(ordre) # ordre n'est pas un ordre de g\u00e8nes\n n = len(ordre)\n nb = 0\nif ordre[0] != 1: # le premier n'est pas 1\nnb = nb + 1\n i = 0\nwhile i < n-1:\nif ordre[i+1] - ordre[i] not in [-1, 1]: # l'\u00e9cart n'est pas 1\nnb = nb + 1\n i = i + 1\nif ordre[n-1] != n: # le dernier n'est pas n\nnb = nb + 1\n return nb\n
L\u2019ordre des g\u00e8nes sur un chromosome est repr\u00e9sent\u00e9 par un tableau `ordre` de `n` cases\nd\u2019entiers distincts deux \u00e0 deux et compris entre 1 et `n`.\n\nPar exemple, `ordre = [5, 4, 3, 6, 7, 2, 1, 8, 9]` dans le cas `n = 9`.\n\nOn dit qu\u2019il y a un point de rupture dans `ordre` dans chacune des situations suivantes :\n\n- la premi\u00e8re valeur de `ordre` n\u2019est pas 1 ;\n- l\u2019\u00e9cart entre deux g\u00e8nes cons\u00e9cutifs n\u2019est pas \u00e9gal \u00e0 1 ;\n- la derni\u00e8re valeur de `ordre` n\u2019est pas n.\n\nPar exemple, si `ordre = [5, 4, 3, 6, 7, 2, 1, 8, 9]` avec `n = 9`, on a\n\n- un point de rupture au d\u00e9but car 5 est diff\u00e9rent de 1\n- un point de rupture entre 3 et 6 (l\u2019\u00e9cart est de 3)\n- un point de rupture entre 7 et 2 (l\u2019\u00e9cart est de 5)\n- un point de rupture entre 1 et 8 (l\u2019\u00e9cart est de 7)\n\nIl y a donc 4 points de rupture.\n\nCompl\u00e9ter les fonctions Python `est_un_ordre` et `nombre_points_rupture`\npropos\u00e9es \u00e0 la page suivante pour que :\n\n\n- la fonction `est_un_ordre` renvoie `True` si le tableau pass\u00e9 en param\u00e8tre\nrepr\u00e9sente bien un ordre de g\u00e8nes de chromosome et `False` sinon ;\n\n- la fonction `nombre_points_rupture` renvoie le nombre de points de rupture\nd\u2019un tableau pass\u00e9 en param\u00e8tre repr\u00e9sentant l\u2019ordre de g\u00e8nes d\u2019un\nchromosome.\n\n```python linenums='1'\ndef est_un_ordre(tab):\n '''\n Renvoie True si tab est de longueur n et contient tous les entiers\n de 1 \u00e0 n, False sinon\n '''\n for i in range(1,...):\n if ...:\n return False\n return True\n\n\ndef nombre_points_rupture(ordre):\n '''\n Renvoie le nombre de point de rupture de ordre qui repr\u00e9sente un ordre\n de g\u00e8nes de chromosome\n '''\n assert ... # ordre n'est pas un ordre de g\u00e8nes\n n = len(ordre)\n nb = 0\n if ordre[...] != 1: # le premier n'est pas 1\n nb = nb + 1\n i = 0\n while i < ...:\n if ... not in [-1, 1]: # l'\u00e9cart n'est pas 1\n nb = nb + 1\n i = i + 1\n if ordre[...] != n: # le dernier n'est pas n\n nb = nb + 1\n return nb\n
Exemples :
>>> est_un_ordre([1, 6, 2, 8, 3, 7])\nFalse\n>>> est_un_ordre([5, 4, 3, 6, 7, 2, 1, 8, 9])\nTrue\n>>> nombre_points_rupture([5, 4, 3, 6, 7, 2, 1, 8, 9])\n4\n>>> nombre_points_rupture([1, 2, 3, 4, 5])\n0\n>>> nombre_points_rupture([1, 6, 2, 8, 3, 7, 4, 5])\n7\n>>> nombre_points_rupture([2, 1, 3, 4])\n2\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-19","title":"\u25b6 Sujet 19","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-191","title":"Exercice 19.1","text":"Exercice 19.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche
qui prend en param\u00e8tres un tableau tab
de nombres entiers tri\u00e9s par ordre croissant et un nombre entier n
, et qui effectue une recherche dichotomique du nombre entier n
dans le tableau non vide tab
.
Cette fonction doit renvoyer un indice correspondant au nombre cherch\u00e9 s\u2019il est dans le tableau, -1
sinon.
Exemples :
>>> recherche([2, 3, 4, 5, 6], 5)\n3\n>>> recherche([2, 3, 4, 6, 7], 5)\n-1\n
def recherche(tab, n):\n ind_debut = 0\n ind_fin = len(tab) - 1\n while ind_debut <= ind_fin:\n ind_milieu = (ind_debut + ind_fin) // 2\n if tab[ind_milieu] == n:\n return ind_milieu\n elif tab[ind_milieu] < n:\n ind_debut = ind_milieu + 1\n else:\n ind_fin = ind_milieu - 1\n return -1\n
\u00c9crire une fonction `recherche` qui prend en param\u00e8tres un tableau `tab` de nombres\nentiers tri\u00e9s par ordre croissant et un nombre entier `n`, et qui effectue une recherche\ndichotomique du nombre entier `n` dans le tableau non vide `tab`.\n\nCette fonction doit renvoyer un indice correspondant au nombre cherch\u00e9 s\u2019il est dans le\ntableau, `-1` sinon.\n\nExemples :\n```python\n>>> recherche([2, 3, 4, 5, 6], 5)\n3\n>>> recherche([2, 3, 4, 6, 7], 5)\n-1\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-192","title":"Exercice 19.2","text":"Exercice 19.2
\u00c9nonc\u00e9CorrectionSources MarkdownLe codage de C\u00e9sar transforme un message en changeant chaque lettre en la d\u00e9calant dans l\u2019alphabet. Par exemple, avec un d\u00e9calage de 3, le A se transforme en D, le B en E, ..., le X en A, le Y en B et le Z en C. Les autres caract\u00e8res (\u2018!\u2019,\u2019 ?\u2019 ...) ne sont pas cod\u00e9s.
La fonction position_alphabet
ci-dessous prend en param\u00e8tre un caract\u00e8re lettre
et renvoie la position de lettre
dans la cha\u00eene de caract\u00e8res ALPHABET
s\u2019il s\u2019y trouve.
La fonction cesar
prend en param\u00e8tre une cha\u00eene de caract\u00e8res message
et un nombre entier decalage
et renvoie le nouveau message cod\u00e9 avec le codage de C\u00e9sar utilisant le d\u00e9calage decalage
.
ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\ndef position_alphabet(lettre):\n return ord(lettre) - ord('A')\n\ndef cesar(message, decalage):\n resultat = ''\n for ... in message:\n if 'A' <= c and c <= 'Z':\n indice = ( ... ) % 26\n resultat = resultat + ALPHABET[indice]\n else:\n resultat = ...\n return resultat\n
Compl\u00e9ter la fonction cesar
.
Exemples :
>>> cesar('BONJOUR A TOUS. VIVE LA MATIERE NSI !', 4)\n'FSRNSYV E XSYW. ZMZI PE QEXMIVI RWM !'\n>>> cesar('GTSOTZW F YTZX. ANAJ QF RFYNJWJ SXN !', -5)\n'BONJOUR A TOUS. VIVE LA MATIERE NSI !'\n
ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\ndef position_alphabet(lettre):\n return ord(lettre) - ord('A')\n\ndef cesar(message, decalage):\n resultat = ''\nfor c in message:\nif 'A' <= c and c <= 'Z':\nindice = (position_alphabet(c) + decalage) % 26\nresultat = resultat + ALPHABET[indice]\n else:\nresultat = resultat + c\nreturn resultat\n
Le codage de C\u00e9sar transforme un message en changeant chaque lettre en la d\u00e9calant\ndans l\u2019alphabet.\nPar exemple, avec un d\u00e9calage de 3, le A se transforme en D, le B en E, ..., le X en A,\nle Y en B et le Z en C. Les autres caract\u00e8res (\u2018!\u2019,\u2019 ?\u2019 ...) ne sont pas cod\u00e9s.\n\nLa fonction `position_alphabet` ci-dessous prend en param\u00e8tre un caract\u00e8re `lettre`\net renvoie la position de `lettre` dans la cha\u00eene de caract\u00e8res `ALPHABET` s\u2019il s\u2019y trouve.\n\nLa fonction `cesar` prend en param\u00e8tre une cha\u00eene de caract\u00e8res `message` et un nombre\nentier `decalage` et renvoie le nouveau message cod\u00e9 avec le codage de C\u00e9sar utilisant\nle d\u00e9calage `decalage`.\n\n```python linenums='1'\nALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\ndef position_alphabet(lettre):\n return ord(lettre) - ord('A')\n\ndef cesar(message, decalage):\n resultat = ''\n for ... in message:\n if 'A' <= c and c <= 'Z':\n indice = ( ... ) % 26\n resultat = resultat + ALPHABET[indice]\n else:\n resultat = ...\n return resultat\n
Compl\u00e9ter la fonction cesar
.
Exemples :
>>> cesar('BONJOUR A TOUS. VIVE LA MATIERE NSI !', 4)\n'FSRNSYV E XSYW. ZMZI PE QEXMIVI RWM !'\n>>> cesar('GTSOTZW F YTZX. ANAJ QF RFYNJWJ SXN !', -5)\n'BONJOUR A TOUS. VIVE LA MATIERE NSI !'\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-20","title":"\u25b6 Sujet 20","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-201","title":"Exercice 20.1","text":"Exercice 20.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction ajoute_dictionnaires
qui prend en param\u00e8tres deux dictionnaires d1
et d2
dont les cl\u00e9s sont des nombres et renvoie le dictionnaire d
d\u00e9fini de la fa\u00e7on suivante :
d
sont celles de d1
et celles de d2
r\u00e9unies.d1
et d2
, sa valeur associ\u00e9e dans le dictionnaire d est la somme de ses valeurs dans les dictionnaires d1
et d2
.d
est la m\u00eame que sa valeur dans le dictionnaire o\u00f9 elle est pr\u00e9sente.Exemples :
>>> ajoute_dictionnaires({1: 5, 2: 7}, {2: 9, 3: 11})\n{1: 5, 2: 16, 3: 11}\n>>> ajoute_dictionnaires({}, {2: 9, 3: 11})\n{2: 9, 3: 11}\n>>> ajoute_dictionnaires({1: 5, 2: 7}, {})\n{1: 5, 2: 7}\n
def ajoute_dictionnaires(d1, d2):\nfor cle in d2:\n if cle in d1:\n d1[cle] += d2[cle]\n else:\n d1[cle] = d2[cle]\nreturn d1\n
\u00c9crire une fonction `ajoute_dictionnaires` qui prend en param\u00e8tres deux\ndictionnaires `d1` et `d2` dont les cl\u00e9s sont des nombres et renvoie le dictionnaire `d` d\u00e9fini de\nla fa\u00e7on suivante :\n\n- Les cl\u00e9s de `d` sont celles de `d1` et celles de `d2` r\u00e9unies.\n- Si une cl\u00e9 est pr\u00e9sente dans les deux dictionnaires `d1` et `d2`, sa valeur associ\u00e9e\ndans le dictionnaire d est la somme de ses valeurs dans les dictionnaires `d1` et `d2`.\n- Si une cl\u00e9 n\u2019est pr\u00e9sente que dans un des deux dictionnaires, sa valeur associ\u00e9e\ndans le dictionnaire `d` est la m\u00eame que sa valeur dans le dictionnaire o\u00f9 elle est\npr\u00e9sente.\n\nExemples :\n\n```python\n>>> ajoute_dictionnaires({1: 5, 2: 7}, {2: 9, 3: 11})\n{1: 5, 2: 16, 3: 11}\n>>> ajoute_dictionnaires({}, {2: 9, 3: 11})\n{2: 9, 3: 11}\n>>> ajoute_dictionnaires({1: 5, 2: 7}, {})\n{1: 5, 2: 7}\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-202","title":"Exercice 20.2","text":"Exercice 20.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re une piste carr\u00e9e qui contient 4 cases par c\u00f4t\u00e9. Les cases sont num\u00e9rot\u00e9es de 0 inclus \u00e0 12 exclu comme ci-dessous :
L\u2019objectif de l\u2019exercice est d\u2019impl\u00e9menter le jeu suivant :
Au d\u00e9part, le joueur place son pion sur la case 0. A chaque coup, il lance un d\u00e9 \u00e9quilibr\u00e9 \u00e0 six faces et avance son pion d\u2019autant de cases que le nombre indiqu\u00e9 par le d\u00e9 (entre 1 et 6 inclus) dans le sens des aiguilles d\u2019une montre.
Par exemple, s\u2019il obtient 2 au premier lancer, il pose son pion sur la case 2 puis s\u2019il obtient 6 au deuxi\u00e8me lancer, il le pose sur la case 8, puis s\u2019il obtient \u00e0 nouveau 6, il pose le pion sur la case 2.
Le jeu se termine lorsque le joueur a pos\u00e9 son pion sur toutes les cases de la piste.
Compl\u00e9ter la fonction nbre_coups
ci-dessous de sorte qu\u2019elle renvoie le nombre de lancers al\u00e9atoires n\u00e9cessaires pour terminer le jeu.
Proposer ensuite quelques tests pour en v\u00e9rifier le fonctionnement.
from random import randint\n\ndef nbre_coups():\n n = ...\n cases_vues = [0]\n case_en_cours = 0\n nbre_cases = 12\n while ... < ...:\n x = randint(1, 6)\n case_en_cours = (case_en_cours + ...) % ...\n if ...:\n cases_vues.append(case_en_cours)\n n = ...\n return n\n
from random import randint\n\ndef nbre_coups():\nn = 0\ncases_vues = [0]\n case_en_cours = 0\n nbre_cases = 12\nwhile len(cases_vues) < nbre_cases:\nx = randint(1, 6)\ncase_en_cours = (case_en_cours + x) % nbre_cases\nif case_en_cours not in cases_vues:\ncases_vues.append(case_en_cours)\nn = n + 1\nreturn n\n
On consid\u00e8re une piste carr\u00e9e qui contient 4 cases par c\u00f4t\u00e9. Les cases sont num\u00e9rot\u00e9es\nde 0 inclus \u00e0 12 exclu comme ci-dessous :\n\n![image](data2023/20_carre.png){: .center width=20%}\n\nL\u2019objectif de l\u2019exercice est d\u2019impl\u00e9menter le jeu suivant :\n\nAu d\u00e9part, le joueur place son pion sur la case 0. A chaque coup, il lance un d\u00e9 \u00e9quilibr\u00e9\n\u00e0 six faces et avance son pion d\u2019autant de cases que le nombre indiqu\u00e9 par le d\u00e9 (entre\n1 et 6 inclus) dans le sens des aiguilles d\u2019une montre.\n\nPar exemple, s\u2019il obtient 2 au premier lancer, il pose son pion sur la case 2 puis s\u2019il\nobtient 6 au deuxi\u00e8me lancer, il le pose sur la case 8, puis s\u2019il obtient \u00e0 nouveau 6, il\npose le pion sur la case 2.\n\nLe jeu se termine lorsque le joueur a pos\u00e9 son pion sur **toutes les cases** de la piste.\n\nCompl\u00e9ter la fonction `nbre_coups` ci-dessous de sorte qu\u2019elle renvoie le nombre de\nlancers al\u00e9atoires n\u00e9cessaires pour terminer le jeu.\n\nProposer ensuite quelques tests pour en v\u00e9rifier le fonctionnement.\n\n```python linenums='1'\nfrom random import randint\n\ndef nbre_coups():\n n = ...\n cases_vues = [0]\n case_en_cours = 0\n nbre_cases = 12\n while ... < ...:\n x = randint(1, 6)\n case_en_cours = (case_en_cours + ...) % ...\n if ...:\n cases_vues.append(case_en_cours)\n n = ...\n return n\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-21","title":"\u25b6 Sujet 21","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-211","title":"Exercice 21.1","text":"Exercice 21.1
\u00c9nonc\u00e9CorrectionSource MarkdownLe codage par diff\u00e9rence (delta encoding en anglais) permet de compresser un tableau de donn\u00e9es en indiquant pour chaque donn\u00e9e, sa diff\u00e9rence avec la pr\u00e9c\u00e9dente (plut\u00f4t que la donn\u00e9e elle-m\u00eame). On se retrouve alors avec un tableau de donn\u00e9es plus petit, n\u00e9cessitant moins de place en m\u00e9moire. Cette m\u00e9thode se r\u00e9v\u00e8le efficace lorsque les valeurs cons\u00e9cutives sont proches.
Programmer la fonction delta(liste)
qui prend en param\u00e8tre un tableau non vide de nombres entiers et qui renvoie un tableau contenant les valeurs enti\u00e8res compress\u00e9es \u00e0 l\u2019aide cette technique.
Exemples :
>>> delta([1000, 800, 802, 1000, 1003])\n[1000, -200, 2, 198, 3]\n>>> delta([42])\n[42] \n
def delta(tab):\n diff = [tab[0]]\n for i in range(1, len(tab)):\n diff.append(tab[i] - tab[i-1])\n return diff\n
Le codage par diff\u00e9rence (*delta encoding* en anglais) permet de compresser un tableau de\ndonn\u00e9es en indiquant pour chaque donn\u00e9e, sa diff\u00e9rence avec la pr\u00e9c\u00e9dente (plut\u00f4t que la\ndonn\u00e9e elle-m\u00eame). On se retrouve alors avec un tableau de donn\u00e9es plus petit, n\u00e9cessitant\nmoins de place en m\u00e9moire. Cette m\u00e9thode se r\u00e9v\u00e8le efficace lorsque les valeurs cons\u00e9cutives\nsont proches.\n\nProgrammer la fonction `delta(liste)` qui prend en param\u00e8tre un tableau non vide de nombres entiers\net qui renvoie un tableau contenant les valeurs enti\u00e8res compress\u00e9es \u00e0 l\u2019aide cette technique.\n\nExemples :\n\n```python\n>>> delta([1000, 800, 802, 1000, 1003])\n[1000, -200, 2, 198, 3]\n>>> delta([42])\n[42] \n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-212","title":"Exercice 21.2","text":"Exercice 21.2
\u00c9nonc\u00e9CorrectionSources MarkdownUne expression arithm\u00e9tique ne comportant que les quatre op\u00e9rations +, \u2212, \u00d7, \u00f7 peut \u00eatre repr\u00e9sent\u00e9e sous forme d\u2019arbre binaire. Les n\u0153uds internes sont des op\u00e9rateurs et les feuilles sont des nombres. Dans un tel arbre, la disposition des n\u0153uds joue le r\u00f4le des parenth\u00e8ses que nous connaissons bien.
En parcourant en profondeur infixe l\u2019arbre binaire ci-dessus, on retrouve l\u2019expression not\u00e9e habituellement :
\\[(3 \\times (8 + 7)) \u2212 (2 + 1)\\]La classe Noeud
ci-apr\u00e8s permet d\u2019impl\u00e9menter une structure d\u2019arbre binaire.
Compl\u00e9ter la fonction r\u00e9cursive expression_infixe
qui prend en param\u00e8tre un objet de la classe Noeud
et qui renvoie l\u2019expression arithm\u00e9tique repr\u00e9sent\u00e9e par l\u2019arbre binaire pass\u00e9 en param\u00e8tre, sous forme d\u2019une cha\u00eene de caract\u00e8res contenant des parenth\u00e8ses.
R\u00e9sultat attendu avec l\u2019arbre ci-dessus :
>>> e = Noeud(Noeud(Noeud(None, 3, None), '*', Noeud(Noeud(None, 8, None),\n'+', Noeud(None, 7, None))), '-', Noeud(Noeud(None, 2, None), '+',\nNoeud(None, 1, None)))\n\n>>> expression_infixe(e)\n'((3*(8+7))-(2+1))'\n
class Noeud:\n'''\n classe impl\u00e9mentant un noeud d'arbre binaire\n '''\n\n def __init__(self, g, v, d):\n'''\n un objet Noeud poss\u00e8de 3 attributs :\n - gauche : le sous-arbre gauche,\n - valeur : la valeur de l'\u00e9tiquette,\n - droit : le sous-arbre droit.\n '''\n self.gauche = g\n self.valeur = v\n self.droit = d\n\n def __str__(self):\n'''\n renvoie la repr\u00e9sentation du noeud en chaine de caract\u00e8res\n '''\n return str(self.valeur)\n\n def est_une_feuille(self):\n'''\n renvoie True si et seulement si le noeud est une feuille\n '''\n return self.gauche is None and self.droit is None\n\n\ndef expression_infixe(e):\n s = ...\n if e.gauche is not None:\n s = '(' + s + expression_infixe(...)\n s = s + ...\n if ... is not None:\n s = s + ... + ...\n return s\n
class Noeud:\n'''\n classe impl\u00e9mentant un noeud d'arbre binaire\n '''\n\n def __init__(self, g, v, d):\n'''\n un objet Noeud poss\u00e8de 3 attributs :\n - gauche : le sous-arbre gauche,\n - valeur : la valeur de l'\u00e9tiquette,\n - droit : le sous-arbre droit.\n '''\n self.gauche = g\n self.valeur = v\n self.droit = d\n\n def __str__(self):\n'''\n renvoie la repr\u00e9sentation du noeud en chaine de caract\u00e8res\n '''\n return str(self.valeur)\n\n def est_une_feuille(self):\n'''\n renvoie True si et seulement si le noeud est une feuille\n '''\n return self.gauche is None and self.droit is None\n\n\ndef expression_infixe(e):\ns = ''\nif e.gauche is not None:\ns = '(' + s + expression_infixe(e.gauche)\ns = s + str(e.valeur)\nif e.droit is not None:\ns = s + expression_infixe(e.droit) + ')'\nreturn s\n
Une expression arithm\u00e9tique ne comportant que les quatre op\u00e9rations +, \u2212, \u00d7, \u00f7 peut \u00eatre\nrepr\u00e9sent\u00e9e sous forme d\u2019arbre binaire. Les n\u0153uds internes sont des op\u00e9rateurs et les feuilles\nsont des nombres. Dans un tel arbre, la disposition des n\u0153uds joue le r\u00f4le des parenth\u00e8ses que\nnous connaissons bien. \n\n![image](data2023/21_arbre.png){: .center width=30%}\n\nEn parcourant en profondeur infixe l\u2019arbre binaire ci-dessus, on\nretrouve l\u2019expression not\u00e9e habituellement : \n\n\n$$(3 \\times (8 + 7)) \u2212 (2 + 1)$$\n\n\nLa classe `Noeud` ci-apr\u00e8s permet d\u2019impl\u00e9menter une structure\nd\u2019arbre binaire.\n\nCompl\u00e9ter la fonction r\u00e9cursive `expression_infixe` qui prend\nen param\u00e8tre un objet de la classe `Noeud` et qui renvoie\nl\u2019expression arithm\u00e9tique repr\u00e9sent\u00e9e par l\u2019arbre binaire pass\u00e9\nen param\u00e8tre, sous forme d\u2019une cha\u00eene de caract\u00e8res contenant\ndes parenth\u00e8ses. \n\nR\u00e9sultat attendu avec l\u2019arbre ci-dessus :\n\n```python\n>>> e = Noeud(Noeud(Noeud(None, 3, None), '*', Noeud(Noeud(None, 8, None),\n'+', Noeud(None, 7, None))), '-', Noeud(Noeud(None, 2, None), '+',\nNoeud(None, 1, None)))\n\n>>> expression_infixe(e)\n'((3*(8+7))-(2+1))'\n
class Noeud:\n'''\n classe impl\u00e9mentant un noeud d'arbre binaire\n '''\n\n def __init__(self, g, v, d):\n'''\n un objet Noeud poss\u00e8de 3 attributs :\n - gauche : le sous-arbre gauche,\n - valeur : la valeur de l'\u00e9tiquette,\n - droit : le sous-arbre droit.\n '''\n self.gauche = g\n self.valeur = v\n self.droit = d\n\n def __str__(self):\n'''\n renvoie la repr\u00e9sentation du noeud en chaine de caract\u00e8res\n '''\n return str(self.valeur)\n\n def est_une_feuille(self):\n'''\n renvoie True si et seulement si le noeud est une feuille\n '''\n return self.gauche is None and self.droit is None\n\n\ndef expression_infixe(e):\n s = ...\n if e.gauche is not None:\n s = '(' + s + expression_infixe(...)\n s = s + ...\n if ... is not None:\n s = s + ... + ...\n return s\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-22","title":"\u25b6 Sujet 22","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-221","title":"Exercice 22.1","text":"Exercice 22.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn rappelle que :
t[-1]
permet d\u2019acc\u00e9der au dernier \u00e9l\u00e9ment du tableau t
.Dans cet exercice, l\u2019op\u00e9rateur **
et la fonction pow
ne sont pas autoris\u00e9s.
Programmer en langage Python une fonction liste_puissances
qui prend en argument un nombre entier a
, un entier strictement positif n
et qui renvoie la liste de ses puissances \\(\\rm{[a^1, a^2, ..., a^n]}\\).
Programmer \u00e9galement une fonction liste_puisssances_borne
qui prend en argument un nombre entier a
sup\u00e9rieur ou \u00e9gal \u00e0 2 et un entier borne
, et qui renvoie la liste de ses puissances, \u00e0 l\u2019exclusion de \\(\\rm{a^0}\\), strictement inf\u00e9rieures \u00e0 borne
.
Exemples :
>>> liste_puissances(3, 5)\n[3, 9, 27, 81, 243]\n>>> liste_puissances(-2, 4)\n[-2, 4, -8, 16]\n>>> liste_puissances_borne(2, 16)\n[2, 4, 8]\n>>> liste_puissances_borne(2, 17)\n[2, 4, 8, 16]\n>>> liste_puissances_borne(5, 5)\n[]\n
def liste_puissances(a,n):\n puissances = [a]\n for i in range(n-1):\n puissances.append(puissances[-1] * a)\n return puissances\n\ndef liste_puissances_borne(a, borne):\n lst = []\n val = a\n while val < borne:\n lst.append(val)\n val = val * a\n return lst\n
On rappelle que :\n\n- le nombre $a^n$ est le nombre $a \\times a \\times a \\times \\dots \\times a$, o\u00f9 le facteur $a$ appara\u00eet $n$ fois,\n- en langage Python, l\u2019instruction `t[-1]` permet d\u2019acc\u00e9der au dernier \u00e9l\u00e9ment du\ntableau `t`.\n\nDans cet exercice, l\u2019op\u00e9rateur ```**``` et la fonction `pow` ne sont pas autoris\u00e9s.\n\nProgrammer en langage Python une fonction `liste_puissances` qui prend en argument\nun nombre entier `a`, un entier strictement positif `n` et qui renvoie la liste de ses puissances\n$\\rm{[a^1, a^2, ..., a^n]}$.\n\nProgrammer \u00e9galement une fonction `liste_puisssances_borne` qui prend en\nargument un nombre entier `a` sup\u00e9rieur ou \u00e9gal \u00e0 2 et un entier `borne`, et qui renvoie la\nliste de ses puissances, \u00e0 l\u2019exclusion de $\\rm{a^0}$, strictement inf\u00e9rieures \u00e0 `borne`.\n\nExemples :\n\n```python\n>>> liste_puissances(3, 5)\n[3, 9, 27, 81, 243]\n>>> liste_puissances(-2, 4)\n[-2, 4, -8, 16]\n>>> liste_puissances_borne(2, 16)\n[2, 4, 8]\n>>> liste_puissances_borne(2, 17)\n[2, 4, 8, 16]\n>>> liste_puissances_borne(5, 5)\n[]\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-222","title":"Exercice 22.2","text":"Exercice 22.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn affecte \u00e0 chaque lettre de l'alphabet un code selon le tableau ci-dessous :
A B C D E F G H I J K L M 1 2 3 4 5 6 7 8 9 10 11 12 13 N O P Q R S T U V W X Y Z 14 15 16 17 18 19 20 21 22 23 24 25 26Pour un mot donn\u00e9, on d\u00e9termine d\u2019une part son code alphab\u00e9tique concat\u00e9n\u00e9, obtenu par la juxtaposition des codes de chacun de ses caract\u00e8res, et d\u2019autre part, son code additionn\u00e9, qui est la somme des codes de chacun de ses caract\u00e8res.
Par ailleurs, on dit que ce mot est \u00ab parfait \u00bb si le code additionn\u00e9 divise le code concat\u00e9n\u00e9.
Exemples :
Pour le mot \"PAUL\"
, le code concat\u00e9n\u00e9 est la cha\u00eene '1612112'
, soit l\u2019entier 1 612 112. Son code additionn\u00e9 est l\u2019entier 50 car 16 + 1 + 21 + 12 = 50. 50 ne divise pas l\u2019entier 1 612 112 ; par cons\u00e9quent, le mot \"PAUL\"
n\u2019est pas parfait.
Pour le mot \"ALAIN\"
, le code concat\u00e9n\u00e9 est la cha\u00eene '1121914'
, soit l\u2019entier 1 121 914. Le code additionn\u00e9 est l\u2019entier 37 car 1 + 12 + 1 + 9 + 14 = 37. 37 divise l\u2019entier 1 121 914 ; par cons\u00e9quent, le mot \"ALAIN\"
est parfait.
Compl\u00e9ter la fonction est_parfait
ci-dessous qui prend comme argument une cha\u00eene de caract\u00e8res mot
(en lettres majuscules) et qui renvoie le code alphab\u00e9tique concat\u00e9n\u00e9, le code additionn\u00e9 de mot
, ainsi qu\u2019un bool\u00e9en qui indique si mot
est parfait ou pas.
dico = {\"A\": 1, \"B\": 2, \"C\": 3, \"D\": 4, \"E\": 5, \"F\": 6,\n \"G\": 7, \"H\": 8, \"I\": 9, \"J\": 10, \"K\": 11, \"L\": 12,\n \"M\": 13, \"N\": 14, \"O\": 15, \"P\": 16, \"Q\": 17,\n \"R\": 18, \"S\": 19, \"T\": 20, \"U\": 21, \"V\": 22,\n \"W\": 23, \"X\": 24, \"Y\": 25, \"Z\": 26}\n\n\ndef est_parfait(mot):\n # mot est une cha\u00eene de caract\u00e8res (en lettres majuscules)\n code_concatene = \"\"\n code_additionne = ...\n for c in mot:\n code_concatene = code_concatene + ...\n code_additionne = ...\n code_concatene = int(code_concatene)\n if ... :\n mot_est_parfait = True\n else:\n mot_est_parfait = False\n return code_additionne, code_concatene, mot_est_parfait\n
Exemples :
>>> est_parfait(\"PAUL\")\n(50, 1612112, False)\n>>> est_parfait(\"ALAIN\")\n(37, 1121914, True)\n
dico = {\"A\": 1, \"B\": 2, \"C\": 3, \"D\": 4, \"E\": 5, \"F\": 6,\n \"G\": 7, \"H\": 8, \"I\": 9, \"J\": 10, \"K\": 11, \"L\": 12,\n \"M\": 13, \"N\": 14, \"O\": 15, \"P\": 16, \"Q\": 17,\n \"R\": 18, \"S\": 19, \"T\": 20, \"U\": 21, \"V\": 22,\n \"W\": 23, \"X\": 24, \"Y\": 25, \"Z\": 26}\n\n\ndef est_parfait(mot):\n # mot est une cha\u00eene de caract\u00e8res (en lettres majuscules)\n code_concatene = \"\"\ncode_additionne = 0\nfor c in mot:\ncode_concatene = code_concatene + str(dico[c])\ncode_additionne = code_additionne + dico[c]\ncode_concatene = int(code_concatene)\nif code_concatene % code_additionne == 0:\nmot_est_parfait = True\n else:\n mot_est_parfait = False\n return code_additionne, code_concatene, mot_est_parfait\n
On affecte \u00e0 chaque lettre de l'alphabet un code selon le tableau ci-dessous :\n\n| A | B | C | D | E | F | G | H | I | J | K | L | M |\n|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|\n| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |\n\n\n| N | O | P | Q | R | S | T | U | V | W | X | Y | Z | \n|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|\n| 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | \n\n\n\nPour un mot donn\u00e9, on d\u00e9termine d\u2019une part son *code alphab\u00e9tique concat\u00e9n\u00e9*, obtenu\npar la juxtaposition des codes de chacun de ses caract\u00e8res, et d\u2019autre part, *son code\nadditionn\u00e9*, qui est la somme des codes de chacun de ses caract\u00e8res.\n\nPar ailleurs, on dit que ce mot est \u00ab *parfait* \u00bb si le code additionn\u00e9 divise le code concat\u00e9n\u00e9.\n\nExemples :\n\n- Pour le mot `\"PAUL\"`, le code concat\u00e9n\u00e9 est la cha\u00eene `'1612112'`, soit l\u2019entier 1 612 112.\nSon code additionn\u00e9 est l\u2019entier 50 car 16 + 1 + 21 + 12 = 50.\n50 ne divise pas l\u2019entier 1 612 112 ; par cons\u00e9quent, le mot `\"PAUL\"` n\u2019est pas\nparfait.\n\n- Pour le mot `\"ALAIN\"`, le code concat\u00e9n\u00e9 est la cha\u00eene `'1121914'`, soit l\u2019entier\n1 121 914. Le code additionn\u00e9 est l\u2019entier 37 car 1 + 12 + 1 + 9 + 14 = 37.\n37 divise l\u2019entier 1 121 914 ; par cons\u00e9quent, le mot `\"ALAIN\"` est parfait.\n\n\nCompl\u00e9ter la fonction `est_parfait` ci-dessous qui prend comme argument une cha\u00eene\nde caract\u00e8res `mot` (en lettres majuscules) et qui renvoie le code alphab\u00e9tique concat\u00e9n\u00e9,\nle code additionn\u00e9 de `mot`, ainsi qu\u2019un bool\u00e9en qui indique si `mot` est parfait ou pas.\n\n```python linenums='1'\ndico = {\"A\": 1, \"B\": 2, \"C\": 3, \"D\": 4, \"E\": 5, \"F\": 6,\n \"G\": 7, \"H\": 8, \"I\": 9, \"J\": 10, \"K\": 11, \"L\": 12,\n \"M\": 13, \"N\": 14, \"O\": 15, \"P\": 16, \"Q\": 17,\n \"R\": 18, \"S\": 19, \"T\": 20, \"U\": 21, \"V\": 22,\n \"W\": 23, \"X\": 24, \"Y\": 25, \"Z\": 26}\n\n\ndef est_parfait(mot):\n # mot est une cha\u00eene de caract\u00e8res (en lettres majuscules)\n code_concatene = \"\"\n code_additionne = ...\n for c in mot:\n code_concatene = code_concatene + ...\n code_additionne = ...\n code_concatene = int(code_concatene)\n if ... :\n mot_est_parfait = True\n else:\n mot_est_parfait = False\n return code_additionne, code_concatene, mot_est_parfait\n
Exemples :
>>> est_parfait(\"PAUL\")\n(50, 1612112, False)\n>>> est_parfait(\"ALAIN\")\n(37, 1121914, True)\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-23","title":"\u25b6 Sujet 23","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-231","title":"Exercice 23.1","text":"Exercice 23.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn consid\u00e8re des tables (des tableaux de dictionnaires) qui contiennent des enregistrements relatifs \u00e0 des animaux h\u00e9berg\u00e9s dans un refuge. Les attributs des enregistrements sont 'nom'
, 'espece'
, 'age'
, 'enclos'
. Voici un exemple d'une telle table :
animaux = [ {'nom':'Medor', 'espece':'chien', 'age':5, 'enclos':2},\n {'nom':'Titine', 'espece':'chat', 'age':2, 'enclos':5},\n {'nom':'Tom', 'espece':'chat', 'age':7, 'enclos':4},\n {'nom':'Belle', 'espece':'chien', 'age':6, 'enclos':3},\n {'nom':'Mirza', 'espece':'chat', 'age':6, 'enclos':5}]\n
Programmer une fonction selection_enclos
qui :
table_animaux
contenant des enregistrements relatifs \u00e0 des animaux (comme dans l'exemple ci-dessus),num_enclos
;table_animaux
dont l'attribut 'enclos'
est num_enclos
.Exemples avec la table animaux
ci-dessus :
>>> selection_enclos(animaux, 5)\n[{'nom':'Titine', 'espece':'chat', 'age':2, 'enclos':5},\n {'nom':'Mirza', 'espece':'chat', 'age':6, 'enclos':5}]\n\n>>> selection_enclos(animaux, 2)\n[{'nom':'Medor', 'espece':'chien', 'age':5, 'enclos':2}]\n\n>>> selection_enclos(animaux, 7)\n[]\n
def selection_enclos(table_animaux, num_enclos):\n table = []\n for animal in table_animaux:\n if animal['enclos'] == num_enclos:\n table.append(animal)\n return table\n
On consid\u00e8re des tables (des tableaux de dictionnaires) qui contiennent des enregistrements\nrelatifs \u00e0 des animaux h\u00e9berg\u00e9s dans un refuge. Les attributs des enregistrements sont\n`'nom'`, `'espece'`, `'age'`, `'enclos'`. Voici un exemple d'une telle table :\n\n```python\nanimaux = [ {'nom':'Medor', 'espece':'chien', 'age':5, 'enclos':2},\n {'nom':'Titine', 'espece':'chat', 'age':2, 'enclos':5},\n {'nom':'Tom', 'espece':'chat', 'age':7, 'enclos':4},\n {'nom':'Belle', 'espece':'chien', 'age':6, 'enclos':3},\n {'nom':'Mirza', 'espece':'chat', 'age':6, 'enclos':5}]\n```\n\nProgrammer une fonction `selection_enclos` qui :\n\n- prend en param\u00e8tres :\n - une table `table_animaux` contenant des enregistrements relatifs \u00e0 des\nanimaux (comme dans l'exemple ci-dessus),\n - un num\u00e9ro d'enclos `num_enclos` ;\n- renvoie une table contenant les enregistrements de `table_animaux` dont l'attribut\n`'enclos'` est `num_enclos`.\n\nExemples avec la table `animaux` ci-dessus :\n\n```python\n>>> selection_enclos(animaux, 5)\n[{'nom':'Titine', 'espece':'chat', 'age':2, 'enclos':5},\n {'nom':'Mirza', 'espece':'chat', 'age':6, 'enclos':5}]\n\n>>> selection_enclos(animaux, 2)\n[{'nom':'Medor', 'espece':'chien', 'age':5, 'enclos':2}]\n\n>>> selection_enclos(animaux, 7)\n[]\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-232","title":"Exercice 23.2","text":"Exercice 23.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re des tableaux de nombres dont tous les \u00e9l\u00e9ments sont pr\u00e9sents exactement trois fois \u00e0 la suite, sauf un \u00e9l\u00e9ment qui est pr\u00e9sent une unique fois et que l'on appelle \u00ab l'intrus \u00bb. Voici quelques exemples :
tab_a = [3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5, 5, 5]\n#l'intrus est 7\n\ntab_b = [8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3]\n#l'intrus est 8\n\ntab_c = [5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8, 8, 8]\n#l'intrus est 3\n
On remarque qu'avec de tels tableaux : Ce que l'on peut observer ci-dessous en observant les valeurs des paires de voisins marqu\u00e9es par des caract\u00e8res ^ :
[3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5, 5, 5]\n ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^\n 0 3 6 9 12 15 18 21\n
Dans des listes comme celles ci-dessus, un algorithme r\u00e9cursif pour trouver l'intrus consiste alors \u00e0 choisir un indice i
multiple de 3 situ\u00e9 approximativement au milieu des indices parmi lesquels se trouve l'intrus.
Puis, en fonction des valeurs de l'\u00e9l\u00e9ment d'indice i
et de son voisin de droite, \u00e0 appliquer r\u00e9cursivement l'algorithme \u00e0 la moiti\u00e9 droite ou \u00e0 la moiti\u00e9 gauche des indices parmi lesquels se trouve l'intrus.
Par exemple, si on s\u2019int\u00e9resse \u00e0 l\u2019indice 12, on voit les valeurs 2 et 4 qui sont diff\u00e9rentes : l\u2019intrus est donc \u00e0 gauche de l\u2019indice 12 (indice 12 compris)
En revanche, si on s\u2019int\u00e9resse \u00e0 l\u2019indice 3, on voit les valeurs 9 et 9 qui sont identiques : l\u2019intrus est donc \u00e0 droite des indices 3-4-5, donc \u00e0 partir de l\u2019indice 6.
Compl\u00e9ter la fonction r\u00e9cursive trouver_intrus
propos\u00e9e page suivante qui met en \u0153uvre cet algorithme.
def trouver_intrus(tab, g, d):\n'''\n Renvoie la valeur de l'intrus situ\u00e9 entre les indices g et d \n dans la liste tab o\u00f9 :\n tab v\u00e9rifie les conditions de l'exercice,\n g et d sont des multiples de 3.\n '''\n if g == d:\n return ...\n\n else:\n nombre_de_triplets = (d - g) // ...\n indice = g + 3 * (nombre_de_triplets // 2)\n if ... :\n return ...\n else:\n return ...\n
Exemples :
>>> trouver_intrus([3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8,\n8, 5, 5, 5], 0, 21)\n7\n\n>>> trouver_intrus([8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3], 0, 12)\n8\n\n>>> trouver_intrus([5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8, 8, 8], 0, 15)\n3\n
def trouver_intrus(tab, g, d):\n'''\n Renvoie la valeur de l'intrus situ\u00e9 entre les indices g et d \n dans la liste tab o\u00f9 :\n tab v\u00e9rifie les conditions de l'exercice,\n g et d sont des multiples de 3.\n '''\n if g == d:\nreturn tab[g]\nelse:\nnombre_de_triplets = (d - g) // 3\nindice = g + 3 * (nombre_de_triplets // 2)\nif tab[indice] != tab[indice + 1] :\nreturn trouver_intrus(tab, g, indice)\nelse:\nreturn trouver_intrus(tab, indice + 3, d)\n
On consid\u00e8re des tableaux de nombres dont tous les \u00e9l\u00e9ments sont pr\u00e9sents exactement\ntrois fois \u00e0 la suite, sauf un \u00e9l\u00e9ment qui est pr\u00e9sent une unique fois et que l'on appelle \u00ab\nl'intrus \u00bb. Voici quelques exemples :\n\n```python\ntab_a = [3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5, 5, 5]\n#l'intrus est 7\n\ntab_b = [8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3]\n#l'intrus est 8\n\ntab_c = [5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8, 8, 8]\n#l'intrus est 3\n
On remarque qu'avec de tels tableaux : Ce que l'on peut observer ci-dessous en observant les valeurs des paires de voisins marqu\u00e9es par des caract\u00e8res ^ :
[3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8, 8, 5, 5, 5]\n ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^\n 0 3 6 9 12 15 18 21\n
Dans des listes comme celles ci-dessus, un algorithme r\u00e9cursif pour trouver l'intrus consiste alors \u00e0 choisir un indice i
multiple de 3 situ\u00e9 approximativement au milieu des indices parmi lesquels se trouve l'intrus.
Puis, en fonction des valeurs de l'\u00e9l\u00e9ment d'indice i
et de son voisin de droite, \u00e0 appliquer r\u00e9cursivement l'algorithme \u00e0 la moiti\u00e9 droite ou \u00e0 la moiti\u00e9 gauche des indices parmi lesquels se trouve l'intrus.
Par exemple, si on s\u2019int\u00e9resse \u00e0 l\u2019indice 12, on voit les valeurs 2 et 4 qui sont diff\u00e9rentes : l\u2019intrus est donc \u00e0 gauche de l\u2019indice 12 (indice 12 compris)
En revanche, si on s\u2019int\u00e9resse \u00e0 l\u2019indice 3, on voit les valeurs 9 et 9 qui sont identiques : l\u2019intrus est donc \u00e0 droite des indices 3-4-5, donc \u00e0 partir de l\u2019indice 6.
Compl\u00e9ter la fonction r\u00e9cursive trouver_intrus
propos\u00e9e page suivante qui met en \u0153uvre cet algorithme.
def trouver_intrus(tab, g, d):\n'''\n Renvoie la valeur de l'intrus situ\u00e9 entre les indices g et d \n dans la liste tab o\u00f9 :\n tab v\u00e9rifie les conditions de l'exercice,\n g et d sont des multiples de 3.\n '''\n if g == d:\n return ...\n\n else:\n nombre_de_triplets = (d - g) // ...\n indice = g + 3 * (nombre_de_triplets // 2)\n if ... :\n return ...\n else:\n return ...\n
Exemples :
>>> trouver_intrus([3, 3, 3, 9, 9, 9, 1, 1, 1, 7, 2, 2, 2, 4, 4, 4, 8, 8,\n8, 5, 5, 5], 0, 21)\n7\n\n>>> trouver_intrus([8, 5, 5, 5, 9, 9, 9, 18, 18, 18, 3, 3, 3], 0, 12)\n8\n\n>>> trouver_intrus([5, 5, 5, 1, 1, 1, 0, 0, 0, 6, 6, 6, 3, 8, 8, 8], 0, 15)\n3\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-24","title":"\u25b6 Sujet 24","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-241","title":"Exercice 24.1","text":"Exercice 24.1
\u00c9nonc\u00e9CorrectionSource MarkdownLe nombre d\u2019occurrences d\u2019un caract\u00e8re dans une cha\u00eene de caract\u00e8re est le nombre d\u2019apparitions de ce caract\u00e8re dans la cha\u00eene.
Exemples :
On cherche les occurrences des caract\u00e8res dans une phrase. On souhaite stocker ces occurrences dans un dictionnaire dont les clefs seraient les caract\u00e8res de la phrase et les valeurs l\u2019occurrence de ces caract\u00e8res.
Par exemple : avec la phrase 'Hello world !' le dictionnaire est le suivant :
{'H': 1,'e': 1,'l': 3,'o': 2,' ': 2,'w': 1,'r': 1,'d': 1,'!': 1}
L\u2019ordre des clefs n\u2019a pas d\u2019importance.
\u00c9crire une fonction nbr_occurrences
prenant comme param\u00e8tre une cha\u00eene de caract\u00e8res chaine
et renvoyant le dictionnaire des nombres d\u2019occurrences des caract\u00e8res de cette cha\u00eene.
def nbr_occurrences(chaine):\n nb_occ = {}\n for caractere in chaine:\n if caractere in nb_occ:\n nb_occ[caractere] += 1\n else:\n nb_occ[caractere] = 1\n return nb_occ\n
Le nombre d\u2019occurrences d\u2019un caract\u00e8re dans une cha\u00eene de caract\u00e8re est le nombre\nd\u2019apparitions de ce caract\u00e8re dans la cha\u00eene.\n\nExemples :\n\n- le nombre d\u2019occurrences du caract\u00e8re \u2018o\u2019 dans \u2018bonjour\u2019 est 2 ;\n- le nombre d\u2019occurrences du caract\u00e8re \u2018b\u2019 dans \u2018B\u00e9b\u00e9\u2019 est 1 ;\n- le nombre d\u2019occurrences du caract\u00e8re \u2018B\u2019 dans \u2018B\u00e9b\u00e9\u2019 est 1 ;\n- le nombre d\u2019occurrences du caract\u00e8re \u2018 \u2018 dans \u2018Hello world !\u2019 est 2.\n\nOn cherche les occurrences des caract\u00e8res dans une phrase. On souhaite stocker ces\noccurrences dans un dictionnaire dont les clefs seraient les caract\u00e8res de la phrase et\nles valeurs l\u2019occurrence de ces caract\u00e8res.\n\nPar exemple : avec la phrase 'Hello world !' le dictionnaire est le suivant :\n\n`{'H': 1,'e': 1,'l': 3,'o': 2,' ': 2,'w': 1,'r': 1,'d': 1,'!': 1}`\n\n*L\u2019ordre des clefs n\u2019a pas d\u2019importance.*\n\n\u00c9crire une fonction `nbr_occurrences` prenant comme param\u00e8tre une cha\u00eene de\ncaract\u00e8res `chaine` et renvoyant le dictionnaire des nombres d\u2019occurrences des\ncaract\u00e8res de cette cha\u00eene.\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-242","title":"Exercice 24.2","text":"Exercice 24.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa fonction fusion
prend deux listes lst1
, lst2
d\u2019entiers tri\u00e9es par ordre croissant et les fusionne en une liste tri\u00e9e lst12
qu\u2019elle renvoie.
Le code Python de la fonction fusion
est
def fusion(lst1,lst2):\n n1 = len(lst1)\n n2 = len(lst2)\n lst12 = [0] * (n1 + n2)\n i1 = 0\n i2 = 0\n i = 0\n while i1 < n1 and ... :\n if lst1[i1] < lst2[i2]:\n lst12[i] = ...\n i1 = ...\n else:\n lst12[i] = lst2[i2]\n i2 = ...\n i += 1\n while i1 < n1:\n lst12[i] = ...\n i1 = i1 + 1\n i = ...\n while i2 < n2:\n lst12[i] = ...\n i2 = i2 + 1\n i = ...\n return lst12\n
Compl\u00e9ter le code.
Exemple :
>>> fusion([1, 6, 10],[0, 7, 8, 9])\n[0, 1, 6, 7, 8, 9, 10]\n
def fusion(lst1, lst2):\n n1 = len(lst1)\n n2 = len(lst2)\n lst12 = [0] * (n1 + n2)\n i1 = 0\n i2 = 0\n i = 0\nwhile i1 < n1 and i2 < n2 :\nif lst1[i1] < lst2[i2]:\nlst12[i] = lst1[i1]\ni1 = i1 + 1\nelse:\n lst12[i] = lst2[i2]\ni2 = i2 + 1\ni += 1\n while i1 < n1:\nlst12[i] = lst1[i1]\ni1 = i1 + 1\ni = i + 1\nwhile i2 < n2:\nlst12[i] = lst2[i2]\ni2 = i2 + 1\ni = i + 1\nreturn lst12\n
La fonction `fusion` prend deux listes `lst1`, `lst2` d\u2019entiers tri\u00e9es par ordre croissant et les\nfusionne en une liste tri\u00e9e `lst12` qu\u2019elle renvoie.\n\nLe code Python de la fonction `fusion` est\n\n```python linenums='1'\ndef fusion(lst1,lst2):\n n1 = len(lst1)\n n2 = len(lst2)\n lst12 = [0] * (n1 + n2)\n i1 = 0\n i2 = 0\n i = 0\n while i1 < n1 and ... :\n if lst1[i1] < lst2[i2]:\n lst12[i] = ...\n i1 = ...\n else:\n lst12[i] = lst2[i2]\n i2 = ...\n i += 1\n while i1 < n1:\n lst12[i] = ...\n i1 = i1 + 1\n i = ...\n while i2 < n2:\n lst12[i] = ...\n i2 = i2 + 1\n i = ...\n return lst12\n
Compl\u00e9ter le code.
Exemple :
>>> fusion([1, 6, 10],[0, 7, 8, 9])\n[0, 1, 6, 7, 8, 9, 10]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-25","title":"\u25b6 Sujet 25","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-251","title":"Exercice 25.1","text":"Exercice 25.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction enumere
qui prend en param\u00e8tre une liste L
et renvoie un dictionnaire d
dont les cl\u00e9s sont les \u00e9l\u00e9ments de L
avec pour valeur associ\u00e9e la liste des indices de l\u2019\u00e9l\u00e9ment dans la liste L
.
Exemple :
>>> enumere([1, 1, 2, 3, 2, 1])\n{1: [0, 1, 5], 2: [2, 4], 3: [3]}\n
def enumere(L):\n d = {}\n for i in range(len(L)):\n if L[i] in d:\n d[L[i]].append(i)\n else:\n d[L[i]] = [i]\n return d\n
\u00c9crire une fonction `enumere` qui prend en param\u00e8tre une liste `L` et renvoie un\ndictionnaire `d` dont les cl\u00e9s sont les \u00e9l\u00e9ments de `L` avec pour valeur associ\u00e9e la liste des\nindices de l\u2019\u00e9l\u00e9ment dans la liste `L`.\n\nExemple :\n\n```python\n>>> enumere([1, 1, 2, 3, 2, 1])\n{1: [0, 1, 5], 2: [2, 4], 3: [3]}\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-252","title":"Exercice 25.2","text":"Exercice 25.2
\u00c9nonc\u00e9CorrectionSources MarkdownUn arbre binaire est impl\u00e9ment\u00e9 par la classe Arbre
donn\u00e9e ci-dessous. Les attributs fg
et fd
prennent pour valeurs des instances de la classe Arbre
ou None
.
class Arbre:\n def __init__(self, etiquette):\n self.v = etiquette\n self.fg = None\n self.fd = None\n\ndef parcours(arbre, liste):\n if arbre != None:\n parcours(arbre.fg, liste)\n liste.append(arbre.v)\n parcours(arbre.fd, liste)\n return liste\n
La fonction r\u00e9cursive parcours
renvoie la liste des \u00e9tiquettes des n\u0153uds de l\u2019arbre impl\u00e9ment\u00e9 par l\u2019instance arbre
dans l\u2019ordre du parcours en profondeur infixe \u00e0 partir d\u2019une liste vide pass\u00e9e en argument.
Compl\u00e9ter le code de la fonction insere
qui ins\u00e8re un n\u0153ud d\u2019\u00e9tiquette cle
en feuille de l\u2019arbre impl\u00e9ment\u00e9 par l\u2019instance arbre
selon la sp\u00e9cification indiqu\u00e9e et de fa\u00e7on que l\u2019arbre ainsi compl\u00e9t\u00e9 soit encore un arbre binaire de recherche.
Tester ensuite ce code en utilisant la fonction parcours
et en ins\u00e9rant successivement des n\u0153uds d\u2019\u00e9tiquette 1, 4, 6 et 8 dans l\u2019arbre binaire de recherche repr\u00e9sent\u00e9 ci- dessous :
def insere(arbre, cle):\n\"\"\" arbre est une instance de la classe Arbre qui impl\u00e9mente\n un arbre binaire de recherche.\n \"\"\"\n if ...:\n if ...:\n insere(arbre.fg, cle)\n else:\n arbre.fg = Arbre(cle)\n else:\n if ...:\n insere(arbre.fd, cle)\n else:\n arbre.fd = Arbre(cle)\n
def insere(arbre, cle):\n\"\"\" arbre est une instance de la classe Arbre qui impl\u00e9mente\n un arbre binaire de recherche.\n\"\"\"\nif cle < arbre.v:\nif arbre.fg is not None:\ninsere(arbre.fg, cle)\n else:\n arbre.fg = Arbre(cle)\n else:\nif arbre.fd is not None:\ninsere(arbre.fd, cle)\n else:\n arbre.fd = Arbre(cle)\n
Tests :
>>> a = Arbre(5)\n>>> insere(a, 2)\n>>> insere(a, 7)\n>>> insere(a, 3)\n>>> parcours(a, [])\n[2, 3, 5, 7]\n>>> insere(a, 1)\n>>> insere(a, 4)\n>>> insere(a, 6)\n>>> insere(a, 8)\n>>> parcours(a, [])\n[1, 2, 3, 4, 5, 6, 7, 8]\n
Un arbre binaire est impl\u00e9ment\u00e9 par la classe `Arbre` donn\u00e9e ci-dessous. \nLes attributs `fg` et `fd` prennent pour valeurs des instances de la classe `Arbre` ou `None`.\n\n```python linenums='1'\nclass Arbre:\n def __init__(self, etiquette):\n self.v = etiquette\n self.fg = None\n self.fd = None\n\ndef parcours(arbre, liste):\n if arbre != None:\n parcours(arbre.fg, liste)\n liste.append(arbre.v)\n parcours(arbre.fd, liste)\n return liste\n
La fonction r\u00e9cursive parcours
renvoie la liste des \u00e9tiquettes des n\u0153uds de l\u2019arbre impl\u00e9ment\u00e9 par l\u2019instance arbre
dans l\u2019ordre du parcours en profondeur infixe \u00e0 partir d\u2019une liste vide pass\u00e9e en argument.
Compl\u00e9ter le code de la fonction insere
qui ins\u00e8re un n\u0153ud d\u2019\u00e9tiquette cle
en feuille de l\u2019arbre impl\u00e9ment\u00e9 par l\u2019instance arbre
selon la sp\u00e9cification indiqu\u00e9e et de fa\u00e7on que l\u2019arbre ainsi compl\u00e9t\u00e9 soit encore un arbre binaire de recherche.
Tester ensuite ce code en utilisant la fonction parcours
et en ins\u00e9rant successivement des n\u0153uds d\u2019\u00e9tiquette 1, 4, 6 et 8 dans l\u2019arbre binaire de recherche repr\u00e9sent\u00e9 ci- dessous :
def insere(arbre, cle):\n\"\"\" arbre est une instance de la classe Arbre qui impl\u00e9mente\n un arbre binaire de recherche.\n \"\"\"\n if ...:\n if ...:\n insere(arbre.fg, cle)\n else:\n arbre.fg = Arbre(cle)\n else:\n if ...:\n insere(arbre.fd, cle)\n else:\n arbre.fd = Arbre(cle)\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-26","title":"\u25b6 Sujet 26","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-261","title":"Exercice 26.1","text":"Exercice 26.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction multiplication
, prenant en param\u00e8tres deux nombres entiers n1
et n2
, et qui renvoie le produit de ces deux nombres.
Les seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.
>>> multiplication(3, 5)\n15\n>>> multiplication(-4, -8)\n32\n>>> multiplication(-2, 6)\n-12\n>>> multiplication(-2, 0)\n0\n
def multiplication(n1, n2):\n # on se ram\u00e8ne d'abord au cas o\u00f9 n1 et n2 sont tous les deux positifs :\n if n1 < 0:\n return -multiplication(-n1, n2)\n if n2 < 0:\n return -multiplication(n1, -n2)\n\n resultat = 0\n for _ in range(n2):\n resultat += n1\n return resultat\n
Programmer la fonction `multiplication`, prenant en param\u00e8tres deux nombres entiers\n`n1` et `n2`, et qui renvoie le produit de ces deux nombres.\n\nLes seules op\u00e9rations autoris\u00e9es sont l\u2019addition et la soustraction.\n\n```python\n>>> multiplication(3, 5)\n15\n>>> multiplication(-4, -8)\n32\n>>> multiplication(-2, 6)\n-12\n>>> multiplication(-2, 0)\n0\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-262","title":"Exercice 26.2","text":"Exercice 26.2
\u00c9nonc\u00e9CorrectionSources MarkdownRecopier et compl\u00e9ter sous Python la fonction suivante en respectant la sp\u00e9cification. On ne recopiera pas les commentaires.
def dichotomie(tab, x):\n\"\"\"\n tab : tableau d\u2019entiers tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\nFalse\n
def dichotomie(tab, x):\n\"\"\"\n tab : tableau d\u2019entiers tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\nm = (debut + fin) // 2\nif x == tab[m]:\nreturn True\nif x > tab[m]:\n debut = m + 1\n else:\nfin = m - 1\nreturn False\n
Recopier et compl\u00e9ter sous Python la fonction suivante en respectant la sp\u00e9cification. On\nne recopiera pas les commentaires.\n\n```python linenums='1'\ndef dichotomie(tab, x):\n \"\"\"\n tab : tableau d\u2019entiers tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\nFalse\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-27","title":"\u25b6 Sujet 27","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-271","title":"Exercice 27.1","text":"Exercice 27.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche_min
qui prend en param\u00e8tre un tableau de nombres non tri\u00e9 tab
, et qui renvoie l'indice de la premi\u00e8re occurrence du minimum de ce tableau. Les tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.
Exemples :
>>> recherche_min([5])\n0\n>>> recherche_min([2, 4, 1])\n2\n>>> recherche_min([5, 3, 2, 2, 4])\n2\n
def recherche_min(tab):\n indice_min = 0\n for i in range(len(tab)):\n if tab[i] < tab[indice_min]:\n indice_min = i\n return indice_min\n
\u00c9crire une fonction `recherche_min` qui prend en param\u00e8tre un tableau de nombres non\ntri\u00e9 `tab`, et qui renvoie l'indice de la premi\u00e8re occurrence du minimum de ce tableau. Les\ntableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.\n\nExemples :\n```python\n>>> recherche_min([5])\n0\n>>> recherche_min([2, 4, 1])\n2\n>>> recherche_min([5, 3, 2, 2, 4])\n2\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-272","title":"Exercice 27.2","text":"Exercice 27.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re la fonction separe
ci-dessous qui prend en argument un tableau tab
dont les \u00e9l\u00e9ments sont des 0
et des 1
et qui s\u00e9pare les 0
des 1
en pla\u00e7ant les 0
en d\u00e9but de tableau et les 1
\u00e0 la suite.
def separe(tab):\n gauche = 0\n droite = ...\n while gauche < droite :\n if tab[gauche] == 0 :\n gauche = ...\n else :\n tab[gauche], tab[droite] = ...\n droite = ...\n return tab\n
Compl\u00e9ter la fonction separe
ci-dessus.
Exemples :
>>> separe([1, 0, 1, 0, 1, 0, 1, 0])\n[0, 0, 0, 0, 1, 1, 1, 1]\n>>> separe([1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0])\n[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\n
Description d\u2019\u00e9tapes effectu\u00e9es par la fonction separe sur le tableau ci-dessous : tab = [1, 0, 1, 0, 1, 0, 1, 0]
Etape 1 : on regarde la premi\u00e8re case, qui contient un 1 : ce 1 va aller dans la seconde partie du tableau final et on l\u2019\u00e9change avec la derni\u00e8re case. Il est \u00e0 pr\u00e9sent bien positionn\u00e9 : on ne prend plus la derni\u00e8re case en compte. tab = [0, 0, 1, 0, 1, 0, 1, 1]
Etape 2 : on regarde \u00e0 nouveau la premi\u00e8re case, qui contient maintenant un 0 : ce 0 va aller dans la premi\u00e8re partie du tableau final et est bien positionn\u00e9 : on ne prend plus la premi\u00e8re case en compte. tab = [0, 0, 1, 0, 1, 0, 1, 1]
Etape 3 : on regarde la seconde case, qui contient un 0 : ce 0 va aller dans la premi\u00e8re partie du tableau final et est bien positionn\u00e9 : on ne prend plus la seconde case en compte. tab = [0, 0, 1, 0, 1, 0, 1, 1]
Etape 4 : on regarde la troisi\u00e8me case, qui contient un 1 : ce 1 va aller dans la seconde partie du tableau final et on l\u2019\u00e9change avec l\u2019avant-derni\u00e8re case. Il est \u00e0 pr\u00e9sent bien positionn\u00e9 : on ne prend plus l\u2019avant-derni\u00e8re case en compte. tab = [0, 0, 1, 0, 1, 0, 1, 1]
Et ainsi de suite...
tab = [0, 0, 0, 0, 1, 1, 1, 1]
Compl\u00e9ter la fonction separe
pr\u00e9sent\u00e9e \u00e0 la page pr\u00e9c\u00e9dente
def separe(tab):\n gauche = 0\ndroite = len(tab) - 1\nwhile gauche < droite :\n if tab[gauche] == 0 :\ngauche = gauche + 1\nelse :\ntab[gauche], tab[droite] = tab[droite], tab[gauche]\ndroite = droite - 1\nreturn tab\n
On consid\u00e8re la fonction `separe` ci-dessous qui prend en argument un tableau `tab` dont\nles \u00e9l\u00e9ments sont des `0` et des `1` et qui s\u00e9pare les `0` des `1` en pla\u00e7ant les `0` en d\u00e9but de\ntableau et les `1` \u00e0 la suite.\n\n```python linenums='1'\ndef separe(tab):\n gauche = 0\n droite = ...\n while gauche < droite :\n if tab[gauche] == 0 :\n gauche = ...\n else :\n tab[gauche], tab[droite] = ...\n droite = ...\n return tab\n
Compl\u00e9ter la fonction separe
ci-dessus.
Exemples :
>>> separe([1, 0, 1, 0, 1, 0, 1, 0])\n[0, 0, 0, 0, 1, 1, 1, 1]\n>>> separe([1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0])\n[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]\n
Description d\u2019\u00e9tapes effectu\u00e9es par la fonction separe sur le tableau ci-dessous : tab = [1, 0, 1, 0, 1, 0, 1, 0]
Etape 1 : on regarde la premi\u00e8re case, qui contient un 1 : ce 1 va aller dans la seconde partie du tableau final et on l\u2019\u00e9change avec la derni\u00e8re case. Il est \u00e0 pr\u00e9sent bien positionn\u00e9 : on ne prend plus la derni\u00e8re case en compte. tab = [0, 0, 1, 0, 1, 0, 1, 1]
Etape 2 : on regarde \u00e0 nouveau la premi\u00e8re case, qui contient maintenant un 0 : ce 0 va aller dans la premi\u00e8re partie du tableau final et est bien positionn\u00e9 : on ne prend plus la premi\u00e8re case en compte. tab = [0, 0, 1, 0, 1, 0, 1, 1]
Etape 3 : on regarde la seconde case, qui contient un 0 : ce 0 va aller dans la premi\u00e8re partie du tableau final et est bien positionn\u00e9 : on ne prend plus la seconde case en compte. tab = [0, 0, 1, 0, 1, 0, 1, 1]
Etape 4 : on regarde la troisi\u00e8me case, qui contient un 1 : ce 1 va aller dans la seconde partie du tableau final et on l\u2019\u00e9change avec l\u2019avant-derni\u00e8re case. Il est \u00e0 pr\u00e9sent bien positionn\u00e9 : on ne prend plus l\u2019avant-derni\u00e8re case en compte. tab = [0, 0, 1, 0, 1, 0, 1, 1]
Et ainsi de suite...
tab = [0, 0, 0, 0, 1, 1, 1, 1]
Compl\u00e9ter la fonction separe
pr\u00e9sent\u00e9e \u00e0 la page pr\u00e9c\u00e9dente ```
Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-28","title":"\u25b6 Sujet 28","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-281","title":"Exercice 28.1","text":"Exercice 28.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction qui prend en param\u00e8tre un tableau d'entiers non vide et qui renvoie la moyenne de ces entiers. La fonction est sp\u00e9cifi\u00e9e ci-apr\u00e8s et doit passer les assertions fournies.
def moyenne (tab):\n'''\n moyenne(list) -> float\n Entr\u00e9e : un tableau non vide d'entiers\n Sortie : nombre de type float\n Correspondant \u00e0 la moyenne des valeurs pr\u00e9sentes dans le\n tableau\n '''\n\nassert moyenne([1]) == 1\nassert moyenne([1, 2, 3, 4, 5, 6, 7]) == 4\nassert moyenne([1, 2]) == 1.5\n
def moyenne(tab):\n'''\n moyenne(list) -> float\n Entr\u00e9e : un tableau non vide d'entiers\n Sortie : nombre de type float\n Correspondant \u00e0 la moyenne des valeurs pr\u00e9sentes dans le\n tableau\n '''\n somme = 0\n for elt in tab:\n somme += elt\n return somme / len(tab)\n
\u00c9crire une fonction qui prend en param\u00e8tre un tableau d'entiers non vide et qui renvoie la\nmoyenne de ces entiers. La fonction est sp\u00e9cifi\u00e9e ci-apr\u00e8s et doit passer les assertions\nfournies.\n```python\ndef moyenne (tab):\n '''\n moyenne(list) -> float\n Entr\u00e9e : un tableau non vide d'entiers\n Sortie : nombre de type float\n Correspondant \u00e0 la moyenne des valeurs pr\u00e9sentes dans le\n tableau\n '''\n\nassert moyenne([1]) == 1\nassert moyenne([1, 2, 3, 4, 5, 6, 7]) == 4\nassert moyenne([1, 2]) == 1.5\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-282","title":"Exercice 28.2","text":"Exercice 28.2
\u00c9nonc\u00e9CorrectionSources MarkdownLe but de l'exercice est de compl\u00e9ter une fonction qui d\u00e9termine si une valeur est pr\u00e9sente dans un tableau de valeurs tri\u00e9es dans l'ordre croissant.
L'algorithme traite le cas du tableau vide et il est \u00e9crit pour que la recherche dichotomique ne se fasse que dans le cas o\u00f9 la valeur est comprise entre les valeurs extr\u00eames du tableau.
On distingue les trois cas qui renvoient False
en renvoyant False, 1
, False, 2
et False, 3
.
Compl\u00e9ter l'algorithme de dichotomie donn\u00e9 ci-apr\u00e8s.
def dichotomie(tab, x):\n\"\"\"\n tab : tableau tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n # cas du tableau vide\n if ...:\n return False, 1\n\n # cas o\u00f9 x n'est pas compris entre les valeurs extr\u00eames\n if (x < tab[0]) or ...:\n return False, 2\n\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\n(False, 3)\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],1)\n(False, 2)\n>>> dichotomie([],28)\n(False, 1)\n
def dichotomie(tab, x):\n\"\"\"\n tab : tableau tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n # cas du tableau vide\nif tab == []:\nreturn False, 1\n\n # cas o\u00f9 x n'est pas compris entre les valeurs extr\u00eames\nif (x < tab[0]) or (x > tab[-1]):\nreturn False, 2\n\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\nm = (debut + fin) // 2\nif x == tab[m]:\nreturn True\nif x > tab[m]:\n debut = m + 1\n else:\nfin = m - 1\nreturn False, 3\n
Le but de l'exercice est de compl\u00e9ter une fonction qui d\u00e9termine si une valeur est pr\u00e9sente\ndans un tableau de valeurs tri\u00e9es dans l'ordre croissant.\n\nL'algorithme traite le cas du tableau vide et il est \u00e9crit pour que la recherche dichotomique ne se fasse que dans le cas o\u00f9\nla valeur est comprise entre les valeurs extr\u00eames du tableau.\n\nOn distingue les trois cas qui renvoient `False` en renvoyant `False, 1` , `False, 2` et\n`False, 3`.\n\nCompl\u00e9ter l'algorithme de dichotomie donn\u00e9 ci-apr\u00e8s.\n\n```python linenums='1'\ndef dichotomie(tab, x):\n \"\"\"\n tab : tableau tri\u00e9 dans l\u2019ordre croissant\n x : nombre entier\n La fonction renvoie True si tab contient x et False sinon\n \"\"\"\n # cas du tableau vide\n if ...:\n return False, 1\n\n # cas o\u00f9 x n'est pas compris entre les valeurs extr\u00eames\n if (x < tab[0]) or ...:\n return False, 2\n\n debut = 0\n fin = len(tab) - 1\n while debut <= fin:\n m = ...\n if x == tab[m]:\n return ...\n if x > tab[m]:\n debut = m + 1\n else:\n fin = ...\n return ...\n
Exemples :
>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],28)\nTrue\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],27)\n(False, 3)\n>>> dichotomie([15, 16, 18, 19, 23, 24, 28, 29, 31, 33],1)\n(False, 2)\n>>> dichotomie([],28)\n(False, 1)\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-29","title":"\u25b6 Sujet 29","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-291","title":"Exercice 29.1","text":"Exercice 29.1
\u00c9nonc\u00e9CorrectionSource MarkdownUn arbre binaire est impl\u00e9ment\u00e9 par la classe Arbre
donn\u00e9e ci-dessous. Les attributs fg
et fd
prennent pour valeurs des instances de la classe Arbre
ou None
.
class Arbre:\n def __init__(self, etiquette):\n self.v = etiquette\n self.fg = None\n self.fd = None\n
L\u2019arbre ci-dessus sera donc impl\u00e9ment\u00e9 de la mani\u00e8re suivante :
a = Arbre(1)\na.fg = Arbre(4)\na.fd = Arbre(0)\na.fd.fd = Arbre(7)\n
\u00c9crire une fonction r\u00e9cursive taille
prenant en param\u00e8tre une instance a
de la classe Arbre
et qui renvoie la taille de l\u2019arbre que cette instance impl\u00e9mente.
\u00c9crire de m\u00eame une fonction r\u00e9cursive hauteur
prenant en param\u00e8tre une instance a
de la classe Arbre
et qui renvoie la hauteur de l\u2019arbre que cette instance impl\u00e9mente.
Si un arbre a un seul n\u0153ud, sa taille et sa hauteur sont \u00e9gales \u00e0 1. S\u2019il est vide, sa taille et sa hauteur sont \u00e9gales \u00e0 0.
Tester les deux fonctions sur l\u2019arbre repr\u00e9sent\u00e9 ci-dessous :
def taille(a):\n if a is None:\n return 0\n else:\n return 1 + taille(a.fg) + taille(a.fd)\n\ndef hauteur(a):\n if a is None:\n return 0\n else:\n return 1 + max(hauteur(a.fg), hauteur(a.fd))\n
Tests :
a = Arbre(0)\na.fg = Arbre(1)\na.fd = Arbre(2)\na.fg.fg = Arbre(3)\na.fd.fg = Arbre(4)\na.fd.fd = Arbre(5)\na.fd.fg.fd = Arbre(6)\n
>>> taille(a)\n7\n>>> hauteur(a)\n4\n
Un arbre binaire est impl\u00e9ment\u00e9 par la classe `Arbre` donn\u00e9e ci-dessous.\nLes attributs `fg` et `fd` prennent pour valeurs des instances de la classe `Arbre` ou `None`.\n\n```python\nclass Arbre:\n def __init__(self, etiquette):\n self.v = etiquette\n self.fg = None\n self.fd = None\n```\n\n![image](data2023/29_arbre1.png){: .center}\n\nL\u2019arbre ci-dessus sera donc impl\u00e9ment\u00e9 de la mani\u00e8re suivante :\n```python\na = Arbre(1)\na.fg = Arbre(4)\na.fd = Arbre(0)\na.fd.fd = Arbre(7)\n```\n\n\u00c9crire une fonction r\u00e9cursive `taille` prenant en param\u00e8tre une instance `a` de la classe\n`Arbre` et qui renvoie la taille de l\u2019arbre que cette instance impl\u00e9mente.\n\n\u00c9crire de m\u00eame une fonction r\u00e9cursive `hauteur` prenant en param\u00e8tre une instance `a`\nde la classe `Arbre` et qui renvoie la hauteur de l\u2019arbre que cette instance impl\u00e9mente.\n\nSi un arbre a un seul n\u0153ud, sa taille et sa hauteur sont \u00e9gales \u00e0 1.\nS\u2019il est vide, sa taille et sa hauteur sont \u00e9gales \u00e0 0.\n\nTester les deux fonctions sur l\u2019arbre repr\u00e9sent\u00e9 ci-dessous :\n\n![image](data2023/29_arbre2.png){: .center}\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-292","title":"Exercice 29.2","text":"Exercice 29.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa m\u00e9thode insert
de la classe list
permet d\u2019ins\u00e9rer un \u00e9l\u00e9ment dans une liste \u00e0 un indice
donn\u00e9.
Le but de cet exercice est, sans utiliser cette m\u00e9thode, d\u2019\u00e9crire une fonction ajoute
r\u00e9alisant cette insertion en produisant une nouvelle liste.
Cette fonction ajoute
prend en param\u00e8tres trois variables indice
, element
et liste
et renvoie une liste L
dans laquelle les \u00e9l\u00e9ments sont ceux de la liste liste
avec, en plus, l\u2019\u00e9l\u00e9ment element
\u00e0 l\u2019indice indice
. On consid\u00e8re que les variables indice
et element
sont des entiers positifs et que les \u00e9l\u00e9ments de liste
sont \u00e9galement des entiers positifs. Les \u00e9l\u00e9ments de la liste liste
, dont les indices sont sup\u00e9rieurs ou \u00e9gaux \u00e0 indice
apparaissent d\u00e9cal\u00e9s vers la droite dans la liste L
. Si indice
est sup\u00e9rieur ou \u00e9gal au nombre d\u2019\u00e9l\u00e9ments de la liste liste
, l\u2019\u00e9l\u00e9ment element est ajout\u00e9 dans L
apr\u00e8s tous les \u00e9l\u00e9ments de la liste liste
.
Exemple :
>>> ajoute(1, 4, [7, 8, 9])\n[7, 4, 8, 9]\n>>> ajoute(3, 4, [7, 8, 9])\n[7, 8, 9, 4]\n>>> ajoute(4, 4, [7, 8, 9])\n[7, 8, 9, 4]\n
Compl\u00e9ter et tester le code ci-dessous :
def ajoute(indice, element, liste):\n nbre_elts = len(liste)\n L = [0 for i in range(nbre_elts + 1)]\n if ...:\n for i in range(indice):\n L[i] = ...\n L[...] = ...\n for i in range(indice + 1, nbre_elts + 1):\n L[i] = ...\n else:\n for i in range(nbre_elts):\n L[i] = ...\n L[...] = ...\n return L\n
def ajoute(indice, element, liste):\n nbre_elts = len(liste)\n L = [0 for i in range(nbre_elts + 1)]\nif indice < nbre_elts:\nfor i in range(indice):\nL[i] = liste[i]\nL[indice] = element\nfor i in range(indice + 1, nbre_elts + 1):\nL[i] = liste[i-1]\nelse:\n for i in range(nbre_elts):\nL[i] = liste[i]\nL[nbre_elts] = element \nreturn L\n
La m\u00e9thode `insert` de la classe `list` permet d\u2019ins\u00e9rer un \u00e9l\u00e9ment dans une liste \u00e0 un\n`indice` donn\u00e9.\n\nLe but de cet exercice est, *sans utiliser cette m\u00e9thode*, d\u2019\u00e9crire une fonction `ajoute`\nr\u00e9alisant cette insertion en produisant une nouvelle liste.\n\nCette fonction `ajoute` prend en param\u00e8tres trois variables `indice`, `element` et `liste`\net renvoie une liste `L` dans laquelle les \u00e9l\u00e9ments sont ceux de la liste `liste` avec, en\nplus, l\u2019\u00e9l\u00e9ment `element` \u00e0 l\u2019indice `indice`. \nOn consid\u00e8re que les variables `indice` et `element` sont des entiers positifs et que les\n\u00e9l\u00e9ments de `liste` sont \u00e9galement des entiers positifs. \nLes \u00e9l\u00e9ments de la liste `liste`, dont les indices sont sup\u00e9rieurs ou \u00e9gaux \u00e0 `indice`\napparaissent d\u00e9cal\u00e9s vers la droite dans la liste `L`. \nSi `indice` est sup\u00e9rieur ou \u00e9gal au nombre d\u2019\u00e9l\u00e9ments de la liste `liste`, l\u2019\u00e9l\u00e9ment\nelement est ajout\u00e9 dans `L` apr\u00e8s tous les \u00e9l\u00e9ments de la liste `liste`.\n\nExemple :\n```python\n>>> ajoute(1, 4, [7, 8, 9])\n[7, 4, 8, 9]\n>>> ajoute(3, 4, [7, 8, 9])\n[7, 8, 9, 4]\n>>> ajoute(4, 4, [7, 8, 9])\n[7, 8, 9, 4]\n
Compl\u00e9ter et tester le code ci-dessous :
def ajoute(indice, element, liste):\n nbre_elts = len(liste)\n L = [0 for i in range(nbre_elts + 1)]\n if ...:\n for i in range(indice):\n L[i] = ...\n L[...] = ...\n for i in range(indice + 1, nbre_elts + 1):\n L[i] = ...\n else:\n for i in range(nbre_elts):\n L[i] = ...\n L[...] = ...\n return L\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-30","title":"\u25b6 Sujet 30","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-301","title":"Exercice 30.1","text":"Exercice 30.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction moyenne
qui prend en param\u00e8tre un tableau non vide de nombres flottants et qui renvoie la moyenne des valeurs du tableau. Les tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.
Exemples :
>>> moyenne([1.0])\n1.0\n>>> moyenne([1.0, 2.0, 4.0])\n2.3333333333333335\n
def moyenne(tab):\n somme = 0\n for val in tab:\n somme += val\n return somme / len(tab)\n
\u00c9crire une fonction `moyenne` qui prend en param\u00e8tre un tableau non vide de nombres\nflottants et qui renvoie la moyenne des valeurs du tableau. Les tableaux seront\nrepr\u00e9sent\u00e9s sous forme de liste Python.\n\nExemples :\n```python\n>>> moyenne([1.0])\n1.0\n>>> moyenne([1.0, 2.0, 4.0])\n2.3333333333333335\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-302","title":"Exercice 30.2","text":"Exercice 30.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re la fonction binaire
ci-dessous qui prend en param\u00e8tre un entier positif a
en \u00e9criture d\u00e9cimale et qui renvoie son \u00e9criture binaire sous la forme d'une chaine de caract\u00e8res.
L\u2019algorithme utilise la m\u00e9thode des divisions euclidiennes successives comme l\u2019illustre l\u2019exemple ci-apr\u00e8s.
def binaire(a):\n bin_a = ...\n a = a // 2\n while a ... :\n bin_a = ... + bin_a\n a = ...\n return bin_a\n
Compl\u00e9ter le code de la fonction binaire
. Exemples :
>>> binaire(83)\n'1010011'\n>>> binaire(127)\n'1111111'\n>>> binaire(0)\n'0'\n
def binaire(a):\nbin_a = str(a%2)\na = a // 2\nwhile a != 0 :\nbin_a = str(a%2) + bin_a\na = a // 2\nreturn bin_a\n
On consid\u00e8re la fonction `binaire` ci-dessous qui prend en param\u00e8tre un entier positif `a` en \u00e9criture d\u00e9cimale et qui renvoie son \u00e9criture binaire sous la forme d'une chaine de caract\u00e8res.\n\nL\u2019algorithme utilise la m\u00e9thode des divisions euclidiennes successives comme l\u2019illustre\nl\u2019exemple ci-apr\u00e8s.\n\n![image](data2023/30_divisions.png){: .center}\n\n\n\n```python linenums='1'\ndef binaire(a):\n bin_a = ...\n a = a // 2\n while a ... :\n bin_a = ... + bin_a\n a = ...\n return bin_a\n
Compl\u00e9ter le code de la fonction binaire
. Exemples :
>>> binaire(83)\n'1010011'\n>>> binaire(127)\n'1111111'\n>>> binaire(0)\n'0'\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-31","title":"\u25b6 Sujet 31","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-311","title":"Exercice 31.1","text":"Exercice 31.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction Python appel\u00e9e nb_repetitions
qui prend en param\u00e8tres un \u00e9l\u00e9ment elt
et une liste tab
et renvoie le nombre de fois o\u00f9 l\u2019\u00e9l\u00e9ment appara\u00eet dans la liste.
Exemples :
>>> nb_repetitions(5, [2, 5, 3, 5, 6, 9, 5])\n3\n>>> nb_repetitions('A', ['B', 'A', 'B', 'A', 'R'])\n2\n>>> nb_repetitions(12, [1, '!', 7, 21, 36, 44])\n0\n
def nb_repetitions(elt, tab):\n nb = 0\n for element in tab:\n if element == elt:\n nb += 1\n return nb\n
\u00c9crire une fonction Python appel\u00e9e `nb_repetitions` qui prend en param\u00e8tres un\n\u00e9l\u00e9ment `elt` et une liste `tab` et renvoie le nombre de fois o\u00f9 l\u2019\u00e9l\u00e9ment appara\u00eet dans la\nliste.\n\nExemples :\n```python\n>>> nb_repetitions(5, [2, 5, 3, 5, 6, 9, 5])\n3\n>>> nb_repetitions('A', ['B', 'A', 'B', 'A', 'R'])\n2\n>>> nb_repetitions(12, [1, '!', 7, 21, 36, 44])\n0\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-312","title":"Exercice 31.2","text":"Exercice 31.2
\u00c9nonc\u00e9CorrectionSources MarkdownPour rappel, la conversion d\u2019un nombre entier positif en binaire peut s\u2019effectuer \u00e0 l\u2019aide des divisions successives comme illustr\u00e9 ici :
Voici une fonction Python bas\u00e9e sur la m\u00e9thode des divisions successives permettant de convertir un nombre entier positif en binaire :
def binaire(a):\n bin_a = str(...)\n a = a // 2\n while a ... :\n bin_a = ...(a%2) + ...\n a = ...\n return bin_a\n
Compl\u00e9ter la fonction binaire
. Exemples :
>>> binaire(0)\n'0'\n>>> binaire(77)\n'1001101'\n
def binaire(a):\nbin_a = str(a%2)\na = a // 2\nwhile a != 0 :\nbin_a = str(a%2) + bin_a\na = a // 2\nreturn bin_a\n
Pour rappel, la conversion d\u2019un nombre entier positif en binaire peut s\u2019effectuer \u00e0 l\u2019aide\ndes divisions successives comme illustr\u00e9 ici :\n\n![image](data2023/31_divisions.png){: .center}\n\nVoici une fonction Python bas\u00e9e sur la m\u00e9thode des divisions successives permettant de\nconvertir un nombre entier positif en binaire :\n\n```python linenums='1'\ndef binaire(a):\n bin_a = str(...)\n a = a // 2\n while a ... :\n bin_a = ...(a%2) + ...\n a = ...\n return bin_a\n
Compl\u00e9ter la fonction binaire
. Exemples :
>>> binaire(0)\n'0'\n>>> binaire(77)\n'1001101'\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-32","title":"\u25b6 Sujet 32","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-321","title":"Exercice 32.1","text":"Exercice 32.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction min_et_max
qui prend en param\u00e8tre un tableau de nombres tab
non vide, et qui renvoie la plus petite et la plus grande valeur du tableau sous la forme d\u2019un dictionnaire \u00e0 deux cl\u00e9s min
et max
.
Les tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.
L\u2019utilisation des fonctions natives min
, max
et sorted
, ainsi que la m\u00e9thode sort
n\u2019est pas autoris\u00e9e.
Exemples :
>>> min_et_max([0, 1, 4, 2, -2, 9, 3, 1, 7, 1])\n{'min': -2, 'max': 9}\n>>> min_et_max([0, 1, 2, 3])\n{'min': 0, 'max': 3}\n>>> min_et_max([3])\n{'min': 3, 'max': 3}\n>>> min_et_max([1, 3, 2, 1, 3])\n{'min': 1, 'max': 3}\n>>> min_et_max([-1, -1, -1, -1, -1])\n{'min': -1, 'max': -1}\n
def min_et_max(tab):\n d = {}\n d['min'] = tab[0]\n d['max'] = tab[0]\n for val in tab:\n if val < d['min']:\n d['min'] = val\n if val > d['max']:\n d['max'] = val\n return d\n
\u00c9crire une fonction `min_et_max` qui prend en param\u00e8tre un tableau de nombres `tab` non vide, et qui renvoie la plus petite et la plus grande valeur du tableau sous la\nforme d\u2019un dictionnaire \u00e0 deux cl\u00e9s `min` et `max`.\n\nLes tableaux seront repr\u00e9sent\u00e9s sous forme de liste Python.\n\nL\u2019utilisation des fonctions natives `min`, `max` et `sorted`, ainsi que la m\u00e9thode `sort` n\u2019est pas\nautoris\u00e9e.\n\nExemples :\n\n```python\n>>> min_et_max([0, 1, 4, 2, -2, 9, 3, 1, 7, 1])\n{'min': -2, 'max': 9}\n>>> min_et_max([0, 1, 2, 3])\n{'min': 0, 'max': 3}\n>>> min_et_max([3])\n{'min': 3, 'max': 3}\n>>> min_et_max([1, 3, 2, 1, 3])\n{'min': 1, 'max': 3}\n>>> min_et_max([-1, -1, -1, -1, -1])\n{'min': -1, 'max': -1}\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-322","title":"Exercice 32.2","text":"Exercice 32.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn dispose d\u2019une classe Carte
permettant de cr\u00e9er des objets mod\u00e9lisant des cartes \u00e0 jouer.
Compl\u00e9ter la classe Paquet_de_cartes
suivante en respectant les sp\u00e9cifications donn\u00e9es dans les cha\u00eenes de documentation.
Ajouter une assertion dans la m\u00e9thode get_carte
afin de v\u00e9rifier que le param\u00e8tre pos
est correct.
class Carte:\n def __init__(self, c, v):\n\"\"\" Initialise les attributs couleur (entre 1 et 4), et valeur (entre 1 et 13). \"\"\"\n self.couleur = c\n self.valeur = v\n\n def get_valeur(self):\n\"\"\" Renvoie la valeur de la carte : As, 2, ..., 10, Valet, Dame, Roi \"\"\"\n valeurs = ['As','2', '3', '4', '5', '6', '7', '8', '9', '10', 'Valet', 'Dame', 'Roi']\n return valeurs[self.valeur - 1]\n\n def get_couleur(self):\n\"\"\" Renvoie la couleur de la carte (parmi pique, coeur, carreau, tr\u00e8fle). \"\"\"\n couleurs = ['pique', 'coeur', 'carreau', 'tr\u00e8fle']\n return couleurs[self.couleur - 1]\n\nclass Paquet_de_cartes:\n def __init__(self):\n\"\"\" Initialise l'attribut contenu avec une liste des 52 objets Carte possibles\n rang\u00e9s par valeurs croissantes en commen\u00e7ant par pique, puis coeur,\n carreau et tr\u00e9fle. \"\"\"\n # A compl\u00e9ter\n\n def get_carte(self, pos):\n\"\"\" Renvoie la carte qui se trouve \u00e0 la position pos (entier compris entre 0 et 51). \"\"\"\n # A compl\u00e9ter\n
Exemple :
Exemple :\n>>> jeu = Paquet_de_cartes()\n>>> carte1 = jeu.get_carte(20)\n>>> print(carte1.get_valeur() + \" de \" + carte1.get_couleur())\n8 de coeur\n>>> carte2 = jeu.get_carte(0)\n>>> print(carte2.get_valeur() + \" de \" + carte2.get_couleur())\nAs de pique\n>>> carte3 = jeu.get_carte(52)\nAssertionError : param\u00e8tre pos invalide\n
class Carte:\n def __init__(self, c, v):\n\"\"\" Initialise les attributs couleur (entre 1 et 4), et valeur (entre 1 et 13). \"\"\"\n self.couleur = c\n self.valeur = v\n\n def get_valeur(self):\n\"\"\" Renvoie la valeur de la carte : As, 2, ..., 10, Valet, Dame, Roi \"\"\"\n valeurs = ['As','2', '3', '4', '5', '6', '7', '8', '9', '10', 'Valet', 'Dame', 'Roi']\n return valeurs[self.valeur - 1]\n\n def get_couleur(self):\n\"\"\" Renvoie la couleur de la carte (parmi pique, coeur, carreau, tr\u00e8fle). \"\"\"\n couleurs = ['pique', 'coeur', 'carreau', 'tr\u00e8fle']\n return couleurs[self.couleur - 1]\n\nclass Paquet_de_cartes:\n def __init__(self):\n\"\"\" Initialise l'attribut contenu avec une liste des 52 objets Carte possibles\n rang\u00e9s par valeurs croissantes en commen\u00e7ant par pique, puis coeur,\n carreau et tr\u00e9fle. \"\"\"\nself.contenu = [Carte(c, v) for c in range(1, 5) for v in range(1, 14)] \ndef get_carte(self, pos):\n\"\"\" Renvoie la carte qui se trouve \u00e0 la position pos (entier compris entre 0 et 51). \"\"\"\nassert 0 <= pos <= 51, 'param\u00e8tre pos invalide'\nreturn self.contenu[pos]\n
On dispose d\u2019une classe `Carte` permettant de cr\u00e9er des objets mod\u00e9lisant des cartes \u00e0\njouer.\n\nCompl\u00e9ter la classe `Paquet_de_cartes` suivante en respectant les sp\u00e9cifications\ndonn\u00e9es dans les cha\u00eenes de documentation.\n\nAjouter une assertion dans la m\u00e9thode `get_carte` afin de v\u00e9rifier que le param\u00e8tre `pos`\nest correct.\n\n```python linenums='1'\nclass Carte:\n def __init__(self, c, v):\n \"\"\" Initialise les attributs couleur (entre 1 et 4), et valeur (entre 1 et 13). \"\"\"\n self.couleur = c\n self.valeur = v\n\n def get_valeur(self):\n \"\"\" Renvoie la valeur de la carte : As, 2, ..., 10, Valet, Dame, Roi \"\"\"\n valeurs = ['As','2', '3', '4', '5', '6', '7', '8', '9', '10', 'Valet', 'Dame', 'Roi']\n return valeurs[self.valeur - 1]\n\n def get_couleur(self):\n \"\"\" Renvoie la couleur de la carte (parmi pique, coeur, carreau, tr\u00e8fle). \"\"\"\n couleurs = ['pique', 'coeur', 'carreau', 'tr\u00e8fle']\n return couleurs[self.couleur - 1]\n\nclass Paquet_de_cartes:\n def __init__(self):\n \"\"\" Initialise l'attribut contenu avec une liste des 52 objets Carte possibles\n rang\u00e9s par valeurs croissantes en commen\u00e7ant par pique, puis coeur,\n carreau et tr\u00e9fle. \"\"\"\n # A compl\u00e9ter\n\n def get_carte(self, pos):\n \"\"\" Renvoie la carte qui se trouve \u00e0 la position pos (entier compris entre 0 et 51). \"\"\"\n # A compl\u00e9ter\n
Exemple :
Exemple :\n>>> jeu = Paquet_de_cartes()\n>>> carte1 = jeu.get_carte(20)\n>>> print(carte1.get_valeur() + \" de \" + carte1.get_couleur())\n8 de coeur\n>>> carte2 = jeu.get_carte(0)\n>>> print(carte2.get_valeur() + \" de \" + carte2.get_couleur())\nAs de pique\n>>> carte3 = jeu.get_carte(52)\nAssertionError : param\u00e8tre pos invalide\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-33","title":"\u25b6 Sujet 33","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-331","title":"Exercice 33.1","text":"Exercice 33.1
\u00c9nonc\u00e9CorrectionSource MarkdownDans cet exercice, un arbre binaire de caract\u00e8res est stock\u00e9 sous la forme d\u2019un dictionnaire o\u00f9 les clefs sont les caract\u00e8res des n\u0153uds de l\u2019arbre et les valeurs, pour chaque clef, la liste des caract\u00e8res des fils gauche et droit du n\u0153ud.
Par exemple, l\u2019arbre
est stock\u00e9 dans
a = {'F':['B','G'], 'B':['A','D'], 'A':['',''], 'D':['C','E'], \\\n'C':['',''], 'E':['',''], 'G':['','I'], 'I':['','H'], \\\n'H':['','']}\n
\u00c9crire une fonction r\u00e9cursive taille
prenant en param\u00e8tres un arbre binaire arbre
sous la forme d\u2019un dictionnaire et un caract\u00e8re lettre
qui est la valeur du sommet de l\u2019arbre, et qui renvoie la taille de l\u2019arbre \u00e0 savoir le nombre total de n\u0153uds.
On observe que, par exemple, arbre[lettre][0]
, respectivement arbre[lettre][1]
, permet d\u2019atteindre la cl\u00e9 du sous-arbre gauche, respectivement droit, de l\u2019arbre arbre
de sommet lettre
.
Exemple :
>>> taille(a, \u2019F\u2019)\n9\n
a = {'F':['B','G'], 'B':['A','D'], 'A':['',''], 'D':['C','E'], 'C':['',''], 'E':['',''], 'G':['','I'], 'I':['','H'], 'H':['','']}\n\ndef taille(arbre, lettre):\n fils_gauche = arbre[lettre][0]\n fils_droit = arbre[lettre][1]\n\n if fils_gauche != '' and fils_droit != '':\n return 1 + taille(arbre, fils_gauche) + taille(arbre, fils_droit)\n\n if fils_gauche != '' and fils_droit == '':\n return 1 + taille(arbre, fils_gauche)\n\n if fils_gauche == '' and fils_droit != '':\n return 1 + taille(arbre, fils_droit)\n\n else:\n return 1\n
ou plus simplement :
def taille(arbre, lettre):\n if lettre == '':\n return 0\n return 1 + taille(arbre, arbre[lettre][0]) + taille(arbre, arbre[lettre][1])\n
Dans cet exercice, un arbre binaire de caract\u00e8res est stock\u00e9 sous la forme d\u2019un\ndictionnaire o\u00f9 les clefs sont les caract\u00e8res des n\u0153uds de l\u2019arbre et les valeurs, pour\nchaque clef, la liste des caract\u00e8res des fils gauche et droit du n\u0153ud.\n\nPar exemple, l\u2019arbre\n\n![image](data2023/33_arbre.png){: .center}\n\nest stock\u00e9 dans\n\n```python\na = {'F':['B','G'], 'B':['A','D'], 'A':['',''], 'D':['C','E'], \\\n'C':['',''], 'E':['',''], 'G':['','I'], 'I':['','H'], \\\n'H':['','']}\n```\n\n\u00c9crire une fonction r\u00e9cursive `taille` prenant en param\u00e8tres un arbre binaire `arbre`\nsous la forme d\u2019un dictionnaire et un caract\u00e8re `lettre` qui est la valeur du sommet de\nl\u2019arbre, et qui renvoie la taille de l\u2019arbre \u00e0 savoir le nombre total de n\u0153uds.\n\nOn observe que, par exemple, `arbre[lettre][0]`, respectivement\n`arbre[lettre][1]`, permet d\u2019atteindre la cl\u00e9 du sous-arbre gauche, respectivement\ndroit, de l\u2019arbre `arbre` de sommet `lettre`.\n\nExemple :\n```python\n>>> taille(a, \u2019F\u2019)\n9\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-332","title":"Exercice 33.2","text":"Exercice 33.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re l'algorithme de tri de tableau suivant : \u00e0 chaque \u00e9tape, on parcourt le sous- tableau des \u00e9l\u00e9ments non rang\u00e9s et on place le plus petit \u00e9l\u00e9ment en premi\u00e8re position de ce sous-tableau.
Exemple avec le tableau : t = [41, 55, 21, 18, 12, 6, 25]
\u00c9tape 1 : on parcourt tous les \u00e9l\u00e9ments du tableau, on permute le plus petit \u00e9l\u00e9ment avec le premier. Le tableau devient t = [6, 55, 21, 18, 12, 41, 25]
\u00c9tape 2 : on parcourt tous les \u00e9l\u00e9ments sauf le premier, on permute le plus petit \u00e9l\u00e9ment trouv\u00e9 avec le second. Le tableau devient : t = [6, 12, 21, 18, 55, 41, 25]
Et ainsi de suite.
La code de la fonction tri_selection
qui impl\u00e9mente cet algorithme est donn\u00e9 ci- dessous.
def tri_selection(tab):\n N = len(tab)\n for k in range(...):\n imin = ...\n for i in range(... , N):\n if tab[i] < ... :\n imin = i\n ... , tab[imin] = tab[imin] , ...\n
Compl\u00e9ter le code de cette fonction de fa\u00e7on \u00e0 obtenir :
>>> liste = [41, 55, 21, 18, 12, 6, 25]\n>>> tri_selection(liste)\n>>> liste\n[6, 12, 18, 21, 25, 41, 55]\n
On rappelle que l'instruction a, b = b, a
\u00e9change les contenus de a
et de b
.
def tri_selection(tab):\n N = len(tab)\nfor k in range(N):\nimin = k\nfor i in range(k+1, N):\nif tab[i] < tab[imin] :\nimin = i\ntab[k] , tab[imin] = tab[imin] , tab[k]\n
On consid\u00e8re l'algorithme de tri de tableau suivant : \u00e0 chaque \u00e9tape, on parcourt le sous-\ntableau des \u00e9l\u00e9ments non rang\u00e9s et on place le plus petit \u00e9l\u00e9ment en premi\u00e8re position de\nce sous-tableau.\n\nExemple avec le tableau : ```t = [41, 55, 21, 18, 12, 6, 25]``` \n\n- \u00c9tape 1 : on parcourt tous les \u00e9l\u00e9ments du tableau, on permute le plus petit \u00e9l\u00e9ment avec\nle premier. Le tableau devient `t = [6, 55, 21, 18, 12, 41, 25]`\n\n- \u00c9tape 2 : on parcourt tous les \u00e9l\u00e9ments sauf le premier, on permute le plus petit \u00e9l\u00e9ment\ntrouv\u00e9 avec le second. Le tableau devient : ```t = [6, 12, 21, 18, 55, 41, 25]``` \n\nEt ainsi de suite. \n\nLa code de la fonction `tri_selection` qui impl\u00e9mente cet algorithme est donn\u00e9 ci-\ndessous.\n\n\n```python linenums='1'\ndef tri_selection(tab):\n N = len(tab)\n for k in range(...):\n imin = ...\n for i in range(... , N):\n if tab[i] < ... :\n imin = i\n ... , tab[imin] = tab[imin] , ...\n
Compl\u00e9ter le code de cette fonction de fa\u00e7on \u00e0 obtenir :
>>> liste = [41, 55, 21, 18, 12, 6, 25]\n>>> tri_selection(liste)\n>>> liste\n[6, 12, 18, 21, 25, 41, 55]\n
On rappelle que l'instruction a, b = b, a
\u00e9change les contenus de a
et de b
. ```
Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-34","title":"\u25b6 Sujet 34","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-341","title":"Exercice 34.1","text":"Exercice 34.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer la fonction moyenne
prenant en param\u00e8tre un tableau d'entiers tab
(de type list
) qui renvoie la moyenne de ses \u00e9l\u00e9ments si le tableau est non vide. Proposer une fa\u00e7on de traiter le cas o\u00f9 le tableau pass\u00e9 en param\u00e8tre est vide.
Dans cet exercice, on s\u2019interdira d\u2019utiliser la fonction Python sum
.
Exemples :
>>> moyenne([5,3,8])\n5.333333333333333\n>>> moyenne([1,2,3,4,5,6,7,8,9,10])\n5.5\n>>> moyenne([])\n# Comportement diff\u00e9rent suivant le traitement propos\u00e9.\n
def moyenne(tab):\n if tab == []:\n print('Le tableau donn\u00e9 est vide')\n return None\n else:\n somme = 0\n for elt in tab:\n somme += elt\n return somme / len(tab)\n
Programmer la fonction ```moyenne``` prenant en param\u00e8tre un tableau d'entiers ```tab``` (de type\n`list`) qui renvoie la moyenne de ses \u00e9l\u00e9ments si le tableau est non vide. Proposer une\nfa\u00e7on de traiter le cas o\u00f9 le tableau pass\u00e9 en param\u00e8tre est vide.\n\nDans cet exercice, on s\u2019interdira d\u2019utiliser la fonction Python `sum`.\n\nExemples :\n```python\n>>> moyenne([5,3,8])\n5.333333333333333\n>>> moyenne([1,2,3,4,5,6,7,8,9,10])\n5.5\n>>> moyenne([])\n# Comportement diff\u00e9rent suivant le traitement propos\u00e9.\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-342","title":"Exercice 34.2","text":"Exercice 34.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re un tableau d'entiers tab
(de type list
) dont les \u00e9l\u00e9ments sont des 0
ou des 1
). On se propose de trier ce tableau selon l'algorithme suivant : \u00e0 chaque \u00e9tape du tri, le tableau est constitu\u00e9 de trois zones cons\u00e9cutives, la premi\u00e8re ne contenant que des 0
, la seconde n'\u00e9tant pas tri\u00e9e et la derni\u00e8re ne contenant que des 1
.
Zone de 0Zone non tri\u00e9eZone de 1
Tant que la zone non tri\u00e9e n'est pas r\u00e9duite \u00e0 un seul \u00e9l\u00e9ment, on regarde son premier \u00e9l\u00e9ment :
Dans tous les cas, la longueur de la zone non tri\u00e9e diminue de 1.
Recopier sous Python en la compl\u00e9tant la fonction tri
suivante :
def tri(tab):\n # i est le premier indice de la zone non tri\u00e9e,\n # j est le dernier indice de cette zone non tri\u00e9e.\n # Au d\u00e9but, la zone non tri\u00e9e est le tableau complet.\n i = ...\n j = ...\n while i != j:\n if tab[i]== 0:\n i = ...\n else:\n valeur = tab[j]\n tab[j] = ...\n ...\n j = ...\n ...\n
Exemple :
>>> tri([0,1,0,1,0,1,0,1,0])\n[0, 0, 0, 0, 0, 1, 1, 1, 1] \n
def tri(tab):\n # i est le premier indice de la zone non tri\u00e9e,\n # j est le dernier indice de cette zone non tri\u00e9e.\n # Au d\u00e9but, la zone non tri\u00e9e est le tableau complet.\ni = 0\nj = len(tab) - 1\nwhile i != j :\n if tab[i] == 0:\ni = i + 1\nelse :\n valeur = tab[j]\ntab[j] = tab[i]\ntab[i] = valeur\nj = j - 1\nreturn tab\n
On consid\u00e8re un tableau d'entiers `tab` (de type `list`) dont les \u00e9l\u00e9ments sont des `0` ou des `1`). On se propose de trier ce tableau selon l'algorithme suivant : \u00e0 chaque \u00e9tape du tri, le tableau est constitu\u00e9 de trois zones cons\u00e9cutives, la premi\u00e8re ne contenant que des `0`,\nla seconde n'\u00e9tant pas tri\u00e9e et la derni\u00e8re ne contenant que des `1`.\n\n<table>\n<tr>\n<td>Zone de 0</td><td>Zone non tri\u00e9e</td><td>Zone de 1</td>\n</tr>\n</table>\n\nTant que la zone non tri\u00e9e n'est pas r\u00e9duite \u00e0 un seul \u00e9l\u00e9ment, on regarde son premier\n\u00e9l\u00e9ment :\n\n- si cet \u00e9l\u00e9ment vaut 0, on consid\u00e8re qu'il appartient d\u00e9sormais \u00e0 la zone ne contenant\nque des 0 ;\n- si cet \u00e9l\u00e9ment vaut 1, il est \u00e9chang\u00e9 avec le dernier \u00e9l\u00e9ment de la zone non tri\u00e9e et on\nconsid\u00e8re alors qu\u2019il appartient \u00e0 la zone ne contenant que des 1.\n\nDans tous les cas, la longueur de la zone non tri\u00e9e diminue de 1.\n\nRecopier sous Python en la compl\u00e9tant la fonction `tri` suivante :\n\n```python linenums='1'\ndef tri(tab):\n # i est le premier indice de la zone non tri\u00e9e,\n # j est le dernier indice de cette zone non tri\u00e9e.\n # Au d\u00e9but, la zone non tri\u00e9e est le tableau complet.\n i = ...\n j = ...\n while i != j:\n if tab[i]== 0:\n i = ...\n else:\n valeur = tab[j]\n tab[j] = ...\n ...\n j = ...\n ...\n
Exemple :
>>> tri([0,1,0,1,0,1,0,1,0])\n[0, 0, 0, 0, 0, 1, 1, 1, 1] \n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-35","title":"\u25b6 Sujet 35","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-351","title":"Exercice 35.1","text":"Exercice 35.1
\u00c9nonc\u00e9CorrectionSource MarkdownL'op\u00e9rateur \u00ab ou exclusif \u00bb entre deux bits renvoie 0 si les deux bits sont \u00e9gaux et 1 s'ils sont diff\u00e9rents. Il est symbolis\u00e9 par le caract\u00e8re \u2295. Ainsi :
On repr\u00e9sente ici une suite de bits par un tableau contenant des 0 et des 1.
Exemples :
a = [1, 0, 1, 0, 1, 1, 0, 1]\nb = [0, 1, 1, 1, 0, 1, 0, 0]\nc = [1, 1, 0, 1]\nd = [0, 0, 1, 1]\n
\u00c9crire la fonction ou_exclusif
qui prend en param\u00e8tres deux tableaux de m\u00eame longueur et qui renvoie un tableau o\u00f9 l\u2019\u00e9l\u00e9ment situ\u00e9 \u00e0 position i
est le r\u00e9sultat, par l\u2019op\u00e9rateur \u00ab ou exclusif \u00bb, des \u00e9l\u00e9ments \u00e0 la position i
des tableaux pass\u00e9s en param\u00e8tres.
En consid\u00e9rant les quatre exemples ci-dessus, cette fonction donne :
>>> ou_exclusif(a, b)\n[1, 1, 0, 1, 1, 0, 0, 1]\n>>> ou_exclusif(c, d)\n[1, 1, 1, 0]\n
def ou_exclusif(tab1, tab2):\n resultat = []\n taille = len(tab1)\n for i in range(taille):\n resultat.append(tab1[i] ^ tab2[i])\n return resultat\n
Si on ne connait pas la fonction native ^ qui fait le \u00abou exclusif\u00bb de deux entiers en Python, on peut la recoder :
def ou_exc(a, b):\n if a == 0 and b == 0:\n return 0\n if a == 0 and b == 1:\n return 1\n if a == 1 and b == 0:\n return 1\n if a == 1 and b == 1:\n return 0\n
Le code devient alors :
def ou_exclusif(tab1, tab2):\n resultat = []\n taille = len(tab1)\n for i in range(taille):\n resultat.append(ou_exc(tab1[i],tab2[i]))\n return resultat\n
L'op\u00e9rateur \u00ab ou exclusif \u00bb entre deux bits renvoie 0 si les deux bits sont \u00e9gaux et 1 s'ils sont\ndiff\u00e9rents. Il est symbolis\u00e9 par le caract\u00e8re \u2295.\nAinsi :\n\n- 0 \u2295 0 = 0\n- 0 \u2295 1 = 1\n- 1 \u2295 0 = 1\n- 1 \u2295 1 = 0\n\nOn repr\u00e9sente ici une suite de bits par un tableau contenant des 0 et des 1.\n\nExemples :\n\n```python\na = [1, 0, 1, 0, 1, 1, 0, 1]\nb = [0, 1, 1, 1, 0, 1, 0, 0]\nc = [1, 1, 0, 1]\nd = [0, 0, 1, 1]\n```\n\n\u00c9crire la fonction ```ou_exclusif``` qui prend en param\u00e8tres deux tableaux de m\u00eame longueur et qui renvoie\nun tableau o\u00f9 l\u2019\u00e9l\u00e9ment situ\u00e9 \u00e0 position `i` est le r\u00e9sultat, par l\u2019op\u00e9rateur \u00ab ou exclusif \u00bb, des\n\u00e9l\u00e9ments \u00e0 la position `i` des tableaux pass\u00e9s en param\u00e8tres.\n\nEn consid\u00e9rant les quatre exemples ci-dessus, cette fonction donne :\n\n```python\n>>> ou_exclusif(a, b)\n[1, 1, 0, 1, 1, 0, 0, 1]\n>>> ou_exclusif(c, d)\n[1, 1, 1, 0]\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-352","title":"Exercice 35.2","text":"Exercice 35.2
\u00c9nonc\u00e9CorrectionSources MarkdownDans cet exercice, on appelle carr\u00e9 d\u2019ordre \\(n\\) un tableau de \\(n\\) lignes et \\(n\\) colonnes dont chaque case contient un entier naturel.
Exemples :
Un carr\u00e9 est dit semimagique lorsque les sommes des \u00e9l\u00e9ments situ\u00e9s sur chaque ligne, chaque colonne sont \u00e9gales.
Ainsi c2 et c3 sont semimagiques car la somme de chaque ligne, chaque colonne et chaque diagonale est \u00e9gale \u00e0 8 pour c2 et 12 pour c3.
Le carre c3bis n'est pas semimagique car la somme de la premi\u00e8re ligne est \u00e9gale \u00e0 15 alors que celle de la deuxi\u00e8me ligne est \u00e9gale \u00e0 10.
La classe Carre
ci-apr\u00e8s contient des m\u00e9thodes qui permettent de manipuler des carr\u00e9s.
La m\u00e9thode constructeur cr\u00e9e un carr\u00e9 sous forme d\u2019un tableau \u00e0 deux dimensions \u00e0 partir d\u2019une liste d\u2019entiers, et d\u2019un ordre.
La m\u00e9thode affiche
permet d\u2019afficher le carr\u00e9 cr\u00e9\u00e9.
Exemple :
>>> liste = (3, 4, 5, 4, 4, 4, 5, 4, 3)\n>>> c3 = Carre(liste, 3)\n>>> c3.affiche()\n[3, 4, 5]\n[4, 4, 4]\n[5, 4, 3]\n
Compl\u00e9ter la m\u00e9thode est_semimagique
qui renvoie True
si le carr\u00e9 est semimagique, False
sinon. Puis tester la fonction est_semimagique
sur les carr\u00e9s c2, c3 et c3bis.
class Carre:\n def __init__(self, liste, n):\n self.ordre = n\n self.tableau = [[liste[i + j * n] for i in range(n)] for j in range(n)]\n\n def affiche(self):\n'''Affiche un carr\u00e9'''\n for i in range(self.ordre):\n print(self.tableau[i])\n\n def somme_ligne(self, i):\n'''Calcule la somme des valeurs de la ligne i'''\n somme = 0\n for j in range(self.ordre):\n somme = somme + self.tableau[i][j]\n return somme\n\n def somme_col(self, j):\n'''Calcule la somme des valeurs de la colonne j'''\n somme = 0\n for i in range(self.ordre):\n somme = somme + self.tableau[i][j]\n return somme\n\n def est_semimagique(self):\n s = self.somme_ligne(0)\n\n #test de la somme de chaque ligne\n for i in range(...):\n if ... != s:\n return ...\n\n #test de la somme de chaque colonne\n for j in range(...):\n if ... != s:\n return ...\n\n return ...\n
Listes permettant de g\u00e9n\u00e9rer les carr\u00e9s c2, c3 et c3bis :
lst_c2 = [1, 7, 7, 1]\nlst_c3 = [3, 4, 5, 4, 4, 4, 5, 4, 3]\nlst_c3bis = [2, 9, 4, 7, 0, 3, 6, 1, 8]\n
class Carre:\n def __init__(self, liste, n):\n self.ordre = n\n self.tableau = [[liste[i + j * n] for i in range(n)] for j in range(n)]\n\n def affiche(self):\n'''Affiche un carr\u00e9'''\n for i in range(self.ordre):\n print(self.tableau[i])\n\n def somme_ligne(self, i):\n'''Calcule la somme des valeurs de la ligne i'''\n somme = 0\n for j in range(self.ordre):\n somme = somme + self.tableau[i][j]\n return somme\n\n def somme_col(self, j):\n'''Calcule la somme des valeurs de la colonne j'''\n somme = 0\n for i in range(self.ordre):\n somme = somme + self.tableau[i][j]\n return somme\n\n def est_semimagique(self):\n s = self.somme_ligne(0)\n\n #test de la somme de chaque ligne\nfor i in range(self.ordre):\nif self.somme_ligne(i) != s:\nreturn False\n#test de la somme de chaque colonne\nfor j in range(self.ordre):\nif self.somme_col(j) != s:\nreturn False\nreturn True\n
Tests avec :
lst_c2 = [1, 7, 7, 1]\nlst_c3 = [3, 4, 5, 4, 4, 4, 5, 4, 3]\nlst_c3bis = [2, 9, 4, 7, 0, 3, 6, 1, 8]\n
>>> c2 = Carre(lst_c2, 2)\n>>> c2.est_semimagique()\nTrue\n\n>>> c3 = Carre(lst_c3, 3)\n>>> c3.est_semimagique()\nTrue\n\n>>> c3bis = Carre(lst_c3bis, 2)\n>>> c3bis.est_semimagique()\nFalse\n
Dans cet exercice, on appelle carr\u00e9 d\u2019ordre $n$ un tableau de $n$ lignes et $n$ colonnes dont chaque case contient un entier naturel.\n\nExemples :\n![image](data2023/35_carre.png){: .center}\n\nUn carr\u00e9 est dit semimagique lorsque les sommes des \u00e9l\u00e9ments situ\u00e9s sur chaque ligne, chaque\ncolonne sont \u00e9gales.\n\n- Ainsi c2 et c3 sont semimagiques car la somme de chaque\nligne, chaque colonne et chaque diagonale est \u00e9gale \u00e0 8 pour c2 et 12 pour c3.\n\n- Le carre c3bis n'est pas semimagique car la somme de la premi\u00e8re ligne est \u00e9gale \u00e0 15 alors que celle de la deuxi\u00e8me ligne\nest \u00e9gale \u00e0 10.\n\nLa classe `Carre` ci-apr\u00e8s contient des m\u00e9thodes qui permettent de manipuler des carr\u00e9s.\n\n- La m\u00e9thode constructeur cr\u00e9e un carr\u00e9 sous forme d\u2019un tableau \u00e0 deux dimensions\n\u00e0 partir d\u2019une liste d\u2019entiers, et d\u2019un ordre.\n\n- La m\u00e9thode `affiche` permet d\u2019afficher le carr\u00e9 cr\u00e9\u00e9.\n\nExemple :\n\n```python\n>>> liste = (3, 4, 5, 4, 4, 4, 5, 4, 3)\n>>> c3 = Carre(liste, 3)\n>>> c3.affiche()\n[3, 4, 5]\n[4, 4, 4]\n[5, 4, 3]\n
Compl\u00e9ter la m\u00e9thode est_semimagique
qui renvoie True
si le carr\u00e9 est semimagique, False
sinon. Puis tester la fonction est_semimagique
sur les carr\u00e9s c2, c3 et c3bis.
class Carre:\n def __init__(self, liste, n):\n self.ordre = n\n self.tableau = [[liste[i + j * n] for i in range(n)] for j in range(n)]\n\n def affiche(self):\n'''Affiche un carr\u00e9'''\n for i in range(self.ordre):\n print(self.tableau[i])\n\n def somme_ligne(self, i):\n'''Calcule la somme des valeurs de la ligne i'''\n somme = 0\n for j in range(self.ordre):\n somme = somme + self.tableau[i][j]\n return somme\n\n def somme_col(self, j):\n'''Calcule la somme des valeurs de la colonne j'''\n somme = 0\n for i in range(self.ordre):\n somme = somme + self.tableau[i][j]\n return somme\n\n def est_semimagique(self):\n s = self.somme_ligne(0)\n\n #test de la somme de chaque ligne\n for i in range(...):\n if ... != s:\n return ...\n\n #test de la somme de chaque colonne\n for j in range(...):\n if ... != s:\n return ...\n\n return ...\n
Listes permettant de g\u00e9n\u00e9rer les carr\u00e9s c2, c3 et c3bis :
lst_c2 = [1, 7, 7, 1]\nlst_c3 = [3, 4, 5, 4, 4, 4, 5, 4, 3]\nlst_c3bis = [2, 9, 4, 7, 0, 3, 6, 1, 8]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-36","title":"\u25b6 Sujet 36","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-361","title":"Exercice 36.1","text":"Exercice 36.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction couples_consecutifs
qui prend en param\u00e8tre une liste de nombres entiers tab
non vide, et qui renvoie la liste (\u00e9ventuellement vide) des couples d'entiers cons\u00e9cutifs successifs qu'il peut y avoir dans tab
.
Exemples :
>>> couples_consecutifs([1, 4, 3, 5])\n[]\n>>> couples_consecutifs([1, 4, 5, 3])\n[(4, 5)]\n>>> couples_consecutifs([1, 1, 2, 4])\n[(1, 2)]\n>>> couples_consecutifs([7, 1, 2, 5, 3, 4])\n[(1, 2), (3, 4)]\n>>> couples_consecutifs([5, 1, 2, 3, 8, -5, -4, 7])\n[(1, 2), (2, 3), (-5, -4)]\n
def couples_consecutifs(tab):\n solution = []\n for i in range(len(tab)-1):\n if tab[i] + 1 == tab[i+1]:\n solution.append((tab[i], tab[i+1]))\n return solution\n
\u00c9crire une fonction `couples_consecutifs` qui prend en param\u00e8tre une liste de\nnombres entiers `tab` non vide, et qui renvoie la liste (\u00e9ventuellement vide) des couples d'entiers cons\u00e9cutifs\nsuccessifs qu'il peut y avoir dans `tab`.\n\nExemples :\n```python\n>>> couples_consecutifs([1, 4, 3, 5])\n[]\n>>> couples_consecutifs([1, 4, 5, 3])\n[(4, 5)]\n>>> couples_consecutifs([1, 1, 2, 4])\n[(1, 2)]\n>>> couples_consecutifs([7, 1, 2, 5, 3, 4])\n[(1, 2), (3, 4)]\n>>> couples_consecutifs([5, 1, 2, 3, 8, -5, -4, 7])\n[(1, 2), (2, 3), (-5, -4)]\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-362","title":"Exercice 36.2","text":"Exercice 36.2
\u00c9nonc\u00e9CorrectionSources MarkdownSoit une image binaire repr\u00e9sent\u00e9e dans un tableau \u00e0 2 dimensions. Les \u00e9l\u00e9ments M[i][j]
, appel\u00e9s pixels, sont \u00e9gaux soit \u00e0 0
soit \u00e0 1
.
Une composante d\u2019une image est un sous-ensemble de l\u2019image constitu\u00e9 uniquement de 1
et de 0
qui sont c\u00f4te \u00e0 c\u00f4te, soit horizontalement soit verticalement.
Par exemple, les composantes de sont
On souhaite, \u00e0 partir d\u2019un pixel \u00e9gal \u00e0 1
dans une image M
, donner la valeur val
\u00e0 tous les pixels de la composante \u00e0 laquelle appartient ce pixel.
La fonction propager
prend pour param\u00e8tre une image M
(repr\u00e9sent\u00e9e par une liste de listes), deux entiers i
et j
et unevaleur enti\u00e8re val
. Elle met \u00e0 la valeur val
tous les pixels de la composante du pixel M[i][j]
s\u2019il vaut 1
et ne fait rien s\u2019il vaut 0
.
Par exemple, propager(M, 2, 1, 3)
donne
Compl\u00e9ter le code r\u00e9cursif de la fonction propager
donn\u00e9 ci-dessous :
def propager(M, i, j, val):\n if M[i][j] == ...:\n M[i][j] = val\n\n # l'element en haut fait partie de la composante\n if i-1 >= 0 and M[i-1][j] == ...:\n propager(M, i-1, j, val)\n\n # l'element en bas fait partie de la composante\n if ... < len(M) and M[i+1][j] == 1:\n propager(M, ..., j, val)\n\n # l'element \u00e0 gauche fait partie de la composante\n if ... and M[i][j-1] == 1:\n propager(M, ..., ..., val)\n\n # l'element \u00e0 droite fait partie de la composante\n if ... and ...:\n propager(..., ..., ..., ...)\n
Exemple :
>>> M = [[0, 0, 1, 0], [0, 1, 0, 1], [1, 1, 1, 0], [0, 1, 1, 0]]\n>>> propager(M, 2, 1, 3)\n>>> M\n[[0, 0, 1, 0], [0, 3, 0, 1], [3, 3, 3, 0], [0, 3, 3, 0]]\n
def propager(M, i, j, val):\nif M[i][j] == 1:\nM[i][j] = val\n\n # l'element en haut fait partie de la composante\nif i-1 >= 0 and M[i-1][j] == 1:\npropager(M, i-1, j, val)\n\n # l'element en bas fait partie de la composante\nif i+1 < len(M) and M[i+1][j] == 1:\npropager(M, i+1, j, val)\n# l'element \u00e0 gauche fait partie de la composante\nif j-1 >= 0 and M[i][j-1] == 1:\npropager(M, i, j-1, val)\n# l'element \u00e0 droite fait partie de la composante\nif j+1 < len(M[i]) and M[i][j+1] == 1:\npropager(M, i, j+1, val)\n
ce code va d\u00e9clencher la propagation m\u00eame si la cellule i,j
n'est pas \u00e0 1. C'est sans doute une erreur d'\u00e9nonc\u00e9. Il faudrait plut\u00f4t \u00e9crire ceci :
def propager(M, i, j, val):\nif M[i][j] == 1:\nM[i][j] = val\n\n # l'element en haut fait partie de la composante\nif i-1 >= 0 and M[i-1][j] == 1:\npropager(M, i-1, j, val)\n\n # l'element en bas fait partie de la composante\nif i+1 < len(M) and M[i+1][j] == 1:\npropager(M, i+1, j, val)\n# l'element \u00e0 gauche fait partie de la composante\nif j-1 >= 0 and M[i][j-1] == 1:\npropager(M, i, j-1, val)\n# l'element \u00e0 droite fait partie de la composante\nif j+1 < len(M[i]) and M[i][j+1] == 1:\npropager(M, i, j+1, val)\n
Soit une image binaire repr\u00e9sent\u00e9e dans un tableau \u00e0 2 dimensions. Les \u00e9l\u00e9ments\n`M[i][j]`, appel\u00e9s pixels, sont \u00e9gaux soit \u00e0 `0` soit \u00e0 `1`.\n\nUne composante d\u2019une image est un sous-ensemble de l\u2019image constitu\u00e9 uniquement de\n`1` et de `0` qui sont c\u00f4te \u00e0 c\u00f4te, soit horizontalement soit verticalement.\n\nPar exemple, les composantes de\n![image](data2023/36_carre1.png){: .center}\nsont\n![image](data2023/36_carre2.png){: .center width=30%}\n\nOn souhaite, \u00e0 partir d\u2019un pixel \u00e9gal \u00e0 `1` dans une image `M`, donner la valeur `val` \u00e0 tous\nles pixels de la composante \u00e0 laquelle appartient ce pixel.\n\nLa fonction `propager` prend pour param\u00e8tre une image `M` (repr\u00e9sent\u00e9e par une liste de\nlistes), deux entiers `i` et `j` et unevaleur enti\u00e8re `val`. Elle met \u00e0 la valeur `val` tous les pixels de la composante du pixel\n`M[i][j]` s\u2019il vaut `1` et ne fait rien s\u2019il vaut `0`.\n\nPar exemple, `propager(M, 2, 1, 3)` donne\n![image](data2023/36_carre3.png){: .center width=30%}\n\nCompl\u00e9ter le code r\u00e9cursif de la fonction `propager` donn\u00e9 ci-dessous :\n\n```python linenums='1'\ndef propager(M, i, j, val):\n if M[i][j] == ...:\n M[i][j] = val\n\n # l'element en haut fait partie de la composante\n if i-1 >= 0 and M[i-1][j] == ...:\n propager(M, i-1, j, val)\n\n # l'element en bas fait partie de la composante\n if ... < len(M) and M[i+1][j] == 1:\n propager(M, ..., j, val)\n\n # l'element \u00e0 gauche fait partie de la composante\n if ... and M[i][j-1] == 1:\n propager(M, ..., ..., val)\n\n # l'element \u00e0 droite fait partie de la composante\n if ... and ...:\n propager(..., ..., ..., ...)\n
Exemple :
>>> M = [[0, 0, 1, 0], [0, 1, 0, 1], [1, 1, 1, 0], [0, 1, 1, 0]]\n>>> propager(M, 2, 1, 3)\n>>> M\n[[0, 0, 1, 0], [0, 3, 0, 1], [3, 3, 3, 0], [0, 3, 3, 0]]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-37","title":"\u25b6 Sujet 37","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-371","title":"Exercice 37.1","text":"Exercice 37.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche
qui prend en param\u00e8tres elt
un nombre entier et tab
un tableau de nombres entiers, et qui renvoie l\u2019indice de la derni\u00e8re occurrence de elt
dans tab
si elt
est dans tab
et -1
sinon.
Exemples :
>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(1, [1, 0, 42, 7])\n0\n>>> recherche(1, [1, 50, 1])\n2\n>>> recherche(1, [8, 1, 10, 1, 7, 1, 8])\n5\n
def recherche(elt, tab):\n for i in range(len(tab)-1, -1, -1):\n if tab[i] == elt:\n return i\n return -1\n
\u00c9crire une fonction `recherche` qui prend en param\u00e8tres `elt` un nombre entier et `tab`\nun tableau de nombres entiers, et qui renvoie l\u2019indice de la derni\u00e8re occurrence de `elt`\ndans `tab` si `elt` est dans `tab` et `-1` sinon.\n\nExemples :\n```python\n>>> recherche(1, [2, 3, 4])\n-1\n>>> recherche(1, [10, 12, 1, 56])\n2\n>>> recherche(1, [1, 0, 42, 7])\n0\n>>> recherche(1, [1, 50, 1])\n2\n>>> recherche(1, [8, 1, 10, 1, 7, 1, 8])\n5\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-372","title":"Exercice 37.2","text":"Exercice 37.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn d\u00e9finit une classe g\u00e9rant une adresse IPv4.
On rappelle qu\u2019une adresse IPv4 est une adresse de longueur 4 octets, not\u00e9e en d\u00e9cimale \u00e0 point, en s\u00e9parant chacun des octets par un point. On consid\u00e8re un r\u00e9seau priv\u00e9 avec une plage d\u2019adresses IP de 192.168.0.0
\u00e0 192.168.0.255
.
On consid\u00e8re que les adresses IP saisies sont valides.
Les adresses IP 192.168.0.0
et 192.168.0.255
sont des adresses r\u00e9serv\u00e9es.
Le code ci-dessous impl\u00e9mente la classe AdresseIP
.
class AdresseIP:\n def __init__(self, adresse):\n self.adresse = ...\n\n def liste_octet(self):\n\"\"\"renvoie une liste de nombres entiers,\n la liste des octets de l'adresse IP\"\"\"\n return [int(i) for i in self.adresse.split(\".\")]\n\n def est_reservee(self):\n\"\"\"renvoie True si l'adresse IP est une adresse\n r\u00e9serv\u00e9e, False sinon\"\"\"\n return ... or ...\n\n def adresse_suivante(self):\n\"\"\"renvoie un objet de AdresseIP avec l'adresse\n IP qui suit l\u2019adresse self\n si elle existe et False sinon\"\"\"\n if ... < 254:\n octet_nouveau = ... + ...\n return AdresseIP('192.168.0.' + ...)\n else:\n return False\n
Compl\u00e9ter le code ci-dessus et instancier trois objets : adresse1
, adresse2
, adresse3
avec respectivement les arguments suivants : '192.168.0.1'
, '192.168.0.2'
, '192.168.0.0'
V\u00e9rifier que :
>>> adresse1.est_reservee()\nFalse\n>>> adresse3.est_reservee()\nTrue\n>>> adresse2.adresse_suivante().adresse\n'192.168.0.3'\n
class AdresseIP:\n def __init__(self, adresse):\nself.adresse = adresse\ndef liste_octet(self):\n\"\"\"renvoie une liste de nombres entiers,\n la liste des octets de l'adresse IP\"\"\"\n return [int(i) for i in self.adresse.split(\".\")]\n\n def est_reservee(self):\n\"\"\"renvoie True si l'adresse IP est une adresse\n r\u00e9serv\u00e9e, False sinon\"\"\"\nreturn self.liste_octet()[3] == 0 or self.liste_octet()[3] == 255\ndef adresse_suivante(self):\n\"\"\"renvoie un objet de AdresseIP avec l'adresse\n IP qui suit l\u2019adresse self\n si elle existe et False sinon\"\"\"\nif self.liste_octet()[3] < 254:\noctet_nouveau = self.liste_octet()[3] + 1\nreturn AdresseIP('192.168.0.' + str(octet_nouveau))\nelse:\n return False\n\nadresse1 = AdresseIP('192.168.0.1')\nadresse2 = AdresseIP('192.168.0.2')\nadresse3 = AdresseIP('192.168.0.0')\n
On d\u00e9finit une classe g\u00e9rant une adresse IPv4.\n\nOn rappelle qu\u2019une adresse IPv4 est une adresse de longueur 4 octets, not\u00e9e en d\u00e9cimale\n\u00e0 point, en s\u00e9parant chacun des octets par un point. On consid\u00e8re un r\u00e9seau priv\u00e9 avec\nune plage d\u2019adresses IP de `192.168.0.0` \u00e0 `192.168.0.255`.\n\nOn consid\u00e8re que les adresses IP saisies sont valides.\n\nLes adresses IP `192.168.0.0` et `192.168.0.255` sont des adresses r\u00e9serv\u00e9es.\n\nLe code ci-dessous impl\u00e9mente la classe `AdresseIP`.\n\n```python linenums='1'\nclass AdresseIP:\n def __init__(self, adresse):\n self.adresse = ...\n\n def liste_octet(self):\n \"\"\"renvoie une liste de nombres entiers,\n la liste des octets de l'adresse IP\"\"\"\n return [int(i) for i in self.adresse.split(\".\")]\n\n def est_reservee(self):\n \"\"\"renvoie True si l'adresse IP est une adresse\n r\u00e9serv\u00e9e, False sinon\"\"\"\n return ... or ...\n\n def adresse_suivante(self):\n \"\"\"renvoie un objet de AdresseIP avec l'adresse\n IP qui suit l\u2019adresse self\n si elle existe et False sinon\"\"\"\n if ... < 254:\n octet_nouveau = ... + ...\n return AdresseIP('192.168.0.' + ...)\n else:\n return False\n
Compl\u00e9ter le code ci-dessus et instancier trois objets : adresse1
, adresse2
, adresse3
avec respectivement les arguments suivants : '192.168.0.1'
, '192.168.0.2'
, '192.168.0.0'
V\u00e9rifier que :
>>> adresse1.est_reservee()\nFalse\n>>> adresse3.est_reservee()\nTrue\n>>> adresse2.adresse_suivante().adresse\n'192.168.0.3'\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-38","title":"\u25b6 Sujet 38","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-381","title":"Exercice 38.1","text":"Exercice 38.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn consid\u00e8re des mots \u00e0 trous : ce sont des cha\u00eenes de caract\u00e8res contenant uniquement des majuscules et des caract\u00e8res *
. Par exemple INFO*MA*IQUE
, ***I***E**
et *S*
sont des mots \u00e0 trous.
Programmer une fonction correspond
qui :
mot
et mot_a_trous
o\u00f9 mot_a_trous
est un mot \u00e0 trous comme indiqu\u00e9 ci-dessus, True
si on peut obtenir mot
en rempla\u00e7ant convenablement les caract\u00e8res '*'
de mot_a_trous
.False
sinon.Exemple :
>>> correspond('INFORMATIQUE', 'INFO*MA*IQUE')\nTrue\n>>> correspond('AUTOMATIQUE', 'INFO*MA*IQUE')\nFalse\n>>> correspond('STOP', 'S*')\nFalse\n>>> correspond('AUTO', '*UT*')\nTrue\n
def correspond(mot, mot_a_trous):\n if len(mot) != len(mot_a_trous):\n return False\n for i in range(len(mot)):\n if mot[i] != mot_a_trous[i] and mot_a_trous[i] != '*':\n return False\n return True\n
On consid\u00e8re des mots \u00e0 trous : ce sont des cha\u00eenes de caract\u00e8res contenant uniquement\ndes majuscules et des caract\u00e8res `*`. Par exemple `INFO*MA*IQUE`, `***I***E**` et\n`*S*` sont des mots \u00e0 trous.\n\nProgrammer une fonction `correspond` qui :\n\n- prend en param\u00e8tres deux cha\u00eenes de caract\u00e8res `mot` et `mot_a_trous` o\u00f9\n`mot_a_trous` est un mot \u00e0 trous comme indiqu\u00e9 ci-dessus, \n- renvoie :\n - `True` si on peut obtenir `mot` en rempla\u00e7ant convenablement les caract\u00e8res\n`'*'` de `mot_a_trous`.\n - `False` sinon.\n\nExemple :\n\n```python\n>>> correspond('INFORMATIQUE', 'INFO*MA*IQUE')\nTrue\n>>> correspond('AUTOMATIQUE', 'INFO*MA*IQUE')\nFalse\n>>> correspond('STOP', 'S*')\nFalse\n>>> correspond('AUTO', '*UT*')\nTrue\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-382","title":"Exercice 38.2","text":"Exercice 38.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re au plus 26 personnes A, B, C, D, E, F ... qui peuvent s'envoyer des messages avec deux r\u00e8gles \u00e0 respecter :
Voici un exemple - avec 6 personnes - de \u00ab plan d'envoi des messages \u00bb qui respecte les r\u00e8gles ci-dessus, puisque chaque personne est pr\u00e9sente une seule fois dans chaque colonne :
Et le dictionnaire correspondant \u00e0 ce plan d'envoi est le suivant :
plan_a = {'A':'E', 'B':'F', 'C':'D', 'D':'C', 'E':'B', 'F':'A'}
Un cycle est une suite de personnes dans laquelle la derni\u00e8re est la m\u00eame que la premi\u00e8re.
Sur le plan d'envoi plan_a
des messages ci-dessus, il y a deux cycles distincts : un premier cycle avec A, E, B, F et un second cycle avec C et D.
En revanche, le plan d\u2019envoi plan_b
ci-dessous :
plan_b = {'A':'C', 'B':'F', 'C':'E', 'D':'A', 'E':'B', 'F':'D'}
comporte un unique cycle : A, C, E, B, F, D. Dans ce cas, lorsqu\u2019un plan d\u2019envoi comporte un unique cycle, on dit que le plan d\u2019envoi est cyclique.
Pour savoir si un plan d'envoi de messages comportant N personnes est cyclique, on peut utiliser l'algorithme ci-dessous :
Compl\u00e9ter la fonction est_cyclique
en respectant la sp\u00e9cification.
Remarque : la fonction python len
permet d'obtenir la longueur d'un dictionnaire.
def est_cyclique(plan):\n'''\n Prend en param\u00e8tre un dictionnaire `plan` correspondant \u00e0 un plan d'envoi de messages (ici entre les personnes A, B, C, D, E, F).\n Renvoie True si le plan d'envoi de messages est cyclique et False sinon.\n '''\n expediteur = 'A'\n destinataire = plan[ ... ]\n nb_destinaires = 1\n\n while destinataire != ...:\n destinataire = plan[ ... ]\n nb_destinaires += ...\n\n return nb_destinaires == ...\n
Exemples :
>>> est_cyclique({'A':'E', 'F':'A', 'C':'D', 'E':'B', 'B':'F', 'D':'C'})\nFalse\n>>> est_cyclique({'A':'E', 'F':'C', 'C':'D', 'E':'B', 'B':'F', 'D':'A'})\nTrue\n>>> est_cyclique({'A':'B', 'F':'C', 'C':'D', 'E':'A', 'B':'F', 'D':'E'})\nTrue\n>>> est_cyclique({'A':'B', 'F':'A', 'C':'D', 'E':'C', 'B':'F', 'D':'E'})\nFalse\n
def est_cyclique(plan):\n'''\n Prend en param\u00e8tre un dictionnaire `plan` correspondant \u00e0 un plan d'envoi de messages (ici entre les personnes A, B, C, D, E, F).\n Renvoie True si le plan d'envoi de messages est cyclique et False sinon.\n '''\n expediteur = 'A'\ndestinataire = plan[expediteur]\nnb_destinaires = 1\nwhile destinataire != expediteur:\ndestinataire = plan[destinataire]\nnb_destinaires += 1\nreturn nb_destinaires == len(plan)\n#tests\nprint(est_cyclique({'A':'E', 'F':'A', 'C':'D', 'E':'B', 'B':'F', 'D':'C'}))\nprint(est_cyclique({'A':'E', 'F':'C', 'C':'D', 'E':'B', 'B':'F', 'D':'A'}))\nprint(est_cyclique({'A':'B', 'F':'C', 'C':'D', 'E':'A', 'B':'F', 'D':'E'}))\nprint(est_cyclique({'A':'B', 'F':'A', 'C':'D', 'E':'C', 'B':'F', 'D':'E'}))\n
On consid\u00e8re au plus 26 personnes A, B, C, D, E, F ... qui peuvent s'envoyer des messages\navec deux r\u00e8gles \u00e0 respecter :\n\n- chaque personne ne peut envoyer des messages qu'\u00e0 une seule personne\n(\u00e9ventuellement elle-m\u00eame),\n- chaque personne ne peut recevoir des messages qu'en provenance d'une seule\npersonne (\u00e9ventuellement elle-m\u00eame).\n\n\nVoici un exemple - avec 6 personnes - de \u00ab plan d'envoi des messages \u00bb qui respecte les\nr\u00e8gles ci-dessus, puisque chaque personne est pr\u00e9sente une seule fois dans chaque\ncolonne :\n\n- A envoie ses messages \u00e0 E\n- E envoie ses messages \u00e0 B\n- B envoie ses messages \u00e0 F\n- F envoie ses messages \u00e0 A\n- C envoie ses messages \u00e0 D\n- D envoie ses messages \u00e0 C\n\nEt le dictionnaire correspondant \u00e0 ce plan d'envoi est le suivant :\n\n`plan_a = {'A':'E', 'B':'F', 'C':'D', 'D':'C', 'E':'B', 'F':'A'}`\n\nUn cycle est une suite de personnes dans laquelle la derni\u00e8re est la m\u00eame que la\npremi\u00e8re.\n\nSur le plan d'envoi `plan_a` des messages ci-dessus, il y a deux cycles distincts : un premier\ncycle avec A, E, B, F et un second cycle avec C et D.\n\nEn revanche, le plan d\u2019envoi `plan_b` ci-dessous :\n\n`plan_b = {'A':'C', 'B':'F', 'C':'E', 'D':'A', 'E':'B', 'F':'D'}`\n\ncomporte un unique cycle : A, C, E, B, F, D. Dans ce cas, lorsqu\u2019un plan d\u2019envoi comporte un\n*unique cycle*, on dit que le plan d\u2019envoi est *cyclique*.\n\nPour savoir si un plan d'envoi de messages comportant N personnes est cyclique, on peut\nutiliser l'algorithme ci-dessous :\n\n\n- on part d\u2019un exp\u00e9diteur (ici A) et on inspecte son destinataire dans le plan d'envoi,\n- chaque destinataire devient \u00e0 son tour exp\u00e9diteur, selon le plan d\u2019envoi, tant\nqu\u2019on ne \u00ab retombe \u00bb pas sur l\u2019exp\u00e9diteur initial,\n- le plan d\u2019envoi est cyclique si on l\u2019a parcouru en entier.\n\n\nCompl\u00e9ter la fonction `est_cyclique` en respectant la sp\u00e9cification.\n\n*Remarque :* la fonction python `len` permet d'obtenir la longueur d'un dictionnaire.\n\n\n```python linenums='1'\ndef est_cyclique(plan):\n '''\n Prend en param\u00e8tre un dictionnaire `plan` correspondant \u00e0 un plan d'envoi de messages (ici entre les personnes A, B, C, D, E, F).\n Renvoie True si le plan d'envoi de messages est cyclique et False sinon.\n '''\n expediteur = 'A'\n destinataire = plan[ ... ]\n nb_destinaires = 1\n\n while destinataire != ...:\n destinataire = plan[ ... ]\n nb_destinaires += ...\n\n return nb_destinaires == ...\n
Exemples :
>>> est_cyclique({'A':'E', 'F':'A', 'C':'D', 'E':'B', 'B':'F', 'D':'C'})\nFalse\n>>> est_cyclique({'A':'E', 'F':'C', 'C':'D', 'E':'B', 'B':'F', 'D':'A'})\nTrue\n>>> est_cyclique({'A':'B', 'F':'C', 'C':'D', 'E':'A', 'B':'F', 'D':'E'})\nTrue\n>>> est_cyclique({'A':'B', 'F':'A', 'C':'D', 'E':'C', 'B':'F', 'D':'E'})\nFalse\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-39","title":"\u25b6 Sujet 39","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-391","title":"Exercice 39.1","text":"Exercice 39.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn s\u2019int\u00e9resse \u00e0 la suite d\u2019entiers d\u00e9finie par :
En math\u00e9matiques, on le formule ainsi :
\\(U_1 = 1\\), \\(U_2 = 1\\) et, pour tout entier naturel non nul \\(n\\), par \\(U_{n+2} = U_{n+1} + U_n\\).
Cette suite est connue sous le nom de suite de Fibonacci. \u00c9crire en Python une fonction fibonacci
qui prend en param\u00e8tre un entier n
suppos\u00e9 strictement positif et qui renvoie le terme d\u2019indice n
de cette suite.
Exemples :
>>> fibonacci(1)\n1\n>>> fibonacci(2)\n1\n>>> fibonacci(25)\n75025\n>>> fibonacci(45)\n1134903170\n
Version r\u00e9cursive :
def fibonacci(n):\n if n == 1 :\n return 1 \n elif n == 1 :\n return 1\n else :\n return fibonacci(n-1) + fibonacci(n-2)\n
Version imp\u00e9rative :
def fibonacci(n):\n a = 1\n b = 1\n for k in range(n-2):\n t = b\n b = a + b\n a = t\n return b\n
Version programmation dynamique :
def fibonacci(n):\n d = {}\n d[1] = 1\n d[2] = 1\n for k in range(3, n+1):\n d[k] = d[k-1] + d[k-2]\n return d[n]\n
On peut constater que la version r\u00e9cursive \u00e9choue \u00e0 calculer fibonacci(45)
, alors que les deux autres versions le font quasi-imm\u00e9diatement.
On s\u2019int\u00e9resse \u00e0 la suite d\u2019entiers d\u00e9finie par :\n\n- les deux premiers termes sont \u00e9gaux \u00e0 1,\n- ensuite, chaque terme est obtenu en faisant la somme des deux termes qui le\npr\u00e9c\u00e8dent.\n\nEn math\u00e9matiques, on le formule ainsi :\n\n$U_1 = 1$, $U_2 = 1$ et, pour tout entier naturel non nul $n$, par $U_{n+2} = U_{n+1} + U_n$.\n\nCette suite est connue sous le nom de suite de Fibonacci. \n\u00c9crire en Python une fonction `fibonacci` qui prend en param\u00e8tre un entier `n` suppos\u00e9\nstrictement positif et qui renvoie le terme d\u2019indice `n` de cette suite.\n\nExemples :\n\n```python\n>>> fibonacci(1)\n1\n>>> fibonacci(2)\n1\n>>> fibonacci(25)\n75025\n>>> fibonacci(45)\n1134903170\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-392","title":"Exercice 39.2","text":"Exercice 39.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn consid\u00e8re la fonction pantheon
prenant en param\u00e8tres eleves
et notes
deux tableaux de m\u00eame longueur, le premier contenant le nom des \u00e9l\u00e8ves et le second, des entiers positifs d\u00e9signant leur note \u00e0 un contr\u00f4le de sorte que eleves[i]
a obtenu la note notes[i]
. Cette fonction renvoie le couple constitu\u00e9 de la note maximale attribu\u00e9e et des noms des \u00e9l\u00e8ves ayant obtenu cette note regroup\u00e9s dans un tableau. Ainsi, l\u2019instruction pantheon(['a', 'b', 'c', 'd'], [15, 18, 12, 18])
renvoie le couple (18, ['b', 'd'])
.
def pantheon(eleves, notes):\n note_maxi = 0\n meilleurs_eleves = ...\n\n for i in range(...) :\n if notes[i] == ... :\n meilleurs_eleves.append(...)\n elif notes[i] > note_maxi:\n note_maxi = ...\n meilleurs_eleves = [...]\n\n return (note_maxi,meilleurs_eleves)\n
Compl\u00e9ter ce code.
Exemples :
>>> eleves_nsi = ['a','b','c','d','e','f','g','h','i','j']\n>>> notes_nsi = [30, 40, 80, 60, 58, 80, 75, 80, 60, 24]\n>>> pantheon(eleves_nsi, notes_nsi)\n(80, ['c', 'f', 'h'])\n>>> pantheon([],[])\n(0, [])\n
def pantheon(eleves, notes):\n note_maxi = 0\nmeilleurs_eleves = []\nfor i in range(len(eleves)) :\nif notes[i] == note_maxi :\nmeilleurs_eleves.append(eleves[i])\nelif notes[i] > note_maxi:\nnote_maxi = notes[i]\nmeilleurs_eleves = [eleves[i]]\nreturn (note_maxi, meilleurs_eleves)\n
On consid\u00e8re la fonction `pantheon` prenant en param\u00e8tres `eleves` et `notes` deux\ntableaux de m\u00eame longueur, le premier contenant le nom des \u00e9l\u00e8ves et le second, des\nentiers positifs d\u00e9signant leur note \u00e0 un contr\u00f4le de sorte que `eleves[i]` a obtenu la\nnote `notes[i]`. \nCette fonction renvoie le couple constitu\u00e9 de la note maximale attribu\u00e9e et des noms\ndes \u00e9l\u00e8ves ayant obtenu cette note regroup\u00e9s dans un tableau. \nAinsi, l\u2019instruction `pantheon(['a', 'b', 'c', 'd'], [15, 18, 12, 18])` renvoie\nle couple `(18, ['b', 'd'])`.\n\n```python linenums='1'\ndef pantheon(eleves, notes):\n note_maxi = 0\n meilleurs_eleves = ...\n\n for i in range(...) :\n if notes[i] == ... :\n meilleurs_eleves.append(...)\n elif notes[i] > note_maxi:\n note_maxi = ...\n meilleurs_eleves = [...]\n\n return (note_maxi,meilleurs_eleves)\n
Compl\u00e9ter ce code.
Exemples :
>>> eleves_nsi = ['a','b','c','d','e','f','g','h','i','j']\n>>> notes_nsi = [30, 40, 80, 60, 58, 80, 75, 80, 60, 24]\n>>> pantheon(eleves_nsi, notes_nsi)\n(80, ['c', 'f', 'h'])\n>>> pantheon([],[])\n(0, [])\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-40","title":"\u25b6 Sujet 40","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-401","title":"Exercice 40.1","text":"Exercice 40.1
\u00c9nonc\u00e9CorrectionSource MarkdownPour cet exercice :
On appelle \u00ab mot \u00bb une cha\u00eene de caract\u00e8res compos\u00e9e avec des caract\u00e8res choisis parmi les 26 lettres minuscules ou majuscules de l'alphabet,
On appelle \u00ab phrase \u00bb une cha\u00eene de caract\u00e8res :
' '
,'.'
qui est alors coll\u00e9 au dernier mot,'!'
ou d'interrogation '?'
qui est alors s\u00e9par\u00e9 du dernier mot par un seul caract\u00e8re espace ' '
.Exemples :
Apr\u00e8s avoir remarqu\u00e9 le lien entre le nombre de mots et le nombres de caract\u00e8res espace dans une phrase, programmer une fonction nombre_de_mots
qui prend en param\u00e8tre une phrase et renvoie le nombre de mots pr\u00e9sents dans cette phrase.
>>> nombre_de_mots('Le point d exclamation est separe !')\n6\n>>> nombre_de_mots('Il y a un seul espace entre les mots !')\n9\n>>> nombre_de_mots('Combien de mots y a t il dans cette phrase ?')\n10\n>>> nombre_de_mots('Fin.')\n1\n
def nombre_de_mots(phrase):\n nb_mots = 0\n for caractere in phrase:\n if caractere == ' ' or caractere == '.':\n nb_mots += 1\n return nb_mots\n
Pour cet exercice :\n\n- On appelle \u00ab mot \u00bb une cha\u00eene de caract\u00e8res compos\u00e9e avec des caract\u00e8res choisis\nparmi les 26 lettres minuscules ou majuscules de l'alphabet,\n\n- On appelle \u00ab phrase \u00bb une cha\u00eene de caract\u00e8res :\n - compos\u00e9e avec un ou plusieurs \u00ab mots \u00bb s\u00e9par\u00e9s entre eux par un seul\ncaract\u00e8re espace `' '`,\n - se finissant :\n - soit par un point `'.'` qui est alors coll\u00e9 au dernier mot,\n - soit par un point d'exclamation `'!'` ou d'interrogation `'?'` qui est alors\ns\u00e9par\u00e9 du dernier mot par un seul caract\u00e8re espace `' '`.\n\n*Exemples :*\n\n- 'Cet exercice est simple.'\n- 'Le point d exclamation est separe !'\n\nApr\u00e8s avoir remarqu\u00e9 le lien entre le nombre de mots et le nombres de caract\u00e8res espace\ndans une phrase, programmer une fonction `nombre_de_mots` qui prend en param\u00e8tre une\nphrase et renvoie le nombre de mots pr\u00e9sents dans cette phrase.\n\n```python\n>>> nombre_de_mots('Le point d exclamation est separe !')\n6\n>>> nombre_de_mots('Il y a un seul espace entre les mots !')\n9\n>>> nombre_de_mots('Combien de mots y a t il dans cette phrase ?')\n10\n>>> nombre_de_mots('Fin.')\n1\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-402","title":"Exercice 40.2","text":"Exercice 40.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa classe ABR ci-dessous permet d'impl\u00e9menter une structure d'arbre binaire de recherche.
class Noeud:\n def __init__(self, valeur):\n'''M\u00e9thode constructeur pour la classe Noeud.\n Param\u00e8tre d'entr\u00e9e : valeur (str)'''\n self.valeur = valeur\n self.gauche = None\n self.droit = None\n\n def getValeur(self):\n'''M\u00e9thode accesseur pour obtenir la valeur du noeud\n Aucun param\u00e8tre en entr\u00e9e'''\n return self.valeur\n\n def droitExiste(self):\n'''M\u00e9thode renvoyant True si l'enfant droit existe\n Aucun param\u00e8tre en entr\u00e9e'''\n return (self.droit is not None)\n\n def gaucheExiste(self):\n'''M\u00e9thode renvoyant True si l'enfant gauche existe\n Aucun param\u00e8tre en entr\u00e9e'''\n return (self.gauche is not None)\n\n def inserer(self, cle):\n'''M\u00e9thode d'insertion de cl\u00e9 dans un arbre binaire de recherche\n Param\u00e8tre d'entr\u00e9e : cle (int)'''\n if cle < ...:\n # on ins\u00e8re \u00e0 gauche\n if self.gaucheExiste():\n # on descend \u00e0 gauche et on retente l'insertion de la cl\u00e9\n ...\n else:\n # on cr\u00e9e un fils gauche\n self.gauche = ...\n elif cle > ... :\n # on ins\u00e8re \u00e0 droite\n if ... :\n # on descend \u00e0 droite et on retente l'insertion de la cl\u00e9\n ...\n else:\n # on cr\u00e9e un fils droit\n ... = Noeud(cle)\n
Compl\u00e9ter la fonction r\u00e9cursive inserer
afin qu'elle permette d\u2019ins\u00e9rer un n\u0153ud dans l\u2019arbre binaire de recherche propos\u00e9, \u00e0 l\u2019aide de sa cl\u00e9.
Voici un exemple d'utilisation :
>>> arbre = Noeud(7)\n>>> for cle in (3, 9, 1, 6):\n arbre.inserer(cle)\n>>> arbre.gauche.getValeur()\n3\n>>> arbre.droit.getValeur()\n9\n>>> arbre.gauche.gauche.getValeur()\n1\n>>> arbre.gauche.droit.getValeur()\n6\n
class Noeud:\n def __init__(self, valeur):\n'''M\u00e9thode constructeur pour la classe Noeud.\n Param\u00e8tre d'entr\u00e9e : valeur (str)'''\n self.valeur = valeur\n self.gauche = None\n self.droit = None\n\n def getValeur(self):\n'''M\u00e9thode accesseur pour obtenir la valeur du noeud\n Aucun param\u00e8tre en entr\u00e9e'''\n return self.valeur\n\n def droitExiste(self):\n'''M\u00e9thode renvoyant True si l'enfant droit existe\n Aucun param\u00e8tre en entr\u00e9e'''\n return (self.droit is not None)\n\n def gaucheExiste(self):\n'''M\u00e9thode renvoyant True si l'enfant gauche existe\n Aucun param\u00e8tre en entr\u00e9e'''\n return (self.gauche is not None)\n\n def inserer(self, cle):\n'''M\u00e9thode d'insertion de cl\u00e9 dans un arbre binaire de recherche\n Param\u00e8tre d'entr\u00e9e : cle (int)'''\nif cle < self.valeur:\n# on ins\u00e8re \u00e0 gauche\n if self.gaucheExiste():\n # on descend \u00e0 gauche et on retente l'insertion de la cl\u00e9\nself.gauche.inserer(cle)\nelse:\n # on cr\u00e9e un fils gauche\nself.gauche = Noeud(cle)\nelif cle > self.valeur:\n# on ins\u00e8re \u00e0 droite\nif self.droitExiste():\n# on descend \u00e0 droite et on retente l'insertion de la cl\u00e9\nself.droit.inserer(cle)\nelse:\n # on cr\u00e9e un fils droit\nself.droit = Noeud(cle)\n
La classe ABR ci-dessous permet d'impl\u00e9menter une structure d'arbre binaire de recherche.\n\n```python linenums='1'\nclass Noeud:\n def __init__(self, valeur):\n '''M\u00e9thode constructeur pour la classe Noeud.\n Param\u00e8tre d'entr\u00e9e : valeur (str)'''\n self.valeur = valeur\n self.gauche = None\n self.droit = None\n\n def getValeur(self):\n '''M\u00e9thode accesseur pour obtenir la valeur du noeud\n Aucun param\u00e8tre en entr\u00e9e'''\n return self.valeur\n\n def droitExiste(self):\n '''M\u00e9thode renvoyant True si l'enfant droit existe\n Aucun param\u00e8tre en entr\u00e9e'''\n return (self.droit is not None)\n\n def gaucheExiste(self):\n '''M\u00e9thode renvoyant True si l'enfant gauche existe\n Aucun param\u00e8tre en entr\u00e9e'''\n return (self.gauche is not None)\n\n def inserer(self, cle):\n '''M\u00e9thode d'insertion de cl\u00e9 dans un arbre binaire de recherche\n Param\u00e8tre d'entr\u00e9e : cle (int)'''\n if cle < ...:\n # on ins\u00e8re \u00e0 gauche\n if self.gaucheExiste():\n # on descend \u00e0 gauche et on retente l'insertion de la cl\u00e9\n ...\n else:\n # on cr\u00e9e un fils gauche\n self.gauche = ...\n elif cle > ... :\n # on ins\u00e8re \u00e0 droite\n if ... :\n # on descend \u00e0 droite et on retente l'insertion de la cl\u00e9\n ...\n else:\n # on cr\u00e9e un fils droit\n ... = Noeud(cle)\n
Compl\u00e9ter la fonction r\u00e9cursive inserer
afin qu'elle permette d\u2019ins\u00e9rer un n\u0153ud dans l\u2019arbre binaire de recherche propos\u00e9, \u00e0 l\u2019aide de sa cl\u00e9.
Voici un exemple d'utilisation :
>>> arbre = Noeud(7)\n>>> for cle in (3, 9, 1, 6):\n arbre.inserer(cle)\n>>> arbre.gauche.getValeur()\n3\n>>> arbre.droit.getValeur()\n9\n>>> arbre.gauche.gauche.getValeur()\n1\n>>> arbre.gauche.droit.getValeur()\n6\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-41","title":"\u25b6 Sujet 41","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-411","title":"Exercice 41.1","text":"Exercice 41.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction recherche(caractere, chaine)
qui prend en param\u00e8tres caractere
, un unique caract\u00e8re (c\u2019est-\u00e0-dire une cha\u00eene de caract\u00e8re de longueur 1), et chaine
, une cha\u00eene de caract\u00e8res. Cette fonction renvoie le nombre d\u2019occurrences de caractere
dans chaine
, c\u2019est-\u00e0-dire le nombre de fois o\u00f9 caractere
appara\u00eet dans chaine.
Exemples :
>>> recherche('e', \"sciences\")\n2\n>>> recherche('i',\"mississippi\")\n4\n>>> recherche('a',\"mississippi\")\n0\n
def recherche(caractere, chaine):\n somme = 0\n for lettre in chaine:\n if lettre == caractere:\n somme += 1\n return somme\n
\u00c9crire une fonction `recherche(caractere, chaine)` qui prend en param\u00e8tres\n`caractere`, un unique caract\u00e8re (c\u2019est-\u00e0-dire une cha\u00eene de caract\u00e8re de longueur 1),\net `chaine`, une cha\u00eene de caract\u00e8res. Cette fonction renvoie le nombre d\u2019occurrences\nde `caractere` dans `chaine`, c\u2019est-\u00e0-dire le nombre de fois o\u00f9 `caractere` appara\u00eet\ndans chaine.\n\nExemples :\n```python\n>>> recherche('e', \"sciences\")\n2\n>>> recherche('i',\"mississippi\")\n4\n>>> recherche('a',\"mississippi\")\n0\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-412","title":"Exercice 41.2","text":"Exercice 41.2
\u00c9nonc\u00e9CorrectionSources MarkdownOn s\u2019int\u00e9resse \u00e0 un algorithme r\u00e9cursif qui permet de rendre la monnaie \u00e0 partir d\u2019une liste donn\u00e9e de valeurs de pi\u00e8ces et de billets.
Le syst\u00e8me mon\u00e9taire est donn\u00e9 sous forme d\u2019une liste valeurs = [100, 50, 20, 10, 5, 2, 1]
. On suppose que les pi\u00e8ces et billets sont disponibles sans limitation.
On cherche \u00e0 donner la liste des valeurs \u00e0 rendre pour une somme donn\u00e9e en argument. L\u2019algorithme utilis\u00e9 est de type glouton.
Compl\u00e9ter le code Python ci-dessous de la fonction rendu_glouton
qui impl\u00e9mente cet algorithme et renvoie la liste des pi\u00e8ces \u00e0 rendre.
valeurs = [100, 50, 20, 10, 5, 2, 1]\n\ndef rendu_glouton(a_rendre, rang):\n if a_rendre == 0:\n return ...\n v = valeurs[rang]\n if v <= ... :\n return ... + rendu_glouton(a_rendre - v, rang)\n else :\n return rendu_glouton(a_rendre, ...)\n
On devra obtenir :
>>>rendu_glouton(67, 0)\n[50, 10, 5, 2]\n>>>rendu_glouton(291, 0)\n[100, 100, 50, 20, 20, 1]\n>>> rendu_glouton(291,1) # si on ne dispose pas de billets de 100\n[50, 50, 50, 50, 50, 20, 20, 1]\n
valeurs = [100,50,20,10,5,2,1]\n\ndef rendu_glouton(a_rendre, rang):\n if a_rendre == 0:\nreturn []\nv = valeurs[rang]\nif v <= a_rendre :\nreturn [v] + rendu_glouton(a_rendre - v, rang)\nelse :\nreturn rendu_glouton(a_rendre, rang + 1)\n
On s\u2019int\u00e9resse \u00e0 un algorithme r\u00e9cursif qui permet de rendre la monnaie \u00e0 partir d\u2019une\nliste donn\u00e9e de valeurs de pi\u00e8ces et de billets.\n\nLe syst\u00e8me mon\u00e9taire est donn\u00e9 sous forme d\u2019une liste `valeurs = [100, 50, 20,\n10, 5, 2, 1]`. On suppose que les pi\u00e8ces et billets sont disponibles sans limitation.\n\n\nOn cherche \u00e0 donner la liste des valeurs \u00e0 rendre pour une somme donn\u00e9e en\nargument. L\u2019algorithme utilis\u00e9 est de type glouton.\n\nCompl\u00e9ter le code Python ci-dessous de la fonction `rendu_glouton` qui impl\u00e9mente cet\nalgorithme et renvoie la liste des pi\u00e8ces \u00e0 rendre.\n\n```python linenums='1'\nvaleurs = [100, 50, 20, 10, 5, 2, 1]\n\ndef rendu_glouton(a_rendre, rang):\n if a_rendre == 0:\n return ...\n v = valeurs[rang]\n if v <= ... :\n return ... + rendu_glouton(a_rendre - v, rang)\n else :\n return rendu_glouton(a_rendre, ...)\n
On devra obtenir :
>>>rendu_glouton(67, 0)\n[50, 10, 5, 2]\n>>>rendu_glouton(291, 0)\n[100, 100, 50, 20, 20, 1]\n>>> rendu_glouton(291,1) # si on ne dispose pas de billets de 100\n[50, 50, 50, 50, 50, 20, 20, 1]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-42","title":"\u25b6 Sujet 42","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-421","title":"Exercice 42.1","text":"Exercice 42.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction tri_selection
qui prend en param\u00e8tre une liste tab
de nombres entiers et qui renvoie la liste tri\u00e9e par ordre croissant. Il est demand\u00e9 de ne pas cr\u00e9er de nouvelle liste mais de modifier celle fournie.
On utilisera l\u2019algorithme suivant :
Exemple :
>>> tri_selection([1, 52, 6, -9, 12])\n[-9, 1, 6, 12, 52]\n
def tri_selection(tab):\n for i in range(len(tab)-1):\n indice_min = i\n for j in range(i+1, len(tab)):\n if tab[j] < tab[indice_min]:\n indice_min = j\n tab[i], tab[indice_min] = tab[indice_min], tab[i]\n return tab\n
\u00c9crire une fonction `tri_selection` qui prend en param\u00e8tre une liste `tab` de nombres\nentiers et qui renvoie la liste tri\u00e9e par ordre croissant. Il est demand\u00e9 de ne pas cr\u00e9er de\nnouvelle liste mais de modifier celle fournie.\n\nOn utilisera l\u2019algorithme suivant :\n\n- on recherche le plus petit \u00e9l\u00e9ment de la liste, en la parcourant du rang 0 au dernier\nrang, et on l'\u00e9change avec l'\u00e9l\u00e9ment d'indice 0 ;\n- on recherche ensuite le plus petit \u00e9l\u00e9ment de la liste restreinte du rang 1 au dernier\nrang, et on l'\u00e9change avec l'\u00e9l\u00e9ment d'indice 1 ;\n- on continue de cette fa\u00e7on jusqu'\u00e0 ce que la liste soit enti\u00e8rement tri\u00e9e.\n\nExemple :\n```python\n>>> tri_selection([1, 52, 6, -9, 12])\n[-9, 1, 6, 12, 52]\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-422","title":"Exercice 42.2","text":"Exercice 42.2
\u00c9nonc\u00e9CorrectionSources MarkdownLe jeu du \u00ab plus ou moins \u00bb consiste \u00e0 deviner un nombre entier choisi entre 1 et 99.
Un \u00e9l\u00e8ve de NSI d\u00e9cide de le coder en langage Python de la mani\u00e8re suivante :
La fonction randint
est utilis\u00e9e. Si a et b sont des entiers tels que a <= b
, randint(a,b)
renvoie un nombre entier compris entre a
et b
.
Compl\u00e9ter le code ci-dessous et le tester :
from random import randint\n\ndef plus_ou_moins():\n nb_mystere = randint(1,...)\n nb_test = int(input(\"Proposez un nombre entre 1 et 99 : \"))\n compteur = ...\n\n while nb_mystere != ... and compteur < ... :\n compteur = compteur + ...\n if nb_mystere ... nb_test:\n nb_test = int(input(\"Trop petit ! Testez encore : \"))\n else:\n nb_test = int(input(\"Trop grand ! Testez encore : \"))\n\n if nb_mystere == nb_test:\n print (\"Bravo ! Le nombre \u00e9tait \",...)\n print(\"Nombre d'essais: \",...)\n else:\n print (\"Perdu ! Le nombre \u00e9tait \",...)\n
from random import randint\n\ndef plus_ou_moins():\nnb_mystere = randint(1,99)\nnb_test = int(input('Proposez un nombre entre 1 et 99 : '))\ncompteur = 1\nwhile nb_mystere != nb_test and compteur < 10 :\ncompteur = compteur + 1\nif nb_mystere > nb_test:\nnb_test = int(input('Trop petit ! Testez encore : '))\n else:\n nb_test = int(input('Trop grand ! Testez encore : '))\n\n if nb_mystere == nb_test:\nprint ('Bravo ! Le nombre \u00e9tait ', nb_mystere)\nprint('Nombre d essais: ', compteur)\nelse:\nprint ('Perdu ! Le nombre \u00e9tait ', nb_mystere)\n
Le jeu du \u00ab plus ou moins \u00bb consiste \u00e0 deviner un nombre entier choisi entre 1 et 99.\n\nUn \u00e9l\u00e8ve de NSI d\u00e9cide de le coder en langage Python de la mani\u00e8re suivante :\n\n- le programme g\u00e9n\u00e8re un nombre entier al\u00e9atoire compris entre 1 et 99 ;\n- si la proposition de l\u2019utilisateur est plus petite que le nombre cherch\u00e9, l\u2019utilisateur en\nest averti. Il peut alors en tester un autre ;\n- si la proposition de l\u2019utilisateur est plus grande que le nombre cherch\u00e9, l\u2019utilisateur en\nest averti. Il peut alors en tester un autre ;\n- si l\u2019utilisateur trouve le bon nombre en 10 essais ou moins, il gagne ;\n- si l\u2019utilisateur a fait plus de 10 essais sans trouver le bon nombre, il perd.\n\nLa fonction `randint` est utilis\u00e9e. \nSi a et b sont des entiers tels que `a <= b`, `randint(a,b)` renvoie un\nnombre entier compris entre `a` et `b`.\n\n\nCompl\u00e9ter le code ci-dessous et le tester :\n\n```python linenums='1'\nfrom random import randint\n\ndef plus_ou_moins():\n nb_mystere = randint(1,...)\n nb_test = int(input(\"Proposez un nombre entre 1 et 99 : \"))\n compteur = ...\n\n while nb_mystere != ... and compteur < ... :\n compteur = compteur + ...\n if nb_mystere ... nb_test:\n nb_test = int(input(\"Trop petit ! Testez encore : \"))\n else:\n nb_test = int(input(\"Trop grand ! Testez encore : \"))\n\n if nb_mystere == nb_test:\n print (\"Bravo ! Le nombre \u00e9tait \",...)\n print(\"Nombre d'essais: \",...)\n else:\n print (\"Perdu ! Le nombre \u00e9tait \",...)\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-43","title":"\u25b6 Sujet 43","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-431","title":"Exercice 43.1","text":"Exercice 43.1
\u00c9nonc\u00e9CorrectionSource Markdown\u00c9crire une fonction ecriture_binaire_entier_positif
qui prend en param\u00e8tre un entier positif n
et renvoie une liste d'entiers correspondant \u00e0 l\u2018\u00e9criture binaire de n
.
Ne pas oublier d\u2019ajouter au corps de la fonction une documentation et une ou plusieurs assertions pour v\u00e9rifier les pr\u00e9-conditions.
Exemples :
>>> ecriture_binaire_entier_positif(0)\n[0]\n>>> ecriture_binaire_entier_positif(2)\n[1, 0]\n>>> ecriture_binaire_entier_positif(105)\n[1, 1, 0, 1, 0, 0, 1]\n
Aide :
//
donne le quotient de la division euclidienne : 5//2
donne 2
;%
donne le reste de la division euclidienne :5%2
donne 1
;append
est une m\u00e9thode qui ajoute un \u00e9l\u00e9ment \u00e0 une liste existante : Soit T=[5,2,4]
, alors T.append(10)
ajoute 10
\u00e0 la liste T
. Ainsi, T
devient [5,2,4,10]
.reverse
est une m\u00e9thode qui renverse les \u00e9l\u00e9ments d'une liste. Soit T=[5,2,4,10]
. Apr\u00e8s T.reverse()
, la liste devient [10,4,2,5]
.On remarquera qu\u2019on r\u00e9cup\u00e8re la repr\u00e9sentation binaire d\u2019un entier n
en partant de la gauche en appliquant successivement les instructions :
b = n%2
n = n//2
r\u00e9p\u00e9t\u00e9es autant que n\u00e9cessaire.
def ecriture_binaire_entier_positif(n):\n # cas particulier pour n = 0\n if n == 0:\n return [0]\n # cas g\u00e9n\u00e9ral\n b = []\n while n != 0:\n b.append(n % 2)\n n = n // 2\n b.reverse()\n return b\n
\u00c9crire une fonction `ecriture_binaire_entier_positif` qui prend en param\u00e8tre un\nentier positif `n` et renvoie une liste d'entiers correspondant \u00e0 l\u2018\u00e9criture binaire de `n`.\n\nNe pas oublier d\u2019ajouter au corps de la fonction une documentation et une ou plusieurs\nassertions pour v\u00e9rifier les pr\u00e9-conditions.\n\nExemples :\n\n```python\n>>> ecriture_binaire_entier_positif(0)\n[0]\n>>> ecriture_binaire_entier_positif(2)\n[1, 0]\n>>> ecriture_binaire_entier_positif(105)\n[1, 1, 0, 1, 0, 0, 1]\n```\n\nAide :\n\n- l'op\u00e9rateur `//` donne le quotient de la division euclidienne : `5//2` donne `2` ;\n- l'op\u00e9rateur `%` donne le reste de la division euclidienne :` 5%2` donne `1` ;\n- `append` est une m\u00e9thode qui ajoute un \u00e9l\u00e9ment \u00e0 une liste existante :\nSoit `T=[5,2,4]`, alors `T.append(10)` ajoute `10` \u00e0 la liste `T`. Ainsi, `T` devient\n`[5,2,4,10]`.\n- `reverse` est une m\u00e9thode qui renverse les \u00e9l\u00e9ments d'une liste.\nSoit `T=[5,2,4,10]`. Apr\u00e8s `T.reverse()`, la liste devient `[10,4,2,5]`.\n\nOn remarquera qu\u2019on r\u00e9cup\u00e8re la repr\u00e9sentation binaire d\u2019un entier `n` en partant de la gauche en appliquant successivement les instructions :\n\n`b = n%2`\n\n`n = n//2`\n\nr\u00e9p\u00e9t\u00e9es autant que n\u00e9cessaire.\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-432","title":"Exercice 43.2","text":"Exercice 43.2
\u00c9nonc\u00e9CorrectionSources MarkdownLa fonction tri_bulles
prend en param\u00e8tre une liste T
d\u2019entiers non tri\u00e9s et renvoie la liste tri\u00e9e par ordre croissant.
Le tri \u00e0 bulles est un tri en place qui commence par placer le plus grand \u00e9l\u00e9ment en derni\u00e8re position en parcourant la liste de gauche \u00e0 droite et en \u00e9changeant au passage les \u00e9l\u00e9ments voisins mal ordonn\u00e9s (si la valeur de l\u2019\u00e9l\u00e9ment d\u2019indice i
a une valeur strictement sup\u00e9rieure \u00e0 celle de l\u2019indice i + 1
, ils sont \u00e9chang\u00e9s). Le tri place ensuite en avant-derni\u00e8re position le plus grand \u00e9l\u00e9ment de la liste priv\u00e9e de son dernier \u00e9l\u00e9ment en proc\u00e9dant encore \u00e0 des \u00e9changes d\u2019\u00e9l\u00e9ments voisins. Ce principe est r\u00e9p\u00e9t\u00e9 jusqu\u2019\u00e0 placer le minimum en premi\u00e8re position.
Exemple : pour trier la liste [7, 9, 4, 3]
:
[7, 4, 3, 9]
[4, 3, 7, 9]
[3, 4, 7, 9]
Compl\u00e9ter le code Python ci-dessous qui impl\u00e9mente la fonction tri_bulles.
def tri_bulles(T):\n'''\n Renvoie le tableau T tri\u00e9 par ordre croissant\n '''\n n = len(T)\n for i in range(...,...,-1):\n for j in range(i):\n if T[j] > T[...]:\n ... = T[j]\n T[j] = T[...]\n T[j+1] = temp\n return T\n
Exemples :
>>> tri_bulles([])\n[]\n>>> tri_bulles([7])\n[7]\n>>> tri_bulles([9, 3, 7, 2, 3, 1, 6])\n[1, 2, 3, 3, 6, 7, 9]\n>>> tri_bulles([9, 7, 4, 3])\n[3, 4, 7, 9]\n
def tri_bulles(T):\n'''\n Renvoie le tableau T tri\u00e9 par ordre croissant\n '''\n n = len(T)\nfor i in range(n-1,-1,-1):\nfor j in range(i):\nif T[j] > T[j+1]:\ntemp = T[j]\nT[j] = T[j+1]\nT[j+1] = temp\n return T\n
La fonction `tri_bulles` prend en param\u00e8tre une liste `T` d\u2019entiers non tri\u00e9s et renvoie la\nliste tri\u00e9e par ordre croissant.\n\n\nLe tri \u00e0 bulles est un tri en place qui commence par placer le plus grand \u00e9l\u00e9ment en\nderni\u00e8re position en parcourant la liste de gauche \u00e0 droite et en \u00e9changeant au passage\nles \u00e9l\u00e9ments voisins mal ordonn\u00e9s (si la valeur de l\u2019\u00e9l\u00e9ment d\u2019indice `i` a une valeur\nstrictement sup\u00e9rieure \u00e0 celle de l\u2019indice `i + 1`, ils sont \u00e9chang\u00e9s). Le tri place ensuite\nen avant-derni\u00e8re position le plus grand \u00e9l\u00e9ment de la liste priv\u00e9e de son dernier \u00e9l\u00e9ment\nen proc\u00e9dant encore \u00e0 des \u00e9changes d\u2019\u00e9l\u00e9ments voisins. Ce principe est r\u00e9p\u00e9t\u00e9 jusqu\u2019\u00e0\nplacer le minimum en premi\u00e8re position.\n\n\nExemple : pour trier la liste `[7, 9, 4, 3]` :\n\n- premi\u00e8re \u00e9tape : 7 et 9 ne sont pas \u00e9chang\u00e9s, puis 9 et 4 sont \u00e9chang\u00e9s, puis 9 et\n3 sont \u00e9chang\u00e9s, la liste est alors `[7, 4, 3, 9]`\n- deuxi\u00e8me \u00e9tape : 7 et 4 sont \u00e9chang\u00e9s, puis 7 et 3 sont \u00e9chang\u00e9s, la liste est\nalors `[4, 3, 7, 9]`\n- troisi\u00e8me \u00e9tape : 4 et 3 sont \u00e9chang\u00e9s, la liste est alors `[3, 4, 7, 9]`\n\n\nCompl\u00e9ter le code Python ci-dessous qui impl\u00e9mente la fonction tri_bulles.\n\n```python linenums='1'\ndef tri_bulles(T):\n '''\n Renvoie le tableau T tri\u00e9 par ordre croissant\n '''\n n = len(T)\n for i in range(...,...,-1):\n for j in range(i):\n if T[j] > T[...]:\n ... = T[j]\n T[j] = T[...]\n T[j+1] = temp\n return T\n
Exemples :
>>> tri_bulles([])\n[]\n>>> tri_bulles([7])\n[7]\n>>> tri_bulles([9, 3, 7, 2, 3, 1, 6])\n[1, 2, 3, 3, 6, 7, 9]\n>>> tri_bulles([9, 7, 4, 3])\n[3, 4, 7, 9]\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-44","title":"\u25b6 Sujet 44","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-441","title":"Exercice 44.1","text":"Exercice 44.1
\u00c9nonc\u00e9CorrectionSource MarkdownProgrammer une fonction renverse
, prenant en param\u00e8tre une cha\u00eene de caract\u00e8res non vide mot
et renvoie une cha\u00eene de caract\u00e8res en inversant ceux de la cha\u00eene mot
.
Exemple :
>>> renverse(\"informatique\")\n\"euqitamrofni\"\n
def renverse(mot):\n sol = ''\n for lettre in mot:\n sol = lettre + sol\n return sol\n
Programmer une fonction `renverse`, prenant en param\u00e8tre une cha\u00eene de caract\u00e8res non vide\n`mot` et renvoie une cha\u00eene de caract\u00e8res en inversant ceux de la cha\u00eene `mot`.\n\nExemple :\n\n```python\n>>> renverse(\"informatique\")\n\"euqitamrofni\"\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-442","title":"Exercice 44.2","text":"Exercice 44.2
\u00c9nonc\u00e9CorrectionSources MarkdownUn nombre premier est un nombre entier naturel qui admet exactement deux diviseurs distincts entiers et positifs : 1 et lui-m\u00eame.
Le crible d\u2019\u00c9ratosth\u00e8ne permet de d\u00e9terminer les nombres premiers plus petit qu\u2019un certain nombre n
fix\u00e9.
On consid\u00e8re pour cela un tableau tab
de n
bool\u00e9ens, initialement tous \u00e9gaux \u00e0 True
, sauf tab[0]
et tab[1]
qui valent False
, 0 et 1 n\u2019\u00e9tant pas des nombres premiers.
On parcourt alors ce tableau de gauche \u00e0 droite.
Pour chaque indice i
:
si tab[i]
vaut True
: le nombre i
est premier et on donne la valeur False
\u00e0 toutes les cases du tableau dont l\u2019indice est un multiple de i
, \u00e0 partir de 2*i
(c\u2019est-\u00e0-dire 2*i
, 3*i
...).
si tab[i]
vaut False
: le nombre i
n\u2019est pas premier et on n\u2019effectue aucun changement sur le tableau.
On dispose de la fonction crible
, incompl\u00e8te et donn\u00e9e ci-dessous, prenant en param\u00e8tre un entier n
strictement positif et renvoyant un tableau contenant tous les nombres premiers plus petits que n
.
def crible(n):\n\"\"\"\n Renvoie un tableau contenant tous les nombres premiers plus petits que N\n \"\"\"\n premiers = []\n tab = [True] * n\n tab[0], tab[1] = False, False\n for i in range(..., n):\n if tab[i] == ...:\n premiers.append(...)\n for multiple in range(2*i, n, ...):\n tab[multiple] = ...\n return premiers\n\nassert crible(40) == [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]\n
Compl\u00e9ter le code de cette fonction.
def crible(n):\n\"\"\"\n Renvoie un tableau contenant tous les nombres premiers plus petits que N\n \"\"\"\n premiers = []\n tab = [True] * n\n tab[0], tab[1] = False, False\nfor i in range(2, n):\nif tab[i] == True:\npremiers.append(i)\nfor multiple in range(2*i, n, i):\ntab[multiple] = False\nreturn premiers\n\nassert crible(40) == [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]\n
Un nombre premier est un nombre entier naturel qui admet exactement deux diviseurs distincts\nentiers et positifs : 1 et lui-m\u00eame. \n\nLe crible d\u2019\u00c9ratosth\u00e8ne permet de d\u00e9terminer les nombres premiers plus petit qu\u2019un certain\nnombre `n` fix\u00e9. \n\nOn consid\u00e8re pour cela un tableau `tab` de `n`bool\u00e9ens, initialement tous \u00e9gaux \u00e0 `True`, sauf\n`tab[0]` et `tab[1]` qui valent `False`, 0 et 1 n\u2019\u00e9tant pas des nombres premiers. \n\nOn parcourt alors ce tableau de gauche \u00e0 droite. \n\nPour chaque indice `i` :\n\n- si `tab[i]` vaut `True` : le nombre `i` est premier et on donne la valeur `False` \u00e0 toutes les\ncases du tableau dont l\u2019indice est un multiple de `i`, \u00e0 partir de `2*i` (c\u2019est-\u00e0-dire `2*i`, `3*i` ...).\n\n- si `tab[i]` vaut `False` : le nombre `i` n\u2019est pas premier et on n\u2019effectue aucun\nchangement sur le tableau. \n\nOn dispose de la fonction `crible`, incompl\u00e8te et donn\u00e9e ci-dessous, prenant en param\u00e8tre un\nentier `n` strictement positif et renvoyant un tableau contenant tous les nombres premiers plus\npetits que `n`.\n\n```python linenums='1'\ndef crible(n):\n \"\"\"\n Renvoie un tableau contenant tous les nombres premiers plus petits que N\n \"\"\"\n premiers = []\n tab = [True] * n\n tab[0], tab[1] = False, False\n for i in range(..., n):\n if tab[i] == ...:\n premiers.append(...)\n for multiple in range(2*i, n, ...):\n tab[multiple] = ...\n return premiers\n\nassert crible(40) == [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]\n
Compl\u00e9ter le code de cette fonction.
```
Compl\u00e9tez le code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#sujet-45","title":"\u25b6 Sujet 45","text":"Version originale du sujet en pdf.
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-451","title":"Exercice 45.1","text":"Exercice 45.1
\u00c9nonc\u00e9CorrectionSource MarkdownOn veut trier par ordre croissant les notes d\u2019une \u00e9valuation qui sont des nombres entiers compris entre 0 et 10 (inclus).
Ces notes sont contenues dans une liste notes_eval
.
\u00c9crire une fonction rangement_valeurs
prenant en param\u00e8tre la liste notes_eval
et renvoyant une liste de longueur 11 telle que la valeur de cette liste \u00e0 chaque rang est \u00e9gale au nombre de notes valant ce rang. Ainsi le terme de rang 0 indique le nombre de note 0, le terme de rang 1 le nombre de note 1, etc.
\u00c9crire ensuite une fonction notes_triees
prenant en param\u00e8tre la liste des effectifs des notes et renvoyant une liste contenant la liste, tri\u00e9e dans l\u2019ordre croissant, des notes des \u00e9l\u00e8ves.
Exemple :
>>> notes_eval = [2, 0, 5, 9, 6, 9, 10, 5, 7, 9, 9, 5, 0, 9, 6, 5, 4]\n\n>>> effectifs_notes = rangement_valeurs(notes_eval)\n>>> effectifs_notes\n[2, 0, 1, 0, 1, 4, 2, 1, 0, 5, 1]\n\n>>> notes_triees(effectifs_notes)\n[0, 0, 2, 4, 5, 5, 5, 5, 6, 6, 7, 9, 9, 9, 9, 9, 10]\n
def rangement_valeurs(notes_eval):\n lst = [0]*11\n for note in notes_eval:\n lst[note] += 1\n return lst\n\ndef notes_triees(effectifs_notes):\n triees = []\n for i in range(11):\n if effectifs_notes[i] != 0:\n for _ in range(effectifs_notes[i]):\n triees.append(i)\n return triees\n
On veut trier par ordre croissant les notes d\u2019une \u00e9valuation qui sont des nombres entiers\ncompris entre 0 et 10 (inclus).\n\nCes notes sont contenues dans une liste `notes_eval`.\n\n\u00c9crire une fonction `rangement_valeurs` prenant en param\u00e8tre la liste `notes_eval` et\nrenvoyant une liste de longueur 11 telle que la valeur de cette liste \u00e0 chaque rang est\n\u00e9gale au nombre de notes valant ce rang. Ainsi le terme de rang 0 indique le nombre de\nnote 0, le terme de rang 1 le nombre de note 1, etc.\n\n\u00c9crire ensuite une fonction `notes_triees` prenant en param\u00e8tre la liste des effectifs\ndes notes et renvoyant une liste contenant la liste, tri\u00e9e dans l\u2019ordre croissant, des notes\ndes \u00e9l\u00e8ves.\n\nExemple :\n\n```python\n>>> notes_eval = [2, 0, 5, 9, 6, 9, 10, 5, 7, 9, 9, 5, 0, 9, 6, 5, 4]\n\n>>> effectifs_notes = rangement_valeurs(notes_eval)\n>>> effectifs_notes\n[2, 0, 1, 0, 1, 4, 2, 1, 0, 5, 1]\n\n>>> notes_triees(effectifs_notes)\n[0, 0, 2, 4, 5, 5, 5, 5, 6, 6, 7, 9, 9, 9, 9, 9, 10]\n```\n
R\u00e9digez votre code sur Basthon
"},{"location":"T6_6_Epreuve_pratique/BNS_2023/#exercice-452","title":"Exercice 45.2","text":"Exercice 45.2
\u00c9nonc\u00e9CorrectionSources MarkdownL\u2019objectif de cet exercice est d\u2019\u00e9crire deux fonctions r\u00e9cursives dec_to_bin
et bin_to_dec
assurant respectivement la conversion de l\u2019\u00e9criture d\u00e9cimale d\u2019un nombre entier vers son \u00e9criture en binaire et, r\u00e9ciproquement, la conversion de l\u2019\u00e9criture en binaire d\u2019un nombre vers son \u00e9criture d\u00e9cimale.
Dans cet exercice, on s\u2019interdit l\u2019usage des fonctions Python bin
et int
.
On rappelle sur l\u2019exemple ci-dessous une fa\u00e7on d\u2019obtenir l\u2019\u00e9criture en binaire du nombre 25 :
\\(25 = 1 + 2 \\times 12\\) \\(\\phantom{25} = 1 + 2 \\times 12\\) \\(\\phantom{25} = 1 + 2 (0 + 2 \\times 6)\\) \\(\\phantom{25} = 1 + 2 (0 + 2 (0 + 2 \\times 3))\\) \\(\\phantom{25} = 1 + 2 (0 + 2 (0 + 2 (1 + 2 \\times 1)))\\) \\(\\phantom{25} = 1 \\times 2^0 + 0 \\times 2^1 + 0 \\times 2^2 + 1 \\times 2^3 + 1 \\times 2^4\\)
L'\u00e9criture binaire de 25 est donc 11001
.
0n rappelle \u00e9galement que :
a // 2
renvoie le quotient de la division euclidienne de a
par 2.a % 2
renvoie le reste dans la division euclidienne de a
par 2.On indique enfin qu\u2019en Python si mot = \"informatique\"
alors :
mot[-1]
renvoie 'e'
, c\u2019est-\u00e0-dire le dernier caract\u00e8re de la cha\u00eene de caract\u00e8res mot
.mot[:-1]
renvoie 'informatiqu'
, c\u2019est-\u00e0-dire l\u2019ensemble de la cha\u00eene de caract\u00e8res mot
priv\u00e9e de son dernier caract\u00e8re.Compl\u00e9ter, puis tester, les codes de deux fonctions ci-dessous. On pr\u00e9cise que la fonction r\u00e9cursive dec_to_bin
prend en param\u00e8tre un nombre entier et renvoie une cha\u00eene de caract\u00e8res contenant l\u2019\u00e9criture en binaire du nombre pass\u00e9 en param\u00e8tre.
Exemple :
>>> dec_to_bin(25)\n'11001'\n
La fonction r\u00e9cursive bin_to_dec
prend en param\u00e8tre une cha\u00eene de caract\u00e8res repr\u00e9sentant l\u2019\u00e9criture d\u2019un nombre en binaire et renvoie l\u2019\u00e9criture d\u00e9cimale de ce nombre.
>>> bin_to_dec('101010')\n42\n
def dec_to_bin(nb_dec):\n q, r = nb_dec // 2, nb_dec % 2\n if q == ...:\n return str(r)\n else:\n return dec_to_bin(...) + ...\n\ndef bin_to_dec(nb_bin):\n if nb_bin == '0':\n return 0\n elif ...:\n return 1\n else:\n if nb_bin[-1] == '0':\n bit_droit = 0\n else:\n bit_droit = ...\n return ... * bin_to_dec(nb_bin[:-1]) + ...\n
def dec_to_bin(nb_dec):\n q, r = nb_dec // 2, nb_dec % 2\nif q == 0:\nreturn str(r)\n else:\nreturn dec_to_bin(q) + str(r)\ndef bin_to_dec(nb_bin):\n if nb_bin == '0':\n return 0\nelif nb_bin == '1':\nreturn 1\n else:\n if nb_bin[-1] == '0':\n bit_droit = 0\n else:\nbit_droit = 1\nreturn 2 * bin_to_dec(nb_bin[:-1]) + bit_droit\n
L\u2019objectif de cet exercice est d\u2019\u00e9crire deux fonctions r\u00e9cursives `dec_to_bin` et\n`bin_to_dec` assurant respectivement la conversion de l\u2019\u00e9criture d\u00e9cimale d\u2019un nombre\nentier vers son \u00e9criture en binaire et, r\u00e9ciproquement, la conversion de l\u2019\u00e9criture en\nbinaire d\u2019un nombre vers son \u00e9criture d\u00e9cimale.\n\nDans cet exercice, on s\u2019interdit l\u2019usage des fonctions Python `bin` et `int`.\n\nOn rappelle sur l\u2019exemple ci-dessous une fa\u00e7on d\u2019obtenir l\u2019\u00e9criture en binaire du\nnombre 25 :\n\n$25 = 1 + 2 \\times 12$ \n$\\phantom{25} = 1 + 2 \\times 12$ \n$\\phantom{25} = 1 + 2 (0 + 2 \\times 6)$ \n$\\phantom{25} = 1 + 2 (0 + 2 (0 + 2 \\times 3))$ \n$\\phantom{25} = 1 + 2 (0 + 2 (0 + 2 (1 + 2 \\times 1)))$ \n$\\phantom{25} = 1 \\times 2^0 + 0 \\times 2^1 + 0 \\times 2^2 + 1 \\times 2^3 + 1 \\times 2^4$ \n\nL'\u00e9criture binaire de 25 est donc ```11001```.\n\n0n rappelle \u00e9galement que :\n\n- `a // 2` renvoie le quotient de la division euclidienne de `a` par 2.\n- ` a % 2` renvoie le reste dans la division euclidienne de `a` par 2.\n\nOn indique enfin qu\u2019en Python si `mot = \"informatique\"` alors :\n\n- `mot[-1]` renvoie `'e'`, c\u2019est-\u00e0-dire le dernier caract\u00e8re de la cha\u00eene de caract\u00e8res `mot`.\n- `mot[:-1]` renvoie `'informatiqu'` , c\u2019est-\u00e0-dire l\u2019ensemble de la cha\u00eene de\ncaract\u00e8res `mot` priv\u00e9e de son dernier caract\u00e8re.\n\nCompl\u00e9ter, puis tester, les codes de deux fonctions ci-dessous. \nOn pr\u00e9cise que la fonction r\u00e9cursive `dec_to_bin` prend en param\u00e8tre un nombre entier\net renvoie une cha\u00eene de caract\u00e8res contenant l\u2019\u00e9criture en binaire du nombre pass\u00e9 en\nparam\u00e8tre.\n\nExemple :\n\n```python\n>>> dec_to_bin(25)\n'11001'\n
La fonction r\u00e9cursive bin_to_dec
prend en param\u00e8tre une cha\u00eene de caract\u00e8res repr\u00e9sentant l\u2019\u00e9criture d\u2019un nombre en binaire et renvoie l\u2019\u00e9criture d\u00e9cimale de ce nombre.
>>> bin_to_dec('101010')\n42\n
def dec_to_bin(nb_dec):\n q, r = nb_dec // 2, nb_dec % 2\n if q == ...:\n return str(r)\n else:\n return dec_to_bin(...) + ...\n\ndef bin_to_dec(nb_bin):\n if nb_bin == '0':\n return 0\n elif ...:\n return 1\n else:\n if nb_bin[-1] == '0':\n bit_droit = 0\n else:\n bit_droit = ...\n return ... * bin_to_dec(nb_bin[:-1]) + ...\n
``` Compl\u00e9tez le code sur Basthon
"},{"location":"T6_Annales/epreuve_bac/","title":"\u00c9preuves du baccalaur\u00e9at","text":""},{"location":"T6_Annales/epreuve_bac/#modalites","title":"Modalit\u00e9s","text":"L'\u00e9preuve se partage en :
Pour r\u00e9sumer, on peut donc dire que la note sur 20 au bacaccalaur\u00e9at en NSI est constitu\u00e9e de 15 points d'\u00e9preuve \u00e9crite et de 5 points d'\u00e9preuve pratique.
"},{"location":"T6_Annales/epreuve_bac/#epreuve-pratique","title":"\u00c9preuve Pratique","text":"Textes r\u00e8glementaires
La partie pratique consiste en la r\u00e9solution de deux exercices sur ordinateur, chacun \u00e9tant not\u00e9 sur 10 points.
Le candidat est \u00e9valu\u00e9 sur la base d\u2019un dialogue avec un professeur-examinateur. Un examinateur \u00e9value au maximum quatre \u00e9l\u00e8ves. L\u2019examinateur ne peut pas \u00e9valuer un \u00e9l\u00e8ve qu\u2019il a eu en classe durant l\u2019ann\u00e9e en cours. L\u2019\u00e9valuation de cette partie se d\u00e9roule au cours du deuxi\u00e8me trimestre pendant la p\u00e9riode de l\u2019\u00e9preuve \u00e9crite de sp\u00e9cialit\u00e9.
Premier exercice
Le premier exercice consiste \u00e0 programmer un algorithme figurant explicitement au programme, ne pr\u00e9sentant pas de difficult\u00e9 particuli\u00e8re, dont on fournit une sp\u00e9cification. Il s\u2019agit donc de restituer un algorithme rencontr\u00e9 et travaill\u00e9 \u00e0 plusieurs reprises en cours de formation. Le sujet peut proposer un jeu de test avec les r\u00e9ponses attendues pour permettre au candidat de v\u00e9rifier son travail.
Deuxi\u00e8me exercice
Pour le second exercice, un programme est fourni au candidat. Cet exercice ne demande pas l\u2019\u00e9criture compl\u00e8te d\u2019un programme, mais permet de valider des comp\u00e9tences de programmation suivant des modalit\u00e9s vari\u00e9es : le candidat doit, par exemple, compl\u00e9ter un programme \u00ab \u00e0 trous \u00bb afin de r\u00e9pondre \u00e0 une sp\u00e9cification donn\u00e9e, ou encore compl\u00e9ter un programme pour le documenter, ou encore compl\u00e9ter un programme en ajoutant des assertions, etc.
"},{"location":"T6_Annales/epreuve_bac/#banque-dexercices","title":"Banque d'exercices","text":"Textes r\u00e8glementaires
Une page sp\u00e9cifique consacr\u00e9e aux exercices de la BNS est disponible ici.
"},{"location":"T6_Annales/epreuve_bac/#epreuve-ecrite","title":"\u00c9preuve \u00c9crite","text":"\u00c0 compter de la session 2023, l'\u00e9preuve consiste en trois exercices qui doivent tous \u00eatre trait\u00e9s. L'\u00e9preuve \u00e9crite donne lieu \u00e0 une note sur 20 points, coefficient 0.75.
Textes r\u00e8glementaires
Les annales des sujets pass\u00e9s (2020, 2021, 2022) comportent tous 5 exercices dont seulement 3 devaient \u00eatre trait\u00e9s. Ce n'est plus le cas depuis la session 2023 o\u00f9 la totalit\u00e9 du sujet doit \u00eatre trait\u00e9.
"},{"location":"T6_Annales/liste_sujets/","title":"Annales des \u00c9preuves \u00c9crites","text":""},{"location":"T6_Annales/liste_sujets/#2023","title":"2023","text":"Sujet
"},{"location":"T6_Annales/corrections/2022/corr_AmSudJ2_2022/#exercice-1","title":"Exercice 1","text":"Correction Q1def plus_proche_voisin(t, cible) :\n dmin = distance(t[0], cible)\n idx_ppv = 0\n n = len(t)\n for idx in range(1, n) :\nif distance(t[idx], cible) < dmin:\ndmin = distance(t[idx], cible)\nidx_ppv = idx\nreturn idx_ppv\n
Correction Q2 La complexit\u00e9 est lin\u00e9aire, car le nombre d'op\u00e9rations est proportionnel \u00e0 la taille du tableau t
.
Il suffit d'ins\u00e9rer la ligne dist = distance(obj, cible)
en dessous de la boucle for
et d'utiliser cette variable dist
partout \u00e0 la place de distance(obj, cible)
.
La complexit\u00e9 (m\u00eame r\u00e9p\u00e9t\u00e9e) d'une op\u00e9ration d'insertion d'un seul \u00e9l\u00e9ment \u00e0 sa bonne place dans une liste est moindre que celle d'un tri global. (NDLR : pas s\u00fbr)
Correction Q3.cdef insertion(kppv, idx, d):\n i = 0\n while d < kppv[i][1] and i < len(kppv):\n i += 1\n kppv.insert(i, (idx, d)) \n
"},{"location":"T6_Annales/corrections/2022/corr_AmSudJ2_2022/#exercice-2","title":"Exercice 2","text":""},{"location":"T6_Annales/corrections/2022/corr_AmSudJ2_2022/#partie-a","title":"Partie A","text":"Correction Q1 ifconfig
DHCP
(NDLR : question hors-programme)
192.168.1.1
C\u2019est possible et cette adresse serait celle de la box vers Internet.
Correction Q5Oui, car les adresses 192.168.x.x ne sont pas rout\u00e9es sur Internet.
"},{"location":"T6_Annales/corrections/2022/corr_AmSudJ2_2022/#partie-b","title":"Partie B","text":"Correction Q1\\(C = \\dfrac{10^9}{50 \\times 10^6}=\\dfrac{1000}{50}=20\\)
Correction Q2.a. Correction Q2.b.Suivant le protocole OSPF, il faut minimiser le co\u00fbt total. Il faut pour cela suivre le chemin R1-R3-R6-R7-R4-R5-R8, pour un co\u00fbt total de 80.
Correction Q3.c.Pour que le protocole OSPF fasse passer par la liaison R1-R4, il faut que celle-ci ait un co\u00fbt inf\u00e9rieur \u00e0 la liaison actuelle R1-R3-R6-R7-R4, qui a un co\u00fbt de 40. Il faut donc que le co\u00fbt R1-R4 soit inf\u00e9rieur \u00e0 40, ce qui sera le cas pour une bande passante sup\u00e9rieure \u00e0 25 Mb/s (car \\(\\dfrac{10^9}{25 \\times 10^6}=40\\))
"},{"location":"T6_Annales/corrections/2022/corr_AmSudJ2_2022/#exercice-3","title":"Exercice 3","text":"Correction Q1UPDATE ModeleVelo\nSET Stock = 0\nWHERE nomModele = \"Bovelo\";\n
Correction Q2 Il faut effectuer d'abord la requ\u00eate 4 (qui d\u00e9clare le nouveau fabricant, qui aura pour idFabricant
3127), puis la requ\u00eate 2 (o\u00f9 on peut retrouver l'id 3127).
SELECT nomModele, idFabricant\nFROM ModeleVelo\nWHERE Stock = 0;\n
Correction Q3.b. SELECT COUNT(numeroCommande)\nFROM Commande\nWHERE date >= '2022-01-01';\n
Correction Q3.c. SELECT Fabricant.nom\nFROM Fabricant\nJOIN ModeleVelo ON Fabricant.idFabricant = ModeleVelo.idFabricant\nWHERE ModeleVelo.Stock > 0\n
Correction Q4. Cette requ\u00eate permet d'obtenir le nom de tous les clients ayant achet\u00e9 le mod\u00e8le de v\u00e9lo \"Bovelo\". Si certains l'ont achet\u00e9 en plusieurs exemplaires, leur nom n'apparaitra qu'une seule fois.
"},{"location":"T6_Annales/corrections/2022/corr_AmSudJ2_2022/#exercice-4","title":"Exercice 4","text":"Correction Q1.a.from math import sqrt\n
Correction Q1.b. def distance_points(a, b):\n return sqrt((b[0]-a[0])**2 + (b[1]-a[1])**2)\n
Correction Q2. def distance(p, a, b):\n if a == b:\n return distance_points(p, a)\n else:\n return distance_point_droite(p, a, b)\n
Correction Q3. def le_plus_loin(ligne):\n n = len(ligne)\n deb = ligne[0]\n fin = ligne[n-1]\n dmax = 0\n indice_max = 0\n for idx in range(1, n-1):\np = ligne[idx]\nd = distance(p, deb, fin)\nif d > dmax:\ndmax = d\nindice_max = idx\nreturn (indice_max, dmax)\n
Correction Q4. def extrait(tab, i, j):\n ext = []\n for k in range(i, j+1):\n ext.append(tab[k])\n return ext\n
Correction Q5. def simplifie(ligne, seuil):\n n = len(ligne)\n if n <= 2:\n return ligne\n else:\n indice_max, dmax = le_plus_loin(ligne)\n if dmax <= seuil:\n return [ligne[0], ligne[n-1]]\n else:\n return simplifie(extrait(ligne, 0, indice_max), seuil) + \\\n simplifie(extrait(ligne, indice_max+1, n-1), seuil)\n
"},{"location":"T6_Annales/corrections/2022/corr_AmSudJ2_2022/#mise-en-pratique-de-lalgorithme-de-douglas-peucker-exercice-4","title":"Mise en pratique de l'algorithme de Douglas-Peucker (exercice 4)","text":"T\u00e9l\u00e9chargez d'abord le fichier coord_france.txt puis placez-le dans le m\u00eame dossier que le code Python ci-dessous :
from math import sqrt\nimport matplotlib.pyplot as plt\n\ndata = open('coord_france.txt').read().splitlines()\nfrance = []\nfor couple in data:\n cpl = couple.split(',')\n france.append((int(cpl[0]), int(cpl[1])))\n\ndef distance_points(a, b):\n return sqrt((b[0]-a[0])**2 + (b[1]-a[1])**2)\n\ndef distance_point_droite(p, a, b):\n if b[0] == a[0]:\n return abs(p[0]-a[0])\n m = (b[1] - a[1]) / (b[0] - a[0])\n od = a[1] - m*a[0]\n xm = (p[0]*(b[0]-a[0])+(p[1]-od)*(b[1]-a[1])) / (b[0]-a[0] + m*(b[1]-a[1]))\n ym = m*xm + od\n return distance_points(p, (xm, ym)) \n\ndef distance(p, a, b):\n if a == b:\n return distance_points(p, a)\n else:\n return distance_point_droite(p, a, b)\n\ndef le_plus_loin(ligne):\n n = len(ligne)\n deb = ligne[0]\n fin = ligne[n-1]\n dmax = 0\n indice_max = 0\n for idx in range(1, n-1):\n p = ligne[idx]\n d = distance(p, deb, fin)\n if d > dmax:\n dmax = d\n indice_max = idx\n return (indice_max, dmax)\n\n\ndef extrait(tab, i, j):\n ext = []\n for k in range(i, j+1):\n ext.append(tab[k])\n return ext\n\ndef simplifie(ligne, seuil):\n n = len(ligne)\n if n <= 2:\n return ligne\n else:\n indice_max, dmax = le_plus_loin(ligne)\n if dmax <= seuil:\n return [ligne[0], ligne[n-1]]\n else:\n return simplifie(extrait(ligne, 0, indice_max), seuil) + \\\n simplifie(extrait(ligne, indice_max+1, n-1), seuil)\n\n\ndef trace(ligne, seuil):\n new_ligne = simplifie(ligne, seuil)\n x = [p[0] for p in new_ligne]\n y = [p[1] for p in new_ligne]\n plt.plot(x, y, 'b-', linewidth=0.5)\n plt.text(195014, 2865745, 'seuil : ' + str(seuil))\n plt.axis('equal')\n plt.axis('off')\n plt.show()\n\ntrace(france, 0)\n
Le rendu avec un seuil \u00e9gal \u00e0 0 est celui-ci :
Vous pouvez faire varier le seuil entre 0 et 5000 et observer les modifications.
"},{"location":"T6_Annales/corrections/2022/corr_AmSudJ2_2022/#exercice-5","title":"Exercice 5","text":"Correction Q1La plus grande somme est 16, via la branche 2-7-4-3.
Correction Q2.a.a = Noeud(2)\na.modifier_sag(Noeud(7))\na.modifier_sad(Noeud(5))\na.sag.modifier_sag(Noeud(4))\na.sag.modifier_sad(Noeud(1))\na.sad.modifier_sad(Noeud(8))\n
Correction Q2.b. La m\u00e9thode niveau
renvoie 2 (qui est la hauteur de cet arbre, en prenant la convention que l'arbre r\u00e9duit \u00e0 son n\u0153ud-racine a une hauteur de 0).
def pgde_somme(self):\n if self.sag != None and self.sad != None:\n pgde_g = self.sag.pgde_somme()\n pgde_d = self.sad.pgde_somme()\n return self.etiquette + max(pgde_g, pgde_d)\n\n if self.sag != None:\n return self.sag.pgde_somme() + self.etiquette\n if self.sad != None:\n return self.sad.pgde_somme() + self.etiquette\n return self.etiquette \n
Correction Q4.a. Correction Q4.b. def est_magique(self):\n if self.sag != None and self.sad != None:\n return self.sag.est_magique() and self.sad.est_magique() \\\n and self.sag.pgde_somme() == self.sad.pgde_somme()\n if self.sag != None:\n return self.sag.est_magique()\n if self.sad != None:\n return self.sad.est_magique()\n return True \n
"},{"location":"T6_Annales/corrections/2023/corr_sujet0_A/","title":"Correction du sujet 0 version A / 2023","text":"Sujet
"},{"location":"T6_Annales/corrections/2023/corr_sujet0_A/#exercice-1","title":"Exercice 1","text":"correction Q1.Les attributs de la table groupes
sont idgrp
, nom
, style
et nb_pers
.
Le musicien Charlie Parker est pr\u00e9sent 2 fois dans cette table (avec deux instruments diff\u00e9rents). L'attribut nom
ne peut donc pas \u00eatre une cl\u00e9 primaire, qui doit \u00eatre unique.
Cette requ\u00eate renvoie 'Weather Report'
et 'Return to Forever'
.
UPDATE concerts\nSET heure_fin = '22h30'\nWHERE idconc = 36;\n
Correction Q5. SELECT groupes.nom\nFROM groupes\nJOIN concerts ON concerts.idgrp = groupes.idgrp\nWHERE concerts.scene = 1;\n
Correction Q6. INSERT INTO groupes\nVALUES (15, 'Smooth Jazz Fourplay', 'Free Jazz', 4);\n
Correction Q7. def recherche_nom(tab_mus):\n lst = []\n for mus in tab_mus:\n if mus['nb_concerts'] >= 4:\n lst.append(mus['nom'])\n return lst\n
"},{"location":"T6_Annales/corrections/2023/corr_sujet0_A/#exercice-2","title":"Exercice 2","text":"correction Q1. Cet ordinateur appartient \u00e0 Alice car il fait partie du r\u00e9seau 172.16.2.0/24
. Le masque en /24
nous indique que ce r\u00e9seau contiendra des adresses de type 172.16.2.X
, ce qui est bien le cas de l'adresse 172.16.2.3
.
\\(C=\\dfrac{10000}{1000}=10\\).
Correction Q3.Table de routage du routeur R6
R1-R2-R5-R6
Le nouveau co\u00fbt de 111 correspond \u00e0 la route R1-R2-R4-R6
. Ce sera la nouvelle route la plus courte si le routeur R5
tombe en panne.
Sujet
"},{"location":"T6_Annales/corrections/2023/corr_sujet0_B/#exercice-1","title":"Exercice 1","text":"correction Q1.a.Commande 1 : cd /home/documents/collections/timbres
(chemin absolu) Commande 2 : cd ../collections/timbres
(chemin relatif)
cd /home/documents/collections/timbres
\\(C = \\dfrac{10^8}{100 \\times 10^6} = 1\\)
Correction Q2.b.La route minimale est donc A-B-C-E-F-G (co\u00fbt total de 1,04)
Correction Q3.Les descripteurs de ce fichier sont :
nom_timbre
(valeurs associ\u00e9es : Gustave Eiffel
, Marianne
, Alan Turing
)annee_fabrication
(valeurs associ\u00e9es : 1950
, 1989
, 2012
)nom_collectionneur
(valeurs associ\u00e9es : Dupont
, Durand
)Une cl\u00e9 primaire est attribut qui d\u00e9signe de mani\u00e8re unique un enregistrement.
Correction Q4.b.Non, car deux enregistrements poss\u00e8dent le nom \u00abGustave Eiffel\u00bb.
Correction Q4.c.Non, car deux enregistrements ont pour ann\u00e9e de fabrication 1989. (merci Vincent)
Correction Q4.d.On peut cr\u00e9er une cl\u00e9 primaire artificielle (un nombre entier), ou bien consid\u00e9rer le couple (nom
, annee_fabrication
) comme cl\u00e9 primaire.
Cette requ\u00eate va modifier l'attribut ref_licence
de Jean-Pierre Dupond ET de Alexandra, qui auront donc la m\u00eame r\u00e9f\u00e9rence de licence 'Ythpswz'
.
L'attribut ref_licence
ne peut plus \u00eatre une cl\u00e9 primaire car deux enregistrements diff\u00e9rents auront la m\u00eame valeur pour cet attribut.
SELECT nom, prenom, nbre_timbres\nFROM collectionneurs\nWHERE annee_naissance >= 1963;\n
"},{"location":"T6_Annales/corrections/2023/corr_sujet0_B/#exercice-2","title":"Exercice 2","text":"Correction Q1.a. Une fonction r\u00e9cursive est une fonction qui fait appel \u00e0 elle-m\u00eame dans sa propre d\u00e9finition.
Correction Q1.b.Lors du premier appel de la fonction, le param\u00e8tre n
vaut 3. Lors des appels r\u00e9cursifs, ce param\u00e8tre va d\u00e9cro\u00eetre \u00e0 2, 1 puis 0 puisque l'appel se fait sous condition que n >= 0
. Le dernier appel se fait avec la valeur n = -1
. Lors de l'ex\u00e9cution de compte_rebours(n-1)
, rien ne se passe. La derni\u00e8re valeur affich\u00e9e est donc 0.
def fact(n):\n\"\"\" renvoie le produit des nombres entiers\n strictement positifs inf\u00e9rieurs \u00e0 n \"\"\"\n if n == 0:\n return 1\n else:\n return n * fact(n-1)\n
Correction Q3.a. L'affichage en console sera :
3\n2\n1\n
Correction Q3.b. La variable res
contiendra la valeur 6.
def somme_entiers(n):\n somme = 0\n for nb in range(n+1):\n somme += nb\n return somme\n
"},{"location":"T6_Annales/corrections/2023/corr_sujet0_B/#exercice-3","title":"Exercice 3","text":"Correction Q1.a. Exemple d'attribut : valeur
Exemple de m\u00e9thode : get_valeur
Apr\u00e8s ex\u00e9cution, a
vaut 15 et b
vaut 6.
Ce n'est pas un ABR car la valeur 13 est cens\u00e9e \u00eatre plus petite que la valeur 12.
Correction Q4.La liste renvoy\u00e9e est [1, 6, 10, 15, 16, 18, 16, 25]
.
Quelles \u00e9tudes pour poursuivre dans l'informatique ?
"},{"location":"T7_Divers/10_orientation/cours/#1-les-cursus-ingenieurs-publics-post-bac","title":"1. Les cursus ing\u00e9nieurs publics post-bac","text":""},{"location":"T7_Divers/10_orientation/cours/#11-ecoles-du-reseau-geipi-polytech","title":"1.1 \u00c9coles du r\u00e9seau Geipi-Polytech","text":"BTS Syst\u00e8mes num\u00e9riques option A informatique et r\u00e9seaux
BTS Services informatiques aux organisations (SIO)
L'affectation des lyc\u00e9ens dans l'enseignement sup\u00e9rieur (par l'algorithme APB jusqu'en 2018, par l'algorithme Parcoursup depuis) fait intervenir un algorithme d'appariement.
Appariement
Action d'apparier, d'unir par couple, d'assortir par paire.
Consid\u00e9rons que les \u00e9l\u00e8ves aient fait un classement de leurs formations pr\u00e9f\u00e9r\u00e9es (ce n'est pas le cas dans Parcoursup, nous y reviendrons). Consid\u00e9rons aussi que ces formations aient class\u00e9 ces \u00e9l\u00e8ves au vu de leur dossier. L'algorithme d'appariement va avoir pour but d'associer chaque \u00e9l\u00e8ve \u00e0 une formation, avec les contraintes suivantes :
Pour illustrer les probl\u00e9matiques li\u00e9es \u00e0 l'appariement, nous allons nous placer dans la situation suivante : au lieu de parler d'\u00e9l\u00e8ves et d'\u00e9tablissements d'enseignement sup\u00e9rieur, nous allons parler d'hommes et de femmes.
Situation d'\u00e9tude
Mariages instables
Deux mariages sont dits instables si, dans chacun des deux couples, il existe la possibilit\u00e9 de quitter son conjoint actuel pour quelqu'un mieux class\u00e9 dans ses pr\u00e9f\u00e9rences.
Exemple de mariages instables
Consid\u00e9rons 4 personnes : 2 hommes (Bryce, Gregory) et 2 femmes (Trinity et Riley).
On leur a demand\u00e9 de classer les deux personnes du sexe oppos\u00e9 par ordre de pr\u00e9f\u00e9rence. Voil\u00e0 le r\u00e9sultat :
Bryce pr\u00e9f\u00e8re Riley \u00e0 Trinity, Gregory pr\u00e9f\u00e8re Riley \u00e0 Trinity, Trinity pr\u00e9f\u00e8re Bryce \u00e0 Gregory, Riley pr\u00e9f\u00e8re Bryce \u00e0 Gregory.
Consid\u00e9rons maintenant qu'un algorithme d'appariement a form\u00e9 les couples suivants : Bryce-Trinity et Gregory-Riley.
Mais alors :
le couple Bryce-Riley cr\u00e9e donc deux mariages instables, car leur int\u00e9r\u00eat est de briser leur couple actuel et de partir ensemble.
Par abus de langage, on pourra dire que le couple Bryce-Riley est un couple instable (car leurs mariages respectifs sont instables).
Exercice 1
La configuration ci-dessous contient-elle des mariages instables ?
CorrectionLe couple Christopher-Evelyn est un couple instable.
Exercice 2
\u00c0 l'adresse https://uw-cse442-wi20.github.io/FP-cs-algorithm/, allez jusqu'\u00e0 la zone \u00abIdentify Unstable Pairs\u00bb et entra\u00eenez-vous \u00e0 rep\u00e9rer les mariages instables.
1.2 Notion de mariage stable
Mariages stables
Un ensemble de mariages sera dit stable s'il n'existe aucun couple instable parmi tous les mariages.
La situation ci-dessus est stable, car aucun couple n'est instable.
Le travail des algorithmes d'appariement va \u00eatre d'essayer d'arriver \u00e0 une situation stable.
"},{"location":"T7_Divers/11_parcoursup/cours/#2-algorithme-de-gale-shapley","title":"2. Algorithme de Gale-Shapley","text":"David Gale (1921-2008) et Lloyd Shapley (1923-2016), deux universitaires am\u00e9ricains, ont pr\u00e9sent\u00e9 en 1962 un algorithme d'appariement qui porte leur nom. (lien vers la publication originale).
Cette publication vaudra le prix Nobel d'\u00e9conomie \u00e0 Lloyd Shapley en 2012 (conjointement avec Alvin Roth), David Gale \u00e9tant d\u00e9c\u00e9d\u00e9 en 2008. Leur algorithme est aujourd'hui utilis\u00e9 quotidiennement pour tous les probl\u00e8mes d'appariemment : dans le milieu universitaire (comme nous le voyons), mais aussi dans le milieu m\u00e9dical. Son application a ainsi permis une tr\u00e8s forte augmentation des greffes d'organes, en optimisant l'ad\u00e9quation donneur-receveur.
R\u00e9sultat d\u00e9montr\u00e9 par Gale-Shapley
Si les deux ensembles \u00e0 associer sont de m\u00eame taille (ici : s'il y a autant d'hommes que de femmes), alors il existe toujours au moins un appariement stable.
Gale et Shapley ont d\u00e9taill\u00e9 l'algorithme permettant de fabriquer un de ces appariements stables :
Algorithme de Gale-Shapley
\u00c0 noter qu'il n'y a pas, en r\u00e8gle g\u00e9n\u00e9rale, un seul appariement stable, mais plusieurs. L'algorithme de Gale-Shapley permet d'en trouver un en particulier.
Illustration
Vous pouvez voir le d\u00e9roulement de l'algorithme sur le site https://uw-cse442-wi20.github.io/FP-cs-algorithm/, dans la partie The solution.
"},{"location":"T7_Divers/11_parcoursup/cours/#3-implementation-en-python","title":"3. Impl\u00e9mentation en Python","text":"Nous allons partir de la situation suivante :
Exercice 3Compl\u00e9ter le code ci-dessous.
hommes = ['J', 'O', 'B', 'L']\nfemmes = ['A', 'M', 'K', 'H']\n\nprefs = {'J':['K', 'M', 'A', 'H'],\n 'O':['K', 'A', 'M', 'H'],\n 'B':['H', 'A', 'K', 'M'],\n 'L':['A', 'H', 'K', 'M'],\n 'A':['O', 'L', 'J', 'B'],\n 'M':['B', 'O', 'L', 'J'],\n 'K':['J', 'B', 'L', 'O'],\n 'H':['J', 'O', 'B', 'L']}\n\nrefus = {h:[] for h in hommes}\n\ncouple = {p:None for p in hommes + femmes}\n\nhommes_maries = []\n\nwhile len(hommes_maries) < len(hommes):\n\n for h in hommes:\n print('--------------------')\n print('Affectation de', h, \":\")\n\n if couple[h] is not None:\n print(\"d\u00e9j\u00e0 en couple\")\n\n else:\nfor f in ... :\nif couple[h] is not None:\n break\n print(h, \"propose \u00e0\", f)\n\n if f in refus[h]:\n print(f, 'a d\u00e9j\u00e0 refus\u00e9, stop')\n\n elif couple[f] is None:\n print(f, 'est libre, go')\ncouple[f] = ...\ncouple[h] = ...\nhommes_maries.append(...) \nelse:\n print(f, 'est prise, \u00e9tude...')\n h_actuel = couple[f]\n liste_prefs = prefs[f]\n if liste_prefs.index(h) < liste_prefs.index(h_actuel):\n\n print(h, \"est mieux class\u00e9 que\", h_actuel, \"dans les prefs de\", f)\n print(h_actuel, \"est vir\u00e9\")\n hommes_maries.remove(...)\ncouple[...] = None\nrefus[...].append(f)\nprint(h, \"est le nouveau mari de\", f)\n hommes_maries.append(...)\n couple[f] = h\n couple[h] = f\n\n else:\n print(h, \"est moins bien class\u00e9 que\", h_actuel, \"dans les prefs de\", f, \"il reste celibataire\")\nrefus[...].append(...)\nbreak \n\nprint('--------------------')\nprint(\"tout le monde est mari\u00e9, fin de l'algo\")\nfor h in hommes:\n print(h, '-', couple[h])\n
Correction hommes = ['J', 'O', 'B', 'L']\nfemmes = ['A', 'M', 'K', 'H']\n\nprefs = {'J':['K', 'M', 'A', 'H'],\n 'O':['K', 'A', 'M', 'H'],\n 'B':['H', 'A', 'K', 'M'],\n 'L':['A', 'H', 'K', 'M'],\n 'A':['O', 'L', 'J', 'B'],\n 'M':['B', 'O', 'L', 'J'],\n 'K':['J', 'B', 'L', 'O'],\n 'H':['J', 'O', 'B', 'L']}\n\nrefus = {h:[] for h in hommes}\n\ncouple = {p:None for p in hommes + femmes}\n\nhommes_maries = []\n\nwhile len(hommes_maries) < len(hommes):\n\n for h in hommes:\n print('--------------------')\n print('Affectation de', h, \":\")\n\n if couple[h] is not None:\n print(\"d\u00e9j\u00e0 en couple\")\n\n else:\nfor f in prefs[h]:\nif couple[h] is not None:\n break\n print(h, \"propose \u00e0\", f)\n\n if f in refus[h]:\n print(f, 'a d\u00e9j\u00e0 refus\u00e9, stop')\n\n elif couple[f] is None:\n print(f, 'est libre, go')\ncouple[f] = h\ncouple[h] = f\nhommes_maries.append(h) \nelse:\n print(f, 'est prise, \u00e9tude...')\n h_actuel = couple[f]\n liste_prefs = prefs[f]\n if liste_prefs.index(h) < liste_prefs.index(h_actuel):\n\n print(h, \"est mieux class\u00e9 que\", h_actuel, \"dans les prefs de\", f)\n print(h_actuel, \"est vir\u00e9\")\n hommes_maries.remove(h_actuel)\ncouple[h_actuel] = None\nrefus[h_actuel].append(f)\nprint(h, \"est le nouveau mari de\", f)\n hommes_maries.append(h)\n couple[f] = h\n couple[h] = f\n\n else:\n print(h, \"est moins bien class\u00e9 que\", h_actuel, \"dans les prefs de\", f, \"il reste celibataire\")\nrefus[h].append(f)\nbreak \n\nprint('--------------------')\nprint(\"tout le monde est mari\u00e9, fin de l'algo\")\nfor h in hommes:\n print(h, '-', couple[h])\n
"},{"location":"T7_Divers/11_parcoursup/cours/#4-qualite-de-la-solution-proposee-par-lalgorithme-de-gale-shapley","title":"4. Qualit\u00e9 de la solution propos\u00e9e par l'algorithme de Gale-Shapley","text":"La situation initiale est parfaitement sym\u00e9trique : les hommes ont \u00e9tabli un classement, les femmes \u00e9galement.
Mais l'algorithme de Gale-Shapley n'est pas sym\u00e9trique : ce sont les hommes qui proposent, dans l'ordre d\u00e9croissant de leur choix. La cons\u00e9quence est importante :
Optimalit\u00e9 de la solution trouv\u00e9e
L'algorithme de Gale-Shapley donne :
Le choix de \u00abqui va faire ses propositions\u00bb parmi les deux groupes est donc crucial avant de lancer l'algorithme, car le groupe qui propose est plus avantag\u00e9 dans le r\u00e9sultat final.
Nous allons l'illustrer \u00e0 partir une situation initiale identique, et les deux configurations que donne l'algorithme suivant si ce sont les hommes qui proposent (exemple 1) ou bien les femmes (exemple 2)
Exemple 1 : si les hommes proposent
Analyse de la solution :
Exemple 2 : si les femmes proposent
Analyse de la solution :
L'algorithme de Parcoursup est bas\u00e9 sur l'algorithme de Gale-Shapley. Mais il faut apporter quelques pr\u00e9cisions importantes.
Rappel : l'algorithme de Parcoursup n'est que l'algorithme global
Il r\u00e9cup\u00e8re les classements effectu\u00e9s en interne par tous les \u00e9tablissements de l'enseignement sup\u00e9rieur.
L'algorithme global de Parcoursup est public (vous pouvez le trouver ici). Les algorithmes de classement internes \u00e0 chaque \u00e9tablissement ne le sont pas forc\u00e9ment.
Dans Parcoursup, les v\u0153ux ne sont pas class\u00e9s
Mais alors, comment peut-on appliquer Gale-Shapley, qui repose sur le classement des deux parties ?
Le classement des v\u0153ux de chaque candidat se fait au moment de l'acceptation ou du refus des v\u0153ux accept\u00e9s. \u00c0 chaque tour de Parcoursup, le candidat donne une indication sur ses pr\u00e9f\u00e9rences, et l'algorithme converge donc vers sa solution d\u00e9finitive.
Si on obligeait les candidats \u00e0 classer leur v\u0153ux, on serait dans le cas d'un Gale-Shapley \u00abpur\u00bb : les r\u00e9sultats serait imm\u00e9diats. C'\u00e9tait le cas avec l'algorithme qui pr\u00e9c\u00e9dait Parcoursup, l'algorithme APB.
De plus, l'algorithme de Parcoursup doit ob\u00e9ir \u00e0 des contraintes suppl\u00e9mentaires qui ne figurent pas dans Gale-Shapley:
Dans Parcoursup, les \u00e9tablissements jouent le r\u00f4le des hommes, les candidats jouent le r\u00f4le des femmes
Ce sont les \u00e9tablissements qui proposent (en appelant le 1er de leur liste, puis le 2\u00e8me, ...). La cons\u00e9quence est importante : la solution donn\u00e9e par l'algorithme est donc optimale pour les \u00e9tablissements et non pour les candidats.
Que se passerait-il si on inversait, afin de rendre la solution optimale pour les candidats ?
Il faut se souvenir des situations rencontr\u00e9es plus haut, lorsqu'on a appari\u00e9 des hommes (qui proposaient) \u00e0 des femmes : il arrivait que des couples \u00e9tablis soient cass\u00e9s lorsqu'un homme mieux class\u00e9 se proposait \u00e0 une femme pourtant d\u00e9j\u00e0 mari\u00e9e.
Comme Parcoursup fonctionne sur plusieurs mois (\u00e0 cause de la non-hi\u00e9rachisation des v\u0153ux), cela reviendrait \u00e0 ce qu'un candidat ait une r\u00e9ponse positive d'un \u00e9tablissement, mais que cette r\u00e9ponse soit annul\u00e9e quelques jours plus tard parce qu'un meilleur candidat aura fait une proposition \u00e0 cet \u00e9tablissement... Ceci est difficilement envisageable d'un point de vue psychologique.
Dans le cas de l'affectation des \u00e9tudiants \u00e0 l'issue de la premi\u00e8re ann\u00e9e de PASS, les v\u0153ux sont hi\u00e9rarchis\u00e9s et Gale-Shapley fonctionne donc de mani\u00e8re imm\u00e9diate : ce sont donc les \u00e9tudiants qui proposent, et l'algorithme aboutit donc \u00e0 une solution optimale pour les \u00e9tudiants. (source)
Finalement, pourquoi les v\u0153ux Parcoursup des candidats ne sont-ils pas hi\u00e9rarchis\u00e9s ?
Les avantages :
Les inconv\u00e9nients :
bibliographie
Il est conseill\u00e9 de travailler avec 3 espaces:
C'est en codant qu'on apprend \u00e0 coder
Tous les exemples de code dans le cours doivent \u00eatre retap\u00e9s (r\u00e9sistez \u00e0 l'envie du copier-coller) dans Thonny, soit en fen\u00eatre de script, soit en console.
Cela permet de :
et le plus important :
Thonny, comme la grande majorit\u00e9 des IDE Python, est compos\u00e9 de deux zones distinctes :
La zone de script est asynchrone. Il ne se passera rien tant que vous n'aurez pas ex\u00e9cut\u00e9 le script (par F5 par exemple). C'est donc l'endroit o\u00f9 on va r\u00e9diger son programme.
La console est synchrone : elle r\u00e9pond d\u00e8s que vous appuyez sur la touche Entr\u00e9e. Elle sert donc aux petits tests rapides, ou bien tests post-ex\u00e9cution d'un code.
Utilisation classique du couple script / console
Pour les extraits de code pr\u00e9sents sur ce site :
Exemple :
def accueil(n):\n for k in range(n):\n print(\"bonjour\") \n
>>>
est \u00e0 taper en console.Exemple :
>>> accueil(5)\n
"},{"location":"T7_Divers/1_Conseils_generaux/cours/#dossiers-fichiers-et-versionning","title":"Dossiers, fichiers et versionning","text":"Cette ann\u00e9e en NSI nous allons manipuler un certain nombre de fichiers. Il est important de les nommer et les classer de fa\u00e7on rigoureuse pour les retrouver rapidement et les partager.
Conseils
python1.py
, python2.py
, python3.py
, etc. Mais plut\u00f4t 1NSI_T4_tri_selection.py
par exemple pour un exercice de programmation sur le tri par selection au th\u00e8me 4.1NSI_projet_morpion_v1.py
, puis 1NSI_projet_morpion_v2.py
, 1NSI_projet_morpion_v3.py
, etc.Utiliser le clavier est souvent bien plus pratique et surtout plus rapide qu'utiliser la souris. Encore faut-il apprendre \u00e0 l'apprivoiser...
La s\u00e9lection au clavier
Outre les touches DEBUT
et FIN
qui permettent d'atteindre rapidement le d\u00e9but ou la fin d'une ligne, les fl\u00e8ches directionelles servent \u00e9videmment \u00e0 se d\u00e9placer dans du texte. Mais combin\u00e9es:
CTRL
: elles permettent de se d\u00e9placer de mot en mot;MAJ
: elles permettent de s\u00e9lectionner un caract\u00e8re;MAJ
et CTRL
: elles permettent de s\u00e9lectionner une mot.De m\u00eame, en se pla\u00e7ant en d\u00e9but d'une ligne et en combinant la touche MAJ
et FIN
, on s\u00e9lectionne la ligne enti\u00e8re.
Les raccourcis clavier
Il existe de tr\u00e8s nombreux raccourcis clavier qui permettent d'ex\u00e9cuter des t\u00e2ches courantes sans passer par les menus du logiciel. Certains sont (quasi-)universels, c'est-\u00e0-dire que ce sont les m\u00eames sur tous les logiciels, d'autres sont sp\u00e9cifiques \u00e0 chaque logiciel. Il est important d'en conna\u00eetre quelques-uns pour \u00eatre plus efficace.
Les universelsIDENavigateur WebCTRL+X
, CTRL+C
, CTRL+V
pour couper, copier, coller;CTRL+O
pour ouvrir un fichierCTRL+N
pour cr\u00e9er un nouveau document;CTRL+S
pour sauvegarder le document en cours;CTRL+MAJ+S
pour sauvegarder en pr\u00e9cisant le nom du fichier;CTRL+Z
pour annuler la derni\u00e8re action, CTRL+Y
ou CTRL+MAJ+Z
pour la r\u00e9tablir;CTRL+W
pour fermer un onglet;CTRL+Q
ou ALT+F4
pour fermer le logiciel;CTRL+A
pour s\u00e9lectionner tout (All).\u00c0 chercher de suite lorsqu'on utilise un nouvel IDE, les raccourcis pour les actions suivantes (entre parenth\u00e8ses ceux de Thonny):
F5
)CTRL+M
)CTRL+T
pour ouvrir un nouvel onglet;CTRL+H
pour ouvrir l'historique;CTRL
+ clic pour forcer l'ouverture d'un lien dans un nouvel onglet;MAJ
+ clic pour forcer l'ouverture d'un lien dans une nouvelle fen\u00eatre;Afin de pouvoir travailler sous le syst\u00e8me d'exploitation libre Linux sur les machines du lyc\u00e9e (sous Windows), nous utilisons la solution de virtualisation Proxmox. De mani\u00e8re simplifi\u00e9e :
Programmation
.Proxmox NSI
. Param\u00e8tres avanc\u00e9s
puis sur Continuer vers le site 172.17.191.244
Proxmox VE Login
, renseigner ses identifiants et s\u00e9lectionner Realm Proxmox VE authentication server
. ok
pour l'ignorer.Start
pour d\u00e9marrer la VM.Console
et choisir Spice
. telechargement.vv
apparu en bas \u00e0 gauche.Remplir ses identifiants dans la fen\u00eatre de connexion :
Basculer l'affichage en plein \u00e9cran
Comme pour tous les langages de programmation, il n'existe pas un logiciel permettant de coder en Python, mais un tr\u00e8s (tr\u00e8s) grand nombre de logiciels diff\u00e9rents, qu'on regroupe sous le nom d'IDE (interfaces de d\u00e9veloppement)
Pour la NSI, nous conseillons Thonny :
"},{"location":"T7_Divers/3_Thonny/cours/#installer-thonny","title":"Installer Thonny","text":"Rendez vous sur la page https://thonny.org/
T\u00e9l\u00e9chargez et installez la version qui correspond \u00e0 votre syst\u00e8me d'exploitation (Windows, Mac, Linux).
Pyzo, PyCharm, Spyder, VisualStudioCode... impossible de toutes les citer !
"},{"location":"T7_Divers/3_Thonny/cours/#solutions-en-ligne","title":"Solutions en ligne","text":"En ligne, sans aucune installation, vous pouvez utiliser https://console.basthon.fr/
ou bien m\u00eame la console ci-dessous !
>>>ou l'IDE qui suit :
\u25b6\ufe0f \u2935\ufe0f \u2934\ufe0f "},{"location":"T7_Divers/3_Thonny/cours/#installer-la-derniere-version-de-thonny-avec-export-python-tutor","title":"Installer la derni\u00e8re version de Thonny (avec export Python Tutor !)","text":"Proc\u00e9dure sur nos VMs au lyc\u00e9e
Dans un terminal ouvert dans votre dossier eleve
mkdir thonny
cd thonny
wget https://github.com/thonny/thonny/releases/download/v4.0.1/thonny-4.0.1-x86_64.tar.gz
tar -xf thonny-4.0.1-x86_64.tar.gz
cd thonny
install
Processing est un outil de cr\u00e9ation multim\u00e9dia utilisant le code informatique. Simple de prise en main, il a \u00e9t\u00e9 cr\u00e9\u00e9 par des artistes pour des artistes. On peut utiliser le langage Python pour entrer les instructions.
Nous l'utiliserons pour ajouter du graphisme \u00e0 nos cr\u00e9ations...
Documentation"},{"location":"T7_Divers/4_Processing/cours/#les-bases-de-processing","title":"Les bases de Processing","text":""},{"location":"T7_Divers/4_Processing/cours/#repere","title":"Rep\u00e8re","text":"
\u00c0 l'ex\u00e9cution de tout script Processing, une fen\u00eatre s'affiche avec une zone de dessin. Sa taille se d\u00e9finit \u00e0 l'aide de la fonction size
. Par exemple, pour cr\u00e9er une zone de dessin de 300 pixels sur 200 pixels, on utilisera:
size(300, 200)\n
Chaque pixel de cette zone est rep\u00e9r\u00e9e par des coordonn\u00e9es dans le rep\u00e8re suivant, dont l'origine se situe en haut \u00e0 gauche et l'axe des ordonn\u00e9es est orient\u00e9 vers le bas.
"},{"location":"T7_Divers/4_Processing/cours/#traces","title":"Trac\u00e9s","text":"
Trac\u00e9s de base
point
: permet de dessiner un point (pixel). En param\u00e8tre, les coordonn\u00e9es du point.line
: permet de tracer une ligne entre deux points. En param\u00e8tres, les coordonn\u00e9es des deux points.rect
: permet de tracer un rectangle. En param\u00e8tres, les coordonn\u00e9es du sommet haut-gauche, puis la largeur et la hauteur du rectangle.ellipse
: permet de tracer une ellipse. En param\u00e8tres, les coordonn\u00e9es du centre, puis la largeur et la hauteur (mettre la m\u00eame valeur pour un cercle).Copier-coller le code suivant et faire varier les param\u00e8tres pour bien les comprendre.
size(200, 200)\npoint(10, 60)\nline(10, 10, 100, 150)\nrect(80, 10, 20, 50)\nellipse(150, 100, 80, 40)\n
"},{"location":"T7_Divers/4_Processing/cours/#couleurs","title":"Couleurs","text":"Pinceau
background
: permet de d\u00e9finir la couleur du fond de la zone de dessin. En param\u00e8tres, les trois composantes RGB de la couleur.stroke
: permet de d\u00e9finir la couleur du pinceau (noir par d\u00e9faut) pour le contour de la forme. En param\u00e8tres, les trois composantes RGB de la couleur.noStroke
: permet de dessiner une forme sans coutour (pas de param\u00e8tre).strokeWeight
: permet de d\u00e9finir la largeur du pinceau. En param\u00e8tre, le nombre de pixel.fill
: permet de d\u00e9finir la couleur de remplissage de la forme. En param\u00e8tres, les trois composantes RGB de la couleur.Copier-coller le code suivant et faire varier les param\u00e8tres pour bien les comprendre.
size(200, 200)\nbackground(255, 255, 255)\nstroke(255, 0, 0)\npoint(10, 60)\nline(10, 10, 100, 150)\nstroke(0, 127, 255)\nstrokeWeight(5)\nrect(80, 10, 20, 50)\nnoStroke()\nfill(204, 153, 204)\nellipse(150, 100, 80, 40)\n
"},{"location":"T7_Divers/4_Processing/cours/#exercices","title":"Exercices","text":"Exercice 9
\u00c9crire un programme qui affiche le drapeau fran\u00e7ais, comme ci-contre, dans une zone de 300 x 200 pixels.
Exercice 10
\u00c9crire un programme qui trace un quadrillage (espacement de 20 pixels).
Contrainte: en seulement 3 lignes (sans compter \u00e9ventuellement size
.
Exercice 11
Afficher une croix verte de longueur 50 centr\u00e9e au point (60 ; 40), et un cercle rouge de diam\u00e8tre 30 centr\u00e9 en (150 ; 100). On prendra 10 pixels comme \u00e9paisseur.
Exercice 12
Cr\u00e9ez un programme permettant d\u2019afficher 100 disques \u00e0 l\u2019\u00e9cran. La taille de chaque disque devra \u00eatre al\u00e9atoire (mais comprise entre 20 et 50). La couleur de chaque disque devra aussi \u00eatre al\u00e9atoire.
Avec Processing, il est tr\u00e8s simple d\u2019avoir un nombre al\u00e9atoire : random(a,b)
permet d\u2019obtenir un nombre al\u00e9atoire entre a
et b
.
Capytale est accessible via lyc\u00e9econnect\u00e9, il faut donc avoir ses identifiants Educonnect.
"},{"location":"T7_Divers/5_Capytale/cours/#activite-test","title":"Activit\u00e9-test :","text":"Lyc\u00e9e Connect\u00e9 (Nouvelle Aquitaine)
Pygame est un package de Python facilitant la cr\u00e9ation de jeux bas\u00e9s une interface graphique. Vous pouvez :
pip3 install pygame
.pygame
dans la liste des langages propos\u00e9s.import pygame, sys\nfrom pygame.locals import *\n\npygame.init()\n\nfenetre = pygame.display.set_mode((640, 480))\n\nfenetre.fill([10,186,181])\n\npygame.display.flip()\n\nwhile True :\n pass\n
Ce code devrait vous donner ceci :
Commentaires
sys
permettra de fermer le programme au niveau de l'OS par la commande sys.exit()
from pygame.locals import *
permettra d'utiliser des variables locales d\u00e9j\u00e0 d\u00e9finies par pygame
, comme MOUSEBUTTONDOWN
, par exemple.fenetre
, dans lequel nous viendrons coller de nouveaux \u00e9l\u00e9ments. \u00c9l\u00e9ments structurants d'un code pygame
:
pygame.init()
effectue une initialisation globale de tous les modules pygame
import\u00e9s. \u00c0 mettre au d\u00e9but du code.pygame.display.flip()
effectue un rafra\u00eechissement total de tous les \u00e9l\u00e9ments graphiques de la fen\u00eatre. \u00c0 mettre donc plut\u00f4t vers la fin du code.while True :
comme tr\u00e8s souvent dans les jeux, la structure essentielle est une boucle infinie dont on ne sortira que par une interruption syst\u00e8me (sys.exit()
) o\u00f9 lors de la bascule d'un bool\u00e9en. Pour l'instant, cette boucle est vide (pass
).Nous allons travailler avec le sprite ci-dessous, nomm\u00e9 perso.png
. Il est issu de https://openclassrooms.com/fr/courses/1399541-interface-graphique-pygame-pour-python/1399813-premieres-fenetres
T\u00e9l\u00e9chargez-le pour le mettre dans le m\u00eame dossier que votre code pygame
.
Vous pouvez trouver sur internet un grand nombre de sprites libres de droits, au format png
(donc g\u00e9rant la transparence), dans de multiples positions (ce qui permet de simuler des mouvements fluides). Ici nous travaillerons avec un sprite unique.
perso = pygame.image.load(\"perso.png\").convert_alpha()\n
La fonction convert_alpha()
est appel\u00e9e pour que soit correctement trait\u00e9 le canal de transparence (canal alpha) de notre image."},{"location":"T7_Divers/6_Pygame/05_Initiation_Pygame/#23-affichage-de-limage","title":"2.3. Affichage de l'image","text":"\u00c0 ce stade, perso
est un objet pygame
de type Surface
.
Afin de facilement pouvoir le d\u00e9placer, nous allons stocker la position de cet objet dans une variable position_perso
, qui sera de type rect
.
position_perso = perso.get_rect()\n
Pour afficher cette image, nous allons venir le superposer aux \u00e9l\u00e9ments graphiques d\u00e9j\u00e0 dessin\u00e9s (en l'occurence : rien) avec l'instruction blit()
: fenetre.blit(perso, position_perso)\n
\u25b8 r\u00e9capitulatif du code
import pygame, sys\nfrom pygame.locals import *\n\npygame.init()\n\nfenetre = pygame.display.set_mode((640, 480))\nfenetre.fill([10,186,181])\n\nperso = pygame.image.load(\"perso.png\").convert_alpha()\nposition_perso = perso.get_rect()\n\nfenetre.blit(perso, position_perso)\n\npygame.display.flip()\n\nwhile True :\n pass\n
Aper\u00e7u
"},{"location":"T7_Divers/6_Pygame/05_Initiation_Pygame/#3-gestion-des-evenements","title":"3. Gestion des \u00e9v\u00e8nements","text":"Lorsqu'un programme pygame
est lanc\u00e9, la variable interne pygame.event.get()
re\u00e7oit en continu les \u00e9v\u00e8nements des p\u00e9riph\u00e9riques g\u00e9r\u00e9s par le syst\u00e8me d'exploitation. Nous allons nous int\u00e9resser aux \u00e9v\u00e8nements de type KEYDOWN
(touche de clavier appuy\u00e9e) ou de type MOUSEBUTTONDOWN
(boutons de souris appuy\u00e9).
La structure de code pour d\u00e9tecter l'appui sur une touche de clavier est, dans le cas de la d\u00e9tection de la touche \u00abFl\u00e8che droite\u00bb :
for event in pygame.event.get(): \n if event.type == KEYDOWN:\n if event.key == K_RIGHT:\n print(\"fl\u00e8che droite appuy\u00e9e\")\n
La touche (en anglais key) \u00abFl\u00e8che Droite\u00bb est appel\u00e9e K_RIGHT
par pygame
. Le nom de toutes les touches peut \u00eatre retrouv\u00e9 \u00e0 l'adresse https://www.pygame.org/docs/ref/key.html.
Remarque : c'est gr\u00e2ce \u00e0 la ligne initiale
from pygame.locals import *\n
que la variable K_RIGHT
(et toutes les autres) est reconnue."},{"location":"T7_Divers/6_Pygame/05_Initiation_Pygame/#312-probleme-de-la-remanence","title":"3.1.2. Probl\u00e8me de la r\u00e9manence","text":"Quand une touche de clavier est appuy\u00e9e, elle le reste un certain temps. Parfois volontairement (sur un intervalle long) quand l'utilisateur d\u00e9cide de la laisser appuy\u00e9e, mais aussi involontairement (sur un intervalle tr\u00e8s court), lors d'un appui \u00abclassique\u00bb. Il existe donc toujours un intervalle de temps pendant lequel la touche reste appuy\u00e9e. Que doit faire notre programme pendant ce temps ? Deux options sont possibles :
Par d\u00e9faut,pygame
est r\u00e9gl\u00e9 sur l'option 1. N\u00e9anmoins, il est classique pour les jeux vid\u00e9os de vouloir que \u00ablaisser la touche appuy\u00e9e\u00bb continue \u00e0 faire avancer le personnage. Nous allons donc faire en sorte que toutes les 50 millisecondes, un nouvel appui soit d\u00e9tect\u00e9 si la touche est rest\u00e9e enfonc\u00e9e. Cela se fera par l'expression :
pygame.key.set_repeat(50)\n
"},{"location":"T7_Divers/6_Pygame/05_Initiation_Pygame/#32-evenements-souris","title":"3.2 \u00c9v\u00e8nements souris","text":""},{"location":"T7_Divers/6_Pygame/05_Initiation_Pygame/#321-exemple-de-code","title":"3.2.1. Exemple de code","text":"La structure de code pour d\u00e9tecter l'appui sur un bouton de la souris est, dans le cas de la d\u00e9tection du bouton de gauche (le bouton 1) :
for event in pygame.event.get(): \n if event.type == MOUSEBUTTONDOWN and event.button == 1 :\n print(\"clic gauche d\u00e9tect\u00e9\")\n
"},{"location":"T7_Divers/6_Pygame/05_Initiation_Pygame/#322-recuperation-des-coordonnees-de-la-souris","title":"3.2.2. R\u00e9cup\u00e9ration des coordonn\u00e9es de la souris","text":"Le tuple (abscisse, ordonn\u00e9e)
des coordonn\u00e9es de la souris sera r\u00e9cup\u00e9r\u00e9 avec l'instruction pygame.mouse.get_pos()
.
Le d\u00e9placement d'un personnage se fera toujours par modification de ses coordonn\u00e9es (et visuellement, par effacement de la derni\u00e8re position). Ce d\u00e9placement pourra \u00eatre : - absolu : on donne de nouvelles coordonn\u00e9es au personnage. - relatif : on indique de combien le personnage doit se d\u00e9caler par rapport \u00e0 sa position initiale.
"},{"location":"T7_Divers/6_Pygame/05_Initiation_Pygame/#41-deplacement-absolu","title":"4.1. D\u00e9placement absolu","text":"Pour afficher le personnage \u00e0 la position (100,200)
, on \u00e9crira :
position_perso.topleft = (100,200)\n
o\u00f9 position_perso
est l'objet de type rect
contenant les coordonn\u00e9es. Exercice 1 : R\u00e9aliser un d\u00e9placement al\u00e9atoire, comme l'animation ci-dessous.
Vous pourrez utiliser les instructions : - pygame.time.delay(1000)
afin de ne bouger le personnage que toutes les 1000 millisecondes. - randint(a,b)
du package random
, qui renvoie un entier pseudo-al\u00e9atoire entre a
et b
.
import pygame, sys\nfrom pygame.locals import *\nfrom random import randint\n\npygame.init()\n\nfenetre = pygame.display.set_mode((640, 480))\n\nperso = pygame.image.load(\"perso.png\").convert_alpha()\n\nposition_perso = perso.get_rect()\n\nwhile True :\n fenetre.fill([10,186,181])\n position_perso.topleft = (randint(0,540),randint(0,380))\n fenetre.blit(perso, position_perso)\n pygame.display.flip()\n pygame.time.delay(1000)\n
"},{"location":"T7_Divers/6_Pygame/05_Initiation_Pygame/#42-deplacement-relatif","title":"4.2. D\u00e9placement relatif","text":"Pour d\u00e9placer le personnage de 15 pixels vers la droite et de 10 pixels vers le haut par rapport \u00e0 sa position pr\u00e9c\u00e9dente, on \u00e9crira :
position_perso.move(15,-10)\n
o\u00f9 position_perso
est l'objet de type rect
contenant les coordonn\u00e9es. Exercice 2 : R\u00e9aliser un contr\u00f4le au clavier du personnage, comme dans l'animation ci-dessous.
Proposition de correction
import pygame, sys\nfrom pygame.locals import *\n\npygame.init()\npygame.key.set_repeat(50)\n\nfenetre = pygame.display.set_mode((640, 480))\n\nperso = pygame.image.load(\"perso.png\").convert_alpha()\n\nposition_perso = perso.get_rect()\n\npas_deplacement = 15 \n\nwhile True :\n\n for event in pygame.event.get() : \n if event.type == KEYDOWN:\n\n if event.key == K_DOWN : \n position_perso = position_perso.move(0,pas_deplacement)\n\n if event.key == K_UP :\n position_perso = position_perso.move(0,-pas_deplacement)\n\n if event.key == K_RIGHT : \n position_perso = position_perso.move(pas_deplacement,0)\n\n if event.key == K_LEFT : \n position_perso = position_perso.move(-pas_deplacement,0) \n\n fenetre.fill([10,186,181])\n fenetre.blit(perso, position_perso)\n pygame.display.flip()\n
"},{"location":"T7_Divers/6_Pygame/05_Initiation_Pygame/#5-a-vous","title":"5. \u00c0 vous !","text":"Fabriquez le jeu que vous souhaitez \u00e0 partir des informations ci-dessus. Bien d'autres aides peuvent \u00eatre trouv\u00e9es dans les liens cit\u00e9es dans la partie Bibliographie.
Exemple de r\u00e9alisation possible : un clicker avec un temps qui diminue \u00e0 progressivement, et comptage des points.
Quelques aides :
\u00e9crire du texte :
font = pygame.font.Font(pygame.font.get_default_font(), 36)\ntext = font.render(\"Game Over\", True, (255, 0, 0))\nfenetre.blit(text, dest=(550,40))\n
dessiner un rectangle :
pygame.draw.rect(fenetre,(0,255,0),(500,20,100,10))\n
dessine un rectangle vert de 100 pixels sur 10 pixels, dont le coin en haut \u00e0 gauche est \u00e0 la position (500,20). g\u00e9rer le temps:
import time\ntopchrono = time.time()\ndelai = 5\nsortir = False\nwhile sortir == False :\n if time.time() - topchrono > delai :\n print(\"5 secondes se sont \u00e9coul\u00e9es\")\n sortir = True\n
Bibliographie
\u00c0 retrouver ici
"},{"location":"T7_Divers/7_Liens/liens/#a-propos-de-la-specialite-nsi","title":"\u00c0 propos de la sp\u00e9cialit\u00e9 NSI","text":"Quelques sites de challenges/\u00e9nigmes/d\u00e9fis de programmation:
Interstices
Inria
Au cas o\u00f9 vous vous ennuieriez...
d\u00e9p\u00f4t : https://github.com/ffaure32/rugby-game-nsi
Cliquer sur Code
puis Download zip
.
ligne \u00e0 \u00e9crire dans un Terminal pour lancer les tests :
python3 -m unittest test_rugby_game.py\n
Je vous conseille de travailler avec 2 fichiers :
input.txt
qui contiendra l'input r\u00e9el qui vous permettra de trouver votre solution.input_test.txt
qui contiendra les donn\u00e9es de test (qui sont toujours propos\u00e9es au sein de l'\u00e9nigme). L'instruction suivante :
data = open('input_test.txt').read().splitlines()\n
va r\u00e9cup\u00e9rer au sein d'une liste toutes les lignes de l'input. Attention, les objets contenus dans la liste sont des cha\u00eenes de caract\u00e8res.
Exemple avec le fichier input_test.txt
1000\n2000\n3000\n\n4000\n\n5000\n6000\n\n7000\n8000\n9000\n\n10000\n
La variable data
sera alors :
>>> data\n['1000', '2000', '3000', '', '4000', '', '5000', '6000', '', '7000', '8000', '9000', '', '10000']\n
"},{"location":"T7_Divers/9_AOC/cours/#22-exploiter-ces-donnees","title":"2.2 Exploiter ces donn\u00e9es","text":"Le plus dur commence ! Suivant ce qu'il va falloir faire avec ces donn\u00e9es, vous allez devoir les triturer pour les utiliser, au sein de diff\u00e9rentes structures (listes, dictionnaires... ). Cela d\u00e9pend des situations. Ici par exemple, les donn\u00e9es sont \u00abjuste\u00bb des nombres, on peut donc parcourir la liste et effectuer un int()
pour les convertir en nombre lorsque c'est n\u00e9cessaire...