机试常用算法和题型-栈和队列专题

堆栈+ordermap使用括号匹配

#include <iostream>
#include <string>
#include <unordered_map>
#include <stack>
using namespace std;

void dispose(string str,unordered_map<char,int> list){
    stack<char> bracket;
    //规则是,左括号全都入栈,直到找到右括号就全部弹出到第一个左括号
    int flag=0;
    for(auto it=str.begin();it!=str.end();it++){
        if(list.count(*it)>0){
            //此处应当是只将括号入栈
                //在list当中有括号的情况下
            if(bracket.empty()==false){
                //这个意思是匹配上了!!一定要注意两个状态,栈顶和当前
                if(list[bracket.top()]+list[*it]==7)
                    bracket.pop();
                else {
                    if(list[*it]<=3)
                        //左括号全部推入
                        bracket.push(*it);
                    //如果it右部匹配又是右括号就要跳出循环
                    else
                        break;
                }
            }
            else{
                //如果当前是空的话,若是立马遇见错括号可以直接跳楼了
                bracket.push(*it);
                if(list[*it]>3)
                    break;
            }
        }
    }
    //这里是左括号多余的情况
    if(bracket.empty()==false)
        flag=0;
    else
        flag=1;
    if(flag==0)
        printf("no\n");
    else
        printf("yes\n");
}


//堆栈括号匹配,主要是不记得括号匹配的规则了,
int main()
{
    int n;
    unordered_map<char,int> list;
    //只想说这样匹配太好用了,优雅
    list['{']=1;
    list['[']=2;
    list['(']=3;
    list[')']=4;
    list[']']=5;
    list['}']=6;
    while(cin>>n){
        string temp;
        for(int i=0;i<n;i++){
            cin>>temp;
            dispose(temp,list);
        }
    }
    return 0;
}

堆栈使用简单计算器

#include <iostream>
#include <sstream>
#include <stack>
#include <string>
#include <unordered_map>
using namespace std;

int str_to_int(const string &string_temp){
    int temp;
    stringstream stream(string_temp);
    stream>>temp;
    return temp;
}

void compute(stack<double> &number,stack<string> &sign){
    double b=number.top();
    //终于知道了,取值只能靠top!!,pop相当于清除
    number.pop();
    double a=number.top();
    number.pop();
    string op=sign.top();
    sign.pop();
    if(op=="+"){
            //果然是按照算法一步步来的
        number.push(a+b);
    }else if(op=="-"){
        number.push(a-b);
    }
    else if(op=="*"){
        number.push(a*b);
    }else{
        number.push(a/b);
    }
}

double dispose(unordered_map<string,int> isp,unordered_map<string,int> osp,string str){
    stack<double> number;
    stack<string> sign;
    int flag=0;
    //这仿佛是在寻找数字和操作符
    while(str.empty()==false){
        string temp;
        int pos=str.find(" ");
        if(pos!=string::npos){
            temp=temp+str.substr(0,pos);
            str.erase(0,pos+1);
        }
        else{
            //找不到空格的时候,直接可以取最后剩余作为字符串
            temp=str;
            str.clear();
        }
        if(flag==0){
            number.push(str_to_int(temp));
            //fflag表示已经转换??,最后存成了double型??
            //flag为1应当表示的是操作符而不是数字
            flag=1;
        }else{
            if(sign.empty()==false){
                    //比较栈顶的和当前temp中的优先级
                if(isp[sign.top()]>=osp[temp]){
                    while(sign.empty()==false){
                            //比较堆栈优先级和当前操作符优先级
                        if(isp[sign.top()]<osp[temp])
                            break;
            //只有栈顶的优先级比较大的时候才可以计算,否则得要符号入栈
                        compute(number,sign);
                    }
                }
            }
            sign.push(temp);
            //操作符入栈,并且表示下一个字符为数字
            flag=0;
        }
    }
    while(sign.empty()==false){
        compute(number,sign);
    }
    return number.top();
}

//中缀表达式转后缀表达式,最后按照相应规则处理数字栈和符号栈
int main()
{

    string temp;
    while(getline(cin,temp)){
        if(temp!="0"){
            unordered_map<string,int> isp,osp;
            isp["+"]=1;
            isp["-"]=1;
            isp["*"]=2;
            isp["/"]=2;
            osp["+"]=1;
            osp["-"]=1;
            osp["*"]=2;
            osp["/"]=2;
            double result=dispose(isp,osp,temp);
            printf("%.2f\n",result);
            temp.clear();
        }else{
            break;
        }
    }
    return 0;
}

栈+队列实现中缀转后缀,计算后缀表达式

#include <iostream>
#include <32/bits/stdc++.h>
//如何模仿计算器
/*
步骤一:中缀表达式转后缀表达式
设立一个操作符栈,可以临时存放操作符,设立一个数组或者队列,用以存放后缀表达式
步骤二:计算后缀表达式
从左到右扫描后缀表达式,操作数则入栈,操作符则连续弹出两个操作数
*/
using namespace std;


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

};

