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
60 changes: 51 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,11 @@ 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*
Comment vous semble évoluer la courbe ? Observez bien les différentes courbes du graphique ci-dessous. Quelle est la plus ressemblante à notre situation ?

Le temps de géneration de nombres aléatoire évolut de façon linéaire -> O(n) (résulats des tests dans le fichier `sort/range.py`)

<img src="img/graph_generation_nombres_aleatoires.PNG">

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

Expand All @@ -75,7 +79,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 ?

1: On parcourt le tableau et on note le nombre le plus petit
2: Une fois le tableau parcourut on déplace le nombre le plus petit au début du tableau
3: On reparcourt le tableau en partant de la deuxième entrée du tableau et on note le nombre le plus petit
4: Une fois le tableau parcourut on déplace le nombre le plus petit à la deuxième case de tableau
5: On repète se processus autant de fois qu'il y a de cases dans le tableau

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 +98,28 @@ 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é ?

L'algorithme semble etre de compléxité O(n²) car quand on double le nomdre d'entrées, le temps d'éxecution est multiplié par 4

<img src="img/graph_tri_par_selection.PNG">

### 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 ?

1: On selectionne le premier nombre et on va considérer qu'il se trouve dans une partie du tableau qui est trié

2: On prends le deuxième nome et on va le comparer avec le premier nombre, si il est plus petit on va le placer avant le premier, sinon on le place en deuxième. Maintenant la partie trié de tableau est de taille 2

3: On prends le troisème nombre, on le compare avec le deuxième, si il est plus petit on le compare au premier, on le place en fonction et
notre tableau trié contient maintenant 3 nombres

4: On répete ces opérations pour tout les nombre du tableau

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 +132,11 @@ 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é ?

Le début du graphique resemble à la courbe du tri par selection, donc un O(n²) mais elle semble progrésser plus lentement ensuite pour ressembler un peu plus à un O(n*log(n))

<img src="img/graph_tri_par_insertion.PNG">

### 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 ?

1: On divise le tableau, autant de fois que nécessaire afin d'arriver avec des morceaux de taille 1
2: On compare les morceaux de taille 1 et on les concatène dans l'ordre croissant, on obtient des morceaux de taille 2 (et 1 morceau de taille 1 si la taille du tableau est impaire)
3: On fusion les tableaux en placant les nombres dans l'orde croissant on répète cette étape jusquà avoir fusion tout les morceaux en un seul

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

Expand All @@ -174,15 +205,26 @@ 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 compléxité semble être O(n*log(n))

<img src="img/graph_tri_par_fusion.PNG">

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 ?

Lors de mes tests, le tri par fusion a été le plus rapide peut importe la taille des données

### 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 ;)
Une dernière fois, analysez le temps d'exécution et découvrez si python fait mieux que nos implémentations rudimentaires ;

La fonction sort de python est largement plus rapide, en moyenne 100x plus rapide

<img src="img/graph_python_sort.PNG">


## Pour rendre ce TP

Expand Down
49 changes: 48 additions & 1 deletion __main__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,52 @@
from sort.range import generate_array_of_number
from sort.insertion import sort as insertion_sort
from sort.selection import sort as selection_sort
from sort.fusion import sort as fusion_sort
from sort.recursion import get_factorial
import time


def main():
print("Hello world")
for sample_size in range(0, 10_000_000, 1_000_000):
start: float = time.time()
sample: list[int] = generate_array_of_number(sample_size)
end: float = time.time()
print(f"Génération de {sample_size} nombres aléatoires en \
{end-start:.2f}s")

for sample_size in range(1_000, 11_000, 1_000):
sample: list[int] = generate_array_of_number(sample_size)
start: float = time.time()
sorted_sample: list[int] = selection_sort(sample)
end: float = time.time()
print(f"Tri par selection: taille tableau={sample_size}, \
temps={end-start}s")

