在数学与计算机科学中,递归是指在函数的定义中使用函数自身的方法。
递归算法是一种直接或者间接地调用自身算法的过程。在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它每每使算法的描述简洁并且易于理解。
递归算法解决问题的特色:
(1) 递归就是在过程或函数里调用自身。
(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
(3) 递归算法解题一般显得很简洁,但递归算法解题的运行效率较低。因此通常不提倡用递归算法设计程序。
(4) 在递归调用的过程中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易形成栈溢出等。因此通常不提倡用递归算法设计程序。在实际编程中尤为要注意栈溢出问题。算法
借助递归方法,咱们能够把一个相对复杂的问题转化为一个与原问题类似的规模较小的问题来求解,递归方法只需少许的程序就可描述出解题过程所须要的屡次重复计算,大大地减小了程序的代码量。但在带来便捷的同时,也会有一些缺点,也即:一般用递归方法的运行效率不高。编程
一、 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); }
二、阶乘 函数
还有就是求一个数的阶乘,也会用到递归,这个比较简单,直接给出实现代码,如图:测试
汉诺塔是根据一个传说造成的数学问题:this
汉诺塔示意图(图片来自网络)spa
有三根杆子A,B,C。A杆上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将全部圆盘移至C杆:
一、每次只能移动一个圆盘;
二、大盘不能叠在小盘上面。
提示:可将圆盘临时置于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图片对比一下):
一、输出任意个数字母、数字的全排列
对于一个长度为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三个字母来测试,输出以下图:
二、将全排列结果保存到链表中
有时候,咱们须要将全排列的结果保存,而后作其余的处理,咱们能够将结果保存到一个链表中。咱们定义以下类做为链表的节点,代码以下:
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就能够了。如图:
递归算法就先说到这里了。谈到算法,就必需提数据结构,看来真的要“学到老了”~~
做者:雲霏霏
QQ交流群:243633526
博客地址:http://www.cnblogs.com/yunfeifei/
声明:本博客原创文字只表明本人工做中在某一时间内总结的观点或结论,与本人所在单位没有直接利益关系。非商业,未受权,贴子请以现状保留,转载时必须保留此段声明,且在文章页面明显位置给出原文链接。
若是你们感受个人博文对你们有帮助,请推荐支持一把,给我写做的动力。