SlideShare une entreprise Scribd logo
1  sur  104
Télécharger pour lire hors ligne
Algorithmique et
   complexité
       Mr. Slim Mesfar

  Mail: mesfarslim@yahoo.fr




       A.U. 2011-2012
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
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
Chapitre 1 – Introduction
     et motivations
Introduction
Un algorithme = une suite ordonnée d'opérations
 ou d'instruction écrites pour la résolution d'un
 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
Structures de données
   Une structure de données indique la manière
    d'organisation des données dans la mémoire.
   Le choix d'une 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 d'un problème en mémoire.
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.
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
    finpour
fin
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
      finpour
Fin
Exemple : Calcul de la valeur d’un polynôme
   3ème variante : Schéma de Horner

P(x) = (….(((anx+an-1)x+an-2)x+an-3)…..)x+a0

début
   P = an
   Pour i de n-1 à 0 (pas = –1) faire
        P = P*X + ai
                                        Coût de l’algorithme :
   finpour
                                        - n additions
Fin                                     - n multiplications

 Nécessité d’estimer le coût d’un algorithme avant de l’écrire
  et l’implémenter
Chapitre 2 – Complexité
     et optimalité
Définitions
   la complexité d'un algorithme est la mesure du
    nombre d'opérations fondamentales qu'il 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é d'un algorithme est souvent
    déterminée à travers une description
    mathématique du comportement de cet
    algorithme.
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 :
        C'est le plus petit nombre d'opérations qu'aura à exécuter l'algorithme
        sur un jeu de données de taille fixée, ici à n.
       Complexité au pire :
        C'est le plus grand nombre d'opérations qu'aura à exécuter
        l'algorithme sur un jeu de données de taille fixée, ici à n.
       Complexité en moyenne :

        C'est la moyenne des complexités de l'algorithme sur des jeux de
        données de taille n.
Définitions
   C'est l'analyse 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.
     l'analyse au pire des cas donne une limite supérieure de
    la performance et elle garantit qu'un algorithme ne fera
    jamais moins bien que ce qu'on 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.
Notations mathématiques
   La notation O est celle qui est le plus communément
    utilisée pour expliquer formellement les performances d'un
    algorithme.
   Cette notation exprime la limite supérieure d'une fonction
    dans un facteur constant.

     La notation O reflète la courbe ou l'ordre croissance d'un
    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)
       L'addition 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 d'une façon
        plus compacte :O(T1)O(T2) = O(T1T2)
Exemple
   On suppose qu’on dispose d'un algorithme dont le temps
    d'exécution est décrit par la fonction T(n) = 3n2+10n+10.
    L'utilisation 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 d'exécution de 3n2 : 3(10)2 / 3(10)2+10(10)+10 = 73,2%
       Temps d'exécution de 10n : 10(10) / 3(10)2+10(10)+10 = 24,4%
       Temps d'exé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.
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 d'un 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
        d'un ensemble de données
Classes de complexité
Calcul de la complexité
   1. Cas d'une instruction simple : écriture, lecture,
    affectation
    Dans le cas d'uns suite d'instructions simples, on considère la
    complexité maximale.




    La complexité de cette séquence vaut max(O(1),O(1))=O(1).
Calcul de la complexité
   2. Cas d'un traitement conditionnel




   3. Cas d'un traitement itératif : Boucle Tant Que
Calcul de la complexité
   4. Cas d'un traitement itératif : Boucle Pour

Pour i de indDeb à indFin faire
     Traitement
Fin Pour
        indFin

         ∑ O(T
       i =indDeb
                   Traitement   )
Exemples de calcul de la complexité
   Exemple 1 : Tri par insertion
       Principe : Cette méthode de tri s'apparente à
        celle utilisée pour trier ses cartes dans un jeu :
        on prend une carte, tab[1], puis la deuxième,
        tab[2], que l'on place en fonction de la
        première, ensuite la troisième tab[3] que l'on
        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.
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
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.
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
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)
Exemples de calcul de la complexité
   Exemple 2 : Recherche dichotomique
Fonction 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 Si
Fin
Exemples de calcul de la complexité
   Exemple 2 : Recherche dichotomique
   Cette fonction effectue une recherche dichotomique d'un
    é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 d'un élément est de
    continuer les divisions jusqu'à obtenir un tableau de taille 1.
   q le nombre d'itérations nécessaires pour aboutir à un
    tableau de taille 1


                        dernière itération  taille tableau = 1




                                    La complexité = log2(n)
