Semaine 8 Retour sur les tableaux : fonctions et récursivité Fonctions et tableaux Récursivité sur les tableaux
Fonctions et tableaux (1) Il est interdit de définir des fonctions qui retournent des tableaux ! En revanche, un tableau peut être passé en paramètre d'une fonction. #include <cini.h> #define TAILLE 7 void afficheTab(int tab[], int taille){ int i; for(i=0; i < taille; i++){ CINI_print_int(tab[i]); CINI_print_char(' '); } CINI_newline(); int main(){ int tab_int[] = {2, 4, 6, 9, 3, 6, 8}; afficheTab(tab_int,TAILLE); return 0;
Fonctions et tableaux (2) Attention : En C, un tableau est passé par référence : Un tableau stocke une suite d'éléments, ce ne sont pas ces éléments qui sont transmis mais une référence à l'accès de ces éléments (l'adresse mémoire du premier élément de la suite). Si on modifie un tableau dans une fonction, il ressort modifié de l'appel de la fonction (contrairement aux autres variables qui sont passées par valeur). On vous expliquera pourquoi bientôt …
Fonctions et tableaux (3) #include <cini.h> #define TAILLE 7 void ajouteTab(int tab[], int taille, int val){ int i; for(i=0; i < taille; i++){ tab[i] = tab[i] + val; } void afficheTab(int tab[], int taille){ CINI_print_int(tab[i]); CINI_print_char(' '); CINI_newline(); int main(){ int tab_int[] = {2, 4, 6, 9, 3, 6, 8}; afficheTab(tab_int,TAILLE); ajouteTab(tab_int, TAILLE, 2); afficheTab(tab_int, TAILLE); return 0; 2 4 6 9 3 6 8 4 6 8 11 5 8 10
Fonctions et tableaux (4) #include <cini.h> #define TAILLE 100 void initialise(int tab[], int taille, int min, int max){ int i; for(i=0; i < taille; i++){ tab[i] = CINI_random(min, max); } void afficheTab(int tab[], int taille){ CINI_print_int(tab[i]); CINI_print_char(' '); CINI_newline(); int main(){ int tab_int[TAILLE]; initialise(tab_int, TAILLE, 1, 50); afficheTab(tab_int, TAILLE); return 0; Tableau non initialisé Tableau initialisé
Fonctions et tableaux (5) Une fonction qui manipule un tableau peut retourner une valeur (autre qu'un tableau) : #include <cini.h> #define TAILLE 100 float initialise(int tab[], int taille, int min, int max){ int i, j; float s = 0; for(i=0; i < taille; i++){ j = CINI_random(min, max); tab[i] = j ; s = s + j; } return s/taille; void afficheTab(int tab[], int taille){ ... } int main(){ int tab_int[TAILLE]; float m; m = ajouteTab(tab_int, TAILLE, 1, 50); CINI_print_string("moyenne des elements du tableau :"); CINI_print_float(m); afficheTab(tab_int, TAILLE); return 0;
Récursivité sur les tableaux (1) Rappel sur le principe de la récursivité : Décomposer le problème en un problème plus simple → réduire la taille du problème considéré Pour la récursion sur des entiers : la taille du problème est définie par un entier, on réduit la valeur de cet entier à chaque appel récursif. Pour la récursion sur les tableaux : Soit on considère la taille du tableau, on réduit la taille du tableau considéré à chaque appel récursif Ou bien on utilise un ou des indices qui varient à chaque appel pour tendre vers la condition d'arrêt (dépendant des valeurs des indices).
Récursivité sur les tableaux (2) Exemple : Somme des N premiers éléments d'un tableau = dernier élément + la somme des N-1 premiers éléments du tableau. Somme des éléments d'un tableau de nombres : Soit N le nombre d'éléments dont on veut faire la somme (taille du tableau) Cas général : somme_elts = dernier_elt + somme_elts des N-1 premiers éléments du tableau Cas de base : somme_elts = 0, si N = 0
Récursivité sur les tableaux (3) Somme des éléments d'un tableau d'entiers : int sommeElt(int tab[], int taille){ if(taille == 0){ return 0; } else{ return (tab[taille-1] + sommeElt(tab, taille-1)); Attention : cette définition, suppose que la valeur du paramètre taille ne dépasse pas la taille réelle du tableau.
Récursivité sur les tableaux (4) Somme des éléments d'un tableau d'entiers : int tab[] = {2, 5, 9, 5, 16, 31}; sommeElt(tab, 6) 31 + sommeElt(tab, 5) 16 + sommeElt(tab, 4) 5 + sommeElt(tab, 3) 9 + sommeElt(tab, 2) 5 + sommeElt(tab, 1) 2 + sommeElt(tab,0) 2 + 0 5 + 2 9 + 7 5 + 16 16 + 21 31 + 37 68
Récursivité sur les tableaux (5) Que se passe-t-il si on modifie l'appel récursif ? int sommeElt(int tab[], int taille){ if(taille == 0){ return 0; } else{ return (tab[taille-1] + sommeElt(tab, taille+1)); Boucle infinie ou erreur de segmentation
Récursivité sur les tableaux (6) Calcul de la valeur maximum présente dans un tableau : int maxInt(int a, int b){ if(a > b){ return a; } else{ return b; int maxTab(int tab[], int taille){ if(taille == 1){ return tab[0]; return (maxInt(tab[taille-1], maxTab(tab, taille-1))); Attention : on suppose ici que le tableau n'est pas vide
Récursivité sur les tableaux (7) Calcul du max d'un tableau : int tab[] = {2, 5, 99, 5, 31}; maxTab(tab, 5) maxInt(31,maxTab(tab, 4)) maxInt(5, maxTab(tab, 3)) maxInt(99, maxTab(tab, 2)) maxInt(5, maxTab(tab, 1)) 2 maxInt(5, 2) maxInt(99,5) maxInt(5, 99) maxInt(31, 99) 99
Récursivité sur les tableaux (8) Palindromes : Un palindrome est un texte dont l'ordre des lettres est identique si on le lit de gauche à droite ou de droite à gauche. On peut représenter un texte par un tableau de caractères. On souhaite vérifier que le texte contenu dans un tableau de caractères est un palindrome. L'appel à palindrome(char tabChar[] , in taille) retourne true si tabChar contient un palindrome, false sinon. Cas de base ? Cas général ?
Récursivité sur les tableaux (9) Palindromes : Soit m le nombre de caractères examinés à partir de la gauche du texte. Initialement m vaut 0. On appelle palindrome(tabChar, taille, m) Cas de base : Si m == (taille / 2) alors retourner true Cas général : Si tabChar[m] == tabChar[taille - m - 1] alors Retourner palindrome(tabChar, taille, m+1) Sinon Retourner false
Récursivité sur les tableaux (10) Palindromes : #include <cini.h> bool palindrome(char tabChar[], int taille, int m){ if(m == (taille / 2)){ return true; } else{ if(tabChar[m] == tabChar[taille - m -1]){ return palindrome(tabChar, taille, m+1); return false; int main(){ char tabChar[] = {'l', 'a', 'v', 'a', 'l'}; bool res = palindrome(tabChar, 5 , 0); CINI_print_string("palindrome ? -> "); CINI_print_bool(res); CINI_newline(); return 0; palindrome ? -> true
Récursivité sur les tableaux (11) Recherche dichotomique : La recherche dichotomique est une méthode de recherche d'un élément dans un tableau trié. On considère des tableaux d'entiers triés en ordre croissant. On souhaite vérifier si un élément elem est présent dans le tableau tabInt. Principe : Soit deb l'indice du début de la zone considérée et fin l'indice de la fin de cette zone. Initialement, on considère tout le tableau deb= 0 et fin = taille -1 On va au fur et à mesure de l'algorithme réduire la taille de la zone envisagée (on modifie les valeurs de deb et fin).
Récursivité sur les tableaux (12) Principe (suite) : On calcule le milieu de cette zone : milieu = (deb+fin) / 2 Soit m la valeur de l'élément d'indice milieu. On compare elem (l'élément recherché) avec m. Si m == elem, l'élément recherché est trouvé. Sinon : Si m < elem, on ré-itère la recherche dans la deuxième moitié du tableau (deb = milieu + 1). Sinon, on ré-itère la recherche dans la première moitié du tableau (fin = milieu - 1).
Récursivité sur les tableaux (13) Recherche dichotomique, principe (suite) : Soit tabInt[] = { 2 , 4 , 9 , 15 , 24 , 45}; On recherche l'élément elem (par exemple 4). On utilise 2 variables deb et fin indiquant l'indice de début et l'indice de fin de la partie du tableau dans laquelle on fait la recherche. Initialement : deb = 0 fin = taille_du_tableau - 1 (dans l'exemple fin = 5) Remarque : L'algorithme est le même que le tableau ait un nombre pair ou impair d'éléments.
Récursivité sur les tableaux (14) Recherche dichotomique, principe (suite) : Initialement : tabInt[] = { 2 , 4 , 9 , 15 , 24 , 45}; elem = 4 deb = 0, fin = 5 On compare elem avec l'élément situé au milieu du tableau : tabInt[ (fin + deb) / 2] == elem → 9 == 4 → false Comme 9 > 4, on ré-itère la recherche dans la première moitié du tableau : deb = 0, fin = 1 tabInt[ (fin + deb) / 2] == elem → 2 == 4 → false Comme 2 < 4, on ré-itère la recherche dans la deuxième moitié de la partie du tableau qui vient d'être considérée: deb = 1, fin = 1 tabInt[ (fin + deb) / 2] == elem → 4 == 4 → true → élément trouvé
Récursivité sur les tableaux (15) Recherche dichotomique, principe (suite) : Initialement : tabInt[] = { 2 , 4 , 9 , 15 , 24 , 45}; elem = 45 deb = 0, fin = 5 On compare elem avec l'élément situé au milieu du tableau : tabInt[ (fin + deb) / 2] == elem → 9 == 45 → false Comme 9 < 45, on ré-itère la recherche dans la deuxième moitié du tableau : deb = 3, fin = 5 tabInt[ (fin + deb) / 2] == elem → 24 == 45 → false Comme 24 < 45, on ré-itère la recherche dans la deuxième moitié de la partie du tableau qui vient d'être considérée : deb = 5, fin = 5 tabInt[ (fin + deb) / 2] == elem → 45 == 45 → true → élément trouvé
Récursivité sur les tableaux (16) Recherche dichotomique, principe (suite) : Initialement : tabInt[] = { 2 , 4 , 9 , 15 , 24 , 45}; elem = 5 deb = 0, fin = 5 On compare elem avec l'élément situé au milieu du tableau : tabInt[ (fin + deb) / 2] == elem → 9 == 5 → false Comme 9 > 5, on ré-itère la recherche dans la première moitié du tableau : deb = 0, fin = 1 On réitère ... tabInt[ (fin + deb) / 2] == elem → 2 == 5 → false
Récursivité sur les tableaux (17) Comme 2 < 5, on ré-itère la recherche dans la deuxième moitié de la partie du tableau qui vient d'être considérée : tabInt[] = { 2 , 4 , 9 , 15 , 24 , 45}; elem = 5 deb = 1, fin = 1 On compare elem avec l'élément situé au milieu de la portion de tableau considérée : tabInt[ (fin + deb) / 2] == elem → 4 == 5 → false deb et fin ont la même valeur donc on ne peut plus réduire la partie du tableau dans laquelle on recherche l'élément → l'élément recherché n'est pas dans le tableau
Récursivité sur les tableaux (18) Recherche dichotomique, fonction : bool rech_dicho(int tabInt[], int taille, int elem, int deb, int fin){ int milieu = (deb+fin) /2; if(deb == fin){ return (tabInt[deb] == elem); } else { if(tabInt[milieu] == elem){ return true; if(tabInt[milieu] > elem){ return rech_dicho(tabInt, taille, elem, deb, milieu -1); return rech_dicho(tabInt, taille, elem, milieu +1, fin);
Récursivité sur les tableaux (19) #include <cini.h> bool rech_dicho(int tabInt[], int taille, int elem, int deb, int fin){ int milieu = (deb+fin) /2; if(deb == fin){ return (tabInt[deb] == elem); } else { if(tabInt[milieu] == elem){ return true; if(tabInt[milieu] > elem){ return rech_dicho(tabInt, taille, elem, deb, milieu -1); return rech_dicho(tabInt, taille, elem, milieu +1, fin); } int main(){ int tab[] = { 2 , 4 , 9 , 15 , 24 , 45}; bool res = rech_dicho(tab, 6, 2, 0, 5); CINI_print_string("rech dicho -> "); CINI_print_int(res); CINI_newline(); return 0; Remarque : on peut omettre le paramètre taille