Chapitre 1 informatique commune
Structures de données
linéaires
1. Complexité d’un algorithme
Analyser un algorithme revient le plus souvent à évaluer les ressources nécessaires à son exécution (la quantité
de mémoire requise) et le temps de calcul à prévoir. Bien évidemment, ces deux notions dépendent de nombreux
paramètres matériels qui sortent du domaine de l’algorithmique : nous ne pouvons attribuer une valeur absolue
ni à la quantité de mémoire requise ni au temps d’exécution d’un algorithme donné. En revanche, il est souvent
possible d’évaluer l’ordre de grandeur de ces deux quantités de manière à identifier l’algorithme le plus efficace
au sein d’un ensemble d’algorithmes résolvant le même problème.
Pour réaliser cette évaluation, il est nécessaire de préciser un modèle de la technologie employée ; en ce qui nous
concerne, il s’agira d’une machine à processeur unique pour laquelle les instructions seront exécutées l’une
après l’autre, sans opération simultanées. Il faudra aussi préciser les instructions élémentaires disponibles ainsi
que leurs coûts. Ceci est particulièrement important lorsqu’on utilise un langage de programmation tel que
python pour illustrer ce cours car ce langage possède de nombreuses instructions de haut niveau qu’il serait
irréaliste de considérer comme ayant un coût constant : par exemple, la fonction
sort
permet effectivement de
trier un tableau en une instruction, mais il serait illusoire de croire que son temps d’exécution est indépendant
de la taille du tableau. En outre, pour évaluer cette dépendance il n’y a guère d’autre solution que de se plonger
dans le code source de python ou sa documentation ; lorsque nous étudierons les algorithmes de tri il sera plus
sage de ne pas tenir compte de l’existence de cette instruction.
1.1 Instructions élémentaires
Les instructions élémentaires (et qui seront considérées comme ayant un coût constant) sont présentes dans la
plupart des langages de programmation :
– opérations arithmétiques (addition, soustraction, multiplication, division, modulo, partie entière, .. .)
– comparaisons de données (relation d’égalité, d’infériorité, . . .)
– transferts de données (lecture et écriture dans un emplacement mémoire)
–
instructions de contrôle (branchement conditionnel et inconditionnel, appel à une fonction auxiliaire, . . .)
mais là encore il est parfois nécessaire de préciser la portée de certaines de ces instructions. En arithmétique
par exemple, il est impératif que les données représentant les nombres soient codées sur un nombre fixe de
bits. C’est le cas en général des nombres flottants (la classe
float
) et des entiers relatifs (la classe
int
) représentés
usuellement sur 64 bits
1
, mais dans certains langages existe aussi un type entier long dans lequel les entiers ne
sont pas limités en taille. C’est le cas en python, où coexistaient jusqu’à la version 3.0 du langage une classe
int
et une classe
long
. Ces deux classes ont depuis fusionné, le passage du type
int
au type
long
étant désormais
transparent pour l’utilisateur.
Dans le cas des nombres entiers, l’exponentiation peut aussi être source de discussion : s’agit-t’il d’une opé-
ration de coût constant ? En général on répond à cette question par la négative : le calcul de
nk
nécessite un
nombre d’opérations élémentaires (essentiellement des multiplications) qui dépend de k. Cependant, certains
processeurs possèdent une instruction permettant de décaler de
k
bits vers la gauche la représentation binaire
d’un entier, autrement dit de calculer 2ken coût constant.
Les comparaisons entre nombres (du moment que ceux-ci sont codés sur un nombre fixe de bits) seront aussi
considérées comme des opérations à coût constant, de même que la comparaison entre deux caractères. En
revanche, la comparaison entre deux chaînes de caractères ne pourra être considérée comme une opération
élémentaire, même s’il est possible de la réaliser en une seule instruction python. Il en sera de même des
opérations d’affectation : lire ou modifier le contenu d’un case d’un tableau est une opération élémentaire, mais
ce n’est plus le cas s’il s’agit de recopier tout ou partie d’un tableau dans un autre, même si la technique du
slicing en python permet de réaliser très simplement ce type d’opération.
1. Voir cours de première année.
Jean-Pierre Becirspahic