c# 扩展方法奇思妙用变态篇一:由 Fibonacci 数列引出 “委托扩展” 及 “递推递归委托”...
先回顾一个数列的概念:按一定次序排列的一列 数 称为数列...(请参见百度百科:数列)
几个简单的数列:
1, 1, 1, 1, 1, 1, 1... //数列1
0, 1, 2, 3, 4, 5, 6, 7... //数列2
0, 1, 4, 9, 16, 25, 36, 49... //数列3
通项公式的定义:数列的第n项与项的序数这间的关系,也就是数列生成算法
上面几个数列可表示为
An = F(n) = 1
An = F(n) = n
An = F(n) = n * n
有了数列和通项公式的定义,我们的任务就好描述了:
用最简洁的代码描述通项公式,用最简洁算法生成数列的前N个数。
在此要求下,用常规代码是做不到简洁的,这里我们用lambda表达式描述通项公式:
public static Func<int, int> fun1 = n => 1;
//数列2 通项公式
public static Func<int, int> fun2 = n => n;
//数列3 通项公式
public static Func<int, int> fun3 = n => n * n;
lambda表达式是不是与数学公式很像啊!
再来看生成算法,这里用了一个不一般的扩展:
/// 生成队列的前count项
/// </summary>
/// <param name="func">通项公式</param>
/// <param name="count">生成的数量</param>
/// <returns>队列前count项</returns>
public static IEnumerable<int> GetSequence(this Func<int, int> func, int count)
{
for (int i = 0; i < count; i++) yield return func(i);
}
相信大家见的扩展大多针对类(object, string)、接口(IEnumerable<T>)进行扩展,针对Func(委托)估计对大多数人来说都是第一次。
这个扩展就是标题中说的“委托扩展”,感觉很怪吧,很别扭吧,很别管太多,看看怎么调用吧:
{
int[] ints1 = fun1.GetSequence(10).ToArray(); //1, 1, 1, 1
int[] ints2 = fun2.GetSequence(10).ToArray(); //0, 1, 2, 3
int[] ints3 = fun3.GetSequence(10).ToArray(); ; //0, 1, 4, 9
}
自我感觉比较简洁,而且将生成数列(GetSequence)与数列算法(通项公式)分开,也达到了生成数列(GetSequence)的复用。
上面几个数列比较简单,现在来看Fibonacci,
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55...
用图形表示如下:
这个序列在大家学习c语言递推递归时都接触过,这个序列很神奇,请参看维基百科:斐波那契数列
它的通项公式是 An = F(n) = n n =0, 1
F(n-1) + F(n-2) n>1
注意:关于这数列有的是从n从0开始,有的是从1开始,这里不计较。
递推递归算法如下,容易理解效率确很低!!
{
if (n > 1) return GetFibonacci(n - 1) + GetFibonacci(n - 2);
else return n;
}
本文是为了引出递推递归委托,暂不是算法的效率
下面就要大(改)变(形)态了。
不考虑 <1 的情况
与数学通项式对比一下,何其相似!这就是我们的“递推递归委托”!
考虑所有情况,完成Fibonacci,如下
实在感叹c#精简的语法,一句代码可以表示一个递推递归!
调用测试下吧!
{
//委托扩展方法 + 递推递归委托
int[] fibonacciSequence = Fibonacci.GetSequence(12).ToArray();
}
当然这个生成算法效率不是一般的低!
最后给出一个数学推导出的精确算法
//Pow扩展,简化调用
public static double Pow(this double x, double y)
{
return Math.Pow(x, y);
}
一点意见:像这样代码,最好是给封装起来,否则会很麻烦的。
这篇文章是给极少数人看的(启发一下),看完后封装好给大多数人用。这是也“变态篇”系列文章的宗旨.
希望大家对 “委托扩展” 和 “递推递归委托”提些看法,名字定义不太好,请指正!
----------------------------------------------------------------------------------------------------------
以下为 2009年8月10日20时52分 追加内容
----------------------------------------------------------------------------------------------------------
看了大家的回复,对我鼓励很大,尤其是 装配脑袋 给出的解法(在#7楼)给了我很大的启发,于是我也忍不住把 装配脑袋 的算法改进了一下:
public static Func<Point, Func<Point, Point>, int, Point> g1 = (p, f, n) => n > 0 ? g1(f(p), f, n - 1) : p;
public static Func<Point, Func<Point, Point>, int, Point> g2 = (p, f, n) => n > 0 ? f(g2(p, f, n - 1)) : new Point(0, 1);
public static void Test8()
{
//测试 generate1
Point p1 = g1(new Point(0, 1), f, 3);
for (int i = 0; i < 12; i++)
Console.WriteLine(g1(new Point(0, 1), f, i));
//测试 generate2
Point p2 = g2(default(Point), f, 3);
for (int i = 0; i < 12; i++)
Console.WriteLine(g2(default(Point), f, i));
}
这里用到Point (System.Drawing中的),因为它能包含两个整数,Fibonacci又是前两项之和,所以...
以下是调试运行的结果:
{X=0,Y=1}
{X=1,Y=0}
{X=1,Y=1}
{X=2,Y=1}
{X=3,Y=2}
{X=5,Y=3}
{X=8,Y=5}
{X=13,Y=8}
{X=21,Y=13}
{X=34,Y=21}
{X=55,Y=34}
{X=89,Y=55}
{X=0,Y=1}
{X=1,Y=0}
{X=1,Y=1}
{X=2,Y=1}
{X=3,Y=2}
{X=5,Y=3}
{X=8,Y=5}
{X=13,Y=8}
{X=21,Y=13}
{X=34,Y=21}
{X=55,Y=34}
{X=89,Y=55}
两列Fibonacci,不过第二列刚开始不对。
g1和g2是两种算法,看上去很相似,有什么不同呢,设个断点单步调试(F11)下吧!
上面的代码还不够简洁,最后将f与g1合在一起,如下:
测试调用代码如下:
public static void Test9()
{
//测试 generate3
Point p3 = g3(new Point(0, 1), 3);
for (int i = 0; i < 12; i++)
Console.WriteLine(g3(new Point(1,0), i));
}
几种算法的优点和缺点大家来评判吧!
c# 扩展方法奇思妙用变态篇一:由 Fibonacci 数列引出 “委托扩展” 及 “递推递归委托”...相关推荐
- c# 扩展方法奇思妙用变态篇四:string 的翻身革命
string是各种编程语言中最基础的数据类型,长期以来受尽其它类的压迫,经常被肢解(Substring.Split).蹂躏(Join)... 而现在string要"翻身闹革命"了, ...
- c#扩展方法奇思妙用变态篇四:string 的翻身革命
string是各种编程语言中最基础的数据类型,长期以来受尽其它类的压迫,经常被肢解(Substring.Split).蹂躏(Join)... 而现在string要"翻身闹革命"了, ...
- c# 扩展方法奇思妙用高级篇一:改进 Scottgu 的 In 扩展
先看下ScottGu对In的扩展: 调用示例1: 调用示例2: 原文地址:New "Orcas" Language Feature: Extension Methods 很多介绍扩 ...
- C#扩展方法奇思妙用高级篇一:改进 Scottgu 的 In 扩展
先看下ScottGu对In的扩展: 调用示例1: 调用示例2: 原文地址:New "Orcas" Language Feature: Extension Methods 很多介绍扩 ...
- c#扩展方法奇思妙用高级篇七:“树”通用遍历器
我的上一篇随笔<c#扩展方法奇思妙用高级篇六:WinForm 控件选择器>中给出了一个WinForm的选择器,其实质就是一个"树"的遍历器,但这个遍历局限于WinFor ...
- c#扩展方法奇思妙用性能篇一:扩展方法性能初测
最近写了几篇<c#扩展方法奇思妙用>的文章,一直只是讨论如何扩展.如何使用的问题,几乎没有涉及效率方面. 而大家的回复好多都在问效率如何.性能怎样,也引起了我对效率的关注,今天将初步测试的 ...
- c# 扩展方法奇思妙用基础篇八:Distinct 扩展(转载)
转载地址:http://www.cnblogs.com/ldp615/archive/2011/08/01/distinct-entension.html 刚看了篇文章 <Linq的Distin ...
- c#扩展方法奇思妙用高级篇四:对扩展进行分组管理
从系列文章开篇到现在,已经实现的很多扩展了,但过多的扩展会给我们带来很多麻烦,试看下图: 面对这么多"泛滥"的扩展,很多人都会感到很别扭,的确有种"喧宾夺主"的 ...
- c#扩展方法奇思妙用高级篇八:Type类扩展
Type 类提供了大量的属性和方法,但在一些基础性开发工作中,Type类功能还有些欠缺,尤其上在处理泛型类型时,如可空类型和泛型集合类型.下面的类就针对这些地方进行扩展. 1 public ...
最新文章
- 改进量子计算机的三项创新
- vscode格式化代码无效--可能的解决方法
- 无需激活直接同步登入discuz,php代码(直接可用)
- hdu 3697 贪心
- 轻松查看Internet Explorer缓存文件
- JQuery 之 跳出循环
- 企业文化:谦虚(谦逊,虚心)
- pycharm初始配置
- 报表统计(六) 访问数据库
- 【图像处理】《数字图像处理-冈萨雷斯》笔记
- Linux:struct dirent
- Pyinstaller 打包Pyside2 报错qt.qpa.plugin
- 详解CAN总线:CAN协议分层结构及功能
- 全电发票的最新进展:有关咨询整理(上篇)
- matlab中count()怎么用,count(1)这里面的1是什么意思
- Nova 实现的 Fit Instance NUMA to Host NUMA 算法
- 一款Java开源的SpringBoot即时通讯IM 聊天系统
- html 取消settimeout,Javascript – setTimeout关闭问题
- 【SpringBoot】:springboot整合FTP文件上传与下载功能
- 微服务是去ESB总线、去中心化和分布式