Skip to main content

Welcome to a Grasp lesson

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

Lesson 29

Complexité Amortie des Tableaux Dynamiques

Recommended resources

Bonjour,

Dans notre leçon précédente, nous avons implémenté une table de hachage fonctionnelle. Nous avons conclu sur une de ses limitations : sa capacité fixe. Si le nombre d'éléments augmente, les listes chaînées s'allongent et les performances se dégradent jusqu'à devenir celles d'une simple liste chaînée, en . La solution évidente est de redimensionner la table lorsque le "facteur de charge" devient trop élevé.

Cependant, cette opération de redimensionnement (créer un nouveau tableau plus grand et recopier tous les anciens éléments) est coûteuse. Si un tableau contient éléments, le redimensionnement coûte . Une analyse naïve de la complexité dans le pire des cas conclurait donc que l'opération d'insertion a une complexité de . Or, cette conclusion est trop pessimiste, car ces opérations coûteuses sont rares.

Aujourd'hui, nous introduisons un outil d'analyse fondamental pour évaluer rigoureusement l'efficacité de telles structures de données : la complexité amortie. L'objectif est de définir ce concept et de l'appliquer à une structure de données canonique, le tableau dynamique, pour prouver que, malgré des redimensionnements coûteux, le coût amorti d'une insertion est en réalité constant, soit .

1. Le Tableau Dynamique et le Problème du Coût

Un tableau dynamique (connu sous le nom de list en Python, ArrayList en Java, ou std::vector en C++) est une structure de données qui se comporte comme un tableau mais qui peut grandir dynamiquement.

La stratégie d'insertion est la suivante :

  • On maintient un tableau interne d'une certaine capacité et on suit le nombre d'éléments réellement stockés.
  • Si le tableau n'est pas plein, on ajoute le nouvel élément à la fin. C'est une opération rapide, en .
  • Si le tableau est plein, on déclenche un redimensionnement avant d'insérer :
    1. On alloue un nouveau tableau, typiquement de taille double.
    2. On copie tous les éléments de l'ancien tableau vers le nouveau. Cette étape est coûteuse : où est le nombre d'éléments.
    3. On ajoute le nouvel élément.
Illustration du redimensionnement d'un tableau dynamique
Cette image illustre comment un tableau dynamique gère les insertions successives. Lorsqu'il est plein, sa capacité est doublée, et tous les éléments existants sont recopiés, ce qui entraîne un coût ponctuel élevé.

Cette alternance entre opérations très rapides et une opération ponctuellement très lente est le scénario idéal pour l'analyse amortie.


2. Qu'est-ce que la Complexité Amortie ?

L'analyse amortie consiste à déterminer le coût moyen d'une opération sur une séquence d'opérations, dans le pire des cas. Elle permet de lisser les pics de coûts.

Attention à ne pas la confondre avec l'analyse en cas moyen, qui repose sur des hypothèses probabilistes sur la distribution des données en entrée. L'analyse amortie, elle, ne fait aucune hypothèse probabiliste et garantit la performance sur n'importe quelle séquence d'opérations.

Pour la calculer, nous disposons de trois méthodes principales :

  1. La méthode de l'agrégat
  2. La méthode comptable
  3. La méthode du potentiel

Nous allons explorer ces trois méthodes en les appliquant à notre problème de tableau dynamique. Je vous propose de commencer par une ressource en français, rédigée pour la préparation à l'Agrégation, qui expose brillamment l'analyse sur cet exemple.

L’exemple d’une table dynamique (dans Leçon 926 : Analyse des algorithmes)

Ces notes de cours de l'ENS Rennes sont une excellente référence pour l'Agrégation. La section sur l'analyse amortie du tableau dynamique est particulièrement claire et rigoureuse. Elle applique les trois méthodes que nous allons étudier.

Lisez attentivement la section intitulée 'L’exemple d’une table dynamique'. Concentrez-vous sur la manière dont les trois méthodes (agrégat, comptable, potentiel) sont utilisées pour arriver à la même conclusion : un coût amorti de O(1) pour l'insertion.

En complément, la vidéo suivante offre une perspective visuelle et très didactique des trois mêmes méthodes.

Amortized Analysis

Cette vidéo de 0612 TV explique de manière très intuitive et visuelle les trois méthodes d'analyse amortie, en utilisant systématiquement l'exemple du tableau dynamique. Elle sera un excellent support pour consolider votre compréhension.

Regardez la vidéo en parallèle de votre lecture. Portez une attention particulière aux parties suivantes : L'introduction au tableau dynamique (02:36 - 04:07) La méthode de l'agrégat (04:51 - 08:22) La méthode comptable (08:22 - 12:27) La méthode du potentiel (12:27 - 18:53)

Maintenant, synthétisons ce que ces ressources nous apprennent.


3. Les Trois Méthodes en Action

a) Méthode de l'Agrégat

