返回未按预期退出递归方法-C#

时间:2018-09-10 13:59:09

标签: c# recursion collatz

这应该是非常基本的。 我觉得我缺少明显的东西,但是我已经盯着它看了一段时间了。 我有一个创建Collat​​z序列的递归方法(用作递归实践) 但是,一旦我的方法达到退出要求,我就会有一个“返回值”,然后返回到该方法内的递归调用。 如果有人能告诉我我想念的东西,我将不胜感激! 谢谢,下面的代码!

public int sequenceCreator(int currentVal, int numOfSteps)
    {
        int nextVal;
        while (currentVal != 1)
        { 
            if (currentVal % 2 == 0)
            {
                nextVal = currentVal / 2;
                numOfSteps++;
            }
            else // (currentVal % 2 > 0)
            {
                nextVal = (currentVal * 3) + 1;
                numOfSteps++;
            }
            return sequenceCreator(nextVal, numOfSteps);
        }

        return numOfSteps;
    }

3 个答案:

答案 0 :(得分:0)

return仅退出该特定方法调用。它并不会终止调用sequenceCreator()的所有时间。

在这种情况下,应该可以,因为它会返回到此行:

return sequenceCreator(nextVal, numOfSteps);

依次返回到其调用者,依此类推,直到最终解决所有递归调用。

但是我可以这样写方法:

public int sequenceCreator(int currentVal)
{
    if (currentVal == 1) return 1;

    if (currentVal % 2 == 0)
    {
        return 1 + sequenceCreator(currentVal / 2);
    }
    else // (currentVal % 2 > 0)
    {
        return 1 + sequenceCreator(currentVal * 3 + 1);
    }
}

对于相同的输入,该代码会产生相同的结果,但是使用更少的代码却更易于理解,并且不需要在方法调用之间传递额外的状态。

为了好玩,我们可以使用三元运算符进一步减少代码(但由于imo可读性差,我不建议使用此版本):

public int sequenceCreator(int currentVal)
{
    if (currentVal == 1) return 1;
    return 1 + sequenceCreatetor(currentValue % 2 == 0? currentVal / 2 : currentVal * 3 + 1);
}

我显示此版本以说明为什么使用 递归。从本质上讲,递归问题就是堆栈问题。对于每个递归解决方案,都有一个匹配解决方案,该解决方案仅依赖于传统方法,而是使用堆栈(递归解决方案仅依靠程序的调用堆栈来“隐藏”堆栈)。但是,对于某些类型的问题,递归可以大大减少解决该问题所需的代码量。因此,我们也有相反的说法。如果您发现自己使用堆栈,则可以使用 来大大简化问题。在这种情况下,方法主体只有两行,如果我真的愿意,我可以将其简化为一行代码。

您还需要了解,此操作不会创建序列。在完全收敛的情况下,它会创建一个恰好一个值。如果您实际上要创建一个序列,则需要返回一个IEnumerable,最好使用yield关键字:

public IEnumerable<int> sequenceCreator(int currentVal)
{
    if (currentVal == 1) yield return 1;

    if (currentVal % 2 == 0)
    {
        yield return 1 + sequenceCreator(currentVal / 2);
    }
    else // (currentVal % 2 > 0)
    {
        yield return 1 + sequenceCreator(currentVal * 3 + 1);
    }
}

从逻辑上讲,我认为您在这里很安全,并且会收敛。此方法的“最终”或基本情况是1的输入。在基本情况下调用甚至减少输入的位置。输入为奇数的调用从基本情况开始增加,但以这种方式使下一个输入始终为偶数,并且始终与我们之前尝试的值不同。最终,我们希望以2的幂或3的2的幂结束,即使将其减小到32,然后是{{1} },然后退出。

但是,我担心可能存在一些永远不会达到此状态的值,或者在它们可以溢出之前溢出整数,或者在增加几次之后减小到我们已经拥有的均匀值尝试,从而创造了一个永无止境的循环。

答案 1 :(得分:-1)

我认为不应有任何循环。使用if条件而不是while。

如果(currentVal!= 1)

答案 2 :(得分:-2)

如果可能,请避免递归:

        int sequenceNumber = Convert.ToInt32(Console.ReadLine());
        List<int> list = new List<int>();

        while (sequenceNumber>=1)
        {
            if (sequenceNumber == 1)
            {
                Console.WriteLine(1);
                sequenceNumber = Convert.ToInt32(Console.ReadLine());
            }

            else if(sequenceNumber>1)
            {
                while (sequenceNumber>=1)
                {
                    if (sequenceNumber == 1)
                    {
                        list.Add(sequenceNumber);
                    }

                    else if (sequenceNumber % 2 == 0)
                    {
                        list.Add(sequenceNumber);
                        sequenceNumber = sequenceNumber / 2;

                    }
                    else if (sequenceNumber % 2 != 0)
                    {
                        list.Add(sequenceNumber);
                        sequenceNumber = sequenceNumber * 3 + 1;

                    }
                }

                list.ForEach(Console.WriteLine);
                foreach (int i in list)
                {
                    Console.Write(i + " ");

                }
            }

            sequenceNumber = Convert.ToInt32(Console.ReadLine());
        } 
    }
相关问题