Introduction à l'analyse des algorithmes

14 Feb 2017 14 Feb 2017 16773 vues ESSADDOUKI Mostafa 10 min de lecture
Complexité algorithmique
1 Introduction à l'analyse des algorithmes 2 Notations asymptotiques 3 Opérations élémentaires et modèles de coût 4 Complexité temporelle et spatiale 5 Méthode de comptage des pas 6 Méthode de comptage des pas pour les boucles
Diviser pour régner & algorithmes de tri
7 Rappel sur l'approche récursive 8 Diviser pour régner 9 la recherche dichotomique 10 Tri par fusion 11 Tri rapide 12 Analyse des fonctions récursives
Les arbres binaires
13 Introduction aux arbres binaires 14 Définitions récursives des arbres 15 Propriétés des arbres binaires 16 Types d'arbre binaire 17 Parcours en profondeur des arbres binaires 18 Parcours en largeur des arbres binaires 19 Exercices corrigés sur les arbres - TD 1 20 Exercices corrigés sur les arbres - TD 2 21 Exercices corrigés sur les arbres - TD 3 22 DS - Arbres binaires de recherche équilibrés (AVL) 23 DS - Codage de Huffman - Compression de données
Algorithmes gloutons
24 Introduction aux algorithmes gloutons 25 Problème de la sélection d'activités 26 Problème de séquencement des tâches 27 Problème du Sac à Dos fraction
Programmation dynamique
28 Introduction à la programmation dynamique 29 Le concept de sous-structure optimale 30 Le concept de sous-problèmes superposés 31 Méthodes de la programmation dynamique 32 Différence entre la programmation dynamique, l'approche diviser pour régner, et les algorithmes gloutons 33 Calculer les nombres de catalan en C++ et Python 34 Calculer le coefficient binomial 35 Le nombre de façons pour construire un mur de dimension 4*N 36 Défi de conversion de mots 37 Décomposition de phrases à partir d'un dictionnaire 38 La collection de pièces dans un labyrinthe 39 Nombre de façons de regrouper les étudiants 40 Compter tous les chemins possibles dans une grille MxN
Méta heuristique
41 Algorithmes heuristiques et métaheuristiques 42 Algorithme de Recuit simulé 43 Algorithme Colonies de fourmis
Théorie des graphes
44 Introduction et notions fondamentales 45 Chemins, cycles et connexité 46 Représentations des graphes 47 Parcours de graphes 48 Algorithme de Dijkstra 49 Algorithme A* 50 Algorithme de Bellman-Ford 51 Algorithme Floyd-Warshall 52 Coloration des graphes
Base de données et SQL
53 Introduction au langage SQL 54 Concepts de base de SGBDR 55 Syntaxes de différentes instructions SQL 56 Création et suppression d'une base de données 57 Opérateurs SQL 58 Les contraintes en SQL 59 Création et suppression des tables en SQL 60 Insertion et modifications des enregistrements 61 Extraction des données - SELECT 62 Filtrer les données - WHERE 63 Recherche de motifs - LIKE 64 Trier les données - ORDER BY 65 Les jointures en SQL - JOIN 66 Fonctions d'agrégation en SQL - SUM, COUNT, AVG, MIN et MAX 67 Organiser des données identiques en groupes - GROUP BY et HAVING 68 Les sous-requêtes en SQL 69 Les fonctions SQL de manipulation de date 70 DS - langage SQL 71 Exercices corrigés de langage SQL
Introduction à l'intelligence artificielle
Introduction à la théorie des jeux
Préparation aux concours
72 Réseau de distribution d'eau 73 Arbre d'expression arithmétique 74 Exploration d'une grotte souterraine

Analyse des algorithmes

Pourquoi se préoccuper des performances ?

Lors du développement d'un logiciel, de nombreux éléments importants doivent être pris en compte, tels que la convivialité, la modularité, la sécurité, la facilité de maintenance, etc. Pourquoi se préoccuper des performances ?

La réponse à cette question est simple : nous ne pouvons avoir toutes les choses ci-dessus que si nous avons des performances. La performance est donc comme une devise à travers laquelle nous pouvons acheter toutes les choses ci-dessus. Une autre raison d'étudier la performance est la vitesse.

Dans l'analyse théorique des algorithmes, il est courant d'estimer leur complexité au sens asymptotique, c'est-à-dire d'estimer la fonction de complexité pour une entrée arbitrairement grande.

L'analyse des algorithmes est une partie importante de la théorie de la complexité de calcul, qui fournit une estimation théorique des ressources requises d'un algorithme pour résoudre un problème de calcul spécifique. La plupart des algorithmes sont conçus pour fonctionner avec des entrées de longueur arbitraire. L'analyse des algorithmes consiste à déterminer la quantité de ressources en temps et en espace nécessaires à son exécution.

