为什么递归比迭代更可取?

24 浏览
0 Comments

为什么递归比迭代更可取?

迭代比递归更高效,对吗?那为什么有些人认为递归比迭代更好(更优雅,用他们的话说)?我真的不明白为什么一些像Haskell这样的语言不允许迭代,而鼓励递归?鼓励一种性能较差的方法(尤其是在更高效的递归可用的情况下)难道不荒谬吗?请给予一些解释。谢谢。

0
0 Comments

为什么应该优先选择递归而不是迭代?

在讨论为什么应该优先选择递归而不是迭代之前,让我们先了解一些关于Haskell的背景知识。Haskell不允许迭代,因为迭代涉及可变状态(即索引)。但这并不意味着Haskell不允许递归,事实上,递归是Haskell中常用的编程技巧之一。那么为什么应该优先选择递归呢?

有人可能会认为,递归调用时构建堆栈是一种可变状态。但这种观点是错误的。堆栈帧不共享数据,每个堆栈帧都有自己的副本。这意味着堆栈帧是不可变的,即使在同一个线程中也是如此。同一个线程可以拥有多个堆栈帧,每个堆栈帧都有自己的数据集,这些数据集无法从任何其他函数的内部访问。

这并不涉及线程的问题,堆栈帧只是语言本身的一个实现细节。简单来说,你的代码无法改变堆栈帧的状态。

那么为什么应该优先选择递归而不是迭代呢?一个可能的原因是,虽然循环可以是不可变的结构,但它仍然鼓励使用副作用和可变性。副作用和可变性可能会引入错误和复杂性,而递归则可以更加清晰和简洁地表达问题。

递归可以将复杂的问题分解为更小的子问题,并通过不断调用自身来解决这些子问题。这种递归的结构使得代码更易于理解和调试。此外,递归还可以利用函数式编程的一些优势,如不变性和纯函数。

在某些情况下,递归还可以比迭代更高效。递归可以利用尾递归优化,将递归调用转化为循环,从而减少堆栈帧的使用。这可以提高性能并节省内存。

尽管迭代在某些情况下可能更加灵活和直观,但递归在许多方面都是更好的选择。它可以提供清晰、简洁和可维护的代码,并且在某些情况下还可以提高性能。因此,应该优先选择递归而不是迭代。

代码示例:

-- 递归计算阶乘

factorial :: Int -> Int

factorial 0 = 1

factorial n = n * factorial (n - 1)

-- 迭代计算阶乘

factorial' :: Int -> Int

factorial' n = loop n 1

where loop 0 acc = acc

loop n acc = loop (n - 1) (n * acc)

0
0 Comments

递归与迭代是编程中常用的两种解决问题的方法。递归是指在一个函数的定义中调用自身的过程,而迭代是通过循环重复执行一段代码的过程。在一些问题中,递归比迭代更容易实现和理解。

在上述对话中,某些情况下了深度优先搜索和归并排序这两个例子,说明了递归在实现这些算法时更加简单。对于深度优先搜索,使用递归可以更直观地遍历树的节点,而使用迭代则需要手动管理栈来跟踪遍历的顺序。同样,归并排序的递归实现也更加简洁。

另外,某些情况下了在递归中可以通过抛出异常或使用布尔标志来中止搜索,而在迭代中只需要简单地跳出循环。这也是迭代相对于递归的一个优势。

然而,并不是所有问题都适合使用递归解决。某些情况下了使用迭代的优势,尤其是在一些问题中,迭代可能比递归更加高效。因此,不应该限制只使用递归,而是根据具体问题选择最合适的方法。

总结起来,递归和迭代是解决问题的两种常用方法。递归在一些问题中更加简洁和直观,而迭代则可以更高效地解决一些问题。选择使用递归还是迭代应根据具体问题的特点来决定。

0
0 Comments

为什么应该优先选择递归而不是迭代?

在许多类似C的语言中,迭代比递归更高效,是吗?

不一定。

这种观念来源于许多类似C的语言,其中调用函数,无论是递归还是非递归,都具有较大的开销,并为每个调用创建一个新的栈帧。

对于许多语言来说,并非如此,递归的性能与迭代版本相同或更高。现在,一些C编译器甚至将一些递归结构重写为迭代版本,或者在尾递归调用中重用栈帧。

+1:不,迭代并不总是具有更高的性能。

在真实的计算机上,迭代更好。有些语言让你为真实的计算机编写代码,有些语言让你为想象中的计算机编写代码,对于真实计算机来说情况并非如此,然后在幕后将你的代码转换为真实计算机可用的版本,将递归转换为迭代。除非有时转换不完美,然后你会注意到,因为性能会下降。

我在选择解决问题的方法时遇到了一些困难。在搜索时,我看到了这个 - cs.cornell.edu/info/courses/spring-98/cs211/lecturenotes/…。这篇论文说数学家更喜欢递归,而没有计算机科学背景的程序员更喜欢迭代。嗯,有些语言利用记忆化来解决重复的内存函数调用的速度问题。不确定这有多少意义。

所以,使用我认为必须有原因的抽象编码是不是好事?还是重新发明轮子,或者反过来说,通过迭代来更好地控制数据结构。然后,如果我选择迭代,是否放弃了递归提供的隐式栈帧。我还有很多要说的...我们能否在某个地方讨论一下?

0