Une vue d`ensemble sur la conception et l`analyse des algorithmes

publicité
Une vue d’ensemble sur la conception et
l’analyse des algorithmes
Ce qui va suivre est juste un bref apperçu des questions que nous allons aborder dans ce
cours.
1 Une brève introduction à la notion d’algorithme et d’espace mémoire
L’objectif initial de l’informatique est de fournir des algorithmes permettant de résoudre un
problème donné.
•
Algorithme : ensemble de règles opératoires dont l’application permet de résoudre le
problème au moyen d’un nombre fini d’opérations.
→ problème majeur à prendre en considération et le temps d’exécution
des traitements à minimiser
•
Espace mémoire : taille des données utilisées dans le traitement et la représentation du
problème.
→ problème majeur à résoudre est l’espace mémoire occupé à minimiser.
Il est clair que les notions de traitements et d’espace mémoire sont liés. Ces deux critères
doivent servir de guide au choix d'une strcuture de données.
2 Approche intuitive de la complexité
Exemple de problème: le voyageur de commerce.
Ce voyageur doit trouver le chemin le plus court pour visiter tous ses clients, localisés chacun
dans une ville différente, et en passant une et une seule fois par chaque ville. On peut imaginer
un algorithme naïf :
1. on envisage tous les chemins possibles,
2. on calcule la longueur pour chacun d'eux,
3. on conserve celui donnant la plus petite longueur.
Cette méthode « brute » conduit à calculer un nombre de chemin atronomique (ce nombre est
«exponentiel») par rapport au nombre de villes. Il existe des algoritmes plus « fins » permettant
de réduire le nombre de chemins à calculer et l’espace mémoire utilisé. Cependant, on ne
connaît pas jusqu’à présent d'algorithme exact dont la la complexité temporelle est «
raisonnable ».
Pour les problèmes qui sont aussi «difficile», on cherche des méthodes approchées, appelées
heuristiques.
1
3. Méthodologie de résolution pour résoudre un problème donné
la démarche suivie, pour résoudre un problème à l’une procédure algorithmique, peut être
résumée comme suit:
• Pour résoudre un problème, plusieurs solutions peuvent être mises à notre disposition. Il
est alors intéressant d’évaluer le temps et/ou l’espace requis pour exécuter l’algorithme
correspondant à la stratégie utilisée. Cette étape est celle de l’analyse des algorithmes.
• Dans le cas où aucune solution n’est dispoible, ou alors qu’on éprouve le besoin d’avoir
une nouvelle solution que celles dont on dispose, la question qui peut alors se poser est
tout simplement de savoir comment on peut en concevoir une autre.
Il est clair qu’il n’existe pas de recette pour résoudre un problème donné. Toutefois, des
approches générales existent telles que la méthode vorace, diviser et régner,
programation dynamique, la réduction, etc. Généralement, ces méthodes, quand elles
sont utilisées, aboutissent souvent à des solutions. Dans ce cas de figure, il est souhaitable
que la nouvelle solution soit plus performante que les solutions déjà existantes. Bien
entendu, parmi les critères de performance, figurent le temps et l’espace mémoire. Si,
maintenant, on est satisfait de la solution existante, il serait intéressant de savoir si le
changement d’organisation des données peut améliorer ces performances.
• Il est clair qu’on ne peut pas améliorer indéfinément une solution. Il existe un point où
cette amiloration s’arrête. Autrement dit, il est intéressant de savoir si la solution dont on
dispose est optimale. On entend généralement par optimale, toute solution dont le temps
d’exécution est minimum. Cette question est intimement liée à celle de la borne inférieure:
déterminer la borne inférieure dun probème revient à démontrer qu’il ne pourrait exister
d’algorithme dont le temps d’’exécution est inférieur à cette borne.
• Théoriquement (du moins), le temps d’exécution d’expression polynomiale, en fonction
de la taille des données du problème du problème, est considérés meilleurs que celui qui
ne l’est pas. Il peut se trouver que, pour un problème donné (les problèmes dit NPdifficiles), toutes les solutions connues jusqu’à date ont des temps d’exécution non
polynomiaux. Le problème dans ce cas est de savoir si cela dû à notre incapacité de trouver
une solution polynomiale ou alors que le problème est intriséquement difficile à résoudre.
Ce genre de question est traité par la théorie de la complexité.
• Si le problème est montré qu’il dans la classe des problème dit «difficles», ceci signifie
qu’il exsite pue d’espoir de trouver une solution polynomiale. Cela ne doit pas nous
empêcher d’essayer de trouver une solution au problème en question. Deux approches de
résolution sont entreprises:
1. approche exacte: dans le cas où l’on souhaite r.soudre d’une manière exacte le
problème considéré, des technqiues comme la méthode branch $ bound sont souvent
tuilisées. Il est utile de rappeler que les temps d’exécution des ces méthodes devient de
plus en plus prohibitif à mesure que les données deviennent de plus en plus grandes.
2. approche heuristique: dans le cas où on désire se contenter d’une solution approchée,
alors des méthode heuristiques telles que les méthodes vorace et les méthodes itératives
(recuit simulé, recherche taboue, etc) sont utilisées. Une étude expérimentale est
généralement effectuée pour étudier la performance de algorithmes. Remarquons que
pour les algorithmes dit voraces, une méthode mathématique est en général effectuée.
En effet, pour ces algorithmes, on calcule en fait la distance qui séparent la valeur de la
solution qu’elles génèrent par rapport à celle de la solution optimale. Ce calcul est fait
généralement dans le pire cas, c’est-à-dire, on calcule la distance maximale. Toutefois,
dans certains cas, le calcul est aussi dans le cas moyen.
2
Ces différentes approches constituent l’étape de la conception des algorithmes.
Problème
facile
-
améliorer la
complexité
complexité
dans le cas
moyen
NP-difficile
-
Étude de cas
particuliers
résolution exacte
Résolution heuristique
- programmation
- vorace
dynamique
- itérative .
- réduction
- diviser et régner
- branch and bound
- etc.
4 Complexité en temps (et mémoire)
Si l’on souhaite comparer les performances d’algorithmes, on peut considérer une mesure
basée sur leur temps d’exécution. Cette mesure est appelée la complexité en temps de
l’algorithme.
On utilise la notion qui traite de l’ordre de grandeur du nombre d’opérations effectuées par un
algorithme donné.
→ on utilise la notation « O » qui donne une majoration de l’ordre de grandeur du nombre
d’opérations.
Pour déterminer cette majoration, il faut
•
connaître la taille n de la donnée en entrée du problème
(ex. nombre de données à traiter, le degré d’un polynôme, taille d’un fichier, le codage
d’un entier, le nombre de sommets d’un graphe, etc. )
•
déterminer les opérations fondamentales qui interviennent dans ces algorithmes et qui
sont telles que les temps d'exécution seront directement proportionnels au nombre de
ces opérations.
3
Exemple : calculer la puissance n-ième d’un entier (n étant positif)
en C :
int puissance (int a, int n){
int i, x ;
x=1;
for (i = 0; i < n; i++)
x=x*a;
// boucle de n iterations
// opération fondamentale de multiplication
return x ;
}
La complexité de cet algorithme est en O(n), appelée complexité linéaire.
Remarque 1 : les performances de la machine n’interviennent pas directement dans l’ordre de
grandeur de la complexité.
Remarque 2 : la théorie de la complexité a pour but de donner un contenu formel à la notion
intuitive de difficulté de résolution d’un problème.
Type de complexité algorithmique
On considère un algorithme dont le temps d’exécution pour une donnée de taille n en entrée est
noté T(n). Chercher la complexité dans le pire cas revient à determiner la situation la plus
défavorable. On peut aussi déterminer la complexité dans le cas moyen. On en reparlera un peu
plus en détails dans le prochain chapitre. Ci-dessous quelques complexités qu’on retrouve dans
la litérature.
•
T(n) = O(1), temps constant : temps d’exécution indépendant de la taille des données à
traiter.
•
T(n) = O(log(n)), temps logarithmique : on rencontre généralement une telle complexité
lorsque l’algorithme casse un gros problème en plusieurs petits, de sorte que la
résolution de l’ensemble de ces petits problèmes conduit à la solution du problème
initial.
•
T(n) = O(n), temps linéaire : cette complexité est généralement obtenue lorsqu’un
travail en temps constant est effectué sur chaque donnée en entrée.
•
T(n) = O(n.log(n)) : l’algorithme scinde le problème en plusieurs sous-problèmes plus
petits qui sont résolus de manière indépendante. La résolution de l’ensemble de ces
problèmes plus petits apporte la solution du problème initial.
•
T(n) = O(n²), temps quadratique : apparaît notamment lorsque l’algorithme envisage
toutes les paires de données parmi les n entrées (ex. deux boucles imbriquées)
•
T(n) = O(2n), temps exponentiel : souvent le résultat d’une recherche implicite ou
explicite d’une solution.
4
Complexité spatiale
L'analyse de la complexité en place mémoire revient à évaluer, en fonction de la taille de la
donnée, la place mémoire nécessaire pour l'exécution de l'algorithme, en dehors de l'espace
occupé par les instructions du programme et des données.
Il s'agit donc d’obtenir le meilleur compromis entre l’espace et le temps.
4 Structure de données et complexité
Un algorithme manipule des données. Il est calir que la manière dont sont organisées ces
donées influe sur l’efficacité d’un algorithme. Ci-dessous un bref rappel sur les principales
structures de données.
Implantation contiguë de liste (tableau)
La première représentation d'un objet de type liste consiste à prendre une zone de mémoire
contiguë, et à y mettre les contenus des places successives de la liste.
On peut constater que cette représentation permet une implémentation simple :
•
complexité constante (indépendante de la longueur) des opérations d’accès : v = A[i], v
prend la valeur du i-ème élement du tableau A
•
l'insertion d'un élément à la k-ième place entraîne un déplacement de tous les éléments
situés derrière lui, donc N-k+1 déplacements.
•
suppression d'un élément situé à la k-ième place entraîne le déplacement de tous les
éléments situés derrière lui, donc N-k déplacements.
La complexité des opérations d'insertion et de suppression est donc au mieux (cas de la fin de la
liste) en θ(l), au pire (cas du début de liste) en θ(n), et en moyenne en θ(n/2).
Implantation chaînée des listes
Une liste chaînée consiste à lier entre elles des zones de mémoire, chacune d'elles contenant la
représentation d'un élément de la liste, et un pointeur vers la suivante.
5
On peut constater que cette représentation permet une implantation simple des opérations
premier, successeur, insérer, supprimer un élément : θ (l)
Par contre les accès par le rang ne peuvent plus être obtenus que par un parcours séquentiel,
donc ont une complexité au mieux (début de liste) en θ (l), au pire (fin de liste) en θ(n), en
moyenne en θ (n/2).
Remarques :
- Une liste est une structure orientée vers les traitements séquentiels.
- Les piles (LIFO) et les files (FIFO) sont des cas particuliers de liste qui ont des
représentations contiguës ou chaînées efficaces. Par exemple, les fichiers séquentiels sont une
certaine forme de liste.
Structures arborescente
Les structures arborescentes sont les structures de données les plus importantes en
informatique.
La notion d'arbre est une notion utilisée dans la vie courante, ailleurs qu'en informatique : Les
résultats d'un tournoi de tennis.
Toute recherche d’un élément par comparaison à l’élément racine sera proportionnelle à la
hauteur de l’arbre. Pour certians arbres, leur hauteur, en moyenne en tou cas, est en O(log (n)).
Recherche dans une liste quelconque
L'algorithme de recherche d’un élément dans une liste quelconque a une complexité
proportionnelle au rang de l'élément recherché.
On peut en conclure que la recherche est alors au mieux en θ(l), en moyenne en θ(n/2), et au
pire en θ(n).
6
Arbres de recherche
Si on peut ordonner une liste, il est possible d’utiliser la recherche dichotomique. La recherche
est alors en θ(log2n), les adjonctions et suppressions sont en θ(n), ce qui est un frein important
à cette représentation.
Le principe même de la dichotomie permet la structuration en arbre binaire de l'ensemble des
éléments : l'élément de rang (i+j)/2 est placé à la racine, ceux qui le précèdent sont mis dans le
sous-arbre gauche, et ceux qui le suivent dans celui de droite. On répète recursivement cette
opération sur chacun des sous-arbres.
De tels arbres sont appelés arbres binaires de recherche, et ils conduisent à des opérations
simples et efficaces (complexité en temps logarithmique en moyenne, linéaire dans le pire).
Arbres H-équilibrés
Les opérations sur les arbres binaires sont d'une complexité moyenne θ(log n), mais il peut
exister des arbres pour lesquels la complexité est en θ (n) (peigne).
Il peut arriver que l'on ne puisse accepter les cas défavorables. Comme ces cas sont dus à de
grandes variations dans les longueurs des branches de l'arbre, on peut essayer d'éviter ces
variations.
Il est possible de construire des arbres de recherche tels que tous les niveaux soient complets
mais cela nécessite en général des réorganisations trop coûteuses lors des adjonctions et des
suppressions pour maintenir cette propriété.
Dans les années 1960, Adelson-Velskii et Landis ont introduit une classe d'arbres équilibrés qui
se rapprochent de cette propriété (només AVL). L'idée est que pour tout nœud d'un AVL, la
différence de hauteur entre ses sous-arbres gauche et droit est au plus de 1. La complexité de
l'adjonction est au pire égale à la hauteur de l'arbre, en terme de comparaisons ou de
modifications du déséquilibre.
Arbres balancés
Lorsque le nombre d'éléments d'un ensemble devient important, la représentation ne peut plus
être conservée en mémoire centrale.
La taille de l'espace mémoire nécessaire à la représentation d'un nœud d'un arbre binaire de
recherche est en général inférieure à la taille d'un secteur de disque.
Aussi est-on amené à mettre plusieurs nœuds par secteur ou bloc disque (groupe de secteurs
consécutifs transférés en une seule opération).
Si les nœuds de l'arbre, même H-équilibré, sont répartis n'importe comment sur ces blocs, le
parcours d'une branche de l'arbre demandera autant d'accès disque qu'il y a de nœuds sur cette
branche.
7
Ce nombre n'est pas très important, puisqu'il est en log2n, mais le temps d'accès disque étant de
l'ordre de 50 ms, ceci peut conduire à des temps de recherche dépassant la seconde.
Pour réduire le nombre d'accès disque, on peut essayer de faire en sorte que les nœuds voisins
sur l'arbre se retrouvent dans un même bloc, permettant de parcourir plusieurs nœuds sans avoir
d'accès disque.
L'autre solution est d'augmenter la taille des nœuds en mettant plus de valeurs dans un nœud.
Ceci conduit à généraliser la notion d’arbre de recherche aux arbres généraux et forêts. Un
arbre balancé est appelé B-arbre.
Comme le degré des B-arbres est borné, les opérations de recherche, adjonction et suppression
ont une complexité, en terme d'opérations de traitement d'un nœud, proportionnelle à la hauteur
des arbres.
Diminuer la hauteur de l'arbre a donc essentiellement pour but de réduire le nombre des accès
disque, dont on sait qu'ils sont près de 10 000 fois plus lents que les accès mémoire centrale.
Même si le traitement d'un nœud est en θ(m), il restera inférieur au temps d'accès disque.
B-arbre d’ordre 2 :
25
6 10 20
1234
78
13 14 15 18
30 40
22 24
26 27 28
32 35 38
41 42 45 46
Conclusion
•
Un algorithme peut avoir une complexité faible dans la mesure ceci peut se traduire par
des temps d'exécutions prohibitifs.
•
La complexité d'un algorithme est toujours relative à une ou plusieurs opérations
fondamentales qu'il faut préciser au préalable. Elle dépend de la taille des données, et
pour une taille donnée, de la configuration de ces données.
•
Les seuls algorithmes pratiquement utilisables sont ceux dont la complexité est
inférieure à n2. Entre n2 et n3 on ne peut traiter que des problèmes de taille moyenne.
Au-delà, on ne pourra traiter que des problèmes de très petite taille.
•
L'amélioration des performances des machines ne change pas fondamentalement
l'efficacité d'un algorithme.
8
Référence :
″Types de données et Algorithmes″ C. Froidevaux, M.C. Gaudel, M. Soria, Ediscience
international.
9
Téléchargement