Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 我应该避免在任何地方递归吗';有可能吗?_C++_Loops_Recursion - Fatal编程技术网

C++ 我应该避免在任何地方递归吗';有可能吗?

C++ 我应该避免在任何地方递归吗';有可能吗?,c++,loops,recursion,C++,Loops,Recursion,在这种情况下,我不能毫无问题地同时使用这两种方法,因为我已经确信循环更容易理解,并且我尝试始终使用它们。但后来我偶然发现了这个(用于二进制搜索树的C++函数): Node*插入(Node*&rootptr,Node*数据){ if(rootptr==nullptr){ rootptr=数据; } else if(数据->编号){ rootptr->leftptr=Insert(rootptr->leftptr,数据); } 否则{ rootptr->rightpr=Insert(rootptr-

在这种情况下,我不能毫无问题地同时使用这两种方法,因为我已经确信循环更容易理解,并且我尝试始终使用它们。但后来我偶然发现了这个(用于二进制搜索树的C++函数):

Node*插入(Node*&rootptr,Node*数据){
if(rootptr==nullptr){
rootptr=数据;
}
else if(数据->编号){
rootptr->leftptr=Insert(rootptr->leftptr,数据);
}
否则{
rootptr->rightpr=Insert(rootptr->rightpr,数据);
}
返回rootptr;
}
当我试着思考如何通过循环时,我的大脑被震晕了。那么,为什么要受苦呢?如果是这种情况,请使用递归。但事实上,我的大脑被震晕了,这表明递归是多么有害,因为当你看它的时候,你不知道它到底做了什么。是的,它很整洁,但它是一种危险的整洁,当它同时做几件事时,你并不真正理解发生了什么


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

你在这里走错了方向:理解递归需要一些学习,以便正确地理解它,但是一旦你掌握了它,你就会理解系统的优雅,所以危险很容易就会消失


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

您在这里走错了方向:理解递归需要一些研究,以便正确地理解它,但一旦掌握了它,您就会理解系统的优雅,因此危险很容易就消失了


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

递归可以更清楚地显示出来。递归唯一令人担心的是,如果使用太多,可能会破坏堆栈。例如,linux通常有一个2MB堆栈,因此您不希望递归数百万行。递归一个只有O(logn)深的二叉树可能很好

在本例中,用如下循环替换它相当简单,但情况并非总是如此

 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;
}
Node*插入(Node*&rootptr,Node*数据){
节点**p=&rootptr;
而((*p)!=nullptr){
如果(数据->编号){
p=&(*p)->leftptr;
}
否则{
p=&(*p)->rightptr;
}
}
(*p)=数据;
返回数据;
}

递归可以更加清晰。递归唯一令人担心的是,如果使用太多,可能会破坏堆栈。例如,linux通常有一个2MB堆栈,因此您不希望递归数百万行。递归一个只有O(logn)深的二叉树可能很好

在本例中,用如下循环替换它相当简单,但情况并非总是如此

 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;
}
Node*插入(Node*&rootptr,Node*数据){
节点**p=&rootptr;
而((*p)!=nullptr){
如果(数据->编号){
p=&(*p)->leftptr;
}
否则{
p=&(*p)->rightptr;
}
}
(*p)=数据;
返回数据;
}

递归表示函数更容易理解。有些数据结构(如示例中的树)自然是递归的,因此使用递归函数处理它们比使用循环简单得多。这就是为什么你的思维会被打乱——因为在这种情况下递归是很自然的case@Telescope是的,你应该总是使用common并选择1个递归而不是10个循环,但是当我在3个循环和1个递归之间有选择时,我会选择3个循环。@ForceBru,但我并不真正理解这个函数。可能是因为调用第一个参数a
root\u ptr
很难理解,因为它只在函数的第一个条目中才是树的根指针。这里有一些很好的答案,我喜欢阅读递归表示函数的书,这会更容易理解。一些数据结构(如示例中的树)自然是递归的,因此,使用递归函数处理它们比使用循环简单得多。这就是为什么你的思维会被打乱——因为在这种情况下递归是很自然的case@Telescope是的,你应该总是使用common并选择1个递归而不是10个循环,但是当我在3个循环和1个递归之间有选择时,我会选择3个循环。@ForceBru,但我并不真正理解这个函数。可能是因为调用第一个参数a
root\u ptr
是不明确的,因为它只在函数的第一个条目中是树的根指针。这里有一些很好的答案,我很喜欢阅读,所以在递归实际有用的情况下,它往往会变得危险?通常不是这样:为了使调用堆栈溢出,您需要大量函数调用,或者代码中存在错误。深度为20的二叉树可能会导致堆栈上的一百万个函数调用,w