Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 70

Optimisation d'algorithmes : techniques de tri

Recommended resources

Bonjour ! J'espère que vous êtes prêt(e) à optimiser.

Dans la leçon précédente, nous avons appris à formuler une première solution à un problème en utilisant l'approche par force brute. Nous avons constaté que cette méthode, bien que simple à concevoir, mène souvent à des algorithmes inefficaces, avec des complexités en ou pires, qui deviennent très lents lorsque la taille des données augmente.

Aujourd'hui, nous allons répondre à la question qui découle logiquement de ce constat : "Comment peut-on faire mieux ?". Cette leçon est consacrée à une technique d'optimisation fondamentale : le tri préalable des données. Vous découvrirez comment un investissement initial dans l'organisation de vos données peut débloquer des approches beaucoup plus rapides et élégantes, un pas de plus vers votre objectif de "code clean".

À l'issue de cette leçon, vous saurez appliquer le tri comme une technique pour transformer un algorithme inefficace en une solution bien plus performante.

1. Le principe de l'optimisation : un coût pour un gain

L'optimisation en algorithmique est souvent une histoire de compromis. L'idée est d'effectuer une opération de "pré-traitement" sur les données. Cette opération a un coût, mais elle permet ensuite d'exécuter l'algorithme principal de manière beaucoup plus efficace.

La stratégie est gagnante si :

Coût du pré-traitement + Coût du nouvel algorithme < Coût de l'algorithme par force brute

La technique de pré-traitement la plus courante et la plus puissante est le tri. Trier une liste de données nous permet d'exploiter l'ordre des éléments pour éviter des opérations inutiles.

Le document ci-dessous illustre parfaitement ce principe.

[PDF] Quelques algorithmes classiques - librecours.net

Le document 'Quelques algorithmes classiques' de librecours.net explique très directement comment le tri préalable des données peut améliorer la complexité d'un problème. Il commence par un exemple très simple.

Lisez le début du document, jusqu'à la section 'Recherche naïve des indices d'une valeur'. Concentrez-vous sur le paragraphe 'Mise en situation' et l'exemple 'Recherche du maximum'. Notez comment le fait de savoir qu'une liste est triée change radicalement la complexité de la recherche du maximum.

Comme vous l'avez lu, si une liste est déjà triée, trouver le maximum devient une opération instantanée (complexité ) au lieu de devoir parcourir toute la liste (complexité ).

Cependant, la liste n'est généralement pas triée au départ. Le véritable gain apparaît lorsque le coût du tri est largement compensé par l'efficacité du nouvel algorithme qu'il autorise. Voyons cela avec l'exemple le plus classique : la recherche d'un élément.


2. Cas d'étude : Recherche d'un élément

Imaginons que nous devons chercher un élément dans un tableau.

  • Approche par force brute : la recherche séquentielle
    Comme son nom l'indique, on parcourt le tableau élément par élément jusqu'à trouver celui qu'on cherche ou arriver à la fin. Dans le pire des cas, il faut vérifier tous les éléments. La complexité est donc linéaire, .

  • Approche optimisée : le tri suivi de la recherche dichotomique
    Cette approche se fait en deux temps :

    1. Pré-traitement : On trie le tableau.
    2. Algorithme optimisé : On utilise la recherche dichotomique (binaire), qui exploite l'ordre pour éliminer la moitié des éléments restants à chaque étape.

Pour comprendre la différence fondamentale entre ces deux méthodes de recherche, l'article suivant est très éclairant.

Les algorithmes de recherche et de tri - Invivoo

L'article 'Les algorithmes de recherche et de tri' d'Invivoo détaille et compare la recherche séquentielle et la recherche dichotomique. C'est essentiel pour comprendre l'avantage procuré par le tri.

Lisez d'abord la section 'Recherche séquentielle' (concentrez-vous sur le cas d'une liste non triée). Ensuite, lisez la section 'Recherche dichotomique', en portant une attention particulière à son principe et à sa complexité finale, bien meilleure.

Analyse de la performance

Analysons le coût de l'approche optimisée :

  1. Coût du tri : Un algorithme de tri efficace, comme le tri fusion ou le tri rapide, a une complexité moyenne de .
  2. Coût de la recherche dichotomique : Comme vous l'avez lu, sa complexité est .

Le coût total est donc , ce qui se simplifie en .

Si vous ne faites qu'une seule recherche, passer de à n'est pas forcément un gain. Mais le tri devient extrêmement rentable si :

  • Vous devez effectuer de nombreuses recherches dans le même tableau.
  • L'algorithme que vous cherchez à optimiser est bien plus coûteux, comme un algorithme en .

