La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

INF1101 Algorithmes et structures de données1 Cours 5 La récursivité.

Présentations similaires


Présentation au sujet: "INF1101 Algorithmes et structures de données1 Cours 5 La récursivité."— Transcription de la présentation:

1 INF1101 Algorithmes et structures de données1 Cours 5 La récursivité

2 INF1101 Algorithmes et structures de données2 Plan du cours I. Notions de base II. Exemple simple (imp. de nombres) III. Limitations (suite de Fibonacci) IV. Arbres (introduction) V. Autres exemples VI. Sous-séquence de somme maximale VII. Backtracking

3 INF1101 Algorithmes et structures de données3 I - Notions de base Définition: Un objet est récursif s'il est défini à partir de lui-même. Une fonction est récursive si elle peut s'appeler elle-même de façon directe ou indirecte Idée générale: Pour bien comprendre la notion de récursivité, il faut connaître le concept des piles. Pour bien comprendre la notion de récursivité, il faut connaître le concept des piles. Les piles sont des structures qui peuvent contenir plusieurs éléments. Toutefois, seul le dernier élément ajouté à la pile est accessible. Une analogie peut être faite avec les piles d'assiettes. Seule l'assiette du dessus est immédiatement accessible. De la même façon, lorsqu'une assiette est ajoutée, celle-ci est nécessairement déposée sur le dessus de la pile.

4 INF1101 Algorithmes et structures de données4 La pile d’assiette Assiette disponible Lorsqu'une fonction est appelée, ses paramètres formels, l'adresse de retour et les variables locales (automatiques) de la fonction appelée sont déposés sur la pile. Toutes ces données sont retirées de la pile à la fin de l'exécution de la fonction. Conséquemment, lors d'appels récursifs, les variables de la fonction sont empilées en cascade.

5 INF1101 Algorithmes et structures de données5 Récursivité (suite) Idée générale : La réalisation d'une tâche par un algorithme récursif repose sur deux éléments: La résolution partielle du problème d'une façon simple. La réalisation du reste de la tâche étant déléguée aux appels récursifs successifs.La résolution partielle du problème d'une façon simple. La réalisation du reste de la tâche étant déléguée aux appels récursifs successifs. La détermination d'une condition d'arrêt qui permet d'arrêter la cascade d'appels récursifs. Résoudre le problème au moment où la condition d'arrêt est détectée correspond en général à résoudre un cas trivial de celui-ci.La détermination d'une condition d'arrêt qui permet d'arrêter la cascade d'appels récursifs. Résoudre le problème au moment où la condition d'arrêt est détectée correspond en général à résoudre un cas trivial de celui-ci.

6 INF1101 Algorithmes et structures de données6 Champs d'application des algorithmes récursifs Structures de données définies récursivement (listes, arbres, graphes, etc.)Structures de données définies récursivement (listes, arbres, graphes, etc.) Équations de récurrence (algébriques, vectorielles, booléennes, formelles, ensemblistes, etc.);Équations de récurrence (algébriques, vectorielles, booléennes, formelles, ensemblistes, etc.); Rétroaction ("backtracking").Rétroaction ("backtracking"). …

7 INF1101 Algorithmes et structures de données7 Avantages et inconvénients Avantages: Formulation compacte, claire et élégante.Formulation compacte, claire et élégante. Maîtrise des problèmes dont la nature même est récursive.Maîtrise des problèmes dont la nature même est récursive.Désavantages: Possibilité de grande occupation de la mémoire.Possibilité de grande occupation de la mémoire. Temps d'exécution peut être plus long.Temps d'exécution peut être plus long. Estimation difficile de la profondeur maximale de la récursivité.Estimation difficile de la profondeur maximale de la récursivité.

8 INF1101 Algorithmes et structures de données8 Fonction récursive factorielle long Factorielle(long N) { if (N==0) return 1; else return (Factorielle(N-1)*N); } Voir main1.cpp Soit la fonction Factorielle, effectuant l’opération n!

