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
53 changes: 45 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,10 @@ 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 ?
Selon moi le tri par selection va regarder toute la liste,
il va selectionner l'element le plus petit et le placer au début de la liste.
Ensuite, il recommence avec le reste de la liste tant qu'elle n'est pas vide.

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 +91,23 @@ 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 tri par selection est de complexité O(N**2)
Car entre la première et la dernière valeur les entrées sont multiplé par 10
alors que les temps sont multipliés par 100.
De plus on a directement une double boucle dans le programme
qui regarde tout les éléments, ce qui fait N*N donc N**2

### 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 ?
Selon moi, Le tri par insertion va regarder le deuxieme element de la liste
et le placer avant ou après le premier si il est plus petit ou non. Puis faire
pareil avec les autres éléments en les comparant avec tous ceux avant

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 +120,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*
Quelle semble être la complexité de notre fonction de tri ? Cela est-il logique par rapport au code que vous avez implémenté ?
Le tri par insertion est de complexité O(N**2)
Car entre la première et la dernière valeur les entrées sont multiplé par 10
alors que les temps sont multipliés par 100.
De plus on a directement une double boucle dans le programme
qui regarde tout les éléments, ce qui fait N*N donc N**2

### 3. Tri par fusion

Expand Down Expand Up @@ -154,7 +170,14 @@ 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 ?
Le tri fusion prend un tableau.
Si le tableau n'est pas vide ou n'est pas composé d'un seul élément,
Python vas le divisé en deux en rappelant la meme fonction puis le merger.
A chaque fois avant de merger les différents tableaux vont se réduire,
jusqu'à ce que chaque tableau n'ait qu'un élément.
Ensuite les tableaux vont se merger petit à petit en restant croissant et
en formant au final un seul tableau

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

Expand All @@ -174,16 +197,30 @@ 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*

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*
Quelle semble être la complexité de notre fonction de tri ? Cela est-il logique par rapport au code que vous avez implémenté ?
Le tri fusion a l'air d'etre de complexité N*log(N)
car on subdivise le tri en plusieurs tri de 1 élément.
Puis on les recombine ensemble en les lisant.
Le nombre d'étape ou on lit chaque valeur est
a chaque fois que l'on merge des élements (2**(k))>=n>(2**(k-1))+1.
Il a donc k étapes ou on lit tout n. k est plus petit que N
car on prend le k supérieur ou égal à 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 ?
Si on considère que le tri par fusion a une complexité inférieur aux autres tri
alors plus le nombre de valeur va augmenté
plus l'écart entre les différentes complexités va augmenté également.
Le tri sera toujours plus rapide qu'un tri avec une complexité supérieur

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

Le tri sort de python est environ 100 fois plus rapide que notre tri fusion.
Sa complexité semble etre N

## Pour rendre ce TP

Merci de faire une Pull Request vers ce repository.
Expand Down
136 changes: 133 additions & 3 deletions __main__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,135 @@
def main():
print("Hello world")
import time
from enum import Enum, unique, auto
from sort.range import generate_array_of_number
from sort.selection import sort as selection_sort
from sort.insertion import sort as insertion_sort
from sort.recursion import get_factorial
from sort.fusion import sort as fusion_sort


main()
@unique
class Function(Enum):
GENERATE_ARRAY = auto()
SELECTION_SORT = auto()
INSERTION_SORT = auto()
FACTORIAL = auto()
FUSION_SORT = auto()
PYTHON_SORT = auto()


# We create a loop where there are all the element we need for test our sort
LOOP_REQUIRED = list[int](((element % 10)+1) * 10 if element < 10
else
((element % 10)+1) * 1_000 if 10 <= element < 20
else
((element % 10)+1) * 10_000 if 20 <= element < 30
else
((element % 10)+1) * 1_000_000
for element in range(0, 40))

TEN_PART: int = 0
THOUSAND_PART: int = 10
TEN_THOUSAND_PART: int = 20
MILLION_PART: int = 30


def main(use_tri: Function):
"""main function call two other fonction
and take on parameter the sort we want use"""
write_result(do_function(use_tri), use_tri)


