From dcdc168b6e5fe59c7b0a189c799b56f1aecd278c Mon Sep 17 00:00:00 2001 From: Louis Chmielewski <louischmielewski@MacBook-Air-de-Louis.local> Date: Wed, 13 Mar 2024 09:17:37 +0100 Subject: [PATCH] tp_tri liste_alea --- .DS_Store | Bin 10244 -> 10244 bytes Projet/.DS_Store | Bin 6148 -> 6148 bytes Projet/README.md | 2 +- Projet/src/bloc.py | 39 +++++++++ Tp01/.DS_Store | Bin 6148 -> 6148 bytes Tp05/.DS_Store | Bin 6148 -> 6148 bytes Tp06/mesures.py | 2 +- Tp07/analyse_tris.csv | 102 ++++++++++++++++++++++ Tp07/analyse_tris.py | 79 +++++++++++++++++ Tp07/ap_decorators.py | 135 +++++++++++++++++++++++++++++ Tp07/apl1test.py | 89 +++++++++++++++++++ Tp07/compare.py | 44 ++++++++++ Tp07/tp_tri.py | 32 +++++++ Tp07/tris.py | 193 ++++++++++++++++++++++++++++++++++++++++++ Tp07/tris_nbcomp.png | Bin 0 -> 28343 bytes 15 files changed, 715 insertions(+), 2 deletions(-) create mode 100644 Tp07/analyse_tris.csv create mode 100644 Tp07/analyse_tris.py create mode 100644 Tp07/ap_decorators.py create mode 100644 Tp07/apl1test.py create mode 100644 Tp07/compare.py create mode 100755 Tp07/tp_tri.py create mode 100644 Tp07/tris.py create mode 100644 Tp07/tris_nbcomp.png diff --git a/.DS_Store b/.DS_Store index 38ad5b6c7137d54edc2b705a4fac73bf004a534a..2123ae47bd8ef83e1b398d97f7ec8e2ce611ea62 100644 GIT binary patch delta 1073 zcmZn(XbG6$FKElaz`)4BAi$85ZWx@LpIfl8a2or>2Eonj94s95AXyd$J%)6KOokGe z3I-71>)XV@zyO!a&3AE0%E?b+U|`@dsCg-J;=)l!RQVLV@&y?X+d)P%C>nq$Him%7 zLIRSkjtmTpT9XX~eloL)m`v6Ylwo6FV9;1~ezKpSoH~RFwu_A+fT4&XpCOAOm7xU1 zJl2HGlLdnr>rp(Q@2v!OU<gA2g8_pfvIiI#8d$0~fDL6~fXgF1fK497Lj4Ai2jF_k zf{XHU^7A&o6%uERwXZ?4)(F*F2ELuB)*9vJBU_6pk76xDz~)2|ZAK>Zy2*W_5};sm z5866;ji?lic}7%*F=6vdQ7y*U-6lxRFhO-jgB;^-6yKYmIs;Q4)fpcq7l=np-YHT# z`GkP`<hw!~le;DOnd<T;&yfJTs_NIF$-5-Lt^zS{Nk}s>7Hs}5q0JbZB!=WHGc;#0 zTb@I4mKmC}Fyv94)iAkUN@jAc2nVD2WElZ@PFVbyPhKa|C~U5yU}RxXtD{hDXkcQg zqhM-aIr)x&G06G#<|rwLVG|^2LsEu0vLi!NR|uVfC4IO&A_}p|qdM{fa>_A>q@2x@ Tr2a5%W>@&d5-?y1hH*Cl^j-XW delta 656 zcmZn(XbG6$FRI7Dz`)4BAi%(o%248&lb@WFlb^IPaWVU5b`BN}L69^XLjXe&Lq0<m zNXg`>((;ox3%pZh00R`c+<X@okah+J29DCQ&9<gzCLa@&V}mkZ3Cc4uFl^=)3TE7V zO<0aG7Hj|uLkL3wg8_pPvgW?R*;>^bjyf_hFd)gNzzxSHUyxxKoSdIq05+9@VRN9U zHX{=Q!{j<K2{zXSr=D_dnmk8L3dY<cCd0_E`KFi_nlnt0opCe0vS-Uq6la*^<|CYe zO&-k|lM^H&CL4+$o?Iiz4{}Yfqy$^4R<3N&zR9a4rC`j{lG31{c_FEd<{UF*=VaXs pJo)PoigV16or6st-8lu)G8<EJSU0mP{9>8>QM4Q6ra=)xHUOIptxW&` diff --git a/Projet/.DS_Store b/Projet/.DS_Store index 3a2ffc2d18ce5b714e3d2e943b2a04fff657c174..012a194f43ef6645fe0c77bd378b13dfb3310c7b 100644 GIT binary patch delta 81 zcmZoMXffEJ$;!;~O>MFcs|+gxL&Iyk$%U-KlM`5Z;5-E;R)x)zS)&=5Sf@_@z$V7Z Zz`)>WKbf0d63WtKmu3{$?8?4h003lP6MX;x delta 81 zcmZoMXffEJ$;!;Yz%W^dRfhFYU)mYl$%U-KlM`5Z;5-E;28PX(S)&=57#JphU=w4_ Z6|&N^o6OBF31w-rOEWTTc4gl$005Ge6$AhP diff --git a/Projet/README.md b/Projet/README.md index 0b83392..dd22c9e 100644 --- a/Projet/README.md +++ b/Projet/README.md @@ -4,5 +4,5 @@ author : Louis Chmielewski - - - # journal -- 6/03 : +- 11/03 : organisation de la résolution du projet diff --git a/Projet/src/bloc.py b/Projet/src/bloc.py index d58bde5..ae3edca 100755 --- a/Projet/src/bloc.py +++ b/Projet/src/bloc.py @@ -10,3 +10,42 @@ """ +from PIL import Image, ImageDraw + +class Bloc: + """Classe d'un bloc d'une image en pixel + """ + + def __init__(self, image: Image): + """ + $$$ + """ + self.image = image + + def __repr__(self) -> str: + """ + $$$ repr(DicoTrie([Association('a', 1)])) + "DicoTrie([Association('a', 1)])" + $$$ repr(DicoTrie([Association('a', 1), Association('b', 2)])) + "DicoTrie([Association('a', 1), Association('b', 2)])" + $$$ repr(DicoTrie([Association('c', 3), Association('a', 2), Association('b', 1)])) + "DicoTrie([Association('a', 2), Association('b', 1), Association('c', 3)])" + """ + return f"DicoTrie({repr(self.liste_assos)})" + + def __eq__(self, autre) -> bool: + """ + $$$ d1 = DicoTrie([Association("a", 1), Association("b", 2)]) + $$$ d2 = DicoTrie([Association("b", 2), Association("a", 1)]) + $$$ d3 = DicoTrie([Association("a", 1), Association("b", 2), Association("c", 3)]) + $$$ d1 == d2 + True + $$$ d1 == d3 + False + $$$ d1 == {"a": 1, "b": 2} + False + """ + if isinstance(autre, DicoTrie): + return self.liste_assos == autre.liste_assos + else: + return False \ No newline at end of file diff --git a/Tp01/.DS_Store b/Tp01/.DS_Store index 1ea4f8f77ec5d17550335a7756d70e129b54b52b..d2da421d72d10f2f3c6366735076c36fe4c04cf1 100644 GIT binary patch delta 302 zcmZoMXfc=|#>B!ku~2NHo+2aH#(>?7iyN4k7`Zm{Fa<Hz=cF43C+FuDFo1w~=X3@J z26l!VhE#?MhD?S+hEj&q+<X_8q@4UD1_lNW1_p++%xjK1VpEkugsOrJWZM=nFiiGk zR!HSSwU9xNp@5;%GbcY8YOMeR1EVYh1B2dwFaWuffg3|l2}1=#37W2Mgs#nn%u5+J hvvcrsFtKoLE@b}BJegm_k%N(efeB>b<_M8B%mBqUN)rG8 delta 71 zcmZoMXfc=|#>B)qu~2NHo+2a5#(>?7j4YdZSb`WQzhmX!EW#noGO?k3Gdl-A2NM(L cW<iec%#-;=961;m7#J8C7+5w(h^%1-0E+_<f&c&j diff --git a/Tp05/.DS_Store b/Tp05/.DS_Store index 3e0563300041a8e1f12e167e8a09a7b9782e4e03..5b10303b2ee0c66a010d9c83b7955f08361dac24 100644 GIT binary patch delta 169 zcmZoMXfc@J&&ahgU^gQp*JK{1%k``bnGDGc`3!js#X0GQ!O8i#1q@&y)6BrYfFzrn z@8Xh_lb^)Ez`()4&|n<2@2DfXiWCAW3Nnywc)-BGF!>&nEhGD62__jPru5A`%)Ts} J**X650|0mpC$|6q delta 35 rcmZoMXfc@J&&awlU^gQp>tr6L%ah}oZ8o1|wqu#tux>Lu$6tN`&d3Y| diff --git a/Tp06/mesures.py b/Tp06/mesures.py index 5ab31e0..6677b6b 100755 --- a/Tp06/mesures.py +++ b/Tp06/mesures.py @@ -15,7 +15,7 @@ from association import Association from types import NoneType from timeit import timeit from random import randrange -#import matplotlib.pyplot as plt +import matplotlib.pyplot as plt def generation_dict(tailles: list[int]) -> list[dict[str, NoneType]]: """Renvoie une liste de dictionnaires dont les clés sont les diff --git a/Tp07/analyse_tris.csv b/Tp07/analyse_tris.csv new file mode 100644 index 0000000..7526113 --- /dev/null +++ b/Tp07/analyse_tris.csv @@ -0,0 +1,102 @@ +taille;"tri séléction";"tri insertion" + 0; 0.00; 0.00 + 1; 0.00; 0.00 + 2; 1.00; 1.00 + 3; 3.00; 2.62 + 4; 6.00; 4.96 + 5; 10.00; 7.72 + 6; 15.00; 11.44 + 7; 21.00; 15.40 + 8; 28.00; 19.02 + 9; 36.00; 24.62 + 10; 45.00; 28.80 + 11; 55.00; 35.70 + 12; 66.00; 40.96 + 13; 78.00; 50.26 + 14; 91.00; 56.38 + 15; 105.00; 66.54 + 16; 120.00; 73.34 + 17; 136.00; 81.82 + 18; 153.00; 94.12 + 19; 171.00; 103.36 + 20; 190.00; 109.78 + 21; 210.00; 121.60 + 22; 231.00; 131.76 + 23; 253.00; 143.06 + 24; 276.00; 156.52 + 25; 300.00; 175.36 + 26; 325.00; 182.90 + 27; 351.00; 192.02 + 28; 378.00; 212.32 + 29; 406.00; 227.84 + 30; 435.00; 243.40 + 31; 465.00; 262.58 + 32; 496.00; 278.14 + 33; 528.00; 293.86 + 34; 561.00; 312.92 + 35; 595.00; 332.28 + 36; 630.00; 344.32 + 37; 666.00; 354.34 + 38; 703.00; 397.18 + 39; 741.00; 410.56 + 40; 780.00; 429.42 + 41; 820.00; 453.40 + 42; 861.00; 461.80 + 43; 903.00; 485.46 + 44; 946.00; 517.10 + 45; 990.00; 540.00 + 46; 1035.00; 554.30 + 47; 1081.00; 575.34 + 48; 1128.00; 607.34 + 49; 1176.00; 620.18 + 50; 1225.00; 647.48 + 51; 1275.00; 693.96 + 52; 1326.00; 712.04 + 53; 1378.00; 732.64 + 54; 1431.00; 768.84 + 55; 1485.00; 794.12 + 56; 1540.00; 820.92 + 57; 1596.00; 822.34 + 58; 1653.00; 877.84 + 59; 1711.00; 917.66 + 60; 1770.00; 948.42 + 61; 1830.00; 956.04 + 62; 1891.00; 1005.00 + 63; 1953.00; 1042.60 + 64; 2016.00; 1037.82 + 65; 2080.00; 1087.02 + 66; 2145.00; 1147.22 + 67; 2211.00; 1184.68 + 68; 2278.00; 1215.44 + 69; 2346.00; 1239.10 + 70; 2415.00; 1247.28 + 71; 2485.00; 1310.14 + 72; 2556.00; 1336.78 + 73; 2628.00; 1395.50 + 74; 2701.00; 1417.10 + 75; 2775.00; 1464.58 + 76; 2850.00; 1482.62 + 77; 2926.00; 1545.84 + 78; 3003.00; 1566.48 + 79; 3081.00; 1622.52 + 80; 3160.00; 1637.64 + 81; 3240.00; 1686.34 + 82; 3321.00; 1740.88 + 83; 3403.00; 1789.50 + 84; 3486.00; 1814.38 + 85; 3570.00; 1857.88 + 86; 3655.00; 1929.30 + 87; 3741.00; 1980.88 + 88; 3828.00; 1973.52 + 89; 3916.00; 2066.94 + 90; 4005.00; 2085.78 + 91; 4095.00; 2125.72 + 92; 4186.00; 2220.08 + 93; 4278.00; 2240.44 + 94; 4371.00; 2283.70 + 95; 4465.00; 2359.88 + 96; 4560.00; 2385.16 + 97; 4656.00; 2450.00 + 98; 4753.00; 2473.96 + 99; 4851.00; 2531.32 +100; 4950.00; 2564.28 diff --git a/Tp07/analyse_tris.py b/Tp07/analyse_tris.py new file mode 100644 index 0000000..9d12c34 --- /dev/null +++ b/Tp07/analyse_tris.py @@ -0,0 +1,79 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +:mod:`analyse_tris` module +:author: FIL - Faculté des Sciences et Technologies - Univ. Lille <http://portail.fil.univ-lille1.fr>_ +:date: janvier 2017 +:dernières révisions: février 2018, février 2019 + +Analyse empirique des tris + +""" +from random import shuffle +from typing import Callable +from compare import compare +from ap_decorators import count +from tris import * + +################################################ +# ANALYSE EMPIRIQUE DES TRIS # +################################################ + +# ajout d'un compteur à la fonction compare +compare = count(compare) + +def analyser_tri(tri: Callable[[list[T], Callable[[T, T], int]], NoneType], + nbre_essais: int, + taille: int) -> float: + """ + renvoie: le nombre moyen de comparaisons effectuées par l'algo tri + pour trier des listes de taille t, la moyenne étant calculée + sur n listes aléatoires. + précondition: n > 0, t >= 0, la fonc + """ + res = 0 + for i in range(nbre_essais): + compare.counter = 0 + l = [k for k in range(taille)] + shuffle(l) + tri(l, compare) + res += compare.counter + return res / nbre_essais + + +if (__name__ == '__main__'): + from matplotlib import pyplot as plt + + # Calcul de nombres moyens de comparaison pour des listes + # de tailles comprises entre 0 et TAILLE_MAX + NB_ESSAIS = 50 + TAILLE_MAX = 100 + c_select = [0.0] * (TAILLE_MAX + 1) + c_insert = [0.0] * (TAILLE_MAX + 1) + + for t in range(TAILLE_MAX + 1): + c_select[t] = analyser_tri(tri_select, 1, t) + # inutile de moyenner pour le tri par sélection + c_insert[t] = analyser_tri(tri_insert, NB_ESSAIS, t) + + # Sauvegarde des données calculées dans un fichier au format CSV + prem_ligne = 'taille;"tri séléction";"tri insertion"\n' + ligne = '{:3d};{:8.2f};{:8.2f}\n' + with open('analyse_tris.csv', 'wt', encoding='utf8') as sortie: + sortie.write(prem_ligne) + for t in range(TAILLE_MAX + 1): + sortie.write(ligne.format(t, + c_select[t], + c_insert[t])) + + # Représentation graphique + plt.plot(list(range(TAILLE_MAX + 1)), c_select, 'b.', label='Tri sélection') + plt.plot(list(range(TAILLE_MAX + 1)), c_insert, 'r.', label='Tri insertion') + plt.title('Tris : nbre de comparaisons') + plt.legend() + plt.xlabel('n = taille des listes') + plt.ylabel('c(n) = nbre de comparaisons') + plt.savefig('tris_nbcomp.png') + plt.show() + diff --git a/Tp07/ap_decorators.py b/Tp07/ap_decorators.py new file mode 100644 index 0000000..5f4adc9 --- /dev/null +++ b/Tp07/ap_decorators.py @@ -0,0 +1,135 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +:module: ap_decorators +:author: FIL - Faculté des Sciences et Technologies - Univ. Lille <http://portail.fil.univ-lille1.fr>_ +:date: 2018, september + +""" + +from functools import wraps + + +def trace(fct): + ''' + Decorator for tracing every call to fct. + Recursive calls are indented. + + :Example: + + >>> @trace + ... def fact(n): + ... if n == 0: + ... return 1 + ... else: + ... return n * fact(n - 1) + + >>> fact(5) + -> fact((5,), {}) + ... -> fact((4,), {}) + ...... -> fact((3,), {}) + ......... -> fact((2,), {}) + ............ -> fact((1,), {}) + ............... -> fact((0,), {}) + ............... <- 1 + ............ <- 1 + ......... <- 2 + ...... <- 6 + ... <- 24 + <- 120 + 120 + ''' + @wraps(fct) + def wrapper(*args, **kwargs): + dots = '...' * wrapper.__depth + print('{:s} -> {:s}{:s}'.format(dots, wrapper.__name__, repr((args, kwargs)))) + wrapper.__depth += 1 + y = fct(*args, **kwargs) + wrapper.__depth -= 1 + print('{:s} <- {:s}'.format(dots, repr(y))) + return y + wrapper.__depth = 0 + return wrapper + +def count(fct): + ''' + decorator for counting calls to function fct + + :Example: + + >>> @count + ... def fact(n): + ... if n == 0: + ... return 1 + ... else: + ... return n * fact(n - 1) + + >>> fact.counter + 0 + >>> fact(5) + 120 + >>> fact.counter + 6 + ''' + @wraps(fct) + def wrapper(*args, **kwargs): + y = fct(*args, **kwargs) + wrapper.counter += 1 + return y + wrapper.counter = 0 + return wrapper + + +def memoize(fct): + ''' + decorator for memoizing computed values of function fct + + :Example: + + >>> @count + ... @memoize + ... def fact(n): + ... if n == 0: + ... return 1 + ... else: + ... return n * fact(n - 1) + + >>> fact.counter + 0 + >>> fact(5) + 120 + >>> fact.counter + 6 + >>> fact.counter = 0 + >>> fact(5) + 120 + >>> fact.counter + 1 + ''' + cache = dict() + @wraps(fct) + def wrapper(*args, **kwargs): + key = repr((args, kwargs)) + if key in cache: + return cache[key] + else: + y = fct(*args, **kwargs) + cache[key] = y + return y + return wrapper + + + +if __name__ == '__main__': + import doctest + doctest.testmod(optionflags=doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS, verbose=False) + + + + + + + + + diff --git a/Tp07/apl1test.py b/Tp07/apl1test.py new file mode 100644 index 0000000..8533cca --- /dev/null +++ b/Tp07/apl1test.py @@ -0,0 +1,89 @@ +import thonnycontrib +from thonnycontrib.backend.evaluator import Evaluator +import thonnycontrib.backend.l1test_backend +from thonny.plugins.cpython_backend.cp_back import MainCPythonBackend +import thonnycontrib.backend.doctest_parser +from thonnycontrib.backend.doctest_parser import ExampleWithExpected, ExampleWithoutExpected +import thonnycontrib.backend.ast_parser +from thonnycontrib.backend.ast_parser import L1DocTest +import thonnycontrib.backend.verdicts +from thonnycontrib.backend.verdicts.ExceptionVerdict import ExceptionVerdict + +import inspect +import tempfile +import os +import sys + +class MockBackend(MainCPythonBackend): + """ + Fake backend. + """ + def __init__(self): + ... + + def send_message(self, msg) -> None: + ... + +# register backend +thonnycontrib.backend.l1test_backend.BACKEND = MockBackend() + +def l1test_to_org(filename: str, source: str=""): + """ + Return an org abstract of the tests presents in `filename` file. + """ + abstract = {'total': 0, + 'success': 0, + 'failures': 0, + 'errors': 0, + 'empty': 0} + + if source == "": + with open(filename, 'rt') as fin: + source = fin.read() + evaluator = Evaluator(filename=filename, + source=source) + tests = evaluator.evaluate() + n = len(tests) + abstract['total'] = n + res = "" + for test in tests: + examples = test.get_examples() + res_examples = "" + nb_test, nb_test_ok = 0, 0 + empty = True + for example in examples: + verdict = test.get_verdict_from_example(example) + if isinstance(example, ExampleWithExpected): + nb_test += 1 + if verdict.isSuccess(): + nb_test_ok += 1 + abstract['success'] += 1 + else: + abstract['failures'] += 1 + empty = False + if isinstance(verdict, ExceptionVerdict): + abstract['errors'] += 1 + empty = False + res_examples += f"** {verdict}\n\n" + if not verdict.isSuccess(): + res_examples += f" {verdict.get_details()}\n\n" + if not empty: + res += f"* {test.get_name()} ~ {nb_test_ok}/{nb_test} réussis\n\n" + else: + abstract['empty'] += 1 + res += f"* {test.get_name()}\n\n Aucun test trouvé !\n\n" + res += res_examples + res = f"Tests exécutés : {abstract['total']}\nSuccès: {abstract['success']}, \ +Echecs: {abstract['failures']}, Erreurs: {abstract['errors']}, \ +Vide: {abstract['empty']}\n\n" + res + return res + + +def testmod(modulename: str): + """ + mimic the doctest.testmod function + for `modulename` module + """ + print(l1test_to_org(modulename)) + + diff --git a/Tp07/compare.py b/Tp07/compare.py new file mode 100644 index 0000000..abad0a4 --- /dev/null +++ b/Tp07/compare.py @@ -0,0 +1,44 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +:mod:`compare` module +:author: FIL - FST - Univ. Lille <http://portail.fil.univ-lille1.fr>_ +:date: 2016, january +:dernière révision: février 2018 + +Fonction de comparaison +pour l'analyse des algos de recherche et de tri + +""" +from typing import TypeVar + + +T = TypeVar('T') +def compare(x: T, y: T) -> int: + """ + renvoie: + - -1 si x < y + - 0 si x == y + - 1 si x > y + précondition: x et y doivent être d'un type pour lequel les opérateurs de comparaison <, <=, == + peuvent s'appliquer + exemples: + + $$$ compare(1, 3) + -1 + $$$ compare(3, 1) + 1 + $$$ compare(3, 3) + 0 + """ + if x == y: + return 0 + elif x > y: + return 1 + else: + return -1 + +if (__name__ == '__main__'): + import apl1test + apl1test.testmod('compare.py') diff --git a/Tp07/tp_tri.py b/Tp07/tp_tri.py new file mode 100755 index 0000000..bd3545d --- /dev/null +++ b/Tp07/tp_tri.py @@ -0,0 +1,32 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +:mod:`tris` module +:author: FIL - Faculté des Sciences et Technologies - + Univ. Lille <http://portail.fil.univ-lille1.fr>_ +:date: 2015, january +:dernière révision: mars 2024 + + +Tris de listes + +- tri par sélection +- tri par insertion + +""" + +from random import shuffle +import matplotlib.pyplot as plt + +def liste_alea(n:int) -> list[int]: + """ + Renvoie une liste de 0 à n-1 mélangé + Précondition : aucune + Exemple(s) : + $$$ + + """ + res = list(range(n)) + shuffle(res) + return res \ No newline at end of file diff --git a/Tp07/tris.py b/Tp07/tris.py new file mode 100644 index 0000000..18df740 --- /dev/null +++ b/Tp07/tris.py @@ -0,0 +1,193 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +:mod:`tris` module +:author: FIL - Faculté des Sciences et Technologies - + Univ. Lille <http://portail.fil.univ-lille1.fr>_ +:date: 2015, january +:dernière révision: février 2018 + + +Tris de listes + +- tri par sélection +- tri par insertion + +""" + +from types import NoneType +from typing import Callable, TypeVar +from compare import compare +T = TypeVar('T') + +def est_trie(liste: list[T], comp: Callable[[T, T], int] = compare) -> bool: + """ + renvoir True si et seulement si liste est triée selon l'ordre défini par comp + + précondition: les éléments de liste doivent être comparables selon comp + + exemples: + + $$$ est_trie([1, 2, 3, 4]) + True + $$$ est_trie([1, 2, 4, 3]) + False + $$$ est_trie([]) + True + """ + i = 0 + res = True + while res and i < len(liste) - 1: + res = comp(liste[i], liste[i+1]) <= 0 + i += 1 + return res + # ou plus simplement + # return all(comp(liste[i], liste[i+1]) <= 0 for i in range(len(liste)-1)) + + +################################################ +# TRI PAR SELECTION # +################################################ + +def echanger(liste: list[T], i: int, j: int) -> NoneType: + """ + échange les éléments d'indice i et j de liste. + + précondition: 0 <= i,j < len(liste) + + exemples: + + $$$ l1 = [3, 1, 4, 9, 5, 1, 2] + $$$ l2 = l1.copy() + $$$ echanger(l2, 3, 5) + $$$ (l1[3], l1[5]) == (l2[5], l2[3]) + True + """ + liste[i], liste[j] = liste[j], liste[i] + + +def select_min(liste: list[T], a: int, b: int, comp: Callable[[T, T], int]=compare) -> int: + """ + renvoie l'indice du minimum dans la tranche liste[a:b] + précondition: 0 <= a < b <= long(liste), + éléments de liste comparables avec comp + exemples: + + $$$ select_min([1, 2, 3, 4, 5, 6, 7, 0], 0, 8) + 7 + $$$ select_min([1, 2, 3, 4, 5, 6, 7, 0], 1, 7) + 1 + """ + ind_min = a + # l'indice du plus petit élément de la tranche liste[a:a+1] est ind_min + for i in range(a + 1, b): + # supposons que l'indice du plus petit élément de la + # tranche liste[a:i] est ind_min + if comp(liste[i], liste[ind_min]) == -1: + ind_min = i + # alors l'indice du plus petit élément de la tranche liste[a:i+1] + # est ind_min + # à l'issue de l'itération l'indice du plus petit élément de la tranche + # liste[a:b] est ind_min + return ind_min + + +def tri_select(liste: list[T], comp: Callable[[T, T], int] = compare) -> NoneType: + """ + modifie la liste liste en triant ses éléments selon l'ordre défini par comp + Algorithme du tri par sélection du minimum + précondition: liste liste homogène d'éléments comparables selon comp + exemples: + + $$$ liste = [3, 1, 4, 1, 5, 9, 2] + $$$ tri_select(liste) + $$$ liste == [1, 1, 2, 3, 4, 5, 9] + True + $$$ from random import randrange + $$$ l1 = [randrange(1000) for k in range(randrange(100))] + $$$ l2 = l1.copy() + $$$ tri_select(l2) + $$$ est_trie(l2) + True + $$$ all(l1.count(elt) == l2.count(elt) for elt in l1) + True + $$$ all(l1.count(elt) == l2.count(elt) for elt in l2) + True + """ + n = len(liste) + # la tranche liste[0:1] est triée + for i in range(n - 1): + # supposons la tranche liste[0:i+1] triée + ind_min = select_min(liste, i, n, comp=comp) + echanger(liste, i, ind_min) + # alors la tranche liste[0:i+1] est triée + # à l'issue de l'itération la tranche liste[0:n] est triée + + +################################################ +# TRI PAR INSERTION # +################################################ + +def inserer(liste: list[T], i: int, comp: Callable[[T, T], int] = compare) -> NoneType: + """ + insère l'élément liste[i] à sa place dans la tranche + liste[0:i+1] de sorte que cette tranche soit triée + si liste[0:i] l'est auparavant + + précondition: 0 <= i < long(liste) + éléments de liste comparables par comp + exemples: + + $$$ liste = [1, 2, 4, 5, 3, 7, 6] + $$$ inserer(liste, 4) + $$$ liste == [1, 2, 3, 4, 5, 7, 6] + True + $$$ inserer(liste, 5) + $$$ liste == [1, 2, 3, 4, 5, 7, 6] + True + $$$ inserer(liste, 6) + $$$ liste == [1, 2, 3, 4, 5, 6, 7] + True + """ + aux = liste[i] + k = i + while k >= 1 and comp(aux, liste[k - 1]) == -1: + liste[k] = liste[k - 1] + k = k - 1 + liste[k] = aux + + +def tri_insert(liste: list[T], comp: Callable[[T, T], int] = compare) -> NoneType: + """ + modifie la liste liste en triant ses éléments selon l'ordre défini par comp Algorithme du tri par insertion + précondition: liste liste homogène d'éléments comparables selon comp + exemples: + + $$$ liste = [3, 1, 4, 1, 5, 9, 2] + $$$ tri_insert(liste) + $$$ liste == [1, 1, 2, 3, 4, 5, 9] + True + $$$ from random import randrange + $$$ l1 = [randrange(1000) for k in range(randrange(100))] + $$$ l2 = l1.copy() + $$$ tri_insert(l2) + $$$ est_trie(l2) + True + $$$ all(l1.count(elt) == l2.count(elt) for elt in l1) + True + $$$ all(l1.count(elt) == l2.count(elt) for elt in l2) + True + """ + n = len(liste) + # la tranche liste[0:1] est triée + for i in range(1, n): + # supposons la tranche liste[0:i] triée + inserer(liste, i, comp=comp) + # alors la tranche liste[0:i+1] est triée + # à l'issue de l'itération la tranche liste[0:n] est triée + + +if (__name__ == '__main__'): + import apl1test + apl1test.testmod('tris.py') diff --git a/Tp07/tris_nbcomp.png b/Tp07/tris_nbcomp.png new file mode 100644 index 0000000000000000000000000000000000000000..a2ce8bdaaad372e005af87d22e90db36c52fb421 GIT binary patch literal 28343 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 XxwL9&T!SV90|SGntDnm{r-UW|=}iBV literal 0 HcmV?d00001 -- GitLab