您的位置:首页 > 编程语言 > Go语言

浅谈尾递归和goto循环

2015-08-11 09:45 323 查看
在学习python递归的时候接触到尾递归,尾递归的要求是,函数的最后一个运算是递归调用,而不是其他的运算。

举阶乘为例子

// tail_recursion.cpp
int fact(int num ){
if(num <= 0 )
return 0 ;
else if(num == 1 )
return 1 ;
else if (num > 1 )
{
return num * fact(num - 1 ) ;
}
}

int fact_tail(int num , int ans){
if(num == 1 ){
return ans ;
}
else if(num <= 0 ){
return 0 ;
}
else if(num > 1 ){
return fact_tail(num - 1 , ans * num ) ;
}
}

第一个函数是我们熟知的递归函数,它的优点是简介易懂。缺点也十分经典,就是大量耗费栈空间,每次调用递归时都要把上一次的数据压栈。第二个函数是我们的尾递归函数。比较两个函数,在递归调用部分,递归函数的最后一个运算是乘法,而尾递归函数里的递归调用是最后一个运算。当最后一个运算是乘法这一类的运算时,我们的就一定要压栈保留原来的数据,用于后来的运算。但是尾递归就不用了,对于尾递归来说,上一次函数的任务已经完成了。它的数据已经通过参数传递了,是完全没有保留意义的,我们是完全可以不用压栈的。

由此,其实在部分语言中,会有我们所称的尾递归优化。编译器会为尾递归提供编译级别的优化,比如至始至终递归函数都只是用一个栈,不会出现栈溢出的情况。但是,可惜的是,我们的python、java还有c++其实是没有尾递归优化的。当然,如果真的在这些语言中需要尾递归优化,其实是可以通过异常处理的修改来实现的。这里提供一个网址:http://www.cnblogs.com/Alexander-Lee/archive/2010/09/16/1827587.html

当然,上述的方法其实是牵强而为之。

今天还了解到一个叫goto 的语句,十分高级,但是也十分危险。

// goto.cpp
int main (){
goto mark ;
int x = 1 ;
mark : printf("*") ;
return 0 ;
}


在程序中,mark是printf语句的标识符,使用goto语句可以使程序直接执行到mark行,起到一个无条件跳转的功能。但是因为是无脑跳转,所以在跳转完以后可能会出现变元没申明的语法错误。如上面的程序,x的声明就被跳过,在后期使用x时就会出现错误。goto语句一直是被认为是有反编程设计思想的。但是,尽管很难把握,goto语句在跳出循环方面还是有很大的作用,尤其是多重嵌套。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  递归 c++ 学习笔记