C#斐波那契数列的各种算法【递归、循环、数组】比较
斐波那契数列,就是整数: 第三项 等于前两项之和.A(n)=A(n-2)+A(n-1).
例如:1,1,2,3,5,8,13,21,34,55,....
现在使用四种方式:
一、递归
二、For循环【使用临时变量】
三、For循环【无临时变量】
四、使用数组作为临时仓库
测试四种算法的性能。以及计算出从第几项开始,超过Int32的最大值
新建控制台应用程序FibonacciSequenceDemo
测试源程序如下:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FibonacciSequenceDemo
{
class Program
{
static void Main(string[] args)
{
Console.SetWindowSize(120, 30);
Task taskRecursion = Task.Run(() => { AlgorithmTimespan(GetFibonacciRecursion, nameof(GetFibonacciRecursion)); });
Task taskFor = Task.Run(() => { AlgorithmTimespan(GetFibonacciFor, nameof(GetFibonacciFor)); });
Task taskForNoTemp = Task.Run(() => { AlgorithmTimespan(GetFibonacciForNoTemp, nameof(GetFibonacciForNoTemp)); });
Task taskArray = Task.Run(() => { AlgorithmTimespan(GetFibonacciArray, nameof(GetFibonacciArray)); });
Task.WaitAll(taskRecursion, taskFor, taskForNoTemp, taskArray);
Console.WriteLine("-------------测试多次调用斐波那契数列方法的用时【获取第一个大于Int32的最大值】------------------");
taskRecursion = Task.Run(() => { AlgorithmTimespanMultiple(GetFibonacciRecursion, nameof(GetFibonacciRecursion)); });
taskFor = Task.Run(() => { AlgorithmTimespanMultiple(GetFibonacciFor, nameof(GetFibonacciFor)); });
taskForNoTemp = Task.Run(() => { AlgorithmTimespanMultiple(GetFibonacciForNoTemp, nameof(GetFibonacciForNoTemp)); });
taskArray = Task.Run(() => { AlgorithmTimespanMultiple(GetFibonacciArray, nameof(GetFibonacciArray)); });
Task.WaitAll(taskRecursion, taskFor, taskForNoTemp, taskArray);
Console.ReadLine();
}
/// <summary>
/// 算法用时:单次
/// </summary>
/// <param name="FibonacciMethod"></param>
/// <param name="methodName"></param>
static void AlgorithmTimespan(Func<int, long> FibonacciMethod, string methodName)
{
Stopwatch stopwatch = Stopwatch.StartNew();
int nItem = 40;
long number = FibonacciMethod(nItem);
Console.WriteLine($"【{methodName.PadRight(26)}】,第【{nItem + 1}】项=【{number}】,用时【{stopwatch.Elapsed.TotalMilliseconds}】ms");
}
/// <summary>
/// 计算多次使用斐波那契函数的时间
/// </summary>
/// <param name="FibonacciMethod"></param>
/// <param name="methodName"></param>
static void AlgorithmTimespanMultiple(Func<int, long> FibonacciMethod, string methodName)
{
Stopwatch stopwatch = Stopwatch.StartNew();
long number;
int nItem = GetIndexLargerMaxInt32(FibonacciMethod, out number);
Console.WriteLine($"【{methodName.PadRight(26)}】,第【{nItem + 1}】项=【{number}】超过Int32的最大值,用时【{stopwatch.Elapsed.TotalMilliseconds}】ms");
}
/// <summary>
/// 找出斐波那契数列的第几项超过Int32的最大值
/// </summary>
/// <param name="FibonacciMethod"></param>
/// <returns></returns>
static int GetIndexLargerMaxInt32(Func<int, long> FibonacciMethod, out long number)
{
int nItem = 0;
number = 0;
while (true)
{
number = FibonacciMethod(nItem);
if (number >= Int32.MaxValue)
{
break;
}
nItem++;
}
return nItem;
}
/// <summary>
/// 获取斐波那契数列的第N项,索引从0开始 使用递归
/// </summary>
/// <param name="nItem">索引:从0开始</param>
/// <returns></returns>
static long GetFibonacciRecursion(int nItem)
{
if (nItem <= 1)
{
return 1;
}
return GetFibonacciRecursion(nItem - 1) + GetFibonacciRecursion(nItem - 2);
}
/// <summary>
/// 获取斐波那契数列的第N项,索引从0开始 使用For循环
/// </summary>
/// <param name="nItem">索引:从0开始</param>
/// <returns></returns>
static long GetFibonacciFor(int nItem)
{
long first = 1;
long second = 1;
for (int i = 1; i < nItem; i++)
{
long temp = first;
first = first + second;
second = temp;
}
return first;
}
/// <summary>
/// 获取斐波那契数列的第N项,索引从0开始 使用For循环,不使用临时变量
/// </summary>
/// <param name="nItem"></param>
/// <returns></returns>
static long GetFibonacciForNoTemp(int nItem)
{
long first = 1;
long second = 1;
for (int i = 1; i < nItem; i++)
{
first = first + second;
second = first - second;
}
return first;
}
/// <summary>
/// 获取斐波那契数列的第N项,索引从0开始 使用数组仓库
/// </summary>
/// <param name="nItem">索引:从0开始</param>
/// <returns></returns>
static long GetFibonacciArray(int nItem)
{
long[] array = new long[nItem + 1];
for (int i = 0; i < array.Length; i++)
{
if (i <= 1)
{
array[i] = 1;
}
else
{
array[i] = array[i - 1] + array[i - 2];
}
}
return array[nItem];
}
}
}
运行效果如图:
我们发现:性能比较结果,依次为:
【for(无临时变量)】
【for(有临时变量)】
【数组仓库】
【递归】
这也是我们编程中经常提醒:尽量减少使用递归