Performance 为什么递归应该优先于迭代?

Performance 为什么递归应该优先于迭代?,performance,language-agnostic,recursion,iteration,Performance,Language Agnostic,Recursion,Iteration,迭代比递归性能更好,对吗?那么为什么有些人认为递归比迭代更好(用他们的话来说更优雅)?我真的不明白为什么像Haskell这样的一些语言不允许迭代和鼓励递归?鼓励一些性能不好的东西(如果有更高性能的选项,如递归可用的话)不是很荒谬吗?请解释一下。谢谢。尝试以递归和迭代的方式实现深度优先搜索,并告诉我哪一种搜索更容易实现。或合并排序。对于许多问题,归结起来就是显式维护自己的堆栈,而不是将数据留在函数堆栈上 我无法与Haskell交谈,因为我从未使用过它,但这是为了解决您在标题中提出的问题中更一般的部

迭代比递归性能更好,对吗?那么为什么有些人认为递归比迭代更好(用他们的话来说更优雅)?我真的不明白为什么像Haskell这样的一些语言不允许迭代和鼓励递归?鼓励一些性能不好的东西(如果有更高性能的选项,如递归可用的话)不是很荒谬吗?请解释一下。谢谢。

尝试以递归和迭代的方式实现深度优先搜索,并告诉我哪一种搜索更容易实现。或合并排序。对于许多问题,归结起来就是显式维护自己的堆栈,而不是将数据留在函数堆栈上


我无法与Haskell交谈,因为我从未使用过它,但这是为了解决您在标题中提出的问题中更一般的部分。

以下是一些关于c中递归和迭代的优缺点的信息:


对我来说,递归有时比迭代更容易理解。

哈斯克尔不允许迭代,因为迭代涉及可变状态(索引)。

我不认为递归本质上有任何性能低下的地方——至少在抽象上是这样。递归是迭代的一种特殊形式。如果一种语言被设计成能够很好地支持递归,那么它的性能就可能和迭代一样好

一般来说,递归会使你在下一次迭代中提出的状态(参数)变得明确。这可以使语言处理器更容易并行执行。至少这是语言设计师们试图利用的一个方向


迭代比 递归,对吗

不一定。 这个概念来自于许多类似C的语言,在这些语言中,调用函数(递归或非递归)有很大的开销,并且为每个调用创建了一个新的stackframe


对于许多语言,情况并非如此,递归的性能与迭代版本相同或更高。现在,甚至有些C编译器将一些递归结构重写为迭代版本,或者重用堆栈框架进行尾部递归调用。

正如其他人所说,递归本质上没有性能差的地方。有些语言的速度会慢一些,但这不是一个普遍的规则

也就是说,对我来说,递归是一种工具,可以在有意义的时候使用。有些算法可以更好地表示为递归(就像有些算法通过迭代更好一样)

例如:

fib 0 = 0
fib 1 = 1
fib n = fib(n-1) + fib(n-2)
我无法想象一个迭代解决方案可能会让意图更加清晰。

迭代比递归更有效”实际上是特定于语言和/或编译器的。想到的情况是编译器执行循环展开时。如果您在这种情况下实现了递归解决方案,那么速度会慢很多

这就是成为一名科学家(测试假设)并了解你的工具的报酬…

