我应该尽可能避免递归吗?
Should I avoid recursion everywhere it's possible?
这不是我可以毫无问题地同时使用两者的情况,因为我已经确信循环更容易理解,并且我尝试始终使用它们。但后来我偶然发现了这个(二叉搜索树的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((,那么问题可能是有限的,但是处理多个递归调用(如在二叉树中(,堆栈上的函数调用量呈指数级增长,这可能会破坏你的调用堆栈并导致你的程序崩溃。
相关文章:
- 递归模板化函数不能分配给具有常量限定类型"const tt &"的变量"state"
- 我已经建立了递归关系,它找到了两个字符串之间最长的连续公共字符串,我怎么能跳过其中一个字符串中的一个字符
- 我应该尽可能避免递归吗?
- 精神:不能在其规则定义中使用x3::skip(skipper)[一些递归规则]
- 你能在递归 lambda 中捕获引用吗?
- 为什么我不能在递归 lambda 函数中使用 auto
- 具有空参数包的递归可变参数模板(以避免基本情况的重复)
- 实现递归函数,避免由 C++ 中 include 的循环调用(没有 #pragma 一次)引起的无限循环输入
- C++中的递归选择不能完全正常工作
- 避免此功能的递归
- 谁能解释一下递归结束后这些语句是如何执行的
- 在响应EN_UPDATE消息时避免递归
- 递归模板成语如何避免基类是儿童课的朋友
- 如何避免无穷大递归中的堆栈溢出
- 递归提升::变量类型不能用"-std=c++11 -stdlib=libc++"编译
- 如何处理和避免递归
- 如何避免递归函数的堆栈溢出
- 内联函数不能包含递归、go to循环等
- 你能解释一下指针和递归结构体吗?
- 避免递归(?)#include声明