Chapitre 3 –
Les algorithmes de Tri
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...
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 pour
Fin
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].
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 pour
Fin
Chapitre 4 – La récursivité
Définitions
   Un algorithme est dit récursif s'il est défini en
    fonction de lui-même.
   La récursion est un principe puissant permettant de
    définir une entité à l'aide d'une partie de celle-ci.
     Chaque appel successif travaille sur un ensemble
    d'entrées toujours plus affinée, en se rapprochant
    de plus en plus de la solution d'un problème.
Evolution d’un appel récursif
   L'exécution d'un 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 l'un 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 l'appel initial soit
        terminé, ce qui termine le processus récursif.
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
Les types de récursivité
     Trace d’exécution de la fonction factorielle (calcul de la
      valeur de 4!)
Les types de récursivité
 2/ La récursivité multiple:
     récursivité multiple  la fonction contient plus d'un
      appel récursif dans son corps
     Exemple : le calcul du nombre de combinaisons en se
      servant de la relation de Pascal :
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é d'un entier peut
      être écrite de la manière suivante :
Les types de récursivité
 4/ La récursivité imbriquée:
     Exemple : La fonction d'Ackermann
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 s'il s'agit de la
    dernière instruction exécutée dans le corps d'une
    fonction et que sa valeur de retour ne fait pas
    partie d'une expression.
   Les    fonctions   récursives     terminales    sont
    caractérisées par le fait qu'elles n'ont rien à faire
    pendant la phase de remontée
Importance de l’ordre des appels récursifs
         Proc. terminale                     Proc. non terminale
Procé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 Si
Fin                                        Fin

 l’ordre des appels récursifs affecte la terminaison d’une
fonction récursive
Importance de l’ordre des appels récursifs
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.
Elimination de la récursivité terminale
simple
      Algo. récursif                       Algo. itératif
Procé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                          Fin
Fin
•X est la liste des paramètres ;
• COND est une condition portant sur X ;
• TRAIT1 est le traitement de base de l'algorithme (dépendant de X) ;
• β(X) représente la transformation des paramètres ;
• TRAIT2 est le traitement de terminaison (dépendant de X).
Application : a est diviseur de b ?
       Algo. récursif                   Algo. itératif
Fonction Diviseur (a,b) : Bool    Fonction Diviseur (a,b) : Bool
Si (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 Si
Fin                               Fin
Elimination de la récursivité non
terminale 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.
Elimination de la récursivité non terminale
simple
     Algo. récursif          Algo. itératif
Procé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                 TRAIT3
Fin                       Tant que (Non_vide_pile())
                          Faire
                               Pile.dépiler(U)
                               TRAIT2
                          Fin Tant que
                       Fin
Elimination de la récursivité non terminale
simple
     Algo. récursif                   Algo. itératif
Procé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())
                                   Faire
TRAIT1 = Ø
                                        Ecrire(Pile.dépiler() )
TRAIT2 = Ecrire(Tab[i])
                                          /* TRAIT2 */
TRAIT3 = Ø
                                   Fin Tant que
                                Fin
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.
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.
Exemple : Tours de Hanoi
 Algorithme
Procé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 Si
Fin
Exemple : Tours de Hanoi
 Trace d’exécution pour n=3
L’appel à Hanoi(3,1,2,3) entraîne l’affichage de :
1. Déplace un disque de la tige 1 vers la tige 3
2. Déplace un disque de la tige 1 vers la tige 2
3. Déplace un disque de la tige 3 vers la tige 2
4. Déplace un disque de la tige 1 vers la tige 3
5. Déplace un disque de la tige 2 vers la tige 1
6. Déplace un disque de la tige 2 vers la tige 3
7. Déplace un disque de la tige 1 vers la tige 3
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
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 d'une façon
        récursive ou le résoudre directement si la taille d'un sous-
        problème est assez réduite ;
       Combiner : les solutions des sous-problèmes en une solution
        globale pour le problème initial.
Exemple 1
   Recherche de l’indice du maximum dans un tableau d’entiers
Fonction 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
    FinSi
FinSi
Fin
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
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)
Analyse des algorithmes « Diviser pour Régner »
   On peut souvent donner une relation de récurrence qui décrit
    le temps d'exécution d’un algorithme « diviser pour régner »
    en fonction des temps d'exé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 d'exé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.
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
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)
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)
Application : algorithme de recherche dichotomique
Fonction 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
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)
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)
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)
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 
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
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  
                               