9 INF1101 Algorithmes et structures de données9 Exécution de Factorielle Factorielle (4) int Reponse = Factorielle (4); Factorielle (3) Factorielle (2) Factorielle (1) Factorielle (0)

10 INF1101 Algorithmes et structures de données10 Récursivité (suite) Quatre règles régissent la récursivité: 1.Présence de cas de base pouvant être résolu sans récursivité 2.Toujours progresser vers le cas de base à chaque appel récursif 3.« Ayez la Foi »: avoir confiance que les appels récursifs progressent réellement vers le cas de base. 4.Intérêt composé: Ne jamais dédoubler du travail dans deux appels récursifs différents.

11 INF1101 Algorithmes et structures de données11 II – Exemple simple : impression de nombres Idée générale: Fonction qui donne l’impression d’un nombre non-négatif N sous forme décimale. Par exemple pour le nombre 248, il est nécessaire d’imprimer 2, puis 4 et finalement 8. La récursivité offre une méthode efficace et simple de programmer une tel méthode. Fonction qui donne l’impression d’un nombre non-négatif N sous forme décimale. Par exemple pour le nombre 248, il est nécessaire d’imprimer 2, puis 4 et finalement 8. La récursivité offre une méthode efficace et simple de programmer une tel méthode. En utilisant l’opérateur %, le dernier chiffre peut être imprimer, suivi des autres par n/10.

12 INF1101 Algorithmes et structures de données12 Fonction récursive pour N en forme décimale void printDecimal( int n ) { if ( n >= 10 ) printDecimal( n/10 ); cout.put( ‘0’ + n%10 ); }

13 INF1101 Algorithmes et structures de données13 Fonction récursive pour N pour n’importe quelle base void printInt( int n, int base) { static string DIGIT_TABLE = “ abcdef”; if ( n >= base ) printInt( n/base, base ); cout << DIGIT_TABLE[ n%base ]; }

14 INF1101 Algorithmes et structures de données14 Exemple simple : impression de nombres Note : Une erreur se produit lors de l’appel à la fonction récursive lorsque en base 1, puisque les deux paramètres sont identiques. Ceci entraîne une série infinie d’appel à la fonction récursive. Une erreur se produit lors de l’appel à la fonction récursive lorsque en base 1, puisque les deux paramètres sont identiques. Ceci entraîne une série infinie d’appel à la fonction récursive. En testant et en validant la base avant de faire appel à la fonction récursive, ceci éviterait de faire appel à la fonction récursive en base 1. Le test n’est effectué qu’une seule fois puisque ce test sera valide pour tous les appels subséquents. Ceci permettra ainsi de posséder une fonction plus robuste.

