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

Programme de baccalauréat en informatique Algorithmique et programmation IFT-17582 Abder Alikacem Abder Alikacem Semaine 13 La récursivité Département.

Présentations similaires


Présentation au sujet: "Programme de baccalauréat en informatique Algorithmique et programmation IFT-17582 Abder Alikacem Abder Alikacem Semaine 13 La récursivité Département."— Transcription de la présentation:

1 Programme de baccalauréat en informatique Algorithmique et programmation IFT Abder Alikacem Abder Alikacem Semaine 13 La récursivité Département dinformatique et de génie logiciel Édition septembre 2007

2 Plan Définition récursive dun problème Technique: diviser pour régner Récursion, conditions darrêt et convergence Efficacité et inefficacité des algorithmes récursifs Exemples Lecture: chapitre 13 des notes de cours

3 La récursivité est l'art de définir une fonction en termes d'elle-même. Pourquoi la récursivité? Pour faire souffrir les étudiants Parce que les profs adorent faire souffrir les étudiants La récursivité

4 La récursivité : Plusieurs problèmes sont résolus de façon récursive parce que : naturellement décrits de façon récursive (en mathématiques entre autres : factorielle, Fibonacci, PGCD, etc.) ça simplifie la résolution du problème (diviser pour régner : ré-appliquer un même traitement sur un échantillon de données dune taille de plus en plus petite) En informatique, la programmation avancée utilise souvent des techniques de programmation récursive. La récursivité

5 Soit f, une fonction comprenant un appel à elle-même, soit directement, soit indirectement. Alors, f est une fonction récursive. Définition La récursivité

6 Le langage C autorise la récursivité des appels de fonctions. Celle-ci peut prendre la forme dune : récursivité directe : une fonction comporte, dans sa définition, au moins un appel à elle-même. int f1 (... ) { x = f1 (... ); } La récursivité

7 récursivité indirecte (croisée) : l'appel d'une fonction entraîne une séquence dappels de fonctions qui incluera éventuellement la fonction de départ int f1 (... ) { x = f2 (... ); } int f2 (... ) { y = f1 (... ); } La récursivité

8 Une fonction récursive doit posséder les deux propriétés suivantes: il doit exister certains critères, appelés critères d'arrêt ou conditions d'arrêt, pour lesquels la fonction ne sappelle pas elle-même; chaque fois que la procédure sappelle elle-même (directement ou indirectement), elle doit converger vers ses conditions d'arrêt. Une fonction récursive possédant ces deux propriétés est dite bien définie. La récursivité

9 Récursivité : Diviser pour régner Expression récursive du problème : L « équation » de la récursivité. Condition darrêt : Quand est-ce quon arrête les appels récursifs? Convergence (vers la condition darrêt): Une petite « preuve » et les conditions qui nous assure quon atteindra la condition darrêt.

10 Idée : Diviser pour régner expression récursive du problème (récursion) n! = n x (n-1) x (n-2) x (n-3) x … x 1 = n x (n-1)! conditions darrêt 1! ou 0! convergence vers une des conditions darrêt si n = 0 ou n = 1 alors on a les conditions darrêt si n 2 alors la soustraction par 1 nous amènera vers n = 1 (n n-1 n-2 n-3 … 2 1) donc convergence si n 0 La récursivité

11 Récursivité : Diviser pour régner Structure générale dune fonction récursive { ! if(/* !condition de convergence */) exit(1); if(/*condition darrêt*/) return(/*Ce quelle doit retourné*/); else appel récursif } Traitement

12 Calculer la factorielle dun nombre entier n récursion: n! = n x (n-1) x (n-2) x (n-3) x … x 1 = n x (n-1)! conditions darrêt 1! ou 0! convergence vers une des conditions darrêt si n 0 Exemple 1

13 long fact(int n) { if (n < 0) exit(1); /* hypothèse de convergence : n 0 */ if (n == 0 || n == 1) return 1; /* conditions darrêt */ else return n * fact(n - 1); /* appel récursif */ } Calculer la factorielle dun nombre entier n

14 Suite de Fibonacci Léonardo Pisano dit le « fils de Bonacci » Entre autre : Léquation de la reproduction des lapins 1, 2, 3, 5, 8, 13, 21, 34, … Exemple 2