Suite du chapitre 3 –
Les algorithmes de Tri
Tri par fusion
 Principe :
 Le principe du tri par fusion est plutôt
  simple. On dit que trier un tableau de
  taille N, c'est 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).
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 si
FIN
                          T(n) = 2 T(n/2) + Tfusion(n)
Tri par fusion
Fonction 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)
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.
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)
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é !
Tri rapide
Tri_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 si
Partionner (T, deb, fin)
x = T(deb)
i = deb-1 ; j= fin+1
Tant que (1)
Répéter { j=j-1 } Jusqu’à T(j) <= x
Répéter { i =i+1 } Jusqu’à T(i) >= x
si ( i < j )
permuter (T(i), T(j))
sinon retourner j Fin Si
Fin
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)
Chapitre 5 –
Graphes et arbres
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.
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
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.
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.
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.
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.
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
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
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.
Parcours des graphes
Algorithme 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
    FinPour
Fin                                    Fin
Parcours des graphes
Algorithme 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)= Noir
FinTant que
Chapitre 6 –
Arbres binaires de
   recherche
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
Parcours préfixé
Algorithme Préfixe(racine : ^Nœud)

Si (racine != Nil) Alors
  AfficheRacine(racine)
  Préfixe (racine^.FilsG)
  Préfixe (racine^.FilsD)
FinSi
Fin
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 que
Fin
Parcours infixé
Algorithme infixe(racine : ^Nœud)

Si (racine != Nil) Alors
  infixe (racine^.FilsG)
  AfficheRacine(racine)
  infixe (racine^.FilsD)
FinSi
Fin
Parcours postfixé
Algorithme Postfixe(racine : ^Nœud)

Si (racine != Nil) Alors
  Postfixe (racine^.FilsG)
  Postfixe (racine^.FilsD)
  AfficheRacine(racine)
FinSi
Fin
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.
Recherche dans un arbre binaire de recherche
Algorithme 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
    FinSi
Fin
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
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
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
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.
Merci pour votre attention !

Contenu connexe

Tendances

Examen principal - Algorithme & Structures de données
Examen principal - Algorithme & Structures de donnéesExamen principal - Algorithme & Structures de données
Examen principal - Algorithme & Structures de donnéesInes Ouaz
 
Cours algorithmique et complexite complet
Cours algorithmique et complexite completCours algorithmique et complexite complet
Cours algorithmique et complexite completChahrawoods Dmz
 
Examen principal - Fondement Multimedia - correction
Examen principal - Fondement Multimedia - correctionExamen principal - Fondement Multimedia - correction
Examen principal - Fondement Multimedia - correctionInes Ouaz
 
Chapitre ii complexité et optimalité
Chapitre ii complexité et optimalitéChapitre ii complexité et optimalité
Chapitre ii complexité et optimalitéSana Aroussi
 
Travaux dirigés 1: algorithme & structures de données (corrigés)
Travaux dirigés 1: algorithme & structures de données (corrigés)Travaux dirigés 1: algorithme & structures de données (corrigés)
Travaux dirigés 1: algorithme & structures de données (corrigés)Ines Ouaz
 
Chapitre iii récursivité et paradigme diviser pour régner
Chapitre iii récursivité et paradigme diviser pour régnerChapitre iii récursivité et paradigme diviser pour régner
Chapitre iii récursivité et paradigme diviser pour régnerSana Aroussi
 
Les arbres de décisions
Les arbres de décisionsLes arbres de décisions
Les arbres de décisionsMariem Chaaben
 
Chapitre 1 arbres de recherche
Chapitre 1 arbres de rechercheChapitre 1 arbres de recherche
Chapitre 1 arbres de rechercheSana Aroussi
 
Chapitre 4 heuristiques et méta heuristiques
Chapitre 4 heuristiques et méta heuristiquesChapitre 4 heuristiques et méta heuristiques
Chapitre 4 heuristiques et méta heuristiquesSana Aroussi
 
Chapitre i introduction et motivations
Chapitre i introduction et motivationsChapitre i introduction et motivations
Chapitre i introduction et motivationsSana Aroussi
 
Curriculum d'informatique aux Troncs Communs, fondements et choix.
Curriculum d'informatique aux Troncs Communs, fondements et choix.Curriculum d'informatique aux Troncs Communs, fondements et choix.
Curriculum d'informatique aux Troncs Communs, fondements et choix.Haddi Abderrahim
 
Cours Programmation Orientée Objet en C++
Cours Programmation Orientée Objet en C++Cours Programmation Orientée Objet en C++
Cours Programmation Orientée Objet en C++Amina HAMEURLAINE
 