Habituellement, l'efficacité ou la durée d'exécution d'un algorithme est définie comme une fonction liant la longueur en entrée au nombre d'étapes, appelée complexité temporelle, ou volume de mémoire, appelé complexité spatiale.

Le besoin d'analyse

Les algorithmes sont souvent assez différents les uns des autres, même si leur objectif est le même. Par exemple, nous savons qu'un ensemble de nombres peut être trié en utilisant différents algorithmes. Le nombre de comparaisons effectuées par un algorithme peut varier avec d'autres pour la même entrée. Par conséquent, la complexité temporelle de ces algorithmes peut différer. Dans le même temps, nous devons calculer l'espace mémoire requis par chaque algorithme.

Comment pouvons-nous savoir lequel est le meilleur ?

Une façon naïve de faire cela consiste à implémenter les deux algorithmes et à exécuter les deux programmes sur votre ordinateur pour différentes entrées et voir lequel prend moins de temps.

Mais cette approche peut échouer dans certains cas :

  • Il est possible que pour certaines entrées, le premier algorithme fonctionne mieux que le second. Et pour certaines entrées, le second fonctionne mieux.
  • Il est également possible que, pour certaines entrées, le premier algorithme fonctionne mieux sur une machine et que le second fonctionne mieux sur une autre machine pour certaines autres entrées.

Une autre approche est l'analyse asymptotique. L'analyse asymptotique est la grande idée qui traite les problèmes ci-dessus dans l'analyse des algorithmes. Dans l'analyse asymptotique, nous évaluons les performances d'un algorithme en termes de taille d'entrée (nous ne mesurons pas le temps d'exécution réel). Nous calculons comment le temps (ou l'espace) pris par un algorithme augmente avec la taille d'entrée.

Est-ce que l'analyse asymptotique fonctionne toujours ?