15 INF1101 Algorithmes et structures de données15 Fonction récursive pour N pour n’importe quelle base void printIntRec( int n, int base) { static string DIGIT_TABLE = static string DIGIT_TABLE = “ abcdef”; “ abcdef”; if ( n >= base ) printIntRec( n/base, base ); cout << DIGIT_TABLE[ n%base ]; cout << DIGIT_TABLE[ n%base ];} void printInt(int n, int base) { if(base MAX_BASE) if(base MAX_BASE) cerr << “Impression impossible en base “ << base <

16 INF1101 Algorithmes et structures de données16 III – Limitations: Fonction récursive Fibonnacci long fibo (long valeur) { if (valeur <= 1) return valeur; else return(fibo(valeur-1) + fibo(valeur-2)); } // voir main1.cpp Soit la fonction Fibo (Fibonacci), effectuant l’opération f(n) = f(n-1) + f(n-2)

17 INF1101 Algorithmes et structures de données17 Exécution de Fibonnacci Soit les appels effecutés pour fibo(4) : fibo(4) fibo(3) fibo(2) fibo(1)fibo(0) fibo(1) fibo(2) fibo(0)fibo(1)

18 INF1101 Algorithmes et structures de données18 Danger de Fibonnacci Note : Cette fonction récursive effectue plusieurs appels au même calcul. Par exemple pour déterminer f(n), on calcule d’abord f(n-1), puis au retour de l’appel, f(n-2) est calculé. Or, dans le calcul de f(n-1), f(n- 2) est déjà calculé!Cette fonction récursive effectue plusieurs appels au même calcul. Par exemple pour déterminer f(n), on calcule d’abord f(n-1), puis au retour de l’appel, f(n-2) est calculé. Or, dans le calcul de f(n-1), f(n- 2) est déjà calculé! Ce problème s’aggrave en descendant l’arborescence, puisque f(n-3) sera appelé à 3 reprises : chaque appel récursif entraînera de plus en plus d’appel redondant.Ce problème s’aggrave en descendant l’arborescence, puisque f(n-3) sera appelé à 3 reprises : chaque appel récursif entraînera de plus en plus d’appel redondant. Règle 4: Ne jamais dupliquer le travail par la résolution d’une même instance d’un problème dans plusieurs appels récursifs.Règle 4: Ne jamais dupliquer le travail par la résolution d’une même instance d’un problème dans plusieurs appels récursifs.

19 INF1101 Algorithmes et structures de données19 IV – Arbres: introduction Définition : Un arbre est une structure fondamentale et omniprésente en informatique.Un arbre est une structure fondamentale et omniprésente en informatique. La plupart des systèmes d’exploitation organisent leur fichiers dans une structure arborescente.La plupart des systèmes d’exploitation organisent leur fichiers dans une structure arborescente.

20 INF1101 Algorithmes et structures de données20 Définitions Arbre : Un arbre est une structure composée de noeuds et d'arêtes pour laquelle il n'existe qu'un seul chemin pour passer d'un noeud à un autre.Arbre : Un arbre est une structure composée de noeuds et d'arêtes pour laquelle il n'existe qu'un seul chemin pour passer d'un noeud à un autre. Racine : Premier noeud d'un arbre (noeud sans père).Racine : Premier noeud d'un arbre (noeud sans père). Feuille : Noeud n'ayant pas de fils.Feuille : Noeud n'ayant pas de fils.

21 INF1101 Algorithmes et structures de données21 Représentation d’un arbre A C FG B ED

22 INF1101 Algorithmes et structures de données22 V – Autres exemples Exemples démontrant des méthodes qui peuvent être implémentés non récursivement et des avantages de la récursivité.Exemples démontrant des méthodes qui peuvent être implémentés non récursivement et des avantages de la récursivité. Ex : recherche dichotomique (binaire)Ex : recherche dichotomique (binaire) Ex : Dessin d’une règleEx : Dessin d’une règle

23 INF1101 Algorithmes et structures de données23 Recherche binaire (dichotomique) Idée générale : La recherche d’une valeur particulière dans un tableau ordonné se fait par divisions successives du tableau en deux parties. Le fait que le tableau soit ordonné permet de déterminer rapidement la moitié dans laquelle se trouve l’élément recherché.La recherche d’une valeur particulière dans un tableau ordonné se fait par divisions successives du tableau en deux parties. Le fait que le tableau soit ordonné permet de déterminer rapidement la moitié dans laquelle se trouve l’élément recherché. i = début –1 j = fin +1 Tant que i et j ne se rencontrent pas Tant que i et j ne se rencontrent pas Trouver le milieu du sous-tableau courant Trouver le milieu du sous-tableau courant Si la valeur cherchée < tableau [milieu] Si la valeur cherchée < tableau [milieu] j = milieu j = milieu Si la valeur cherchée = tableau [milieu] Si la valeur cherchée = tableau [milieu] Retourne milieu Retourne milieu Si la valeur cherchée > tableau [milieu] Si la valeur cherchée > tableau [milieu] i = milieu i = milieu Retourne -1

24 INF1101 Algorithmes et structures de données24 Recherche dichotomique : Exemple d’exécution Valeur Cherchée = 17; Début = 0, Fin = i j milieu 11 La valeur cherchée est dans la partie gauche du tableau Valeur cherchée = tableau[milieu] Valeur cherchée > tableau[milieu] La valeur cherchée est dans la partie droite du tableau Valeur cherchée < tableau[milieu] On retourne milieu

25 INF1101 Algorithmes et structures de données25 Recherche binaire : programmation non-récursive int RechercheBinaire( int * Tableau, int Debut, int Fin, int ValeurCherchee) int ValeurCherchee){ int i = Debut - 1; int i = Debut - 1; int j = Fin + 1; int j = Fin + 1; while ( i+1 != j) while ( i+1 != j) { int milieu = (i+j)/2; int milieu = (i+j)/2; if ( ValeurCherchee < Tableau[milieu]) if ( ValeurCherchee < Tableau[milieu]) j = milieu; j = milieu; if (ValeurCherchee == Tableau[milieu]) if (ValeurCherchee == Tableau[milieu]) return milieu; return milieu; if (ValeurCherchee > Tableau[milieu]) if (ValeurCherchee > Tableau[milieu]) i = milieu; i = milieu; } return -1; return -1;}

