68 votes

La Tour de Hanoi : Algorithme récursif

Bien que je n'aie aucun problème à comprendre la récursion, je ne parviens pas à comprendre la solution récursive du problème de la tour de Hanoi. Voici le code de Wikipedia :

procedure Hanoi(n: integer; source, dest, by: char);
Begin
    if (n=1) then
        writeln('Move the plate from ', source, ' to ', dest)
    else begin
        Hanoi(n-1, source, by, dest);
        writeln('Move the plate from ', source, ' to ', dest);
        Hanoi(n-1, by, dest, source);
    end;
End;

Je comprends le cas de base et le concept de décomposer le problème en petits morceaux jusqu'à ce que vous soyez en mesure de déplacer un seul disque. Cependant, je n'arrive pas à comprendre comment les deux appels récursifs dans le cas non basique fonctionnent ensemble. Peut-être quelqu'un peut-il m'aider ? Merci.

3 votes

Ce code pourrait être amélioré en vérifiant si n=0 et en ne faisant rien dans ce cas, pour éviter la duplication du déplacement.

0 votes

Cela pourrait aider : learneroo.com/modules/71/nodes/402

3 votes

J'ai écrit un article de blog sur la récursion elle-même. Il va très loin et, honnêtement, il faut un certain temps pour le comprendre, mais une fois que vous l'avez visualisé, il est beaucoup plus logique. Sérieusement, économisez votre temps et consultez cet article : dima.to/blog/?p=29

48voto

Joey Points 148544

En fait, le la section d'où vous avez pris ce code offre également une explication :

Pour déplacer n disques du pion A au pion C :

  1. déplacer n1 disques de A à B. Cela laisse le disque n seul sur la cheville A.
  2. déplacer le disque n de A à C
  3. déplacer n1 disques de B à C pour qu'ils se trouvent sur le disque #n

C'est assez clair que vous devez d'abord enlever n 1 disques pour avoir accès à la n e. Et que vous devez d'abord les déplacer sur un autre piquet que celui où vous voulez que la tour complète apparaisse.

Le code dans votre post a trois arguments, en plus du nombre de disques : A source cheville, un destination et un temporaire sur lequel les disques peuvent être stockés entre les deux (où chaque disque de taille n 1 correspond).

La récursion se produit en fait deux fois, ici, une fois avant que les writeln et une fois après. Celui qui précède le writeln bougera n 1 disques sur la cheville temporaire, en utilisant la cheville de destination comme stockage temporaire (les arguments dans l'appel récursif sont dans un ordre différent). Après cela, le disque restant sera déplacé vers le piquet de destination et ensuite la deuxième récursion compulse le déplacement de la tour entière, en déplaçant les disques de la tour. n 1 tour de la cheville provisoire à la cheville de destination, au-dessus du disque. n.

0 votes

La seule façon de déplacer le disque n de A à C est de faire deux choses : (1) retirer tous les petits disques du disque n (qui est toujours sur la cheville A). (2) s'assurer que la cheville C est prête à recevoir le disque #n. La seule façon d'y parvenir est de placer tous les autres disques sur la cheville B afin qu'ils ne soient pas sur le chemin.

0 votes

@JasonS Je suis clair avec les étapes 1 et 2, mais je n'ai pas pu obtenir la 3ème étape. Pouvez-vous m'expliquer pourquoi ?

0 votes

Hum... mon message date d'il y a 2 ans et demi.... si vous voulez dire "La seule façon de faire cela est de mettre tous ces autres disques sur la cheville B pour qu'ils ne soient pas dans le chemin", vous pouvez le faire récursivement : les disques 1 à n sont sur la cheville A donc tous les disques sur la cheville B sont plus grands que n.

32voto

f0b0s Points 1130

Il y a un an j'ai eu un cours de programmation fonctionnelle et j'ai dessiné cette illustration pour l'algorithme. J'espère que cela vous aidera !

(0)  _|_         |          |
    __|__        |          |
   ___|___       |          |
  ____|____  ____|____  ____|____

(1.1) |          |          |
    __|__        |          |
   ___|___      _|_         |
  ____|____  ____|____  ____|____ (A -> B)

(1.2) |          |          |
      |          |          |
   ___|___      _|_       __|__
  ____|____  ____|____  ____|____ (A -> C)

(1.3) |          |          |
      |          |         _|_
   ___|___       |        __|__
  ____|____  ____|____  ____|____ (B -> C)

(2.1) |          |          |
      |          |         _|_
      |       ___|___     __|__
  ____|____  ____|____  ____|____ (A -> B)

(3.1) |          |          |
      |          |          |
     _|_      ___|___     __|__
  ____|____  ____|____  ____|____ (C -> A)

(3.2) |          |          |
      |        __|__        |
     _|_      ___|___       |
  ____|____  ____|____  ____|____ (C -> B)

(3.3) |         _|_         |
      |        __|__        |
      |       ___|___       |
  ____|____  ____|____  ____|____ (A -> B)

Le problème des 3 anneaux a été divisé en 2 problèmes de 2 anneaux (1.x et 3.x).

14voto

matthock Points 420

Une bonne explication de l'implémentation récursive de Hanoi se trouve à l'adresse suivante http://www.cs.cmu.edu/~cburch/survey/recurse/hanoiimpl.html .

En résumé, si vous voulez déplacer la plaque inférieure du bâton A vers le bâton B, vous devez d'abord déplacer toutes les plaques plus petites situées au-dessus de A vers C. Le deuxième appel récursif consiste alors à déplacer les plaques que vous avez déplacées vers C vers B après que votre cas de base ait déplacé la grande plaque unique de A vers B.

13voto

Sean Points 3298

Je reconnais que celui-ci n'est pas immédiat quand on le regarde pour la première fois, mais il est assez simple quand on s'y met.

Cas de base : votre tour est de taille 1. Vous pouvez donc le faire en un seul mouvement, de la source directement à la destination.

Cas récursif : votre tour est de taille n > 1. Vous déplacez donc la tour supérieure de taille n-1 sur un piquet supplémentaire (by), vous déplacez la "tour" inférieure de taille 1 sur le piquet de destination, et vous déplacez la tour supérieure de by à dest.

Ainsi, dans un cas simple, vous avez une tour de hauteur 2 :

 _|_    |     |
__|__   |     |
===== ===== =====

Première étape : déplacez la tour supérieure de 2-1 (=1) vers la cheville supplémentaire (celle du milieu, par exemple).

  |     |     |
__|__  _|_    |
===== ===== =====

Suivant : déplacez le disque inférieur vers la destination :

  |     |     |
  |    _|_  __|__
===== ===== =====

Et enfin, déplacer la tour supérieure de (2-1)=1 vers la destination.

  |     |    _|_
  |     |   __|__
===== ===== =====

Si vous y réfléchissez, même si la tour était de 3 ou plus, il y aura toujours un piquet supplémentaire vide, ou un piquet avec tous les disques les plus grands, que la récursion pourra utiliser pour échanger les tours.

0 votes

Je pense que la clé est que, dans tous les problèmes de récursion, nous devons d'abord penser à un cas d'utilisation simple et le résoudre avec un algorithme, puis appliquer la même chose à plus d'entrées.Merci !

4voto

Supposons que nous voulions déplacer un disque de A à C en passant par B alors :

  1. déplacer un disque plus petit vers B.
  2. déplacer un autre disque vers C.
  3. déplacer B vers C.
  4. se déplacer de A à B.
  5. déplacer tout de C à A.

Si vous répétez toutes les étapes ci-dessus, le disque sera transféré.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X