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