26 INF1101 Algorithmes et structures de données26 Fonction récursive pour la recherche binaire template template int binarySearch(const vector & a, const Comparable& x) { return binarySearch(a, x, 0, a.size()-1); } { return binarySearch(a, x, 0, a.size()-1); } template template int binarySearch(const vector & a, const Comparable& x, int low, int high) { if(low > high) if(low > high) return NOT_FOUND; return NOT_FOUND; int mid = (low+ high)/2; int mid = (low+ high)/2; if( a[mid] < x) if( a[mid] < x) return binarySearch(a, x, mid+1, high) return binarySearch(a, x, mid+1, high) else if( x < a[mid]) else if( x < a[mid]) return binarySearch(a, x, low, mid-1); return binarySearch(a, x, low, mid-1); else else return mid; return mid;}

27 INF1101 Algorithmes et structures de données27 VI – Sous-séquence de somme maximale Définition: La technique de diviser et conquérir (divide- and-conquer) est une méthode de résolution de problèmes basée sur la récursivité:La technique de diviser et conquérir (divide- and-conquer) est une méthode de résolution de problèmes basée sur la récursivité: Diviser en plusieurs sous problèmes résolus récursivement.Diviser en plusieurs sous problèmes résolus récursivement. Conquérir, où la solution du problème original est composé de la solution des sous-problèmes.Conquérir, où la solution du problème original est composé de la solution des sous-problèmes.

28 INF1101 Algorithmes et structures de données28 Sous-séquence de somme maximale Définition: Étant donnée des entiers (possiblement négatifs) A 1, A 2,..., A N, trouver et identifier la séquence correspondante à la valeur maximale de. La somme de la sous- séquence est nulle si tous les entiers sont négatifs.Étant donnée des entiers (possiblement négatifs) A 1, A 2,..., A N, trouver et identifier la séquence correspondante à la valeur maximale de. La somme de la sous- séquence est nulle si tous les entiers sont négatifs.

29 INF1101 Algorithmes et structures de données29 Sous-séquence de somme maximale Exemple: Soit les entiers suivants: {4, -3, 5, -2, -1, 2, 6, -2}. On divise cet ensemble en deux:Soit les entiers suivants: {4, -3, 5, -2, -1, 2, 6, -2}. On divise cet ensemble en deux: Première moitié Deuxième moitié ValeursSommes * * 5 Sommes à partir du centre (* indique la somme maximale pour chaque moitié)

30 INF1101 Algorithmes et structures de données30 Sous-séquence de somme maximale Cas possible: Cas 1: La séquence est situé dans la première moitié.Cas 1: La séquence est situé dans la première moitié. Cas 2: La séquence est situé dans la deuxième moitié.Cas 2: La séquence est situé dans la deuxième moitié. Cas 3: La séquence commence dans la première moitié et se termine dans la deuxième moitié.Cas 3: La séquence commence dans la première moitié et se termine dans la deuxième moitié.

