使用递归在 C# 中解决汉内塔

Solving Towers of Hanoi in C# using recursion

我遇到了汉诺塔问题,我从 wikipedia 那里读到了概念和解决它的递归方法,但我看不出我在执行上述步骤时遗漏了什么在维基百科中。

我在这里看到了很多例子,但我不希望我的程序打印这些步骤,我希望程序解决在 3 个集合之间移动 "discs" 的问题,在我的代码中我使用 3堆叠模拟钉子。

这是我当前的代码:

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        var hs = new HanoiSolver(discs: 3);

        hs.Solve();

        Console.ReadKey();
    }
}

class HanoiSolver
{
    private int TotalDiscs { get; set; } = 0;
    private Stack<int> FirstPeg { get; set; } = new Stack<int>();
    private Stack<int> SecondPeg { get; set; } = new Stack<int>();
    private Stack<int> ThirdPeg { get; set; } = new Stack<int>();

    public HanoiSolver(int discs = 3)
    {
        TotalDiscs = discs;

        //Create list of items (discs)
        var discList = Enumerable.Range(1, TotalDiscs).Reverse();

        //Add items (discs) to first peg
        foreach (var d in discList)
        {
            FirstPeg.Push(d);
        }
    }

    public void Solve()
    {
        if (ThirdPeg.Count != TotalDiscs)
        {
            PrintPegs();

            //Move first item from firstpeg to secondpeg
            if (FirstPeg.Any())
            {
                var fp_f = FirstPeg.Pop();
                SecondPeg.Push(fp_f);
            }

            PrintPegs();

            //Move second item from firstpeg to thirdpeg
            if (FirstPeg.Any())
            {
                var fp_s = FirstPeg.Pop();
                ThirdPeg.Push(fp_s);
            }

            PrintPegs();

            //Move first item from secondpeg to thirdpeg
            if (SecondPeg.Any())
            {
                var sp_f = SecondPeg.Pop();
                ThirdPeg.Push(sp_f);
            }

            PrintPegs();

            Solve();
        }
    }

    private void PrintPegs()
    {
        var fp = FirstPeg.Select(x => x.ToString()).ToList();

        if (fp.Count < TotalDiscs)
        {
            fp.AddRange(Enumerable.Repeat(string.Empty, (TotalDiscs - fp.Count)));
        }

        var sp = SecondPeg.Select(x => x.ToString()).ToList();

        if (sp.Count < TotalDiscs)
        {
            sp.AddRange(Enumerable.Repeat(string.Empty, (TotalDiscs - sp.Count)));
        }

        var tp = ThirdPeg.Select(x => x.ToString()).ToList();

        if (tp.Count < TotalDiscs)
        {
            tp.AddRange(Enumerable.Repeat(string.Empty, (TotalDiscs - tp.Count)));
        }

        Console.WriteLine($"{"[First Peg]",10}" + $"{"[Second Peg]",10}" + $"{"[Third Peg]",10}");

        for (var i = 0; i < TotalDiscs; i++)
        {
            Console.WriteLine($"{fp[i],10}" +
                              $"{sp[i],10}" +
                              $"{tp[i],10}");
        }
    }
}

为了创建递归方法,您需要一个或多个递归结束的基本情况,然后进行一个或多个递归调用,将问题分解为更接近基本情况之一。对于汉诺塔,想法是将 n 个圆盘从 Peg A 移动到 Peg C 只是将 n-1 从 Peg A 移动到 Peg B,然后将第 n 个从 A 移动到 C,最后将 n-1 个圆盘从 C 移动到 B . 这最终会让你不移动光盘,这是你的基本情况。这可以通过递归方法非常简单地完成。

private static void Move(
    int discs, 
    Stack<int> fromPeg, 
    Stack<int> toPeg, 
    Stack<int> otherPeg)
{
    if (discs == 0)
    {
        return;
    }

    Move(discs - 1, fromPeg, otherPeg, toPeg);

    toPeg.Push(fromPeg.Pop());

    Move(discs -1, otherPeg, toPeg, fromPeg);
}

当您实施 TOH 时,这意味着您是 DS 和数据类型的新手。因此必须使用 DS 中不存在的数据类型,如堆栈和队列。所以下面的方法是使用数组。

使用系统; 使用静态 System.Console; 名称空间 TOH {

class Program
{
    // Problem statement
    //Create an array tower(a) containing all element in ascending order

    public static int[] towerSource = new int[] { 1, 3, 5,6,7,9,11,12,13,14,15,16,17};

    //solution statement
    //we have two more towers with same capacity, tower(b) as auxiliary and tower(c) as destination
    public static int[] towerAuxiliary;
    public static int[] towerDestination;

    public static void CreateTowers()
    {
        towerAuxiliary = new int[towerSource.Length];
        towerDestination = new int[towerSource.Length];
    }

    public static void Print(int[] tower)
    {
        for (int i = 0; i < tower.Length; i++)
            Write(tower[i].ToString());
        WriteLine("--------next run-------------");
    }       
    //start operation
    public static void TOH(int numberOfDisks, int[] source,int[] auxiliary,int[] destination)
    {
        //check if there is only one disk in source
        if(numberOfDisks == 1)
        {
            //move to destination and come out
            towerDestination[numberOfDisks-1] = towerSource[numberOfDisks-1];
            Print(towerDestination);
            return;
        }

        //move n-1 disks from source to auxiliary
        TOH(numberOfDisks - 1, towerSource, towerAuxiliary, towerDestination);
        towerDestination[numberOfDisks-1] = towerSource[numberOfDisks-1];

        //move nth disc from source to dest
        //this is being handeled by if condition

        //move n-1 disks from auxiliary to dest
        TOH(numberOfDisks - 1, towerAuxiliary, towerSource, towerDestination);

        return;
    }


    static void Main(string[] args)
    {
        CreateTowers();
        TOH(towerSource.Length, towerSource, towerAuxiliary, towerDestination);
    }
}

}