L'analyse asymptotique n'est pas parfaite, mais c'est le meilleur moyen disponible pour analyser des algorithmes. Par exemple, supposons qu'il existe deux algorithmes de tri qui prennent respectivement 3000n log n et 10n log n sur une machine. Ces deux algorithmes sont asymptotiquement identiques (l'ordre de croissance est n log n). Ainsi, avec l'analyse asymptotique, nous ne pouvons pas déterminer lequel est le meilleur car nous ignorons les constantes dans l'analyse asymptotique.

En outre, dans l'analyse asymptotique, nous parlons toujours de tailles d'entrée supérieures à une valeur constante. Il se peut que ces entrées volumineuses ne soient jamais données à votre logiciel et qu'un algorithme asymptotiquement plus lent donne toujours de meilleurs résultats dans votre situation particulière. Vous pouvez donc choisir un algorithme asymptotiquement plus lent mais plus rapide pour votre logiciel.

Types d'analyse

Généralement, nous effectuons les types d'analyse suivants :

  • Le pire des cas (Worst case) − Le nombre maximum d'opérations effectuées sur une instance de taille n.
  • Le meilleur des cas (Best case) − Le nombre minimum d'opérations effectuées sur une instance de taille n.
  • Cas moyen (Average case) − Le nombre moyen d'opérations effectuées sur une instance de taille n.

Analyse asymptotique - Exemple de la recherche linéaire

Considérons l'implémentation suivante de la recherche linéaire.

#include <stdio.h>

int recherche(int tab[], int n, int x)
{
    int i;
    for (i = 0; i < n; i++)
    {
        if (tab[i] == x)
            return i;
    }
    return -1;
}

int main()
{
    int T[] = {1, 3, 17, 80, 25, 10, 30, 15};
    int x = 25, n, pos;
    n = sizeof(T) / sizeof(T[0]); // calculer la taille du tableau

    pos = recherche(T, n, x);
    if (pos < 0)
        printf("l'élément %d n'appartient pas à la table", x);
    else
        printf("l'élément %d est trouvé dans le tableau à la position %d", x, pos);

    return 0;
}
def recherche(tab, n, x):
    i = 0
    for i in range(i, n):
        if (tab[i] == x):
            return i
    return -1


T = [1, 3, 17, 80, 25, 10, 30, 15]
x = 25
n = len(T)
pos = recherche(T, n, x)
if (pos < 0):
    print("l'élément {} n'appartient pas à la table".format(x))
else:
    print("l'élément {} est trouvé dans le tableau à la position {}".format(x, pos))

Lorsque le code ci-dessus est compilé et exécuté, il produit le résultat suivant :

Résultat
l'élément 25 est trouvé dans le tableau à la position 4

Analyse des différents cas

Le pire des cas - Worst case

Dans le pire des cas, nous calculons la limite supérieure du temps d'exécution d'un algorithme. Nous devons connaître le cas qui entraîne l'exécution d'un nombre maximal d'opérations.

Pour la recherche linéaire, le pire des cas se produit lorsque l'élément à rechercher (x dans le code ci-dessus) n'est pas présent dans le tableau. Lorsque x n'est pas présent, la fonction recherche() le compare à tous les éléments de tab[] un à un.

Complexité dans le pire des cas

La complexité temporelle de la recherche linéaire dans le pire des cas serait : \[ \Theta(n) \]

Cas moyen - Average case

Dans l'analyse de cas moyen, nous prenons toutes les entrées possibles et calculons le temps de calcul pour toutes les entrées. Faisons la somme de toutes les valeurs calculées et divisons la somme par le nombre total d'entrées. Nous devons connaître (ou prédire) la distribution des cas.

Pour le problème de la recherche linéaire, supposons que tous les cas soient uniformément distribués (y compris le cas où x n'est pas présent dans le tableau). Nous additionnons donc tous les cas et divisons la somme par \((n + 1)\).

\[ \begin{equation} \begin{split} \text{Temps moyen} & = \frac{\sum_{i=1}^{n+1} \Theta(i)}{n+1} \\ & = \frac{\Theta((n+1)*(n+2)/2)}{n+1} \\ & = \Theta(n) \end{split} \end{equation} \]

Complexité en cas moyen

La complexité temporelle de la recherche linéaire en cas moyen est également : \[ \Theta(n) \]

Remarque

L'analyse de cas moyen n'est pas facile à faire dans la plupart des cas pratiques et c'est rarement fait. Dans l'analyse de cas moyen, nous devons connaître (ou prévoir) la distribution mathématique de toutes les entrées possibles.

Le meilleur des cas - Best case

Dans l'analyse du meilleur des cas, nous calculons la limite inférieure du temps d'exécution d'un algorithme. Nous devons connaître le cas qui entraîne l'exécution d'un nombre minimal d'opérations.

Dans le problème de la recherche linéaire, le meilleur des cas se produit lorsque x est présent au premier emplacement. Le nombre d'opérations dans le meilleur des cas est constant (ne dépend pas de n).

Complexité dans le meilleur des cas

La complexité temporelle dans le meilleur des cas serait : \[ \Theta(1) \]

Attention

L'analyse du meilleur des cas est trompeuse. Garantir une limite inférieure sur un algorithme ne fournit aucune information car dans le pire des cas, un algorithme peut prendre des années à s'exécuter.

Tableau récapitulatif pour la recherche linéaire

Type d'analyseConditionNombre d'opérationsComplexité
Meilleur casL'élément recherché est en première position1 comparaison\(\Theta(1)\)
Cas moyenDistribution uniforme des positions\(\frac{n+1}{2}\) en moyenne\(\Theta(n)\)
Pire casL'élément n'est pas présent ou est en dernière positionn comparaisons\(\Theta(n)\)

Quel type d'analyse privilégier ?

Recommandations
  • La plupart du temps, nous effectuons une analyse dans le pire des cas. Dans cette analyse, nous garantissons une limite supérieure sur le temps d'exécution d'un algorithme, ce qui est une bonne information.
  • L'analyse de cas moyen n'est pas facile à faire dans la plupart des cas pratiques et c'est rarement fait.
  • L'analyse du meilleur des cas est trompeuse et ne fournit pas d'information utile pour évaluer un algorithme.
Résumé du cours

L'analyse des algorithmes est essentielle pour évaluer leurs performances indépendamment de la machine et du langage d'implémentation.

  • Analyse asymptotique : étude du comportement d'un algorithme quand la taille de l'entrée devient très grande.
  • Trois types d'analyse:
    • Pire cas (\(\Theta(n)\) pour la recherche linéaire) : le plus utile en pratique
    • Cas moyen (\(\Theta(n)\) pour la recherche linéaire) : difficile à calculer
    • Meilleur cas (\(\Theta(1)\) pour la recherche linéaire) : trompeur
  • L'analyse asymptotique ignore les constantes et les termes de plus faible ordre pour se concentrer sur l'ordre de croissance.

Sortie
// La sortie apparaîtra ici…
Prêt · Ctrl+Entrée pour exécuter

Discussion (0)

Soyez le premier à laisser un commentaire !

Laisser un commentaire

Votre commentaire sera visible après modération.