链栈+队列

一、链栈

1.定义

栈是后进先出的线性序列,也是一种线性表,操作受限的线性表,只能在一端进行进出操作,进出的一端被称为栈顶,另一端被称为栈底。栈可以采用顺序存储,也可以采用链式存储,分别被称为顺序栈和链栈。

链栈数据结构定义

typedef struct Snode{
    ElemType data;//数据域
    struct Snode *next;//指向下一个结点的指针
}Snode,*LinkSnode;

2.初始化

初始化一个空栈,链栈是不需要头结点的,只需要让栈顶指针为空即可(栈顶指针S就是最上方那个元素)。

bool InitStack(LinkSnode &S){
    S=NULL;
    return true;
}

3.入栈

将新元素结点压入栈顶,将新元素结点插入到第一个节点的前面,然后修改栈顶指针。

bool Push(LinkSnode &S,int e){
    LinkSnode p;
    p=new Snode;
    p->data=e;
    p->next=S;
    S=p;
    return true;
}

4.出栈

将栈顶元素删除,栈顶指针指向下一个结点,然后释放空间。

bool Pop(LinkSnode &S,int &e){
    if(S==NULL)
        return false;
    LinkSnode p;
    p=S;//用p存S,然后delete p,不能delete S
    e=S->data;
    S=S->next;
    delete p;
    return true;
}

5.取栈顶元素

int GetTop(LinkSnode S){
    if(S==NULL)
        return -1;
    return S->data;
}

二、队列

1.定义

队列是先进先出的线性序列,也是一种线性表,操作受限的线性表,只能在两端操作:从一端进,从另一端出。进的一端被称为队尾(rear),出的一端被称为队头(front)。队列可以顺序存储,也可以链式存储。

顺序存储静态定义

typedef struct sqQueue{
    ElemType data[Maxsize];
    int front,rear;
}sqQueue

顺序存储动态定义

typedef struct sqQueue{
    ElemType *base;//使用基地址
    int front,rear;
}sqQueue
Q.base=new int[Maxsize];

2.假溢出

明明有空间,却出现了队满的情况,这种情况称为“假溢出”。

使用循环队列可以解决这个假溢出的问题。 

3.队空

循环队列队空的判定条件:Q.front==Q.rear(Q.front和Q.rear指向同一个位置)

4.队满

循环队列队满的判定条件:(Q.rear+1)%Maxsize==Q.front(尾指针的下一个状态是头指针,浪费了一个空间)

5.入队

入队时,首先将元素x放入Q.rear所指空间,然后Q.rear后移一位

Q.base[Q.rear]=x;
Q.rear=(Q.rear+1)%Maxsize;

6.出队

先用变量保存队头元素,然后队头Q.front后移一位。

e=Q.base[Q.front]; 
Q.front=(Q.front+1)%Maxsize;

7.队列长度

循环队列中的内容实际上为Q.front到Q.rear-1这一区间的数据元素。

Q.rear>=Q.front:元素个数为Q.rear-Q.front;

Q.rear<Q.front:元素个数为Q.rear-Q.front+MaxSize;

8.全部代码 

typedef struct sqQueue{
    int *base;
    int front,rear;//指针域
}sqQueue;

bool InitQueue(sqQueue &Q){
    Q.base=new int[Maxsize];
    if(!Q.base)
        return false;
    Q.rear=Q.front=0;
    return true;
}

bool EnQueue(sqQueue &Q,int e){
    if((Q.rear+1)%Maxsize==Q.front)
        return false;
    Q.base[Q.rear]=e;
    Q.rear=(Q.rear+1)%Maxsize;
    return true;
}

bool DnQueue(sqQueue &Q,int &e){
    if(Q.rear==Q.front)
        return false;
    e=Q.base[Q.front];
    Q.front=(Q.front+1)%Maxsize;
    return true;
}

int GetHead(sqQueue Q){
    if(Q.rear!=Q.front)
        return Q.base[Q.front];
    return -1;
}

int QueueLength(sqQueue Q){
    return (Q.rear-Q.front+Maxsize)%Maxsize;
}

三、题目

1.表达式括号匹配

 这道题很显然用栈就可以解决了。

