From 8222b3441e65b4d01c23a79ab60aefc45af20e77 Mon Sep 17 00:00:00 2001 From: Timo Date: Fri, 24 Nov 2023 09:18:06 +0100 Subject: [PATCH 1/5] sorts done --- README.md | 19 ++++++++++++++++++- __main__.py | 28 +++++++++++++++++++++++++++- img/fusion graph.png | Bin 0 -> 31595 bytes img/insertion graph.png | Bin 0 -> 34052 bytes img/selection graph.png | Bin 0 -> 32026 bytes sort/fusion.py | 29 +++++++++++++++++++++++++++-- sort/insertion.py | 9 ++++++++- sort/range.py | 16 ++++++++++++++-- sort/selection.py | 8 +++++++- 9 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 img/fusion graph.png create mode 100644 img/insertion graph.png create mode 100644 img/selection graph.png diff --git a/README.md b/README.md index 74f925a..1d6ed12 100644 --- a/README.md +++ b/README.md @@ -88,8 +88,12 @@ Mesurez le temps d'éxécution pour un tableau de : Tracez le graphique correspondant. + + Quelle semble être la complexité de notre fonction de tri ? Cela est-il logique par rapport au code que vous avez implémenté ? *Écrivez votre réponse ici* +* La complexité de notre fonction de tri est O(n²). C'est logique par rapport au code que nous avons implémenté car nous avons deux boucles imbriquées. + ### 2. Tri par insertion Observez attentivement l'animation de tri par insertion ci-dessous pour en comprendre le fonctionnement. @@ -109,8 +113,12 @@ Mesurez le temps d'éxécution pour un tableau de : Tracez le graphique correspondant. + + Quelle semble être la complexité de notre fonction de tri ? Cela est-il logique par rapport au code que vous avez implémenté ? *Écrivez votre réponse ici* +* La complexité de notre fonction de tri est O(n²). C'est logique par rapport au code que nous avons implémenté car nous avons deux boucles imbriquées. + ### 3. Tri par fusion Le tri par fusion est plus complexe : il utilise en effet la récursion, c'est à dire une fonction qui s'appelle elle-même. @@ -174,16 +182,25 @@ Mesurez le temps d'éxécution pour un tableau de : Tracez le graphique correspondant. -Quelle semble être la complexité de notre fonction de tri ? Cela est-il logique par rapport au code que vous avez implémenté ? *Écrivez votre réponse ici* + + +Quelle semble être la complexité de notre fonction de tri ? Cela est-il logique par rapport au code que vous avez implémenté ? +* La complexité de notre fonction de tri est O(n log n). +ça peut s'expliquer par le fait que nous divisons le tableau en deux à chaque fois, et que nous fusionnons les tableaux en les triant. +la division du tableau en deux se fait en O(log n) et la fusion se fait en O(n). + Question bonus : Y a-t-il des tailles de tableaux pour lesquelles le tri par fusion n'est pas aussi rapide que les précédents tris abordés ? *Écrivez votre réponse ici* +* Le tri par fusion est plus rapide que les autres tris abordés pour toutes les tailles de tableaux. ### 4. sort() Bien que tout cela soit fascinant, Python possède sa propre méthode de tri : `sort()`. Une dernière fois, analysez le temps d'exécution et découvrez si python fait mieux que nos implémentations rudimentaires ;) +* après avoir fait plusieurs tests, il s'avère que la fonction sort() de python est plus rapide que le tri fusion qui était pourtant le plus rapide des tris que nous avons implémentés. + ## Pour rendre ce TP Merci de faire une Pull Request vers ce repository. diff --git a/__main__.py b/__main__.py index 98a585e..66523be 100644 --- a/__main__.py +++ b/__main__.py @@ -1,5 +1,31 @@ +import random +import time + +from sort import selection, insertion, fusion + + +def generate_array_of_number(n): + return [random.randint(0, 100) for _ in range(n)] + + +def measure_time(sort_function, array): + start = time.time() + sort_function(array) + end = time.time() + return end - start + + def main(): - print("Hello world") + sizes = [1000 * i for i in range(1, 11)] # 1000, 2000, ..., 10000 + algorithms = [selection.sort, insertion.sort, fusion.sort, sorted] + algorithms_names = ["Selection", "Insertion", "Fusion", "Python's sorted"] + + for algorithm, name in zip(algorithms, algorithms_names): + print(f"\nTime measurements for {name} sort:") + for size in sizes: + array = generate_array_of_number(size) + elapsed_time = measure_time(algorithm, array) + print(f"Size: {size}, Time: {elapsed_time} seconds") main() diff --git a/img/fusion graph.png b/img/fusion graph.png new file mode 100644 index 0000000000000000000000000000000000000000..05e2f4f1db26a0d11163129bb54e98e2205ba65a GIT binary patch literal 31595 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
{H%EJ)b#Y5D73_)cna(ZU-kg|_ z)ZkA%AG3Z|8*|K1D;M|*L9V^zH%g?X7i?cGp{s=4N9*r@qU$@N443}7g6)brv!s{` zYVX>Qq94Il4w(Bb993Z19PQu%Z$&pV@?0#(A&P?QkHQ73>)0-d_L=4MkFZ}MCG^kq zvg}-_gMowj%)b6YO4Hyze%L&2Lgj|X1Q z)wF^n1DJ1ZoS-Y?ssre8V#I(pEqbhV^n&6*HP}n19GQ$att0*aDvCwepTgp>>7F3# zr^Gm7pT#oQnuNZ0{4x1l^A&xnX!>NnO{EoNq=uE@V&pr}h^vvnz<6#lK1#4We@x5y#EHzN4xPSZNVD<9e)a-!0(2b=$H~uO%XQ?U^^!$2ma^c-Np~{%l6=ZaB2NdSTiC0s zQG(|d4}<5#B^-5xwn%CxH=>bbN5H!Pmv6r0FN_UUvd>P66#rn{hs{LA+#kmo)rBVwmJPgJK z#;rk2@NihuZyovpQy|h8mQzpwJAl3pRbQ##ug|x}p#0r^TJAjHMk`8ktM4p`tF1kN z>R%J*T{$LNJN*6E!pRYXe)_U{fS^;5`9w$WoyHDzq;lC(pxzs35X^z<&7H3=qAq;K zCRJBr*>-ds8S8UnHp|b^-@exf{kuI;PoOyVTs%xkBLD1E5ejAHQ{{{6;Le=M7nmBb ziyyvsuJeJl{N(lgjTaxbZk-bSIbje&_u`4o%(?wMl*v+=^RGU2lkNv_zSPo?e^cDE zEtU=6?kf+(o;dx|y(-K$#AWkAF|{}nOiPm=aA`q}$nqMxcHA5RNGn!H?OVk4$K7kc zK5VdkU&A|O>E7Mpq2>9VxIeh@Xjay(_r9KqbM|)}26RpTj9gQcQ&1;)fX!>o`77&aDs_$mD_&i^mH?p?BAFd%-a)Yr1 z?~wrs{UbS4*K1S@;`b!nD(_A2yD#Hw2DeJRW2vxiEpEAQa|RW5|9Fn1Nl;RZ zcEC>|l`!{^!>Vl5dOP&5VYa<74=yBW4)5NKyFuUCh0u3)x>XbIUCRb@6SF-%p0jcD zrR3zod6(g#Uz5+ade>9=mE5mXbk7Q10}>85eXlGiSnbt(8hYvWP|3UotV%ia`uZ|L zgPJ>~CDhVgLJu1f#jM-FE=w7zzsElcOgU=3#JN$uVH*|Blp6WEadL?VAMurjiDHF9AE82-k zGpiKm2+EVbH@8bSii|HgrVm${ zFk5C%Dz=%PrQPu!rg+%wN34U9ZDd)nf#!!w{}SlfH&M>bbO$w58Pe;#@vbYy(l{N*(A3R+>sUGkPwHI-beips-fm>sT zJNNk0;k?TsAx#@cGODN&3_g_F0ApE z@7+zEppYwf0Yk1t{-317T;1d4{JV(~0P+3*K&+x+;G&?V(T3Tpx$)hLnh_H7>yHtL z7q8%=V%L&_a*Quk=CQix$lb307fds*yMql4=T8R;@MLom2X|_y8{bz|6ClK&gcI;& zhMVai1b^P3*}1~vE5xju+QjHIw|vEI94SsR$NvkBWYX&5#BGQd$W{d2eJ*69BR09Xu)ktZc(?Pa=MJcn;E2_>e!>Ap_q2VykL zUQ7v05p}@i@fEI2Kho4h6AqZn+5&P%NVo)msZPY zO02a}nwE?IKHP=%7Z?a`cNCt!qfAyO3}Md(Zk(`ub(M5#$!SQd$@pm?Z*24D=h8*IybNc&YeDV_sqV%7j{HlZz+Nr`EmgYi2 z4RwE2mwiwX@yU&u%Qw!vXzCk#r64fZ*??~1qhHdu0v90rexTl%95XYi&EtTSgFB`# z*H#>-yE~B9wE`u+R^@(~Sqr-8*)yCZ VH)@b3Lq@=#!3E>Ae~A{cXtd(4BarK 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 literal 0 HcmV?d00001 diff --git a/sort/fusion.py b/sort/fusion.py index 73a21d3..0265324 100644 --- a/sort/fusion.py +++ b/sort/fusion.py @@ -1,2 +1,27 @@ -def sort(array: list[int]) -> list[int]: - return array +def merge(left, right): + result = [] + i = j = 0 + + while i < len(left) and j < len(right): + if left[i] < right[j]: + result.append(left[i]) + i += 1 + else: + result.append(right[j]) + j += 1 + + result.extend(left[i:]) + result.extend(right[j:]) + return result + + +def sort(array): + if len(array) <= 1: + return array + + mid = len(array) // 2 + left = sort(array[:mid]) + right = sort(array[mid:]) + + return merge(left, right) + diff --git a/sort/insertion.py b/sort/insertion.py index 73a21d3..0e7446e 100644 --- a/sort/insertion.py +++ b/sort/insertion.py @@ -1,2 +1,9 @@ -def sort(array: list[int]) -> list[int]: +def sort(array): + for i in range(1, len(array)): + key = array[i] + j = i - 1 + while j >= 0 and key < array[j]: + array[j + 1] = array[j] + j -= 1 + array[j + 1] = key return array diff --git a/sort/range.py b/sort/range.py index fc252ab..7d8a123 100644 --- a/sort/range.py +++ b/sort/range.py @@ -1,2 +1,14 @@ -def generate_array_of_number(array_size: int) -> list[int]: - return [] +import random +import time + + +def generate_array_of_number(n): + start = time.time() + array = [random.randint(0, 100) for _ in range(n)] + end = time.time() + print(f"Time taken to generate an array of {n} entries: {end - start} seconds") + return array + + +for i in range(1, 11): + generate_array_of_number(i * 1_000_000) \ No newline at end of file diff --git a/sort/selection.py b/sort/selection.py index 73a21d3..d26c193 100644 --- a/sort/selection.py +++ b/sort/selection.py @@ -1,2 +1,8 @@ -def sort(array: list[int]) -> list[int]: +def sort(array): + for i in range(len(array)): + min_index = i + for j in range(i + 1, len(array)): + if array[j] < array[min_index]: + min_index = j + array[i], array[min_index] = array[min_index], array[i] return array From d9b68e174462c9bfe0fdacb39954d9c26921358d Mon Sep 17 00:00:00 2001 From: Timo Date: Fri, 24 Nov 2023 10:24:50 +0100 Subject: [PATCH 2/5] big refactor --- .gitignore | 3 ++- README.md | 3 +++ __main__.py | 30 +++++++++++++++++------------- img/tableau random list.png | Bin 0 -> 4725 bytes sort/fusion.py | 30 ++++++++++++++++++++++-------- sort/insertion.py | 12 +++++++++--- sort/range.py | 18 +++++++++++------- sort/recursion.py | 11 ++++++++++- sort/selection.py | 10 ++++++++-- 9 files changed, 82 insertions(+), 35 deletions(-) create mode 100644 img/tableau random list.png diff --git a/.gitignore b/.gitignore index ed8ebf5..341e31e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -__pycache__ \ No newline at end of file +__pycache__ +.idea \ No newline at end of file diff --git a/README.md b/README.md index 1d6ed12..0281425 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,10 @@ Mesurez combien de temps prend python à générer un tableau composés de : Sur un tableur, générez un tableau permettant de visualiser le temps d'éxécution en fonction de la taille de l'entrée. + + Comment vous semble évoluer la courbe ? Observez bien les différentes courbes du graphique ci-dessous. Quelle est la plus ressemblante à notre situation ? *Écrivez votre réponse ici* +* La courbe semble évoluer de manière linéaire. La plus ressemblante à notre situation est la courbe O(n). diff --git a/__main__.py b/__main__.py index 66523be..61b5d23 100644 --- a/__main__.py +++ b/__main__.py @@ -1,30 +1,34 @@ -import random import time +from typing import Callable, List from sort import selection, insertion, fusion +from sort.range import generate_array_of_number -def generate_array_of_number(n): - return [random.randint(0, 100) for _ in range(n)] +def measure_time(sort_function: Callable[[list[int]], list[int]], array: list[int]) -> float: + """ + Measure the time it takes to run a sorting function on an array. - -def measure_time(sort_function, array): - start = time.time() + :param sort_function: The sorting function to be measured. + :param array: The array to be sorted. + :return: The time taken to run the sorting function on the array. + """ + start: float = time.time() sort_function(array) - end = time.time() + end: float = time.time() return end - start -def main(): - sizes = [1000 * i for i in range(1, 11)] # 1000, 2000, ..., 10000 - algorithms = [selection.sort, insertion.sort, fusion.sort, sorted] - algorithms_names = ["Selection", "Insertion", "Fusion", "Python's sorted"] +def main() -> None: + sizes: list[int] = [1000 * i for i in range(1, 11)] # 1000, 2000, ..., 10000 + algorithms: list[Callable[[list[int]], list[int]]] = [selection.sort, insertion.sort, fusion.sort, sorted] + algorithms_names: list[str] = ["Selection", "Insertion", "Fusion", "Python's sorted"] for algorithm, name in zip(algorithms, algorithms_names): print(f"\nTime measurements for {name} sort:") for size in sizes: - array = generate_array_of_number(size) - elapsed_time = measure_time(algorithm, array) + array: list[int] = generate_array_of_number(size) + elapsed_time: float = measure_time(algorithm, array) print(f"Size: {size}, Time: {elapsed_time} seconds") diff --git a/img/tableau random list.png b/img/tableau random list.png new file mode 100644 index 0000000000000000000000000000000000000000..1a78b153d3d0fa3ff452a0a9a52add2fa87b60bf GIT binary patch literal 4725 zcmb_gc|4SB`&S~~XhMey4_Y{qEoH(O326~0rzA#^wJbBC%w%LY$)2)gnNl664I$gu zpESr|D3Y;EgBiPFvSfS5@;K-B{?0$|=kxyKGw$cQ@9TSgzt?r$*XIuZ&D2=12?r(L0&D_7IT5fT8ctjDW4fQWzuZ*U-dos>s8J4N2)(#JT!D=iz z-_E#hG0A)J_yIXop>pn&VW~ibU`DM$tf=!CZDv|eE@a0E0lARb>)lHWJqGtQjwl=l z0uVeno=Kj*O|`tSTV-L#fx|3{p#wGbKUP=FYM;Qx;*7jD|78npmJ9ASF%+i=uAKm_ zt{h1ax}za-`M-5E0ixxJGHA36k4Vp+teEcEAyKpzJ_>k9=)$UQGbJ~*a+SMQ#JQRwC&xd_}VD5mKOt9 zw53le2wu(?zkKSlvbN(y^Euv8WAV2};^r0+rh-g4FLbPtYh38VFB!jU!)%@f=Ny1+ zYnlw;Ld!!_bgFNXt1WaU7Pc+E=X_l#_q5#DT&st2SPd=h+oS2rp~T(;Jti#+HEr4V zNY5HZD5}?#zA3+-M=NEmIy=k(5}f9{p}h)cQw z0pCsYqy7vmH}jO^2EO9$Kyq0!eqqQ;uUS_rZMnLIQ@8JKLWL)-SGC}-QHIu>*UzNH z4kIb)kSi-x5K8XFR zg(;IhABaK@n9B<%Jl0wZjX#SIy9JK^XRy^fgp`hv-c)}GXJ z{^d6BY5*%G?fP`q4w?q@)Ib)3>y%W+^Ji86!y2^Zgq-yv|?er&M zU80<)pjz;3Kp+aNl`$JAy@3P|a@N_*%FQ-wji+9JfG+YrrqC&xV7QXVp0n`ytghUu zTV5AmGUV0>iO0FvEbQljBHQ=V@BLVGMer4f5<&{$1*4HnHg1lD!o>gq!w*pR9)4LZ zm+Ot)CT%g}vuL3GOSNMHzDrYT*PP4k8%d4(uNCFmYe`UKjlZTvRPYqa`x;-y7oA-z zD$fug0eB9z$a;}GUtPKuEjKd0%|J3Z;GHzov-FvpoR*4l0=K6Z!Kh>iI~(!AE9Yt(mArP*z9R(c``T%eV292tdvAwVYx%#k8*E`e=Uex3hOWEIDzA4yc3o-3dxRGk zW$F47YrWol2W)u)Q6whQNw(hTFV#59$GP$l!A8s~qCX94r!NGUcJ|kuQa0{~ono-^ za~ti`v92`P_UV}3oa@m){`_S`hQQb>)BbTd-6pZ$z<;MZwLDJOH?MdcJHj#C>Kihk zR^laS(v{4S{z6sJ$8Wl^D!CAK@x+!l5Ys|s1hc8-MhBNJh{(exV-cY*I-W~FL^k7Q z^GF@VMO7V^j&Jy=LcGb@$SClGf$PqN zG2~T9iPN5F`QbB*7H(F9Z8oBLf%pZtY<~BecNB9?fG=7Z)!OpI8ktmYLZAzfucAPG zO-@?4%80?)q=ma14rSU8pg zUBC+nZ~HA)A%H9OGxd^iE+xur~5Yg(%~&= z`4b^7rhlJSRtKN}ghO*mcx{H(roWFxYi695TO{AJ1a4m}oI8KM4K zU7e|RbDZ|({<9;?9+S11Y{z$J+&rH%0xA$2HVErEiKcI=V89O(jmvx6gNW zl9@$XMx8S{+b6TVy0qr3{$VTwC!AXDo+Rw_Ph7SsXHxnqN)uU>zWKp0tY=q3-Jp7? z4NDSL18z30AqLYgv|IH$&6)zWh*$yC2e9tKcmtFE985z@L?AEaV-#R9<&C<$mWe4i z9y*xgN|)+t0P%pSHrMtH_NfnRif#d%U=8|A826v=MZnPVVU9O1EnUNZQeV2_7#KNv00Aowhnl`a^!36tge61zN$ohcdXvqQoTZN4;t zL4L7C!kE%yeSs)WamFJO?rZ#XmF3{MV_Cg+TAAJ80v=$4ImCb`p_JEP%Lhhc};s;h0t4e%602eo6DVJZ zzU^v@wqJ~CV((HQYubuyy}~TG27A0#x>a}gP1nicN*kiI@8fr1qFj1>Vl@S+5>9-< z&S)rFh_8`UpUr81&&+c+uAo0+XMWQk2sG?92lh}ejCa-{qzt9U7+j)4GUlHq2(8?Mq4df z#Jj*B@ry+>LrU&q*3-_uYV7IH-_pCb=h^3Rs)%Mz?ysXX7xI?_+A*6_;r^3;?1o5J zPU{D+Npr08(zJ^kZ^_{w2vqh*K7^D>qYTDoV7%Xq$wC6GmAtAq*!OtIeI5@SI!~C# z%1Y=y<$j^POm0Q{D=$l(lodo#Kn@(-?7Qol<&s;q%(L2gtnHL-xDE>BB{gqtWg3tl z>HcP(IquA;yDBjUk9TZ!Qz3Xx-gHACMn3M#kK_Y?=Gkk6h>AaU?Ue19Q18ypYH*wI zxm`Gx^L&^CuEKN-oQ$&&ee5AY=98Gf9B(2H<+kqX)|_ECYY+*?N*)r(Zm$X*v|(XI zpdW(cy#n$i@U2)n?x^}m=$|PMBe0cmyzoIuXBg;Y-}3z=w`4|SGNo1M^pO)=i&R5( zu(b?R|6t@nGhMwYr)!}yAI#h)sX%Lx7R{Z{C#mv6&@*M-0^W8z1;jyPteEDsUm85m z4i!SqYK4h4)t#k3qGT7+HH|FL_ht#b;g>waEnb#Ijt5J^)wYf5_8anL@BpE_{Pv$qNd@KX-s`{ zE@R}UIdim6mQoF>7n$mrAQV(X;i>UoPd1LiJJ_3n?WH2YFt|;p?y+l8G;%Q51V+cG z^aYyy2ukepkZGYK0V%SP*{>z;$-yK?rD#!2Kp2P)eETy2KsW*XLEE#( z18rRHlLmAWITMH2gQTt1OAWQyy91Q{-|{sa`WRmw7ibgC@6{3>H`yPtvntr~)TjyT zw&+~ggNX$%M>&}cX)mg=Q%l94<*}`5BCo2BYM=8V1relGWM3;S@R!690&fCB`rg05 z@UJ8lrYd!4wO~LQOW{7?Gn11>B8i+-Ph{I-6n>%V3N2nLk-SH`lZ00ecmnn#Vq1p= zO>ghJr^2L1_DV@I#HzY>JCQmUU&6(F1c>BiQT(q8GVJ5D=w@065v&lngYxU5jp8oE zaqGshg0#$sS9R~s@!j(yQ;b!Z*;37ZU9NLIkNKf0Mx?1Of*NV+bWP$8YP#%3Q2)ld+P4?~^Z<7-*x7?n zxJpT+r2Xe>OJ$8Nro80=_xa>LIz2wyaSkn1;WG69u2GfIz^V5M list[int]: + """ + Merge two lists in a sorted order. + + :param left: The first list to be merged. + :param right: The second list to be merged. + :return: A new list that is a sorted merge of the two input lists. + """ + result: list[int] = [] + i: int = 0 + j: int = 0 while i < len(left) and j < len(right): if left[i] < right[j]: @@ -15,13 +23,19 @@ def merge(left, right): return result -def sort(array): +def sort(array: list[int]) -> list[int]: + """ + Sorts an array in ascending order using the merge sort algorithm. + + :param array: The array to be sorted. + :return: The sorted array. + """ if len(array) <= 1: return array - mid = len(array) // 2 - left = sort(array[:mid]) - right = sort(array[mid:]) + # Divide the array into two halves and sort each half. + mid: int = len(array) // 2 + left: list[int] = sort(array[:mid]) + right: list[int] = sort(array[mid:]) return merge(left, right) - diff --git a/sort/insertion.py b/sort/insertion.py index 0e7446e..7347842 100644 --- a/sort/insertion.py +++ b/sort/insertion.py @@ -1,7 +1,13 @@ -def sort(array): +def sort(array: list[int]) -> list[int]: + """ + Sort the given array in ascending order using the insertion sort algorithm. + + :param array: The array to be sorted. + :return: The sorted array. + """ for i in range(1, len(array)): - key = array[i] - j = i - 1 + key: int = array[i] + j: int = i - 1 while j >= 0 and key < array[j]: array[j + 1] = array[j] j -= 1 diff --git a/sort/range.py b/sort/range.py index 7d8a123..ab8ff32 100644 --- a/sort/range.py +++ b/sort/range.py @@ -2,13 +2,17 @@ import time -def generate_array_of_number(n): - start = time.time() - array = [random.randint(0, 100) for _ in range(n)] - end = time.time() - print(f"Time taken to generate an array of {n} entries: {end - start} seconds") +def generate_array_of_number(n: int) -> list: + """ + :param n: The number of elements to generate in the array. + :return: A list of random integers with 'n' elements. + """ + array: list[int] = [random.randint(0, 100) for _ in range(n)] return array -for i in range(1, 11): - generate_array_of_number(i * 1_000_000) \ No newline at end of file +for i in range(10): + start: float = time.time() + generate_array_of_number(1_000_000 * (i + 1)) + end: float = time.time() + print(f"Size: {1_000_000 * (i + 1)}, Time: {end - start} seconds") \ No newline at end of file diff --git a/sort/recursion.py b/sort/recursion.py index e7f4320..ea6b025 100644 --- a/sort/recursion.py +++ b/sort/recursion.py @@ -1,2 +1,11 @@ def get_factorial(number: int) -> int: - return number + """ + Calculate the factorial of a given number. + + :param number: The number for which the factorial needs to be calculated. + :return: The factorial of the given number. + """ + if number == 0: + return 1 + return number * get_factorial(number - 1) + diff --git a/sort/selection.py b/sort/selection.py index d26c193..0fd0ac5 100644 --- a/sort/selection.py +++ b/sort/selection.py @@ -1,6 +1,12 @@ -def sort(array): +def sort(array: list[int]) -> list[int]: + """ + Sorts an array in ascending order using the selection sort algorithm. + + :param array: A list of integers to be sorted. + :return: The sorted list. + """ for i in range(len(array)): - min_index = i + min_index: int = i for j in range(i + 1, len(array)): if array[j] < array[min_index]: min_index = j From 6aeee99c7f1abf54c87ebd3df34f8d97f82107cc Mon Sep 17 00:00:00 2001 From: Timo Date: Fri, 24 Nov 2023 10:50:28 +0100 Subject: [PATCH 3/5] refactor again --- README.md | 13 ++++++++++--- __main__.py | 3 ++- sort/fusion.py | 2 ++ sort/range.py | 9 +-------- sort/recursion.py | 1 - sort/selection.py | 2 ++ 6 files changed, 17 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 0281425..cbbbd0c 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,8 @@ Observez attentivement l'animation de tri par sélection ci-dessous pour en comp Écrivez en français classique ce que vous voyez. Quel est le fonctionnement ? Comment l'expliqueriez-vous à quelqu'un ? *Écrivez votre réponse ici* +* Le tri par sélection consiste à parcourir le tableau pour trouver le plus petit élément, puis à le placer en première position. On recommence ensuite avec le deuxième plus petit élément, et ainsi de suite jusqu'à ce que le tableau soit trié. + Puis implémentez l'algorithme en python dans la fonction `sort` du fichier `sort/selection.py`. Vérifiez son bon fonctionnement en éxécutant le fichier `python3 -m unittest`. Le test correspondant au tri par sélection doit passer. Mesurez le temps d'éxécution pour un tableau de : @@ -91,7 +93,7 @@ Mesurez le temps d'éxécution pour un tableau de : Tracez le graphique correspondant. - + Quelle semble être la complexité de notre fonction de tri ? Cela est-il logique par rapport au code que vous avez implémenté ? *Écrivez votre réponse ici* @@ -105,6 +107,8 @@ Observez attentivement l'animation de tri par insertion ci-dessous pour en compr Écrivez en français classique ce que vous voyez. Quel est le fonctionnement ? Comment l'expliqueriez-vous à quelqu'un ? *Écrivez votre réponse ici* +* Le tri par insertion consiste à parcourir le tableau en plaçant au fur et à mesure chaque élément à sa place dans le tableau trié. Pour cela, on compare l'élément avec les éléments précédents, et on les décale vers la droite tant que l'élément est plus petit. + Puis implémentez l'algorithme en python dans la fonction `sort` du fichier `sort/insertion.py`. Utilisez les tests automatiques pour vérifier votre implémentation. Mesurez le temps d'éxécution pour un tableau de : @@ -116,7 +120,7 @@ Mesurez le temps d'éxécution pour un tableau de : Tracez le graphique correspondant. - + Quelle semble être la complexité de notre fonction de tri ? Cela est-il logique par rapport au code que vous avez implémenté ? *Écrivez votre réponse ici* @@ -167,6 +171,8 @@ Cet algorithme est de type "diviser pour régner". Écrivez en français classique ce que vous voyez. Quel est le fonctionnement ? Comment l'expliqueriez-vous à quelqu'un ? *Écrivez votre réponse ici* +* Le tri par fusion consiste à diviser le tableau en deux, puis de diviser chaque moitié jusqu'à ce qu'il ne reste plus que 1 ou 2 éléments. On trie ces éléments, puis on fusionne les tableaux, on les tries etc... jusqu'à ce qu'il ne reste plus qu'un seul tableau trié. + Complétez la fonction `sort` du fichier `sort/fusion.py` en suivant les instructions suivantes. Il vous faudra deux fonctions : @@ -185,7 +191,7 @@ Mesurez le temps d'éxécution pour un tableau de : Tracez le graphique correspondant. - + Quelle semble être la complexité de notre fonction de tri ? Cela est-il logique par rapport au code que vous avez implémenté ? * La complexité de notre fonction de tri est O(n log n). @@ -196,6 +202,7 @@ la division du tableau en deux se fait en O(log n) et la fusion se fait en O(n). Question bonus : Y a-t-il des tailles de tableaux pour lesquelles le tri par fusion n'est pas aussi rapide que les précédents tris abordés ? *Écrivez votre réponse ici* * Le tri par fusion est plus rapide que les autres tris abordés pour toutes les tailles de tableaux. + ### 4. sort() Bien que tout cela soit fascinant, Python possède sa propre méthode de tri : `sort()`. diff --git a/__main__.py b/__main__.py index 61b5d23..142b62f 100644 --- a/__main__.py +++ b/__main__.py @@ -1,5 +1,5 @@ import time -from typing import Callable, List +from typing import Callable from sort import selection, insertion, fusion from sort.range import generate_array_of_number @@ -24,6 +24,7 @@ def main() -> None: algorithms: list[Callable[[list[int]], list[int]]] = [selection.sort, insertion.sort, fusion.sort, sorted] algorithms_names: list[str] = ["Selection", "Insertion", "Fusion", "Python's sorted"] + # Loop to measure and print the time taken by each sorting algorithm for different array sizes for algorithm, name in zip(algorithms, algorithms_names): print(f"\nTime measurements for {name} sort:") for size in sizes: diff --git a/sort/fusion.py b/sort/fusion.py index c3fe3d5..457e75a 100644 --- a/sort/fusion.py +++ b/sort/fusion.py @@ -11,6 +11,7 @@ def merge(left: list[int], right: list[int]) -> list[int]: j: int = 0 while i < len(left) and j < len(right): + # Append the smaller element between left[i] and right[j] to the result if left[i] < right[j]: result.append(left[i]) i += 1 @@ -18,6 +19,7 @@ def merge(left: list[int], right: list[int]) -> list[int]: result.append(right[j]) j += 1 + # Append any remaining elements in left and right to the result result.extend(left[i:]) result.extend(right[j:]) return result diff --git a/sort/range.py b/sort/range.py index ab8ff32..bb4b7c7 100644 --- a/sort/range.py +++ b/sort/range.py @@ -1,18 +1,11 @@ import random -import time def generate_array_of_number(n: int) -> list: """ + Generate a list of random integers. :param n: The number of elements to generate in the array. :return: A list of random integers with 'n' elements. """ array: list[int] = [random.randint(0, 100) for _ in range(n)] return array - - -for i in range(10): - start: float = time.time() - generate_array_of_number(1_000_000 * (i + 1)) - end: float = time.time() - print(f"Size: {1_000_000 * (i + 1)}, Time: {end - start} seconds") \ No newline at end of file diff --git a/sort/recursion.py b/sort/recursion.py index ea6b025..25fbe2d 100644 --- a/sort/recursion.py +++ b/sort/recursion.py @@ -8,4 +8,3 @@ def get_factorial(number: int) -> int: if number == 0: return 1 return number * get_factorial(number - 1) - diff --git a/sort/selection.py b/sort/selection.py index 0fd0ac5..1aa268c 100644 --- a/sort/selection.py +++ b/sort/selection.py @@ -7,8 +7,10 @@ def sort(array: list[int]) -> list[int]: """ for i in range(len(array)): min_index: int = i + # Loop to find the index of the smallest element in the unsorted part of the array for j in range(i + 1, len(array)): if array[j] < array[min_index]: min_index = j + # Swap the found minimum element with the first element of the unsorted part array[i], array[min_index] = array[min_index], array[i] return array From efd17677fa1a75fd8482ca40e1c77042c01d6867 Mon Sep 17 00:00:00 2001 From: Timo Date: Fri, 24 Nov 2023 14:21:58 +0100 Subject: [PATCH 4/5] respect pycodestyle --- __main__.py | 22 ++++++++++++++++------ sort/selection.py | 5 +++-- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/__main__.py b/__main__.py index 142b62f..bcf08a2 100644 --- a/__main__.py +++ b/__main__.py @@ -5,7 +5,8 @@ from sort.range import generate_array_of_number -def measure_time(sort_function: Callable[[list[int]], list[int]], array: list[int]) -> float: +def measure_time(sort_function: Callable[[list[int]], list[int]], + array: list[int]) -> float: """ Measure the time it takes to run a sorting function on an array. @@ -20,11 +21,20 @@ def measure_time(sort_function: Callable[[list[int]], list[int]], array: list[in def main() -> None: - sizes: list[int] = [1000 * i for i in range(1, 11)] # 1000, 2000, ..., 10000 - algorithms: list[Callable[[list[int]], list[int]]] = [selection.sort, insertion.sort, fusion.sort, sorted] - algorithms_names: list[str] = ["Selection", "Insertion", "Fusion", "Python's sorted"] - - # Loop to measure and print the time taken by each sorting algorithm for different array sizes + sizes: list[int] = [1000 * i for i in + range(1, 11)] # 1000, 2000, ..., 10000 + + algorithms: list[Callable[[list[int]], list[int]]] = [ + selection.sort, + insertion.sort, + fusion.sort, + sorted + ] + algorithms_names: list[str] = ["Selection", "Insertion", "Fusion", + "Python's sorted"] + + # Loop to measure and print the time taken by each sorting algorithm for + # different array sizes for algorithm, name in zip(algorithms, algorithms_names): print(f"\nTime measurements for {name} sort:") for size in sizes: diff --git a/sort/selection.py b/sort/selection.py index 1aa268c..ad6f942 100644 --- a/sort/selection.py +++ b/sort/selection.py @@ -7,10 +7,11 @@ def sort(array: list[int]) -> list[int]: """ for i in range(len(array)): min_index: int = i - # Loop to find the index of the smallest element in the unsorted part of the array + # Find the index of the smallest element + # in the unsorted part of the array for j in range(i + 1, len(array)): if array[j] < array[min_index]: min_index = j - # Swap the found minimum element with the first element of the unsorted part + # Swap the smallest element with the first element of the unsorted part array[i], array[min_index] = array[min_index], array[i] return array From eedfad9d226689dee6e1e7874ca01f5e03a55c7d Mon Sep 17 00:00:00 2001 From: Timo Date: Fri, 24 Nov 2023 16:43:22 +0100 Subject: [PATCH 5/5] refactor --- sort/fusion.py | 55 ++++++++++++++++++++++++----------------------- sort/insertion.py | 7 +++--- sort/recursion.py | 4 +--- sort/selection.py | 2 ++ 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/sort/fusion.py b/sort/fusion.py index 457e75a..bd608b9 100644 --- a/sort/fusion.py +++ b/sort/fusion.py @@ -1,30 +1,3 @@ -def merge(left: list[int], right: list[int]) -> list[int]: - """ - Merge two lists in a sorted order. - - :param left: The first list to be merged. - :param right: The second list to be merged. - :return: A new list that is a sorted merge of the two input lists. - """ - result: list[int] = [] - i: int = 0 - j: int = 0 - - while i < len(left) and j < len(right): - # Append the smaller element between left[i] and right[j] to the result - if left[i] < right[j]: - result.append(left[i]) - i += 1 - else: - result.append(right[j]) - j += 1 - - # Append any remaining elements in left and right to the result - result.extend(left[i:]) - result.extend(right[j:]) - return result - - def sort(array: list[int]) -> list[int]: """ Sorts an array in ascending order using the merge sort algorithm. @@ -41,3 +14,31 @@ def sort(array: list[int]) -> list[int]: right: list[int] = sort(array[mid:]) return merge(left, right) + + +def merge(left_array: list[int], right_array: list[int]) -> list[int]: + """ + Merge two lists in a sorted order. + + :param left_array: The first list to be merged. + :param right_array: The second list to be merged. + :return: A new list that is a sorted merge of the two input lists. + """ + result: list[int] = [] + left_index: int = 0 + right_index: int = 0 + + while left_index < len(left_array) and right_index < len(right_array): + # Append the smaller element between + # left_array[left_index] and right_array[right_index] to the result + if left_array[left_index] < right_array[right_index]: + result.append(left_array[left_index]) + left_index += 1 + else: + result.append(right_array[right_index]) + right_index += 1 + + # Append any remaining elements in left and right to the result + result.extend(left_array[left_index:]) + result.extend(right_array[right_index:]) + return result diff --git a/sort/insertion.py b/sort/insertion.py index 7347842..b5dafc9 100644 --- a/sort/insertion.py +++ b/sort/insertion.py @@ -6,10 +6,9 @@ def sort(array: list[int]) -> list[int]: :return: The sorted array. """ for i in range(1, len(array)): - key: int = array[i] + value_to_insert: int = array[i] j: int = i - 1 - while j >= 0 and key < array[j]: - array[j + 1] = array[j] + while j >= 0 and value_to_insert < array[j]: j -= 1 - array[j + 1] = key + array.insert(j + 1, array.pop(i)) return array diff --git a/sort/recursion.py b/sort/recursion.py index 25fbe2d..acc2bab 100644 --- a/sort/recursion.py +++ b/sort/recursion.py @@ -5,6 +5,4 @@ def get_factorial(number: int) -> int: :param number: The number for which the factorial needs to be calculated. :return: The factorial of the given number. """ - if number == 0: - return 1 - return number * get_factorial(number - 1) + return 1 if number == 0 else number * get_factorial(number - 1) diff --git a/sort/selection.py b/sort/selection.py index ad6f942..adc8c2b 100644 --- a/sort/selection.py +++ b/sort/selection.py @@ -7,11 +7,13 @@ def sort(array: list[int]) -> list[int]: """ for i in range(len(array)): min_index: int = i + # Find the index of the smallest element # in the unsorted part of the array for j in range(i + 1, len(array)): if array[j] < array[min_index]: min_index = j + # Swap the smallest element with the first element of the unsorted part array[i], array[min_index] = array[min_index], array[i] return array