C#简介(从入门到精通)
一、发展历史
C#的主要作者是丹麦计算机科学家安德斯·海尔斯伯格(Anders Hejlsberg),他是该语言的首席设计师,同时也是Turbo Pascal(Pascal 语言编译器)、Delphi(由 Borland(后被 Embarcadero 收购)开发的面向对象编程语言与集成开发环境(IDE))和TypeScript(由微软开发的开源编程语言,JavaScript 的超级版)的创造者,以及.NET框架的创立者。
C#(读作 “C Sharp”)是由微软开发的面向对象编程语言,基于.NET 框架,旨在结合灵活性、性能和生产力。其发展历程如下:
1. 起源与早期版本(2000-2005)
-
2000 年:C# 1.0 随.NET Framework 1.0 发布,设计灵感源自 C++、Java 和 Delphi,目标是简化企业级开发。
2. 功能扩展(2007-2010)
-
2007 年:C# 3.0 推出 Lambda 表达式、LINQ(语言集成查询)、自动属性和匿名类型,大幅提升数据查询效率。
-
2010 年:C# 4.0 支持动态类型(
dynamic
)、命名参数、可选参数和 COM 互操作性,增强灵活性。
3. 异步与并行编程(2012-2015)
-
2012 年:C# 5.0 引入
async/await
异步编程模型,简化异步操作的编写。 -
2015 年:C# 6.0 增加异常过滤器、字典初始化语法、空条件运算符(
?.
)和 nameof 表达式,提升代码可读性。
4. 现代特性与跨平台(2017 - 至今)
-
2017 年:C# 7.0 支持模式匹配、元组、局部函数和二进制字面量,增强代码表达力。
-
2019 年:C# 8.0 引入 nullable 引用类型、异步流、范围运算符(
..
)和模式匹配增强,配合.NET Core 实现跨平台开发。 -
2020 年:C# 9.0 推出记录类型(
record
)、顶级程序集、模式匹配改进和 init 只读属性。 -
2022 年:C# 10.0 支持源生成器、文件范围命名空间、集合表达式改进和原始字符串字面量。
-
2023 年:C# 11.0 新增泛型数学、集合切片、原始字符串内插和
required
修饰符,持续优化开发体验。
关键发展背景:
-
随着.NET 从 Windows 平台扩展到.NET Core(2016)和统一的.NET(2020),C# 成为跨平台开发(Windows、macOS、Linux)的核心语言。
-
社区驱动的改进通过.NET 基金会持续推进,例如通过 RFC(Request for Comments)收集开发者反馈。
二、开发工具
C# 开发工具覆盖从 IDE 到命令行,适配不同开发场景:
1. 集成开发环境(IDE)
Visual Studio
Visual Studio Code(VS Code)
JetBrains Rider
2. 命令行工具
-
.NET CLI:跨平台命令行接口,用于创建项目、编译代码和管理依赖(如
dotnet new
、dotnet build
) -
MSBuild:微软构建平台,通过
.csproj
项目文件定义编译流程,支持自动化构建和 CI/CD
3. 辅助工具
-
Resharper(VS 插件):代码分析、重构建议和代码生成,提升开发效率。
-
NUnit/MSTest/xUnit:单元测试框架,支持自动化测试和断言。
-
Fiddler/Postman:接口调试工具,适用于 C# 开发的 Web 服务测试。
.NET 技术栈核心组件
1. .NET Framework 与 .NET Core
-
.NET Framework 传统 Windows 平台的运行时环境,包含:
-
CLR (Common Language Runtime):底层运行时,负责内存管理、垃圾回收等。
-
FCL (Framework Class Library):基础类库,提供如
System.IO
、System.Net
等功能。 -
支持 Windows Forms、ASP.NET等应用模型。
-
-
.NET Core/.NET 5+ 跨平台(Windows/macOS/Linux)的现代框架,统一了.NET Framework、.NET Core 和 Xamarin,支持:
-
控制台、Web、移动(MAUI)、云服务等应用类型。
-
模块化依赖管理(NuGet)和更小的部署包。
-
2. C# 与公共类型系统 (CTS)
-
C# 语言:.NET 生态的主要编程语言,语法简洁,支持面向对象、泛型、LINQ 等特性。
-
CTS (Common Type System):.NET 的类型规范,定义了:
-
基础类型(如
int
映射到System.Int32
)。 -
类型兼容性规则,确保不同语言(C#、VB.NET等)间的互操作性。
-
示例:
int a = 10; // C#语法糖,实际对应System.Int32Int32 b = 20; // 显式使用CTS类型名string s = \"hello\"; // C#字符串(映射到System.String)String s2 = \"HELLO\"; // 等效于string(CTS类型名)
3. CLR 与 JIT 编译
-
CLR (Common Language Runtime):.NET 的运行时环境,负责:
-
加载和执行程序集(IL 代码)。
-
通过 JIT(Just-In-Time)编译器将 IL 转换为机器码。
-
提供内存管理、类型安全检查等服务。
-
-
JIT 工作流程:
C#源码 → 编译器(csc) → IL中间语言(.dll/.exe) → JIT → 机器码(CPU执行)
4. CTS 与 CLS
-
CTS (Common Type System):定义所有.NET 语言必须遵循的类型规范。
-
CLS (Common Language Specification):CTS 的子集,确保语言间互操作性(如 C# 与VB.NET)。
三、基础语法知识
第一个 C# 程序解析
代码结构
using System; // 引入System命名空间namespace demo2 // 命名空间:组织代码的逻辑容器{ public class Program // 公共类:程序入口点 { public static void Main() // 程序主方法(入口点) { Console.WriteLine(\"Hello C#\"); // 输出到控制台 Console.ReadKey(); // 等待用户按键,防止窗口自动关闭 } }}
编译流程
-
源码 (.cs) → IL 中间语言 (.exe) → 机器码
-
手动编译步骤
(需配置环境变量):
# 1. 进入源码目录cd C:\\Users\\YourName\\Documents# 2. 使用csc编译器生成.execsc HelloWorld.cs# 3. 运行程序HelloWorld.exe
编译工具与环境配置
1. csc 编译器
-
路径:
C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\csc.exe
(64 位系统的.NET Framework 4.0 版本)
2. 环境变量配置
-
旧方法:手动将
csc.exe
路径添加到系统PATH
变量。 -
现代开发:安装 Visual Studio 后自动配置环境变量,支持直接使用
csc
命令。
DOS 命令基础
cd
cd C:\\Projects
dir
dir
cls
cls
csc
csc Program.cs
命名空间与标识符规范
命名空间(Namespace)
-
逻辑分组代码,避免命名冲突。
-
示例:
System.Console
中的System
是命名空间。
标识符规范
CustomerManager
GetUserInfo()
userName
MAX_CONNECTIONS
核心类与方法解析
1. Console 类
-
位于
System//命名空间,提供控制台输入 / 输出功能:Console.WriteLine(\"文本\"); // 输出并换行Console.Write(\"不换行\"); // 输出不换行Console.ReadLine(); // 读取用户输入(按回车结束)
2. Main 方法
-
程序入口点,签名必须为:
public static void Main() // 无参数版本public static int Main() // 返回int表示退出代码public static void Main(string[] args) // 接收命令行参数
语句、块与空白
-
语句:一行可执行代码(如
int a = 10;
)。 -
块:用
{}
包裹的语句组(如方法体)。 -
空白:空格、制表符、换行符,用于提高代码可读性,编译器会忽略。
C# 标识符规则
标识符用于命名类、变量、函数等用户定义的元素,命名需遵循以下规则:
-
字符组成:由字母、数字、下划线(
_
)组成。 -
开头限制:必须以字母、下划线或
@
开头,不能以数字开头。 -
特殊符号:禁止包含空格或特殊符号(如
?、+、!、#
等)。 -
关键字冲突:不能是 C# 关键字,但若添加
@
前缀可作为标识符(如@if
)。 -
大小写敏感:严格区分大小写(如
UserAge
和userAge
是不同标识符)。 -
命名规范:建议 “见名知意”,例如用
userName
表示用户名。
C# 关键字
C# 关键字分为保留关键字和上下文关键字,以下是常见类型:
保留关键字(不可直接作为标识符)
上下文关键字(仅在特定上下文有特殊含义)
| add | alias | ascending| dynamic | from | get | | global | group | into | join | let | orderby | | partial | remove | select | set | where | yield |
变量与常量
变量
-
定义格式:
数据类型 变量名;
(如int age;
)。 -
赋值方式:通过
=
运算符赋值(如age = 18;
),可声明时直接赋值(如string name = \"张三\";
)。 -
注意事项:
-
变量名不可重复声明。
-
必须初始化(赋值)后才能使用。
-
可同时定义多个同类型变量(如
int a, b, c;
)。
-
常量
-
定义格式:使用
const
关键字,值在编译阶段确定且不可修改。
const double PI = 3.1415926; // 正确 // PI = 3.14; // 错误:常量不可修改
控制台常用方法
WriteLine()
Console.WriteLine(\"Hello World!\");
)。Write()
Console.Write(\"No newline\");
)。ReadKey()
ReadLine()
Beep()
Console.Beep(2000, 800);
:频率 2000Hz,持续 800ms)。Clear()
控制台属性(修改颜色)
Console.BackgroundColor = ConsoleColor.Red; // 设置背景色为红色 Console.ForegroundColor = ConsoleColor.Yellow; // 设置字体颜色为黄色 Console.WriteLine(\"红色背景+黄色字体\");
1.数据类型
C# 数据类型分为值类型和引用类型:
值类型(直接存储数据值)
int age = 18;
byte score = 90;
float price = 9.9f;
double pi = 3.14;
bool isReady = true;
char gender = \'男\';
\\0
string name = \"李四\";
引用类型(存储数据引用)
-
对象(
object
):所有类型的基类,可存储任意类型数据(如object obj = \"文本\"; obj = 123;
)。 -
动态类型(
dynamic
):类型检查在运行时进行,灵活性高但可能引发运行时错误。
1.1 值类型(Value Types)
直接存储数据值,分配在栈内存中。常见值类型:
int age = 25; // 整数(32位)double height = 1.75; // 双精度浮点数bool isStudent = true; // 布尔值char grade = \'A\'; // 字符(Unicode)decimal salary = 5000.00m; // 高精度小数(金融计算)
特殊值类型:
-
枚举(enum):定义命名常量集合:
enum Color { Red, Green, Blue }Color favorite = Color.Blue;
-
结构体(struct):轻量级数据结构,可包含字段和方法:
struct Point { public int X; public int Y; public double Distance() => Math.Sqrt(X*X + Y*Y);}
1.2 引用类型(Reference Types)
存储对象引用,实际数据在堆内存中。常见引用类型:
string name = \"Doubao\"; // 字符串(不可变)object obj = 42; // 基类型,可引用任何对象int[] numbers = { 1, 2, 3 }; // 数组
动态类型(dynamic):运行时确定类型(C# 4.0+):
dynamic dynamicVar = \"Hello\";dynamicVar = 123; // 合法,运行时绑定
1.3 可空类型(Nullable Types)
处理值类型可能为null
的场景(值类型默认不可为null
):
int? nullableInt = null; // 可空intif (nullableInt.HasValue) { Console.WriteLine(nullableInt.Value);} else { Console.WriteLine(\"Value is null\");}// 空合并运算符(??)int result = nullableInt ?? 0; // 若nullableInt为null,赋值0
作业:变量定义练习
根据描述定义合适的变量(注意数据类型和命名规范):
扩展知识:计算机存储单位
-
基本单位:
-
位(bit):最小存储单位,只能是
0
或1
。 -
字节(Byte, B):基本存储单位,
1 Byte = 8 bit
,一个英文字符占1 Byte
,一个汉字占2 Byte
。
-
-
换算关系:
1 B = 8 bit1 KB = 2^10 B = 1024 B1 MB = 2^10 KB = 2^20 B1 GB = 2^10 MB = 2^30 B1 TB = 2^10 GB = 2^40 B1 PB = 2^10 TB = 2^50 B1 EB = 2^10 PB = 2^60 B1 ZB = 2^10 EB = 2^70 B1 YB = 2^10 ZB = 2^80 B
-
注意:
-
十进制单位(GB)与二进制单位(GiB)易混淆,计算机实际按二进制换算。
-
大文件存储(如视频、硬盘容量)常用 GB、TB 表示。
-
运算符概述
运算符是用于执行特定数学或逻辑操作的符号。通过组合变量、常量和运算符,可以构成表达式(如 a + b
、true && false
)。表达式的运算结果具有值类型。
算术运算符
+
5 + 3
→ 8
+
(如 \"a\" + \"b\"
→ \"ab\"
)-
5 - 3
→ 2
*
5 * 3
→ 15
/
5 / 3
→ 1
(整数)%
5 % 3
→ 2
0
(如 10 % 0
会报错)示例代码:
int a = 10; int b = 3; Console.WriteLine(a / b); // 输出 3(整数除法) Console.WriteLine(a % b); // 输出 1(取余) // 字符串拼接 string name = \"张三\"; int age = 20; Console.WriteLine(name + \"今年\" + age + \"岁\"); // 输出:张三今年20岁
赋值运算符
=
int a = 10;
+=
a = a + n
a += 5
→ a = 15
-=
a = a - n
a -= 3
→ a = 7
*=
a = a * n
a *= 2
→ a = 20
/=
a = a / n
a /= 5
→ a = 2
%=
a = a % n
a %= 3
→ a = 1
自增 / 自减运算符(++
/--
)
-
后置自增(
a++
):先返回值,再自增。 -
前置自增(
++a
):先自增,再返回值。
示例:
int a = 5; int b = a++; // b = 5(先赋值,后a自增为6) int c = ++a; // c = 7(a先自增为7,再赋值给c) Console.WriteLine(a); // 输出 7 Console.WriteLine(b); // 输出 5 Console.WriteLine(c); // 输出 7
比较运算符(返回bool
类型)
<
5 < 3
→ false
>
5 > 3
→ true
<=
5 <= 5
→ true
>=
5 >= 3
→ true
==
5 == 3
→ false
!=
5 != 3
→ true
逻辑运算符(操作bool
值)
&&
true && false
→ false
||
true || false
→true
!
!true
→ false
&
true & false
→ false
|
true | false
→true
短路逻辑:
-
&&
:若左侧为false
,右侧不执行。 -
||
:若左侧为true
,右侧不执行。
示例:
int a = 5; bool result = (a > 10) && (++a > 0); // a>10为false,右侧不执行 Console.WriteLine(a); // 输出 5(a未自增) bool result2 = (a 0); // a<10为true,右侧不执行 Console.WriteLine(a); // 输出 5(a未自增)
运算符优先级(从高到低)
.
()
{}
;
++
--
!
*
/
%
+
-
<
>
<=
>=
==
!=
&
&&
?:
(三元运算符)建议:使用括号明确运算顺序,避免混淆(如 (a + b) * c
)。
2. 控制流语句
用于控制程序执行流程,支持常见的条件和循环结构。
2.1 条件语句
// if-elseint score = 85;if (score >= 90) { Console.WriteLine(\"优秀\");} else if (score >= 80) { Console.WriteLine(\"良好\");} else { Console.WriteLine(\"一般\");}// switch(支持模式匹配,C# 7.0+)var day = DayOfWeek.Monday;switch (day) { case DayOfWeek.Saturday: case DayOfWeek.Sunday: Console.WriteLine(\"周末\"); break; default: Console.WriteLine(\"工作日\"); break;}// switch表达式(C# 8.0+)string result = day switch { DayOfWeek.Saturday or DayOfWeek.Sunday => \"休息\", _ => \"工作\"};
2.2 循环语句
// for循环for (int i = 0; i < 5; i++) { Console.WriteLine(i);}// foreach循环(遍历集合)var names = new List { \"Alice\", \"Bob\" };foreach (var name in names) { Console.WriteLine(name);}// while循环int count = 0;while (count < 3) { Console.WriteLine(count++);}// do-while循环(至少执行一次)do { Console.WriteLine(\"执行一次\");} while (false);
3. 方法与参数
方法是代码复用的基本单元,支持多种参数传递方式。
3.1 方法定义与调用
// 方法定义(返回类型、方法名、参数列表)int Add(int a, int b) { return a + b;}// 调用方法int sum = Add(3, 5); // sum = 8
3.2 参数传递方式
// 值传递(默认)void Increment(int value) { value++; // 不影响原始值}// 引用传递(ref关键字)void Swap(ref int a, ref int b) { int temp = a; a = b; b = temp;}int x = 1, y = 2;Swap(ref x, ref y); // x=2, y=1// 输出参数(out关键字)void SplitName(string fullName, out string firstName, out string lastName) { var parts = fullName.Split(\' \'); firstName = parts[0]; lastName = parts.Length > 1 ? parts[1] : \"\";}SplitName(\"John Doe\", out var first, out var last);
3.3 可选参数与命名参数(C# 4.0+)
// 可选参数(提供默认值)void PrintInfo(string name, int age = 0) { Console.WriteLine($\"Name: {name}, Age: {age}\");}PrintInfo(\"Alice\"); // Age默认0// 命名参数(调用时指定参数名)PrintInfo(age: 30, name: \"Bob\");
4. 面向对象基础
C# 是纯面向对象语言,支持封装、继承和多态。
4.1 类与对象
// 类定义class Person { // 字段(通常私有) private string _name; // 属性(封装字段) public string Name { get => _name; set => _name = value; } // 自动属性(简化写法) public int Age { get; set; } // 构造函数 public Person(string name, int age) { Name = name; Age = age; } // 方法 public void SayHello() { Console.WriteLine($\"Hello, I\'m {Name}, {Age} years old.\"); }}// 创建对象var person = new Person(\"Charlie\", 22);person.SayHello(); // 输出: Hello, I\'m Charlie, 22 years old.
4.2 继承与多态
// 基类class Animal { public virtual void Speak() { // 虚方法,可被子类重写 Console.WriteLine(\"Animal speaks\"); }}// 派生类class Dog : Animal { public override void Speak() { // 重写基类方法 Console.WriteLine(\"Woof!\"); }}// 多态调用Animal animal = new Dog();animal.Speak(); // 输出: Woof!
4.3 接口(Interface)
定义行为契约,类可实现多个接口:
interface ICanSwim { void Swim();}interface ICanFly { void Fly();}class Duck : ICanSwim, ICanFly { public void Swim() => Console.WriteLine(\"Swimming...\"); public void Fly() => Console.WriteLine(\"Flying...\");}
5. 集合与数组
用于存储和操作多个元素。
5.1 数组(Array)
固定长度,类型统一:
int[] numbers = new int[5]; // 声明长度为5的整数数组numbers[0] = 100;// 初始化器语法string[] names = { \"Alice\", \"Bob\", \"Charlie\" };// 多维数组int[,] matrix = new int[3, 3];
5.2 泛型集合(推荐使用)
动态调整大小,类型安全:
// List(动态数组)var list = new List { 1, 2, 3 };list.Add(4);foreach (var num in list) { Console.WriteLine(num);}// Dictionary(键值对)var dict = new Dictionary { [\"apple\"] = 1, [\"banana\"] = 2};Console.WriteLine(dict[\"apple\"]); // 输出: 1// H吗你ashSet(不重复集合)var uniqueNumbers = new HashSet { 1, 2, 2 }; // 实际只有1, 2
6. 异常处理
使用try-catch-finally
结构捕获和处理运行时错误:
try { int result = 10 / 0; // 抛出DivideByZeroException}catch (DivideByZeroException ex) { Console.WriteLine(\"错误:除数不能为零\"); Console.WriteLine(ex.Message);}catch (Exception ex) { Console.WriteLine(\"未知错误:\" + ex.Message);}finally { Console.WriteLine(\"无论是否出错,都会执行此代码\");}
自定义异常:
public class CustomException : Exception { public CustomException(string message) : base(message) { }}
7. 命名空间与程序集
-
命名空间(Namespace):组织代码,避免命名冲突:
namespace MyApp.Data { public class DatabaseConnection { /* ... */ }}// 使用其他命名空间的类型using MyApp.Data;var conn = new DatabaseConnection();
-
程序集(Assembly):物理打包单元(.dll 或.exe),包含类型和资源。
8. 现代 C# 语法糖(C# 6.0+)
简化代码编写:
// 字符串内插(C# 6.0+)string name = \"Doubao\";Console.WriteLine($\"Hello, {name}!\"); // 替代string.Format// 表达式体方法(C# 6.0+)public string GetFullName() => $\"{FirstName} {LastName}\";// 空条件运算符(C# 6.0+)string result = person?.Name?.ToUpper(); // 若person或Name为null,直接返回null// 模式匹配(C# 7.0+)object obj = 42;if (obj is int num) { // 类型模式匹配并赋值 Console.WriteLine(num);}// 元组(Tuple)(C# 7.0+)(string First, string Last) GetName() => (\"John\", \"Doe\");var (first, last) = GetName();
通过上述内容,你已了解 C# 的基础语法结构。进一步学习可深入高级特性(如 LINQ、异步编程)或框架应用(如ASP.NET Core)。
C# 逻辑练习题解析
1. 判断奇偶数
题目:接收用户输入的整数,判断其奇偶性。 关键逻辑:利用取余运算符 %
判断是否能被 2 整除。
Console.Write(\"请输入一个整数: \");int number = Convert.ToInt32(Console.ReadLine()); // 兼容空输入的健壮性处理string result = number % 2 == 0 ? \"偶数\" : \"奇数\";Console.WriteLine($\"{number} 是{result}\");
扩展:负数的奇偶性判断与正数一致(如 -3 % 2 = -1
,取余结果符号与被除数相同)。
2. 找出三个数中的最大值
题目:比较三个整数,输出最大值。 解法 1:逐步比较
int a = 10, b = 25, c = 15;int max = Math.Max(Math.Max(a, b), c); // 利用内置Math类简化代码Console.WriteLine($\"最大值是: {max}\");
解法 2:三目运算符
int max = a > b ? (a > c ? a : c) : (b > c ? b : c);
注意:Math.Max
支持多个重载,可直接处理数组或参数列表。
3. 斐波那契数列
题目:输出前 n 项斐波那契数列(0, 1, 1, 2, 3, 5...)。 优化代码:
int n = 10;int first = 0, second = 1;Console.Write(\"斐波那契数列前{0}项: \", n);for (int i = 0; i < n; i++){ Console.Write(first + \" \"); (first, second) = (second, first + second); // 元组赋值简化代码}
扩展:递归实现(适用于小 n 值,大 n 会因重复计算导致性能问题):
int Fibonacci(int n) => n <= 1 ? n : Fibonacci(n-1) + Fibonacci(n-2);
4. 判断素数
题目:判断输入的正整数是否为素数(只能被 1 和自身整除)。 优化逻辑:
-
1 不是素数,直接排除。
-
只需遍历到平方根(减少循环次数)。
Console.Write(\"请输入一个正整数: \");if (!int.TryParse(Console.ReadLine(), out int num) || num < 2) // 输入验证{ Console.WriteLine(\"输入无效或非素数\"); return;}bool isPrime = true;for (int i = 2; i <= Math.Sqrt(num); i++){ if (num % i == 0) { isPrime = false; break; }}Console.WriteLine($\"{num} {(isPrime ? \"是\" : \"不是\")}素数\");
5. 反转字符串
题目:不使用内置反转方法(如Reverse()
),手动反转字符串。 核心思路:通过字符数组交换首尾字符。
string input = \"Hello World\";char[] chars = input.ToCharArray();for (int i = 0, j = chars.Length - 1; i < j; i++, j--){ (chars[i], chars[j]) = (chars[j], chars[i]); // 元组交换,无需临时变量}Console.WriteLine(\"反转后的字符串: \" + new string(chars));
注意:string
是不可变类型,需转换为char[]
操作。
6. 二分查找
题目:在有序数组中查找目标值的索引。 代码优化:
int[] sortedArray = { 2, 5, 8, 12, 16, 23, 38, 56, 72, 91 };int target = 23;int left = 0, right = sortedArray.Length - 1;while (left <= right){ int mid = left + (right - left) / 2; // 避免整数溢出 if (sortedArray[mid] == target) return mid; else if (sortedArray[mid] < target) left = mid + 1; else right = mid - 1;}Console.WriteLine(\"未找到目标值\");
前提:数组必须已排序,否则需先排序(如Array.Sort()
)。
7. 水仙花数
题目:找出 100-999 之间的水仙花数(各位数字立方和等于自身)。 数学拆解:
-
百位:
num / 100
-
十位:
(num / 10) % 10
-
个位:
num % 10
Console.WriteLine(\"100-999之间的水仙花数:\");for (int i = 100; i <= 999; i++){ int a = i / 100, b = (i / 10) % 10, c = i % 10; if (a*a*a + b*b*b + c*c*c == i) { Console.WriteLine(i); // 常见结果:153, 370, 371, 407 }}
8. 汉诺塔问题
题目:使用递归解决汉诺塔问题,输出移动步骤。 递归逻辑:
-
若只有 1 个盘子,直接移动。
-
否则,先将 n-1 个盘子从起点移到辅助柱,再移动第 n 个盘子,最后将 n-1 个盘子从辅助柱移到终点。
void Hanoi(int n, char from, char to, char aux){ if (n == 0) return; Hanoi(n-1, from, aux, to); // 递归移动n-1个盘子到辅助柱 Console.WriteLine($\"将盘子{n}从 {from} 移动到 {to}\"); Hanoi(n-1, aux, to, from); // 递归移动n-1个盘子到终点}Hanoi(3, \'A\', \'C\', \'B\'); // 输出3层汉诺塔的7步移动
扩展:时间复杂度为 O (2ⁿ),n 层需要 2ⁿ-1 步移动。