#include<iostream>
#include<cstdio>
#include <cstring>
#define ll long long
using namespace std;

typedef struct Snode{
    char data;
    struct Snode *next;
}Snode,*LinkSnode;

void Push(LinkSnode &S,char e){
    LinkSnode p;
    p=new Snode;
    p->data=e;
    p->next=S;
    S=p;
}

bool Pop(LinkSnode &S){
    if(S==NULL)
        return false;
    LinkSnode p;
    p=S;//用p存S,然后delete p,不能delete S
    S=S->next;
    delete p;
    return true;
}

int main()
{
    LinkSnode S;
    char ch;
    int flag=0;//flag为0式子正确,flag为1式子错误
    S=NULL;
    while(ch != '@'){
        scanf("%c",&ch);
        if(ch=='('){
            Push(S,ch);
        }
        if(ch==')'){
            if(!Pop(S)){//如果栈为空,没有(,式子错误
                flag=1;
            }
        }
    }
    if(flag==0&&S==NULL){//以上判断会漏掉(的情况
       printf("YES");
    }
    else{
       printf("NO");
    }
}

在网上看到了一个更简单的代码

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int top;
int main()
{
	char ch;
	while(ch!='@')
	{
		scanf("%c",&ch);
		if(ch=='(')
			top++;
		if(ch==')')
			if(top>0)
				top--;
			else
			{
				cout<<"NO";
				return 0; 
			}
	}
	if(top==0)
		printf("YES");
	else
		printf("NO");
}

2.Rails

某城市有一个火车站,有n节车厢从A方向驶入车站,按进站的顺序编号为1到n.你的任务是判断是否能让它们按照某种特定的顺序进入B方向的铁轨并驶入车站。例如,出栈顺序(5 4 1 2 3)是不可能的,但是(5 4 3 2 1)是可能的。

 显然,这个火车站是一个中间栈,从A方向进栈,从B方向出栈。题目不难,但是这个输入输出让我看了半天才看明白。

#include<bits/stdc++.h>
using namespace std;
int target[1000];
int n;
typedef struct Snode{
    int data;//数据域
    struct Snode *next;//指向下一个结点的指针
}Snode,*LinkSnode;
void Push(LinkSnode &S,int e){
    LinkSnode p;
    p=new Snode;
    p->data=e;
    p->next=S;
    S=p;
}
bool Pop(LinkSnode &S){
    if(S==NULL)
        return false;
    LinkSnode p;
    p=S;//用p存S,然后delete p,不能delete S
    S=S->next;
    delete p;
    return true;
}
int main()
{
    LinkSnode S;
    S=NULL;
	while (scanf("%d",&n)==1 && n) {
		while (1) {
			if (scanf("%d",&target[0])==1&&!target[0]) break;
			for (int i = 1; i < n; i++) {
				scanf("%d",&target[i]);
			}
			int a=0,b=0;
			while(b<n){
			    if(target[b]==(a+1)){//如果从A过来的车厢是B所期望的,直接b++
                    b++;
                    a++;
			    }
			    else{//否则看栈顶元素
                    if(S!=NULL&&S->data==target[b]){//如果栈顶元素是B所期望的,出栈
                        b++;
                        Pop(S);
                    }
                    else{//否则
                        if(a<n){
                            Push(S,a+1);//将A过来的车厢压入栈,看下一个来的车厢
                            a++;
                        }
                        else{//A过来的车厢都在中间栈了,但栈顶元素不是B所期望的,说明不可能了
                            break;
                        }
                    }
			    }
			}
			if (S==NULL) {
				cout << "Yes" << endl;
			}
			else {
				cout << "No" << endl;
				while(Pop(S));
			}
		}
		cout << endl;
	}
	return 0;
}

3.Matrix Chain Multiplication

 

这题不需要考虑括号是否匹配的, 即不会有 (AB)) 的情况, 碰到字母就进栈, 碰到 ) 就出栈两个数, 进行运算后入栈。栈里的数据要保存行和列,可以用map。

