用递归解决C#中的河内塔

时间:2016-02-09 17:51:36

标签: c# recursion towers-of-hanoi

我正面对河内塔问题,我从wikipedia读到了解决它的概念和递归方式,但是我无法看到维基百科中提到的步骤实现中缺少的内容

我在这里看过很多例子,但我不希望我的程序打印步骤,我希望程序解决了在3个集合之间移动“光盘”的问题,在我的代码中我使用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}");
        }
    }
}

2 个答案:

答案 0 :(得分:2)

为了制作递归方法,您需要一个或多个基本情况,其中递归将结束,然后一个或多个递归调用将问题分解为更接近其中一个基本情况。对于河内之塔,我们的想法是将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 == 1)
    {
        toPeg.Push(fromPeg.Pop());
        return;
    }

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

    toPeg.Push(fromPeg.Pop());

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

答案 1 :(得分:0)

实施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);
    }
}

}