string str;
//处理输入

stack<node> s; //操作符栈
queue<node> q; //后缀表达式序列
map<char,int> op;  //存储优先级!!

void Change(){
    double num;
    node temp;
    for(int i=0;i<str.size();){
        if(isdigit(str[i])){
            temp.flag=true;  //标记为数字
            temp.num=str[i++]-'0';  //由于可能是一个百位数字,先记录高位
            while(i<str.size()&&isdigit(str[i])){
                temp.num=temp.num*10+(str[i]-'0');
                i++;
            }
            q.push(temp);
        }else{
            temp.flag=false;
            //标记是操作符,只要栈顶元素比该操作符优先级高,就把栈顶元素弹到表达式中
            while(!s.empty()&&op[str[i]]<=op[s.top().op]){
                q.push(s.top());
                s.pop();
            }
            temp.op=str[i];
            //压入新的操作符
            s.push(temp);
            i++;

        }

    }

    while(!s.empty()){

        //若操作符中还有操作符,就得都弹入后缀表达式序列
        q.push(s.top());
        s.pop();
    }
}

double Cal(){
    //计算后缀表达式
    double temp1,temp2;
    node cur,temp;

    while(!q.empty()){
        cur=q.front();  //cur记录队首元素
        q.pop();
        if(cur.flag==true) s.push(cur);  //操作数直接压栈
        else{
            temp2=s.top().num; //先弹出来的是第二操作数
            s.pop();
            temp1=s.top().num; //弹出第一操作数
            s.pop();

            temp.flag=true;
            //临时记录草锁住
            if(cur.op=='+') temp.num=temp1+temp2;
            else if(cur.op=='-') temp.num=temp1-temp2;
            else if(cur.op=='*') temp.num=temp1*temp2;
            else if(cur.op=='/') temp.num=temp1/temp2;

            s.push(temp);
        }
    }

    return s.top().num;
    //栈顶元素为后缀表达式的值

}

int main()
{
    op['+']=op['-']=1;
    op['*']=op['/']=2;

    while(getline(cin,str),str!="0"){
        for(auto it=str.end();it!=str.begin();it--){
            if(*it==' ') str.erase(it); //去除掉表达式中空格
        }

        while(!s.empty()) s.pop(); //初始化栈
        Change();  //中缀转后缀
        printf("%.2f\n",Cal());
    }
    cout << "Hello world!" << endl;
    return 0;
}

栈+队列计算,包括括号版

48*((70-65)-43)+8*1
#include <iostream>
#include <stack>
#include <queue>
#include <string>
#include <cctype>
#include <map>
using namespace std;

struct node{
    int num;
    char op;
    bool flag;
    //true表示操作数
};
string str;

stack<node> s; //操作符栈
queue<node> q;//后缀表达式序列
map<char,int> op;  //map存储符号优先级

void Change(){
    int num;
    node temp;

    for(int i=0;i<str.size();){
            //括号处理出的问题
        if(str[i]=='('){
            temp.flag=false;
            temp.op=str[i];
            s.push(temp);
            i++;
        }else if(str[i]==')'){
            while(s.top().op!='('){
                q.push(s.top());
                s.pop();
            }
            s.pop();
            i++;
        }
        else if(isdigit(str[i])){
            temp.flag=true;
            temp.num=str[i++]-'0';
            //多位数怎么办
            while(i<str.size()&&isdigit(str[i])){
                temp.num=temp.num*10+(str[i]-'0');
                i++;
            }
            //真正的队列压入
            q.push(temp);
        }else{
            temp.flag=false;
            while(!s.empty()&&op[str[i]]<=op[s.top().op]){
                q.push(s.top());
                s.pop();
            }
            temp.op=str[i];
            //真正的操作符压入
            s.push(temp);
            i++;

        }

    }

    while(!s.empty()){
        q.push(s.top());
        s.pop();
    }
}

int Cal(){
    int temp1,temp2;
    node cur,temp;

    while(!q.empty()){
        cur=q.front();
        q.pop();
        if(cur.flag==true)
            //一个栈多用
            s.push(cur);
        else{
                //第二操作数
            temp2=s.top().num;
            s.pop();
            //弹出第一操作数
            temp1=s.top().num;
            s.pop();

            temp.flag=true;
            //temp1,temp2生成
            if(cur.op=='+')
                temp.num=temp1+temp2;
            else if(cur.op=='-')
                temp.num=temp1-temp2;
            else if(cur.op=='*')
                temp.num=temp1*temp2;
            else if(cur.op=='/')
                temp.num=temp1/temp2;

            s.push(temp);
        }
    }
    return s.top().num;
    //栈顶元素为最后值
}


int main()
{
    op['+']=op['-']=1;
    op['*']=op['/']=2;

    while(getline(cin,str)){
        while(!s.empty()) s.pop(); //初始化栈
        Change();  //中缀转后缀
        printf("%d\n",Cal());
    }

    return 0;
}

另一种直接写法,不会栈溢出

