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
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +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.

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

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 être une droite. Cela signifie que le temps d'éxécution est proportionnel à la taille de l'entrée. La complexité semble linéaire et ressemble à la courbe de complexité O(N).

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

#### Quelques exemples de complexités courante :
Expand All @@ -77,6 +81,14 @@ 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 fonctionnement de ce tri est le suivant :

* Vous commencez par regarder toutes les valeurs et vous trouvez la plus petite.
* Une fois que vous avez identifié la plus petite valeur vous la mettez au tout début de la liste ( dans le cas où on trie dans l'ordre croissant comme ici par exemple ).
* Ensuite, vous regardez les valeurs restantes et vous trouvez la nouvelle valeur la plus petite.
* Vous la mettez au début de la liste juste après la précédente valeur triée.
* Vous répétez ce processus jusqu'à ce que toutes les valeurs soient triées.

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 :
Expand All @@ -88,8 +100,13 @@ Mesurez le temps d'éxécution pour un tableau de :

Tracez le graphique correspondant.

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

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é semble être quadratique ( O(N²) ). Cela 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.
Expand All @@ -98,6 +115,14 @@ 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 fonctionnement de ce tri est le suivant :

* Vous prenez le premier élément de la liste et vous le considérez comme une liste triée de un élémént.
* Ensuite vous parcourez le reste de la liste et vous insérez chaque élément dans la liste triée de manière à ce que la liste reste triée.
* Pour insérer un élément dans la liste triée, vous parcourez la liste triée de la fin vers le début et vous décalez les éléments jusqu'à ce que vous trouviez la bonne place pour insérer l'élément.
* Vous répétez ce processus jusqu'à ce que tous les éléments soient triés.


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 :
Expand All @@ -109,8 +134,12 @@ Mesurez le temps d'éxécution pour un tableau de :

Tracez le graphique correspondant.

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

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é semble aussi être quadratique ( O(N²) ). Cela est logique par rapport au code que nous avons implémenté car nous avons également 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.
Expand Down Expand Up @@ -156,6 +185,13 @@ 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 fonctionnement du tri par fusion est le suivant :

* Vous prenez la liste à trier et vous la divisez en deux listes.
* Vous répétez ce processus jusqu'à ce que vous ayez des listes de taille 1.
* Ensuite vous fusionnez les listes deux par deux en les triant.
* Vous répétez ce processus jusqu'à ce que vous ayez une seule liste triée.

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

Il vous faudra deux fonctions :
Expand All @@ -174,16 +210,26 @@ Mesurez le temps d'éxécution pour un tableau de :

Tracez le graphique correspondant.

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

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é semble être linéarithmique ( O(N log(N)) ). Cela est logique par rapport au code que nous avons implémenté car nous avons une boucle qui divise le tableau en deux et une autre boucle qui fusionne les tableaux.

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

Graphique pour la fonction `sort()` de python :

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

## Pour rendre ce TP

Merci de faire une Pull Request vers ce repository.
Expand Down
62 changes: 61 additions & 1 deletion __main__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,65 @@
import time
from typing import Callable
from typing import TypedDict

from sort.fusion import sort as fusion_sort
from sort.insertion import sort as insertion_sort
from sort.range import generate_array_of_number
from sort.selection import sort as selection_sort

algorithms = (
insertion_sort,
selection_sort,
fusion_sort,
)

array_sizes = (1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000)
array_sizes_generate_array = (1_000_000, 2_000_000, 3_000_000, 4_000_000,
5_000_000, 6_000_000, 7_000_000, 8_000_000,
9_000_000, 10_000_000)


class FunctionMetrics(TypedDict):
"""Function metrics"""
name: str
sort_metrics: dict[int, float]


def get_metrics(sort_function: Callable) -> dict[int, float]:
"""Get metrics for sort functions"""
time_metric: dict[int, float] = {}
for array_size in array_sizes:
start_time = time.time()
print(f"Testing for array size: {array_size}")
sort_function(generate_array_of_number(array_size))
end_time = time.time()
time_metric[array_size] = end_time - start_time
return time_metric


def main():
print("Hello world")

# Used to test the time it takes to sort lists using python sort function
for array_size in array_sizes:
start_time = time.time()
generate_array_of_number(array_size).sort()
end_time = time.time()
print(end_time - start_time)

# Used to test the time it takes to sort lists using the fusion sort,
# selection sort and insertion sort algorithms
metrics: list[FunctionMetrics] = []
for algorithm in algorithms:
metrics.append({
"name": algorithm.__name__,
"sort_metrics": get_metrics(algorithm)
})

# Print metrics
for metric in metrics:
print(f"Metrics for {metric['name']}")
for array_size, time_metric in metric["sort_metrics"].items():
print(f"Array size: {array_size} - Time: {time_metric}")


main()
Binary file added img/Courbe_Fusion_sort.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/Courbe_Insertion_sort.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/Courbe_Python_sort.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/Courbe_Selection_sort.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/Tableau_Range.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: 38 additions & 2 deletions sort/fusion.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,38 @@
def sort(array: list[int]) -> list[int]:
return array
def sort(input_list: list[int]) -> list[int]:
"""
Merge sort algorithm

:param input_list: The list to be sorted.
:return: The sorted list.
"""
if len(input_list) <= 1:
return input_list

# Split input_list in half
middle = len(input_list) // 2
left = sort(input_list[:middle])
right = sort(input_list[middle:])

return merge(left, right)


def merge(left_list: list[int], right_list: list[int]) -> list[int]:
"""Merge two sorted lists into one sorted list"""
merged_result = []
left_index = right_index = 0

# Compare elements from left and right lists and add the smallest
# one to the result
while left_index < len(left_list) and right_index < len(right_list):
if left_list[left_index] < right_list[right_index]:
merged_result.append(left_list[left_index])
left_index += 1
else:
merged_result.append(right_list[right_index])
right_index += 1

# Append the remaining elements from left and right lists
merged_result.extend(left_list[left_index:])
merged_result.extend(right_list[right_index:])

return merged_result
27 changes: 25 additions & 2 deletions sort/insertion.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,25 @@
def sort(array: list[int]) -> list[int]:
return array
def sort(input_list: list[int]) -> list[int]:
"""
Insertion sort algorithm

:param input_list: The list to be sorted.
:return: The sorted list.
"""
for current_index in range(1, len(input_list)):
current_value = input_list[current_index]
position = current_index

# Find the right position for current_value
while position > 0 and current_value < input_list[position - 1]:
position -= 1

# Once the right position is found, shift all elements between
# position and current_index to the right by one.
if position != current_index:
for i in range(current_index, position, -1):
input_list[i] = input_list[i - 1]

# Place the current_value at its correct position
input_list[position] = current_value

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


def generate_array_of_number(array_size: int) -> list[int]:
return []
"""
Generates an array of random numbers

:param array_size:
:return: array of random numbers
"""
return [random.randint(0, 100) for i in range(array_size)]
8 changes: 7 additions & 1 deletion sort/recursion.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
def get_factorial(number: int) -> int:
return number
"""
Gets the factorial of a number.

:param number:
:return: factorial of a number
"""
return 1 if number == 0 else number * get_factorial(number - 1)
27 changes: 25 additions & 2 deletions sort/selection.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,25 @@
def sort(array: list[int]) -> list[int]:
return array
def sort(input_list: list[int]) -> list[int]:
"""
Selection sort algorithm

:param input_list: The list to be sorted.
:return: The sorted list.
"""
# Iterate over the entire list
for current_index in range(len(input_list)):
# Assume the current index is the index of the smallest element
min_index = current_index

# Iterate over the rest of the list
for comparison_index in range(current_index + 1, len(input_list)):
# If a smaller element is found, update min_index
if input_list[min_index] > input_list[comparison_index]:
min_index = comparison_index

# Swap the current element with the smallest element found in
# the unsorted part of the list
input_list[current_index], input_list[min_index] = input_list[
min_index], input_list[current_index]

# Return the sorted list
return input_list