15 La suite de Fibonacci f n = f n-1 + f n-2 récursion f 1 = 1conditions darrêt f 2 = 2 convergence ? Exemples : f 3 = f 2 + f 1 = 3 f 4 = f 3 + f 2 = 5 Exemple 2

16 long fibo(int n) { if (n < 1) exit(1); /* assertion : n >= 1 */ if (n == 1) return 1; /* cond. darrêt #1 */ if (n == 2) return 2; /* cond. darrêt #2 */ else /* appels récursifs */ return fibo(n - 1) + fibo(n - 2); } La suite de Fibonacci

17 Exemple 3 La légende des Tours de Hanoï remonte aux origines des temps... Pour un certain nombre de disques, le problème est soluble si nous sommes capables daccomplir les actions suivantes: 1.Déplacer les n-1 disques du dessus de Src vers Aux (utilisant Dest comme tour auxilaire) 2.Déplacer le disque restant de Src vers Dst 3.Déplacer les n-1 disques de Aux vers Dst (utilisant Src comme tour auxiliaire)

18 void hanoi(int nbDisques, char Src,char Aux, char Dest) { if (nbDisques == 1) /*condition darret*/ { printf("%c -> %c\n", Src, Dest); } else { /*premier appel recursif*/ hanoi( (nbDisques-1), Src, Dest, Aux); printf("%c -> %c\n", Src, Dest); /*deuxieme appel recursif*/ hanoi( (nbDisques-1), Aux, Src, Dest); } }

19 Un palindrome est un mot qui peut être lu de la même manière de gauche à droite ou de droite à gauche. Exemples : Laval coloc à Abba elle... Les palindromes Exemple 4

20 1. La récursion : Les palindromes

21 1. La récursion : est un palindrome si : ch[0] == ch[l-1] et est un palindrome. 2. Les conditions d'arrêt : Les palindromes

22 1. La récursion : est un palindrome si : ch[0] == ch[l-1] et est un palindrome. 2. Les conditions d'arrêt : 1 er cas : un seul caractère ( l = 1 ) VRAI Les palindromes

23 1. La récursion : est un palindrome si : ch[0] == ch[l-1] et est un palindrome. 2. Les conditions d'arrêt : 1 er cas : un seul caractère ( l = 1 ) VRAI 2 e cas : une chaîne vide ( l = 0 ) VRAI Les palindromes

24 1. La récursion : est un palindrome si : ch[0] == ch[l-1] et est un palindrome. 2. Les conditions d'arrêt : 1 er cas : un seul caractère ( l = 1 ) VRAI 2 e cas : une chaîne vide ( l = 0 ) VRAI 3 e cas : si ch[0] != ch[l-1] FAUX (supposant que l 0 ) 3. La convergence : Les palindromes

25 1. La récursion : est un palindrome si : ch[0] == ch[l-1] et est un palindrome. 2. Les conditions d'arrêt : 1 er cas : un seul caractère ( l = 1 ) VRAI 2 e cas : une chaîne vide ( l = 0 ) VRAI 3 e cas : si ch[0] != ch[l-1] FAUX (supposant que l 0 ) 3. La convergence : comme l est nécessairement 0, sa valeur se rapproche d'une condition d'arrêt à chaque appel récursif Les palindromes

26 typedef enum {FAUX, VRAI} Bool; Bool palindrome(char * mot, int longueur) { } Les palindromes

27 typedef enum {FAUX, VRAI} Bool; Bool palindrome(char * mot, int longueur) { if (longueur < 0) exit(1); /* assertion : longueur >= 0 */ } Les palindromes

28 typedef enum {FAUX, VRAI} Bool; Bool palindrome(char * mot, int longueur) { if (longueur < 0) exit(1); /* assertion : longueur >= 0 */ /* 2 conditions darrêt */ if ((longueur == 0) || (longueur == 1)) return(VRAI); } Les palindromes

29 typedef enum {FAUX, VRAI} Bool; Bool palindrome(char * mot, int longueur) { if (longueur < 0) exit(1); /* assertion : longueur >= 0 */ /* 2 conditions darrêt */ if ((longueur == 0) || (longueur == 1)) return(VRAI); /* 3e condition darrêt */ if (mot[0] != mot[longueur-1]) return(FAUX); else } Les palindromes