#include<cstdio>
#include<map>
#include<cstring>
#include<ctype.h>
#include<stack>
#include<queue>
using namespace std;
struct node{
    int data;
    char op;
    int flag;
}Node;
stack<char> s;
queue<node> q;
char str[1010];
map<char,int> m;

int main(){
    m['+']=1;
    m['-']=1;
    m['(']=0;
    m['*']=2;
    m['/']=2;
    scanf("%s",str);
    int len=strlen(str);
    for(int i=0;i<len;++i){
        if(str[i]>='0'&&str[i]<='9'){
            int sum=0;
            while(str[i]>='0'&&str[i]<='9'){
                sum=sum*10+str[i]-'0';
                i++;
            }
            Node.data=sum;
            Node.flag=1;
            q.push(Node);
            i--;
        }

        else if(!(str[i]>='0'&&str[i]<='9')){
            if(str[i]=='(')
                s.push(str[i]);
            else if(str[i]==')'){
                while(s.top()!='('){
                    Node.op=s.top();
                    Node.flag=0;
                    q.push(Node);
                    s.pop();
                }
                s.pop();
            }else if(s.empty()||m[str[i]]>m[s.top()]){
                s.push(str[i]);
            }else{
               while(!s.empty()&&m[str[i]]<=m[s.top()]){
                Node.op=s.top();
                Node.flag=0;
                q.push(Node);
                s.pop();
               }
               s.push(str[i]);
            }
        }
        //printf("2");
    }
    while(!s.empty()){
        Node.op=s.top();
        Node.flag=0;
        q.push(Node);
        s.pop();
    }
    stack<int> s1;
    int sum=0;
    while(!q.empty()){
        node no=q.front();
        if(no.flag==1){
            s1.push(no.data);
        }else{
            int a=s1.top();
            s1.pop();
            int b=s1.top();
            s1.pop();
            if(no.op=='+'){
                sum=a+b;
            }else if(no.op=='-'){
                sum=b-a;
            }else if(no.op=='*'){
                sum=a*b;
            }else{
                sum=b/a;
            }
            s1.push(sum);
        }
        q.pop();
    }
    printf("%d",s1.top());
    return 0;
}

队列使用

#include <iostream>
#include <queue>
#include <iterator>
using namespace std;

int main(){
  queue<int> q;
  for(int i=1;i<=5;i++){
    q.push(i);
    //入队
  }
  if(q.empty()){
    cout<<q.front()<<" ";
  }
  //输出队首1和队尾5
  cout<<q.back()<<endl;
  if(q.empty()){
    q.pop();
  }
  return 0;
}

任务调度:优先队列+string处理和unordermap

//优先队列进行任务调度
/*
输入 
输入包含多组测试数据。

每组第一行输入一个整数n(n<100000),表示有n个任务。

接下来n行,每行第一个表示前序任务,括号中的任务为若干个后序任务,表示只有在前序任务完成的情况下,后序任务才能开始。若后序为NULL则表示无后继任务。

输出 
输出调度方式,输出如果有多种适合的调度方式,请输出字典序最小的一种。

*/
#include <iostream>
#include <string>
#include <unordered_map>
#include <queue>
using namespace std;

struct Task{
    string name;
    int level;
    //定义优先规则
    friend bool operator < (const Task &t1,const Task &t2){
        if(t1.level!=t2.level)
            return t1.level>t2.level;
        else return t1.name>t2.name;
    }
};

//使用引用表示要修改
void dispose(string str,priority_queue<Task> &task,unordered_map<string,int> &list){
    string first;
    int pos;
    int firstlevel;
    //从输入当中分理出任务
    pos=str.find('(');
    first=str.substr(0,pos);
    str.erase(0,pos+1);
  //list.count只能是1或0,,1表示存在,0表示没有,类似find
  //而find返回的则是元素的迭代器
    if(list.count(first)==0){
        Task newtask;
        newtask.name=first;
        newtask.level=0;
        task.push(newtask);
        firstlevel=list[first]=0;
    }
    else{
        firstlevel=list[first];
    }
    //str也可以使用empty函数
    while(str.empty()==false){
        string last;
        pos=str.find(',');
        if(str.find(',')==string::npos){
            pos=str.find(')');
            last=str.substr(0,pos);
            str.clear();
        }else{
        last=str.substr(0,pos);
        str.erase(0,pos+1);
        }
        if(last!="NULL"){
            Task newtask;
            newtask.name=last;
            newtask.level=firstlevel+1;
            list[last]=newtask.level;
            task.push(newtask);
        }
    }

}

int main()
{
    int n;
    while(cin>>n){
        priority_queue<Task> task;
      //hash对应,且不排序
        unordered_map<string,int> list;
        string temp;
        for(int i=0;i<n;i++){
            cin>>temp;
            dispose(temp,task,list);

        }
        while(task.empty()==false){
            cout<<task.top().name;
            task.pop();
            if(!task.empty()){
                cout<<" ";
            }
        }
        list.clear();
    }
    return 0;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容