Introduction A L'algorithmique
Introduction A L'algorithmique
l’algorithmique
ATSA ETOUNDI Roger
Professeur Titulaire en Informatique
[email protected]
La société se
digitalise!!!
La société se digitalise!!!
La société se digitalise!!!
Réalité virtuelle
• Marketing digital
Réalité augmentée
• Internet
Intelligence artificielle • Systèmes distribués
• etc
Robotisation
Algorithmes
Génie logiciel
Data science
Réseaux informatiques
Internet des objets
Résolution Informatique des Problèmes
Nous vivons dans un monde digital, les ordinateurs et les robots sont désormais autour de nous.
Les ordinateurs à travers les programmes informatiques ou logiciels et les robots permettent à l’homme de réaliser des travaux répétitifs non
cognitifs en faisant des économies en temps tout en minimisant les erreurs et maintenant une certaine qualité de service.
Les ordinateurs et les robots remplacent l’humain dans l’exécution de certaines activités au sein de l’entreprise.
Les ordinateurs et les robots ont une chose en commun, c’est les programmes informatique qui tournent ou sont exécutés en leur sein.
Les programmes informatiques constituent la base de l’informatique et qui donnent un sens à l’informatique.
Avant que l’ordinateur ou le robot ne résolve le problème, l’informaticien doit dans un premier temps comprendre comment ce problème est
résolu par l’homme.
Un problème est résolu avec les définition des différentes étapes non conflictuelles qui permettent d’attendre le résultat souhaité.
Les différentes étapes conflictuelles permettant l’atteinte d’un résultat escompté est appelé un algorithme.
L’algorithme sera par la suite traduit dans un langage compréhensible par l’ordinateur.
L’activité de traduction de l’algorithme en langage compréhensible par l’ordinateur est appelée programmation.
La programmation se fait en utilisant un langage de programmation.
C’est au terme de la programmation que l’informaticien va mettre en place une application ou logiciel devant être exécuté par un ordinateur
ou un robot.
Retenons: Pas d’algorithme pas de programmation. Pas de programmation pas de logiciel. Pas de logiciel pas d’ordinateur et de robot. Tout
informaticien doit savoir écrire les algorithme et les programmes informatiques.
Résolution Informatique des Problèmes
L’informaticien pour mener à bien son travail doit:
Définir les étapes non conflictuelles a la résolution du problème
Pour définir ces étapes, l’informaticien doit tres bien comprendre le problème.
La compréhension du problème suppose la définition ou l’existence d’un cahier de charges.
Le cahier de charges contient les différentes contraintes et différents besoins des utilisateurs finaux ou les demandeurs ou ceux qui
observent le problème.
Chaque étapes de l’algorithme doit être maitrisée.
La maitrise suppose la connaissance des données à prendre en compte des le départ (données d’entrée - Input) et les données à
l’arrivée (donnée en sortie – output)
Les données de la première étape sont appelées données initiales.
Les données de la dernière étape sont appelées données résultats.
Pour les étapes intermédiaires, les données résultats de l’ étape précédentes constituent les les données d’entrée pour l’ étape
suivante.
Un algorithme peut etre vu comme une boîte noire ou une boîte blanche.
L’algorithme vu comme une boite noir es juste la définition des données initiales associées à leurs contraintes et les données
résultats associées à leurs contraintes.
L’algorithme vu comme une boite blanche est la données des détails de toutes étapes et les conditions pour leurs exécutions
Algorithme
Algorithme vu comme une boîte noire
Entrées sorties
Nom de l’algorithme
Résolution Informatique des Problèmes
Algorithme de glouton
Diviser pour régner
Programmation dynamique
Algorithme de glouton
Les algorithmes pour problèmes d’optimisation exécutent en général une série d’étapes,
chaque étape proposant un ensemble de choix.
Pour de nombreux problèmes d’optimisation, la programmation dynamique est une
approche bien trop lourde pour déterminer les meilleurs choix ; d’autres algorithmes,
plus simples et plus efficaces, peuvent faire l’affaire. Un algorithme glouton fait
toujours le choix qui lui semble le meilleur sur le moment.
Autrement dit, il fait un choix localement optimal dans l’espoir que ce choix mènera à
une solution globalement optimale. Cette activité étudie les problèmes d’optimisation
qui peuvent se résoudre par des algorithmes gloutons.
Algorithme de glouton: Le principe
La méthode de diviser pour régner est une méthode qui permet, parfois de trouver des
solutions efficaces à des problèmes algorithmiques.
L’idée est de découper le problème initial, de taille n, en sous-problèmes de taille plus
petite, résoudre les sous-problèmes récursivement (ou les résoudre directement si de
taille suffisamment petite), puis recombiner les solutions des sous-problèmes pour
obtenir la solution du problème d’origine.
Principe
Afin de résoudre un problème, on commence tout d’abord par résoudre les plus petits
sous-problèmes et on stocke les valeurs de ces sous-problèmes dans une table de
programmation dynamique.
Ensuite, on utilise ces valeurs pour calculer la valeur des sous-problèmes de plus en
plus grands, jusqu’à obtenir la solution de notre problème global.
Spécification d’un algorithme
Une séquence est une série d’ étape s qui s’exécutent une par une suivant un ordre
prédéfini
Une étape sera appelée une instruction
Exemple
Présenter le probatoire
Présenter le baccalauréat
Les sélections
Seules certaines instruction sont exécuter lorsque certaines conditions sont satisfaites
On en distingue:
Si..
Si sinon
Cas selon
Structures de contrôle
On
On execute un nombre fini de fois un ensemble d’instructions
Syntaxe
Pour cp = val-ini a valf, pas faire
Action(s)
Fin_pour
Cp represdnte le compteur
Val-ini représente la valeur initiale du compteur
Valf représente la valeur finale
Pas représente le saut a chaque iteration
Remarques
Si val-ini < valf, on va incrementer cp du pas à la fin de chaque interation
Si val-ini > valf, on decremengte cp du pas à la fin de chaque iteration
Si pas = 1 ou pas = -1, on ne le représente pas sur la boucle
Exemple
….
…. ….
P<- 1
P<- 1 Pour j =100 a 1 faire
Pour j =1 a 100 faire p<- p*j Pour j =0 a 100,2 faire
p<- p*j Finpour afficher (j)
Finpour afficher (p) Finpour
La valeur du pas est 1
afficher (p) ce bout de
La valeur du pas est 1 programme affiche
Le bout de programme calcule la
factoriel de 100 tous les nombres pairs
Le bout de programme
inferieur ou egal a 100
calcule la factoriel de 100
Répéter
Ce mot clé permet l’execution d’un ensemble d’instructions jusqua ce que une
condition soit satisfaite
Syntaxe
Répéter
action(s)
Jusqu’à cond
Sémantique
L’ensemble d’actions est executees jusqu’à ce que la condition cond soit evaluee a
vraie
Repeter
….
P<- 1
J<-1
repeter
p<- p*j
j <- j+1
Jusqu’à j>100
afficher (p)
Le bout de programme
calcule la factoriel de 100
Tant-que
Ce mot cle permet d’executer un ensemble d’instruction tant qu’une condition est
satisfaite
Syntaxe
Tantque Cond faire
action(s)
Fintantque
Sémantique
On execute l’ensemble des actions tant que la condition cond est evaluee a vraie
Exemple
….
P<- 1
J<-1
Tantque j<=100 faire
p<- p*j
j <- j+1
fintantque
afficher (p)
Le bout de programme
calcule la factoriel de 100
Ecriture d’algorithme
Un type abstrait de donnée est une représentation formelle d’un type de données, le type de données étant un
ensemble de données ayant les mêmes opérations
La représentation est dite formelle car elle utilise les concepts mathématiques
Elle est définie par
Son nom
Son type d’ Intérêt ou ensemble de données ayant les mêmes propriétés
Primitive (utilise, étendre)
Les opérations
Générateurs
transformateur
Constructeurs
Observateurs
prédicats
Les propriétés
Type abstrait de donnée
La primitive « Utilise » est suivie ou definit les types abstraits que l'on va utiliser dans
celui que l'on est en train de décrire
Parmi les opération on a:
Un générateur est une opération qui donne naissance au type que l’on est entrain de définir
les constructeurs permettent de créer un objet du type que l'on est en train de définir ;
les transformateurs permettent de modifier les objets et leur contenu;
les observateurs sont des fonctions donnant des informations sur l'état de l'objet.
Type Booléen
TAD Bool1
Tyepe: Bool
Générateur TAD Bool2
true:Bool
étendre Bool1 avec
false:Bool
Constructeurs Constructeur
et: Bool xBool -> Bool non: Bool -> Bool
ou : Bool x Bool -> Bool Propriété
eq : Bool x Bool -> Bool
P3: b:Bool non (non b))=b
Propriétés
P1: b:Bool b et b =b fin
p2: b,b’:Bool, b=/=b’ => b eq b’ = false
fin
Type abstrait des entiers naturels
TAD Tableau1
Etendre Tableau avec
Axiome x ∈ Obj, j : Nat, t,t’ : Tab
P9: empty(t) => last(t) = findex(t) -1
P10: set(t,j,x) = t’ => non full(t) /\
last(t’)=last(t)+1 /\
get(t’,last(t’))=x
P11: full(t) => last(t) = lindex(t)
Type abstrait pile
Une pile est une liste linéaire d’objets où les consultations les insertions et les
suppressions se font du même coté.
Dernier arrivé, premier servi.
Les opérations suivantes peuvent lui être appliquées: empiler (push), dépiler (pop),
sommet (top), pile vide (empty)
Type abstrait pile
Une file d’attente ou tout simplement un file est une liste linéaire d’objets où les
consultations et les suppressions se font du même coté, les insertions se font de l’autre
coté.
Elle respecte le principe: Premier arrivé, premier servi.
Les opérations suivantes sot appliquées à une file:
enfiler, défiler,tête, queue, file vide
Formalisation de la File d’attente
TAD File
Type File, Obj
utilise Bool Axiomes : f,f’:File, o:obj
Opérations : P1: defiler(f ) =f’ => non estVide(f )
fileVide : → File
P2: estVide(FileVide()) = VRAI
P3: estVide(Enfiler(o,f )) = FAUX
estVide : File → Booleen
P4: defiler(Enfiler(o, f)) = f
enfiler : Obj x File → File
P5: non estVide(f ) =>
defiler : File → File
defiler(Enfiler(o, f )) = f
fin
Formes canoniques de la file
Une file d’attente prioritaire est une liste linéaire d’objets où les consultations et les
suppressions se font du même coté, les insertions se font de l’autre coté, à la différence de
la file normale, les objets sont classés par ordre de priorité.
Notons:
L’objet le plus prioritaire se trouve toujours le premier à être consulté ou supprimé.
File prioritaire
TAD Objet
Type Obj, Priorité
Opération
priority : Obj → Priorité
Axiome
o,o’ :Obj o=o’ => priority(o) = priority(o’)
fin
File prioritaire
Axiomes : f,f’:Filep, o:obj
TAD Filep P1: defiler(f ) =f’ => non estVide(f )
Type Filep P2: estVide(fileVide()) = VRAI
utilise Bool, Objet P3: estVide(Enfiler(o,f )) = FAUX
Opérations :
P4: defiler(o, f)) = f’ =>
fileVide : → Filep
priority(dernier(f’)
priority(premier(f’))
estVide : Filep → Booleen
P5: enfiler(o, enfiler(0’,fileVide))
enfiler : Obj x Filep → Filep
= f => priority(dernier(f)
defiler : Filep → Filep priority(premier(f))
premier: FileP → Obj fin
dernier: FileP → Obj
Les listes chaînées
l'utilisation des files, si elle semble similaire à celle des piles, est en réalité fort différente.
Chacun de ces TAD a ses avantages et inconvénients.
Le principal défaut de ces TAD est d'être obligé de défiler/dépiler les éléments les uns
après les autres pour pouvoir les traiter, ce qui oblige à les rempiler/renfiler par la suite
avec tous les risques que cela implique quant à l'ordre des éléments.
Notre troisième TAD va donc régler ce souci puisque nous allons traiter des listes chaînées
Les listes chaînées
Comme dit précédemment, les listes chaînées sont linéaires, doublement chaînées, non
cycliques et non contraintes.
Qui plus est, elles pourront être traitées en LIFO (comme une pile) ou en FIFO (comme
une file) mais il sera également possible d'insérer un élément au beau «milieu» de la liste.
Pour cela, il devra être possible de parcourir la liste sans la «démonter» comme nous le
faisions avec les piles ou les files.
Les listes chaînées
Une liste L est composée de 2 parties :
sa tête (souvent noté car), qui correspond au dernier élément ajouté à la liste,
sa queue (souvent noté cdr) qui correspond au reste de la liste.
Le langage de programmation Lisp (inventé par John McCarthy en 1958) a été un des premiers langages de programmation à
introduire cette notion de liste (Lisp signifie "list processing").
Voici les opérations qui peuvent être effectuées sur une liste :
créer une liste vide (L=vide() on a créé une liste L vide)
tester si une liste est vide (estVide(L) renvoie vrai si la liste L est vide)
ajouter un élément en tête de liste (ajouteEnTete (x,L) avec L une liste et x l'élément à ajouter)
Ajouter un élément a une position intermédiaire
Ajouter un élément a la fin de la liste
supprimer la tête x d'une liste L et renvoyer cette tête x (supprEnTete(L))
Compter le nombre d'éléments présents dans une liste (compte(L) renvoie le nombre d'éléments présents dans la liste L)
Supprimer l’ élément de fin de liste
Supprimer un élément intermédiaire
Formalisation de la liste chaînée
Pour formaliser le fonctionnement d’une liste chainée, il
est important de comprendre la spécification d’une cellule,
car en réalité, une liste est une association des cellules
TAD Cellule
mémoires.
Type Cel, Obj. Adr
*Une cellule est constituée: Opérations
créer: → Cel
d’une zone d’adresse de la cellule suivante
adresse: Cel → Adr
*d’une zone de donnée data: Cel → Obj
adrsuiv: Cel → Adr
Axiomes
" c,c:Cel
c c’ => adresse Cc) adresse(c’)
fin
Formalisation de la liste chaînée
TAD Liste0
Type List
Utilise Cellule
Operations Axiomes l’l’:List. o:Obj
listevide: List P1: l’=ajouter(l,o) => data(tete(l’))=o /\
queue(l’)=l /\
créer: → List adrsuiv(tete(l’))=adr(tete(l))
ajoutertete: ListxObjt → List P2: l’=deltete(l) => l listvide /\ l’=queue(l)
fin
deltete: List → List
tete : List → Cel
queue: List → List
Formalisation de la liste chaînée
TAD Liste1
Etendre List0 avec Axiomes l’l’:List. o:Obj
Operations P1: l’=ajouterfin(l,o) => data(last(l’))=o /\
ajouterfin: ListxObjt → List
delfin: List → List precedent(last(l’))=last(l)
last : List → List
P2: l’=delfin(l) => l listvide /\
last(l’) =
precedent: CelxList → Cel
precedent(last(l))
Fin
Formalisation de la liste chaînée
TAD Liste2
Etendre List1 avec Axiomes l’l’:List. o:Obj,c:Cel
P1: l’=ajouterinter(l,o,c) =>
Operations data(precedent(c,l’))=o /\
ajouterinter: ListxObjtxCel→ List suiv(suiv(precedent(c,l),l’),l’)=c
delinter: ListxCel→ List
P2: l’=delfinter(l,c) => l listvide /\
last : List → List suiv(precedent(c,l),l’) =
suiv: CelxList → Cel suiv(c,l)
Fin
Le type Ensemble
Définition informelle
On décrit une collection d’objets de même type, avec les
opérations d’ajout d’un élément, de suppression, d’appartenance et
de cardinalité (nombre d’éléments).
Notons:
un élément, s’il appartient à un ensemble n’y apparaît
qu’une fois et une seule.
Définition formelle d’un ensemble
Axiomes : o, o’:Obj, e:Ens
estVide(Vide()) = Vrai
TAD Ensemble estVide(ajoute(x; e)) = Faux
appartient(o,Vide()) = Faux
Type Ens. Obj appartient(o; ajoute(o; e)) = Vrai
Utilise Bool
o =o’ => ajoute(o, ajoute(o’, e)) =
Opérations : ajoute(o, e)
vide : → Ens supprime(o,ajoute(o, e)) = e
estVide : Ens(T) → Booleen
oo’ => ajoute(o,ajoute(o’,e)) =
ajoute : Obj x Ens → Ens ajoute(o’ ajoute(o, e))
supprime : Obj x Ens → Ens
Supprime(o,ajoute(o’,e)) =
appartient : Obj x Ens → Booleen ajoute(o,supprime(o, e))
fin
Type chaine de caractères
TAD Ch1
Type: Ch, Char
utilise Nat
Générateur
chv:Ch
Constructeurs
concat: Ch x Ch -> Ch
sousch: ChxNatxNat -> Nat
long: Ch -> Nat
souschg: Ch x Nat -> Ch
souschd ChxNat -> Ch
observateur
char: ChxNat -> Char
Enregistrement
TAD Etudiant
type: Etud, Nom, Filiere, Niveau, Matricule
Operations
nom: Etdu -> Nom
matricule: Etud -> Matricule
filiere-etud: Etud -> Filiere
niveau: Etud -> Niveau
Axiomes
[a1] e,e’:Etud ee’ => matricule(e) matricule(e’)
fin
Exercices
1. Ecrire les algorithmes associés aux fonctions définies dans les types abstraits vus
précédemment
2. En reprenant l’épreuve du contrôle continu, donner les algorithmes associés aux
fonctions décrites.
Sous-programmes
Le sous-programme est une partie presque indépendante d’un alogorithme qui a un nom et peut être appelée d'un
autre sous-programme ou de l’algorithme principal.
Il y a deux sortes de sous-programmes:
Procédures
fonctions.
L'appel d'une fonction est une expression, c'est-à-dire que la fonction renvoie un résultat (valeur).
L’appel d’une procédure est
une instruction, c'est-à-dire que la procédure ne renvoie rien
Ecriture de Sous-programmes
Les paramètres (formels) d'un sous-algorithme sont simplement des variables locales qui sont initialisées par les valeurs
obtenues lors de l'appel (paramètres effectifs ou arguments)
Au moment de l'appel du sous-algorithme , les valeurs des arguments sont affectés aux paramètres formels de statut (D)
ou (D/R) ; • Le nombre de paramètres doit correspondre au nombre d’arguments.
Le type du kième argument doit correspondre au type du kième paramètre.
Un paramètre défini en "Donnée" doit correspondre à un argument qui
possède une valeur dans l’algorithme appelant au moment de l’appel. • Un paramètre défini en "Résultat"
doit recevoir une valeur dans le sous algorithme
Procédure : syntaxe
Fonction : syntaxe
Mise en ouvre d'une fonction
Le principe du tri par sélection/échange (ou tri par extraction) est d'aller chercher le plus
petit élément du vecteur pour le mettre en premier, puis de repartir du second élément et
d'aller chercher le plus petit élément du vecteur pour le mettre en second, etc..
Le tri à peigne est un algorithme de tri par comparaison qui améliore de façon notable
les performances du tri à bulle. Cet algorithme fut conçu en 1980 par Włodzimierz
Dobosiewicz. Quelques années plus tard, en 1991, Stephen Lacey et Richard Box ont
montré dans un article dans Byte Magazine que l'idée de Donald Shell pouvait
s'appliquer également, et avec autant de bénéfices, au tri bulle.
Le principe est de ne plus comparer uniquement des éléments adjacents, mais de
commencer par comparer des éléments plus lointains, puis de raccourcir
progressivement l'intervalle entre les éléments pour aboutir finalement à un tri à bulle
classique.
Le tri à peigne
Donald L. Shell proposa, en 1959, une variante du tri par insertion. Ce tri consiste à
trier séparément des sous-suites de la table, formées par les éléments répartis de h en h.
Empiriquement, Shell propose la suite d'incréments vérifiant h 1 = 1, hn+1 = 3hn+1 en
réalisant les tris du plus grand intervalle possible vers le plus petit.
Le tri de Shell
Cet algorithme a été d'abord proposé en 2000 - sous le nom de "tri stupide" - par le Dr.
Hamid Sarbazi-Azad (Professeur à l'université de Sharif, une des plus grandes
universités d'Iran) puis redécouvert plus tard par Dick Grune (le premier développeur
de CVS) qui l'appela "gnome sort" (parce qu'il parait que c'est la méthode qu'utilisent
les nains de jardin hollandais pour trier une rangée de pots de fleurs).
L'algorithme est similaire au tri par insertion, sauf que, au lieu de insérer directement
l'élément à sa bonne place, l'algorithme effectue une série de permutations, comme
dans un tri bulle.
Le tri Gnome
PROCEDURE tri_Gnome(tableau[])
pos ← 1
TANT QUE pos < longueur(tableau)
SI (tableau[pos] >= tableau[pos-1])
pos ← pos + 1
SINON
echanger tableau[pos] ET tableau[pos-1]
SI (pos > 1)
pos ← pos - 1
FIN SI
FIN SI
FIN TANT QUE
FIN PROCEDURE
Le tri maximier
Cette méthode de tri (aussi appelée «tri par tas» ou «heapsort» ou «tri de Williams») est
basée sur la notion de tas. Un tas est un arbre binaire parfait tel que l’information
contenue dans tout nœud est supérieure à celle contenue dans ses fils. La méthode du tri
par tas comporte deux étapes :
Construction par insertions successives d’un tas à partir du vecteur à trier.
On remplace la racine, qui est nécessairement le plus grand élément du tableau par son
fils le plus grand. La racine est transférée à la place de la dernière feuille de l’arbre et
celle-ci est repositionnée. On réitère avec la nouvelle racine autant de fois qu’il y a de
nœuds dans l’arbre.
Le tri fusion
Le tri rapide - aussi appelé "tri de Hoare" (du nom de son inventeur Tony Hoare) ou "tri par segmentation"
ou "tri des bijoutiers" ou, en anglais "quicksort" - est certainement l’algorithme de tri interne le plus
efficace.
Le principe de ce tri est d’ordonner le vecteur T.(0)..T.(n) en cherchant dans celui-ci une clé pivot autour de
laquelle réorganiser ses éléments. Il est souhaitable que le pivot soit aussi proche que possible de la clé
relative à l’enregistrement central du vecteur, afin qu’il y ait à peu près autant d’éléments le précédant que le
suivant, soit environ la moitié des éléments du tableau. Dans la pratique, comme dans la démo ci-dessous,
on prend souvent le dernier élément du tableau.
On permute ceux-ci de façon à ce que pour un indice j particulier tous les éléments dont la clé est inférieure
à pivot se trouvent dans T.(0)...T.(j) et tous ceux dont la clé est supérieure se trouvent dans T.(j+1)...T.(n).
On place ensuite le pivot à la position j.
On applique ensuite le tri récursivement à, sur la partie dont les éléments sont inférieurs au pivot et sur la
partie dont les éléments sont supérieurs au pivot.
Le tri rapide
Le choix du pivot est déterminant pour l'efficacité de ce tri. Plusieurs options sont possibles :
Choisir le premier élément du tableau
Choisir le dernier élément du tableau
Choisir un élément au hasard
Choisir l'élément au milieu du tableau
Trouver le pivot optimal en recherchant la médiane
Ces différentes options peuvent être testées avec l'application ci-dessous. Choisir la médiane comme pivot
est bien entendu la solution optimale... sauf que, la recherche de cette médiane est elle-même coûteuse.
Le tri rapide
Généralement, nous effectuons les types d'analyse suivants avec n la taille des données
en entree:
Le pire des cas: Le nombre maximum de mesures prises sur une instance de taille n.
Le meilleur des cas: Le nombre minimum de mesures prises sur une instance de taille n.
Cas moyen: Nombre moyen d'étapes effectuées sur une instance de taille n.
Le pire des cas - Worst case
Dans le pire des cas, nous calculons jusqu'à 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 dans un tableau, le pire des cas se produit lorsque l'élément à
rechercher n'est pas présent dans le tableau.
Lorsque l’element n’est pas présent, la fonction recherche() le compare à tous les
éléments de tab[0..n] un à un.
Par conséquent, la complexité temporelle de la recherche linéaire dans le pire des cas
serait Θ(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.
Faites la somme de toutes les valeurs calculées et divisez 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ù l’element n'est pas présent dans le
tableau).
Nous additionnons donc tous les cas et divisons la somme par (n + 1).
Cas moyen - Average case
Le meilleur des cas - Best case
Dans l'analyse 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
l’element est présent au premier emplacement. Le nombre d'opérations dans le meilleur
des cas est constant (ne dépend pas de n).
Donc, la complexité temporelle dans le meilleur des cas serait Θ(1).
Conclusion
La plupart du temps, nous effectuons une analyse dans le pire des cas. Dans la pire
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. Dans l'analyse de cas moyen, nous devons connaître (ou prévoir) la
distribution mathématique de toutes les entrées possibles.
L'analyse meilleur de cas est fausse. 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.