1.栈

栈是一种后进先出的数据结构。向栈中插入新元素称为进栈、入栈、压栈,使新元素成为栈顶元素;从栈中删除一个元素称为出栈、退栈,于其相邻的元素成为栈顶元素。栈顶指针是指向栈顶元素的标记,通常记为TOP,在数组栈中TOP是一个int型变量,而在链表栈中是一个int*类型指针。数组栈中数组下标从0开始,TOP为栈顶元素的下标。

2.栈的基本操作

以数组栈为例
(1)获取栈内元素个数

int size(){
	return TOP+1;
}

(2)是否为空
TOP=-1表示栈内没有元素

bool empty(){
	if(TOP==-1)
		return true;
	return false;
}

(3)入栈

void push(int x){
	TOP++;
	s[TOP]=x;
}

(4)出栈

void pop(){
	POP--;
}

(5)获得栈顶元素

int top(){
	return s[TOP];
}

注意:出栈和获取栈顶元素两项操作前要先判断栈是否为空。
(6)清空

void clear(){
	TOP=-1;
}

3.stl中的栈

(1)头文件

#include <stack>
using namespace std;

(2)定义
typename可以是任意基本数据类型和容器

stack<typename> s;

(3)常用函数
1.push()
push(x)将元素x压栈
2.pop()
弹出栈顶元素
3.top()
获得栈顶元素
4.empty()
判断栈是否为空,空返回true,否则返回false
5.size()
返回栈内元素个数
一个简单实例:

#include <stdio.h>
#include <stack>
using namespace std;

int main(){
    stack<int> s;
    for(int i=1;i<=5;i++)
        s.push(i);
    printf("%d\n",s.top());    //5
    while(!s.empty()){
        s.pop();
    }
    printf("%d\n",s.size());    //0
    return 0;
}

4.经典问题之括号匹配

大致题意就是给出一个只含有(、)、{、}、[、]的字符串,判断是否满足如下规则:
1.左括号和对应右括号匹配
2.左括号按照正确的顺序匹配
示例1:

输入:([{}])
输出:Yes

示例2:

输入:()[}
输出:No

思路:
1.遍历整个字符串。
2.如果遇到左括号([{,将括号入栈。
3.如果遇到右括号)]},若此时栈为空,直接匹配失败。不为空的话将栈顶元素与右括号进行匹配,不匹配的话匹配失败,匹配的话则将栈顶元素出栈并继续循环。
4.字符串遍历结束如果中途没有出现匹配失败并且最终栈为空,则整个字符串匹配成功。

代码:

#include <stdio.h>
#include <iostream>
#include <string>
#include <stack>
using namespace std;

bool match(char a,char b){
    if(a=='(' && b==')')
        return true;
    else if(a=='[' && b==']')
        return true;
    else if(a=='{' && b=='}')
        return true;
    else
        return false;
}

int main(){
    string str;
    cin>>str;
    stack<char> s;
    int flag=0;
    for(string::iterator it=str.begin();it!=str.end();it++){
        if(*it=='(' || *it=='[' || *it=='{')
            s.push(*it);
        else{
            if(s.empty()){
                printf("No\n");
                flag=-1;
                break;
            }
            char t=s.top();
            if(match(t,*it)==false){
                printf("No\n");
                flag=-1;
                break;
            }
            s.pop();
            flag=1;
        }
    }
    if(flag=1 && s.empty())
        printf("Yes\n");
    return 0;
}

5.经典问题之后缀表达式(逆波兰表达式)

(1)中缀表达式转后缀表达式
中缀表达式就是平常最常见的算术表达式,运算符在运算数中间,需要考虑运算符的优先级
后缀表达式中运算符在运算数之后,无需考虑优先级,是计算机方便运算的一种算术表达式。

示例:

输入:(2*(9+6/3-5)+4)
输出:2 9 6 3 / + 5 - * 4 +

思路:
1.建立一个栈存放操作符
2.从左到右遍历字符串,遇到左括号进栈
3.遇到操作符时,如果优先级大于栈顶元素的优先级则入栈,否则不断弹出栈顶元素加入后缀表达式,直到满足该操作符优先级大于栈顶元素优先级 (优先级顺序:乘除>加减>括号)
4.遇到操作数直接加入后缀表达式中
5.遇到右括号,不断弹出栈顶元素加入后缀表达式直到遇到左括号
6.若字符串遍历完栈非空,则将栈顶元素依次弹出加入后缀表达式中

代码:
我这里直接使用了字符串存放后缀表达式(这种方法局限性较大)

#include <stdio.h>
#include <iostream>
#include <stack>
#include <ctype.h>
using namespace std;

