Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 59 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,12 @@ 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*
<img src="./img/array_exectime.png">

Comment vous semble évoluer la courbe ? Observez bien les différentes courbes du graphique ci-dessous. Quelle est la plus ressemblante à notre situation ?

<span style="color:lightblue">Après des tests en générant des tableaux de 1M à 10M d'éléments, la croissance du temps de calcul semble évoluer
de manière linéaire (O(n))</span>.

<img src="img/o.webp" width="400">

Expand All @@ -75,7 +80,13 @@ Observez attentivement l'animation de tri par sélection ci-dessous pour en comp

<img src="img/selection.gif">

Écrivez en français classique ce que vous voyez. Quel est le fonctionnement ? Comment l'expliqueriez-vous à quelqu'un ? *Écrivez votre réponse ici*
Écrivez en français classique ce que vous voyez. Quel est le fonctionnement ? Comment l'expliqueriez-vous à quelqu'un ?
<br>
<span style="color:lightblue">
L'algorithme semble commencer au début du tableau. A chaque itération, l'algorithme va comparer le nombre actuel au plus petit
trouvé précédemment et ce jusqu'à atteindre la fin du tableau. Lorsque l'algorithme arrive à la fin du tableau, il échange le plus petit nombre trouvé
avec la position du premier nombre considéré comme "non trié". Il incrémente ensuite la position du début des nombres non triés et recommence à partir de la.</span>


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.

Expand All @@ -88,15 +99,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*
<img src="img/selection_exectime.png">

Quelle semble être la complexité de notre fonction de tri ? Cela est-il logique par rapport au code que vous avez implémenté ?
<br>
<span style="color:lightblue">
La complexité de l'algorithme par sélection semble être de O(N²), cela semble être logique car au mieux le tableau est déjà trié, au pire il faut accéder au tableau n + n-1 + n-2 + ... fois, ce qui est très long.
</span>

### 2. Tri par insertion

Observez attentivement l'animation de tri par insertion ci-dessous pour en comprendre le fonctionnement.

<img src="img/insertion.gif">

Écrivez en français classique ce que vous voyez. Quel est le fonctionnement ? Comment l'expliqueriez-vous à quelqu'un ? *Écrivez votre réponse ici*
Écrivez en français classique ce que vous voyez. Quel est le fonctionnement ? Comment l'expliqueriez-vous à quelqu'un ?
<br>
<span style="color:lightblue">
L'algorithme commence au début du tableau. Pour chaque nombre, il regarde si le nombre derrière lui est supérieur. (Ou ne fait rien pour la première itération). Si le nombre derrière est plus grand, il continue avec le nombre encore derrière jusqu'à ce que le nombre soit inférieur, auquel cas il insère le nombre juste après lui. Il marque ce nombre comme "rangé" et passe au nombre non rangé suivant.
</span>

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.

Expand All @@ -109,7 +130,13 @@ 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*
<img src="img/insertion_exectime.png">

Quelle semble être la complexité de notre fonction de tri ? Cela est-il logique par rapport au code que vous avez implémenté ?
<br>
<span style="color:lightblue">
La complexité de l'algorithme par sélection semble être de O(N²), cela semble être logique car au mieux chaque élément est trié et donc il n'y a aucun déplacement, au pire chaque élément inséré est inséré au tout début du tableau, ce qui peut être très long.
</span>

### 3. Tri par fusion

Expand Down Expand Up @@ -154,7 +181,11 @@ Observez bien le schéma suivant : il représente le concept du tri par fusion.

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*
Écrivez en français classique ce que vous voyez. Quel est le fonctionnement ? Comment l'expliqueriez-vous à quelqu'un ?
<br>
<span style="color:lightblue">
L'algorithme utilise la méthode dite dichotomique (divier pour régner). Il commence par diviser le tableau en deux autant de fois que nécéssaire afin d'arriver à une seule valeur par tableau. L'algorithme fusionne ensuite les deux tableaux en comparant les deux et en insérant les valeurs des deux tableaux en ordre croissant.
</span>

Complétez la fonction `sort` du fichier `sort/fusion.py` en suivant les instructions suivantes.

Expand All @@ -174,16 +205,36 @@ 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*
<img src="./img/fusion_exectime.png">

Quelle semble être la complexité de notre fonction de tri ? Cela est-il logique par rapport au code que vous avez implémenté ?
<br>
<span style="color:lightblue">
La complexité (malgré les apparences) est de O(n log n). Cela est logique car contrairement aux algorithmes précédents, il n'y a pas
d'imbrication de boucle.
</span>

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*
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 ?
<br>
<span style="color:lightblue">
Sachant que la complexité des algorithmes précédents est n² et que la complexité actuelle est de n\*log(n), le tri par fusion sera toujours plus rapide car pour n'importe quelle valeur de n supérieur à 0, n\*log(n) < n².
</span>

### 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 ;)

<img src="./img/python_exectime.png"/>