Chapitre 2 -Complexité des problèmes avec correction.pdf
Chapitre 2 -Complexité des problèmes avec correction.pdfChapitre 2 -Complexité des problèmes avec correction.pdf
Chapitre 2 -Complexité des problèmes avec correction.pdfMbarkiIsraa
 
Chapitre 4-Apprentissage non supervisé (1) (1).pdf
Chapitre 4-Apprentissage non supervisé (1) (1).pdfChapitre 4-Apprentissage non supervisé (1) (1).pdf
Chapitre 4-Apprentissage non supervisé (1) (1).pdfZizoAziz
 
Exercice arbre de décision
Exercice arbre de décision Exercice arbre de décision
Exercice arbre de décision Yassine Badri
 

Tendances (20)

Examen principal - Algorithme & Structures de données
Examen principal - Algorithme & Structures de donnéesExamen principal - Algorithme & Structures de données
Examen principal - Algorithme & Structures de données
 
Cours algorithmique et complexite complet
Cours algorithmique et complexite completCours algorithmique et complexite complet
Cours algorithmique et complexite complet
 
Examen principal - Fondement Multimedia - correction
Examen principal - Fondement Multimedia - correctionExamen principal - Fondement Multimedia - correction
Examen principal - Fondement Multimedia - correction
 
Chapitre ii complexité et optimalité
Chapitre ii complexité et optimalitéChapitre ii complexité et optimalité
Chapitre ii complexité et optimalité
 
Knn
KnnKnn
Knn
 
Travaux dirigés 1: algorithme & structures de données (corrigés)
Travaux dirigés 1: algorithme & structures de données (corrigés)Travaux dirigés 1: algorithme & structures de données (corrigés)
Travaux dirigés 1: algorithme & structures de données (corrigés)
 
Animations tris
Animations trisAnimations tris
Animations tris
 
Algorithmes de tri
Algorithmes de triAlgorithmes de tri
Algorithmes de tri
 
Chapitre iii récursivité et paradigme diviser pour régner
Chapitre iii récursivité et paradigme diviser pour régnerChapitre iii récursivité et paradigme diviser pour régner
Chapitre iii récursivité et paradigme diviser pour régner
 
Les arbres de décisions
Les arbres de décisionsLes arbres de décisions
Les arbres de décisions
 
Chapitre 1 arbres de recherche
Chapitre 1 arbres de rechercheChapitre 1 arbres de recherche
Chapitre 1 arbres de recherche
 
Chapitre 4 heuristiques et méta heuristiques
Chapitre 4 heuristiques et méta heuristiquesChapitre 4 heuristiques et méta heuristiques
Chapitre 4 heuristiques et méta heuristiques
 
Chapitre i introduction et motivations
Chapitre i introduction et motivationsChapitre i introduction et motivations
Chapitre i introduction et motivations
 
Traitement du signal
Traitement du signalTraitement du signal
Traitement du signal
 
Curriculum d'informatique aux Troncs Communs, fondements et choix.
Curriculum d'informatique aux Troncs Communs, fondements et choix.Curriculum d'informatique aux Troncs Communs, fondements et choix.
Curriculum d'informatique aux Troncs Communs, fondements et choix.
 
Cours Programmation Orientée Objet en C++
Cours Programmation Orientée Objet en C++Cours Programmation Orientée Objet en C++
Cours Programmation Orientée Objet en C++
 
Chapitre 2 -Complexité des problèmes avec correction.pdf
Chapitre 2 -Complexité des problèmes avec correction.pdfChapitre 2 -Complexité des problèmes avec correction.pdf
Chapitre 2 -Complexité des problèmes avec correction.pdf
 
Chapitre 4-Apprentissage non supervisé (1) (1).pdf
Chapitre 4-Apprentissage non supervisé (1) (1).pdfChapitre 4-Apprentissage non supervisé (1) (1).pdf
Chapitre 4-Apprentissage non supervisé (1) (1).pdf
 
Exercice arbre de décision
Exercice arbre de décision Exercice arbre de décision
Exercice arbre de décision
 
Chapitre 1 rappel
Chapitre 1 rappelChapitre 1 rappel
Chapitre 1 rappel
 

En vedette

Algorithmique
AlgorithmiqueAlgorithmique
Algorithmiqueelharraj
 
INF220 - Algo DUT SRC1 - Cours 1 - 2013
INF220 - Algo DUT SRC1 - Cours 1 - 2013INF220 - Algo DUT SRC1 - Cours 1 - 2013
INF220 - Algo DUT SRC1 - Cours 1 - 2013PGambette
 
