在开始学习lisp时,我遇到了尾递归这个术语.这究竟是什么意思?
language-agnostic algorithm recursion functional-programming tail-recursion
如果我们在算法中使用循环而不是递归,反之亦然,那么两者是否可以起到同样的作用?例如:检查给定的字符串是否为回文.我已经看到许多程序员使用递归作为一种手段来展示一个简单的迭代算法可以适应账单.编译器在决定使用什么方面起着至关重要的作用吗?
迭代比递归更高效,对吧?那么为什么有些人认为递归比迭代更好(用他们的话来说更优雅)?我真的不明白为什么像Haskell这样的语言不允许迭代并鼓励递归?鼓励表现不佳的东西是不是很荒谬(当更高性能的选项即递归可用时也是如此)?请详细说明一下.谢谢.
是否有任何通用的启发式,提示,技巧或常用设计范例可用于将递归算法转换为迭代算法?我知道可以做到,我想知道在这样做的时候是否有值得牢记的做法.
这可能是一个简单的问题,所以希望有人能够轻易指出我的错误或者这是否可能.
我有一个具有多个对象作为属性的对象.我希望能够动态设置这些对象的属性,如下所示:
class Person(object):
def __init__(self):
self.pet = Pet()
self.residence = Residence()
class Pet(object):
def __init__(self,name='Fido',species='Dog'):
self.name = name
self.species = species
class Residence(object):
def __init__(self,type='House',sqft=None):
self.type = type
self.sqft=sqft
if __name__=='__main__':
p=Person()
setattr(p,'pet.name','Sparky')
setattr(p,'residence.type','Apartment')
print p.__dict__
Run Code Online (Sandbox Code Playgroud)
输出是:
{'pet':< main .Pet对象位于0x10c5ec050>,'住所':< main .Residence对象位于0x10c5ec0d0>,'pet.name':'Sparky','residence.type':'公寓'}
如您所见,不是在人的宠物对象上设置name属性,而是创建一个新属性"pet.name".
我无法将person.pet指定为setattr,因为不同的子对象将通过相同的方法设置,即解析某些文本并在找到相关键时填写对象属性.
有没有简单/内置的方法来实现这一目标?
或者我可能需要编写一个递归函数来解析字符串并多次调用getattr,直到找到必要的子对象,然后在找到的对象上调用setattr?
谢谢!
可能重复:
递归是否比循环更快?
大约15年前,我第一次接受C语言培训.我的雇主想要高度优化的代码来处理计算困难的任务.我记得不止一次被建议将递归重写为循环,即使是在昂贵的可读性方面,以避免"递归开销".正如我所理解的那样,递归开销是将数据推送到堆栈然后将其弹出所需的额外工作.
现在我用C,Python,Perl编写,有时用Java编写代码,我有时会想到递归.还有什么东西可以通过重写来获得吗?如果它们是尾递归怎么办?现代编译器让所有这些问题都没有实际意义吗?这些担忧是否与解释语言无关?
optimization recursion programming-languages tail-recursion interpreted-language
我已经在C#中实现了一个四叉树,并且遇到了一个奇怪的现象,其中递归似乎比迭代更好,尽管它看起来应该是相反的.
我的节点看起来像这样:
class QuadNode
{
private QuadNode topLeft;
private QuadNode topRight;
private QuadNode bottomRight;
private QuadNode bottomLeft;
// other fields...
}
Run Code Online (Sandbox Code Playgroud)
为了遍历树,我使用了以下递归方法,我在根节点上调用:
Traverse()
{
// visit 'this'
if (topLeft != null)
topLeft.Traverse();
if (topRight != null)
topRight.Traverse();
if (bottomRight != null)
bottomRight.Traverse();
if (bottomLeft != null)
bottomLeft.Traverse();
}
Run Code Online (Sandbox Code Playgroud)
主要是出于兴趣,我试图创建一个遍历树的迭代方法.
添加以下字段到每个节点:private QuadNode next,当我创建树我使用队列,连接进行广度优先遍历next各节点的字段中线上的下一个节点.基本上我从树的节点创建了一个单链表.
此时,我可以使用以下方法遍历树:
Traverse()
{
QuadNode node = this;
while (node != null)
{
// visit node
node = node.next;
}
}
Run Code Online (Sandbox Code Playgroud)
测试每个方法的表现后,我很惊讶地得知,迭代版本是一致且明显比递归一个慢.我已经在巨大的树木和小树上进行了测试,递归方法总是更快.(我用了一个Stopwatch标杆)
,我证实,这两种方法成功地遍历整个树和迭代版本只访问每个节点恰好一次按计划进行 …
我正在通过项目Euler,我遇到了一个组合问题.组合逻辑意味着计算阶乘.所以,我决定创建一个阶乘方法.然后我遇到了一个问题 - 因为我可以很容易地使用迭代和递归来做到这一点,我应该去哪一个?我快速写了2个方法 - 迭代:
public static long factorial(int num) {
long result = 1;
if(num == 0) {
return 1;
}
else {
for(int i = 2; i <= num; i++) {
result *= i;
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
和递归:
public static long factorial(int num) {
if(num == 0) {
return 1;
}
else {
return num * factorial(num - 1);
}
}
Run Code Online (Sandbox Code Playgroud)
如果我(显然)在这里谈论速度和功能,我应该使用哪一个?而且,一般来说,这种技术通常比其他技术更好(所以如果我以后遇到这个选择,我该怎么做)?
我一直在尝试比较C中的函数速度,有些东西我无法理解,
我试图获得素数之和(1到100000)
在递归中我得到2.1 ....秒
int sumOfPrime(unsigned int top)
{
if( top % 2 == 0 ) top -= 1;
static int total = 2; // sum of prime numbers
int i;
int control=0; // prime or not
if( top == 2 | top < 2) return total;
for (i = 3; i < (top/2)+1; i++)
{
if( top % i == 0 ) // if there is a multiple
{
control++;
break;
}
}
if( control == 0 ){
total …Run Code Online (Sandbox Code Playgroud) 我有这个方法来计算一些统计数据:
public void calculateAverage(int hour){
if (hour != 20) {
int data =0;
int times = 0;
for (CallQueue cq : queues) {
data += cq.getCallsByTime().get(hour);
times++;
}
averageData.add((double)data/times);
calculateAverage(hour + 1);
}
}
Run Code Online (Sandbox Code Playgroud)
现在我非常自豪我创建了一个递归方法,但我知道这可以通过循环解决.
我的问题是:递归或循环解决这些问题会更好吗?
如果你有时间解释你的答案,请
recursion ×10
algorithm ×4
iteration ×4
performance ×3
java ×2
attributes ×1
c ×1
c# ×1
heuristics ×1
loops ×1
optimization ×1
python ×1
python-2.7 ×1
setattr ×1