C#实现递归算法经典实例

 更新时间:2022年01月19日 14:59:54   作者:雲霏霏  
这篇文章主要为大家介绍了C#实现递归算法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

一 、递归算法简介

在数学与计算机科学中,递归是指在函数的定义中使用函数自身的方法。

递归算法是一种直接或者间接地调用自身算法的过程。在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解。

递归算法解决问题的特点:

(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 < 0) return -1;
         if (n == 0) return 0;
         if (n == 1) return 1;
         return Fibonacci(n - 1) + Fibonacci(n - 2);
      }

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 == 1)
         {
            Console.WriteLine("Move disk " + n + " from " + from + " to " + to);
         }
         else
         {
            hannoi(n - 1, from, to, buffer);
            Console.WriteLine("Move disk " + n + " from " + from + " to " + to);
            hannoi(n - 1, 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 - 1)
         {
            Permutation(nums, m + 1, n);
            for (int i = m + 1; i < n; i++)
            {
               //可抽取Swap方法
               t = nums[m];
               nums[m] = nums[i];
               nums[i] = t;
               Permutation(nums, m + 1, n);
               //可抽取Swap方法
               t = nums[m];
               nums[m] = nums[i];
               nums[i] = t;
            }
         }
         else
         {for (int j = 0; j < nums.Length; j++)
            {
               Console.Write(nums[j]);
            }
            Console.WriteLine();
         }
      }

调用代码如下:

static void Main(string[] args)
      {
         Nums = new string[] { "a", "b", "c" };
         Permutation(Nums, 0, 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 - 1)
         {
            Permutation(nums, m + 1, n);
            for (int i = m + 1; i < n; i++)
            {
               //可抽取Swap方法
               t = nums[m];
               nums[m] = nums[i];
               nums[i] = t;
               Permutation(nums, m + 1, n);
               //可抽取Swap方法
               t = nums[m];
               nums[m] = nums[i];
               nums[i] = t;
            }
         }
         else
         {
            Node root = null;
            Node currentNode;
            for (int j = 0; j < nums.Length; j++)
            {
               currentNode = new Node(nums[j]);
               currentNode.nextNode = root;
               root = currentNode;
            }
            NodeList.Add(root);
         }
      }

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

总结

递归算法就先说到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

相关文章

  • C#实现聊天消息渲染与图文混排详解

    C#实现聊天消息渲染与图文混排详解

    在实现聊天软件时,渲染文字表情图文混排是一项非常繁琐的工作,再加上还要支持GIF动图、引用消息、撤回消息、名片等不同样式的消息渲染时,就更加麻烦了。本文就来和大家分享一下具体实现方法,希望对大家有所帮助
    2023-02-02
  • C#存储相同键多个值的Dictionary实例详解

    C#存储相同键多个值的Dictionary实例详解

    在本篇文章里小编给大家整理的是关于C#存储相同键多个值的Dictionary实例内容,需要的朋友们可以学习下。
    2020-03-03
  • C#的this关键字的2种用法

    C#的this关键字的2种用法

    这篇文章主要给大家分享的是C#的this关键字的2种用法,在使用C#的过程中,发现this关键是比较少用的,但是在下面这二个场合下是必须要使用的,不使用它是解决不了问题。下面我们就来看看文章的具体内容吧
    2021-10-10
  • C#设计模式之Facade外观模式解决天河城购物问题示例

    C#设计模式之Facade外观模式解决天河城购物问题示例

    这篇文章主要介绍了C#设计模式之Facade外观模式解决天河城购物问题,简单描述了外观模式的定义并结合具体实例分析了外观模式解决购物问题的相关步骤与操作技巧,需要的朋友可以参考下
    2017-09-09
  • C#中的where泛型约束介绍

    C#中的where泛型约束介绍

    这个关于泛型约束的东西我看了几天了。一直没打看懂,我的领悟能力有点差,刚才突然明白了一点
    2013-04-04
  • WPF中引入WindowsForms控件的方法

    WPF中引入WindowsForms控件的方法

    这篇文章主要介绍了WPF中引入WindowsForms控件的方法,结合实例形式分析了在WPF中调用Windows Forms控件的具体步骤与相关实现技巧,需要的朋友可以参考下
    2016-07-07
  • C#中基于流的XML文件操作笔记

    C#中基于流的XML文件操作笔记

    这篇文章主要介绍了C#中基于流的XML文件操作笔记,本文主要是讲解针对XmlReader和XmlWriters两个XML读写类的使用,需要的朋友可以参考下
    2015-06-06
  • C#异常处理的技巧和方法

    C#异常处理的技巧和方法

    在本篇文章里小编给大家整理了关于C#异常处理的技巧和方法以及相关知识点,需要的朋友们学习下。
    2019-03-03
  • 详解C#中的属性和属性的使用

    详解C#中的属性和属性的使用

    这篇文章主要介绍了C#中的属性和属性的使用,包括get访问器和set访问器等内容,需要的朋友可以参考下
    2016-01-01
  • C#如何给枚举类型增加一个描述特性详解

    C#如何给枚举类型增加一个描述特性详解

    这篇文章主要给大家介绍了关于C#如何给枚举类型增加一个描述特性的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-02-02

最新评论