31 INF1101 Algorithmes et structures de données31 Algorithme de la sous-séquence de somme maximale Sommaire de l’algorithme: 1.Déterminer récursivement la sous-séquence de somme maximale uniquement dans la première moitié. 2.Déterminer récursivement la sous-séquence de somme maximale uniquement dans la deuxième moitié. 3.Avec deux boucles consécutives, déterminer la sous- séquence de somme maximale qui débute dans la première moitié et qui termine dans la deuxième moitié. 4.Choisir la somme la plus élevée des trois.

32 INF1101 Algorithmes et structures de données32 Fonction récursive pour la sous- séquence de somme maximale template template Comparable maxSubSum( const vector & a, int left, int right) { Comparable maxLeftBorderSum = 0, maxRightBorderSum = 0; Comparable maxLeftBorderSum = 0, maxRightBorderSum = 0; Comparable leftBorderSum = 0, rightBorderSum = 0; Comparable leftBorderSum = 0, rightBorderSum = 0; int center = ( left + right ) / 2; int center = ( left + right ) / 2; if(left == right) if(left == right) return a[left] > 0 ? a[left] : 0; return a[left] > 0 ? a[left] : 0; Comparable maxLeftSum = maxSubSum(a,left,center); Comparable maxLeftSum = maxSubSum(a,left,center); Comparable maxRightSum = maxSubSum(a,center+1,right); Comparable maxRightSum = maxSubSum(a,center+1,right); for(int i=center; i>=left ;i--) for(int i=center; i>=left ;i--) { leftBorderSum += a[i]; leftBorderSum += a[i]; if( leftBorderSum > maxLeftBorderSum ) if( leftBorderSum > maxLeftBorderSum ) maxLeftBorderSum = leftBorderSum; maxLeftBorderSum = leftBorderSum; }......

33 INF1101 Algorithmes et structures de données33 for(int j=center+1; j<=right; j++) for(int j=center+1; j<=right; j++) { rightBorderSum += a[j]; rightBorderSum += a[j]; if( rightBorderSum > maxRightBorderSum ) if( rightBorderSum > maxRightBorderSum ) maxRightBorderSum = rightBorderSum; maxRightBorderSum = rightBorderSum; } return max3( maxLeftSum, maxRightSum, maxLeftBorderSum + return max3( maxLeftSum, maxRightSum, maxLeftBorderSum + maxRightBorderSum ); maxRightBorderSum );} template template Comparable maxSubsequenceSum( const vector & a) { return a.size() > 0 ? maxSubSum( a, 0, a.size() – 1) : 0; return a.size() > 0 ? maxSubSum( a, 0, a.size() – 1) : 0;} Fonction récursive pour la sous- séquence de somme maximale

34 INF1101 Algorithmes et structures de données34 Sous-séquence de somme maximale (Exemple) max(2,0,2+0) 2 max(3,2,3+2) max(0,0,0+0) 02 max(0,2,0+2) max(0,2,0+1) dstj

35 INF1101 Algorithmes et structures de données35 Sous-séquence de somme maximale (Exemple) max(2,0,2+0) 2 max(3,2,3+2) max(0,0,0+0) 02 max(0,2,0+2) max(0,2,0+1) max(5,2,0+0 )=5 dstj

36 INF1101 Algorithmes et structures de données36 VII – Backtracking Problématique : Pour résoudre certains types de problèmes, il peut être souvent utile de procéder à l'exploration systématique des différentes solutions possibles. Il est donc essentiel de développer des techniques algorithmiques qui permettent une telle exploration.Pour résoudre certains types de problèmes, il peut être souvent utile de procéder à l'exploration systématique des différentes solutions possibles. Il est donc essentiel de développer des techniques algorithmiques qui permettent une telle exploration. Idée générale pour le calcul du trajet du robot: Il s'agit de concevoir un algorithme qui permet à un robot de trouver un chemin menant à la sortie d'un labyrinthe. Pour ce faire le robot explore systématiquement les quatre directions vers lesquelles il peut se déplacer. De plus, afin d'éviter que le robot ne se retrouve sur des cases déjà explorées chacune de celles-ci seront marquées à mesure qu'elles sont visitées. C'est de façon récursive que les cases faisant partie du chemin seront identifiées.Il s'agit de concevoir un algorithme qui permet à un robot de trouver un chemin menant à la sortie d'un labyrinthe. Pour ce faire le robot explore systématiquement les quatre directions vers lesquelles il peut se déplacer. De plus, afin d'éviter que le robot ne se retrouve sur des cases déjà explorées chacune de celles-ci seront marquées à mesure qu'elles sont visitées. C'est de façon récursive que les cases faisant partie du chemin seront identifiées.

