数据结构——栈

栈 计蒜客 - A1047

问题描述

这是一个简单的栈问题,你将会有4个操作:

  1. push x 将 x 入栈;
  2. pop 将栈顶元素移除;
  3. sum 是输出此时栈里的元素的个数;
  4. out 是将栈的元素全部输出。

输入格式:

本题多组测试数据,每组第一行输入一个整数 n (n<100),代表接下来的操作数。

接下来的 n 行输入操作方式。

输出格式:按题意输出,并换行。

样例输入

7
push 12
push 142
push 456
sum
pop
sum
out

样例输出

3
2
142
12
  • 参考程序
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
const int N=1e5+10;
int sta[N], head=0;

void push(int x) {//入栈
    sta[++head] = x;//[1,N]
}
void pop() {//出栈
    --head;
}
int top() {//栈顶
    return sta[head];
}
bool empty() {//栈空 
    return head==0;
}
int size() {
    return head;
}
void out() {
    for(int i=head; i>=1; i--) {
        cout<<sta[i]<<endl;
    }
}
void init() {
    //memset(sta,0,sizeof(sta));
    head=0;
}
int main() {
    //freopen("data.in","r",stdin);
    int n;
    while(cin>>n) {
    	init(); 
        for(int i=1; i<=n; i++) {
            string op; int x; cin>>op;
            if(op=="push") {
                cin>>x; push(x);
            } else if(op=="sum") {
                cout<<size()<<endl;
            } else if(op=="pop") {
                pop();
            } else if(op=="out") {
                out();
            }
        }
    }
    return 0;
}

操作栈 51Nod - 3199

问题描述

有一个初始为空的栈,我们对这个栈进行n次操作,操作共分为2种:

  1. 1 x(将数字 x 放入栈)
  2. 2(将栈顶元素弹出)

对于第2种操作,你需要把弹出的这个数字输出,如果进行操作2时,栈为空,则输出"empty"。

例如:n = 5,对应的操作为:
1 123 (操作后栈里面的元素为:123)
1 234(操作后栈里面的元素为:123, 234)
2(输出:234,操作后栈里面的元素为:123)
2(输出:123,操作后栈里面的元素为:空)
2(输出:empty)
对应后面3个第2类操作,你的程序需要输出,
234
123
empty

输入格式:第一行,1个数n(1 <= n <= 10000);

后面n行,每行1种操作,1 X或者2(0 <= x <= 10000)。

输出格式:对应所有操作2,输出被弹出的数或者"empty"

样例输入

5
1 123
1 234
2
2
2

样例输出

234
123
empty
  • 参考程序
#include<iostream>
#include<stack>
using namespace std;
stack<int> sta; // 定义格式
int main(){
//	freopen("data.in", "r", stdin);// read
//	freopen("data.out", "w", stdout);// write
    int n; cin>>n;
    for(int i=1; i<=n; i++){
        int op,x; cin>>op;
        if(op==1){
            cin>>x; sta.push(x);
        }else if(op==2){
            if(sta.empty()) {
                cout<<"empty"<<endl;
            }else {
                cout<<sta.top()<<endl;
                sta.pop();
            }
        }
    } 
    return 0;
}

出栈合法性 计蒜客 - T1565

问题描述

已知自然数 1, 2, …, N(1≤N≤100)依次入栈,请问序列 C1,C2,…,CN是否为合法的出栈序列。

输入格式

输入包含多组测试数据。

每组测试数据的第一行为整数 N(1≤N≤100),当 N=0 时,输入结束。

第二行为 N 个正整数,以空格隔开,为出栈序列。

输出格式

对于每组输入,输出结果为一行字符串。

如给出的序列是合法的出栈序列,则输出"Yes",否则输出"No"。

样例输入

5
3 4 2 1 5
5
3 5 1 4 2
0

样例输出

Yes
No
  • 参考程序
