目录
一,stack的基本操作
#include<iostream>
#include<stack> //引用栈的文件
using namespace std;
int main()
{
stack<int> s; //默认构造方法
//stack<double> s; 也可以构造别的类型的栈
//stack<string> s;
int num=1;
s.push(num);//入栈,将num的值存入栈中
cout<<"num="<<s.top()<<endl;//输出栈顶
s.pop();//出栈
if(s.empty()) cout<<"栈为空"<<endl; //判断栈是否为空
for(int i=0;i<5;i++) s.push(i);
cout<<"栈的大小="<<s.size()<<endl; //栈的大小
//拷贝调用函数的两种写法
stack<int> s2=s; //这里也是拷贝调用
stack<int> s3(s);//都是将s里的内容拷贝给s2或s3
//这种写法才是赋值
stack<int> s4;
s4=s;
return 0;
}
二,题目练习
A---表达式括号匹配
题目描述
假设一个表达式有英文字母(小写)、运算符(+,—,*,/)和左右小(圆)括号构成,以“@”作为表达式的结束符。请编写一个程序检查表达式中的左右圆括号是否匹配,若匹配,则返回"YES";否则返回"NO"。表达式长度小于255,左圆括号少于20个。
输入
输入表达式(只有1行,长度小于255)
输出
输出包括一行,即"YES"或"NO"
样例输入 Copy
【样例输入1】 2*(x+y)/(1-x)@ 【样例输入2】 (25+x)*(a*(a+b+b)@
样例输出 Copy
【样例输出1】 YES 【样例输出2】 NO
AC代码
#include <iostream>
#include <stack>
#include <string>
using namespace std;
int main() {
string expression;//字符串长度
stack<char> s;
getline(cin, expression, '@'); // 以@作为结束符,读入表达式
for (int i = 0; i < expression.length(); i++) {
if (expression[i] == '(') {//左括号入栈
s.push(expression[i]);
}
else if (expression[i] == ')') {
if (s.empty() || s.top() != '(') {//读入右括号时,若栈为空或栈顶不是左括号,则输出NO,终止程序
cout << "NO" << endl;
return 0;
} else {
s.pop();//若成功,则左括号出栈
}
}
}
if (s.empty()) {//若栈为空,则输出YES
cout << "YES" << endl;
} else {//不为空则代表左括号多了
cout << "NO" << endl;
}
return 0;
}
B---括弧匹配检验
题目描述
假设表达式中允许包含两种括号:圆括号和方括号,其嵌套的顺序随意,如([]())或[([][])]等为正确的匹配,[(])或([]()或(()))均为错误的匹配。
现在的问题是,要求检验一个给定表达式中的括弧是否正确匹配?
输入一个只包含圆括号和方括号的字符串,判断字符串中的括号是否匹配,匹配就输出 “OK” ,不匹配就输出“Wrong”。
输入一个字符串:[([][])],输出:OK
输入
输入仅一行字符(字符个数小于255)
输出
匹配就输出 “OK” ,不匹配就输出“Wrong”。
样例输入 Copy
[(])
样例输出 Copy
Wrong
AC代码
#include<iostream>
#include<stack>
#include<string>//调用getlinewen()函数
using namespace std;
int main()
{
string s;
stack<char> a;
getline(cin,s,'\n');//输入字符串,遇到'\n'停止
for(int i=0;i<s.length();i++){
if(s[i]=='('||s[i]=='['){//是括号的左边就进栈
a.push(s[i]);
}
else if(s[i]==')'){
if(a.empty()||a.top()!='('){
cout<<"Wrong"<<endl;
return 0;
}
else{
a.pop();
}
}
else if(s[i]==']'){
if(a.empty()||a.top()!='['){
cout<<"Wrong"<<endl;
return 0;
}
else{
a.pop();
}
}
}
if(a.empty()){
cout<<"OK"<<endl;
}
else{//不为空则代表左括号多了
cout<<"Wrong"<<endl;
}
return 0;
}
C---车厢调度
题目描述
有一个火车站,铁路如图所示,每辆火车从A驶入,再从B方向驶出,同时它的车厢可以重新组合。假设从A方向驶来的火车有n节(n<=1000),分别按照顺序编号为1,2,3,…,n。假定在进入车站前,每节车厢之间都不是连着的,并且它们可以自行移动到B处的铁轨上。另外假定车站C可以停放任意多节车厢。但是一旦进入车站C,它就不能再回到A方向的铁轨上了,并且一旦当它进入B方向的铁轨,它就不能再回到车站C。
负责车厢调度的工作人员需要知道能否使它以a1,a2,…,an的顺序从B方向驶出,请来判断能否得到指定的车厢顺序。
输入
输入文件的第一行为一个整数n,其中n<=1000,表示有n节车厢,第二行为n个数字,表示指定的车厢顺序。
输出
如果可以得到指定的车厢顺序,则输出一个字符串”YES”,否则输出”NO”(注意要大写,不包含引号)。
样例输入 Copy
5 5 4 3 2 1
样例输出 Copy
YES
AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;
int main(){
stack <int> q;
int a,b[1000+5],j=1;
scanf("%d",&a);
for(int i=1;i<=a;i++){
scanf("%d",&b[i]);
}
for(int i=1;i<=a;i++){
q.push(i);//依次进栈
while(!q.empty()&&q.top()==b[j]){//直到栈顶与想要的值相同时出栈
j++;
q.pop();
}
}
if(q.empty()==1){//若栈为空,则代表符合车厢顺序,输出“YES”
printf("YES");
}
else{
printf("NO");
}
return 0;
}
D---字符串匹配
题目描述
字符串中只含有括号 (),[],<>,{},判断输入的字符串中括号是否匹配。如果括号有互相包含的形式,从内到外必须是<>,(),[],{},例如。输入: [()] 输出:YES,而输入([]), ([])都应该输出NO。
输入
第一行为一个整数n,表示以下有多少个由括好组成的字符串。接下来的n行,每行都是一个由括号组成的长度不超过255的字符串
输出
在输出中有N行,每行都是YES或NO。
样例输入 Copy
5 {}{}<><>()()[][] {{}}{{}}<<>><<>>(())(())[[]][[]] {{}}{{}}<<>><<>>(())(())[[]][[]] {<>}{[]}<<<>><<>>>((<>))(())[[(<>)]][[]] ><}{{[]}<<<>><<>>>((<>))(())[[(<>)]][[]]
样例输出 Copy
YES YES YES YES NO
难点:符号优先级的考虑,可以用switch-case()来进行条件判断
AC代码
#include <iostream>
#include <stack>
#include <string>
using namespace std;
//检验符号优先级问题
int check(char c, stack<char> st) {
if (st.empty()) return 1;
else {
switch (c) {
//{入栈时,前面不能是 [ ( <
case '{': if (st.top() == '[' || st.top() == '(' || st.top() == '<') return 0;
// [ 入栈时 前面不能是 ( <
case '[': if (st.top() == '(' || st.top() == '<') return 0;
// ( 入栈时 前面不能是 <
case '(': if (st.top() == '<') return 0;
// < 可以直接入栈
case '<': st.push(c); break;
// () 差1 其他括号的差2
}
return 1;
}
}
// 函数用于判断括号是否匹配
bool isMatchingPair(char opening, char closing) {
return (opening == '(' && closing == ')') ||
(opening == '[' && closing == ']') ||
(opening == '{' && closing == '}') ||
(opening == '<' && closing == '>');
}
// 函数用于判断字符串中的括号是否平衡
bool isBalanced(string expr) {
stack<char> st; // 用于存放左括号的栈
for (char c : expr) {//将字符串expr中的每个字符赋值给c,遍历
if (c == '(' || c == '[' || c == '{' || c == '<') {
if (check(c,st)) st.push(c); // 遇到左括号,入栈
else return false;
}
else if (c == ')' || c == ']' || c == '}' || c == '>') {
if (st.empty() || !isMatchingPair(st.top(), c)) {
return false; // 遇到右括号,检查栈顶是否与之匹配,不匹配则返回false
}
st.pop(); // 匹配,则弹出栈顶元素
}
}
return st.empty(); // 若栈为空,则括号平衡,返回true;否则返回false
}
int main() {
int n;
cin >> n; // 输入测试数据组数
cin.ignore(); // 忽略读取n后的换行符
for (int i = 0; i < n; i++) {
string expr;
getline(cin, expr); // 读取每组测试数据的括号字符串
if (isBalanced(expr)) {
cout << "YES" << endl; // 判断括号是否平衡并输出结果
}
else {
cout << "NO" << endl;
}
}
return 0;
}
E---情书
雄雄学长的智商高达180,但他有个憨憨的习惯——写英语的时候喜欢把每一个单词都倒过来写。现在他写了一封给女神的情书,但是因为他的坏习惯,女神看不懂他的信,来找你帮忙。你能帮雄雄学长,向女神翻译他的信吗?
Input
输入包含多组数据。 第一行输入一个正整数 T 表示总的行数。接下来是T行。
每行包含一些单词,每行最多1000个字符。
Output
对于每一行输入的每个单词,请你都把他倒过来,雄雄学长会谢谢你的哟。
注意,雄雄学长只会将每个由空格所分隔的单词倒过来写,但单词间的顺序不会变。
Sample Input
3
!hO yM .raed
m'I .gnoixgnoix
I evol .uoy
Sample Output
Oh! My dear.
I'm xiongxiong.
I love you.
实现:以空格为标志,将输入的字符进栈,当入读空格时,出栈
AC代码
#include<iostream>
#include<string.h>
#include<sstream>
#include<stack>
#include<ctype.h>
using namespace std;
int main(){
string s;
while(getline(cin, s) && s != "0"){
//判断是否为0
stack<double> nums;
stringstream s1(s);
//用stringstream分割空格
while(s1 >> s){
if(isdigit(s[0])){
//判断当前是否数字
stringstream s2;
double num;
s2 << s;
s2 >> num;
nums.push(num);
//存入数字
}else{
if(s == "+" || s == "-"){
if(s == "-"){
//如果是减,读入后面的数字*-1存进栈里
double num;
s1 >> num;
nums.push(num * -1);
}
}else{
//如果是乘除,读入后面的数字运算后存进栈里
double num;
s1 >> num;
double num1 = nums.top();
nums.pop();
if(s == "*"){
nums.push(num1 * num);
}else{
nums.push(num1 / num);
}
}
}
}
//栈内只剩下+,将所有的数字加起来
double num = nums.top();
nums.pop();
while(nums.size()){
double num1 = nums.top();
nums.pop();
num = num + num1;
}
printf("%.2lf\n", num);
}
return 0;
}
E---计算器
读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。
Input
测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔。没有非法表达式。当一行中只有0时输入结束,相应的结果不要输出。
Output
对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。
Sample
Inputcopy | Outputcopy |
---|---|
1 + 2 4 + 2 * 5 - 7 / 11 0 | 3.00 13.36 |
难点:符号优先级的考虑,字符串的读取和转换类型。遇到乘除则读取后面的数字直接计算,遇到减,则之间将后面的数字变为负数。最后把所有的数加起来。关于字符串的处理可以使用stringstream。
AC代码
#include<iostream>
#include<string.h>
#include<sstream>
#include<stack>
#include<ctype.h>
using namespace std;
int main() {
string s;
while (getline(cin, s) && s != "0") {
//判断是否为0
stack<double> nums;
stringstream s1(s);
//用stringstream分割空格
while (s1 >> s) {//从s1中逐步读取字符串,并赋值给s
if (isdigit(s[0])) {
//判断当前是否数字
stringstream s2;
double num;
s2 << s;
s2 >> num;//将字符串s变为double类型
nums.push(num); //存入数字
}
else {
if (s == "+" || s == "-") {
if (s == "-") {
//如果是减,读入后面的数字*-1存进栈里
double num;
s1 >> num;
nums.push(num * -1);
}
}
else {
//如果是乘除,读入后面的数字运算后存进栈里
double num;
s1 >> num;
double num1 = nums.top();
nums.pop();
if (s == "*") {
nums.push(num1 * num);
}
else {
nums.push(num1 / num);
}
}
}
}
//栈内只剩下+,将所有的数字加起来
double num = nums.top();
nums.pop();
while (nums.size()) {
double num1 = nums.top();
nums.pop();
num = num + num1;
}
printf("%.2lf\n", num);
}
return 0;
}