星辰.Net技术社区论坛

首页 » .NET » LINQ » Linq与斐波那契数列
admin - 2008-6-12 14:20:00
从学习算法开始就免不了递归实现一个有趣的题目——斐波那契数列。生于公元1170年的意大利数学家列昂纳多·斐波那契通过兔子的繁殖来引入这样一个数列:1,1,2,3,5,8,13,21……这个数列从第三项开始,每一项都等于前两项之和。它的通向公式:(1/√5)*{[(1+√5)/2]^n - [(1-√5)/2]^n}。如果用C语言等通过递归方式实现它非常的简单如下面所示:íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
1long fibonacci(long n)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
2{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
3    if(n == 0 || n == 1)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
4        return n;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
5    elseíS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
6        return fibonacci(n-1) + fibonacci(n-2);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
7}
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
然而如果我们结合Linq的Lambda语句实现它又如何呢?这里必须澄清的是Lambda语句与Lambda表达式类似,只是语句在大括号中:íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
(parameters)=>{statement;}íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
和匿名方法一样,Lambda语句无法创建表达式目录树。由此引发了我们通过委托来帮助Lambda语句实现该数列的假想。先回顾一下之前委托调用的方法:íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
第一:通过明确定义匹配的函数原型íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
这也是最早的委托,先定义一个函数实体,然后相应的定义委托类型,最后通过声明一个变量来调用它,如下所示:íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
static double Square(double source)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
 
return Math.Pow(source, 2);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
}
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
delegate double CallMethod(double input);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
CallMethod callMethod1
= Square;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Console.WriteLine(callMethod1(
3));
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
第二:实例化泛型委托Func<T,TResult>(这种类型的委托还有好几个)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
同样的要定义具体的函数,不同的是不需要定义具体的委托类型,而是通过实例化Func泛型委托来实现,如:íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Func<double, double> callMethod2 = Square;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Console.WriteLine(callMethod2(
3));
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
第三:通过Func<T,TResult>与匿名方法一起使用íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
通过这种方式减轻了复杂度,并且提高了代码的可读性。如下:íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Func<double, double> callMethod3 = delegate(double input) íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{ return Math.Pow(input, 2); };
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
第四:通过Lambda表达式或Lambda语句íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
这也是相对来说比较简单的方式,它通过泛型委托定义函数和Lambda表达式实现功能的方式来实现。íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Func<double, double> callMethod4 = d => Math.Pow(d, 2);íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Console.WriteLine(callMethod4(
3));
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
由此可知,泛型委托在Lambda实现上有着链接和协调的作用。因此在这个意义上讲我们通过两种泛型委托的实现第一种是Action<T1,T2,T3>,该委托用于封装一个方法,该方法采用三个参数并且没有返回值。第二种是Func<T1,TResult>,该委托封装一个具有一个参数并且返回TResult参数指定类型值的方法。必须应用System.Core.dll命名空间System;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
根据命题,我们设定实现两种目标的函数,分别命名为Fibonacci_A和Fibonacci_B,前者实现给出前两个数打印出在n之前的斐波那契数,后者则实现打印出前n个斐波那契数。对于递归的方法两个函数的具体实现会有所不同。íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
Action<int, int, int> Fibonacci_A = (firstNum, secondNum, boundNum) => íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
             
int exchangeNum = firstNum + secondNum;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
              firstNum
= secondNum;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
              secondNum
= exchangeNum ;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
             
if (secondNum > boundNum)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
             
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
                 
return;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
              }
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
             
elseíS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
         
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
                  Console.WriteLine(exchangeNum );íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
                  MethodBase.GetCurrentMethod().Invoke(
null, new object[]  { firstNum, secondNum ,boundNum});íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
              }
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
          }
;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
  Fibonacci_A(0,1,200);
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
          Func<int,int> Fibonacci_B = n =>íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
     
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
                 
if ((n == 0) || (n == 1))íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
                 
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
                     
return 1;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
                  }
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
                 
return (Convert.ToInt32(MethodBase.GetCurrentMethod().Invoke(null, new object[] { n - 2 })) íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
                     
+Convert.ToInt32(MethodBase.GetCurrentMethod().Invoke(null, new object[] { n - 1 })));íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
              }
;íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
         
for (int i = 0; i < 10; i++)íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
         
{íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
              Console.WriteLine(Fibonacci_B(i));íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
          }
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
为了实现委托自身的递归调用两个函数都通过反射来实现。íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
通过这两个简单的递归函数,让我们更加了解了Lambda语句的高级功能。以上的函数不一定是最简练的,希望有更好的方法的朋友把它贴出来,以之共勉。íS ¾ £Hª;www.netcsharp.cnÅÑà’­×AŰi
1
查看完整版本: Linq与斐波那契数列