L'idée est simple : calculer le coût total d'une séquence de opérations dans le pire des cas, puis diviser par pour obtenir le coût amorti.

Considérons une séquence de insertions dans un tableau initialement vide qui double de taille.

  • Une insertion a un coût de 1 si le tableau n'est pas plein.
  • La -ème insertion a un coût de ( pour l'insertion elle-même + pour la copie) si elle déclenche un redimensionnement. Cela se produit lorsque est une puissance de 2 (en partant de la taille 1).

Le coût total pour insertions est la somme des coûts de toutes les insertions "simples" et des coûts de toutes les insertions "coûteuses" (avec redimensionnement).

Une analyse plus simple, comme dans la note de l'ENS, consiste à majorer le coût total :

La somme est une série géométrique : . Comme , la somme est inférieure à .
Donc, .
Le coût total est en . Le coût amorti par opération est donc .

Analyse Amortie de l'Insertion dans un Tableau Dynamique
Cette image détaille le calcul par la méthode de l'agrégat. Elle montre que la somme des coûts, malgré les pics, reste linéaire par rapport au nombre d'opérations, conduisant à un coût amorti constant.

b) Méthode Comptable

Cette méthode utilise une analogie financière. On assigne un coût amorti (ou "paiement") à chaque opération.

  • Si le paiement est supérieur au coût réel, on stocke la différence ("crédit") dans une "banque".
  • Si le paiement est inférieur au coût réel, on utilise le crédit accumulé pour combler le déficit.

La règle d'or est que le solde de la banque ne doit jamais être négatif.

Pour notre tableau dynamique :

  • Assignons un coût amorti de 3 "pièces" à chaque insertion.
  • Cas 1 : Pas de redimensionnement. Le coût réel est de 1 pièce. On paie 1 pièce pour l'insertion et on dépose les 2 pièces restantes en banque.
  • Cas 2 : Redimensionnement. Supposons que le tableau passe de la taille à . Cela signifie que le tableau est plein et contient éléments. Le coût réel est de (copier éléments et en insérer un nouveau).
    • D'où vient l'argent pour payer ces copies ? Depuis le dernier redimensionnement (de à ), on a inséré éléments. Chacun a déposé 2 pièces en banque.
    • Nous avons donc pièces en banque.
    • Ces pièces paient exactement pour la copie des éléments. La pièce "courante" de notre paiement de 3 paie pour l'insertion elle-même. Les 2 autres pièces sont déposées pour un futur redimensionnement.

Le solde ne devient jamais négatif. Puisque nous avons trouvé un coût amorti constant (3) pour chaque opération, la complexité amortie est de .

c) Méthode du Potentiel

Cette méthode est une version plus formelle de la méthode comptable. Au lieu de crédits, on définit une fonction de potentiel qui associe un nombre réel (le "potentiel") à chaque état de la structure de données.

Le coût amorti de la -ème opération est défini par :

où est le coût réel, est l'état avant l'opération, et est l'état après. est la variation de potentiel.

On doit choisir telle que :

  1. pour l'état initial.
  2. pour tout état .

Pour le tableau dynamique, une fonction de potentiel efficace est :

où T.num est le nombre d'éléments et T.capacity la capacité du tableau.

  • Vérifions les conditions : Pour une table vide, , donc . Juste après un doublement, , donc . Entre deux redimensionnements, augmente, et on peut montrer que toujours.

Calculons le coût amorti :

  • Cas 1 : Pas de redimensionnement.

    • Coût réel .
    • , .
    • .
    • .
  • Cas 2 : Redimensionnement.

    • . Le coût réel .
    • , .
    • .
    • .
    • .
    • .

Dans les deux cas, le coût amorti est constant. La complexité amortie est donc de . Pour une présentation formelle de ces calculs, je vous encourage à consulter la ressource LINK (MIT OpenCourseWare).


Conclusion

Aujourd'hui, nous avons ajouté un outil puissant à votre arsenal d'analyste d'algorithmes. L'analyse amortie nous permet d'obtenir une vision plus juste de la performance des structures de données dynamiques, en évitant le pessimisme de l'analyse du pire cas sur une seule opération.

Points clés à retenir :

  • La complexité amortie analyse le coût moyen d'une opération sur une séquence dans le pire des cas, et n'est pas de nature probabiliste.
  • Le tableau dynamique, avec sa stratégie de doublement de capacité, est l'exemple canonique.
  • Les trois méthodes (agrégat, comptable, potentiel) sont trois perspectives différentes qui mènent à la même conclusion rigoureuse : l'insertion dans un tableau dynamique a un coût amorti de .

Dans notre prochaine leçon, nous entamerons un nouveau module fondamental : les algorithmes de tri. Nous commencerons par l'un des plus simples, le tri par insertion, et analyserons sa complexité dans le meilleur et le pire des cas, ce qui nous ramènera à l'analyse plus classique d'une seule opération.