-
方法重载与递归——用C#斐波那契数列生成器
第一部分:C#基础入门
实例6:方法重载与递归——斐波那契数列生成器
实例介绍
本实例通过斐波那契数列生成器,系统讲解方法重载(同一方法名适配不同场景)和递归(方法自我调用解决问题)的核心概念。你将学会用重载方法灵活生成数列项、前n项数组或格式化字符串,理解递归的简洁性与性能瓶颈,掌握迭代优化技巧,为复杂算法设计打下基础。
需求分析
1.多场景生成:支持生成第n项、前n项数组、带格式的字符串(如逗号分隔);
2.方法重载:用同一方法名Fibonacci适配不同参数需求;
3.递归与迭代对比:展示递归的简洁性与迭代的高性能;
4.边界处理:处理n=0、n=1、负数输入等特殊情况;
5.性能提示:警告递归对大n的栈溢出风险,提供优化方向。
代码实现
csharp
using System;
using System.Text;
namespace MethodOverloadAndRecursionDemo
{
class FibonacciGenerator
{
// 备忘录:优化递归(保存已计算项,避免重复计算)
private static readonly Dictionary<int, long> _fibMemo = new Dictionary<int, long>();
static void Main(string[] args)
{
Console.Write("请输入斐波那契数列的项数n(正整数):");
if (!int.TryParse(Console.ReadLine(), out int n) || n < 1)
{
Console.WriteLine("输入无效!n必须是正整数。");
Console.ReadKey();
return;
}
// 1. 用重载方法生成第n项(递归实现)
long nthTerm = Fibonacci(n);
Console.WriteLine($"第{n}项(递归):{nthTerm}");
// 2. 用重载方法生成前n项数组(迭代实现)
long[] fibArray = Fibonacci(n, true);
Console.WriteLine($"前{n}项数组:[{string.Join(", ", fibArray)}]");
// 3. 用重载方法生成格式化字符串(逗号分隔)
string fibStr = Fibonacci(n, "comma");
Console.WriteLine($"前{n}项字符串:{fibStr}");
// 4. 迭代实现对比(性能更高)
long nthTermIter = FibonacciIterative(n);
Console.WriteLine($"第{n}项(迭代):{nthTermIter}");
Console.WriteLine("
按任意键退出...");
Console.ReadKey();
}
#region 方法重载:同一方法名适配不同需求
/// <summary>
/// 重载1:生成斐波那契数列第n项(递归+备忘录优化)
/// </summary>
public static long Fibonacci(int n)
{
if (n < 0) throw new ArgumentOutOfRangeException(nameof(n), "n不能为负数");
// 终止条件:F(0)=0,F(1)=1
if (n <= 1) return n;
// 备忘录:已计算过的项直接返回
if (_fibMemo.ContainsKey(n)) return _fibMemo[n];
// 递归调用:问题规模缩小(n→n-1、n-2)
long result = Fibonacci(n - 1) + Fibonacci(n - 2);
_fibMemo[n] = result;
return result;
}
/// <summary>
/// 重载2:生成前n项数组(迭代实现)
/// </summary>
public static long[] Fibonacci(int n, bool returnArray)
{
if (!returnArray) throw new ArgumentException("参数returnArray必须为true");
if (n < 1) throw new ArgumentOutOfRangeException(nameof(n));
long[] array = new long[n];
if (n >=1) array[0] =0; // F(0)
if (n >=2) array[1] =1; // F(1)
// 迭代计算:用循环替代递归,性能更高
for(int i=2; i<n; i++)
{
array[i] = array[i-1] + array[i-2];
}
return array;
}
/// <summary>
/// 重载3:生成前n项格式化字符串(如逗号分隔)
/// </summary>
public static string Fibonacci(int n, string format)
{
if (string.IsNullOrEmpty(format)) throw new ArgumentNullException(nameof(format));
long[] array = Fibonacci(n, true); // 复用重载2的逻辑
switch(format.ToLower())
{
case "comma":
return string.Join(", ", array);
case "line":
return string.Join(Environment.NewLine, array);
default:
throw new ArgumentException($"不支持的格式:{format}");
}
}
#endregion
/// <summary>
/// 迭代实现:生成第n项(无递归,性能最优)
/// </summary>
public static long FibonacciIterative(int n)
{
if (n <0) throw new ArgumentOutOfRangeException(nameof(n));
if (n <=1) return n;
long prevPrev =0; // F(n-2)
long prev =1; // F(n-1)
long current =0; // F(n)
for(int i=2; i<=n; i++)
{
current = prevPrev + prev;
prevPrev = prev;
prev = current;
}
return current;
}
}
}
逐行讲解
-
方法重载核心:同一方法名适配不同参数
重载规则:同一类中,方法名相同,参数列表(类型、数量、顺序)不同。例如:
oFibonacci(int n):参数为int,返回第n项;
oFibonacci(int n, bool returnArray):参数为int+bool,返回前n项数组;
oFibonacci(int n, string format):参数为int+string,返回格式化字符串。
好处:无需记忆多个方法名,代码更简洁易读。 -
递归实现(带备忘录优化)
csharp
public static long Fibonacci(int n)
{
if (n <=1) return n; // 终止条件:F(0)=0,F(1)=1
if (_fibMemo.ContainsKey(n)) return _fibMemo[n]; // 复用已计算项
long result = Fibonacci(n-1)+Fibonacci(n-2); // 递归调用:规模缩小
_fibMemo[n] = result; // 保存结果到备忘录
return result;
}
递归三要素:
1.终止条件:n<=1时直接返回,避免无限递归;
2.递归调用:Fib(n-1)+Fib(n-2),问题规模从n缩小到n-1和n-2;
3.备忘录优化:用字典保存已计算项,将时间复杂度从O(2^n)降到O(n)。
3. 迭代实现(性能最优)
csharp
public static long FibonacciIterative(int n)
{
if (n<=1) return n;
long prevPrev=0, prev=1, current=0;
for(int i=2; i<=n; i++)
{
current = prevPrev + prev;
prevPrev = prev;
prev = current;
}
return current;
}
逻辑:用三个变量保存F(n-2)、F(n-1)、F(n),循环更新直到第n项;
优势:无递归栈开销,时间复杂度O(n),空间复杂度O(1),适合大n(如n=1000)。
4. 重载方法复用
Fibonacci(n, "comma")调用Fibonacci(n, true)生成数组,再转成逗号分隔字符串;
复用原则:避免重复代码,让重载方法调用基础实现。
基础知识拓展
-
方法重载的深层规则
规则 示例 是否合法
参数类型不同 Fib(int) vs Fib(long) ✅
参数数量不同 Fib(int) vs Fib(int, bool) ✅
参数顺序不同 Fib(int, string) vs Fib(string, int) ✅
返回类型不同(参数相同) long Fib(int) vs int Fib(int) ❌(编译器无法区分)
修饰符不同(参数相同) public Fib(int) vs private Fib(int) ❌(编译器无法区分) -
递归的优缺点
优点:代码简洁,符合数学思维(斐波那契的定义直接对应递归逻辑);
缺点:
性能低:重复计算(无备忘录时)+ 栈溢出风险(n>1000时递归深度过大);
调试难:栈帧嵌套多,错误定位复杂。 -
斐波那契数列的数学定义
标准定义:F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2);
常见误区:有些资料将F(1)=1、F(2)=1作为起始,需根据需求调整终止条件。 -
递归优化方向
备忘录模式:如代码中的_fibMemo字典,保存已计算项;
尾递归优化:C#不直接支持,但可通过尾递归改写(将递归调用放在方法最后);
迭代替代:对于线性递归(如斐波那契),迭代是最优解。
扩展思考
1.大数支持:用System.Numerics.BigInteger替代long,处理n>90的超大项(long最大值约9e18,F(90)=2880067194370816120);
2.备忘录线程安全:给_fibMemo加锁(lock(_fibMemo)),支持多线程环境;
3.性能对比工具:用Stopwatch测试n=50时递归(备忘录)、迭代的时间差;
4.生成文件:将前n项保存到文本文件(每行一项);
5.尾递归改写:尝试将递归方法改为尾递归(如Fib(n, a, b),其中a=F(n-2),b=F(n-1))。
总结
本实例通过斐波那契数列,串联了方法重载(灵活适配场景)和递归(简洁解决问题)两大核心知识点。你需记住:
重载:用同一方法名适配不同参数,提升代码可读性;
递归:优先考虑简洁性,但需注意性能与栈溢出风险,大n场景用迭代或备忘录优化;
工程实践:复杂算法需平衡简洁性与性能,复用代码是关键。
本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49397.html
最新更新
异常处理——用C#文件读写错误捕获与恢
方法重载与递归——用C#斐波那契数列生
字符串操作——用C#文本内容替换与提取
数组与循环——用C#批量数据统计工具
流程控制综合应用——用c#学生成绩分级
Hello World进阶——控制台交互与参数传递
EF Core入门:ORM映射与查询
ADO.NET基础:连接数据库与执行SQL
自定义特性
反射:动态获取类型信息
SQL SERVER中递归
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
uniapp/H5 获取手机桌面壁纸 (静态壁纸)
[前端] DNS解析与优化
为什么在js中需要添加addEventListener()?
JS模块化系统
js通过Object.defineProperty() 定义和控制对象
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比