for sample_size in range(1_000, 11_000, 1_000):
sample: list[int] = generate_array_of_number(sample_size)
start: float = time.time()
sorted_sample: list[int] = insertion_sort(sample)
end: float = time.time()
print(f"Tri par insertion: taille tableau={sample_size}, \
temps={end-start}s")

# print(get_factorial(5))

for sample_size in range(1_000, 11_000, 1_000):
sample: list[int] = generate_array_of_number(sample_size)
start: float = time.time()
sorted_sample: list[int] = fusion_sort(sample)
end: float = time.time()
print(f"Tri par fusion: taille tableau={sample_size}, \
temps={end-start}s")

for sample_size in range(100_000, 1_100_000, 100_000):
sample: list[int] = generate_array_of_number(sample_size)
start: float = time.time()
sample.sort()
end: float = time.time()
print(f"Tri Python: taille tableau={sample_size}, \
temps={end-start}s")


main()
Binary file added img/graph_generation_nombres_aleatoires.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/graph_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/graph_tri_par_fusion.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/graph_tri_par_insertion.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/graph_tri_par_selection.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
76 changes: 75 additions & 1 deletion sort/fusion.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,76 @@
def sort(array: list[int]) -> list[int]:
return array
"""sort the array using fusion sort"""
return fusion_sort(array)


def fusion_sort(array: list[int]) -> list[int]:
# Fusion sort est une fonction récursive, elle s'apelle elle même
# On commence donc par définir les conditions de fin de cette recursion

# Si le passé est vide on arrette la récursion
if array == []:
return []

size: int = len(array)

# Si le tableau est de taille 1, on arrete la récursion
if size == 1:
return array