bool compare(char a,char b){
    if((a=='*' || a=='/') && (b=='+' || b=='-' || b=='(' || b==')'))
        return true;
    else if((a=='+' || a=='-') && (b=='(' || b==')'))
        return true;
    else
        return false;
}

int main(){
    stack<char> op;
    string s;
    string ans;
    cin>>s;
    for(string::iterator it=s.begin();it!=s.end();it++){
        if(isdigit(*it)){
            ans+=*it;
            ans+=' ';
        }
        else if(*it=='('){
            op.push(*it);
        }
        else if(*it==')'){
            while(op.top()!='('){
                ans+=op.top();
                ans+=' ';
                op.pop();
            }
            op.pop();
        }
        else{
            if(op.empty()){
                op.push(*it);
                continue;
            }
            char t=op.top();
            if(compare(*it,t)==true){
                op.push(*it);
            }
            else{
                while(compare(*it,op.top())==false){
                    ans+=op.top();
                    ans+=' ';
                    op.pop();
                    if(op.empty())
                        break;
                }
                op.push(*it);
            }
        }
    }
    while(!op.empty()){
        ans+=op.top();
        ans+=' ';
        op.pop();
    }
    cout<<ans<<endl;
    return 0;
}

(2)后缀表达式求值
得到后缀表达式之后将值求出来

示例:

输入:2 9 6 3 / + 5 - * 4 +
输出:16.00

思路:
1.从左到右遍历后缀表达式,遇到操作数进栈
2.遇到操作符,从栈中弹出两个操作数(后弹出的是第一操作数),将两个操作数运算的结果压栈
3.整个后缀表达式遍历结束,栈中唯一一个元素就是所求的值

采用结构体、队列、映射等对代码进行改良后的整体代码:

#include <stdio.h>
#include <iostream>
#include <stack>
#include <queue>
#include <map>
#include <string>
#include <ctype.h>
using namespace std;

struct node{
    bool flag;    //flag=true表示操作数,=false表示操作符
    float num;
    char op;
};

string str;
stack<node> s;    
queue<node> q;
map<char,int> m;

//中缀转后缀
void expression(){
    for(string::iterator it=str.begin();it!=str.end();it++){
        node t;
        if(isdigit(*it)){
            t.flag=true;
            t.num=*it-'0';
            string::iterator it1=it+1;
            while(isdigit(*it1) && it1!=str.end()){
                t.num=t.num*10+*it1-'0';
                it1++;
            }
            q.push(t);
            it=it1-1;
        }
        else if(*it=='('){
            t.flag=false;
            t.op=*it;
            s.push(t);
        }
        else if(*it==')'){
            t.flag=false;
            t.op=*it;
            while(s.top().op!='('){
                q.push(s.top());
                s.pop();
            }
            s.pop();
        }
        else{
            t.flag=false;
            t.op=*it;
            if(s.empty()){
                s.push(t);
                continue;
            }
            if(m[*it]>m[s.top().op])
                s.push(t);
            else{
                while(m[*it]<=m[s.top().op]){
                    q.push(s.top());
                    s.pop();
                    if(s.empty())
                        break;
                }
                s.push(t);
            }
        }
    }
    while(!s.empty()){
        q.push(s.top());
        s.pop();
    }
}

//后缀表达式求值
float cal(){
    while(!q.empty()){
        node t=q.front();
        q.pop();
        if(t.flag==true){
            s.push(t);
        }
        else{
            node c;
            c.flag=true;
            float a=s.top().num;
            s.pop();
            float b=s.top().num;
            s.pop();
            if(t.op=='+')
                c.num=b+a;
            else if(t.op=='-')
                c.num=b-a;
            else if(t.op=='*')
                c.num=b*a;
            else if(t.op=='/')
                c.num=b/a;
            s.push(c);
        }
    }
    return s.top().num;
}

int main(){
    m['+']=1;
    m['-']=1;
    m['*']=2;
    m['/']=2;
    getline(cin,str);
    for(string::iterator it=str.begin();it!=str.end();it++){
        if(*it==' ')
            str.erase(it);
    }
    expression();
    /*  检查后缀表达式是否正确
    while(!q.empty()){
        if(q.front().flag==true)
            printf("%f",q.front().num);
        else
            printf("%c",q.front().op);
        q.pop();
    }*/
    printf("%.2f\n",cal());
    return 0;
}

几个注意点:
1.输入字符串可能有空格和左右括号,需分别处理
2.操作数可能是两位以上的,因此改用结构体
3.处理过程中几个条件判断要考虑栈空的情况,不然可能会卡死在循环中

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值