几件事:

  • 迭代不一定更快
  • 万恶之源:仅仅因为某件事情可能会稍微快一点就鼓励它是不成熟的;还有其他考虑
  • 递归通常更简洁、更清楚地传达您的意图
  • 通过通常避免可变状态,函数式编程语言更容易推理和调试,递归就是一个例子
  • 递归比迭代占用更多内存

  • 在Java中,递归解决方案通常优于非递归解决方案。在C语言中,情况往往相反。我认为这通常适用于自适应编译语言和超前编译语言

    编辑: 我所说的“一般”是指60/40的分割。这在很大程度上取决于语言处理方法调用的效率。我认为JIT编译支持递归,因为它可以选择如何处理内联并在优化中使用运行时数据。不过,它非常依赖于所讨论的算法和编译器。特别是Java在处理递归方面继续变得更加智能


    用Java进行定量研究。请注意,这些主要是排序算法,并且使用的是较旧的Java虚拟机(如果我没有读错的话,请参阅1.5.x)他们有时通过使用递归实现获得2:1或4:1的性能改进,递归很少会明显变慢。以我个人的经验,这种差异通常不那么明显,但是,当我明智地使用递归时,通常会有50%的改进。

    我认为这将有助于了解性能的真正含义。显示了一个完全合理编码的应用程序实际上有很大的优化空间——即43倍!这些都与迭代与递归无关


    当一个应用程序被调优到这样的程度时,它会达到这样的程度:迭代保存的周期与递归保存的周期实际上可能会有所不同。

    作为一个低级迭代,它处理CX注册表以计算循环,当然还有数据注册表。 递归不仅处理这个问题,它还向堆栈指针添加引用,以保留以前调用的引用,然后返回-


    我的大学老师告诉我,无论你用递归做什么,都可以用迭代来完成,反之亦然,但是有时候用递归比用迭代更简单(更优雅),但在性能水平上使用迭代更好。-

    递归是迭代的典型实现。它只是一个较低级别的抽象(至少在Python中是这样):


    迭代只是递归的一种特殊形式

    递归在理论上看似优雅或高效,但在实践中通常效率较低(除非编译器或动态重新编译器正在改变代码的功能)。通常,任何导致不必要的子例程调用的
    class iterator(object):
        def __init__(self, max):
            self.count = 0
            self.max = max
    
        def __iter__(self):
            return self
    
        # I believe this changes to __next__ in Python 3000
        def next(self):
            if self.count == self.max:
                raise StopIteration
            else:
                self.count += 1
                return self.count - 1
    
    # At this level, iteration is the name of the game, but
    # in the implementation, recursion is clearly what's happening.
    for i in iterator(50):
        print(i)
    
    private long recursive(File rootFile, long counter) {
                long duration = 0;
                sendScanUpdateSignal(rootFile.getAbsolutePath());
                if(rootFile.isDirectory()) {
                    File[] files = getChildren(rootFile, MUSIC_FILE_FILTER);
                    for(int i = 0; i < files.length; i++) {
                        duration += recursive(files[i], counter);
                    }
                    if(duration != 0) {
                        dhm.put(rootFile.getAbsolutePath(), duration);
                        updateDurationInUI(rootFile.getAbsolutePath(), duration);
                    }   
                }
                else if(!rootFile.isDirectory() && checkExtension(rootFile.getAbsolutePath())) {
                    duration = getDuration(rootFile);
                    dhm.put(rootFile.getAbsolutePath(), getDuration(rootFile));
                    updateDurationInUI(rootFile.getAbsolutePath(), duration);
                }  
                return counter + duration;
            }
    
    private void traversal(File file) {
                int pointer = 0;
                File[] files;
                boolean hadMusic = false;
                long parentTimeCounter = 0;
                while(file != null) {
                    sendScanUpdateSignal(file.getAbsolutePath());
                    try {
                        Thread.sleep(Constants.THREADS_SLEEP_CONSTANTS.TRAVERSAL);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
    
                    files = getChildren(file, MUSIC_FILE_FILTER);
    
                    if(!file.isDirectory() && checkExtension(file.getAbsolutePath())) {
                        hadMusic = true;
                        long duration = getDuration(file);
                        parentTimeCounter = parentTimeCounter + duration;
                        dhm.put(file.getAbsolutePath(), duration);
                        updateDurationInUI(file.getAbsolutePath(), duration);
                    }
    
                    if(files != null && pointer < files.length) {
                        file = getChildren(file,MUSIC_FILE_FILTER)[pointer];
                    }
                    else if(files != null && pointer+1 < files.length) {
                        file = files[pointer+1];
                        pointer++;
                    }
                    else {
                        pointer=0;
                        file = getNextSybling(file, hadMusic, parentTimeCounter);
                        hadMusic = false;
                        parentTimeCounter = 0;
                    }
                }
            }
    
    private File getNextSybling(File file, boolean hadMusic, long timeCounter) {
                File result= null;
                //se o file é /mnt, para
                if(file.getAbsolutePath().compareTo(userSDBasePointer.getParentFile().getAbsolutePath()) == 0) {
                    return result;
                }
                File parent = file.getParentFile();
                long parentDuration = 0;
                if(hadMusic) { 
                    if(dhm.containsKey(parent.getAbsolutePath())) {
                        long savedValue = dhm.get(parent.getAbsolutePath());
                        parentDuration = savedValue + timeCounter;
                    }
                    else {
                        parentDuration = timeCounter; 
                    }
                    dhm.put(parent.getAbsolutePath(), parentDuration);
                    updateDurationInUI(parent.getAbsolutePath(), parentDuration);
                }
    
                //procura irmao seguinte
                File[] syblings = getChildren(parent,MUSIC_FILE_FILTER);
                for(int i = 0; i < syblings.length; i++) {
                    if(syblings[i].getAbsolutePath().compareTo(file.getAbsolutePath())==0) {
                        if(i+1 < syblings.length) {
                            result = syblings[i+1];
                        }
                        break;
                    }
                }
                //backtracking - adiciona pai, se tiver filhos musica
                if(result == null) {
                    result = getNextSybling(parent, hadMusic, parentDuration);
                }
                return result;
            }