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

1
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.
2
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 NP-
difficiles), 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.
3
Ces différentes approches constituent l’étape de la conception des algorithmes.
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.
Problème
facile
N
P-difficile
- améliorer la
complexité
- complexité
dans le cas
moyen - Étude de cas
particuliers
résolution exacte
- programmation
dynamique
- réduction
- diviser et régner
- branch and bound
- etc.
Résolution heuristique
- vorace
- itérative .
4
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++) // boucle de n iterations
x = x * a ; // 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.
5
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.
1 / 9 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !