TD d algorithmique avacée Corrigé du TD : récursivité Jea-Michel Dischler et Frédéric Vivie Suite de Fiboacci La suite de Fiboacci est défiie comme suit : 1 si = 0 Fib() = 1 si = 1 Fib( 1) + Fib( ) sio. 1. Écrivez u algorithme récursif calculat Fib(). Fiboacci() si = 0 ou = 1 alors revoyer 1 sio revoyer Fiboacci( 1) + Fiboacci( ). Motrez que la complexité (e ombre d additios) de cet algorithme est e Ω( ). O procède par récurrece. O veut motrer qu il existe ue costate c strictemet positive telle que T () c., pour des valeurs de supérieures à ue certaie bore 0 (à détermier). Supposos le résultat démotré jusqu au rag 1. Alors : T () = T ( 1) + T ( ) + 1 c. 1 + c + 1 c. + c. + 1 c. = c. Il ous reste juste à motrer que cette équatio est vraie «au départ». Nous e pouvos bie évidemmet pas partir des cas = 0 et = 1, puisque pour ces valeurs T () = 0. Nous partos doc des cas = et = 3 (la récurrece écessite deux valeurs de départ) : Cas = : Fiboacci() = Fiboacci(1) + Fiboacci(0), et T () = 1. Pour que la propriété désirée soit vraie, c doit doc vérifier : 1 c. = c c 1 Cas = 3 : Fiboacci(3) = Fiboacci() + Fiboacci(1), et T (3) =. Pour que la propriété désirée soit vraie, c doit doc vérifier : c. 3 = c c Doc si c = 1, pour, o a T () c et doc T () = Ω( ). 3. Écrire u algorithme récursif qui calcule, pour > 0, le couple (Fiboacci(), Fiboacci( 1)). Fib-Paire() si = 1 alors revoyer (1, 1) sio (x, y) = Fib-Paire( 1) revoyer (x + y, x) 4. Utilisez l algorithme précédet pour écrire u ouvel algorithme calculat Fiboacci(). 1
Fiboacci() si = 0 alors revoyer 1 sio (x, y) = Fib-Paire() revoyer x 5. Qu elle est la complexité (e ombre d additios) de cet algorithme? La complexité de l algorithme Fib-Paire, e ombre d additios, est doée par la récurrece T () = 1 + T ( 1). O a doc T () = 1 pour Fib-Paire, et par extesio pour la ouvelle versio de Fiboacci. Opératios esemblistes Das cette partie o cosidère des esembles représetés par des tableaux, certais esembles serot triés et d autres pas. Toutes les solutios proposées doivet être récursives. 1. Nous voulos u algorithme Apparteace(A, x) qui recherche si u élémet x appartiet à l esemble A. Si x appartiet effectivemet à A, l algorithme reverra Vrai, et Faux sio. Recherche(A, rag, x) si rag > logueur(a) alors revoyer Faux si A[rag] = x alors revoyer Vrai sio revoyer Recherche(A, rag + 1, x) L appel iitial de l algorithme est alors Recherche(A, 1, x). ii. Quelle est sa complexité e ombre de comparaisos? Das le pire cas, l élémet appartiet pas à l esemble et tout le tableau est parcouru. La complexité au pire est doc e Θ(), où est la logueur du tableau (et doc la taille de l esemble). Recherche(A, rag, x) si rag > logueur(a) ou A[rag] > x alors revoyer Faux sio si A[rag] = x alors revoyer Vrai sio revoyer Recherche(A, rag + 1, x) L appel iitial de l algorithme est alors Recherche(A, 1, x). ii. Quelle est sa complexité e ombre de comparaisos? Le pire cas est aussi e Θ() : il iterviet quad l élémet recherché appartiet pas à l esemble mais est plus grad que tous les élémets de l esemble. iii. Utilisez ue recherche dichotomique pour améliorer votre algorithme. Recherche(A, x, if, sup) milieu if +sup si A[milieu] = x alors revoyer Vrai sio si A[milieu] > x alors revoyer Recherche(A, x, if, milieu - 1) sio revoyer Recherche(A, x, milieu + 1, sup)
iv. Quelle est la complexité de votre ouvel algorithme? Posos = sup if +1 le ombre d élémets das la partie du tableau à étudier. Cosidéros la taille du tableau lors de l évetuel appel récursif. Nous avos deux cas à cosidérer : L appel effectué est : Recherche(A, x, if, milieu - 1). Le ombre d élémets cocerés sup if. est alors : milieu 1 if + 1 = = 1 L appel effectué est : Recherche(A, x, milieu + 1, sup). Le ombre d élémets cocerés est alors : sup (milieu + 1) + 1 = sup if = 1. O passe doc d u esemble de taille à u esemble de taille au plus. D où T () T ( ) (la foctio T () état croissate, o peut se permettre l approximatio). Par coséquet : T () log ()T ( ) et T () = O(log log ).. Nous voulos maiteat u algorithme Uio(A, B) qui ous revoie l uio des deux esembles qui lui sot passés e argumet. Uio(A, B, rag, C) si Recherche(A, B[rag]) = Faux C[logueur(C)] B[rag] Uio(A, B, rag + 1, C) L appel iitial est alors Uio(A, B, 1, C) où C est u tableau de taille logueur(a) + logueur(b), et dot les logueur(a) premières cases cotieet les élémets de A. La recopie de A das C est de coût logueur(a). L algorithme Uio est appelé logueur(b) fois, chacu de ces appels effectuat u appel à Recherche sur A, dot le coût au pire est e logueur(a). La complexité au pire de Uio est doc e Θ(logueur(A) logueur(b)) ou Θ(m), et m déotat la taille des deux tableaux. Ce pire cas apparaît quad les tableaux A et B sot disjoits. Uio(A, a, B, b, C) si a > logueur(a) et b > logueur(b) alors revoyer C si b > logueur(b) ou B[b] > A[a] Uio(A, a + 1, B, b, C) sio logueur(c) logueur(c) + 1 C[logueur(C)] B[b] si a logueur(a) et A[a] = B[b] alors Uio(A, a + 1, B, b + 1, C) sio Uio(A, a, B, b + 1, C) L appel iitial est Uio(A, 1, B, 1, C). La complexité de cet algorithme est au pire e Θ(logueur(A) + logueur(b)) ou Θ( + m) : 3. Nous voulos maiteat u algorithme Itersectio(A, B) qui ous revoie l itersectio des deux esembles qui lui sot passés e argumet. 3
Itersectio(A, B, rag, C) si Recherche(A, B[rag]) = Vrai C[logueur(C)] B[rag] Itersectio(A, B, rag + 1, C) L appel iitial est alors Itersectio(A, B, 1, C) où C est u ouveau tableau, de taille mi(logueur(a), logueur(b)), et e coteat iitialemet aucu élémet (logueur(c) = 0). L algorithme Itersectio est appelé logueur(b) fois, chacu de ces appels effectuat u appel à Recherche sur A, dot le coût au pire est e logueur(a). La complexité au pire de Itersectio est doc e Θ(logueur(A) logueur(b)) ou Θ(m), et m déotat la taille des deux tableaux. Ce pire cas apparaît quad les tableaux A et B sot disjoits. Itersectio(A, a, B, b, C) si a > logueur(a) ou b > logueur(b) alors revoyer C si A[a] = B[b] revoyer Itersectio(A, a + 1, B, b + 1, C) sio si B[b] > A[a] alors revoyer Itersectio(A, a + 1, B, b, C) sio revoyer Itersectio(A, a, B, b + 1, C) L appel iitial est Itersectio(A, 1, B, 1, C, 0). La complexité de cet algorithme est au pire e Θ(logueur(A) + logueur(b)) ou Θ( + m) : 4. Nous voulos maiteat u algorithme Différece(A, B) qui ous revoie la différece des deux esembles qui lui sot passés e argumet (La différece de A et de B, otée A \ B est l esemble des élémets de A apparteat pas à B). Différece(A, rag, B, C) si Recherche(B, A[rag]) = Faux C[logueur(C)] A[rag] Différece(A, rag + 1, B, C) L appel iitial est alors Différece(A, 1, B, C) où C est u tableau de taille logueur(a), e coteat iitialemet aucu élémet (logueur(c) = 0). L algorithme Différece est appelé logueur(a) fois, chacu de ces appels effectuat u appel à Recherche sur B, dot le coût au pire est e logueur(b). La complexité au pire de Différece est doc e Θ(logueur(A) logueur(b)) ou Θ(m), et m déotat la taille des deux tableaux. Ce pire cas apparaît quad les tableaux A et B sot disjoits. 4
Différece(A, a, B, b, C) si a > logueur(a) alors revoyer C si A[a] = B[b] alors revoyer Différece(A, a + 1, B, b + 1, C) sio si A[a] < B[b] revoyer Différece(A, a + 1, B, b, C) sio revoyer Différece(A, a, B, b + 1, C) L appel iitial est Différece(A, 1, B, 1, C, 0). La complexité de cet algorithme est au pire e Θ(logueur(A) + logueur(b)) ou Θ( + m) : 5