INF120 - Algo DUT SRC1 - Cours 3
INF120 - Algo DUT SRC1 - Cours 3INF120 - Algo DUT SRC1 - Cours 3
INF120 - Algo DUT SRC1 - Cours 3PGambette
 
Ch1 Algorthmique Avancée - Rappel & Notions de Base
Ch1 Algorthmique Avancée - Rappel & Notions de BaseCh1 Algorthmique Avancée - Rappel & Notions de Base
Ch1 Algorthmique Avancée - Rappel & Notions de Baselotfibenromdhane
 
INF220 - Algo DUT SRC1 - Cours 1
INF220 - Algo DUT SRC1 - Cours 1INF220 - Algo DUT SRC1 - Cours 1
INF220 - Algo DUT SRC1 - Cours 1PGambette
 

En vedette (9)

Algorithmique
AlgorithmiqueAlgorithmique
Algorithmique
 
INF220 - Algo DUT SRC1 - Cours 1 - 2013
INF220 - Algo DUT SRC1 - Cours 1 - 2013INF220 - Algo DUT SRC1 - Cours 1 - 2013
INF220 - Algo DUT SRC1 - Cours 1 - 2013
 
algorithmique
algorithmiquealgorithmique
algorithmique
 
Algorithmique
AlgorithmiqueAlgorithmique
Algorithmique
 
Chapitre 1 rappel
Chapitre 1   rappelChapitre 1   rappel
Chapitre 1 rappel
 
INF120 - Algo DUT SRC1 - Cours 3
INF120 - Algo DUT SRC1 - Cours 3INF120 - Algo DUT SRC1 - Cours 3
INF120 - Algo DUT SRC1 - Cours 3
 
Ch1 Algorthmique Avancée - Rappel & Notions de Base
Ch1 Algorthmique Avancée - Rappel & Notions de BaseCh1 Algorthmique Avancée - Rappel & Notions de Base
Ch1 Algorthmique Avancée - Rappel & Notions de Base
 
Dc 1
Dc 1Dc 1
Dc 1
 
INF220 - Algo DUT SRC1 - Cours 1
INF220 - Algo DUT SRC1 - Cours 1INF220 - Algo DUT SRC1 - Cours 1
INF220 - Algo DUT SRC1 - Cours 1
 

Similaire à Cours algorithmique et complexite complet

la complexité des algorithmes en toute simplicité
la complexité des algorithmes en toute simplicitéla complexité des algorithmes en toute simplicité
la complexité des algorithmes en toute simplicitéSana REFAI
 
Présentation Finale - Partie I.pptx
Présentation Finale - Partie I.pptxPrésentation Finale - Partie I.pptx
Présentation Finale - Partie I.pptxouassityoussef
 
1 analyse-et-mesure-des-performances
1 analyse-et-mesure-des-performances1 analyse-et-mesure-des-performances
1 analyse-et-mesure-des-performancesm.a bensaaoud
 
algo et complexité .pptx
algo et complexité  .pptxalgo et complexité  .pptx
algo et complexité .pptxtarekjedidi
 
Chapitre 3 _Conception et analyse d’algorithme-DPR.pdf
Chapitre 3 _Conception et analyse d’algorithme-DPR.pdfChapitre 3 _Conception et analyse d’algorithme-DPR.pdf
Chapitre 3 _Conception et analyse d’algorithme-DPR.pdfMbarkiIsraa
 
Chap5 La manipulation des iterables en python
Chap5 La manipulation des iterables en pythonChap5 La manipulation des iterables en python
Chap5 La manipulation des iterables en pythonMariem ZAOUALI
 
Cours_3_0910_2.pdf
Cours_3_0910_2.pdfCours_3_0910_2.pdf
Cours_3_0910_2.pdfSongSonfack
 
Cours - TC - Histoire Algorithmique.pdf
Cours - TC - Histoire Algorithmique.pdfCours - TC - Histoire Algorithmique.pdf
Cours - TC - Histoire Algorithmique.pdfadeljaouadi
 
Algorithmique seconde (corrigés et commentaires)
Algorithmique seconde (corrigés et commentaires)Algorithmique seconde (corrigés et commentaires)
Algorithmique seconde (corrigés et commentaires)DriNox NordisTe
 
Traitement des données massives (INF442, A2)
Traitement des données massives (INF442, A2)Traitement des données massives (INF442, A2)
Traitement des données massives (INF442, A2)Frank Nielsen
 
Complexité_ENSI_2011.ppt
Complexité_ENSI_2011.pptComplexité_ENSI_2011.ppt
Complexité_ENSI_2011.pptMbarkiIsraa
 