#include<iostream>
#include<algorithm>
using namespace std;
const int N=110;
int a[N], sta[N],head=0,pre=0;
int main(){
    //freopen("data.in","r",stdin);
    int n;
    while(cin>>n){
        if(n==0) break;
        for(int i=1;i<=n;i++) cin>>a[i];
        head=0,pre=1;
        for(int i=1;i<=n;i++){
            pre=max(pre,a[i-1]+1);//原本应该出现的元素 
            if(a[i]>pre){//升序入栈 
                for(int j=pre;j<a[i];j++){
                    sta[++head]=j;
                }
            }else if(a[i]==sta[head]){
                --head;
            }
        }
        if(head>0) cout<<"No\n";
        else cout<< "Yes\n";
    }
    return 0;
}

表达式括号匹配 计蒜客 - T1655

问题描述

给出一个表达式,该表达式仅由字符(、)、+、-以及数字组成。

请编写一个程序检查表达式中的左右圆括号是否匹配,若匹配,则返回"YES";否则返回"NO"。

输入格式:一行一个表达式,长度不超过 2000。

输出格式:若匹配,则输出"YES";否则输出"NO"

样例输入:2+(3-4)-2-6)

样例输出:NO

  • 参考程序
#include<iostream>
#include<algorithm>
#include<stack>
using namespace std;
stack<char> sta; 
int main(){
//    freopen("data.in","r",stdin);
    string s; getline(cin, s);
    bool flag=1;
	for(int i=0; i<s.length(); i++){
		if(s[i]=='(') sta.push(s[i]);
		else if(s[i]==')') {
			if(!sta.empty()) sta.pop();
			else {
				flag=0; break;
			}
		}
	}
	if(flag && sta.empty()) cout<<"YES"<<endl;
	else cout<<"NO"<<endl;
    return 0;
}

括号匹配 计蒜客 - 42574

问题描述

蒜头君在纸上写了一个串,只包含’(‘和’)‘。
一个’(‘能唯一匹配一个’)‘,但是一个匹配的’(‘必须出现在’)'之前。

请判断蒜头君写的字符串能否括号完全匹配,
如果能,输出配对的括号的位置(匹配的括号不可以交叉,只能嵌套)。

输入格式

一行输入一个字符串只含有’(‘和’)',输入的字符串长度不大于 50000。

输出格式

如果输入括号不能匹配,输出一行"No",否则输出一行"Yes",

接下里若干行每行输出 2 个整数,用空格隔开,表示所有匹配对的括号的位置(下标从 1 开始)。

你可以按照任意顺序输出。

样例输入

(())

样例输出

Yes
1 4
2 3
  • 参考程序
#include<iostream>
#include<algorithm>
#include<stack>
#include<string>
using namespace std;
const int N=1e5+10;
int a[N], b[N], cnt=0;
stack<int> sta;
int main(){
//    freopen("data.in","r",stdin);
    string s; getline(cin, s);
    bool flag=1;
	for(int i=0; i<s.length(); i++){
		if(s[i]=='(') sta.push(i);
		else if(s[i]==')') {
			if(!sta.empty()) {
				++cnt;
				a[cnt] = sta.top()+1;
				b[cnt] = i+1;
				sta.pop();
			} else {
				flag=0; break;
			}
		}
	}
	if(flag && sta.empty()) {
		cout<<"Yes"<<endl;
		for(int i=1; i<=s.length()/2; i++){
			cout<<a[i]<<" "<<b[i]<<endl;
		}
	}else cout<<"No"<<endl;
    return 0;
}

后缀表达式(逆波兰表达式) 51Nod - 3404

问题描述

后缀表达式是一种把运算符后置的算术表达式,例如普通的表达式 2 + 3 的后缀表示法为 2 3 +。

后缀表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如 (2 + 3) * 4 的后缀表示法为 2 3 + 4 *。

本题求解后缀表达式的值,其中运算符包括+ - * /四个。

计算后缀表达式,要从前向后遍历字符串。

当遇见运算数时,压入栈中。

当读到运算符时,将栈中的连续2个运算数弹栈;

用当前运算符计算后(注意后缀表达式的先出栈的运算数,放在运算符后面;后出栈的运算数,放在运算符前面),再将结果压栈。