30 typedef enum {FAUX, VRAI} Bool; Bool palindrome(char * mot, int longueur) { if (longueur < 0) exit(1); /* assertion : longueur >= 0 */ /* 2 conditions darrêt */ if ((longueur == 0) || (longueur == 1)) return(VRAI); /* 3e condition darrêt */ if (mot[0] != mot[longueur-1]) return(FAUX); else /* appel récursif */ return palindrome(mot+1, longueur-2); } Les palindromes

31 s = x 0 + x x n-1 1. La récursion : La somme des éléments dun tableau Exemple 5

32 s = x 0 + x x n-1 1. La récursion : s(x 0,..., x n-1 ) = x 0 + s(x 1,..., x n-1 ) 2. La condition d'arrêt : La somme des éléments dun tableau

33 s = x 0 + x x n-1 1. La récursion : s(x 0,..., x n-1 ) = x 0 + s(x 1,..., x n-1 ) 2. La condition d'arrêt : s(x 0 ) = x 0 (1 seul terme) 3. La convergence : La somme des éléments dun tableau

34 s = x 0 + x x n-1 1. La récursion : s(x 0,..., x n-1 ) = x 0 + s(x 1,..., x n-1 ) 2. La condition d'arrêt : s(x 0 ) = x 0 (1 seul terme) 3. La convergence : n > 0 et décroît vers 1 La somme des éléments dun tableau

35 long somme(int tab[ ], int n, int debut) { } La somme des éléments dun tableau

36 long somme(int tab[ ], int n, int debut) { if (n < 1) exit(1); /* assertion : n >= 1 */ } La somme des éléments dun tableau

37 long somme(int tab[ ], int n, int debut) { if (n < 1) exit(1); /* assertion : n >= 1 */ /* assertion : debut est un indice valide, debut 0 */ } La somme des éléments dun tableau

38 long somme(int tab[ ], int n, int debut) { if ((n < 1) || (debut < 0)) exit(1); /* assertion : n >= 1 */ /* assertion : debut est un indice valide, debut 0 */ } La somme des éléments dun tableau

39 long somme(int tab[ ], int n, int debut) { if ((n < 1) || (debut < 0)) exit(1); /* assertion : n >= 1 */ /* assertion : debut est un indice valide, debut 0 */ /* condition darrêt */ } La somme des éléments dun tableau

40 long somme(int tab[ ], int n, int debut) { if ((n < 1) || (debut < 0)) exit(1); /* assertion : n >= 1 */ /* assertion : debut est un indice valide, debut 0 */ /* condition darrêt */ if (n == 1) return tab[debut]; else } La somme des éléments dun tableau

41 long somme(int tab[ ], int n, int debut) { if ((n < 1) || (debut < 0)) exit(1); /* assertion : n >= 1 */ /* assertion : debut est un indice valide, debut 0 */ /* condition darrêt */ if (n == 1) return tab[debut]; else /* appel récursif */ return tab[debut] + somme(tab, n-1, debut+1); } La somme des éléments dun tableau

42 Somme dun tableau: autre version Somme(tab[], n) = tab[0] + Somme(tab + 1, n-1) long somme(int * tab, int n) { if (n < 1)/* hypothèse de convergence : n 1*/ exit(1); if (n == 1) /* condition darrêt */ return tab[0]; else /* appel récursif */ return tab[0] + somme(tab + 1, n – 1); }

43 Soit ch1 et ch2, les deux chaînes à comparer. 1. La récursion : La comparaison de 2 chaînes de caractères Exemple 6

44 Soit ch1 et ch2, les deux chaînes à comparer. 1. La récursion : ch1 est égale à ch2 à partir de debut si : ch1[debut] == ch2[debut] et ch1 et ch2 sont égales à partir de debut Les conditions d'arrêt : La comparaison de 2 chaînes de caractères

45 Soit ch1 et ch2, les deux chaînes à comparer. 1. La récursion : ch1 est égale à ch2 à partir de debut si : ch1[debut] == ch2[debut] et ch1 et ch2 sont égales à partir de debut Les conditions d'arrêt : ch1[debut] != ch2[debut] FAUX La comparaison de 2 chaînes de caractères

46 Soit ch1 et ch2, les deux chaînes à comparer. 1. La récursion : ch1 est égale à ch2 à partir de debut si : ch1[debut] == ch2[debut] et ch1 et ch2 sont égales à partir de debut Les conditions d'arrêt : ch1[debut] != ch2[debut] FAUX ch1[debut] == '\0 si ch1[debut] == ch2[debut] VRAI si ch1[debut] != ch2[debut] FAUX 3. La convergence : La comparaison de 2 chaînes de caractères

