[转]斐波那契数列算法(c#版)
首先介绍一下什么是斐波那契数列:1,1,2,3,5,8,13,21…… ,可以看到这里面的规律吧.就是每一项是前面相邻两项之和.
网上有很多的这样的算法来计算第n位的值,我再次只是想比较一下他们的优劣来提供一下参考.
先介绍递归法吧,因为我发现好多面试题里面都提到要用递归法来实现.
为了考虑知识层次的不同,我先来帮大家查一下什么是递归,百度知识里面是这样定义的:
程序调用自身的编程技巧称为递归( recursion)。
一个过程或函数在其定义或说明中又直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。用递归思想写出的程序往往十分简洁易懂。
一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。
注意:
(1) 递归就是在过程或函数里调用自身;
(2) 在使用递增归策略时,必须有一个明确的递归结束条件,称为递归出口。
看一个最普遍的用法:
大家试想一下这个算法复杂度,指数倍增吧!
我们做个改良吧
当然我们也可以不用递归啊.
用数组来实现也是不错的,当然经过我测试,这个也是速度最快的.
网上有很多的这样的算法来计算第n位的值,我再次只是想比较一下他们的优劣来提供一下参考.
先介绍递归法吧,因为我发现好多面试题里面都提到要用递归法来实现.
为了考虑知识层次的不同,我先来帮大家查一下什么是递归,百度知识里面是这样定义的:
程序调用自身的编程技巧称为递归( recursion)。
一个过程或函数在其定义或说明中又直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。用递归思想写出的程序往往十分简洁易懂。
一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。
注意:
(1) 递归就是在过程或函数里调用自身;
(2) 在使用递增归策略时,必须有一个明确的递归结束条件,称为递归出口。
看一个最普遍的用法:
1 static int GetNumberAtPos(int pos)
2 {
3 if (pos == 0 || pos == 1)
4 {
5 return 1;
6 }
7 int res = GetNumberAtPos(pos - 1) + GetNumberAtPos(pos - 2);
8 return res;
9 }
此算法的算法复杂度相对的大,如果感兴趣的朋友可以运行一下它,让得到第100位的数值,你会发现运行了半天还是没有出来结果,我来分析一下具体的原因.pos100=pos99+pos98,接着我们分别计算pos99=pos98+pos97和pos98=pos97+pos96,不知道您发现了没有,这里的pos98会在接下来的计算2次,而pos97会被计算3次,看个图理解一下吧2 {
3 if (pos == 0 || pos == 1)
4 {
5 return 1;
6 }
7 int res = GetNumberAtPos(pos - 1) + GetNumberAtPos(pos - 2);
8 return res;
9 }
大家试想一下这个算法复杂度,指数倍增吧!
我们做个改良吧
1 static Int64 GetNumberAtPos(int pos)
2 {
3 return GetNumberAtPos(1, 1, 3, pos);
4 }
5 static Int64 GetNumberAtPos(Int64 fist, Int64 second, int num, int pos)
6 {
7 Int64 third = fist + second;
8 if (num < pos)
9 {
10 Int64 next = GetNumberAtPos(second, third, ++num, pos);
11
12 }
13 else
14 {
15 Console.WriteLine(third.ToString());
16 }
17 return third;
18
19 }
这个也算是递归,也同样满足递归的定义,就是看起来难看点,不过运行速度上已经是明显的提升了,结果3736710778780434371,的确这个数字不小.2 {
3 return GetNumberAtPos(1, 1, 3, pos);
4 }
5 static Int64 GetNumberAtPos(Int64 fist, Int64 second, int num, int pos)
6 {
7 Int64 third = fist + second;
8 if (num < pos)
9 {
10 Int64 next = GetNumberAtPos(second, third, ++num, pos);
11
12 }
13 else
14 {
15 Console.WriteLine(third.ToString());
16 }
17 return third;
18
19 }
当然我们也可以不用递归啊.
用数组来实现也是不错的,当然经过我测试,这个也是速度最快的.
1 static void GetNumberAtListPos(int pos)
2 {
3 Int64[] list = new Int64[pos];
4 list[0] = 1;
5 list[1] = 1;
6 for (int i = 2; i < pos; i++)
7 {
8 list[i] = list[i - 1] + list[i - 2];
9 }
10
11 Console.WriteLine(list[pos-1].ToString());
12 }
2 {
3 Int64[] list = new Int64[pos];
4 list[0] = 1;
5 list[1] = 1;
6 for (int i = 2; i < pos; i++)
7 {
8 list[i] = list[i - 1] + list[i - 2];
9 }
10
11 Console.WriteLine(list[pos-1].ToString());
12 }