IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Algorithmes et structures de données Discussion :

[Récursivité] Existe-t-il des cas où elle est inévitable ?


Sujet :

Algorithmes et structures de données

  1. #1
    Membre émérite
    Avatar de prgasp77
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Juin 2004
    Messages
    1 306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 306
    Points : 2 466
    Points
    2 466
    Par défaut [Récursivité] Existe-t-il des cas où elle est inévitable ?
    Bonjour à toutes et à tous.
    J'ai entendu des dizaines de fois des phrases comme "Ça me gêne d'utiliser une fonction récursive, mais j'ai pas le choix" ... Mais je pense, sans pouvoir le démontrer, qu'il est toujours possible de l'éviter.
    Quelqu'un pourrait-il, si cela existe, me trouver un cas où il n'est à priori pas possible de l'éviter ?

    Merci.
    -- Yankel Scialom

  2. #2
    Membre éclairé

    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    717
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 717
    Points : 858
    Points
    858
    Par défaut
    Toute fonction récursive peut-être transformée en fonction non-récursive, par exemple en utilisant une pile.

    D'ailleurs la machine de Turing n'est pas récursive, elle permet pourtant de calculer tout ce qui est calculable.

  3. #3
    Rédacteur
    Avatar de pseudocode
    Homme Profil pro
    Architecte système
    Inscrit en
    Décembre 2006
    Messages
    10 062
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte système
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2006
    Messages : 10 062
    Points : 16 081
    Points
    16 081
    Par défaut
    Citation Envoyé par prgasp77 Voir le message
    J'ai entendu des dizaines de fois des phrases comme "Ça me gêne d'utiliser une fonction récursive, mais j'ai pas le choix" ... Mais je pense, sans pouvoir le démontrer, qu'il est toujours possible de l'éviter.
    La récursivité est un style de programmation, ce n'est pas une solution "obligatoire" à un problème.

    C'est vrai qu'il est plus simple d'employer le style récursif lorsque l'algorithme utilise une méthode inductive (= un raisonnement par récurrence). Mais on peut très bien employer un autre style comme l'itératif ou le fonctionnel.

    De toutes façons, dans les langages impératifs, les appels récursifs sont transformés en appels séquentiels (call & return) avec une pile de mémoire pour sauvegarder/restaurer le contexte local entre chaque appel.
    ALGORITHME (n.m.): Méthode complexe de résolution d'un problème simple.

  4. #4
    Membre émérite
    Avatar de prgasp77
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Juin 2004
    Messages
    1 306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 306
    Points : 2 466
    Points
    2 466
    Par défaut
    Citation Envoyé par pseudocode Voir le message
    De toutes façons, dans les langages impératifs, les appels récursifs sont transformés en appels séquentiels (call & return) avec une pile de mémoire pour sauvegarder/restaurer le contexte local entre chaque appel.
    Exact ... cela constitue en quelque sort une preuve

    PS : j'aime beaucoup l'incrustation de ton père noël
    -- Yankel Scialom

  5. #5
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    Il faut tout de même voir que même si toute fonction récursive peut-être transformé en itération, ce n'est pas toujours pertinent de le faire, certaines solutions sont naturellement récursive et leur équivalent itératif demande de simuler la récursion par une structure de donnée type pile... L'intérêt est alors limité.
    Evidemment ça dépend aussi du langage, par exemple les langages qui optimisent la récursivité terminale n'ont pas besoin de boucles, par contraste, certains langages supportent très mal le style récursif parce que leur pile est trop petite ou les appels de fonctions trop couteux. C'est le cas par exemple du C et d'autres langages impératifs historiques, qui ont malheureusement forgé cette mauvaise réputation de la récursivité dans toute une génération de programmeurs.

    --
    Jedaï

  6. #6
    Rédacteur

    Homme Profil pro
    Comme retraité, des masses
    Inscrit en
    Avril 2007
    Messages
    2 978
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 83
    Localisation : Suisse

    Informations professionnelles :
    Activité : Comme retraité, des masses
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2007
    Messages : 2 978
    Points : 5 179
    Points
    5 179
    Par défaut
    Simple curiosité:
    L'algorithme de Strassen peut-il être programmé sans récursivité ?
    Jean-Marc Blanc
    Calcul numérique de processus industriels
    Formation, conseil, développement

    Point n'est besoin d'espérer pour entreprendre, ni de réussir pour persévérer. (Guillaume le Taiseux)

  7. #7
    Membre émérite
    Homme Profil pro
    Inscrit en
    Mai 2008
    Messages
    2 040
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 2 040
    Points : 2 841
    Points
    2 841
    Par défaut
    Bonjour.
    Ça me gêne d'utiliser une fonction récursive
    On évite d'utiliser la récursivité quand :
    - l'horizon est trops grand (nombre d'itérations qui nécessite des sauvegarde de mémoires et de registres)
    - en programmation temps-réel qui privilégie les interruptions.
    Mais on l'utilise quand on veut faire un "beau programme" (la programmation est aussi de l'art).
    La récursivité permet la meilleure concision (logiciel le plus court)
    exemple en Caml de la factorielle :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    let rec fac=fun 0 ->1 |n ->n*fac(n-1);;
    Que c'est beau!

  8. #8
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Jedai Voir le message
    Il faut tout de même voir que même si toute fonction récursive peut-être transformé en itération, ce n'est pas toujours pertinent de le faire, certaines solutions sont naturellement récursive et leur équivalent itératif demande de simuler la récursion par une structure de donnée type pile... L'intérêt est alors limité.
    Nous sommes d'accord jusqu'ici.

    Evidemment ça dépend aussi du langage, par exemple les langages qui optimisent la récursivité terminale n'ont pas besoin de boucles, par contraste, certains langages supportent très mal le style récursif parce que leur pile est trop petite ou les appels de fonctions trop couteux. C'est le cas par exemple du C et d'autres langages impératifs historiques, qui ont malheureusement forgé cette mauvaise réputation de la récursivité dans toute une génération de programmeurs.
    Il y a déjà assez de bonnes raisons pour critiquer le C que pour ne pas en inventer des fausses. Le C n'a pas de limitations intrinsèque sur la profondeur de pile -- elles sont le fait de l'OS -- et ses conventions d'appels de fonctions sont parmi les moins coûteuses qui soient, et historiquement c'est un des premiers langages avec les Lisp à permettre les appels récursifs sans marquage particulier. Il faut remonter à bien plus loin pour comprendre d'où vient la réputation de lenteur des appels de fonctions, et en particulier des appels de fonctions récursifs. Et ce n'est pas dû aux langages, mais aux architectures.

    Il a fallu du temps pour établir les conventions actuelles à base de pile. Une technique courante d'appel de fonction était de placer les paramètres à un endroit fixe en mémoire. L'adresse de retour était soit un des paramètres placés aux même endroit, soit carrément patchée dans l'instruction de saut terminant la routine. Naturellement, avec un tel mécanisme de base, les fonctions récursives étaient difficiles à supporter.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  9. #9
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    Désolé, ma formulation n'était pas très claire, je ne voulais pas dire que les appels de fonctions en C étaient couteux, c'était juste l'un des exemples de problèmes potentiel pour la récursivité dans un langage. Je disais simplement que C n'était pas adapté à la récursivité, d'une part parce que la pile est souvent trop petite (même si je suis d'accord que ce n'est pas spécifié dans le standard), d'autre part parce qu'il est très difficile d'écrire des closures ou même de simple fonctions imbriquées (ce n'est pas supporté par le langage), ce qui réduit l'intérêt de la récursivité pour le programmeur.

    --
    Jedaï

  10. #10
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    La tâche est clairement rendue aisée dans les langages fonctionnels c'est certain.
    Après, le plus important pour le PO c'est de saisir autant que possible les notions clés rattachées à la récursivité et la "façon de penser récursif". Le langage ne sera qu'un moyen de mettre en oeuvre finalement, comparé à la compréhension de la récursivité (terminale ou pas), ...

  11. #11
    Expert éminent sénior

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 603
    Détails du profil
    Informations personnelles :
    Âge : 66
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 603
    Points : 17 913
    Points
    17 913
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Il y a déjà assez de bonnes raisons pour critiquer le C que pour ne pas en inventer des fausses. Le C n'a pas de limitations intrinsèque sur la profondeur de pile -- elles sont le fait de l'OS -- et ses conventions d'appels de fonctions sont parmi les moins coûteuses qui soient, et historiquement c'est un des premiers langages avec les Lisp à permettre les appels récursifs sans marquage particulier. Il faut remonter à bien plus loin pour comprendre d'où vient la réputation de lenteur des appels de fonctions, et en particulier des appels de fonctions récursifs. Et ce n'est pas dû aux langages, mais aux architectures.



    Citation Envoyé par Jedai Voir le message
    Désolé, ma formulation n'était pas très claire, je ne voulais pas dire que les appels de fonctions en C étaient couteux, c'était juste l'un des exemples de problèmes potentiel pour la récursivité dans un langage. Je disais simplement que C n'était pas adapté à la récursivité, d'une part parce que la pile est souvent trop petite (même si je suis d'accord que ce n'est pas spécifié dans le standard), d'autre part parce qu'il est très difficile d'écrire des closures ou même de simple fonctions imbriquées (ce n'est pas supporté par le langage), ce qui réduit l'intérêt de la récursivité pour le programmeur.
    Euh franchement je ne te suis pas.... pour le C..

    Le C est très bien adapté à la récursivité dans certains cas, et comme on l'a dit la taille de la pile ne dépend pas en grande partie du langage...



    Citation Envoyé par Alp Voir le message
    La tâche est clairement rendue aisée dans les langages fonctionnels c'est certain.
    Après, le plus important pour le PO c'est de saisir autant que possible les notions clés rattachées à la récursivité et la "façon de penser récursif". Le langage ne sera qu'un moyen de mettre en oeuvre finalement, comparé à la compréhension de la récursivité (terminale ou pas), ...
    "Un homme sage ne croit que la moitié de ce qu’il lit. Plus sage encore, il sait laquelle".

    Consultant indépendant.
    Architecture systèmes complexes. Programmation grosses applications critiques. Ergonomie.
    C, Fortran, XWindow/Motif, Java

    Je ne réponds pas aux MP techniques

  12. #12
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Jedai Voir le message
    Je disais simplement que C n'était pas adapté à la récursivité, d'une part parce que la pile est souvent trop petite (même si je suis d'accord que ce n'est pas spécifié dans le standard),
    Je ne suis pas convaincu; j'attends toujours de voir le moment où elle m'explose à la figure pour autre chose qu'un bug. Et je n'ai pas peur d'utiliser la récursivité.

    d'autre part parce qu'il est très difficile d'écrire des closures ou même de simple fonctions imbriquées (ce n'est pas supporté par le langage)
    Ca je sais. Mais je ne vois pas le rapport avec

    ce qui réduit l'intérêt de la récursivité pour le programmeur.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  13. #13
    Membre émérite
    Avatar de SpiceGuid
    Homme Profil pro
    Inscrit en
    Juin 2007
    Messages
    1 704
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 704
    Points : 2 990
    Points
    2 990
    Par défaut
    D'ailleurs la machine de Turing n'est pas récursive, elle permet pourtant de calculer tout ce qui est calculable.
    Très bon exemple

    Voici mon implémentation (oui, contrairement aux apparences, elle est bien récursive terminale!) de la machine de Turing universelle inventée en 1962 par Marvin Minsky
    (http://mathworld.wolfram.com/Univers...ngMachine.html) :
    Code OCaml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    (* les 4 couleurs *)
    type color =
      C3 | C2 | C1 | C0
    
    (* une transition: écrire une couleur c, curseur + i, passer à l'état s *)
    let trans (c3,c2,c1,c0) (i3,i2,i1,i0) (s3,s2,s1,s0) tape cursor =
      match tape.(cursor) with
      | C3 -> tape.(cursor) <- c3; s3 tape (i3 cursor)
      | C2 -> tape.(cursor) <- c2; s2 tape (i2 cursor)
      | C1 -> tape.(cursor) <- c1; s1 tape (i1 cursor)
      | C0 -> tape.(cursor) <- c0; s0 tape (i0 cursor)
    
    (* arrêter la machine *)
    let stop cursor = cursor
    let halt tape cursor = () 
    
    (* les 7 états et leur transition associée *)
    let
    rec s0 t = trans (C2,C0,C3,C2) (pred,pred,succ,succ) (s4,s1,s0,s0) t
    and s1 t = trans (C1,C0,C3,C0) (pred,pred,succ,pred) (s1,s1,s0,s1) t
    and s2 t = trans (C1,C2,C3,C2) (succ,succ,succ,pred) (s2,s2,s2,s4) t
    and s3 t = trans (C1,C2,C3,C3) (succ,succ,succ,pred) (s3,s3,s3,s4) t
    and s4 t = trans (C1,C2,C3,C0) (pred,pred,pred,stop) (s5,s4,s4,halt) t
    and s5 t = trans (C1,C2,C1,C2) (pred,pred,pred,succ) (s5,s5,s6,s2) t
    and s6 t = trans (C0,C0,C1,C2) (succ,succ,succ,succ) (s0,s6,s6,s3) t
    Maintenant j'aimerais bien voir :
    • une implémentation itérative tout aussi élégante
    • une implémentation récursive en C qui ne déborderait pas la pile
    Du même auteur: mon projet, le dernier article publié, le blog dvp et le jeu vidéo.
    Avant de poser une question je lis les règles du forum.

  14. #14
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 101
    Points : 5 849
    Points
    5 849
    Par défaut
    Citation Envoyé par FR119492 Voir le message
    Simple curiosité:
    L'algorithme de Strassen peut-il être programmé sans récursivité ?
    Jean-Marc Blanc
    Ben oui, comme tout le reste: il suffit d'implémenter la récursivité sans récursivité!

    Mais ça risque d'être coûteux!

    )jack(

  15. #15
    Rédacteur

    Homme Profil pro
    Comme retraité, des masses
    Inscrit en
    Avril 2007
    Messages
    2 978
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 83
    Localisation : Suisse

    Informations professionnelles :
    Activité : Comme retraité, des masses
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2007
    Messages : 2 978
    Points : 5 179
    Points
    5 179
    Par défaut
    Mais ça risque d'être coûteux!
    Ce n'est pas trop grave, puisqu'en pratique personne n'utilise l'algorithme de Strassen!
    Jean-Marc Blanc
    Calcul numérique de processus industriels
    Formation, conseil, développement

    Point n'est besoin d'espérer pour entreprendre, ni de réussir pour persévérer. (Guillaume le Taiseux)

  16. #16
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par SpiceGuid Voir le message
    Maintenant j'aimerais bien voir :
    • une implémentation itérative tout aussi élégante
    Tu donnes une implémentation itérative (la récursivité terminale, c'est de
    l'itération, en particulier quand on dépend du fait qu'elle est compilée
    comme telle!) et tu demandes à voir une implémentation itérative tout aussi
    élégante? Bon, virer la récursivité terminale, c'est trivial. Voici le
    coeur exprimé en C -- c'est de la pure translittération.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    #define STATE(c0, c1, c2, c3, s0, s1, s2, s3, n0, n1, n2, n3) \
    switch(tape[pos]) { \
    case C3: tape[pos] = c0; pos += s0; goto n0; \
    case C2: tape[pos] = c1; pos += s1; goto n1; \
    case C1: tape[pos] = c2; pos += s2; goto n2; \
    case C0: tape[pos] = c3; pos += s3; goto n3; \
    } \
    break
     
    ...
    S2: STATE(C1, C0, C3, C0, +1, +1, +1, -1, S2, S2, S2, S4);
    ...
    Dans un language sans macro, c'est un peu plus redondant. Quoiqu'en Algol
    (un langage de 1960!) ou en Pascal (le vrai!) qui peuvent passer des
    labels comme paramètre, ca ne pose naturellement aucun problème de
    concision non plus.

    En passant, j'ai du mal à voir en quoi elle est particulièrement élégante.
    Je préfère une implémentation plus purement conduite par les données:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    while (state >= 0) {
        StateDesc desc = transitions[state, tape[pos]];
        tape[pos] = desc.new_color;
        pos += desc.step;
        state = desc.next_state;
    }
    • une implémentation récursive en C qui ne déborderait pas la pile
    J'ai deux compilateurs C ici (gcc, SunStudio), tous les deux remplacent les appels finaux par des sauts
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  17. #17
    Membre émérite
    Avatar de SpiceGuid
    Homme Profil pro
    Inscrit en
    Juin 2007
    Messages
    1 704
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 704
    Points : 2 990
    Points
    2 990
    Par défaut
    En passant, j'ai du mal à voir en quoi elle est particulièrement élégante.
    L'élégance est une notion assez personnelle.
    Disons que mon implantation est complète et "minimale", il n'y a pas de variables globales, si je devais multithreader il n'y aurait rien à ajouter.
    Du même auteur: mon projet, le dernier article publié, le blog dvp et le jeu vidéo.
    Avant de poser une question je lis les règles du forum.

Discussions similaires

  1. Réponses: 17
    Dernier message: 10/07/2015, 16h58
  2. [WD-2010] TextBox affichant des indications quand elle est vide
    Par Tho69 dans le forum Word
    Réponses: 0
    Dernier message: 29/08/2013, 10h09
  3. ajouter des lignes qd elles n'existent pas
    Par freestyler dans le forum Shell et commandes GNU
    Réponses: 4
    Dernier message: 30/01/2008, 15h28
  4. existe t 'il des programme pour transformer les bases
    Par creazone dans le forum Décisions SGBD
    Réponses: 1
    Dernier message: 05/10/2004, 14h11
  5. Existe-t-il des Dé-compilateurs sur Terre?
    Par Julien_riquelme dans le forum Autres éditeurs
    Réponses: 11
    Dernier message: 15/12/2003, 01h46

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo