`
hilyhoo
  • 浏览: 13148 次
  • 性别: Icon_minigender_1
  • 来自: 合肥
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

C语言之尾递归

阅读更多

昨天被问到了尾递归及编译器对它的处理相关,一直对它没有研究过,解释得很含糊。
回来查了下,记录如下:

递归有线性递归(普通的递归)和尾递归。
由于尾递归的特殊性,一般的编译器会做些特殊处理。因此,在效率和开销上,比普通递归好。
举个例子,计算n!
1)线性递归:
type recurve(long n)
{
return (n == 1) ? 1 : n * recurve(n - 1);
}
2)尾递归:
type recurve_tail(long n, long result)
{
return (n == 1) ? result : recurve_tail(n - 1, result * n);
}
再封装成1)的形式:
type recurve(long n)
{
return (n == 0) ? 1 : recurve_tail(n, 1);
}

分析:
很容易看出, 普通的线性递归比尾递归更加消耗资源。每次调用都使得调用链条不断加长,系统不得不开辟新的栈进行数据保存和恢复;而尾递归就
不存在这样的问题, 因为他的状态完全由n 和 a 保存,并且,被调用函数返回的值即为要求的值,本函数再没有作用,于是本函数不再保存,直接在本函数堆栈上进行递归调用,
对于特殊情况,甚至可以不使用内存空间,直接在寄存器完成。

编译器如何判断是否尾递归?
返回的值是函数本身,没有其它选择。

看一下上述尾递归函数在gcc 4.3.2-1-1下未进行优化的编译结果:
1 .file "rec .c "
2 .text
3 .globl recurve_tail
4 .type recurve_tail , @function
5 recurve_tail :
6 pushl %ebp
7 movl %esp , %ebp
8 subl $24 , %esp
9 cmpl $1 , 8 (%ebp )
10 je .L2
11 movl 12 (%ebp ), %eax
12 movl %eax , %edx
13 imull 8 (%ebp ), %edx
14 movl 8 (%ebp ), %eax
15 subl $1 , %eax
16 movl %edx , 4 (%esp )
17 movl %eax , (%esp )
18 call recurve_tail
19 movl %eax , -4 (%ebp )
20 jmp .L3
21 .L2 :
22 movl 12 (%ebp ), %eax
23 movl %eax , -4 (%ebp )
24 .L3 :
25 movl -4 (%ebp ), %eax
26 leave
27 ret
28 .size recurve_tail , .-recurve_tail
29 .ident "GCC : (Debian 4 .3 .2 -1 .1 ) 4 .3 .2 "
30 .section .note.GNU -stack ,"",@progbits


未进行优化,与普通递归处理方式相同,新开辟了栈;再看-O3优化结果:


1 .file "rec .c "
2 .text
3 .p2align 4 ,,15
4 .globl recurve_tail
5 .type recurve_tail , @function
6 recurve_tail :
7 pushl %ebp
8 movl %esp , %ebp
9 movl 8 (%ebp ), %edx
10 movl 12 (%ebp ), %eax
11 cmpl $1 , %edx
12 je .L2
13 .p2align 4 ,,7
14 .p2align 3
15 .L5 :
16 imull %edx , %eax
17 subl $1 , %edx
18 cmpl $1 , %edx
19 jne .L5
20 .L2 :
21 popl %ebp
22 ret
23 .size recurve_tail , .-recurve_tail
24 .ident "GCC : (Debian 4 .3 .2 -1 .1 ) 4 .3 .2 "
25 .section .note.GNU -stack ,"",@progbits

此时,正如上面分析,一直在本空间计算,未开辟新栈。

分享到:
评论

相关推荐

    C.rar_instead5ss_尾递归_整数转为二进制数

    在C语言的环境下,运用尾递归将整数转换为二进制数 在C语言的环境下,运用尾递归将整数转换为二进制数

    从尾到头打印链表(C语言实现)

    C语言实现 从尾到头打印链表 递归 反转链表

    C语言解析教程(原书第4版)(美) 凯利.pdf

    1.10.3 输入文件尾标志 1.10.4 输入和输出的重定向 1.11 总结 1.12 练习 第2章 词法元素、操作符和c系统 2.1 字符和词法元素 2.2 语法规则 2.3 注释 2.4 关键字 2.5 标识符 2.6 常量 2.7 字符串常量 2.8 操作符和...

    C语言实例解析精粹(第二版) 光盘代码

    C语言实例解析精粹(第二版) 光盘代码 本文件包括以下内容: ※ 1、文件说明 ※ 2、源码操作说明 ※ 3、光盘目录清单 ◎ 源码操作说明 源代码使用方法是(以实例1为例): 将该实例的源码,比如实例1的1.c文件(可以...

    C语言程序源代码(大集合).rar

    C语言程序源代码(大集合).rar 实际只有139个,其余部分丢失! 第一部分 基础篇 001 第一个C程序 002 运行多个源文件 003 求整数之积 004 比较实数大小 005 字符的输出 006 显示变量所占字节数 007 自增/自...

    C语言源代码实例.rar

    003 求整数之积 004 比较实数大小 005 字符的输出 006 显示变量所占字节数 007 自增/自减运算 008 数列求和 009 乘法口诀表 010 猜数字游戏 011 模拟ATM(自动柜员机)界面 012 用一维数组统计学生成绩 ...

    C语言通用范例开发金典.part2.rar

    1.4.11 中序非递归遍历二叉树(链式结构)(2) 177 范例1-65 中序非递归遍历二叉树 177 ∷相关函数:InOrderTraverse2函数 1.4.12 后序遍历二叉树(顺序结构) 180 范例1-66 后序遍历二叉树 180 ∷相关函数:...

    C语言实例解析精粹

    003 求整数之积 004 比较实数大小 005 字符的输出 006 显示变量所占字节数 007 自增/自减运算 008 数列求和 009 乘法口诀表 010 猜数字游戏 011 模拟ATM(自动柜员机)界面 012 用一维数组统计学生成绩 ...

    C语言经典源代码实例 数据结构 操作系统 图形等

    003 求整数之积 004 比较实数大小 005 字符的输出 006 显示变量所占字节数 007 自增/自减运算 008 数列求和 009 乘法口诀表 010 猜数字游戏 011 模拟ATM(自动柜员机)界面 012 用一维数组统计学生成绩 ...

    C语言程序设计-精选习题和案例

    递归实现字符串逆序,爱因斯坦台阶问题,字符串拆分到数组,Sin(X)展开式,二进制回文,地铁导航,绘制cos(x)曲线,魔方矩阵,插入单词,通用数据类型的设计,约瑟夫问题,数字反转,有机体生命游戏,N!有多少个尾数...

    c语言实例解析-数值趣味数学篇

    108 递归整数四则运算 109 复平面作图 110 绘制彩色抛物线 111 绘制正态分布曲线 112 求解非线性方程 113 实矩阵乘法运算 114 求解线性方程 115 n阶方阵求逆 116 复矩阵乘法 117 求定积分 118 求满足特异...

    C语言常用算法

    003 求整数之积 004 比较实数大小 005 字符的输出 006 显示变量所占字节数 007 自增/自减运算 008 数列求和 009 乘法口诀表 010 猜数字游戏 011 模拟ATM(自动柜员机)界面 012 用一维数组统计学生成绩 ...

    C语言 数据结构之单链表基本操作

    单链表的各种操作,适合于初学,也适合于复习 单链表操作介绍 1. 创建头节点 2. 创建有数据节点 3. 判断链表是否为空 ...13. 已知两个链表head1和head2各自有序,请把它们合并成一个链表依然有序,要求用递归方法

    220个C语言程序源代码.zip

    003 求整数之积 004 比较实数大小 005 字符的输出 006 显示变量所占字节数 007 自增/自减运算 008 数列求和 009 乘法口诀表 010 猜数字游戏 011 模拟ATM(自动柜员机)界面 012 用一维数组统计学生成绩 ...

    C语言精粹(第2版)随书关盘

    003 求整数之积 004 比较实数大小 005 字符的输出 006 显示变量所占字节数 007 自增/自减运算 008 数列求和 009 乘法口诀表 010 猜数字游戏 011 模拟ATM(自动柜员机)界面 012 用一维数组统计学生成绩 ...

    c语言的cps实现求fibonacci数列示例

    CPS:http://en.wikipedia.org/wiki/Continuation-passing_style示例代码使用迭代 + 尾递归。 代码如下:#include typedef void (*END_OF_END)(unsigned long);void fibonacci(int, unsigned long, unsigned long, ...

    浙江大学C语言上机练习题附答案

    浙江大学C语言上机练习题&答案 第2周(M2) 2 20011求华氏温度100°F对应的摄氏温度。 2 20012 求华氏温度 150°F 对应的摄氏温度。 3 20013求摄氏温度26°C对应的华氏温度。 3 20015当n为152时,分别求出n的个位...

    C语言通用范例开发金典.part1.rar

    1.4.11 中序非递归遍历二叉树(链式结构)(2) 177 范例1-65 中序非递归遍历二叉树 177 ∷相关函数:InOrderTraverse2函数 1.4.12 后序遍历二叉树(顺序结构) 180 范例1-66 后序遍历二叉树 180 ∷相关函数:...

    关于C的精粹包含至少200个C语言小程序

    003 求整数之积 004 比较实数大小 005 字符的输出 006 显示变量所占字节数 007 自增/自减运算 008 数列求和 009 乘法口诀表 010 猜数字游戏 011 模拟ATM(自动柜员机)界面 012 用一维数组统计学生成绩 ...

    220个C源代码 初学C语言必备

    003 求整数之积 004 比较实数大小 005 字符的输出 006 显示变量所占字节数 007 自增/自减运算 008 数列求和 009 乘法口诀表 010 猜数字游戏 011 模拟ATM(自动柜员机)界面 012 用一维数组统计学生成绩 ...

Global site tag (gtag.js) - Google Analytics