栈是一种基本的数据结构,具有后进先出(LIFO)的特点。在栈中,最后进入的元素最先被访问。在实际生活中,例如乘坐电梯或使用药片盒时,都可以用栈的概念来解释。在C++中,我们可以使用<stack>
头文件提供的栈类实现栈数据结构。
栈的操作
- 栈的定义,Stack类同样是模板类,因此需要在尖括内声明数据类型,例如int、float、char等基本数据类型或自定义类型:
stack<Type> S;
定义了一个栈对象S
,它存储的元素类型由Type
表示。
- 将元素item压入栈顶:
S.push(item);
将一个元素item
添加到栈的顶部。这相当于将元素放在栈的顶部,而原来在栈顶的元素会被往下推。这就是入栈操作。
- 返回栈顶元素,但是不删除该元素:
S.top();
会返回栈顶的元素,但并不从栈中移除它。它用于查看栈中当前位于栈顶的元素,不影响栈原本的结构。
- 删除栈顶元素,不返回该元素:
S.pop();
将栈顶的元素从栈中移除,但并不返回该元素的值。因此通常会先使用S.top()
获取栈顶元素的值,然后使用S.pop()
将其从栈中删除。进行出栈操作,防止出栈元素丢失。
- 返回栈中元素个数:
S.size();
返回栈中元素的数量,即栈当前的大小。
- 检查栈是否为空:
S.empty();
检查栈是否为空。如果栈中没有任何元素,就认为栈为空,返回true
;否则,返回false
。你可以使用这个函数来判断是否需要进一步处理栈中的元素。
堆栈数据结构的视频演示
下面是一个我使用Manim(Python库)制作的有关堆栈数据结构后入先出的演示过程。
【Manim】堆栈可视化演示【数据结构】
示例解析:hdu 1062 “Text Reverse”
-
题目来源:hdu 1062 Text Reverse Hangzhou Dianzi University ACM Team
-
题目
- Problem Description
Ignatius likes to write words in reverse way. Given a single line of text which is written by Ignatius, you should reverse all the words and then output them. - Input
The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow.
Each test case contains a single line with several words. There will be at most 1000 characters in a line. - Output
For each test case, you should output the text which is processed. - Sample Input
3 olleh !dlrow m'I morf .udh I ekil .mca
- Sample Output
hello world! I'm from hdu. I like acm.
- Hint
Remember to use getchar() to read ‘\n’ after the interger T, then you may use gets() to read a line and process it.
- Problem Description
-
题目(翻译)
- 题目描述:
伊格纳修斯喜欢以相反的方式书写单词。给定由伊格纳修斯编写的一行文本,你应该颠倒所有单词的顺序,然后输出它们。 - 输入:
输入包含多个测试用例。第一行是一个整数T,表示测试用例的数量。接下来是T行,每行包含若干个单词。每行的长度不超过1000个字符。 - 输出:
对于每个测试用例,你应该输出处理后的文本。 - 示例输入:
3 olleh !dlrow m'I morf .udh I ekil .mca
- 示例输出:
hello world! I'm from hdu. I like acm.
- 提示:
记得使用getchar()
来读取整数T后的换行符\n
,然后可以使用gets()
读取一行并进行处理。
- 题目描述:
-
解题思路:
- 首先我们先声明部分变量。
int n;//记录输入的测试用例数量 char ch;//存储读入的字符
- 然后读入数据并且对数据处理。
scanf("%d", &n);//读取一个整数n getchar();//处理输入缓冲区中的换行符
- 设置外层循环,执行n次。
while (n--);
- 题目要求翻转字符串。我们可以使用栈来模拟该过程。
- 循环部分。
- 在内层循环中,定义一个
stack<char> S;
,用于存储字符。 - 使用
ch = getchar();
从输入中读取一个字符,赋值给变量ch
。 - 进入一个判断语句
if (ch == ' ' || ch == '\n' || ch == EOF)
,判断读入的字符是否为空格、换行或文件结尾。 - 如果是空格、换行或文件结尾,进入一个循环
while (!S.empty())
,将栈中的元素输出并清除。 - 使用
printf("%c", S.top());
输出栈顶元素。 - 使用
S.pop();
将栈顶元素弹出,达到清除栈顶的目的。
- 在内层循环中,定义一个
- 判断语句。
- 如果判断到换行符或文件结尾,跳出内层循环。
- 如果是空格,则输出一个空格。
- 如果不是空格,则将字符入栈
S.push(ch);
。
- 内层循环结束后,输出一个换行符。
- 外层循环结束后,返回 0,表示程序正常运行结束。
- 首先我们先声明部分变量。
-
总代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
char ch;
scanf("%d", &n);
getchar();
while (n--) {
stack<char> S;
while (true) {
ch = getchar();
if (ch == ' ' || ch == '\n' || ch == EOF) {
while (!S.empty()) {
printf("%c", S.top());
S.pop();
}
if (ch == '\n' || ch == EOF)
break;
printf(" ");
} else {
S.push(ch);
}
}
printf("\n");
}
return 0;
}
上述程序通过栈来翻转字符串。根据题目要求,我们按照空格、换行符或文件结尾作为分隔符,将输入的字符串进行翻转输出。
3. 栈的爆栈问题
栈在使用过程中需要一定的空间来存储元素。如果栈的深度过大或存入栈的数组过大,总数会超过系统为栈分配的空间,导致栈溢出的问题。解决此问题的方法有两种:
- 调整系统栈大小:通过在程序中调大系统的栈大小,但这种方法依赖于系统和编译器。
- 手工实现栈:可以手动编写栈的数据结构,详细内容可参考本书第10.5节。
本文对栈的使用进行初步介绍。在实际应用中,应根据需求选择合适的数据结构和操作,以实现更高效和准确的算法。
参考资料:
算法竞赛入门到进阶 罗勇军
Problem - 1062 Hangzhou Dianzi University Online Judge 3.0