这题有个问题,表达式的输入有可能是空行, 对此必须不作处理。没注意这点很可能输出0,就会一直wa。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int rows[26],cols[26];
int n;
typedef struct Snode{
    map<string,int> data;//数据域
    struct Snode *next;//指向下一个结点的指针
}Snode,*LinkSnode;
void Push(LinkSnode &S,map<string,int> e){
    LinkSnode p;
    p=new Snode;
    p->data=e;
    p->next=S;
    S=p;
}
bool Pop(LinkSnode &S,map<string,int> &e){
    if(S==NULL)
        return false;
    LinkSnode p;
    p=S;//用p存S,然后delete p,不能delete S
    e=S->data;
    S=S->next;
    delete p;
    return true;
}
int main()
{
    LinkSnode S;
    char ch;
    string str;
    map<string,int> x,y;
    int flag=1;
    ll sum=0;
    S=NULL;
	cin>>n;
	for(int i=0;i<n;i++){
        cin.ignore();
        scanf("%c",&ch);
        scanf("%d",&rows[int(ch)-65]);
        scanf("%d",&cols[int(ch)-65]);
	}
	while(getline(cin, str)){
        if(str=="")continue;
        else{
            for(int i=0;i<str.size();i++){
                if(str[i]==')'){
                    Pop(S,y);Pop(S,x);
                    if(x["col"]!=y["row"]){
                        flag=0;
                        break;
                    }
                    else{
                        sum+=x["row"]*x["col"]*y["col"];//计算相乘次数
                        x["col"]=y["col"];
                        Push(S,x);//将xy相乘后的新的矩阵存进去
                    }
                }
                else if(str[i]=='(') continue;
                else{
                    x["row"]=rows[int(str[i])-65];x["col"]=cols[int(str[i])-65];
                    Push(S,x);
                }
            }
            if(flag==0){
                printf("error\n");
                flag=1;
            }
            else printf("%d\n",sum);//不管是一个矩阵还是一个以上的矩阵,最后栈里只有一个矩阵
            S=NULL;//清空栈
            sum=0;
        }
	}
	return 0;
}

4.Printer Queue

 

这道题根据题目就知道用队列来解决,解决思路很简单,通过代码对应解释就能明白。 

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int Maxsize=105;
int n,m;
typedef struct sqQueue{
    int *base;
    int front,rear;//指针域
}sqQueue;

bool InitQueue(sqQueue &Q){
    Q.base=new int[Maxsize];
    if(!Q.base)
        return false;
    Q.rear=Q.front=0;
    return true;
}

bool EnQueue(sqQueue &Q,int e){
    if((Q.rear+1)%Maxsize==Q.front)
        return false;
    Q.base[Q.rear]=e;
    Q.rear=(Q.rear+1)%Maxsize;
    return true;
}

bool DnQueue(sqQueue &Q,int &e){
    if(Q.rear==Q.front)
        return false;
    e=Q.base[Q.front];
    Q.front=(Q.front+1)%Maxsize;
    return true;
}
int findMax(sqQueue Q){//获得队列中的最大值
    int i=Q.front;
    int maxn=0;
    while(i!=Q.rear){
        if(maxn<Q.base[i])maxn=Q.base[i];
        i=(i+1)%Maxsize;
    }
    return maxn;
}

int main()
{
    int T,e,maxQ;
    sqQueue Q;
    scanf("%d",&T);
    for(int i=0;i<T;i++){
        int sum=0;
        InitQueue(Q);
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++){
            scanf("%d",&e);
            EnQueue(Q,e);
        }
        maxQ=findMax(Q);
        while(1){
            if(Q.base[Q.front]==maxQ){//如果队头是队列中优先级最高的
                sum+=1;//完成了一个打印任务
                if(Q.front==m){printf("%d\n",sum);break;}//如果队头是要完成的任务,则结束循环
                DnQueue(Q,e);//出队
                maxQ=findMax(Q);//获取新的最大值
            }
            else{
                if(Q.front==m){//如果要放队尾的是要完成的任务
                    DnQueue(Q,e);
                    EnQueue(Q,e);//放到队尾去
                    m=(Q.rear-1+Maxsize)%Maxsize;//更新任务编号
                }else{DnQueue(Q,e);EnQueue(Q,e);}//直接出队放入队尾
            }
        }
    }
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值