我应该尽可能避免递归吗?

Should I avoid recursion everywhere it's possible?

本文关键字:递归 能避免 我应该      更新时间:2023-10-16

这不是我可以毫无问题地同时使用两者的情况,因为我已经确信循环更容易理解,并且我尝试始终使用它们。但后来我偶然发现了这个(二叉搜索树的C++函数(:

Node* Insert(Node* &rootptr,Node* data) {
if (rootptr == nullptr) {
rootptr = data;
}
else if (data->number <= rootptr->number) {
rootptr->leftptr = Insert(rootptr->leftptr,data);
}
else {
rootptr->rightptr = Insert(rootptr->rightptr,data);
}
return rootptr;
}

当我试图思考如何通过循环时,我的头脑被炸毁了。那么,为什么要受苦呢?如果是这种情况,请使用递归。但是,我的头脑被炸毁的事实实际上表明了递归是多么有害,因为当你看到它时,你不明白它到底做了什么。是的,它很整洁,但这是一种危险的整洁,当它同时做几件事并且你并不真正理解正在发生的事情时。

所以在我看来有3种情况:当递归很简单并且没有理由处理它时,当递归很复杂并且你使代码不可读时,当然在某些情况下没有其他方法,所以你只需要使用它,就像阿克曼函数一样。那么为什么要使用它(除了一些特定情况(?

递归可以更清晰。递归的唯一担忧是,如果你过度使用它,你可能会破坏堆栈。例如,linux 通常有一个 2MB 的堆栈,因此您不希望递归数百万行深度。递归只有 O(log n( 深的二叉树可能没问题。

在这种情况下,用如下所示的循环替换它相当简单,但情况并非总是如此。

Node* Insert(Node* &rootptr,Node* data) {
Node** p=&rootptr;
while ((*p) != nullptr) {
if (data->number <= (*p)->number) {
p=&(*p)->leftptr;
}
else {
p=&(*p)->rightptr;
}
}
(*p) = data;
return data;
}

你在这里走错了路:理解递归需要一些研究,以便把它正确地进入你的头脑,但是一旦你掌握了,你就会理解系统的优雅,所以危险很容易消失。

这是否意味着递归完全没有危险?嗯,有一个非常重要的风险:每次调用递归函数时,它都会被添加到调用堆栈中。当你处理单个递归时(如 fact(n( = n*fact(n-1((,那么问题可能是有限的,但是处理多个递归调用(如在二叉树中(,堆栈上的函数调用量呈指数级增长,这可能会破坏你的调用堆栈并导致你的程序崩溃。