47 Soit ch1 et ch2, les deux chaînes à comparer. 1. La récursion : ch1 est égale à ch2 à partir de debut si : ch1[debut] == ch2[debut] et ch1 et ch2 sont égales à partir de debut Les conditions d'arrêt : ch1[debut] != ch2[debut] FAUX ch1[debut] == '\0 si ch1[debut] == ch2[debut] VRAI si ch1[debut] != ch2[debut] FAUX 3. La convergence : Balayage des 2 chaînes jusqu'à la fin de chaîne. La comparaison de 2 chaînes de caractères

48 Bool egal(char *ch1, char *ch2, int debut) { } La comparaison de 2 chaînes de caractères

49 Bool egal(char *ch1, char *ch2, int debut) { /* assertion : ch1 pointe sur une chaîne de caractères */ } La comparaison de 2 chaînes de caractères

50 Bool egal(char *ch1, char *ch2, int debut) { /* assertion : ch1 pointe sur une chaîne de caractères */ /* assertion : debut est un indice valide, debut 0 */ } La comparaison de 2 chaînes de caractères

51 Bool egal(char *ch1, char *ch2, int debut) { /* assertion : ch1 pointe sur une chaîne de caractères */ /* assertion : debut est un indice valide, debut 0 */ /* assertion : debut strlen(ch1) */ } La comparaison de 2 chaînes de caractères

52 Bool egal(char *ch1, char *ch2, int debut) { /* assertion : ch1 pointe sur une chaîne de caractères */ /* assertion : debut est un indice valide, debut 0 */ /* assertion : debut strlen(ch1) */ if ((debut strlen(ch1))) exit(1); } La comparaison de 2 chaînes de caractères

53 Bool egal(char *ch1, char *ch2, int debut) { /* assertion : ch1 pointe sur une chaîne de caractères */ /* assertion : debut est un indice valide, debut 0 */ /* assertion : debut strlen(ch1) */ if ((debut strlen(ch1))) exit(1); /* condition darrêt : sur la fin de chaîne de ch1 */ } La comparaison de 2 chaînes de caractères

54 Bool egal(char *ch1, char *ch2, int debut) { /* assertion : ch1 pointe sur une chaîne de caractères */ /* assertion : debut est un indice valide, debut 0 */ /* assertion : debut strlen(ch1) */ if ((debut strlen(ch1))) exit(1); /* condition darrêt : sur la fin de chaîne de ch1 */ if (ch1[debut] == '\0') if (ch2[debut] == '\0') return(VRAI); else return(FAUX); else } La comparaison de 2 chaînes de caractères

55 Bool egal(char *ch1, char *ch2, int debut) { /* assertion : ch1 pointe sur une chaîne de caractères */ /* assertion : debut est un indice valide, debut 0 */ /* assertion : debut strlen(ch1) */ if ((debut strlen(ch1))) exit(1); /* condition darrêt : sur la fin de chaîne de ch1 */ if (ch1[debut] == '\0') if (ch2[debut] == '\0') return(VRAI); else return(FAUX); else/* condition darrêt : inégalité des car. correspondants */ } La comparaison de 2 chaînes de caractères

56 Bool egal(char *ch1, char *ch2, int debut) { /* assertion : ch1 pointe sur une chaîne de caractères */ /* assertion : debut est un indice valide, debut 0 */ /* assertion : debut strlen(ch1) */ if ((debut strlen(ch1))) exit(1); /* condition darrêt : sur la fin de chaîne de ch1 */ if (ch1[debut] == '\0') if (ch2[debut] == '\0') return (VRAI); else return (FAUX); else/* condition darrêt : inégalité des car. correspondants */ if (ch1[debut] != ch2[debut]) return(FAUX); else } La comparaison de 2 chaînes de caractères

57 Bool egal(char *ch1, char *ch2, int debut) { /* assertion : ch1 pointe sur une chaîne de caractères */ /* assertion : debut est un indice valide, debut 0 */ /* assertion : debut strlen(ch1) */ if ((debut strlen(ch1))) exit(1); /* condition darrêt : sur la fin de chaîne de ch1 */ if (ch1[debut] == '\0') if (ch2[debut] == '\0') return(VRAI); else return (FAUX); else/* condition darrêt : inégalité des car. correspondants */ if (ch1[debut] != ch2[debut]) return(FAUX); else /* appel récursif */ return egal(ch1, ch2, debut+1); } La comparaison de 2 chaînes de caractères

