forked from menault/2026_TD1_DEV51_Qualite_Algo
Remplacement du tri à bulles par un tri par tas pour améliorer les performances de tri
This commit is contained in:
@@ -0,0 +1 @@
|
||||
// Piste : réduire le temps d'exécution de `doit_echanger`
|
||||
+25
-8
@@ -319,16 +319,33 @@ int doit_echanger(const Entree *a, const Entree *b)
|
||||
return comparer(a->mot, b->mot) > 0;
|
||||
}
|
||||
|
||||
/* La racine du tas est l'entrée qui doit apparaître le plus tard. */
|
||||
void retablir_tas(Entree *table, int n, int racine)
|
||||
{
|
||||
while (racine < n / 2) {
|
||||
int enfant = 2 * racine + 1;
|
||||
if (enfant + 1 < n && doit_echanger(&table[enfant + 1], &table[enfant]))
|
||||
enfant++;
|
||||
if (!doit_echanger(&table[enfant], &table[racine]))
|
||||
break;
|
||||
|
||||
Entree tmp = table[racine];
|
||||
table[racine] = table[enfant];
|
||||
table[enfant] = tmp;
|
||||
racine = enfant;
|
||||
}
|
||||
}
|
||||
|
||||
void trier_entrees(Entree *table, int n)
|
||||
{
|
||||
for (int i = 0; i < n - 1; i++) {
|
||||
for (int j = 0; j < n - 1 - i; j++) {
|
||||
if (doit_echanger(&table[j], &table[j + 1])) {
|
||||
Entree tmp = table[j];
|
||||
table[j] = table[j + 1];
|
||||
table[j + 1] = tmp;
|
||||
}
|
||||
}
|
||||
/* Construire le tas, puis placer chaque racine à sa position finale. */
|
||||
for (int i = n / 2 - 1; i >= 0; i--)
|
||||
retablir_tas(table, n, i);
|
||||
for (int fin = n - 1; fin > 0; fin--) {
|
||||
Entree tmp = table[0];
|
||||
table[0] = table[fin];
|
||||
table[fin] = tmp;
|
||||
retablir_tas(table, fin, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -365,4 +365,54 @@ Empreinte du rapport : 1d53de903efd2b7c
|
||||
real 0m0.751s
|
||||
user 0m0.703s
|
||||
sys 0m0.004s
|
||||
```
|
||||
```
|
||||
|
||||
## Remplacement du tri à bulles par un tri par tas
|
||||
|
||||
Le tri à bulles effectuait systématiquement n(n - 1)/2 comparaisons,
|
||||
soit 17 202 045 appels à `doit_echanger` pour 5 866 mots distincts.
|
||||
|
||||
`trier_entrees` utilise maintenant un tri par tas. La racine du tas contient
|
||||
l'entrée qui doit apparaître le plus tard dans le classement. Elle est
|
||||
échangée avec la dernière entrée de la partie non triée, puis `retablir_tas`
|
||||
restaure cette propriété sur les entrées restantes. La construction du tas
|
||||
coûte O(n), puis les extractions coûtent O(log n) chacune : le tri complet
|
||||
passe de O(n²) à O(n log n), y compris dans le pire cas.
|
||||
|
||||
Le tri travaille directement dans le tableau, avec O(1) de mémoire
|
||||
supplémentaire. `doit_echanger` reste inchangée : fréquence décroissante,
|
||||
puis ordre alphabétique croissant. Chaque échange déplace l'entrée entière,
|
||||
y compris la longueur mémorisée.
|
||||
|
||||
Profil enregistré dans [out/profil_apres_tri.txt](out/profil_apres_tri.txt).
|
||||
La comparaison porte sur la version précédente, décrite dans
|
||||
`out/profil_apres_longueurs.txt`.
|
||||
|
||||
| Mesure | Tri à bulles | Tri par tas |
|
||||
| --- | ---: | ---: |
|
||||
| Appels à `doit_echanger` pendant le tri | 17 202 045 | 129 602 |
|
||||
| Appels à `comparer` pour départager les fréquences égales | 12 172 087 | 32 813 |
|
||||
| Temps réel médian du programme sans profiling (`gcc -O0`, 5 exécutions par version) | 0,367 s | 0,113 s |
|
||||
|
||||
Le tri effectue environ 133 fois moins de comparaisons d'entrées.
|
||||
Le temps total baisse de 69,3 %, soit une accélération d'environ 3,25.
|
||||
Les cinq mesures, réalisées en alternant les deux versions sur la même
|
||||
machine, sont respectivement : 0,365 / 0,363 / 0,372 / 0,383 / 0,367 s
|
||||
avant, et 0,112 / 0,113 / 0,115 / 0,113 / 0,112 s après.
|
||||
|
||||
Validation : compilation sans avertissement avec `-Wall -Wextra -Wpedantic`,
|
||||
rapport et sortie console identiques octet par octet sur les dix exécutions,
|
||||
avec `-pg` et sous AddressSanitizer et UndefinedBehaviorSanitizer.
|
||||
L'empreinte reste **`1d53de903efd2b7c`**.
|
||||
Des tests temporaires ont comparé le résultat à `qsort` sur des tableaux
|
||||
de 0 à 20 000 entrées, aléatoires, déjà triés ou inversés. Ils vérifient
|
||||
aussi les fréquences égales, les doublons, les préfixes, les valeurs
|
||||
extrêmes de fréquence et la conservation des longueurs des mots.
|
||||
|
||||
Commandes pour reproduire ce profil :
|
||||
|
||||
```bash
|
||||
mkdir -p out/apres_tri
|
||||
gcc -O0 -pg analyseur.c -o out/apres_tri/analyseur
|
||||
(cd out/apres_tri && ./analyseur && gprof -b ./analyseur gmon.out > ../profil_apres_tri.txt)
|
||||
```
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,160 @@
|
||||
Flat profile:
|
||||
|
||||
Each sample counts as 0.01 seconds.
|
||||
% cumulative self self total
|
||||
time seconds seconds calls ms/call ms/call name
|
||||
45.45 0.05 0.05 12198772 0.00 0.00 egales
|
||||
18.18 0.07 0.02 1 20.00 27.09 analyser_bigrammes
|
||||
9.09 0.08 0.01 5297256 0.00 0.00 est_lettre
|
||||
9.09 0.09 0.01 1266663 0.00 0.00 en_minuscule
|
||||
9.09 0.10 0.01 250000 0.00 0.00 est_mot_vide
|
||||
9.09 0.11 0.01 1 10.00 10.00 decouper_lignes
|
||||
0.00 0.11 0.00 928117 0.00 0.00 alea
|
||||
0.00 0.11 0.00 150182 0.00 0.00 chercher_mot
|
||||
0.00 0.11 0.00 150182 0.00 0.00 compter_mot
|
||||
0.00 0.11 0.00 150182 0.00 0.00 hacher_mot
|
||||
0.00 0.11 0.00 129602 0.00 0.00 doit_echanger
|
||||
0.00 0.11 0.00 32813 0.00 0.00 comparer
|
||||
0.00 0.11 0.00 26801 0.00 0.00 ajouter
|
||||
0.00 0.11 0.00 21746 0.00 0.00 compter_mots_ligne
|
||||
0.00 0.11 0.00 21746 0.00 0.00 normaliser_ligne
|
||||
0.00 0.11 0.00 8798 0.00 0.00 retablir_tas
|
||||
0.00 0.11 0.00 5866 0.00 0.00 copier
|
||||
0.00 0.11 0.00 1 0.00 0.00 construire_rapport
|
||||
0.00 0.11 0.00 1 0.00 0.00 ecart_type_longueur
|
||||
0.00 0.11 0.00 1 0.00 0.00 empreinte
|
||||
0.00 0.11 0.00 1 0.00 0.00 generer_texte
|
||||
0.00 0.11 0.00 1 0.00 0.00 generer_vocabulaire
|
||||
0.00 0.11 0.00 1 0.00 0.00 longueur_moyenne
|
||||
0.00 0.11 0.00 1 0.00 0.00 racine
|
||||
0.00 0.11 0.00 1 0.00 0.00 trier_entrees
|
||||
|
||||
Call graph
|
||||
|
||||
|
||||
granularity: each sample hit covers 4 byte(s) for 9.09% of 0.11 seconds
|
||||
|
||||
index % time self children called name
|
||||
<spontaneous>
|
||||
[1] 100.0 0.00 0.11 main [1]
|
||||
0.00 0.06 21746/21746 compter_mots_ligne [2]
|
||||
0.02 0.01 1/1 analyser_bigrammes [5]
|
||||
0.00 0.01 21746/21746 normaliser_ligne [6]
|
||||
0.01 0.00 1/1 decouper_lignes [9]
|
||||
0.00 0.00 1/1 generer_vocabulaire [23]
|
||||
0.00 0.00 1/1 generer_texte [22]
|
||||
0.00 0.00 1/1 trier_entrees [26]
|
||||
0.00 0.00 1/1 longueur_moyenne [24]
|
||||
0.00 0.00 1/1 ecart_type_longueur [20]
|
||||
0.00 0.00 1/1 racine [25]
|
||||
0.00 0.00 1/1 construire_rapport [19]
|
||||
0.00 0.00 1/1 empreinte [21]
|
||||
-----------------------------------------------
|
||||
0.00 0.06 21746/21746 main [1]
|
||||
[2] 54.5 0.00 0.06 21746 compter_mots_ligne [2]
|
||||
0.01 0.05 250000/250000 est_mot_vide [3]
|
||||
0.00 0.00 150182/150182 compter_mot [11]
|
||||
-----------------------------------------------
|
||||
0.01 0.05 250000/250000 compter_mots_ligne [2]
|
||||
[3] 54.0 0.01 0.05 250000 est_mot_vide [3]
|
||||
0.05 0.00 12045671/12198772 egales [4]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 153101/12198772 chercher_mot [10]
|
||||
0.05 0.00 12045671/12198772 est_mot_vide [3]
|
||||
[4] 45.5 0.05 0.00 12198772 egales [4]
|
||||
-----------------------------------------------
|
||||
0.02 0.01 1/1 main [1]
|
||||
[5] 24.6 0.02 0.01 1 analyser_bigrammes [5]
|
||||
0.01 0.00 3757672/5297256 est_lettre [7]
|
||||
-----------------------------------------------
|
||||
0.00 0.01 21746/21746 main [1]
|
||||
[6] 11.7 0.00 0.01 21746 normaliser_ligne [6]
|
||||
0.01 0.00 1266663/1266663 en_minuscule [8]
|
||||
0.00 0.00 1539584/5297256 est_lettre [7]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 1539584/5297256 normaliser_ligne [6]
|
||||
0.01 0.00 3757672/5297256 analyser_bigrammes [5]
|
||||
[7] 9.1 0.01 0.00 5297256 est_lettre [7]
|
||||
-----------------------------------------------
|
||||
0.01 0.00 1266663/1266663 normaliser_ligne [6]
|
||||
[8] 9.1 0.01 0.00 1266663 en_minuscule [8]
|
||||
-----------------------------------------------
|
||||
0.01 0.00 1/1 main [1]
|
||||
[9] 9.1 0.01 0.00 1 decouper_lignes [9]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 150182/150182 compter_mot [11]
|
||||
[10] 0.6 0.00 0.00 150182 chercher_mot [10]
|
||||
0.00 0.00 153101/12198772 egales [4]
|
||||
0.00 0.00 150182/150182 hacher_mot [13]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 150182/150182 compter_mots_ligne [2]
|
||||
[11] 0.6 0.00 0.00 150182 compter_mot [11]
|
||||
0.00 0.00 150182/150182 chercher_mot [10]
|
||||
0.00 0.00 5866/5866 copier [18]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 27934/928117 generer_vocabulaire [23]
|
||||
0.00 0.00 900183/928117 generer_texte [22]
|
||||
[12] 0.0 0.00 0.00 928117 alea [12]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 150182/150182 chercher_mot [10]
|
||||
[13] 0.0 0.00 0.00 150182 hacher_mot [13]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 129602/129602 retablir_tas [17]
|
||||
[14] 0.0 0.00 0.00 129602 doit_echanger [14]
|
||||
0.00 0.00 32813/32813 comparer [15]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 32813/32813 doit_echanger [14]
|
||||
[15] 0.0 0.00 0.00 32813 comparer [15]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 5867/26801 construire_rapport [19]
|
||||
0.00 0.00 20934/26801 generer_vocabulaire [23]
|
||||
[16] 0.0 0.00 0.00 26801 ajouter [16]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 8798/8798 trier_entrees [26]
|
||||
[17] 0.0 0.00 0.00 8798 retablir_tas [17]
|
||||
0.00 0.00 129602/129602 doit_echanger [14]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 5866/5866 compter_mot [11]
|
||||
[18] 0.0 0.00 0.00 5866 copier [18]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 1/1 main [1]
|
||||
[19] 0.0 0.00 0.00 1 construire_rapport [19]
|
||||
0.00 0.00 5867/26801 ajouter [16]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 1/1 main [1]
|
||||
[20] 0.0 0.00 0.00 1 ecart_type_longueur [20]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 1/1 main [1]
|
||||
[21] 0.0 0.00 0.00 1 empreinte [21]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 1/1 main [1]
|
||||
[22] 0.0 0.00 0.00 1 generer_texte [22]
|
||||
0.00 0.00 900183/928117 alea [12]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 1/1 main [1]
|
||||
[23] 0.0 0.00 0.00 1 generer_vocabulaire [23]
|
||||
0.00 0.00 27934/928117 alea [12]
|
||||
0.00 0.00 20934/26801 ajouter [16]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 1/1 main [1]
|
||||
[24] 0.0 0.00 0.00 1 longueur_moyenne [24]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 1/1 main [1]
|
||||
[25] 0.0 0.00 0.00 1 racine [25]
|
||||
-----------------------------------------------
|
||||
0.00 0.00 1/1 main [1]
|
||||
[26] 0.0 0.00 0.00 1 trier_entrees [26]
|
||||
0.00 0.00 8798/8798 retablir_tas [17]
|
||||
-----------------------------------------------
|
||||
|
||||
Index by function name
|
||||
|
||||
[16] ajouter [9] decouper_lignes [23] generer_vocabulaire
|
||||
[12] alea [14] doit_echanger [13] hacher_mot
|
||||
[5] analyser_bigrammes [20] ecart_type_longueur [24] longueur_moyenne
|
||||
[10] chercher_mot [4] egales [6] normaliser_ligne
|
||||
[15] comparer [21] empreinte [25] racine
|
||||
[11] compter_mot [8] en_minuscule [17] retablir_tas
|
||||
[2] compter_mots_ligne [7] est_lettre [26] trier_entrees
|
||||
[19] construire_rapport [3] est_mot_vide
|
||||
[18] copier [22] generer_texte
|
||||
Reference in New Issue
Block a user