Similaire à Cours algorithmique et complexite complet (20)

la complexité des algorithmes en toute simplicité
la complexité des algorithmes en toute simplicitéla complexité des algorithmes en toute simplicité
la complexité des algorithmes en toute simplicité
 
Présentation Finale - Partie I.pptx
Présentation Finale - Partie I.pptxPrésentation Finale - Partie I.pptx
Présentation Finale - Partie I.pptx
 
cours algorithme
cours algorithmecours algorithme
cours algorithme
 
1 analyse-et-mesure-des-performances
1 analyse-et-mesure-des-performances1 analyse-et-mesure-des-performances
1 analyse-et-mesure-des-performances
 
algo et complexité .pptx
algo et complexité  .pptxalgo et complexité  .pptx
algo et complexité .pptx
 
Rapport Projet Module Complexité
Rapport Projet Module ComplexitéRapport Projet Module Complexité
Rapport Projet Module Complexité
 
TAD (1).pptx
TAD (1).pptxTAD (1).pptx
TAD (1).pptx
 
langage C++
langage C++langage C++
langage C++
 
Chapitre 3 _Conception et analyse d’algorithme-DPR.pdf
Chapitre 3 _Conception et analyse d’algorithme-DPR.pdfChapitre 3 _Conception et analyse d’algorithme-DPR.pdf
Chapitre 3 _Conception et analyse d’algorithme-DPR.pdf
 
Chap5 La manipulation des iterables en python
Chap5 La manipulation des iterables en pythonChap5 La manipulation des iterables en python
Chap5 La manipulation des iterables en python
 
Cours_3_0910.pdf
Cours_3_0910.pdfCours_3_0910.pdf
Cours_3_0910.pdf
 
Cours_3_0910_2.pdf
Cours_3_0910_2.pdfCours_3_0910_2.pdf
Cours_3_0910_2.pdf
 
algo-imsi-2.pdf
algo-imsi-2.pdfalgo-imsi-2.pdf
algo-imsi-2.pdf
 
Cours - TC - Histoire Algorithmique.pdf
Cours - TC - Histoire Algorithmique.pdfCours - TC - Histoire Algorithmique.pdf
Cours - TC - Histoire Algorithmique.pdf
 
Rapport MOGPL
Rapport MOGPLRapport MOGPL
Rapport MOGPL
 
Mathématiques et Python
Mathématiques et PythonMathématiques et Python
Mathématiques et Python
 
Algorithmique seconde (corrigés et commentaires)
Algorithmique seconde (corrigés et commentaires)Algorithmique seconde (corrigés et commentaires)
Algorithmique seconde (corrigés et commentaires)
 
COURS_PYTHON_22.ppt
COURS_PYTHON_22.pptCOURS_PYTHON_22.ppt
COURS_PYTHON_22.ppt
 
Traitement des données massives (INF442, A2)
Traitement des données massives (INF442, A2)Traitement des données massives (INF442, A2)
Traitement des données massives (INF442, A2)
 
Complexité_ENSI_2011.ppt
Complexité_ENSI_2011.pptComplexité_ENSI_2011.ppt
Complexité_ENSI_2011.ppt
 

