PTA栈和队列编程作业

本文介绍了两个关于栈的问题:一是判断给定的数字序列是否可能由最大容量为M的栈按照1到N的顺序随机出栈得到;二是将中缀表达式转换为后缀表达式。对于前者,通过模拟栈的push和pop操作验证序列的合法性;对于后者,通过优先级判断和栈操作实现中缀到后缀的转换。
摘要由CSDN通过智能技术生成

4-3 Pop Sequence

Given a stack which can keep M numbers at most. Push N numbers in the order of 1, 2, 3, ..., N and pop randomly. You are supposed to tell if a given sequence of numbers is a possible pop sequence of the stack. For example, if M is 5 and N is 7, we can obtain 1, 2, 3, 4, 5, 6, 7 from the stack, but not 3, 2, 1, 7, 5, 6, 4.

Input Specification:

Each input file contains one test case. For each case, the first line contains 3 numbers (all no more than 1000): M (the maximum capacity of the stack), N (the length of push sequence), and K (the number of pop sequences to be checked). Then K lines follow, each contains a pop sequence of N numbers. All the numbers in a line are separated by a space.

Output Specification:

For each pop sequence, print in one line "YES" if it is indeed a possible pop sequence of the stack, or "NO" if not.

Sample Input:

5 7 5
1 2 3 4 5 6 7
3 2 1 7 5 6 4
7 6 5 4 3 2 1
5 6 4 3 7 2 1
1 7 6 5 4 3 2

Sample Output:

YES
NO
NO
YES
NO

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

翻译:

给出若干组数组,检测每组数组能否通过指定大小的栈pop得到,入栈顺序:1到N。
输入第一行:M(栈的最大容量)N(要检测的数字有多少个)K(有多少组要检测的数字);

后K行每行N个数字,代表要检测的数组;

输出:如果可以通过栈的pop得到,则输出YES,否则输出NO。
如: 5 6 4 3 7 2 1:

push:1,2,3,4,5;

pop:5,

push:6,

pop:6,

pop:4,

pop:3,

push:7,

pop:7,

pop:2,

pop:1,即可得到。

Code:

#include<bits/stdc++.h>
const int  MAXN = 1e3 + 10;
using namespace std;
stack<int> s;
int a[MAXN];
int main(){
    int M,N,K;
    scanf("%d %d %d",&M,&N,&K);
 
    int index = 0,flag = 1;
    int tmp = 1;
    for(int i = 0;i < K;i ++ ){
    //恢复现场。
        flag = 1;
        index = 0;
        tmp = 1;
    
        s.push(1);
    
    //读入序列
    for(int j = 0;j < N;j ++ ){
        scanf("%d",&a[j]);
    }
    
    //判定序列
    while(index < N){
    //一直存入顺序数,直到栈顶元素不小于当前需输出的元素
       while(s.top() < a[index]){
            //如果存满了还是小于,则序列非法
           if(s.size() < M && s.top() < N){
               s.push(tmp + 1);
               tmp ++ ;
           }
		   else{
               flag = 0;
               break;
           }
       }
    //若大于则序列非法,若等于则删除栈顶元素,index++,进行本轮下一元素输出判定
       if(s.top() == a[index]){
           s.pop();
           index ++ ;
       }
	   else{
           flag = 0;
       }
 
    //序列非法直接退出本轮判定
       if(!flag) break;
 
    //若栈空,必须压入下一元素,也有可能是本轮最后一个元素的判定       
       if(s.size() == 0){
              if(tmp < N) s.push(tmp + 1);
              else break;
        } 
    }
 
    if(flag == 1) printf("YES\n");
    else printf("NO\n");
 
    //清除本轮模拟栈元素
    while(!s.empty()){
        s.pop();
    }
}
    return 0;  
}


 

4-4 表达式转换

算术表达式有前缀表示法、中缀表示法和后缀表示法等形式。日常使用的算术表达式是采用中缀表示法,即二元运算符位于两个运算数中间。请设计程序将中缀表达式转换为后缀表达式。

输入格式:

输入在一行中给出不含空格的中缀表达式,可包含+-*\以及左右括号(),表达式不超过20个字符。

输出格式:

在一行中输出转换后的后缀表达式,要求不同对象(运算数、运算符号)之间以空格分隔,但结尾不得有多余空格。

输入样例:

2+3*(7-4)+8/4

输出样例:

2 3 7 4 - * + 8 4 / +

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

思路:

