diff --git a/README.md b/README.md index 74f925a..292a103 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ 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 ? Une droite en NlogN @@ -75,7 +75,7 @@ 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* +Écrivez en français classique ce que vous voyez. Quel est le fonctionnement ? Comment l'expliqueriez-vous à quelqu'un ? L'algo cherche le plus petit élément de la liste en la parcourant, il l'échange avec le premier, puis recommence, il prend à nouveau le plus petit (mais sans compter ceux triés évidement) et le déplace. Jusqu'à avoir trié la liste 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. @@ -86,17 +86,16 @@ Mesurez le temps d'éxécution pour un tableau de : - ... - 10000 entrées -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* +Tracez le graphique correspondant. voir main +Quelle semble être la complexité de notre fonction de tri ? Cela est-il logique par rapport au code que vous avez implémenté ? N² ### 2. Tri par insertion - + Observez attentivement l'animation de tri par insertion ci-dessous pour en comprendre le fonctionnement. -É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 ? L'algorithme parcourt la liste un élément après l'autre et place l'élément au bon endroit par rapport aux précédents 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. @@ -107,9 +106,9 @@ Mesurez le temps d'éxécution pour un tableau de : - ... - 10000 entrées -Tracez le graphique correspondant. +Tracez le graphique correspondant. voir main -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é ? N² ### 3. Tri par fusion @@ -154,7 +153,7 @@ 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 ? Il trie une liste efficassement via une séries d'étapes répétées à plusieurs échelles. Il y a 2 grandes étapes : 1/ couper la liste en 2 listes, puis chacune en 2 etc. jusqu'à laisser que des listes de 1 élément. 2/ Il rassemble chaque liste par paire en les les triant (trie que les premières valeurs entre elles mais comme on part de listes de 1 élément elles sont finalement toutes triées) Complétez la fonction `sort` du fichier `sort/fusion.py` en suivant les instructions suivantes. @@ -174,15 +173,15 @@ 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é ? 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* +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 ? pour de petits 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 ;) +Une dernière fois, analysez le temps d'exécution et découvrez si python fait mieux que nos implémentations rudimentaires :) ## Pour rendre ce TP diff --git a/__main__.py b/__main__.py index 98a585e..05dc533 100644 --- a/__main__.py +++ b/__main__.py @@ -1,5 +1,101 @@ +import time +import numpy as np +import matplotlib.pyplot as plt +from sort.fusion import sort as fusion_sort +from sort.insertion import sort as insertion_sort +from sort.selection import sort as selection_sort +from sort.range import generate_array + + +def measure_time(algo_func, array): + """Mesurer la durée d'exécution d'une fonction de tri""" + start_time = time.time() + algo_func(array) + end_time = time.time() + return end_time - start_time + + def main(): - print("Hello world") + """Fonction principale""" + max_tab_size = int(input("Enter the maximum size of the array: ")) + num_sizes = int(input("Enter the number of array sizes to generate: ")) + critical_time = float(input("Enter the critical time for stopping the \ + execution (in seconds): ")) + + # Choix de l'échelle avec par défaut la logarithmique + scale_choice = input("Choose scale (linear/log): ").lower() + if scale_choice not in ['linear', 'log']: + # Utilisation de l'échelle logarithmique par défaut + scale_choice = 'log' + + # Générer des tableaux intermédiaires de taille croissante + if scale_choice == 'log': + sizes = np.logspace(0, np.log10(max_tab_size), num=num_sizes, + endpoint=True, base=10, dtype=int) + else: + sizes = np.linspace(1, max_tab_size, num=num_sizes, dtype=int) + + selection_times = [] + insertion_times = [] + fusion_times = [] + + # Variables de contrôle pour arrêter la mesure du temps pour chaque algo + stop_selection = False + stop_insertion = False + stop_fusion = False + + for size in sizes: + tab = generate_array(size) + + # Mesurer la durée d'exécution du tri par SELECTION + if not stop_selection: + selection_time = measure_time(selection_sort, tab.copy()) + selection_times.append(selection_time) + if size < max_tab_size and selection_time > critical_time: + print(f"Selection Sort exceeded critical time ({critical_time}\ + seconds) for size {size}. Stopping.") + stop_selection = True + + # Mesurer la durée d'exécution du tri par insertion + if not stop_insertion: + insertion_time = measure_time(insertion_sort, tab.copy()) + insertion_times.append(insertion_time) + if size < max_tab_size and insertion_time > critical_time: + print(f"Insertion Sort exceeded critical time ({critical_time}\ + seconds) for size {size}. Stopping.") + stop_insertion = True + + # Mesurer la durée d'exécution du tri par FUSION + if not stop_fusion: + fusion_time = measure_time(fusion_sort, tab.copy()) + fusion_times.append(fusion_time) + if size < max_tab_size and fusion_time > critical_time: + print(f"Fusion Sort exceeded critical time ({critical_time}\ + seconds) for size {size}. Stopping.") + stop_fusion = True + + # Vérifier si tous les algorithmes ont atteint le seuil critique + if stop_selection and stop_insertion and stop_fusion: + break + + # Créer un graphique avec la légende à gauche + plt.plot(sizes[:len(selection_times)], selection_times, + label='Selection Sort', marker='o') + plt.plot(sizes[:len(insertion_times)], insertion_times, + label='Insertion Sort', marker='o') + plt.plot(sizes[:len(fusion_times)], fusion_times, label='Fusion Sort', + marker='o') + + if scale_choice == 'log': + # Utiliser échelle logarithmique pour l'axe des x + plt.xscale('log') + + # Paramètres du graph + plt.xlabel('Array Size') + plt.ylabel('Time (s)') + plt.title('Comparison of Sorting Algorithms') + plt.legend(loc='upper left') + plt.show() main() diff --git a/chart.png b/chart.png new file mode 100644 index 0000000..6e01775 Binary files /dev/null and b/chart.png differ diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..aaac661 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,15 @@ +[tool.poetry] +name = "pyproject-toml" +version = "1" +description = "1" +authors = ["1"] +readme = "README.md" +packages = [{include = "pyproject"}] + +[tool.poetry.dependencies] +python = "^3.12" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/sort/fusion.py b/sort/fusion.py index 73a21d3..b41716e 100644 --- a/sort/fusion.py +++ b/sort/fusion.py @@ -1,2 +1,35 @@ def sort(array: list[int]) -> list[int]: + """Tri par algorithme de fusion""" + if len(array) <= 1: + return array + + if len(array) <= 10: + # Utiliser un tri plus simple pour de petites listes + return sorted(array) + + mid = len(array) // 2 + left = sort(array[:mid]) + right = sort(array[mid:]) + return merge(left, right) + + +def merge(array1: list[int], array2: list[int]) -> list[int]: + """Donne 1 liste triée à partir de 2 listes triées""" + array: list[int] = [] + + # Indices pour les deux listes + i = j = 0 + + while i < len(array1) and j < len(array2): + if array1[i] < array2[j]: + array.append(array1[i]) + i += 1 + else: + array.append(array2[j]) + j += 1 + + # Ajouter les éléments restants de array1 et array2 + array.extend(array1[i:]) + array.extend(array2[j:]) + return array diff --git a/sort/insertion.py b/sort/insertion.py index 73a21d3..857513a 100644 --- a/sort/insertion.py +++ b/sort/insertion.py @@ -1,2 +1,16 @@ def sort(array: list[int]) -> list[int]: + """Tri par algorithme d'insertion""" + len_list = len(array) + for index in range(1, len_list): + value = array[index] + start = index - 1 + + # Trouver le bon emplacement en déplaçant les éléments plus grands + while start >= 0 and array[start] > value: + array[start + 1] = array[start] + start -= 1 + + # Insérer la valeur à la bonne position + array[start + 1] = value + return array diff --git a/sort/range.py b/sort/range.py index fc252ab..34096fa 100644 --- a/sort/range.py +++ b/sort/range.py @@ -1,2 +1,7 @@ -def generate_array_of_number(array_size: int) -> list[int]: - return [] +import random + + +def generate_array(array_size: int) -> list[int]: + """Génère un tableau de n entiers posififs aléatoires (avec n la + taille du tableau en para)""" + return [random.randint(0, 100) for i in range(array_size)] diff --git a/sort/recursion.py b/sort/recursion.py index e7f4320..8133e99 100644 --- a/sort/recursion.py +++ b/sort/recursion.py @@ -1,2 +1,3 @@ def get_factorial(number: int) -> int: - return number + """factoctorielle""" + return number if number <= 1 else number * get_factorial(number - 1) diff --git a/sort/selection.py b/sort/selection.py index 73a21d3..7807045 100644 --- a/sort/selection.py +++ b/sort/selection.py @@ -1,2 +1,19 @@ def sort(array: list[int]) -> list[int]: + """Tri par algorithme de sélection""" + len_list = len(array) + + for index in range(len_list - 1): + min_index = index + + for j in range(index + 1, len_list): + if array[j] < array[min_index]: + min_index = j + + # Echanger les valeurs si nécessaire + if min_index != index: + array[index], array[min_index] = array[min_index], array[index] + return array + + +print(sort([1, 2, 3, 4, 6, 9, 5, 7, 9, 1, 2, 0]))