58 Comparaison de chaînes: autre version Egal(mot1, mot2) = *mot1 = *mot2 ET Egale(mot1 + 1,mot2 + 1) Bool egal(char * mot1, char * mot2) { if (*mot1 != *mot2) /* condition darrêt */ return FAUX; if (*mot1 == \0) /* condition darrêt */ if (*mot2 == '\0') return VRAI; else return FAUX ; else /* appel récursif */ return egal(mot1 + 1, mot2 + 1); }

59 1. La récursion : Vérifier quune suite de nombres est triée Exemple 7

60 1. La récursion : est triée si : x 0 x 1 et est triée. 2. Les conditions d'arrêt : Vérifier quune suite de nombres est triée

61 1. La récursion : est triée si : x 0 x 1 et est triée. 2. Les conditions d'arrêt : est triée (longueur = 1 VRAI ) Vérifier quune suite de nombres est triée

62 1. La récursion : est triée si : x 0 x 1 et est triée. 2. Les conditions d'arrêt : est triée (longueur = 1 VRAI ) x 0 > x 1 FAUX 3. La convergence : Vérifier quune suite de nombres est triée

63 1. La récursion : est triée si : x 0 x 1 et est triée. 2. Les conditions d'arrêt : est triée (longueur = 1 VRAI ) x 0 > x 1 FAUX 3. La convergence : La taille de la séquence regardée diminue jusquà 1. Vérifier quune suite de nombres est triée

64 Bool triee(int x[ ], int debut, int longueur) { } Vérifier quune suite de nombres est triée

65 Bool triee(int x[ ], int debut, int longueur) { /* assertion : longueur 1 */ /* assertion : debut est un indice valide, debut 0 */ if ((longueur < 1) || (debut < 0)) exit(1); } Vérifier quune suite de nombres est triée

66 Bool triee(int x[ ], int debut, int longueur) { /* assertion : longueur 1 */ /* assertion : debut est un indice valide, debut 0 */ if ((longueur < 1) || (debut < 0)) exit(1); /* cond. darrêt : longueur = 1 */ if (longueur == 1) return VRAI; else /* cond. darrêt : bris de l ordre */ } Vérifier quune suite de nombres est triée

67 Bool triee(int x[ ], int debut, int longueur) { /* assertion : longueur 1 */ /* assertion : debut est un indice valide, debut 0 */ if ((longueur < 1) || (debut < 0)) exit(1); /* cond. darrêt : longueur = 1 */ if (longueur == 1) return VRAI; else /* cond. darrêt : bris de l ordre */ if (x[debut] > x[debut+1]) return FAUX; else } Vérifier quune suite de nombres est triée

68 Bool triee(int x[ ], int debut, int longueur) { /* assertion : longueur 1 */ /* assertion : debut est un indice valide, debut 0 */ if ((longueur < 1) || (debut < 0)) exit(1); /* cond. darrêt : longueur = 1 */ if (longueur == 1) return VRAI; else /* cond. darrêt : bris de l ordre */ if (x[debut] > x[debut+1]) return FAUX; else /* appel récursif */ } Vérifier quune suite de nombres est triée

69 Bool triee(int x[ ], int debut, int longueur) { /* assertion : longueur 1 */ /* assertion : debut est un indice valide, debut 0 */ if ((longueur < 1) || (debut < 0)) exit(1); /* cond. darrêt : longueur = 1 */ if (longueur == 1) return VRAI; else /* cond. darrêt : bris de l ordre */ if (x[debut] > x[debut+1]) return FAUX; else /* appel récursif */ return triee(x, debut+1, longueur-1); } Vérifier quune suite de nombres est triée

70 Tableau trié : autre version trie(tab[], n) = tab[0] tab[1] ET trie(tab + 1, n – 1) Bool trie(int tab[], int n) { if (n < 1) /* Hypothèse de convergence*/ exit(1); if (n == 1) /* condition darrêt */ return VRAI; if (tab[0] > tab[1]) /* condition darrêt */ return FAUX; /* appel récursif */ return trie(tab + 1, n – 1); }