最后的栈顶就是后缀表达式的运算结果。

输入格式:输入为一行,其中运算符和运算数之间都用空格分隔,运算数是浮点数。

输出格式:输出为一行,表达式的值。

输入样例:11.0 12.0 + 24.0 35.0 + *

输出样例:1357.000000

可使用以下语句保留固定长度的小数点后尾数

C++:cout<<setiosflags(ios::fixed)<<setprecision(6)<<ans<<endl;
C:printf("%.6lf\n", ans);
  • 参考程序
#include<iostream>
#include<stack> 
#include<cstring>
#include<cstdlib>
#include<cstdio>
using namespace std;
stack<double> sta;
double n,m;
char s[110];
int main(){
    // freopen("data.in", "r", stdin);
    while(~scanf("%s", s)){
        if(s[0]!='+' && s[0]!='-' && s[0]!='*' && s[0]!='/'  ){
            sta.push(atof(s));//字符数组转数字的 2种方式 
         // sscanf(s, "%lf", &n); sta.push(n);
        }else if(strlen(s)>1){//负数的情况
            sta.push(atof(s)); 
        }else{
            n = sta.top(); sta.pop();
            m = sta.top(); sta.pop();
            switch(s[0]){
                case '+': sta.push(m+n); break;
                case '-': sta.push(m-n); break;
                case '*': sta.push(m*n); break;
                case '/': sta.push(m/n); break;
            }
        } 
    }
    printf("%.6lf\n", sta.top());    
    return 0;
}

中缀表达式求值 51Nod - 3425

问题描述

现在给你一个中缀表达式,式子中包括±*/()六种运算符号,要求你求出这个中缀表达式的值。

中缀表达式:所谓中缀表达式就是我们平常写的算式,例如1+2、(1+2)*3,。

输入格式:输入一个中缀表达式。

输出格式:输出一行,表示表达式的值。

输入样例:( 11.0 + 12.0 ) * ( 24.0 + 35.0 )

输出样例:1357.000000

  • 参考程序

波兰表达式 OpenJ_Bailian - 2694

问题描述

波兰表达式是一种把运算符前置的算术表达式,
例如普通的表达式2 + 3的波兰表示法为+ 2 3。

波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,
例如(2 + 3) * 4的波兰表示法为* + 2 3 4。

本题求解波兰表达式的值,其中运算符包括+ - * /四个。

输入格式:输入为一行,其中运算符和运算数之间都用空格分隔,运算数是浮点数。

输出格式:输出为一行,表达式的值。可直接用printf(“%f\n”, v)输出表达式的值v。

样例输入:* + 11.0 12.0 + 24.0 35.0

样例输出:1357.000000

提示
可使用 atof(str) 把字符串转换为一个 double 类型的浮点数。
atof 定义在 math.h 中。
此题可使用函数递归调用的方法求解。

  • 参考程序
#include<iostream>
#include<stack>
#include<cstdio>
#include<cstdlib>
using namespace std;
double  fun(){
    char s[110]; scanf("%s", s);
    switch(s[0]){
        case '+': return fun()+fun();
        case '-': return fun()-fun();
        case '*': return fun()*fun();
        case '/': return fun()/fun();
    }
    return atof(s);
} 
int main(){
    printf("%lf\n", fun());
    return 0;
}

简单计算器 HDU - 1237

问题描述

读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。

输入格式

测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,
整数和运算符之间用一个空格分隔。

没有非法表达式。
当一行中只有0时输入结束,相应的结果不要输出。

输出格式

对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。

输入样例

1 + 2
4 + 2 * 5 - 7 / 11
0

输出样例

3.00
13.36
  • 参考程序
