# Stack
概念：
	`Stack` 是 C# 提供的一个==非泛型栈集合==
	栈的特点是：==先进后出，后进先出==

英文：
	`LIFO`：Last In First Out

简单理解：
	像一摞盘子
	最后放上去的，最先被拿走

命名空间：
```csharp
using System.Collections;
```

----
# 通常用法
1. 处理需要“后进先出”的数据
2. 临时保存操作记录
3. 实现撤销、回退、调用顺序等逻辑
4. 学习栈这种数据结构

实际开发中：
	新代码更推荐使用 `Stack<T>`
	这里的 `Stack` 是非泛型版本，主要用于理解集合和数据结构

----
# 语法
创建：
```csharp
Stack stack = new Stack();
```

入栈：
```csharp
stack.Push(数据);
```

出栈：
```csharp
object value = stack.Pop();
```

查看栈顶：
```csharp
object value = stack.Peek();
```

数量：
```csharp
stack.Count
```

----
# 基础案例
```csharp
using System;
using System.Collections;

Stack stack = new Stack();

stack.Push("第一步");
stack.Push("第二步");
stack.Push("第三步");

Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
Console.WriteLine(stack.Pop());
```

输出：
```text
第三步
第二步
第一步
```

理解：
1. `"第一步"` 最先进栈
2. `"第三步"` 最后进栈
3. `Pop()` 会先取出最后进去的元素

----
# Push、Pop、Peek
`Push`：
	把元素放到栈顶

```csharp
stack.Push("A");
```

`Pop`：
	取出并删除栈顶元素

```csharp
object item = stack.Pop();
```

`Peek`：
	只查看栈顶元素，不删除

```csharp
object item = stack.Peek();
```

案例：
```csharp
Stack stack = new Stack();
stack.Push("A");
stack.Push("B");

Console.WriteLine(stack.Peek()); // B
Console.WriteLine(stack.Count);  // 2

Console.WriteLine(stack.Pop());  // B
Console.WriteLine(stack.Count);  // 1
```

----
# 遍历
```csharp
Stack stack = new Stack();

stack.Push("A");
stack.Push("B");
stack.Push("C");

foreach (object item in stack)
{
	Console.WriteLine(item);
}
```

输出顺序一般是：
```text
C
B
A
```

理解：
	遍历 `Stack` 时，也是从栈顶到栈底

----
# 常用成员
```csharp
Stack stack = new Stack();

stack.Push("A");
stack.Push("B");

Console.WriteLine(stack.Count);
Console.WriteLine(stack.Contains("A"));

object top = stack.Peek();
object value = stack.Pop();

stack.Clear();
```

常用方法：
1. `Push(object obj)`：入栈
2. `Pop()`：出栈并删除
3. `Peek()`：查看栈顶但不删除
4. `Contains(object obj)`：判断是否包含
5. `Clear()`：清空
6. `ToArray()`：转成数组

----
# 空栈不能 Pop 或 Peek
错误写法：
```csharp
Stack stack = new Stack();

stack.Pop();
```

原因：
	栈里没有元素，不能取栈顶

更稳的写法：
```csharp
if (stack.Count > 0)
{
	object value = stack.Pop();
}
```

`Peek()` 也一样，使用前最好先判断 `Count`。

----
# 取值时要类型转换
```csharp
Stack stack = new Stack();
stack.Push(100);

int num = (int)stack.Pop();
```

原因：
	非泛型 `Stack` 中的元素按 `object` 存储
	取出来也是 `object`

如果值类型放进去，会涉及装箱和拆箱：
```csharp
stack.Push(100);        // 装箱
int num = (int)stack.Pop(); // 拆箱
```

----
# 适合场景：撤销操作
```csharp
Stack undoStack = new Stack();

undoStack.Push("创建角色");
undoStack.Push("移动角色");
undoStack.Push("修改颜色");

if (undoStack.Count > 0)
{
	string lastAction = (string)undoStack.Pop();
	Console.WriteLine("撤销：" + lastAction);
}
```

理解：
	最后做的操作，通常最先撤销
	所以适合用栈

----
# Stack 和 ArrayList 的区别
| 对比点 | ArrayList | Stack |
|---|---|---|
| 访问方式 | 按下标访问 | 只关心栈顶 |
| 数据顺序 | 按添加顺序保存 | 后进先出 |
| 添加方法 | `Add` | `Push` |
| 取出方法 | `list[index]` | `Pop` / `Peek` |
| 适合场景 | 普通列表 | 回退、撤销、临时反向处理 |

----
# 注意
1. `Stack` 在 `System.Collections` 命名空间中
2. `Stack` 是非泛型集合，元素按 `object` 存储
3. 栈的规则是后进先出
4. `Push` 是入栈
5. `Pop` 是取出并删除栈顶
6. `Peek` 是查看栈顶但不删除
7. 空栈调用 `Pop()` 或 `Peek()` 会出错
8. 新项目通常优先使用 `Stack<T>`

----
# 一句话记忆
==Stack 是后进先出的集合，最后放进去的最先出来。==

----
# 面试/复习时怎么说
可以这样答：

“Stack 是栈结构，特点是后进先出，也就是 LIFO。  
常用方法有 `Push`、`Pop` 和 `Peek`，分别表示入栈、出栈、查看栈顶。  
非泛型 Stack 存的是 object，取值时可能需要强制类型转换，新项目中更推荐使用 `Stack<T>`。”

----
引用：
1. Microsoft Learn: [Stack Class](https://learn.microsoft.com/en-us/dotnet/api/system.collections.stack?view=net-9.0)
2. Microsoft Learn: [System.Collections Namespace](https://learn.microsoft.com/en-us/dotnet/api/system.collections?view=net-9.0)

#Stack
#栈
#集合
#进阶