def do_function(use_tri: Function) -> list[float]:
"""do_function make ten time the right sort
and return a tab of time different for the number of element"""
timer_tab: list[float] = []
for element in range(len(LOOP_REQUIRED)//4):
tab_generate = generate_array_of_number(
generate_index_tab_with_sort(use_tri, element))

start: float = time.time()
# Generate a tab from 1_000_000 to 10_000_000
if (use_tri == Function.GENERATE_ARRAY):
generate_array_of_number(LOOP_REQUIRED[element + MILLION_PART])

# Use factorial on number from 10 to 100
if (use_tri == Function.FACTORIAL):
get_factorial(LOOP_REQUIRED[element//3] // 100)

# Use selection sort on tab from 1_000 to 10_000
if (use_tri == Function.SELECTION_SORT):
selection_sort(tab_generate)

# Use insertion sort on tab from 1_000 to 10_000
if (use_tri == Function.INSERTION_SORT):
insertion_sort(tab_generate)

# Use fusion sort on tab from 10_000 to 100_000
if (use_tri == Function.FUSION_SORT):
fusion_sort(tab_generate)

# Use python sort on tab from 1_000_000 to 10_000_000
if (use_tri == Function.PYTHON_SORT):
tab_generate.sort()

end: float = time.time()
timer_tab.append(end-start)

return timer_tab


def generate_index_tab_with_sort(use_tri: Function, element: int) -> int:
"""Generate a tab with different length for different sort"""

# Generate a tab from 10 to 100
if (use_tri == Function.FACTORIAL):
return LOOP_REQUIRED[element + TEN_PART]

# Generate a tab from 10_000 to 100_000
elif (use_tri == Function.FUSION_SORT):
return LOOP_REQUIRED[element + TEN_THOUSAND_PART]

# Generate a tab from 1_000_000 to 10_000_000
elif (use_tri == Function.PYTHON_SORT):
return LOOP_REQUIRED[element + MILLION_PART]

# Generate a tab from 1_000 to 10_000
else:
return LOOP_REQUIRED[element + THOUSAND_PART]


def write_result(timer_tab: list[float], use_tri: Function) -> None:
"""write_result take tab of time and the sort for write them to user"""

for element in range(len(timer_tab)):
tab_generate = generate_index_tab_with_sort(use_tri, element)
# print time for function use
print("Le résultat pour " + str(tab_generate) +
" entrées est " + str(timer_tab[element]))


# A décommenter
# main(Function.GENERATE_ARRAY)
# main(Function.SELECTION_SORT)
# main(Function.INSERTION_SORT)
# main(Function.FACTORIAL)
# main(Function.FUSION_SORT)
# main(Function.PYTHON_SORT)


"""
Le tri sort de python est environ 100 fois plus rapide que notre tri fusion.
Sa complexité semble etre N

Résultat du python sort :
Le résultat pour 1000000 entrées est 0.10117459297180176
Le résultat pour 2000000 entrées est 0.24679017066955566
Le résultat pour 3000000 entrées est 0.31505799293518066
Le résultat pour 4000000 entrées est 0.42998576164245605
Le résultat pour 5000000 entrées est 0.537330150604248
Le résultat pour 6000000 entrées est 0.6411576271057129
Le résultat pour 7000000 entrées est 0.7325379848480225
Le résultat pour 8000000 entrées est 0.9010059833526611
Le résultat pour 9000000 entrées est 0.9867992401123047
Le résultat pour 10000000 entrées est 1.0364351272583008
"""
Binary file added graphique courbes.xlsx
Binary file not shown.
73 changes: 72 additions & 1 deletion sort/fusion.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,73 @@
"""
Le tri fusion prend un tableau.
Si le tableau n'est pas vide ou n'est pas composé d'un seul élément,
Python vas le divisé en deux en rappelant la meme fonction puis le merger.
A chaque fois avant de merger les différents tableaux vont se réduire,
jusqu'à ce que chaque tableau n'ait qu'un élément.
Ensuite les tableaux vont se merger petit à petit en restant croissant et
en formant au final un seul tableau
"""


def sort(array: list[int]) -> list[int]:
return array
"""if length of array <=1 return array,
else return the merge of the left part and the right part of the array"""
if len(array) <= 1:
return array
return merge(sort(array[:len(array) // 2]), sort(array[len(array) // 2:]))


def merge(array_left: list[int], array_right: list[int]) -> list[int]:
"""We can erge two array together by forming a new array"""
"""merge take two array and create one new array we both of them,
at every loop it takes the smallest number between two arrays
and remove from the array. Then we return new array created"""
new_array: list[int] = []

# We loop until the new array have all left and right values
while (True):

# if left or right list is empty then we can had the other
# at our new array and return it because it is sorted
if (array_left == []):
return new_array + array_right
elif (array_right == []):
return new_array + array_left

# if we suppose that the right and the left list is sorted then for
# have a new sort we just need to compare the first element of each
# list. We don't forget to add it at the new array and remove it
# because we add this value
if array_right[0] < array_left[0]:
new_array.append(array_right.pop(0))
else:
new_array.append(array_left.pop(0))


"""
Résultat :
Le résultat pour 10000 entrées est 0.14179372787475586
Le résultat pour 20000 entrées est 0.11987948417663574
Le résultat pour 30000 entrées est 0.18050265312194824
Le résultat pour 40000 entrées est 0.32453370094299316
Le résultat pour 50000 entrées est 0.38787841796875
Le résultat pour 60000 entrées est 0.49108314514160156
Le résultat pour 70000 entrées est 0.6442813873291016
Le résultat pour 80000 entrées est 0.9117996692657471
Le résultat pour 90000 entrées est 0.9976096153259277
Le résultat pour 100000 entrées est 1.2517235279083252

Le tri fusion a l'air d'etre de complexité N*log(N)
car on subdivise le tri en plusieurs tri de 1 élément.
Puis on les recombine ensemble en les lisant.
Le nombre d'étape ou on lit chaque valeur est
a chaque fois que l'on merge des élements (2**k)>=n>(2**(k-1))+1.
Il a donc k étapes ou on lit tout n. k est plus petit que N
car on prend le k supérieur ou égal à N

Si on considère que le tri par fusion a une complexité inférieur aux autres tri
alors plus le nombre de valeur va augmenté
plus l'écart entre les différentes complexités va augmenté également.
Le tri sera toujours plus rapide qu'un tri avec une complexité supérieur

"""
50 changes: 50 additions & 0 deletions sort/insertion.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,52 @@
"""
Selon moi, Le tri par insertion va regarder chaque élément de la liste,
les uns après les autres. A chaque fois, l'élément sera inséré
entre deux autres éléments dans la liste déja trié,
à la fin ou au début de la liste. On décalera tous les éléments triés
après la nouvelle position, de cette nouvelle position
vers l'ancienne position de l'élément
"""


def sort(array: list[int]) -> list[int]:
"""we sort a list of int by insert each number at their position"""

# The first loop represent element who search to sort
# and who will be insert between other number
for increment in range(len(array)):

# The secund loop go from the element who want to sort
# to the begin of the list
for number in range(increment, -1, -1):

# if the element size is between two element or
# if we reach the top of the list we insert it on list
if (array[increment] < array[number]
and (array[increment] >= array[number-1]
or number == 0)):

# We remove the element at increment
# position and we insert it at number position
array.insert(number, array.pop(increment))
return array


"""
Résultat :
Le résultat pour 1000 entrées est 0.028821706771850586
Le résultat pour 2000 entrées est 0.16448330879211426
Le résultat pour 3000 entrées est 0.3654301166534424
Le résultat pour 4000 entrées est 0.691014289855957
Le résultat pour 5000 entrées est 1.0119526386260986
Le résultat pour 6000 entrées est 1.4506659507751465
Le résultat pour 7000 entrées est 2.0582830905914307
Le résultat pour 8000 entrées est 2.850092887878418
Le résultat pour 9000 entrées est 3.4401211738586426
Le résultat pour 10000 entrées est 4.12743878364563

Le tri par insertion est de complexité O(N**2)
Car entre la première et la dernière valeur les entrées sont multiplé par 10
alors que les temps sont multipliés par 100.
De plus on a directement une double boucle dans le programme
qui regarde tout les éléments, ce qui fait N*N donc N**2
"""
21 changes: 20 additions & 1 deletion sort/range.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,21 @@
import random


def generate_array_of_number(array_size: int) -> list[int]:
return []
""" return an array generate number randomly between 1 and 100"""
return [random.randint(0, 100) for i in range(array_size)]


"""
Résultat :
Le résultat pour 1000000 entrées est 0.4899604320526123
Le résultat pour 2000000 entrées est 0.9306461811065674
Le résultat pour 3000000 entrées est 1.527371883392334
Le résultat pour 4000000 entrées est 1.882685899734497
Le résultat pour 5000000 entrées est 2.3193047046661377
Le résultat pour 6000000 entrées est 3.0640199184417725
Le résultat pour 7000000 entrées est 3.450831651687622
Le résultat pour 8000000 entrées est 3.9937903881073
Le résultat pour 9000000 entrées est 4.156933307647705
Le résultat pour 10000000 entrées est 4.718446493148804
"""
Loading