#include<iostream>
#include<iomanip>
#include<stack>
#include<cstdio>
using namespace std;
int main() {
//    freopen("data.in", "r", stdin);
    double a,b,c; char ch;
    while(cin>>a){
        stack<double> sta; 
        sta.push(a);
        while(getchar()!='\n'){//空格 
            cin>>ch>>b;
            if(ch=='+') sta.push(b);
            else if(ch=='-') sta.push(-b);
            else if(ch=='*') {
                c = sta.top(); sta.pop();
                sta.push(b*c);
            }else if(ch=='/'){
                c = sta.top(); sta.pop();
                sta.push(c/b);
            }
        }
        if(sta.size()==1 && sta.top()==0) return 0;
        double ans=0;
        while(!sta.empty()){
            ans += sta.top(); sta.pop();
        }
        cout<<fixed<<setprecision(2)<<ans<<endl; 
    }
    return 0;
}

出栈序列统计 OpenJ_Bailian - 4077

问题描述

栈是常用的一种数据结构,有n个元素在栈顶端一侧等待进栈,栈顶端另一侧是出栈序列。

你已经知道栈的操作有两种:push和pop,前者是将一个元素进栈,后者是将栈顶元素弹出。

现在要使用这两种操作,由一个操作序列可以得到一系列的输出序列。

请你编程求出对于给定的n,计算并输出由操作数序列1,2,…,n,经过一系列操作可能得到的输出序列总数。

输入格式:就一个数n(1≤n≤15)。

输出格式:一个数,即可能输出序列的总数目。

输入样例:3

输出样例:5

提示

先了解栈的两种基本操作,进栈push就是将元素放入栈顶,栈顶指针上移一位,
等待进栈队列也上移一位,出栈pop是将栈顶元素弹出,同时栈顶指针下移一位。
用一个过程采模拟进出栈的过程,可以通过循环加递归来实现回溯:
重复这样的过程,如果可以进栈则进一个元素,如果可以出栈则出一个元素。
就这样一个一个地试探下去,当出栈元素个数达到n时就计数一次(这也是递归调用结束的条件)。

  • 参考程序
#include<iostream>
#include<queue>
using namespace std;
//未入栈元素个数,栈内元素个数
int dfs(int a,int b){
    if(a==0 && b==0) return 1;
    else if(a>0 && b>0) return dfs(a-1, b+1)+dfs(a, b-1);
    else if(a>0 && b==0) return dfs(a-1, b+1);
    else if(a==0) return dfs(a, b-1);
}
int main() {
//    freopen("data.in", "r", stdin);
    int n; cin>>n;
    cout<<dfs(n,0)<<endl; 
    return 0;
}

P4387 【深基15.习9】验证栈序列

题目描述

给出两个序列 pushed 和 poped 两个序列,其取值从 1 到 n(n≤100000)。

已知入栈序列是 pushed,如果出栈序列有可能是 poped,则输出 Yes,否则输出 No。

为了防止骗分,每个测试点有多组数据。

输入格式
第一行一个整数 q,询问次数。
接下来 q 个询问,对于每个询问:
第一行一个整数 n 表示序列长度;
第二行 n 个整数表示入栈序列;
第三行 n 个整数表示出栈序列;

输出格式
对于每个询问输出答案。

输入样例

2
5
1 2 3 4 5
5 4 3 2 1
4
1 2 3 4
2 4 1 3

输出样例

Yes
No
  • 参考程序
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int q,n;
int pushed[N],poped[N];
stack<int> sta;

//根据入栈序列,判断出栈序列是否合法 
bool islegal(){
    while(!sta.empty()) sta.pop();//栈的清空 
    int pre=0; 
    for(int i=0; i<n; i++){
        sta.push(pushed[i]);
        while(!sta.empty() && sta.top()==poped[pre]){
            sta.pop(); pre++;
        }
    }
    if(sta.empty()) return 1;  
    return 0;
}

int main(){
//    freopen("data.in", "r", stdin);
    scanf("%d", &q);
    while(q--){
        scanf("%d", &n);
        for(int i=0; i<n; i++) scanf("%d", &pushed[i]);
        for(int i=0; i<n; i++) scanf("%d", &poped[i]);
        printf("%s\n", islegal() ? "Yes" : "No");
    }
    return 0;
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值