一、提取操作对象(操作数或操作符):
起始点:

      指向中缀串指针所指字符是数字,则是无符号数,

      指向中缀串指针所指字符是正负号且所指字符是第一个或者所指字符的前一个字符是 ‘(’,则是有符号数。

      否则所指为操作符。

结束点:

      当是操作数时,直到下一个既不是数字也不是小数点的符号为止。

      当是操作符时,直接加1(这里操作符都是1位)。

二、定义算符优先级

加减号是2,乘除号是3。为了在接下来遇到‘(’时省去判断栈顶是否是‘(’,将‘)’优先级定为1。优先级初始化为0。

三、中缀转后缀(后缀又称为逆波兰式)
中缀指针所指是操作数,则直接将之复制到后缀串尾,加空格。

中缀指针所指是左括号 ‘(’ ,则直接将之入栈。

中缀指针所指是右括号 ‘)’ ,则一直弹栈(并且复制到后缀串尾,加空格)到左括号 ‘(’ 为止,再将左括号弹栈。

中缀指针所指是一般的操作符‘+’、‘-’、‘*’、‘/’,则

     若栈为空,则直接入栈;

     否则,若其优先级比栈顶元素高,则将之入栈;

         否则,则一直弹栈(并且复制到后缀串尾,加空格)直到栈空或者其优先级比栈顶元素高为止(注意若此时遇到左括号,因为左括号我们设置的优先级很低,所以其优先级必比左括号高,可以停止)。然后将该操作符入栈。

遍历中缀表达式后,将栈中所剩操作符全部弹栈(并且复制到后缀串尾,加空格)。

最后根据题目要求,将最后一个空格赋值为结束符 ‘\0’。

思考:如何将中缀表达式转换为后缀表达式比较准而且快?


比如:2+3*(7-4)+8/4

第一步,把每两个数之间的运算都加上括号(涉及视觉上并行地进行局部运算次序的判定)。((2+(3*(7-4)))+(8/4))

第二步,把中间的运算符放在所在的那一层括号右边(符号移动)。((2(3 (7 4)-)*)+(84)/)+

第三步,把括号全部去掉即为后缀表达式(符号消除或代替)。2 3 7 4 - * + 8 4 / +

转换为前缀表达式同理。

Code:

#include<bits/stdc++.h>
using namespace std;

///是否是数字
int IsNumber(char a){
    return a>='0'&&a<='9';
}

///从字符串start处开始提取操作数或操作符,并返回下一次提取的开端和提取的结果
int get(char a[],int start,int &nextstart,char c[]){
    int i,j;
    if(IsNumber(a[start])){///是数字
        for(i = 0;IsNumber(a[start + i]) || a[start + i] == '.';i ++ ){///复制给c
            c[i] = a[start + i];
        }
		c[i] = 0;
        nextstart = start + i;///下一次提取的开端
        return 1;
    }
	else if((a[start] == '+' || a[start] == '-') && (start == 0 || a[start - 1] == '(')){///是一个有符号数
        if(a[start] == '-'){
            c[0] = a[start];
			j=1;
        }
		else{///去掉正号
            j = 0;
        }
        for(i = 1;IsNumber(a[start + i]) || a[start + i] == '.';i ++ ){///复制给c
            c[j ++ ] = a[start + i];
        }
		c[j] = 0;
        nextstart = start + i;///下一次提取的开端
        return 1;
    }
	else{//不是数
        c[0] = a[start];///复制操作符
        c[1] = 0;
        nextstart = start+1;///下一次提取的开端
    }
    return 0;
}

///定义优先级。括号最低。
int Prior(char ch){
    int prior = 0;
    switch(ch){
        case '(':
            prior = 1;
			break;
        case '+':
        case '-':
            prior = 2;
		    break;
        case '*':
        case '/':
            prior = 3;
			break;
    }
    return prior;
}

///表达式转换
void translate(char a[],char b[]){
    stack<char> s;
    int i,j,nexti;char c[100];
    for(i = 0,j = 0;a[i];i = nexti){
        int isnumber = get(a,i,nexti,c);///提取操作对象
        if(isnumber){//是数字
            int k = 0;///复制到b中
            for(k = 0;c[k];k ++ ){
                b[j ++ ] = c[k];
            }
            b[j ++ ]=' ';///用空格分隔
        }
		else if(a[i]=='('){///左括号直接入栈
            s.push(a[i]);
        }
		else if(a[i] == ')'){///右括号则弹出栈中全部操作符并复制到b后,直到左括号为止
            while(s.top()!='('){
                b[j++] = s.top();
				s.pop();
                b[j++] = ' ';///用空格分隔
            }
            s.pop();///弹出左括号
        }
		else{///是个一般的四则运算符
            if(s.empty()){///空栈直接入栈
                s.push(a[i]);
            }
			else if(Prior(a[i]) > Prior(s.top())){///优先级高于栈顶则入栈
                s.push(a[i]);
            }
			else{///否则弹出栈中元素直到优先级比栈顶高或空栈为止
                while(!s.empty() && Prior(a[i]) <= Prior(s.top())){
                    b[j ++ ] = s.top();
                    s.pop();
                    b[j ++ ] = ' ';
                }
                s.push(a[i]);///将该操作符入栈
            }
        }
    }
    
    while(!s.empty()){///弹出栈中全部元素
        b[j ++ ] = s.top();
        s.pop();
        b[j ++ ]=' ';
    }
    b[j - 1 ] = 0;///最后一个空格赋值为0
    
}
int main(){
    char a[100] = "",b[100] = "";
    scanf("%s",a);
    translate(a,b);
    printf(b);
    return 0;
}


 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

那就随便一点

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值