Cours algorithmique et complexite complet

4,089 views
4,028 views

Published on

0 Comments
5 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
4,089
On SlideShare
0
From Embeds
0
Number of Embeds
13
Actions
Shares
0
Downloads
258
Comments
0
Likes
5
Embeds 0
No embeds

No notes for slide

Cours algorithmique et complexite complet

  1. 1. Algorithmique et complexité Mr. Slim Mesfar Mail: mesfarslim@yahoo.fr A.U. 2011-2012
  2. 2. Plan du cours Chap-1: Introduction & motivations Chap-2: Complexité & optimalité Chap-3: Algorithmes de tri: analyse et estimation de la complexité Chap-4: Récursivité  Différents types de récursivité  Dérécursivation d’algorithmes  Récursivité terminale et non terminale  Paradigme « diviser pour régner » Chap-5: Graphes et arbres Chap-6: Arbres binaires de recherche
  3. 3. Objectifs du cours Elaborer des algorithmes performants et efficaces Comprendre la notion de complexité d’un algorithme Maîtriser la récursivité (simple, multiple, mutuelle, imbriquée) Savoir dérécursiver des algorithmes simples et multiples Maîtriser la démarche « diviser pour régner » Savoir estimer la complexité d’un algorithme itératif ou récursif pouvant conduire à des récurrences linéaires d’ordre 1, d’ordre 2 et des récurrences de type « diviser régner » Connaître les différents algorithmes de tri et estimer leur complexité Elaborer des algorithmes à base de graphes et d’arbres Réaliser des algorithmes de parcours de graphes et d’arbres
  4. 4. Chapitre 1 – Introduction et motivations
  5. 5. IntroductionUn algorithme = une suite ordonnée dopérations ou dinstruction écrites pour la résolution dun problème donné. Algorithme = une suite d’actions que devra effectuer un automate pour arriver à partir d’un état initial, en un temps fini, à un résultat L’algorithmique désigne le processus de recherche d’algorithme
  6. 6. Structures de données Une structure de données indique la manière dorganisation des données dans la mémoire. Le choix dune structure de données adéquate dépend généralement du problème à résoudre. Deux types de structures de données :  Statiques : Les données peuvent être manipulées dans la mémoire dans un espace statique alloué dès le début de résolution du problème. Ex : les tableaux  Dynamiques : On peut allouer de la mémoire pour y stocker des données au fur et à mesure des besoins de la résolution du problème. Ex: liste chainée, pile, file, …  notion des pointeurs  nécessité de la gestion des liens entre les données dun problème en mémoire.
  7. 7. Qualités d’un bon algorithme Correct: Il faut que le programme exécute correctement les tâches pour lesquelles il a été conçu Complet: Il faut que le programme considère tous les cas possibles et donne un résultat dans chaque cas. Efficace: Il faut que le programme exécute sa tâche avec efficacité c’est à dire avec un coût minimal. Le coût pour un ordinateur se mesure en termes de temps de calcul et d’espace mémoire nécessaire.
  8. 8. Exemple : Calcul de la valeur d’un polynôme Soit P(X) un polynôme de degré n P(X) = anXn + an-1Xn-1 + ... + a1X + a0 Où,  n : entier naturel  an, an-1, ..., a1, a0 : les coefficients du polynôme 1ère variante :début Coût de l’algorithme : P=0 - (n+1) additions Pour i de 0 à n faire - (n+1) multiplications - (n+1) puissances P = P+ ai*Xi finpourfin
  9. 9. Exemple : Calcul de la valeur d’un polynôme 2ème variante : Coût de l’algorithme :debut - (n+1) additions Inter=1 - 2(n+1) multiplications P =0 Pour i de 0 à N faire P = P+ Inter *ai Inter = Inter * X finpourFin
  10. 10. Exemple : Calcul de la valeur d’un polynôme 3ème variante : Schéma de HornerP(x) = (….(((anx+an-1)x+an-2)x+an-3)…..)x+a0début P = an Pour i de n-1 à 0 (pas = –1) faire P = P*X + ai Coût de l’algorithme : finpour - n additionsFin - n multiplications Nécessité d’estimer le coût d’un algorithme avant de l’écrire et l’implémenter
  11. 11. Chapitre 2 – Complexité et optimalité
  12. 12. Définitions la complexité dun algorithme est la mesure du nombre dopérations fondamentales quil effectue sur un jeu de données. La complexité est exprimée comme une fonction de la taille du jeu de données. La complexité dun algorithme est souvent déterminée à travers une description mathématique du comportement de cet algorithme.
  13. 13. Définitions On note Dn l’ensemble des données de taille n et T(d) le coût de l’algorithme sur la donnée d. On définit 3 types de complexité :  Complexité au meilleur : Cest le plus petit nombre dopérations quaura à exécuter lalgorithme sur un jeu de données de taille fixée, ici à n.  Complexité au pire : Cest le plus grand nombre dopérations quaura à exécuter lalgorithme sur un jeu de données de taille fixée, ici à n.  Complexité en moyenne : Cest la moyenne des complexités de lalgorithme sur des jeux de données de taille n.
  14. 14. Définitions Cest lanalyse pessimiste ou au pire qui est généralement adoptée. En effet, de nombreux algorithmes fonctionnent la plupart du temps dans la situation la plus mauvaise pour eux.  lanalyse au pire des cas donne une limite supérieure de la performance et elle garantit quun algorithme ne fera jamais moins bien que ce quon a établi.  Un algorithme est dit optimal si sa complexité est la complexité minimale parmi les algorithmes de sa classe. Même si on s’intéresse quasi-exclusivement à la complexité en temps des algorithmes. Il est parfois intéressant de s’intéresser à d’autres ressources, comme la complexité en espace (taille de l’espace mémoire utilisé), la largeur de bande passante requise, etc.
  15. 15. Notations mathématiques La notation O est celle qui est le plus communément utilisée pour expliquer formellement les performances dun algorithme. Cette notation exprime la limite supérieure dune fonction dans un facteur constant.  La notation O reflète la courbe ou lordre croissance dun algorithme. Les règles de la notation O sont les suivantes :  Les termes constants : O(c) = O(1)  Les constantes multiplicatives sont omises : O(cT ) = cO(T) = O(T)  Laddition est réalisée en prenant le maximum : O(T1) + O(T2) = O(T1 + T2) = max(O(T1);O(T2))  La multiplication reste inchangée mais est parfois réécrite dune façon plus compacte :O(T1)O(T2) = O(T1T2)
  16. 16. Exemple On suppose qu’on dispose dun algorithme dont le temps dexécution est décrit par la fonction T(n) = 3n2+10n+10. Lutilisation des règles de la notation O nous permet de simplifier en : O(T(n)) = O(3n2 + 10n + 10) = O(3n2) = O(n2) Pour n = 10 nous avons :  Temps dexécution de 3n2 : 3(10)2 / 3(10)2+10(10)+10 = 73,2%  Temps dexécution de 10n : 10(10) / 3(10)2+10(10)+10 = 24,4%  Temps dexécution de 10 : 10 / 3(10)2+10(10)+10 = 2,4% Le poids de 3n2 devient encore plus grand quand n = 100, soit 96,7%  on peut négliger les quantités 10n et 10. Ceci explique les règles de la notation O.
  17. 17. Classes de complexité Les algorithmes usuels peuvent être classés en un certain nombre de grandes classes de complexité. Les complexités les plus utilisées sont :  Constante : O(1) Accéder au premier élément dun ensemble de données  Logarithmique : O(logn) Couper un ensemble de données en deux parties égales, puis couper ces moitiés en deux parties égales, etc.  Linéaire : O(n) Parcourir un ensemble de données  Quasi-linéaire : O(nlogn) Couper répétitivement un ensemble de données en deux et combiner les solutions partielles pour calculer la solution générale  Quadratique : O(n2) Parcourir un ensemble de données en utilisant deux boucles imbriquées  Polynomiale : O(nP) Parcourir un ensemble de données en utilisant P boucles imbriquées  Exponentielle : O(2n) Générer tous les sous-ensembles possibles dun ensemble de données
  18. 18. Classes de complexité
  19. 19. Calcul de la complexité 1. Cas dune instruction simple : écriture, lecture, affectation Dans le cas duns suite dinstructions simples, on considère la complexité maximale. La complexité de cette séquence vaut max(O(1),O(1))=O(1).
  20. 20. Calcul de la complexité 2. Cas dun traitement conditionnel 3. Cas dun traitement itératif : Boucle Tant Que
  21. 21. Calcul de la complexité 4. Cas dun traitement itératif : Boucle PourPour i de indDeb à indFin faire TraitementFin Pour indFin ∑ O(T i =indDeb Traitement )
  22. 22. Exemples de calcul de la complexité Exemple 1 : Tri par insertion  Principe : Cette méthode de tri sapparente à celle utilisée pour trier ses cartes dans un jeu : on prend une carte, tab[1], puis la deuxième, tab[2], que lon place en fonction de la première, ensuite la troisième tab[3] que lon insère à sa place en fonction des deux premières et ainsi de suite. Le principe général est donc de considérer que les (i-1) premières cartes, tab[1],..., tab[i-1] sont triées et de placer la ie carte, tab[i], à sa place parmi les (i-1) déjà triées, et ce jusquà ce que i = N.
  23. 23. Exemples de calcul de la complexité Exemple 1 : Tri par insertion Procédure tri_Insertion (var tab : tableau entier [N]) i, k :entier ; tmp : entier ; Pour i de 2 à N faire tmp ← tab[i]; k ← i; Tant que k > 1 ET tab[k - 1] > tmp faire tab[k] ← tab[k - 1]; k ← k - 1; Fin Tant que tab[k] ← tmp; Fin pour Fin
  24. 24. Exemples de calcul de la complexitéExemple 1 : Tri par insertion Calcul de la complexité:  la taille du tableau à trier est n.  On a deux boucles imbriquées :  La première indique lélément suivant à insérer dans la partie triée du tableau.  Elle effectuera n - 1 itérations puisque le premier élément est déjà trié.  Pour chaque élément donné par la première boucle, on fait un parcourt dans la partie triée pour déterminer son emplacement.
  25. 25. Exemples de calcul de la complexitéExemple 1 : Tri par insertion Calcul de la complexité:  Au meilleur des cas : le cas le plus favorable pour cet algorithme est quand le tableau est déjà trié (de taille n)  O(n)  Au pire des cas : Le cas le plus défavorable pour cet algorithme est quand le tableau est inversement trié  on fera une itération pour le 1er élément, deux itérations pour le 2ème et ainsi de suite pour les autres éléments. Soit 1+2+3+4+…+(n-1) = n(n + 1) − n  sa complexité O(n2) 2
  26. 26. Exemples de calcul de la complexitéExemple 1 : Tri par insertion Calcul de la complexité:  En moyenne des cas : En moyenne, la moitié des éléments du tableau sont triés, et sur l’autre moitié ils sont inversement triés.  O(n2)
  27. 27. Exemples de calcul de la complexité Exemple 2 : Recherche dichotomiqueFonction RechDicho(Tab :Tableau, borneinf :entier, bornesup :entier,elemcherche :entier) : entier Trouve = false ; Tant que ((non trouve) ET (borneinf<=bornesup)) faire mil = (borneinf+bornesup) DIV 2 ; Si (Tab[mil]=elemcherche) Alors trouve=true ; Sinon Si (elemcherche < Tab[mil]) Alors bornesup = mil-1 ; Sinon borneinf = mil+1 ; Fin Si Fin Si Fin Tant que Si (trouve) Alors Retourner (mil) ; Sinon Retourner (-1) ; Fin SiFin
  28. 28. Exemples de calcul de la complexité Exemple 2 : Recherche dichotomique Cette fonction effectue une recherche dichotomique dun élément dans un tableau trié. Supposons que le tableau est de taille n une puissance de 2 (n = 2q). Le pire des cas pour la recherche dun élément est de continuer les divisions jusquà obtenir un tableau de taille 1. q le nombre ditérations nécessaires pour aboutir à un tableau de taille 1 dernière itération  taille tableau = 1  La complexité = log2(n)
  29. 29. Chapitre 3 –Les algorithmes de Tri
  30. 30. Tri par sélection Principe : Le principe est que pour classer n valeurs, il faut rechercher la plus petite valeur (resp. la plus grande) et la placer au début du tableau (resp. à la fin du tableau), puis la plus petite (resp. plus grande) valeur dans les valeurs restantes et la placer à la deuxième position (resp. en avant dernière position) et ainsi de suite...
  31. 31. Tri par sélection Algorithme :i, j: entier ;tmp, small : entier ;t : tableau entier [n] ;Début Pour i de 1 à n-1 faire small←i; Pour j de i+1 à n faire Si t[j] < t[small] alors small ←j ; Fin si Fin pour tmp←t[small];  T(n) = O(n²) t[small] ←t[i]; t[i] ← tmp; Fin pourFin
  32. 32. Tri par propagation / à bulles Principe : Il consiste à parcourir le tableau tab en permutant toute paire déléments consécutifs (tab[k],tab[k+1]) non ordonnés - ce qui est un échange et nécessite donc encore une variable intermédiaire de type entier. Après le premier parcours, le plus grand élément se retrouve dans la dernière case du tableau, en tab[N], et il reste donc à appliquer la même procédure sur le tableau composé des éléments tab[1], ..., tab[N-1].
  33. 33. Tri par propagation / à bulles Algorithme : Procédure tri_Bulle (tab : tableau entier [N] ) i, k :entier ;tmp : entier ; Pour i de N à 2 faire Pour k de 1 à i-1 faire Si (tab[k] > tab[k+1]) alors tmp ← tab[k]; tab[k] ← tab[k+1]; tab[k+1] ← tmp; Fin si Fin pour  T(n) = O(n²) Fin pourFin
  34. 34. Chapitre 4 – La récursivité
  35. 35. Définitions Un algorithme est dit récursif sil est défini en fonction de lui-même. La récursion est un principe puissant permettant de définir une entité à laide dune partie de celle-ci.  Chaque appel successif travaille sur un ensemble dentrées toujours plus affinée, en se rapprochant de plus en plus de la solution dun problème.
  36. 36. Evolution d’un appel récursif Lexécution dun appel récursif passe par deux phases, la phase de descente et la phase de la remontée :  Dans la phase de descente, chaque appel récursif fait à son tour un appel récursif. Cette phase se termine lorsque lun des appels atteint une condition terminale.  condition pour laquelle la fonction doit retourner une valeur au lieu de faire un autre appel récursif.  Ensuite, on commence la phase de la remontée. Cette phase se poursuit jusquà ce que lappel initial soit terminé, ce qui termine le processus récursif.
  37. 37. Les types de récursivité 1/ La récursivité simple :  récursivité simple  la fonction contient un seul appel récursif dans son corps.  Exemple : la fonction factorielle
  38. 38. Les types de récursivité  Trace d’exécution de la fonction factorielle (calcul de la valeur de 4!)
  39. 39. Les types de récursivité 2/ La récursivité multiple:  récursivité multiple  la fonction contient plus dun appel récursif dans son corps  Exemple : le calcul du nombre de combinaisons en se servant de la relation de Pascal :
  40. 40. Les types de récursivité 3/ La récursivité mutuelle:  Des fonctions sont dites mutuellement récursives si elles dépendent les unes des autres  Par exemple la définition de la parité dun entier peut être écrite de la manière suivante :
  41. 41. Les types de récursivité 4/ La récursivité imbriquée:  Exemple : La fonction dAckermann
  42. 42. Récursivité terminale vs. non terminale Une fonction récursive est dite récursive terminale si tous ses appels sont récursifs terminaux. Un appel récursif est terminal sil sagit de la dernière instruction exécutée dans le corps dune fonction et que sa valeur de retour ne fait pas partie dune expression. Les fonctions récursives terminales sont caractérisées par le fait quelles nont rien à faire pendant la phase de remontée
  43. 43. Importance de l’ordre des appels récursifs Proc. terminale Proc. non terminaleProcédure AfficherGaucheDroite ( Procédure AfficherDroiteGauche ( Tab : Tableau entier, N : entier, Tab : Tableau entier, N : entier, i : entier) i : entier) Si (i<=N) Alors Si (i<=N) Alors Ecrire(Tab[i]) ; AfficherDroiteGauche (Tab,N,i+1) ; AfficherGaucheDroite (Tab,N,i+1) ; Ecrire(Tab[i]) ; Fin Si Fin SiFin Fin l’ordre des appels récursifs affecte la terminaison d’unefonction récursive
  44. 44. Importance de l’ordre des appels récursifs
  45. 45. Elimination de la récursivité Dérécursiver, c’est transformer un algorithme récursif en un algorithme équivalent ne contenant pas des appels récursifs. Elimination de la récursivité terminale simple  Rappel : Un algorithme est dit récursif terminal s’il ne contient aucun traitement après un appel récursif.  La récursivité terminale simple peut être remplacée par une solution itérative.
  46. 46. Elimination de la récursivité terminalesimple Algo. récursif Algo. itératifProcédure ALGOR(X) Procédure ALGOI(X) Si (COND) Alors Tant que (COND) faire TRAIT1 TRAIT1 ALGOR(β (X)) X  β (X) Sinon Fin tant que TRAIT2 TRAIT2 Fin Si FinFin•X est la liste des paramètres ;• COND est une condition portant sur X ;• TRAIT1 est le traitement de base de lalgorithme (dépendant de X) ;• β(X) représente la transformation des paramètres ;• TRAIT2 est le traitement de terminaison (dépendant de X).
  47. 47. Application : a est diviseur de b ? Algo. récursif Algo. itératifFonction Diviseur (a,b) : Bool Fonction Diviseur (a,b) : BoolSi (a <=0) Alors Si (a <=0) Alors Retourner(Faux) Retourner(Faux)Sinon Sinon Si (a>=b) Retourner (a=b) Tant que (a<b) Faire Sinon b  b-a Retourner (Diviseur (a,b-a)) Fin tant que Fin Si Retourner (a=b)Fin Si Fin SiFin Fin
  48. 48. Elimination de la récursivité nonterminale simple Dans un algorithme récursif non terminal, l’appel récursif est suivi d’un traitement  il reste un traitement à reprendre après l’appel récursif Il va falloir donc sauvegarder, sur une pile, le contexte de l’appel récursif, typiquement les paramètres de l’appel engendrant l’appel récursif.  La récursivité non terminale simple peut être remplacée par une solution itérative utilisant une pile.
  49. 49. Elimination de la récursivité non terminalesimple Algo. récursif Algo. itératifProcédure ALGOR(X) Procédure ALGOI(X) Si (COND) Alors Pile.init() TRAIT1 Tant que (COND) Faire ALGOR(β (X)) TRAIT1 TRAIT2 Pile.empiler(X) Sinon X  β (X) TRAIT3 Fin Tant que Fin Si TRAIT3Fin Tant que (Non_vide_pile()) Faire Pile.dépiler(U) TRAIT2 Fin Tant que Fin
  50. 50. Elimination de la récursivité non terminalesimple Algo. récursif Algo. itératifProcédure Procédure ALGOI(X) AfficherDroiteGauche ( Tab Pile.init() : Tableau entier, N : Tant que (i<=N) Faire entier, i : entier) /* TRAIT1 */ Si (i<=N) Alors Pile.empiler(Tab[i]) AfficherDroiteGauche i  i+1 (Tab,N,i+1) ; Ecrire(Tab[i]) ; Fin Tant que Fin Si /* TRAIT3 */Fin Tant que (Non_vide_pile()) FaireTRAIT1 = Ø Ecrire(Pile.dépiler() )TRAIT2 = Ecrire(Tab[i]) /* TRAIT2 */TRAIT3 = Ø Fin Tant que Fin
  51. 51. Exemple : Tours de Hanoi Problème : Le jeu est constitué d’une plaquette de bois où sont plantées trois tiges numérotées 1, 2 et 3. Sur ces tiges sont empilés des disques de diamètres tous différents. Les seules règles du jeu sont que l’on ne peut déplacer qu’un seul disque à la fois, et qu’il est interdit de poser un disque sur un disque plus petit. Au début, tous les disques sont sur la tige 1 (celle de gauche), et à la fin ils doivent être sur celle de droite.
  52. 52. Exemple : Tours de Hanoi Résolution: On suppose que l’on sait résoudre le problème pour (n-1) disques. Pour déplacer n disques de la tige 1 vers la tige 3, on déplace les (n-1) plus petits disques de la tige 1 vers la tige 2, puis on déplace le plus gros disque de la tige 1 vers la tige 3, puis on déplace les (n-1) plus petits disques de la tige 2 vers la tige 3.
  53. 53. Exemple : Tours de Hanoi AlgorithmeProcédure Hanoi (n, départ, intermédiaire, destination) Si n > 0 Alors Hanoi (n-1, départ, destination, intermédiaire) déplacer un disque de départ vers destination Hanoi (n-1, intermédiaire, départ, destination) Fin SiFin
  54. 54. Exemple : Tours de Hanoi Trace d’exécution pour n=3L’appel à Hanoi(3,1,2,3) entraîne l’affichage de :1. Déplace un disque de la tige 1 vers la tige 32. Déplace un disque de la tige 1 vers la tige 23. Déplace un disque de la tige 3 vers la tige 24. Déplace un disque de la tige 1 vers la tige 35. Déplace un disque de la tige 2 vers la tige 16. Déplace un disque de la tige 2 vers la tige 37. Déplace un disque de la tige 1 vers la tige 3
  55. 55. Exemple : Tours de Hanoi Calcul de la complexité : On compte le nombre de déplacements de disques effectués par l’algorithme Hanoi invoqué sur n disques. On trouve :  T(n) = T(n-1) + 1 + T(n-1)  T(n) = 2T(n-1) + 1  T(n) = 2n – 1  Complexité exponentielle
  56. 56. Paradigme « diviser pour régner » De nombreux algorithmes ont une structure récursive: pour résoudre un problème donné, ils s’appellent eux-mêmes récursivement une ou plusieurs fois sur des problèmes très similaires, mais de tailles moindres, résolvent les sous problèmes de manière récursive puis combinent les résultats pour trouver une solution au problème initial. Le paradigme « diviser pour régner » parcourt trois étapes à chaque appel récursif à savoir :  Diviser : le problème en un certain nombre de sous- problèmes de taille moindre ;  Régner : sur les sous-problèmes en les résolvant dune façon récursive ou le résoudre directement si la taille dun sous- problème est assez réduite ;  Combiner : les solutions des sous-problèmes en une solution globale pour le problème initial.
  57. 57. Exemple 1 Recherche de l’indice du maximum dans un tableau d’entiersFonction maximum ( Tab , indDeb, indFin)Si ( indDeb = indFin) alors retourner (indDeb)Sinon m=(indDeb+indFin)/2 // division du problème en 2 sous-problèmes k1 = maximum (Tab, indDeb, m ) // régner sur le 1er sous-problème k2 = maximum (Tab, m+1, indFin)// régner sur le 2ème sous-problème Si(Tab[k1] > Tab[k2]) Alors // combiner les solutions retourner (k1) Sinon retourner (k2)  T(n) = 2 T(n/2) + cte FinSiFinSiFin
  58. 58. Exemple2 : multiplication de matrices carrées Dans cet exemple, on se propose de multiplier 2 matrices carrées A et B de taille n * n chacune, où n est une puissance exacte de 2. C est la matrice résultante. Si on décompose les matrices A, B et C en sous- matrices de taille n/2 * n/2, léquation C = AB peut alors se réécrire : Le développement de cette équation donne : r = ae+bf ; s = ag+bh; t = ce+df et u = cg+dh
  59. 59. Exemple2 : multiplication de matrices carrées Chacune de ces quatre opérations correspond à :  deux multiplications de matrices carrées de taille n/2  2T(n/2)  et une addition de telles matrices n2/4 A partir de ces équations on peut dériver un algorithme « diviser pour régner » dont la complexité est donnée par la récurrence :  T(n) = 8T(n/2)+O(n2)
  60. 60. Analyse des algorithmes « Diviser pour Régner » On peut souvent donner une relation de récurrence qui décrit le temps dexécution d’un algorithme « diviser pour régner » en fonction des temps dexécution des appels récursifs résolvant les sous-problèmes associés de taille moindre. Cette récurrence se décompose suivant les trois étapes du paradigme de base :  Si la taille du problème est suffisamment réduite, n ≤ c pour une certaine constante c, la résolution est directe et consomme un temps constant O(1).  Sinon, on divise le problème en a sous-problèmes chacun de taille 1/b de la taille du problème initial. Le temps dexécution total se décompose alors en trois parties :  D(n) : le temps nécessaire à la division du problème en sous- problèmes.  aT (n/b) : le temps de résolution des a sous-problèmes.  C(n) : le temps nécessaire pour construire la solution finale à partir des solutions aux sous-problèmes.
  61. 61. Analyse des algorithmes « Diviser pour Régner » La relation de récurrence prend alors la forme : Soit la fonction f (n) la fonction qui regroupe D(n) et C(n). La fonction T(n) est alors définie : T(n) = a.T(n / b) + f (n) T (n) = a.T (n / b) + c.nk
  62. 62. Résolution des récurrence des algorithmes« Diviser pour Régner » Théorème de résolution de la récurrence :  si a > bk  T(n) = O(nlogb a )  si a = bk  T(n) = O(nk logbn)  si a < bk  T(n) = O( f (n)) = O(nk ) Résolution de la relation de récurrence pour l’exemple de la multiplication de matrices :  T(n) = 8 T(n/2) + O(n2)  a = 8 , b = 2, k = 2  a > bk  Logba = 3  T(n) = O(n3)
  63. 63. Analyse des algorithmes « Diviser pour Régner » Complexité de l’algorithme de recherche du maximum: T(n) = 2 T(n/2) + 3  a = 2 , b = 2, k = 0  a > bk  Logba = 1  T(n) = O(n)
  64. 64. Application : algorithme de recherche dichotomiqueFonction RechDicho(Tab :Tableau, borneinf :entier, bornesup :entier,elem :entier) : bool Si (borneinf<=bornesup) alors mil = (borneinf+bornesup) DIV 2 ; Si (Tab[mil]=elem) Alors retourner (vrai) Sinon Si (Tab[mil]>elem) Alors Retourner (RechDicho(Tab, borneinf, mil-1, elem)) Sinon Retourner(RechDicho(Tab, mil+1, bornesup, elem)) Fin Si Fin Si Sinon Retourner (Faux) FinSi
  65. 65. Application : algorithme de recherche dichotomique Analyse de la complexité :  T(n) = T(n/2) + cte  a = 1 , b = 2, k = 0  a = bk  a = bk  T(n) = O(nk logbn)  T(n) = O(log2n)
  66. 66. Exemples d’application n Exemple 1 : T (n) = 9T   + n  a = 9 , b = 3 , k = 1 3  a > bk  Logba = 2  T(n) = O(n²)  2n  Exemple 2 : T ( n) = T   + 1  3   a = 1 , b = 3/2 , k = 0  a = bk  T(n) = O(nklogn) = O(logn)
  67. 67. Exemples d’application n Exemple 3 : T (n) = 3T   + n log n  a = 3 , b = 4 , k = ?? 4 or n < nlogn < n² 1 < k < 2  4 < bk < 16  a < bk  T(n) = O(f(n)) = O(n logn)
  68. 68. Autres résolutions de récurrence Equations de récurrence linéaires:  n f (i )  T (n) = aT (n − 1) + f (n ) T ( n ) = a  T ( 0) + ∑ i  n  i =1 a  Exemple : Les Tours de Hanoi  n 1 T(n) = 2 T(n-1) + 1  T ( n) = 2  0 + ∑ i  = 2 − 1 n n  i =1 2 
  69. 69. Autres résolutions de récurrence Equations de récurrence linéaires sans second membre (f(n) = cte) T (n) − a1T (n − 1) − a2T (n − 2 ) − ... − ak T (n − k ) = cte A une telle équation, on peut associer un polynôme: P ( x) = x k − a x k −1 − a x k − 2 − ... − a 1 2 k La résolution de ce polynôme nous donne m racines ri ( avec m<=k). La solution de l’équation de récurrence est ainsi donnée par : T (n) = c1r1 + c2 r2 + c3 r3 + ... + c r n n n n m m Cette solution est en général exponentielle
  70. 70. Autres résolutions de récurrence Exemple : La suite de Fibonacci T(n) = T(n-1) + T(n-2) On pose P(x) = X² - X – 1  r = 1 + 5 et r = 1 − 5 1 2 2 2  1 + 5 n 1− 5  n T (n) = a r1n + b r2n = a    2  +b   2          1 + 5 n   T (n) = Ο     2     
  71. 71. Suite du chapitre 3 –Les algorithmes de Tri
  72. 72. Tri par fusion Principe : Le principe du tri par fusion est plutôt simple. On dit que trier un tableau de taille N, cest trier deux tableaux de taille N/2; une fois les deux tableaux triés on n’a plus quà les réunir (les fusionner) de sorte à ce que le tableau final soit trié. Ce tri bien sûr utilise une notion de récursivité (un tableau étant la somme de deux tableaux).
  73. 73. Tri par fusion Algorithme : Fonction tri_fusion (T, deb, fin) : tableau entier T1, T2 : tableau entier [N/2] ; Si (deb >= fin) alors Retourner T ; Sinon mil = (deb + fin) DIV 2; T1 = tri_fusion (T, deb, mil) ; T2 = tri_fusion (T, mil+1, fin)) ; Retourner fusion (T1, T2) ; Fin siFIN  T(n) = 2 T(n/2) + Tfusion(n)
  74. 74. Tri par fusionFonction fusion (T1, T2) : tableau entier T1 : tableau entier [1...N] ; T2 : tableau entier [1...M] ; T: tableau entier [1...M+N] ; i, j: entier; i←1 ;j←1 ; Tantque (i+j-1 <> N+M) faire Si (i ≤ N) alors si (j ≤ M) alors si (T1[i] < T2[j]) alors T[i+j-1]←T1[i] ; i←i+1 ; sinon T[i+j-1]←T2[j] ; j←j+1 ; Fin si sinon T[i+j-1]←T1[i]; i←i+1; Fin si sinon T[i+j-1]←T2[j] ; j←j+1 ; Fin si FinTanque Retourner T ;FIN  Tfusion(n) = O(n)
  75. 75. Tri par fusion L’algorithme Tri_Fusion est de type « diviser pour régner ». Il faut donc étudier ses trois phases: Diviser : cette étape se réduit au calcul du milieu de l’intervalle [deb,fin], sa complexité est donc en O(1). Régner : l’algorithme résout récursivement deux sous-problèmes de tailles respectives (n/2) , d’où une complexité en 2T(n/2). Combiner : la complexité de cette étape est celle de l’algorithme de fusion qui est de O(n) pour la construction d’un tableau solution de taille n.
  76. 76. Tri par fusion T(n) = 2 T(n/2) + O(n) Rappel : Théorème de résolution de la récurrence T(n) = a T(n/b) + O(nk):  si a > bk  T(n) = O(nlogb a )  si a = bk  T(n) = O(nk logbn)  si a < bk  T(n) = O( f (n)) = O(nk )a = 2, b = 2, k = 1 (2ème cas) T(n) = O(n log2n)
  77. 77. Tri rapide (Quicksort) Principe : Le tri rapide est fondé sur le paradigme « diviser pour régner», tout comme le tri par fusion, il se décompose donc en trois étapes : Diviser : Le tableau T[deb..fin] est partitionné (et réarrangé) en deux sous-tableaux non vides, T[deb..inter] et T[inter+1..fin] tels que chaque élément de T[deb..fin] soit inférieur ou égal à chaque élément de T[inter+1..fin]. L’indice inter est calculé pendant la procédure de partitionnement. Régner : Les deux sous-tableaux T[deb..inter] et T[inter+1..fin] sont triés par des appels récursifs. Combiner : Comme les sous-tableaux sont triés sur place, aucun travail n’est nécessaire pour les recombiner, le tableau T[deb..fin] est déjà trié !
  78. 78. Tri rapideTri_Rapide (T, deb, fin)Si (deb < fin ) alors inter =Partionner (T, deb, fin) Tri_Rapide (T, deb, inter) Tri_Rapide (T, inter+1, fin)Fin siPartionner (T, deb, fin)x = T(deb)i = deb-1 ; j= fin+1Tant que (1)Répéter { j=j-1 } Jusqu’à T(j) <= xRépéter { i =i+1 } Jusqu’à T(i) >= xsi ( i < j )permuter (T(i), T(j))sinon retourner j Fin SiFin
  79. 79. Tri rapide : calcul de la complexité Pire cas Le cas pire intervient quand le partitionnement produit une région à n-1 éléments et une à 1 élément. Comme le partitionnement coûte O(n) et que T(1) = O(1), la récurrence pour le temps d’exécution est : T(n) = T(n-1) +O(n) et par sommation on obtient : T(n) = O(n²) Meilleur cas : Le meilleur cas intervient quand le partitionnement produit deux régions de longueur n/2. La récurrence est alors définie par : T(n) = 2T(n / 2) + O(n) ce qui donne d’après le théorème de résolution des récurrences : T(n) = O(nlog n)
  80. 80. Chapitre 5 –Graphes et arbres
  81. 81. Les graphes Un graphe orienté G est représenté par un couple (S, A) où S est un ensemble fini et A une relation binaire sur S. L’ensemble S est l’ensemble des sommets de G et A est l’ensemble des arcs de G. Il existe deux types de graphes :  graphe orienté : les relations sont orientées et on parle d’arc. Un arc est représenté par un couple de sommets ordonnés.  Graphe non orienté : les relations ne sont pas orientées et on parle alors d’arêtes. Une arête est représentée par une paire de sommets non ordonnés.
  82. 82. Les graphes Une boucle est un arc qui relie un sommet à lui-même. Dans un graphe non orienté les boucles sont interdites et chaque arête est donc constituée de deux sommets distincts. Degré d’un sommet : Dans un graphe non orienté, le degré d’un sommet est le nombre d’arêtes qui lui sont incidentes. Si un sommet est de degré 0, il est dit isolé. Degré sortant d’un sommet : Dans un graphe orienté, le degré sortant d’un sommet est le nombre d’arcs qui en partent, Degré rentrant d’un sommet : le degré entrant est le nombre d’arcs qui y arrivent et le degré est la somme du degré entrant et du degré sortant. Chemin : Dans un graphe orienté G = (S,A), un chemin de longueur k d’un sommet u à un sommet v est une séquence (u0,u1,…, uk) de sommets telle que u = u0, v = uk et (ui-1, ui) appartient à A pour tout i. Un chemin est élémentaire si ses sommets sont tous distincts
  83. 83. Les graphes Un sous-chemin p0 d’un chemin p = (u0,u1, …. ,uk) est une sous- séquence contiguë de ses sommets. Autrement dit, il existe i et j, 0<=i<= j <=k, tels que p0 = (ui,ui+1, …. ,uj). Circuit : Dans un graphe orienté G=(S,A), un chemin (u0,u1, …. ,uk) forme un circuit si u0 =uk et si le chemin contient au moins un arc. Ce circuit est élémentaire si les sommets u0, ..., uk sont distincts. Une boucle est un circuit de longueur 1. Cycle : Dans un graphe non orienté G = (S,A), une chaîne (u0,u1,…., uk) forme un cycle si k >= 2 et si u0 = uk. Ce cycle est élémentaire si les sommets u0, ..., uk sont distincts. Un graphe sans cycle est dit acyclique. Sous-graphe : On dit qu’un graphe G0 = (S0,A0) est un sous- graphe de G = (S,A) si S0 est inclus dans S et si A0 est inclus dans A.
  84. 84. Les arbres Propriétés des arbres : Soit G = (S,A) un graphe non orienté. Les affirmations suivantes sont équivalentes.  1. G est un arbre.  2. Deux sommets quelconques de G sont reliés par un unique chemin élémentaire.  3. G est acyclique et |A| = |S| - 1  4. G est acyclique, mais si une arête quelconque est ajoutée à A, le graphe résultant contient un cycle.
  85. 85. Arbres – définitions Arbre enraciné (ou arborescence): C’est un arbre dans lequel l’un des sommets se distingue des autres. On appelle ce sommet la racine. Ce sommet particulier impose en réalité un sens de parcours de l’arbre Ancêtre : Soit x un noeud (ou sommet) d’un arbre A de racine r. Un noeud quelconque y sur l’unique chemin allant de r à x est appelé ancêtre de x. Père et fils : Si (y,x) est un arc alors y est le père de x et x est le fils de y. La racine est le seul noeud qui n’a pas de père. Feuille ou noeud externe (ou terminal) : Une feuille est un noeud sans fils. Un noeud qui n’est pas une feuille est un noeud interne. Sous-arbre : Le sous-arbre de racine x est l’arbre composé des descendants de x, enraciné en x.
  86. 86. Arbres - définitions Degré d’un nœud : Le nombre de fils du nœud x est appelé le degré de x. Profondeur d’un nœud : La longueur du chemin entre la racine r et le nœud x est la profondeur de x. Profondeur de l’arbre : c’est la plus grande profondeur que peut avoir un nœud quelconque de l’arbre. Elle est dite aussi la hauteur de l’arbre. Arbre binaire : c’est un arbre dont chaque nœud a au plus deux fils. Arbre binaire complet : Dans un arbre binaire complet chaque nœud est soit une feuille, soit de degré deux. Aucun nœud n’est donc de degré 1.
  87. 87. Parcours des arbres Parcours en profondeur Dans un parcours en profondeur, on descend d’abord le plus profondément possible dans l’arbre puis, une fois qu’une feuille a été atteinte, on remonte pour explorer les autres branches en commençant par la branche « la plus basse » parmi celles non encore parcourues. Les fils d’un nœud sont bien évidemment parcourus suivant l’ordre sur l’arbre. Algorithme: Algorithme ParPro(A) si A n’est pas réduit à une feuille alors Pour tous les fils u de racine(A) Faire ParPro(u) Fin pour finSi Fin
  88. 88. Parcours des arbres Parcours en largeur Dans un parcours en largeur, tous les nœuds à une profondeur i doivent avoir été visités avant que le premier nœud à la profondeur i+1 ne soit visité. Un tel parcours nécessite l’utilisation d’une file d’attente pour se souvenir des branches qui restent à visiter. Algorithme: Algorithme Parcours_Largeur(A) F : File d’attente F.enfiler(racine(A)) Tant que F != vide Faire u=F.défiler() Afficher (u) Pour « chaque fils v de » u Faire F.enfiler (v) FinPour Fin Tant que Fin
  89. 89. Parcours des graphes Le parcours des graphes est un peu plus compliqué que celui des arbres. En effet, les graphes peuvent contenir des cycles et il faut éviter de parcourir indéfiniment ces cycles. Pour cela, il suffit de colorier les sommets du graphe.  Initialement les sommets sont tous blancs,  lorsqu’un sommet est rencontré pour la première fois il est peint en gris,  lorsque tous ses successeurs dans l’ordre de parcours ont été visités, il est repeint en noir.
  90. 90. Parcours des graphesAlgorithme Pacours_Profondeur (G) Algorithme VisiterPP(G, s) Pour chaque sommet u de G Faire couleur[s]=Gris couleur[u]=Blanc Pour chaque voisin v de s Faire FinPour Si couleur[v] = Blanc alors Pour chaque sommet u de G Faire VisiterPP(G, v) si couleur[u] = Blanc alors FinSi VisiterPP(G, u) FinPour FinSi couleur[s]=Noir FinPourFin Fin
  91. 91. Parcours des graphesAlgorithme Parcours_Largeur(G, s) F : File d’attente Pour chaque sommet u de G Faire couleur[u] = Blanc FinPour couleur[s]=Gris F.enfiler(s) Tant que F != Vide Faire u=F.défiler() Pour chaque voisin v de u Faire Si couleur(v) = Blanc alors couleur(v)= Gris F.enfiler(v) FinPour Couleur(u)= NoirFinTant que
  92. 92. Chapitre 6 –Arbres binaires de recherche
  93. 93. Définitions Un arbre binaire est un graphe qui admet une racine et sans cycle et dont chaque nœud admet deux fils : fils droit et fils gauche. Structure de données :Enregistrement Nœud{ Info : Type (entier, réel, chaine, …) FilsG : ^ Nœud FilsD : ^ Nœud}Racine : ^Nœud Il existe 3 méthodes de parcours d’un arbre binaire :  parcours préfixe : père, fils gauche, fils droit  parcours infixe : fils gauche, père, fils droit  parcours postfixe : fils gauche, fils droit, père
  94. 94. Parcours préfixéAlgorithme Préfixe(racine : ^Nœud)Si (racine != Nil) Alors AfficheRacine(racine) Préfixe (racine^.FilsG) Préfixe (racine^.FilsD)FinSiFin
  95. 95. Parcours préfixé utilisant une pile Le programme suivant est une version dérécursivée utilisant une pile explicite et permettant le parcours préfixé d’un arbre binaire.Algorithme Préfixe (racine : ^Nœud) P : pile Empiler (P, racine) Tant que (Non_Vide(P)) racine = depiler (P) Empiler (P,racine^.FilsD) Empiler (P,racine^.FilsG) Fin Tant queFin
  96. 96. Parcours infixéAlgorithme infixe(racine : ^Nœud)Si (racine != Nil) Alors infixe (racine^.FilsG) AfficheRacine(racine) infixe (racine^.FilsD)FinSiFin
  97. 97. Parcours postfixéAlgorithme Postfixe(racine : ^Nœud)Si (racine != Nil) Alors Postfixe (racine^.FilsG) Postfixe (racine^.FilsD) AfficheRacine(racine)FinSiFin
  98. 98. Arbre binaire de recherche Un arbre binaire de recherche est un arbre binaire dans lequel chaque nœud est supérieur à son fils gauche et inférieur à son fils droit et il n’y a pas de nœuds égaux. Un arbre binaire de recherche est intéressant puisqu’il est toujours possible de connaître dans quelle branche de l’arbre se trouve un élément et de proche en proche le localiser dans l’arbre. On peut aussi utiliser un arbre binaire de recherche pour ordonner une liste d’éléments.
  99. 99. Recherche dans un arbre binaire de rechercheAlgorithme Chercher (racine : ^Nœud , X : élément) Si ( racine = Nil) alors retourner 0 Sinon Si( racine^.info = X ) alors retourner 1 Else Si (X < racine^.info ) alors retourner Chercher(racine^.FilsG, X) Else retourner Chercher (racine^.FilsD, X) Finsi FinSi FinSiFin
  100. 100. Insertion dans un arbre binaire de recherche L’élément à ajouter est inséré là où on l’aurait trouvé s’il avait été présent dans l’arbre. L’algorithme d’insertion recherche donc l’élément dans l’arbre et, quand il aboutit à la conclusion que l’élément n’appartient pas à l’arbre (il aboutit à la terre), il insère l’élément comme fils du dernier nœud visité.Algorithme Insérer (racine : ^Nœud, X : élément ) Si (racine = nil) alors « ajouter un nœud pour X à cet endroit» Sinon Si (racine^.info = X) Ecrire ("l’élément à insérer existe déjà dans l’arbre") Sinon Si (X> racine^.info) Insérer (racine^.FD, X) Sinon Insérer (racine^.FG, X)Fin
  101. 101. Suppression dans un arbre binaire de recherche 1er cas : l’élément à supprimer n’a pas de fils  il est terminal et il suffit de le supprimer
  102. 102. Suppression dans un arbre binaire de recherche 2ème cas : l’élément a un fils unique  on supprime le nœud et on relie son fils à son père
  103. 103. Suppression dans un arbre binaire de recherche 3ème cas : l’élément à supprimer a deux fils  on le remplace par son successeur qui est toujours le minimum de ses descendants droits.
  104. 104. Merci pour votre attention !

×