71 Il sagit de programmer le triangle de Pascal dont le prototype obligatoire de la fonction à développer est : int trigPas(int col, int lig); Cette fonction reçoit le numéro de la ligne ainsi que le numéro de la colonne et renvoie la valeur contenue dans la case correspondante selon le triangle de Pascal. Exercice

72 Exercice Vous devez écrire une fonction récursive pour faire la somme des chiffres d'un nombre entier n 0 jusquà ce que le résultat soit composé par un seul chiffre. Par exemple, la somme des chiffres de 854 est 8 (8+5+4=17, 1+7=8). Le prototype obligatoire de la fonction est : int sommeChiffres(int n);

73 C'est toujours assez complexe de suivre un code récursif, mais l'écriture en est plus simple. La taille de la pile peut augmenter rapidement et, comme lespace-mémoire réservé pour cette pile est toujours limité, cela peut conduire à un dépassement de sa capacité (stack overflow). Pour utiliser la récursivité, il faut disposer d'assez de mémoire, par opposition à la méthode d'implémentation itérative. Exécution d'une fonction récursive

74 Gestion de la pile : fact(3) long fact(int n) { long f; if (n < 0) exit(1); if ( (n == 0) || (n == 1) ) f = 1; else f = n * fact(n-1); return f; } typedef struct {int n; long f; void *retour; } TypeEl;

75 pile n f retour long fact(int n) { long f; if (n < 0) exit(1); if ( (n == 0) || (n == 1) ) f = 1; else f = n * fact(n-1); return f; } typedef struct {int n; long f; void *retour; } TypeEl; Gestion de la pile : fact(3)

76 pile n f retour Gestion de la pile : fact(3) long fact(int n) { long f; if (n < 0) exit(1); if ( (n == 0) || (n == 1) ) f = 1; else f = n * fact(n-1); return f; } typedef struct {int n; long f; void *retour; } TypeEl;

77 pile n f retour Gestion de la pile : fact(3) long fact(int n) { long f; if (n < 0) exit(1); if ( (n == 0) || (n == 1) ) f = 1; else f = n * fact(n-1); return f; } typedef struct {int n; long f; void *retour; } TypeEl;

78 pile n f retour Gestion de la pile : fact(3) long fact(int n) { long f; if (n < 0) exit(1); if ( (n == 0) || (n == 1) ) f = 1; else f = n * fact(n-1); return f; } typedef struct {int n; long f; void *retour; } TypeEl;

79 pile n f retour Gestion de la pile : fact(3) long fact(int n) { long f; if (n < 0) exit(1); if ( (n == 0) || (n == 1) ) f = 1; else f = n * fact(n-1); return f; } typedef struct {int n; long f; void *retour; } TypeEl;

80 pile n f retour Gestion de la pile : fact(3) long fact(int n) { long f; if (n < 0) exit(1); if ( (n == 0) || (n == 1) ) f = 1; else f = n * fact(n-1); return f; } typedef struct {int n; long f; void *retour; } TypeEl;

81 pile n f retour Gestion de la pile : fact(3) long fact(int n) { long f; if (n < 0) exit(1); if ( (n == 0) || (n == 1) ) f = 1; else f = n * fact(n-1); return f; } typedef struct {int n; long f; void *retour; } TypeEl;

82 pile n f retour Gestion de la pile : fact(3) long fact(int n) { long f; if (n < 0) exit(1); if ( (n == 0) || (n == 1) ) f = 1; else f = n * fact(n-1); return f; } typedef struct {int n; long f; void *retour; } TypeEl;

83 pile n f retour Gestion de la pile : fact(3) long fact(int n) { long f; if (n < 0) exit(1); if ( (n == 0) || (n == 1) ) f = 1; else f = n * fact(n-1); return f; } typedef struct {int n; long f; void *retour; } TypeEl;

84 pile n f retour Gestion de la pile : fact(3) long fact(int n) { long f; if (n < 0) exit(1); if ( (n == 0) || (n == 1) ) f = 1; else f = n * fact(n-1); return f; } typedef struct {int n; long f; void *retour; } TypeEl;

85 pile Gestion de la pile : fact(3) long fact(int n) { long f; if (n < 0) exit(1); if ( (n == 0) || (n == 1) ) f = 1; else f = n * fact(n-1); return f; } typedef struct {int n; long f; void *retour; } TypeEl;