# La fonction s'appelle elle même deux fois,
# Une fois pour chaque moitiée du tableau,
# afin de couper le tableau jusqu'a avoir des morceaux de taille 1
first_half: list[int] = fusion_sort(array[:size//2])
second_half: list[int] = fusion_sort(array[size//2:])

# Le premier tableau peut être vide
# exemple:
# array = [1]
# size = 1 => size//2 = 0
# first_half = [1][:0] = []
# second_half = [1][0:] = [1]

# On fusionne nos deux tableaux
return fuse_2_array(first_half, second_half)


def fuse_2_array(array1: list[int], array2: list[int]) -> list[int]:
"""Fuse 2 arrays into 1, the result array is sorted"""

# Le premier tableau peut être vide apres le passage dans fusion sort
# Voir commentaires dans fusion_sort
if array1 == []:
return array2

# On a un curseur dans chacun des tableaux
index1: int = 0
index2: int = 0

size1: int = len(array1)
size2: int = len(array2)

sorted_array: list[int] = []
while len(sorted_array) < size1 + size2:
# Si l'un ou l'autre des curseurs a atteinds la fin de son tableau
# alors on insère les données de l'autre tableau
if index1 >= size1 and index2 < size2:
sorted_array += array2[index2:]
break
elif index2 >= size2 and index1 < size1:
sorted_array += array1[index1:]
break

# Sinon comportement classique, on insère le plus petit des deux
# nombres en premier
number1: int = array1[index1]
number2: int = array2[index2]

if number1 < number2:
sorted_array.append(number1)
index1 += 1
else:
sorted_array.append(number2)
index2 += 1

# print(f"fuse {array1} and {array2} => {res}")
return sorted_array
35 changes: 35 additions & 0 deletions sort/insertion.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,37 @@
def sort(array: list[int]) -> list[int]:
"""Sort the array using insertion sort"""

# nombre de nombre trié dans le tableau
# On commence à 1 puisque qu'un tableau de taille 1 est trié
number_of_sorted_numbers: int = 1

# On parcours le tableau dans le sens croissant
for index in range(1, len(array)):
number: int = array[index]
# on parcours la partie trié du tableau dans le sens décroissant
for sorted_num_index in reversed(range(0, number_of_sorted_numbers)):
sorted_number = array[sorted_num_index]

if number < sorted_number and sorted_num_index > 0:
# Le nombre actuel est plus petit que le nombre trié
# et on n'est pas encore a la première case
# On continue de traverser le tableau trié
continue

# On insère notre nombre, On vérifie si num<sorted_num
# Car on peut se trouver dans le cas où index==0
# On doit donc vérifier où placer le nombre
#
# Si number > sorted_number alors,
# on insert number après l'index actuel
# Sinon insert à l'index actuel
array.pop(index)
array.insert(sorted_num_index + (number > sorted_number), number)

# Le nombre de nombre trié augmente
number_of_sorted_numbers += 1

# On a placé notre nombre, on quitte cette boucle
break

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


def generate_array_of_number(array_size: int) -> list[int]:
return []
"""Generates an array of size `array_size` filled with random numbers
between 0 and 100"""
random_numbers: list[int] = [random.randint(0, 100)
for i in range(array_size)]
return random_numbers

# Résultats
# Génération de 1000000 nombres aléatoires en 1.42s
# Génération de 2000000 nombres aléatoires en 3.20s
# Génération de 3000000 nombres aléatoires en 3.96s
# Génération de 4000000 nombres aléatoires en 5.15s
# Génération de 5000000 nombres aléatoires en 6.32s
# Génération de 6000000 nombres aléatoires en 7.66s
# Génération de 7000000 nombres aléatoires en 8.97s
# Génération de 8000000 nombres aléatoires en 10.20s
# Génération de 9000000 nombres aléatoires en 11.47s
# Génération de 10000000 nombres aléatoires en 13.51s
3 changes: 2 additions & 1 deletion sort/recursion.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
def get_factorial(number: int) -> int:
return number
"""Returns the factorial of a number"""
return number * get_factorial(number-1) if number > 1 else 1
44 changes: 44 additions & 0 deletions sort/selection.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,46 @@
def sort(array: list[int]) -> list[int]:
"""Sorts the array using selection sort"""

array_size: int = len(array)

# `number_of_sorted_numbers` helps keep track of how many value has been
# sorted so far
# It tells us where we have to insert the lowest value we found
for number_of_sorted_numbers in range(array_size):

# `smallest_number_index` stores the index of the smallest number
# we intialize it with the index of the first value of the table that
# isnt sorted yet
smallest_number_index: int = number_of_sorted_numbers

# We go through the part of the table that is not sorted
# and store the smallest value
for index in range(number_of_sorted_numbers, array_size):
number: int = array[index]
if number < array[smallest_number_index]:
smallest_number_index = index

# We remove the smallest number with its index
smallest_number: int = array.pop(smallest_number_index)
# We insert it back after the other sorted numbers
array.insert(number_of_sorted_numbers, smallest_number)

return array


# Résultats
# Trie par insertion: taille tableau=1000, temps=0.10017824172973633s
# Trie par insertion: taille tableau=2000, temps=0.2648162841796875s
# Trie par insertion: taille tableau=3000, temps=0.5844788551330566s
# Trie par insertion: taille tableau=4000, temps=1.1860754489898682s
# Trie par insertion: taille tableau=5000, temps=1.6009154319763184s
# Trie par insertion: taille tableau=6000, temps=2.032719135284424s
# Trie par insertion: taille tableau=7000, temps=2.8216004371643066s
# Trie par insertion: taille tableau=8000, temps=3.711418867111206s
# Trie par insertion: taille tableau=9000, temps=4.674601316452026s
# Trie par insertion: taille tableau=10000, temps=5.86929988861084s
# Trie par insertion: taille tableau=11000, temps=8.09083604812622s
# Trie par insertion: taille tableau=16000, temps=15.981599569320679s
# Trie par insertion: taille tableau=21000, temps=29.68224310874939s
# Trie par insertion: taille tableau=26000, temps=45.70301032066345s
# Trie par insertion: taille tableau=31000, temps=61.37903904914856s