我在学校里很难理解递归。每当教授谈到它的时候,我似乎都懂了,但当我自己尝试的时候,它完全震撼了我的大脑。
我整晚都在尝试着解决《Towers of Hanoi》这款游戏,结果完全出乎我的意料。我的课本只有大约30页关于递归的内容,所以它不是很有用。有人知道哪些书籍或资源可以帮助澄清这个话题吗?
我在学校里很难理解递归。每当教授谈到它的时候,我似乎都懂了,但当我自己尝试的时候,它完全震撼了我的大脑。
我整晚都在尝试着解决《Towers of Hanoi》这款游戏,结果完全出乎我的意料。我的课本只有大约30页关于递归的内容,所以它不是很有用。有人知道哪些书籍或资源可以帮助澄清这个话题吗?
当前回答
http://javabat.com是一个有趣而令人兴奋的练习递归的地方。他们的例子开始时相当简单,然后逐步扩展(如果你想这么做的话)。注意:他们的方法是在实践中学习。这是我写的一个递归函数,用来替换for循环。
for循环:
public printBar(length)
{
String holder = "";
for (int index = 0; i < length; i++)
{
holder += "*"
}
return holder;
}
这是做同样事情的递归。(请注意,我们重载了第一个方法,以确保它像上面那样使用)。我们还有另一种方法来维护索引(类似于上面的for语句)。递归函数必须维护自己的索引。
public String printBar(int Length) // Method, to call the recursive function
{
printBar(length, 0);
}
public String printBar(int length, int index) //Overloaded recursive method
{
// To get a better idea of how this works without a for loop
// you can also replace this if/else with the for loop and
// operationally, it should do the same thing.
if (index >= length)
return "";
else
return "*" + printBar(length, index + 1); // Make recursive call
}
简而言之,递归是一种编写更少代码的好方法。在后面的printBar中,请注意我们有一个if语句。如果我们的条件已经达到,我们将退出递归并返回到前一个方法,该方法返回到前一个方法,等等。如果我发送一个printBar(8),我得到********。我希望通过一个简单函数的例子,它做的事情与for循环相同,这可能会有所帮助。不过,您可以在Java Bat中进行更多的练习。
其他回答
想想工蜂。它试着酿蜂蜜。它完成了自己的工作,并期待其他工蜂来酿造剩下的蜂蜜。蜂房满了,蜂房就停了。
把它想象成魔法。你有一个与你要实现的函数同名的函数,当你给它子问题时,它就会帮你解决它,你唯一需要做的就是把你的部分的解与它给你的解集成起来。
例如,我们想计算一个列表的长度。让我们用magical_length来调用我们的函数,用magical_length来调用神奇的助手 我们知道,如果我们给出没有第一个元素的子列表,它会神奇地给我们子列表的长度。那么我们唯一需要考虑的就是如何将这些信息与我们的工作结合起来。第一个元素的长度是1,而magic_counter给出了子列表的长度n-1,因此总长度是(n-1) + 1 -> n
int magical_length( list )
sublist = rest_of_the_list( list )
sublist_length = magical_length( sublist ) // you can think this function as magical and given to you
return 1 + sublist_length
然而,这个答案是不完整的,因为我们没有考虑如果我们给出一个空列表会发生什么。我们认为我们的列表总是至少有一个元素。因此,我们需要思考,如果给我们一个空列表,答案显然是0,那么答案应该是什么。所以把这些信息加到我们的函数中,这被称为基础/边缘条件。
int magical_length( list )
if ( list is empty) then
return 0
else
sublist_length = magical_length( sublist ) // you can think this function as magical and given to you
return 1 + sublist_length
递归函数只是一个函数,它可以根据需要多次调用自己。如果您需要多次处理某件事,但不确定实际需要多少次,那么它就很有用。在某种程度上,你可以把递归函数看作是一种循环。然而,就像循环一样,您需要指定中断流程的条件,否则它将变得无限。
子函数隐式地使用递归,例如:
去迪士尼乐园自驾游
我们到了吗?(没有) 我们到了吗?(很快) 我们到了吗?(快了……) 我们到了吗? 我们到了吗?(!!!!!)
这时孩子就睡着了……
这个倒数函数是一个简单的例子:
倒计时()函数 { 返回(参数[0]> 0 ? ( Console.log(参数[0]),倒计时(参数[0]- 1)): “完成” ); } 倒计时(10);
霍夫施塔特定律也适用于软件项目。
The essence of human language is, according to Chomsky, the ability of finite brains to produce what he considers to be infinite grammars. By this he means not only that there is no upper limit on what we can say, but that there is no upper limit on the number of sentences our language has, there's no upper limit on the size of any particular sentence. Chomsky has claimed that the fundamental tool that underlies all of this creativity of human language is recursion: the ability for one phrase to reoccur inside another phrase of the same type. If I say "John's brother's house", I have a noun, "house", which occurs in a noun phrase, "brother's house", and that noun phrase occurs in another noun phrase, "John's brother's house". This makes a lot of sense, and it's an interesting property of human language.
参考文献
递归与人类思想
要理解递归,你只需要看看洗发水瓶上的标签:
function repeat()
{
rinse();
lather();
repeat();
}
这样做的问题是没有终止条件,递归将无限重复,或者直到洗发水或热水用完为止(外部终止条件,类似于吹你的堆栈)。
递归
方法A调用方法A调用方法A,最终这些方法A中的一个不会调用并退出,但这是递归,因为有东西调用了它自己。
递归的例子,我想打印出硬盘驱动器上的每个文件夹名称:(在c#中)
public void PrintFolderNames(DirectoryInfo directory)
{
Console.WriteLine(directory.Name);
DirectoryInfo[] children = directory.GetDirectories();
foreach(var child in children)
{
PrintFolderNames(child); // See we call ourself here...
}
}