86 Quand utiliser la récursivité ? quand il existe une définition récursive claire; (pour les structures de données régulières par exemple) quand la récursivité est plus simple que la version itérative; quand on a besoin d'un gain en performance possible grâce à une formulation récursive habile. La La récursivité

87 x y = x * x y-1 x 0 = 1 x 1 = x long exp (int x, int y) {/* */ /* assertion : y >= 0 */ if (y < 0 ) exit(1); if (y == 0) return 1; else if (y == 1) return x; else return x * exp (x, y-1); } Exemple. Gain en performance

88 x y = x y/2 * x y/2, si y pair et x y = x * x y/2 * x y/2, si y impair. long exp (int x, int y) { /* assertion : y >= 0 */ if (y < 0) exit(1); if (y == 0) return 1; else if (y == 1) return x; else if (y % 2 == 0) return exp (x, y/2) * exp (x, y/2); else return x * exp (x, y/2) * exp (x, y/2); } x 16 = x 8 * x 8 (ceci correspondra à un appel) x 8 = x 4 * x 4 (un autre appel) x 4 = x 2 * x 2 (un appel également) x 2 (encore un autre appel) Exemple. Gain en performance

89 La récursivité offre généralement une rapidité et une simplicité dans le développement dune solution donnée. Par contre, son principal désavantage est la lourdeur dans lexécution de cette solution et le temps de mise au point (débuggage) qu'elle requiert habituellement. Quand utiliser la récursivité ? La La récursivité

90 Exercices

91 Rappel Expression récursive Expression récursive du problème (récursion): L « équation » de la récursivité. Diviser pour régner n! = n x (n-1) x (n-2) x (n-3) x … x 1 = n x (n-1)! Condition darrêt Condition darrêt : Quand est-ce quon arrête les appels récursifs? 1! ou 0! Convergence Convergence (vers la condition darrêt): Des conditions qui nous assure quun jour on va atteindre les conditions darrêt. si n = 0 ou n = 1 alors on a les conditions darrêt si n 2 alors la soustraction par 1 nous amènera vers n = 1 (n n-1 n-2 n-3 … 2 1) donc convergence si n 0

92 Récursivité : Diviser pour régner Structure générale dune fonction récursive : { ! if(/* !condition de convergence */) exit(1); if(/*condition darrêt*/) return(/*Ce quelle doit retourné*/); else appel récursif } Traitement

93 long fact(int n) { if (n < 0) exit(1); /* condition de convergence : n 0 */ if (n == 0 || n == 1) return 1l; /* conditions darrêt */ else return n * fact(n - 1); /* appel récursif */ } Exemple dune conception

94 Écrivez une fonction récursive qui fait l'addition de 2 nombres entiers, n et m, où m est positif ou nul, selon la définition récursive suivante: add(n,m) = n si m = 0 add(n,m) = 1 + add(n,m-1)

95 int add(int n, int m) { /* assertion: m>=0 */ if (m < 0) exit(1); /* cond. d'arrêt: m == 0 */ if (m == 0) return n; else /* récursion */ return 1+add(n,m-1); }

96 Écrivez une fonction récursive qui multiplie n par m en additionnant n, m fois. Par exemple: multiplie(3,4) = = 12. Vous pouvez supposer que m est positif ou nul, et que m et n sont entiers.

97 int multiplie(int n, int m) { /* assertion: m>=0 */ if (m<0) exit(1); /* cond. d'arrêt: m == 0 */ if (m == 0) return 0; else /* récursion */ return n+multiplie(n,m-1); }

98 Écrivez une fonction récursive qui calcul x exposant y pour y >= 0, sachant que x exposant 0 donne 1, et que x et y sont entiers.

99 long exp(int x, int y) { /* assertion: y>=0 */ if( y<0) exit(1); /* cond. d'arrêt: x exposant 0 == 1 */ if (y == 0) return 1l; else /* récursion */ return (long) (x*exp(x,y-1)); }

