Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/xamarin/3.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++_Recursion - Fatal编程技术网

C++ 使显式堆栈算法更快

C++ 使显式堆栈算法更快,c++,recursion,C++,Recursion,有一些递归算法可以很快填满堆栈。一种解决方案是使堆栈显式,从而将算法转化为迭代算法 但我注意到,显式堆栈会使算法变得相当慢(这可能不应该让我感到惊讶)。有什么通用的C++准则让显式栈更快吗?它们是否可能比最初的递归算法运行得更快 编辑:下面是我为其编写的显式堆栈的函数。我还粘贴了迭代代码。出于某种原因,使用std::vector比使用std::stack更快,这非常令人惊讶 // A(m, n) = n + 1 if m = 0 // = A(m

有一些递归算法可以很快填满堆栈。一种解决方案是使堆栈显式,从而将算法转化为迭代算法

但我注意到,显式堆栈会使算法变得相当慢(这可能不应该让我感到惊讶)。有什么通用的C++准则让显式栈更快吗?它们是否可能比最初的递归算法运行得更快


编辑:下面是我为其编写的显式堆栈的函数。我还粘贴了迭代代码。出于某种原因,使用
std::vector
比使用
std::stack
更快,这非常令人惊讶

// A(m, n) = n + 1                 if m = 0
//         = A(m - 1, 1)           if m > 0 and n = 0
//         = A(m - 1, A(m, n - 1)) if m, n > 0


int A(int m, int n, long& iterations,
    std::vector<std::pair<int, int> >& stack)
{
    stack.push_back(std::make_pair(m, n));
    long result = 0;
    bool result_available = false;

    while (stack.size() > 0)
    {
        iterations += 1;

        if (result_available) {
            stack.back().second = result;
            result_available = false;
        }

        m = stack.back().first;
        n = stack.back().second;
        stack.pop_back();

        if (m == 0) {
            result = n + 1;
            result_available = true;
        }
        else if (m > 0 && n == 0) {
            stack.push_back(std::make_pair(m - 1, 1));
        }
        else if (m > 0 && n > 0) {
            stack.push_back(std::make_pair(m - 1, n));
            stack.push_back(std::make_pair(m, n - 1));
        }
    }

    return result;
}
//A(m,n)=n+1如果m=0
//=A(m-1,1),如果m>0且n=0
//=A(m-1,A(m,n-1))如果m,n>0
int A(int m,int n,long&iterations,
标准:向量和堆栈)
{
stack.push_back(std::make_pair(m,n));
长结果=0;
bool result_available=false;
while(stack.size()>0)
{
迭代次数+=1;
如果(结果可用){
stack.back().second=结果;
结果_可用=错误;
}
m=堆栈。返回()。首先;
n=stack.back().秒;
stack.pop_back();
如果(m==0){
结果=n+1;
结果_可用=真;
}
else如果(m>0&&n==0){
stack.push_-back(std::make_-pair(m-1,1));
}
else如果(m>0&&n>0){
stack.push_-back(std::make_-pair(m-1,n));
stack.push_-back(std::make_-pair(m,n-1));
}
}
返回结果;
}

对于gcc最新版本的幸运用户,还有另一个解决方案:
-fsplit stack

拆分堆栈不是一个新想法,Lisp当时就有这个想法。。。这仅仅意味着编译器创建的程序不必预先设置完整的堆栈,而是能够根据需要对其进行扩展。因此,堆栈变得不连续

当然,这需要所有(或大多数)库都适应这种新的堆栈机制(因此需要重新编译整个软件堆栈)。忽略它的库可能仍然会创建堆栈溢出异常,如果您避免在此类库中使用深度递归函数,那么这并不是什么问题

使用这种机制,只要您有可用内存,堆栈就会增长以容纳您的程序

  • 尽量少从堆中分配内存。非常慢

  • 消除尾部递归-对于它们,您不需要递归调用。它看起来不像递归解决方案那么优雅,但速度更快。例如,搜索斐波那契实现。有两个递归变量和一个非递归变量

  • 使用显式堆栈不会更快,因为函数调用&通过堆栈传递参数是一些最快的汇编指令,因为它们经常被使用


  • 如果您包括一个递归和显式堆栈版本的算法的示例,在该算法中,计时差别很大,那么回答这个问题就会容易得多。一般来说,很难回答性能问题(除了算法复杂性),因为影响性能的因素太多。严格地猜测(正如@Mankarse所说,显示一些代码),但创建堆栈帧通常比分配堆内存快得多,因此如果迭代方法最终频繁扩展堆栈,堆分配会对性能产生影响。解决方案是减少分配的频率…某些类型的递归可以消除为循环(尾部递归)。那么你根本不需要这个堆栈。了解实际的算法和递归行为会很好。@Mankarse我添加了原始函数和代码。对于Fibonacci,我们不要忘记第一个改进是使用O(N)实现(感谢记忆化/动态编程)是的-这是第二个带尾部递归的递归算法。但是如果你消除了算法中的尾部递归,它会更快。