<span style="color:lightblue">
Python semble faire mieux que nous, le temps d'exécution comparé au Fusion Sort est plus rapide d'un facteur 100 !
Pour une même taille de tableau, le sort natif de python met 100x moins de temps que notre fusion sort.
<br>
La complexité de l'algorithme implémenté par python semble être 0(n).
</span>

## Pour rendre ce TP

Merci de faire une Pull Request vers ce repository.
Expand Down
48 changes: 47 additions & 1 deletion __main__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,51 @@
import sort.range as srange
import sort.selection as selection
import sort.insertion as insertion
import sort.fusion as fusion
import time


def main():
print("Hello world")
"""This is the main function !"""

# Array Generation
"""for i in range(1000000, 1100000, 100000):
start: float = time.time()
array: list[int] = srange.generate_array_of_number(i)
end: float = time.time()
print(str(end - start).replace(".", ","))"""

# Selection Sort
"""for i in range(10000, 100000, 10000):
array: list[int] = srange.generate_array_of_number(i)
start: float = time.time()
selection.sort(array)
end: float = time.time()
print(str(end - start).replace(".", ","))"""

# Insertion Sort
"""for i in range(10000, 100000, 10000):
array: list[int] = srange.generate_array_of_number(i)
start: float = time.time()
insertion.sort(array)
end: float = time.time()
print(str(end - start).replace(".", ","))"""

# Fusion Sort
"""for i in range(100000, 3100000, 100000):
array: list[int] = srange.generate_array_of_number(i)
start: float = time.time()
fusion.sort(array)
end: float = time.time()
print(str(end - start).replace(".", ","))"""

# Python Sort
for i in range(100000, 3100000, 100000):
array: list[int] = srange.generate_array_of_number(i)
start: float = time.time()
array.sort()
end: float = time.time()
print(str(end - start).replace(".", ","))


main()
Binary file added img/array_exectime.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/fusion_exectime.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/insertion_exectime.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/python_exectime.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/selection_exectime.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 39 additions & 1 deletion sort/fusion.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,40 @@
def sort(array: list[int]) -> list[int]:
return array
# Arrays of size 0/1 are already sorted.
if len(array) < 2:
return array

if len(array) > 2:
# Split and merge sorted
middle: int = len(array) // 2 + 1
return merge(sort(array[:middle]), sort(array[middle:]))
else:
# For array of size 2, just swap if needed
return [array[1], array[0]] if array[1] < array[0] else array
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Soit le comportement (simplifié) de la fonction merge pour ce cas précis. Il serait plus clair de rester sur la fonction merge plutôt que de répliquer ce comportement ici.



def merge(array_1: list[int], array_2: list[int]):
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type de retour manquant

final_array: list[int] = []
index_1: int = 0
index_2: int = 0
len_1: int = len(array_1)
len_2: int = len(array_2)

for i in range(len_1 + len_2):
# If either list is empty, that means the other list is the end of
# the final array
if index_1 == len_1:
final_array += array_2[index_2:]
break
elif index_2 == len_2:
final_array += array_1[index_1:]
break

# Append the smallest value of either list.
if array_1[index_1] < array_2[index_2]:
final_array.append(array_1[index_1])
index_1 += 1
else:
final_array.append(array_2[index_2])
index_2 += 1

return final_array
24 changes: 24 additions & 0 deletions sort/insertion.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,26 @@
def sort(array: list[int]) -> list[int]:
"""Sorts the array using the insertion sort method."""
# Arrays of size 0/1 are already sorted.
if len(array) < 2:
return array

array_length: int = len(array)

for i in range(array_length):
# Skip first
if i == 0:
continue
Comment on lines +11 to +12
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On peut supprimer ça si on part directement du bon index ;)


# Main logic loop
new_index = i
while new_index > 0:
if array[new_index - 1] < array[i]:
break

new_index -= 1

# Insert value right after the first number less than it
value_to_insert = array.pop(i)
array.insert(new_index, value_to_insert)

return array
5 changes: 4 additions & 1 deletion sort/range.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
import random


def generate_array_of_number(array_size: int) -> list[int]:
return []
return [random.randint(0, 100) for i in range(array_size)]
5 changes: 4 additions & 1 deletion sort/recursion.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
def get_factorial(number: int) -> int:
return number
if number > 1:
return number * get_factorial(number - 1)
else:
return 1
Comment on lines +2 to +5
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Utiliser un ternaire ?

18 changes: 18 additions & 0 deletions sort/selection.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,20 @@
def sort(array: list[int]) -> list[int]:
"""Sorts the given array using the selection sort method."""
# Arrays of size 0/1 are already sorted.
if len(array) < 2:
return array

array_length: int = len(array)

for i in range(array_length - 1):
# Sorting iteration loop
min_index: int = i
for j in range(i, array_length):
min_index = j if array[j] < array[min_index] else min_index

# If the current index is already sorted, do nothing.
if min_index != i:
# Swap the minimum and current numbers
array[i], array[min_index] = array[min_index], array[i]

return array