Cours algorithmique et complexite complet

  • 1. Algorithmique et complexité Mr. Slim Mesfar Mail: mesfarslim@yahoo.fr A.U. 2011-2012
  • 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. 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. Chapitre 1 – Introduction et motivations
  • 5. Introduction Un algorithme = une suite ordonnée d'opérations ou d'instruction écrites pour la résolution d'un 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. Structures de données  Une structure de données indique la manière d'organisation des données dans la mémoire.  Le choix d'une 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 d'un problème en mémoire.
  • 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. 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 finpour fin
  • 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 finpour Fin
  • 10. Exemple : Calcul de la valeur d’un polynôme  3ème variante : Schéma de Horner P(x) = (….(((anx+an-1)x+an-2)x+an-3)…..)x+a0 début P = an Pour i de n-1 à 0 (pas = –1) faire P = P*X + ai Coût de l’algorithme : finpour - n additions Fin - n multiplications  Nécessité d’estimer le coût d’un algorithme avant de l’écrire et l’implémenter
  • 11. Chapitre 2 – Complexité et optimalité
  • 12. Définitions  la complexité d'un algorithme est la mesure du nombre d'opérations fondamentales qu'il 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é d'un algorithme est souvent déterminée à travers une description mathématique du comportement de cet algorithme.
  • 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 : C'est le plus petit nombre d'opérations qu'aura à exécuter l'algorithme sur un jeu de données de taille fixée, ici à n.  Complexité au pire : C'est le plus grand nombre d'opérations qu'aura à exécuter l'algorithme sur un jeu de données de taille fixée, ici à n.  Complexité en moyenne : C'est la moyenne des complexités de l'algorithme sur des jeux de données de taille n.
  • 14. Définitions  C'est l'analyse 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.  l'analyse au pire des cas donne une limite supérieure de la performance et elle garantit qu'un algorithme ne fera jamais moins bien que ce qu'on 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. Notations mathématiques  La notation O est celle qui est le plus communément utilisée pour expliquer formellement les performances d'un algorithme.  Cette notation exprime la limite supérieure d'une fonction dans un facteur constant.  La notation O reflète la courbe ou l'ordre croissance d'un 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)  L'addition 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 d'une façon plus compacte :O(T1)O(T2) = O(T1T2)
  • 16. Exemple  On suppose qu’on dispose d'un algorithme dont le temps d'exécution est décrit par la fonction T(n) = 3n2+10n+10. L'utilisation 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 d'exécution de 3n2 : 3(10)2 / 3(10)2+10(10)+10 = 73,2%  Temps d'exécution de 10n : 10(10) / 3(10)2+10(10)+10 = 24,4%  Temps d'exé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. 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 d'un 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 d'un ensemble de données
  • 19. Calcul de la complexité  1. Cas d'une instruction simple : écriture, lecture, affectation Dans le cas d'uns suite d'instructions simples, on considère la complexité maximale. La complexité de cette séquence vaut max(O(1),O(1))=O(1).
  • 20. Calcul de la complexité  2. Cas d'un traitement conditionnel  3. Cas d'un traitement itératif : Boucle Tant Que
  • 21. Calcul de la complexité  4. Cas d'un traitement itératif : Boucle Pour Pour i de indDeb à indFin faire Traitement Fin Pour indFin ∑ O(T i =indDeb Traitement )
  • 22. Exemples de calcul de la complexité  Exemple 1 : Tri par insertion  Principe : Cette méthode de tri s'apparente à celle utilisée pour trier ses cartes dans un jeu : on prend une carte, tab[1], puis la deuxième, tab[2], que l'on place en fonction de la première, ensuite la troisième tab[3] que l'on 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. 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. 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. 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. 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. Exemples de calcul de la complexité  Exemple 2 : Recherche dichotomique Fonction 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 Si Fin
  • 28. Exemples de calcul de la complexité  Exemple 2 : Recherche dichotomique  Cette fonction effectue une recherche dichotomique d'un é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 d'un élément est de continuer les divisions jusqu'à obtenir un tableau de taille 1.  q le nombre d'itérations nécessaires pour aboutir à un tableau de taille 1 dernière itération  taille tableau = 1  La complexité = log2(n)
  • 29. Chapitre 3 – Les algorithmes de Tri
  • 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. 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 pour Fin
  • 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. 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 pour Fin
  • 34. Chapitre 4 – La récursivité
  • 35. Définitions  Un algorithme est dit récursif s'il est défini en fonction de lui-même.  La récursion est un principe puissant permettant de définir une entité à l'aide d'une partie de celle-ci.  Chaque appel successif travaille sur un ensemble d'entrées toujours plus affinée, en se rapprochant de plus en plus de la solution d'un problème.
  • 36. Evolution d’un appel récursif  L'exécution d'un 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 l'un 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 l'appel initial soit terminé, ce qui termine le processus récursif.
  • 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. Les types de récursivité  Trace d’exécution de la fonction factorielle (calcul de la valeur de 4!)
  • 39. Les types de récursivité 2/ La récursivité multiple:  récursivité multiple  la fonction contient plus d'un appel récursif dans son corps  Exemple : le calcul du nombre de combinaisons en se servant de la relation de Pascal :
  • 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é d'un entier peut être écrite de la manière suivante :
  • 41. Les types de récursivité 4/ La récursivité imbriquée:  Exemple : La fonction d'Ackermann
  • 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 s'il s'agit de la dernière instruction exécutée dans le corps d'une fonction et que sa valeur de retour ne fait pas partie d'une expression.  Les fonctions récursives terminales sont caractérisées par le fait qu'elles n'ont rien à faire pendant la phase de remontée
  • 43. Importance de l’ordre des appels récursifs Proc. terminale Proc. non terminale Procé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 Si Fin Fin  l’ordre des appels récursifs affecte la terminaison d’une fonction récursive
  • 44. Importance de l’ordre des appels récursifs
  • 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. Elimination de la récursivité terminale simple Algo. récursif Algo. itératif Procé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 Fin Fin •X est la liste des paramètres ; • COND est une condition portant sur X ; • TRAIT1 est le traitement de base de l'algorithme (dépendant de X) ; • β(X) représente la transformation des paramètres ; • TRAIT2 est le traitement de terminaison (dépendant de X).
  • 47. Application : a est diviseur de b ? Algo. récursif Algo. itératif Fonction Diviseur (a,b) : Bool Fonction Diviseur (a,b) : Bool Si (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 Si Fin Fin
  • 48. Elimination de la récursivité non terminale 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. Elimination de la récursivité non terminale simple Algo. récursif Algo. itératif Procé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 TRAIT3 Fin Tant que (Non_vide_pile()) Faire Pile.dépiler(U) TRAIT2 Fin Tant que Fin
  • 50. Elimination de la récursivité non terminale simple Algo. récursif Algo. itératif Procé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()) Faire TRAIT1 = Ø Ecrire(Pile.dépiler() ) TRAIT2 = Ecrire(Tab[i]) /* TRAIT2 */ TRAIT3 = Ø Fin Tant que Fin
  • 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. 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. Exemple : Tours de Hanoi  Algorithme Procé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 Si Fin
  • 54. Exemple : Tours de Hanoi  Trace d’exécution pour n=3 L’appel à Hanoi(3,1,2,3) entraîne l’affichage de : 1. Déplace un disque de la tige 1 vers la tige 3 2. Déplace un disque de la tige 1 vers la tige 2 3. Déplace un disque de la tige 3 vers la tige 2 4. Déplace un disque de la tige 1 vers la tige 3 5. Déplace un disque de la tige 2 vers la tige 1 6. Déplace un disque de la tige 2 vers la tige 3 7. Déplace un disque de la tige 1 vers la tige 3
  • 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. 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 d'une façon récursive ou le résoudre directement si la taille d'un sous- problème est assez réduite ;  Combiner : les solutions des sous-problèmes en une solution globale pour le problème initial.
  • 57. Exemple 1  Recherche de l’indice du maximum dans un tableau d’entiers Fonction 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 FinSi FinSi Fin
  • 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. 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. Analyse des algorithmes « Diviser pour Régner »  On peut souvent donner une relation de récurrence qui décrit le temps d'exécution d’un algorithme « diviser pour régner » en fonction des temps d'exé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 d'exé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. 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. 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. 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. Application : algorithme de recherche dichotomique Fonction 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. 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. 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. 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. 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. 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. 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. Suite du chapitre 3 – Les algorithmes de Tri
  • 72. Tri par fusion  Principe :  Le principe du tri par fusion est plutôt simple. On dit que trier un tableau de taille N, c'est 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. 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 si FIN  T(n) = 2 T(n/2) + Tfusion(n)
  • 74. Tri par fusion Fonction 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. 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. 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. 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. Tri rapide Tri_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 si Partionner (T, deb, fin) x = T(deb) i = deb-1 ; j= fin+1 Tant que (1) Répéter { j=j-1 } Jusqu’à T(j) <= x Répéter { i =i+1 } Jusqu’à T(i) >= x si ( i < j ) permuter (T(i), T(j)) sinon retourner j Fin Si Fin
  • 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)
  • 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. 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. 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. 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. 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. 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. 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. 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. 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. Parcours des graphes Algorithme 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 FinPour Fin Fin
  • 91. Parcours des graphes Algorithme 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)= Noir FinTant que
  • 92. Chapitre 6 – Arbres binaires de recherche
  • 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. Parcours préfixé Algorithme Préfixe(racine : ^Nœud) Si (racine != Nil) Alors AfficheRacine(racine) Préfixe (racine^.FilsG) Préfixe (racine^.FilsD) FinSi Fin
  • 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 que Fin
  • 96. Parcours infixé Algorithme infixe(racine : ^Nœud) Si (racine != Nil) Alors infixe (racine^.FilsG) AfficheRacine(racine) infixe (racine^.FilsD) FinSi Fin
  • 97. Parcours postfixé Algorithme Postfixe(racine : ^Nœud) Si (racine != Nil) Alors Postfixe (racine^.FilsG) Postfixe (racine^.FilsD) AfficheRacine(racine) FinSi Fin
  • 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. Recherche dans un arbre binaire de recherche Algorithme 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 FinSi Fin
  • 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. 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. 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. 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. Merci pour votre attention !