• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C#教程 > C#中尾递归的使用、优化及编译器优化

C#中尾递归的使用、优化及编译器优化

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了c#递归,c#递归算法,c#递归算法经典实例,c#方法的递归,c#递归函数等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

递归运用

一个函数直接或间接的调用自身,这个函数即可叫做递归函数。

递归主要功能是把问题转换成较小规模的子问题,以子问题的解去逐渐逼近最终结果。
递归最重要的是边界条件,这个边界是整个递归的终止条件。
static int RecFact(int x)
{
    if (x == 0)
        return 1;
    return x * RecFact(x - 1);
}
RecFact(10);
</div>

上面是个经典阶乘函数的实现。这里分2步:

1.转换,把10的阶乘转化成10*9!,10(9*8!)....每次转换规模就变的更小。
2.逼近,转换到最小规模时0!,求解1。开始逆向合并逐渐逼近到10,得出解。
这里的x==0就是我们的边界条件(即终止条件),也有的依赖外部变量为边界。

如果一个递归函数没有边界,也就无法停止(无限循环至内存溢出),当然这样也没什么意义。

RecFact调用堆栈:

常见使用场景:

1.阶乘/斐波那契数列/汉诺塔
2.遍历硬盘文件
3.InnerExceptions异常扑捉(exception.InnerException==null)

尾递归优化

当边界不明确的时候,递归就很容易出现溢出问题。

在阶乘过程中,堆栈需要保存每次(RecFact)调用的返回地址及当时所有的局部变量状态,期间堆栈空间是无法释放的(即容易出现溢出)。

为了优化堆栈占用问题,从而提出尾递归优化的办法。
static void TailRecursion(int x)
    {
        Console.WriteLine(x);
        if (x == 10)
            return;
        TailRecursion(x + 1);
    }
    TailRecursion(0);
</div>

使用尾递归堆栈可以不用保存上次的函数返回地址/各种状态值,而方法遗留在堆栈上的数据完全可以释放掉,这是尾递归优化的核心思想。

由于尾递归期间,堆栈是可以释放/再利用的,也就解决递归过深而引起的溢出问题,这也是尾递归的优势所在。

编译器优化

尾递归优化,看起来是蛮美好的,但在net中却有点乱糟糟的感觉。

1.Net在C#语言中是JIT编译成汇编时进行优化的。
2.Net在IL上,有个特殊指令tail去实现尾递归优化的(F#中)。

我们执行 TailRecursion(0)(x==1000000) 得出如下结论:

C#/64位/Release是有JIT编译器进行尾递归优化的(非C#编译器优化)。

C#/32位或C#/Debug模式中JIT是不进行优化的。

F#在优化尾递归也分2种情况:

1、 简单的尾递归优化成while循环,如下:
let rec TailRecursion(x) =
  if (x = 1000) then true
  else TailRecursion(x + 1)
</div>
(方便演示C#呈现)编译器优化成:
public static bool TailRecursion(int x)
    {
        while (x != 0x3e8)
        {
            x++;
        }
        return true;
    }
</div>
2、 复杂的尾递归,F#编译器会生成IL指令Tail进行优化,如下:
let TailRecursion2 a cont = cont (a + 1) 
</div>

优化成:

如何定义复杂的尾递归呢?通常是后继传递模式(CPS)。

F#中在debug模式下,需要在编译时配置:

总结

在C#语言(过程式/面向对象编程思想)中,优先考虑的是循环,而不是递归/尾递归。 但在函数式编程思想当中,递归/尾递归使用则是主流用法,就像在C#使用循环一样。

</div>
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • C#遍历文件夹及其子目录的完整实现方法
  • C#简单遍历指定文件夹中所有文件的方法
  • C#递归算法之打靶算法分析
  • C#递归算法寻找数组中第K大的数
  • C#用递归算法解决经典背包问题
  • C#快速排序算法实例分析
  • C#二分查找算法实例分析
  • C#中尾递归的使用、优化及编译器优化
  • C#插入法排序算法实例分析
  • C#排序算法的比较分析

相关文章

  • 2017-05-28C# 数组实例介绍(图文)
  • 2017-09-12C#类概念介绍
  • 2017-05-28C#中的递归APS和CPS模式详解
  • 2017-05-28C#运算符大全_各种运算符号的概述及作用
  • 2017-05-28Windows系统中C#读写ini配置文件的程序代码示例分享
  • 2017-05-28在WinForm中发送HTTP请求的实现方法
  • 2017-05-28C#中StringBuilder类的使用总结
  • 2017-05-28C#中单例模式的三种写法示例
  • 2017-05-28解决用Aspose.Words,在word文档中创建表格的实现方法
  • 2017-05-28C#词法分析器之正则表达式的使用

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • C#中Winfrom默认输入法的设置方法
    • C#读取视频的宽度和高度等信息的方法
    • C#使用Socket发送和接收TCP数据实例
    • c# HttpWebRequest通过代理服务器抓取网页内容应用介绍
    • 简介Winform中创建用户控件
    • c#协变和逆变实例分析
    • c# 实现窗体拖到屏幕边缘自动隐藏
    • C#实现char字符数组与字符串相互转换的方法
    • C#读取二进制文件方法分析
    • C#中sleep和wait的区别分析

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有