一 、递归算法简介

在数学与计算机科学中,递归是指在函数的定义中使用函数自身的方法。
  递归算法是一种直接或者间接地调用自身算法的过程。在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解。
递归算法解决问题的特点:
  (1) 递归就是在过程或函数里调用自身。
  (2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
  (3) 递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。
  (4) 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。所以一般不提倡用递归算法设计程序。在实际编程中尤其要注意栈溢出问题。

  借助递归方法,我们可以把一个相对复杂的问题转化为一个与原问题相似的规模较小的问题来求解,递归方法只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。但在带来便捷的同时,也会有一些缺点,也即:通常用递归方法的运行效率不高。

 二 、Fibonacci数列和阶乘

1、 Fibonacci数列

提到递归,我们可能会想到的一个实例便是斐波那契数列。斐波那契数列就是如下的数列:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, …,总之,就是第N(N > 2)个数等于第(N - 1)个数和(N - 2)个数的和。用递归算法实现如下:

 public static int Fibonacci(int n)
{
if (n < ) return -;
if (n == ) return ;
if (n == ) return ;
return Fibonacci(n - ) + Fibonacci(n - );
}

2、阶乘 

还有就是求一个数的阶乘,也会用到递归,这个比较简单,直接给出实现代码,如图:

 三 、汉诺塔问题

汉诺塔是根据一个传说形成的数学问题:

        汉诺塔示意图(图片来自网络)

有三根杆子A,B,C。A杆上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至C杆:
  1、每次只能移动一个圆盘;
  2、大盘不能叠在小盘上面。
  提示:可将圆盘临时置于B杆,也可将从A杆移出的圆盘重新移回A杆,但都必须遵循上述两条规则。
  问:如何移?最少要移动多少次?

下面是汉诺塔的递归求解实现(C#代码):

public static void hannoi(int n, string from, string buffer, string to)
{
if (n == )
{
Console.WriteLine("Move disk " + n + " from " + from + " to " + to);
}
else
{
hannoi(n - , from, to, buffer);
Console.WriteLine("Move disk " + n + " from " + from + " to " + to);
hannoi(n - , buffer, from, to);
}
}

其运行结果如图(大家可以跟上面的gif图片对比一下):

 四 、排列组合

1、输出任意个数字母、数字的全排列

  对于一个长度为n的串或者n个字符(数字、节点)组成的字符串数组,它的全排列共有A(n, n)=n!种。这个问题也是一个递归的问题。如1,2,3,全排列可得到:{123,132,213,231,312,321}。

用递归算法实现代码如下:

public static void Permutation(string[] nums, int m, int n)
{
string t;
if (m < n - )
{
Permutation(nums, m + , n);
for (int i = m + ; i < n; i++)
{
//可抽取Swap方法
t = nums[m];
nums[m] = nums[i];
nums[i] = t; Permutation(nums, m + , n); //可抽取Swap方法
t = nums[m];
nums[m] = nums[i];
nums[i] = t;
}
}
else
{for (int j = ; j < nums.Length; j++)
{
Console.Write(nums[j]);
}
Console.WriteLine();
}
}

调用代码如下:

static void Main(string[] args)
{
Nums = new string[] { "a", "b", "c" };
Permutation(Nums, , Nums.Length);
Console.ReadKey();
}

这里传入一个string数组,abc三个字母来测试,输出如下图:

2、将全排列结果保存到链表中

  有时候,我们需要将全排列的结果保存,然后做其他的处理,我们可以将结果保存到一个链表中。我们定义如下类作为链表的节点,代码如下:

   public class Node
{
public string value { get; set; }
public Node nextNode { get; set; } public Node(string value)
{
this.value = value;
this.nextNode = null;
}
}

此时声明全局变量,如下:

public static List<Node> NodeList = new List<Node>();

这个时候,我们修改Permutation方法,如下:

  public static void Permutation(string[] nums, int m, int n)
{
string t;
if (m < n - )
{
Permutation(nums, m + , n);
for (int i = m + ; i < n; i++)
{
//可抽取Swap方法
t = nums[m];
nums[m] = nums[i];
nums[i] = t; Permutation(nums, m + , n); //可抽取Swap方法
t = nums[m];
nums[m] = nums[i];
nums[i] = t;
}
}
else
{
Node root = null;
Node currentNode;
for (int j = ; j < nums.Length; j++)
{
currentNode = new Node(nums[j]);
currentNode.nextNode = root;
root = currentNode;
}
NodeList.Add(root);
}
}

这样,我们执行了Permutation方法后,就将结果保存到链表中了。用的时候,我们只要遍历NodeList就可以了。如图:

递归算法就先说到这里了。谈到算法,就必需提数据结构,看来真的要“学到老了”~~

作者:雲霏霏

QQ交流群:243633526

博客地址:http://www.cnblogs.com/yunfeifei/

声明:本博客原创文字只代表本人工作中在某一时间内总结的观点或结论,与本人所在单位没有直接利益关系。非商业,未授权,贴子请以现状保留,转载时必须保留此段声明,且在文章页面明显位置给出原文连接。

如果大家感觉我的博文对大家有帮助,请推荐支持一把,给我写作的动力。

递归算法经典实例小结(C#实现)的更多相关文章

  1. Java递归算法经典实例(兔子问题、阶乘、1到100累加)

    https://blog.csdn.net/isitman/article/details/61199070

  2. 《C#并发编程经典实例》笔记

    1.前言 2.开宗明义 3.开发原则和要点 (1)并发编程概述 (2)异步编程基础 (3)并行开发的基础 (4)测试技巧 (5)集合 (6)函数式OOP (7)同步 1.前言 最近趁着项目的一段平稳期 ...

  3. c#初学-多线程中lock用法的经典实例

    本文转载自:http://www.cnblogs.com/promise-7/articles/2354077.html 一.Lock定义     lock 关键字可以用来确保代码块完成运行,而不会被 ...

  4. 数据可视化(5)--jqplot经典实例

    本来想把实例也写到上篇博客里,最后发现太长了,拆成两篇博客了. 实例来源于官方文档:http://www.jqplot.com/tests/ 这篇博客主要是翻译了官方文档关于经典实例的解说,并在相应代 ...

  5. 《C# 并发编程 · 经典实例》读书笔记

    前言 最近在看<C# 并发编程 · 经典实例>这本书,这不是一本理论书,反而这是一本主要讲述怎么样更好的使用好目前 C#.NET 为我们提供的这些 API 的一本书,书中绝大部分是一些实例 ...

  6. Sql Server专题:SQL 经典实例

    SQL 经典实例 1.实例表: Student(S#,Sname,Sage,Ssex) 学生表 S#:学号:Sname:学生姓名:Sage:学生年龄:Ssex:学生性别 Course(C#,Cname ...

  7. 多线程中lock用法的经典实例

    多线程中lock用法的经典实例 一.Lock定义     lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断.它可以把一段代码定义为互斥段(critical section),互斥段在一 ...

  8. 【SQL】ROW_NUMBER() OVER(partition by 分组列 order by 排序列)用法详解+经典实例

    #用法说明 select row_number() over(partition by A order by B ) as rowIndex from table A :为分组字段 B:为分组后的排序 ...

  9. 《C#并发编程经典实例》学习笔记—2.3 报告任务

    问题 异步操作时,需要展示该操作的进度 解决方案 IProgress<T> Interface和Progress<T> Class 插一段话:读<C#并发编程经典实例&g ...

随机推荐

  1. CozyRSS开发记录11-够用的RSS源管理

    CozyRSS开发记录11-够用的RSS源管理 1.分析需求 先随手画个用例图来看看有哪些参与者会访问我们的源管理: 2.搞一个Controller类 根据前面分析得出的用例图,我们就可以来设计实现一 ...

  2. Spring的JDBC模板

    Spring对持久层技术支持 JDBC : org.springframework.jdbc.core.JdbcTemplate Hibernate3.0 : org.springframework. ...

  3. 微信小程序简介

    什么是微信小程序? 今年下半年的时候,微信推出了微信小程序,当然刚刚推出来的时候还是处于内测阶段,但是这并不影响这家伙的热度,也许这是一个新的时代的开启.但是什么是微信小程序呢?微信应用号是一个app ...

  4. js中的 || 与 && 运算符 的使用

    &&和||总是傻傻分不清,在这里详细记录一下吧.也给你们分享一下. 表达式a && 表达式b :  计算表达式(或者函数)a的运算结果, 如果为 True, 执行表达式 ...

  5. Unity5中WebGL平台封装的一些技巧

    最近在接触unity的WebGL平台,其实这个平台作为Web Player的替代品,已经能满足大部分的开发需求,而且不需要额外的插件支持,确实方便了不少,但开发中依旧遇到了不少问题,在这里记录和共享一 ...

  6. 《程序员的自我修养》读书笔记 - dllimport

    Math.c  { __declspec (dllexport)  double Add (xx, xx) {...}} MathApp.c  { __declspec(dllimport) doub ...

  7. ios 数据库存储json数据

    NSData *data = [NSJSONSerialization dataWithJSONObject:info.bdata options:NSJSONWritingPrettyPrinted ...

  8. rinetd

    1.安装 tar zxvf rinetd.tar.gz    make    make install 2.设置 vi /etc/rinetd.conf 0.0.0.0 8080 172.19.94. ...

  9. java项目启动后,数据库字段生成 user_name带下划线这种形式的

    hibernate 5.0 版本以上去掉了 hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy  这个属性,如果非 ...

  10. CSS Sticky Footer

    ----CSS Sticky Footer 当正文内容很少时,底部位于窗口最下面.当改变窗口高度时,不会出现重叠问题. ----另一个解决方法是使用:flexBox布局  http://www.w3c ...