3. Application : Optimiser le problème de la somme de deux nombres

Rappelez-vous du problème de la leçon précédente :

Étant donné un tableau T de n nombres et un nombre cible S, existe-t-il deux nombres dans le tableau dont la somme est égale à S ?

La solution par force brute consistait à tester toutes les paires possibles avec deux boucles imbriquées, pour une complexité de .

Appliquons notre technique d'optimisation :

  1. Pré-traitement : On trie le tableau T. Coût : .

  2. Algorithme optimisé : la technique des deux pointeurs.
    Une fois le tableau trié, on peut utiliser une méthode très astucieuse. On place un pointeur gauche au tout début du tableau et un pointeur droite à la toute fin.

    Algorithme TrouverSommeOptimise(T, S)
      Trier(T)  // Étape 1 : Coût O(n log n)
    
      gauche <- 0
      droite <- longueur(T) - 1
    
      Tant que gauche < droite
        somme_actuelle <- T[gauche] + T[droite]
    
        Si somme_actuelle = S
          Retourner Vrai  // On a trouvé !
    
        Sinon Si somme_actuelle < S
          // La somme est trop petite, il faut l'augmenter.
          // On déplace le pointeur gauche vers un plus grand nombre.
          gauche <- gauche + 1
    
        Sinon // somme_actuelle > S
          // La somme est trop grande, il faut la diminuer.
          // On déplace le pointeur droite vers un plus petit nombre.
          droite <- droite - 1
    
      Retourner Faux // On a parcouru tout le tableau sans trouver de solution
    

Analyse de la performance

  • Coût du tri : .
  • Coût de la boucle Tant que : Dans le pire des cas, les pointeurs gauche et droite se croisent après avoir parcouru l'ensemble du tableau une seule fois. Cette partie de l'algorithme a donc une complexité linéaire, .

Le coût total est , ce qui se simplifie en .

Conclusion : Nous avons transformé un algorithme quadratique en un algorithme quasi-linéaire . Pour un tableau d'un million d'éléments, cela représente la différence entre des milliers de milliards d'opérations et seulement quelques millions. Le gain est spectaculaire !


4. Le coût du tri

Nous avons vu que le tri est la clé, mais il n'est pas gratuit. Il est important de savoir qu'il existe de nombreux algorithmes de tri, avec des performances très différentes.

L'image ci-dessous compare visuellement deux approches pour trier : le tri à bulles (simple mais lent) et le tri rapide (plus complexe mais efficace).

Comparison of Bubble Sort vs. Quick Sort
Cette image illustre le fonctionnement de deux algorithmes de tri. À gauche, le tri à bulles, qui compare et échange les éléments adjacents. C'est un exemple de tri simple mais lent, souvent en O(n²). À droite, le tri rapide, qui utilise une stratégie "diviser pour régner" bien plus efficace, souvent en O(n log n). Cela montre que le choix de l'algorithme de tri pour le pré-traitement a lui-même un impact sur l'efficacité globale.

Le choix de l'algorithme de tri est donc important. Heureusement, comme le souligne la ressource suivante, il est rare d'avoir à les implémenter soi-même.

[PDF] Quelques algorithmes classiques - librecours.net

Pour finir, revenons au document 'Quelques algorithmes classiques'. Il présente un exemple d'algorithme de tri simple, le tri à bulles, et donne un conseil très important pour la pratique.

Lisez la section 'Trier des listes (tri à bulles)'. Notez la complexité du tri à bulles (O(n²)) et retenez surtout l'avertissement dans l'encadré rouge 'Ne jamais implémenter un tri soi-même'.


Conclusion

Aujourd'hui, vous avez découvert l'une des stratégies d'optimisation les plus fondamentales en algorithmique. Une solution par force brute est un bon début, mais une analyse plus poussée révèle souvent des opportunités d'amélioration spectaculaires.

Points clés à retenir :

  • L'optimisation consiste souvent à investir dans un pré-traitement (comme le tri) pour rendre l'algorithme principal beaucoup plus rapide.
  • Le tri préalable des données est une technique extrêmement puissante. Il permet de passer de recherches séquentielles () à des recherches dichotomiques ().
  • Cette technique peut transformer des algorithmes lents, comme une recherche de paires en , en solutions très efficaces en grâce à des méthodes comme celle des deux pointeurs.
  • Le coût du tri ( pour un bon algorithme) est le facteur qui détermine la complexité finale de la solution optimisée.

Dans notre prochaine leçon, nous conclurons ce module en analysant le gain de complexité que nous obtenons après avoir optimisé un algorithme, afin de quantifier précisément l'amélioration de performance réalisée.