diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..45cb9f5 --- /dev/null +++ b/Readme.md @@ -0,0 +1,155 @@ +**Exercice 1** + +1. **`function_1(tableau1, tableau2)`** : + Dans cette fonction, il y a deux boucles imbriquées : la première parcourt tous les éléments de `tableau1` (de taille \(n\)), et pour chaque élément, la deuxième boucle parcourt `tableau2` (de taille \(m\)). + Dans le pire des cas, si aucun élément ne correspond (ou si le `break` n'est jamais atteint), chaque élément de `tableau1` sera comparé à tous les éléments de `tableau2`. + Donc, la complexité de cette fonction est \( O(n \cdot m) \). + +2. **`function_2(x)`** : + Ici, on a une boucle `while` qui s’exécute \(x\) fois. À chaque itération, on effectue une addition et une décrémentation, qui prennent toutes les deux un temps constant. + Du coup, la complexité est proportionnelle à \(x\), donc \( O(x) \). + +3. **`function_3(x)`** : + Cette fonction contient uniquement des blocs `if` indépendants, qui s’exécutent chacun au maximum une seule fois. Il n’y a pas de boucle, donc chaque opération est constante. + La complexité est donc \( O(1) \), car c’est constant peu importe la valeur de \(x\). + + +**Exercice 2** + +Pour analyser la complexité de la fonction **`sort_students`**, on décompose chaque étape : + +1. **Boucle externe sur les grades** : + La boucle externe parcourt tous les grades des étudiants, soit \( \text{grades\_number} \) itérations. + +2. **Allocation dynamique des notes** : + L’allocation du tableau `grades` est faite avec `malloc`, qui est supposée avoir une complexité \( O(1) \). Cela n’affecte donc pas significativement la complexité globale. + +3. **Copie des notes des étudiants** : + Dans la boucle interne : + ```c + for(j = 0; j < students_number; j++) { + grades[j] = students_array[j][i]; + } + ``` + on copie les notes des \( \text{students\_number} \) étudiants, ce qui prend \( O(\text{students\_number}) \) par itération de la boucle externe. + +4. **Tri des notes avec `bubblesort`** : + La fonction `bubblesort` trie un tableau de taille \( \text{students\_number} \), avec une complexité \( O(\text{students\_number}^2) \). + +5. **Trouver le rang de chaque étudiant** : + Ensuite, dans cette boucle interne : + ```c + for(j = 0; j < students_number; j++) { + students_rank[j][i] = find_rank_student(students_array[j][i], grades, students_number); + } + ``` + on appelle `find_rank_student` pour chaque étudiant. Cette fonction effectue : + - Un tri par bulles \( O(\text{students\_number}^2) \), + - Une recherche pour trouver le rang, qui prend \( O(\text{students\_number}) \). + + Donc, chaque appel à `find_rank_student` a une complexité totale de \( O(\text{students\_number}^2) \), et cette fonction est appelée \( \text{students\_number} \) fois par itération de la boucle externe. Cela donne une complexité \( O(\text{students\_number}^3) \) par itération de la boucle externe. + +6. **Libération de mémoire** : + Enfin, la mémoire allouée pour `grades` est libérée avec `free`, ce qui est une opération \( O(1) \). + +### Complexité totale : +La boucle externe s’exécute \( \text{grades\_number} \) fois, et la partie la plus coûteuse de la boucle interne est \( O(\text{students\_number}^3) \). La complexité globale de la fonction est donc : +\[ +O(\text{grades\_number} \cdot \text{students\_number}^3) +\] + +### Conclusion : +La fonction **`sort_students`** a une complexité algorithmique de **\( O(\text{grades\_number} \cdot \text{students\_number}^3) \)**. + + +**Exercice 3** + +### **Algorithme proposé** + +Pour trier un tableau à \( N \)-dimensions avec \( M \) valeurs par dimension, voici l'algo. + +#### Étapes de l’algorithme : + +1. Si on est au niveau d’un tableau 1D (dimension la plus basse), on le trie directement. +2. Sinon : + - Trier chaque sous-dimension récursivement. + - Calculer la somme des valeurs de chaque sous-dimension. + - Trier les sous-dimensions en fonction de leurs sommes. + +--- + +### **Implémentation en Python** + +Voici l’algorithme en code : + +```python +def recursive_sort(T): + # Si c'est un tableau 1D, on le trie directement + if not isinstance(T[0], list): + return sorted(T) + + # Sinon, on trie chaque sous-dimension récursivement + for i in range(len(T)): + T[i] = recursive_sort(T[i]) + + # Puis on trie le tableau actuel selon la somme des sous-dimensions + T.sort(key=lambda x: sum(sum(val) if isinstance(val, list) else val for val in x)) + return T + +# Exemple avec un tableau 2D +tableau = [[0, 3, 2], [9, 4, 5], [4, 1, 3]] +resultat = recursive_sort(tableau) +print(resultat) # Résultat attendu : [[0, 2, 3], [1, 3, 4], [4, 5, 9]] +``` + +--- + +### **Exemple d’exécution** + +Pour le tableau donné : +\[ [ [0, 3, 2], [9, 4, 5], [4, 1, 3] ] \] + +1. **Trier chaque ligne individuellement** : + \[ + [ [0, 2, 3], [4, 5, 9], [1, 3, 4] ] + \] + +2. **Calculer la somme des valeurs pour chaque ligne** : + - Première ligne : \( 0 + 2 + 3 = 5 \) + - Deuxième ligne : \( 4 + 5 + 9 = 18 \) + - Troisième ligne : \( 1 + 3 + 4 = 8 \) + +3. **Trier les lignes en fonction de leurs sommes** : + \[ + [ [0, 2, 3], [1, 3, 4], [4, 5, 9] ] + \] + +--- + +### **Complexité de l’algorithme** + +#### Analyse : + +1. **Pour la dimension la plus basse (1D)** : + - Trier \( M \) éléments coûte \( O(M \log M) \). + +2. **Pour les dimensions supérieures (\( N > 1 \))** : + - Chaque dimension contient \( M^{N-1} \) sous-tableaux. + - Trier ces sous-tableaux coûte \( O(M^{N-1} \log M^{N-1}) \). + - Calculer les sommes pour ces sous-tableaux prend \( O(M^N) \). + +3. **Récursivité sur \( N \) dimensions** : + - La complexité totale est donnée par la somme : + \[ + T(N, M) = O(M^N \log M + M^{N-1} \log M^{N-1} + \dots + M \log M) + \] + - La partie dominante est celle de la dimension principale : + \[ + T(N, M) = O(M^N \log M) + \] + +--- + +### **Conclusion** + +- La complexité globale est **\( O(M^N \log M) \)**. \ No newline at end of file