- C++
📦 C++ 栈(Stack)
- 2025-5-22 23:11:23 @
📦 C++ 栈(Stack)通俗易懂教程 🚀
📌 从零掌握栈的定义、实现、操作与励志鼓励语!
🎯 一、什么是栈?
栈(Stack) 是一种 后进先出(LIFO, Last In First Out) 的线性数据结构。
你可以把它想象成:
📦 一个只有一端开口的箱子,只能从顶部放进去或取出来东西。
🔢 最后放进来的元素,最先被取出。
✅ 栈的特点:
- 后进先出
- 插入和删除都在栈顶进行
- 不支持随机访问
🧱 二、栈的基本操作 ⚙️
操作 | 功能说明 |
---|---|
push(x) |
将元素 x 压入栈顶 |
pop() |
弹出栈顶元素 |
top() |
获取栈顶元素(不弹出) |
empty() |
判断栈是否为空 |
size() |
返回栈中元素个数 |
📈 三、图解栈的操作流程 📊
初始栈:[ ]
push(10) → [10]
push(20) → [10, 20]
push(30) → [10, 20, 30]
top() → 30
pop() → [10, 20]
🎯 这就是典型的“先进后出”行为!
🧪 四、C++ 中如何使用栈?💼
在 C++ 中,我们可以用两种方式来实现栈:
- ✅ 使用 STL 中的
stack
容器适配器 - ✅ 自定义栈结构(顺序栈/链式栈)
📦 方法一:使用 STL 的 stack(最简单)📦
#include <iostream>
#include <stack>
using namespace std;
int main() {
stack<int> s; // 创建一个整型栈
// 压栈
s.push(10);
s.push(20);
s.push(30);
cout << "栈顶元素: " << s.top() << endl; // 输出 30
// 出栈
s.pop();
cout << "新的栈顶: " << s.top() << endl; // 输出 20
// 判断是否为空
if (s.empty())
cout << "栈为空!" << endl;
else
cout << "栈不为空!" << endl;
// 获取当前栈大小
cout << "栈的大小: " << s.size() << endl;
return 0;
}
📌 输出:
栈顶元素: 30
新的栈顶: 20
栈不为空!
栈的大小: 2
🔗 方法二:自定义顺序栈(使用数组)🔗
适合想了解栈底层原理的同学!
#include <iostream>
#define MAX_SIZE 100
using namespace std;
// 定义顺序栈结构体
typedef struct {
int data[MAX_SIZE]; // 存储数据
int top; // 栈顶指针
} Stack;
// 初始化栈
void initStack(Stack* s) {
s->top = -1;
}
// 判断栈是否满
bool isFull(Stack* s) {
return s->top == MAX_SIZE - 1;
}
// 判断栈是否空
bool isEmpty(Stack* s) {
return s->top == -1;
}
// 入栈
bool push(Stack* s, int value) {
if (isFull(s)) {
cout << "栈已满,无法压栈!" << endl;
return false;
}
s->data[++s->top] = value;
return true;
}
// 出栈
bool pop(Stack* s) {
if (isEmpty(s)) {
cout << "栈为空,无法出栈!" << endl;
return false;
}
s->top--;
return true;
}
// 获取栈顶元素
int top(Stack* s) {
if (isEmpty(s)) {
cout << "栈为空,无栈顶元素!" << endl;
return -1;
}
return s->data[s->top];
}
// 获取栈大小
int size(Stack* s) {
return s->top + 1;
}
🧪 主函数测试:
int main() {
Stack s;
initStack(&s);
push(&s, 10);
push(&s, 20);
push(&s, 30);
cout << "栈顶元素:" << top(&s) << endl; // 输出 30
pop(&s);
cout << "出栈后栈顶:" << top(&s) << endl; // 输出 20
cout << "栈的大小:" << size(&s) << endl;
return 0;
}
📌 输出:
栈顶元素:30
出栈后栈顶:20
栈的大小:2
🧠 五、应用场景举例 💡
场景 | 示例 |
---|---|
括号匹配 | 判断表达式中的括号是否正确闭合 |
表达式求值 | 计算中缀、后缀表达式 |
浏览器历史记录 | 实现“返回上一页”功能 |
DFS 深度优先搜索 | 图或树的遍历 |
函数调用栈 | 程序运行时函数的调用机制 |
📌 六、注意事项 ❗
注意项 | 说明 |
---|---|
下标从 -1 开始 | top == -1 表示空栈 |
避免越界 | 压栈前要判断栈是否已满 |
出栈前检查 | 避免对空栈执行 pop |
可读性优化 | 封装为函数或类更清晰(本篇用结构体) |
🎁 七、小彩蛋:递归与栈的关系 🎲
🤔 你知道吗?递归的本质其实就是系统自动维护了一个“函数调用栈”!
每次进入一个函数,它就被压入栈; 每次返回结果,它就从栈中弹出。
🧠 所以你写的每一段递归代码,其实背后都是一段“隐式的栈”在帮你工作!
🏆 八、加油鼓励语 💪
👋 亲爱的同学,你已经掌握了 C++ 中非常实用的栈知识!这是通往算法高手之路的重要一步!
🧩 栈不仅是一个基础的数据结构,更是理解程序运行机制的关键。
🚀 掌握它,你会发现自己能轻松应对很多看似复杂的编程挑战!
🎯 不管是括号匹配、表达式计算,还是深度优先搜索,栈都是你的好帮手!
👏 继续努力,坚持练习,你一定能在编程世界中大放异彩!我们在这里为你打call!👏👏👏
📅 最后更新时间:2025年5月22日 23:07
🎉 祝你学习愉快,早日成为编程高手!🌟
1 条评论
-
admin SU @ 2025-5-22 23:12:04
📚 C++栈(Stack)完全教程:从入门到精通
🌟 欢迎进入栈的奇妙世界
在编程的世界里,栈(Stack)是一种非常重要且基础的数据结构。它遵循"后进先出"(Last In First Out, LIFO)的原则,如同叠放的盘子,最后放上去的总是最先被拿走。栈在计算机科学中有着广泛的应用,从函数调用、表达式计算到浏览器的后退功能,都离不开栈的身影。
今天,我们就来系统学习C++中的栈,从基本概念到实际应用,一步一步揭开栈的神秘面纱!
🧩 什么是栈?
栈是一种线性数据结构,它的操作遵循**后进先出(LIFO)**的原则。栈支持两种基本操作:
- 入栈(Push):将元素添加到栈顶
- 出栈(Pop):从栈顶移除元素
此外,栈通常还提供以下操作:
- 查看栈顶元素(Top/Peek):返回栈顶元素的值,但不移除它
- 判断栈是否为空(Empty):检查栈中是否有元素
- 获取栈的大小(Size):返回栈中元素的数量
🌰 生活中的栈比喻
栈就像一摞盘子:
- 新盘子总是放在最上面(入栈)
- 取盘子时总是从最上面拿(出栈)
- 只能看到最上面的盘子(查看栈顶元素)
- 如果没有盘子,栈为空(判断栈是否为空)
- 盘子的总数就是栈的大小(获取栈的大小)
🔧 栈的基本操作
栈的核心操作包括:
- Push(x):将元素x压入栈顶
- Pop():移除并返回栈顶元素
- Top():返回栈顶元素,但不移除
- Empty():判断栈是否为空
- Size():返回栈的大小
这些操作的时间复杂度都是O(1),即常数时间。
🛠️ C++中栈的实现方式
在C++中,栈有多种实现方式:
1. 使用数组实现栈
下面是一个使用数组实现的栈:
#include <iostream> using namespace std; const int MAX_SIZE = 100; template<typename T> class ArrayStack { private: T data[MAX_SIZE]; // 存储栈中元素的数组 int top; // 栈顶指针,指向栈顶元素的下一个位置 public: // 构造函数 ArrayStack() { top = 0; // 初始化栈顶指针为0 } // 判断栈是否为空 bool empty() const { return top == 0; } // 获取栈的大小 int size() const { return top; } // 入栈操作 void push(const T& value) { if (top >= MAX_SIZE) { cout << "栈已满,无法入栈!" << endl; return; } data[top++] = value; } // 出栈操作 void pop() { if (empty()) { cout << "栈为空,无法出栈!" << endl; return; } top--; } // 获取栈顶元素 T topElement() const { if (empty()) { cout << "栈为空,没有栈顶元素!" << endl; return T(); // 返回默认值 } return data[top - 1]; } }; int main() { ArrayStack<int> stack; // 入栈操作 stack.push(10); stack.push(20); stack.push(30); // 输出栈顶元素 cout << "栈顶元素: " << stack.topElement() << endl; // 输出: 30 // 出栈操作 stack.pop(); cout << "出栈后栈顶元素: " << stack.topElement() << endl; // 输出: 20 // 输出栈的大小 cout << "栈的大小: " << stack.size() << endl; // 输出: 2 return 0; }
2. 使用链表实现栈
下面是一个使用链表实现的栈:
#include <iostream> using namespace std; template<typename T> struct Node { T data; Node* next; Node(const T& value) : data(value), next(nullptr) {} }; template<typename T> class LinkedStack { private: Node<T>* topNode; // 栈顶节点指针 int count; // 栈中元素个数 public: // 构造函数 LinkedStack() : topNode(nullptr), count(0) {} // 析构函数 ~LinkedStack() { while (!empty()) { pop(); } } // 判断栈是否为空 bool empty() const { return count == 0; } // 获取栈的大小 int size() const { return count; } // 入栈操作 void push(const T& value) { Node<T>* newNode = new Node<T>(value); newNode->next = topNode; topNode = newNode; count++; } // 出栈操作 void pop() { if (empty()) { cout << "栈为空,无法出栈!" << endl; return; } Node<T>* temp = topNode; topNode = topNode->next; delete temp; count--; } // 获取栈顶元素 T topElement() const { if (empty()) { cout << "栈为空,没有栈顶元素!" << endl; return T(); // 返回默认值 } return topNode->data; } }; int main() { LinkedStack<int> stack; // 入栈操作 stack.push(10); stack.push(20); stack.push(30); // 输出栈顶元素 cout << "栈顶元素: " << stack.topElement() << endl; // 输出: 30 // 出栈操作 stack.pop(); cout << "出栈后栈顶元素: " << stack.topElement() << endl; // 输出: 20 // 输出栈的大小 cout << "栈的大小: " << stack.size() << endl; // 输出: 2 return 0; }
3. 使用C++标准库中的stack容器
C++标准库提供了
stack
容器,它是一个适配器类,默认使用deque
作为底层容器。#include <iostream> #include <stack> using namespace std; int main() { stack<int> stack; // 入栈操作 stack.push(10); stack.push(20); stack.push(30); // 输出栈顶元素 cout << "栈顶元素: " << stack.top() << endl; // 输出: 30 // 出栈操作 stack.pop(); cout << "出栈后栈顶元素: " << stack.top() << endl; // 输出: 20 // 输出栈的大小 cout << "栈的大小: " << stack.size() << endl; // 输出: 2 // 判断栈是否为空 if (stack.empty()) { cout << "栈为空" << endl; } else { cout << "栈不为空" << endl; } return 0; }
📊 数组栈 vs 链表栈 vs 标准库栈
特性 数组栈 链表栈 标准库栈(stack) 实现方式 静态数组 动态链表 适配器(默认deque) 内存管理 需要预先分配固定大小 动态分配,按需扩展 自动管理 插入/删除效率 O(1) 空间利用率 可能有空间浪费 按需分配,无浪费 自动优化 适用场景 元素数量固定或已知上限 元素数量不确定 快速开发,无需自定义 💡 栈的应用场景
栈在计算机科学中有广泛的应用,常见场景包括:
1. 函数调用栈
- 每当调用一个函数时,系统会将当前的执行上下文(局部变量、返回地址等)压入栈中
- 函数返回时,系统从栈中弹出执行上下文,恢复之前的执行状态
- 这就是为什么递归过深会导致栈溢出的原因
2. 表达式求值
- 中缀表达式转后缀表达式(逆波兰表达式)
- 后缀表达式的计算
- 括号匹配检查
3. 浏览器后退功能
- 浏览器将用户访问的每个页面依次压入栈中
- 用户点击后退按钮时,从栈中弹出页面并显示
4. 编辑器的撤销操作
- 编辑器将用户的每一步操作压入栈中
- 用户点击撤销按钮时,从栈中弹出最近的操作并恢复
🚀 栈的经典问题
1. 括号匹配问题
问题描述:检查表达式中的括号是否匹配
解决思路:
- 遍历表达式,遇到左括号时入栈
- 遇到右括号时,弹出栈顶元素并检查是否匹配
- 遍历结束后,栈应为空
#include <iostream> #include <stack> #include <string> using namespace std; bool isMatchingPair(char left, char right) { if (left == '(' && right == ')') return true; if (left == '[' && right == ']') return true; if (left == '{' && right == '}') return true; return false; } bool isBalanced(string expr) { stack<char> s; for (char c : expr) { if (c == '(' || c == '[' || c == '{') { s.push(c); // 左括号入栈 } else if (c == ')' || c == ']' || c == '}') { if (s.empty()) { return false; // 右括号多余 } char top = s.top(); s.pop(); if (!isMatchingPair(top, c)) { return false; // 括号不匹配 } } } return s.empty(); // 栈为空表示括号完全匹配 } int main() { string expr = "{[()]}"; if (isBalanced(expr)) { cout << "括号匹配" << endl; } else { cout << "括号不匹配" << endl; } return 0; }
2. 逆波兰表达式求值
问题描述:计算逆波兰表达式(后缀表达式)的值
解决思路:
- 遍历表达式,遇到操作数时入栈
- 遇到运算符时,弹出栈顶的两个操作数进行计算,并将结果入栈
- 遍历结束后,栈顶元素即为表达式的值
#include <iostream> #include <stack> #include <string> #include <sstream> using namespace std; int evaluateRPN(vector<string>& tokens) { stack<int> s; for (string token : tokens) { if (token == "+" || token == "-" || token == "*" || token == "/") { // 遇到运算符,弹出两个操作数 int b = s.top(); s.pop(); int a = s.top(); s.pop(); // 计算结果并压入栈 if (token == "+") s.push(a + b); else if (token == "-") s.push(a - b); else if (token == "*") s.push(a * b); else if (token == "/") s.push(a / b); } else { // 遇到操作数,转换为整数并入栈 int num; stringstream ss(token); ss >> num; s.push(num); } } return s.top(); // 返回栈顶元素 } int main() { vector<string> tokens = {"2", "1", "+", "3", "*"}; int result = evaluateRPN(tokens); cout << "表达式的值: " << result << endl; // 输出: 9 return 0; }
🌟 总结与鼓励
恭喜你完成了C++栈的学习!现在你已经掌握了:
- 栈的基本概念和后进先出(LIFO)的原则
- 栈的基本操作:入栈、出栈、查看栈顶元素、判断栈是否为空、获取栈的大小
- 栈的三种实现方式:数组栈、链表栈和C++标准库中的stack容器
- 栈的应用场景和经典问题:函数调用栈、表达式求值、括号匹配等
栈是编程中非常重要的一种数据结构,希望你能够熟练掌握并灵活运用。继续加油,你一定能在编程的道路上越走越远! 💪
📚 拓展学习
- 练习更多栈相关的算法题(如迷宫求解、汉诺塔等)
- 学习栈与递归的关系
- 探索栈在编译器、操作系统等领域的应用
- 研究其他数据结构(如队列、链表、树等)
记住,编程的进步源于不断的实践和思考。继续加油,你一定能成为编程高手! 🚀
- 1