37 INF1101 Algorithmes et structures de données37 Algorithme du retour-arrière

38 INF1101 Algorithmes et structures de données38 Plan du site

39 INF1101 Algorithmes et structures de données39 Programmation du trajet d’un robot mobile #define Y 9 /* Les dimensions du labyrinthe */ #define X 7 char laby[X][Y] = { {'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X'}, {'X', ' ', ' ', 'X', ' ', ' ', ' ', ' ', 'X'}, {'X', ' ', ' ', 'X', ' ', ' ', ' ', ' ', 'X'}, {'X', ' ', 'X', 'X', ' ', 'X', 'X', ' ', 'X'}, {'X', ' ', 'X', 'X', ' ', 'X', 'X', ' ', 'X'}, {'X', ' ', ' ', ' ', ' ', ' ', 'X', 'X', 'X'}, {'X', ' ', ' ', ' ', ' ', ' ', 'X', 'X', 'X'}, {'X', 'X', 'X', ' ', 'X', ' ', 'X', ' ', 'X'}, {'X', 'X', 'X', ' ', 'X', ' ', 'X', ' ', 'X'}, {'X', 's', ' ', ' ', ' ', ' ', ' ', ' ', 'X'}, {'X', 's', ' ', ' ', ' ', ' ', ' ', ' ', 'X'}, {'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X'}}; {'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X'}};main(){ int i, j; int i, j; bool Parcours(int x, int y); bool Parcours(int x, int y); if (Parcours(1,1)) { if (Parcours(1,1)) { // Imprimer le résultat de la recherche // Imprimer le résultat de la recherche for (i = 0; i < X; i++, cout<

40 INF1101 Algorithmes et structures de données40 Programmation du trajet d’un robot mobile (suite) bool Parcours(int x, int y) { if (laby[x][y] == 's') { /* on a trouvé la sortie */ if (laby[x][y] == 's') { /* on a trouvé la sortie */ laby[x][y] = 'S'; laby[x][y] = 'S'; return true; return true; } else if (laby[x][y] == ' ') { /* la case est libre */ } else if (laby[x][y] == ' ') { /* la case est libre */ laby[x][y] = 'o'; /* marquer la case visitée */ laby[x][y] = 'o'; /* marquer la case visitée */ if (Parcours(x-1, y)) /* Parcours nord */ if (Parcours(x-1, y)) /* Parcours nord */ return(true); return(true); else if (Parcours(x, y+1)) /* Parcours est */ else if (Parcours(x, y+1)) /* Parcours est */ return(true); return(true); else if (Parcours(x+1, y)) /* Parcours sud */ else if (Parcours(x+1, y)) /* Parcours sud */ return(true); return(true); else if (Parcours(x, y-1)) /* Parcours ouest */ else if (Parcours(x, y-1)) /* Parcours ouest */ return(true); return(true); else else laby[x][y] = '-'; /* on laisse une marque */ laby[x][y] = '-'; /* on laisse une marque */ } return false; return false;}

41 INF1101 Algorithmes et structures de données41 Retour en arrière - exercice Quel est le chemin parcouru? Combien de retours en arrière? Utiliser des appels récursifs et l’ordre d’appel suivant: Nord Sud Est Ouest A B S C D E F E G H I J

42 INF1101 Algorithmes et structures de données42 Retour en arrière - réponse A B C D E F G H I J X E S oo o o ooX X o o o o o ooo o oX o oo o ooo o o o oo oX Xo o


Télécharger ppt "INF1101 Algorithmes et structures de données1 Cours 5 La récursivité."

Présentations similaires


Annonces Google