100 Écrivez une fonction récursive qui affiche un tableau dentier du dernier élément au premier élément (laboratoire#13).

101 #define MAX 10 void affiche (int t[], int n) { /* assertion: n>1 et n=< MAX */ if (n MAX) exit (1); /* cond. d'arrêt: n == 1 */ if (n==1) printf("%d", *t); else /* récursion */ { affiche(t+1, n-1); printf(" %d ", *t); }

102 Il sagit dimplanter un algorithme permettant dafficher le tableau dentiers suivant dune certaine manière : Il est à noter que tout élément du tableau est lié logiquement avec deux autres éléments, le lien1 et le lien2, du même tableau, ainsi: le lien1 a comme identificateur 2D le lien2 a comme identificateur 2D + 1 où D est l'indice de l'élément en question La récursion à considérer est la suivante: 1. Afficher lélément lié à e par le lien1; 2. Afficher e; 3. Afficher lélément lié à e par le lien2;

103 void affiche(int T[ ], int nb, int i) { /* assertion: nb>=0 et 0<= i

104 void affiche(int T[ ], int nb, int i) { /* assertion: nb>=0 et 0<= i

105 void affiche(int T[ ], int nb, int i) { /* assertion: nb>=0 et 0<= i

106 Ré-écrivez la fonction strlen() sous une forme récursive (laboratoire#13).

107 #include #define OK 1 int longueur(char *c, int *err) { /*A: c est une chaîne de caractères*/ *err=OK; if (*c!= '\0') { return 1+ longueur(c+1, err); } return 0; } int main() { char c[]="Bonjour"; int err; printf("\n %d \n\n", longueur(c, &err)); return 0; }

108 Écrivez une fonction récursive qui renverse une chaîne de caractères. Exemple: la chaîne « Bonjour » doit être transformée en « ruojnoB ».

109 void miroir(char *c, int l1, int l2) { char car; if (*(c+l1)!= '\0') { car= *(c+l1); miroir(c,l1+1,l2-1); *(c+l2-1)= car; } int main() { char c[]="Bonjour toi !"; miroir(c, 0, strlen(c)); printf("\n C: %s \n\n", c); return 0; }

110 Écrivez une fonction récursive qui compte le nombre de chiffres que composent un nombre entier n 0. Le prototype obligatoire est : int longueur (int n); Exemple : si n = 78945, la fonction doit retourner 5 (78945 est composé de 5 chiffres). Utilisez la fonction exit() pour léventuelle gestion de ou des pré-conditions à lexécution de la fonction.

111 int longueurNombre (int n) { if (n<0) exit(1); if (n <=9) return 1; else return(1+longueurNombre(n/10)); }

112 Il sagit de programmer le triangle de Pascal dont le prototype obligatoire de la fonction à développer est : int trigPas(int col, int lig); Cette fonction reçoit le numéro de la ligne ainsi que le numéro de la colonne et renvoie la valeur contenue dans la case correspondante selon le triangle de Pascal.

113 int trigPas (int x, int y) { if(x<=0 || y<=0) exit(1); if (x == 1 ||/*point d'appui : la première colonne */ y == x)/* point d'appui : la diagonale */ return 1; else return (trigPas(x, y - 1) + trigPas (x - 1, y - 1)); /*appel récursif */ } int main() { int ligne, colonne; for (ligne= 1; ligne <=15; ligne++) { for (colonne = 1; colonne <= ligne; colonne++) { printf (" %d ", comb(colonne, ligne)); } printf("\n"); } return 0; }

114 Soit la fonction suivante : int f(int m, int n) { if(m == 0) return(n + 1); if(n == 0) return f(m – 1, 1); return f(m – 1, f(m, n – 1)); } Faites une trace (larbre des appels récursifs) pour m = 1, n = 3.

115 Vous devez écrire une fonction récursive pour faire la somme des chiffres d'un nombre entier n 0 jusquà ce que le résultat soit composé par un seul chiffre. Par exemple, la somme des chiffres de 854 est 8 (8+5+4=17, 1+7=8). Le prototype obligatoire de la fonction est : int sommeChiffres(int n);

116 #include int sommeChiffres(int n) { if(n<0) exit(1); if(n <= 9) { return n; /*Condition d'arrêt: c'est un chiffre*/ } else /*C'est un nombre, on recommence*/ { return sommeChiffres(n%10 + sommeChiffres(n/10)); } int main() /*pour tester*/ { printf("%d\n", sommeChiffres(789)); return 0; }


Télécharger ppt "Programme de baccalauréat en informatique Algorithmique et programmation IFT-17582 Abder Alikacem Abder Alikacem Semaine 13 La récursivité Département."

Présentations similaires


Annonces Google