3月16日OJ刷题

本文介绍了如何使用双栈数据结构实现初始化、判断栈空、栈满、进栈和出栈操作。给出了多组输入数据,涉及双栈的序列处理,包括进栈、出栈序列的生成和判断栈是否为空或满的算法。此外,还讨论了栈在回文序列判断、基于栈的可操作序列合法性验证以及后缀表达式求值等方面的应用。
摘要由CSDN通过智能技术生成

双栈的基本操作

描述

将编号为0和1的两个栈存放于一个数组空间V[m]中,栈底分别处于数组的两端。当第0号栈的栈顶指针top[0]等于-1时该栈为空;当第1号栈的栈顶指针top[1]等于m时,该栈为空。两个栈均从两端向中间增长(见下图)。试编写双栈初始化,判断栈空、栈满、进栈和出栈算法的函数。函数调用次序依次为:进栈、栈满的判断、出栈、栈空的判断。

双栈数据结构的定义如下:

typedef struct

{

int top[2], bot[2];                         //栈顶和栈底指针

SElemType *V;                                     //栈数组

int m;                                                    //栈最大可容纳元素个数

}DblStack;

双栈结构的表示

输入

多组数据,每组数据有四行,每行的数据之间均用空格分隔。第一行为一个整数m,表示数组V的大小,第二行为四个整数e0、e1、d0、d1,e0和e1分别代表压入0号栈和1号栈的整数序列E0和E1的长度(依次连续入栈,中间没有出栈的情况),d0和d1分别代表从0号栈和1号栈弹出的序列的长度(依次连续出栈,中间没有入栈的情况)。第三行和第四行分别表示序列E0和E1。当m=0时,输入结束。

输出

对于每组数据输出三行。第一行代表进栈操作完成时栈是否为满(出栈操作尚未执行),栈满输出1,栈不满输出0。第二行和第三行的数据分别对应0号栈和1号栈。第二行包括d0+1个整数,其中前d0个整数代表出栈序列D0,最后一个整数代表出栈操作完成时0号栈是否为空,栈空输出0,不空输出1。第三行包括d1+1个整数,其中前d1个整数代表出栈序列D1,最后一个整数代表出栈操作完成时1号栈是否为空,栈空输出0,不空输出1。整数之间用空格分隔。

输入样例 1 

7
3 4 2 2
1 2 3
2 3 4 5
12
4 6 4 3
1 3 4 5
1 3 5 6 8 1
0

输出样例 1

1
3 2 1
5 4 1
0
5 4 3 1 0
1 8 6 1
#include<bits/stdc++.h>
using namespace std;
typedef struct
{
	int top[2],bot[2];
	int *V;
	int m;
}DStack;

int InitStack(DStack &s,int m)
{
    s.V=new int[m];
    s.top[0]=s.bot[0]=-1;
    s.top[1]=s.bot[1]=m;
}

int isEmpty(DStack s,int i)
{
    if(s.top[i]==s.bot[i])
        return 0;
    else
        return 1;
}

int isFull(DStack s)
{
    if(s.top[0]+1==s.top[1])
        return 1;
    else
        return 0;
}

int Push(DStack &s,int i,int x)
{
    if(s.top[0]+1==s.top[1])
        return 0;
    if(i==0)
    {
        s.top[0]++;
        s.V[s.top[0]]=x;
    }
    else
    {
        s.top[1]--;
        s.V[s.top[1]]=x;
    }
    return 1;
}

int Pop(DStack &s,int i,int &x)
{
    if(s.top[i]==s.bot[i])
        return 0;
    if(i==0)
    {
        x=s.V[s.top[0]];
        s.top[0]--;
    }
    else
    {
        x=s.V[s.top[1]];
        s.top[1]++;
    }
    return 1;
}

int main()
{
    int n;
    while(cin>>n&&n!=0)
    {
        DStack s;
        InitStack(s,n);
        int a,b,c,d;
        cin>>a>>b>>c>>d;
        int x;
        for(int i=0;i<a;i++)
        {
            cin>>x;
            Push(s,0,x);
        }
        for(int i=0;i<b;i++)
		{
			cin>>x;
			Push(s,1,x);
		}
		cout<<isFull(s)<<endl;
		for(int i=0;i<c;i++)
		{
			Pop(s,0,x);
			cout<<x<<" ";
		}
		cout<<isEmpty(s,0)<<endl;
		for(int i=0;i<d;i++)
		{
			Pop(s,1,x);
			cout<<x<<" ";
		}
		cout<<isEmpty(s,1)<<endl;
    }
}

 

基于栈的回文字符序列判断

描述

回文序列是正反读均相同的字符序列,如“abba”和“abdba”均是回文,但是“good”不是回文。请设计一个算法判定给定的字符序列是否为回文。

输入

多组数据,每组数据有一行。每一行为一个长度不定的字符序列A。当A为“0”时,输入结束。

输出

对于每组数据输出一行。若字符序列A是回文序列,则输出“YES”,否则输出“NO”。

输入样例 1 

abba
abdba
good
0

输出样例 1

YES
YES
NO
#include<bits/stdc++.h>
using namespace std;
int main()
{
    string s;
    while(cin>>s&&s!="0")
    {
        int top=-1;
        char a[1000];
        for(int i=0;i<s.length();i++)
        {
            top++;
            a[top]=s[i];
        }
        int flag=1;
        for(int i=0;i<s.length();i++)
        {
            if(a[top]==s[i])
            {
                top--;
            }
            else
            {
                flag=0;
                break;
            }
        }
        if(flag)
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
}

入栈和出栈的基本操作

描述

输入一个整数序列a1,a2,a3...,an。当ai不等于-1时将ai进栈;当ai=-1时,输出栈顶元素并将其出栈。

输入

多组数据,每组数据有两行,第一行为序列的长度n,第二行为n个整数,整数之间用空格分隔。当n=0时输入结束。

输出

对于每一组数据输出若干行。每行为相应的出栈元素。当出栈异常时,输出“POP ERROR”并结束本组数据的输出。

输入样例 1 

5
1 2 -1 -1 1
5
1 -1 -1 2 2
0

输出样例 1

2
1
1
POP ERROR

 

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n;
    int a[10000];
    int b[10000];
    while(cin>>n&&n!=0)
    {
        for(int i=0;i<n;i++)
        {
            cin>>a[i];
        }
        int top=-1;
        for(int i=0;i<n;i++)
        {
            if(a[i]!=-1)
            {
                top++;
                b[top]=a[i];
            }
            else
            {
                if(top!=-1)
                {
                    cout<<b[top]<<endl;
                    top--;
                }
                else
                {
                    cout<<"POP ERROR"<<endl;
                    break;
                }
            }
        }
    }
}

基于栈的可操作判断

描述

假设I和O分别代表入栈和出栈操作。栈的始态和终态均为空。入栈和出栈的操作序列可以表示为仅由I和O组成的序列,称可操作的序列为合法序列,否则称为非法序列。请设计一个算法,判断所给的操作序列是否合法。若合法输出“true”,反之输出“false”。

输入

多组数据,每组数据为一行长度不定的操作序列A。当A为“0”时,输入结束。

输出

对应每组数据输出一行。若序列A为合法序列输出“TRUE”,反之输出“FALSE”。

输入样例 1 

IOIOIO
IIOOOO
0

输出样例 1

TRUE
FALSE

 

#include<bits/stdc++.h>
using namespace std;
int main()
{
    char s[1000];
    while(cin>>s&&s[0]!='0')
    {
        int i=0;
        int j=0,k=0;
        int flag=1;
        while(s[i]!='\0')
        {
            if(s[i]=='I')
            {
                j++;
            }
            else if(s[i]=='O')
            {
                k++;
                if(k>j)
                {
                    flag=0;
                }
            }
            i++;
        }
        if(j!=k||flag==0)
        {
            cout<<"FALSE"<<endl;
        }
        else
        {
            cout<<"TRUE"<<endl;
        }
    }
}

基于栈的后缀算术表达式求值

描述

从键盘上输入一个后缀表达式,试编写算法计算表达式的值。规定:后缀表达式的长度不超过一行,以“=”作为输入结束,操作数之间用空格分隔,操作符只可能有+、−、*、/四种运算。

输入

多组数据,每组数据一行,对应一个后缀算术表达式,每个表达式均以“=”结尾。当表达式只有一个“=”时,输入结束。

输出

对于每组数据输出一行,为表达式的运算结果。

输入样例 1 

1 2+8 2-7 4-/*=
1 2+=
1 2/=
=

输出样例 1

6.00
3.00
0.50

 

#include<bits/stdc++.h>
using namespace std;
double Operate(double a,double b,char op)
{
	if(op=='+')
		return a+b;
	else if(op=='-')
		return a-b;
	else if(op=='*')
		return a*b;
	else if(op=='/')
		return b/a;
}
int main()
{
    char s[1000];
    while(cin>>s&&s[0]!='=')
    {
        double n[1000];
        int top=-1;
        for(int i=0;s[i]!='=';i++)
        {
            if(s[i]>=48&&s[i]<=57)
            {
                top++;
                n[top]=(double)s[i]-48;
            }
            else
            {
                double x=n[top];
                top--;
                double y=n[top];
                top--;
                top++;
                n[top]=Operate(x,y,s[i]);
            }
        }
        printf("%.2f\n",n[top]);
    }
}

 

基于循环链表的队列的基本操作

描述

用带头结点的循环链表表示队列,并且只设一个指针指向队尾元素结点(不设头指针)。实现该队列的入队出队以及判断队列是否为空操作。

输入

多组数据,每组数据有两行。第一行为两个整数n和m,n表示入队序列A的长度(n个数依次连续入队,中间没有出队的情况),m表示出队序列B的元素数量(m个数依次连续出队,中间没有入队的情况)。第二行为序列A(空格分隔的n个整数)。当n和m都等于0时,输入结束。

输出

对应每组数据输出一行。每行包括m+1个整数,前m个数代表出队序列B的各个整数,最后一个整数表示队列是否为空,队列为空输出0,不为空输出1。整数之间用空格分隔。

输入样例 1 

5 3
1 3 5 3 6
4 4
-1 2 3 4
0 0

输出样例 1

1 3 5 1
-1 2 3 4 0
#include<bits/stdc++.h>
using namespace std;
typedef struct LNode
{
    int data;
    LNode *next;
}LNode,*LinkList;
typedef struct
{
    LNode *fro,*rear;
}LinkQueue;

void InitQueue(LinkQueue &q)
{
    q.fro=q.rear=new LNode;
    q.fro->next=NULL;
}

void IsEmpty(LinkQueue &q)
{
    if(q.fro==q.rear)
        cout<<"0"<<endl;
    else
        cout<<"1"<<endl;
}

void EnQueue(LinkQueue &q,int x)
{
    LNode *s=new LNode;
    s->data=x;
    q.rear->next=s;
    q.rear=s;
}
void DeQueue(LinkQueue &q)
{
    LNode *s=q.fro->next;
    cout<<s->data<<" ";
    q.fro->next=s->next;
    if(q.rear==s)
    {
        q.rear=q.fro;
    }
    free(s);
}
int main()
{
    int n,m;
    while(cin>>n>>m&&n!=0&&m!=0)
    {
        int x;
        LinkQueue q;
        InitQueue(q);
        for(int i=0;i<n;i++)
        {
            cin>>x;
            EnQueue(q,x);
        }
        for(int i=0;i<m;i++)
        {
            DeQueue(q);
        }
        IsEmpty(q);
    }
}

附加判定标志的循环队列的基本操作

描述

假设以数组Q[m]存放循环队列中的元素, 同时设置一个标志tag,以tag== 0和tag == 1来区别在队头指针(front)和队尾指针(rear)相等时,队列状态为“空”还是“满”。试编写与此结构相应的插入(enqueue)和删除(dlqueue)算法。

输入

多组数据,每组数据有两行。第一行为一个整数n,n表示入队序列A的长度(n个数依次连续入队,中间没有出队的情况),第二行为序列A(空格分隔的n个整数)。当n=0时,输入结束。

输出

对应每组数据输出一行。依次输出队列中所有的整数,每两个整数之间用空格分隔。

输入样例 1 

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

输出样例 1

1 2 3 4
1 2 4 5 3

 

#include<bits/stdc++.h>
using namespace std;
typedef struct
{
    int data[1000];
    int fro,rear;
    int tag;
}SqQueue;

void InitQueue(SqQueue &q)
{
    q.fro=q.rear=0;
    q.tag=0;
}


bool EnQueue(SqQueue &q,int x)
{
    if(q.tag==1&&q.fro==q.rear)
    {
        return false;
    }
    q.data[q.rear]=x;
    q.rear++;
    if(q.tag==0)
    {
        q.tag=1;
    }
    return true;
}
bool DeQueue(SqQueue &q,int &x)
{
    if(q.tag==0&&q.fro==q.rear)
    {
        return false;
    }
    x=q.data[q.fro];
    q.fro++;
    if(q.tag==0)
    {
        q.tag=1;
    }
    return true;
}
int main()
{
    int n;
    while(cin>>n&&n!=0)
    {
        int x;
        SqQueue q;
        InitQueue(q);
        for(int i=0;i<n;i++)
        {
            cin>>x;
            EnQueue(q,x);
        }
        for(int i=0;i<n-1;i++)
        {
            DeQueue(q,x);
            cout<<x<<" ";
        }
        DeQueue(q,x);
        cout<<x<<endl;
    }
}

基于两端操作的循环队列的实现

描述

如果允许在循环队列的两端都可以进行插入和删除操作。构造一个循环队列,实现从队头入队,从队尾出队并输出。约定从队头入队时向下标小的方向发展,从队尾入队时则向下标大的方向发展。

输入

多组数据,每组数据有两行。第一行为一个整数n,n表示入队序列A的长度(n个数依次连续入队,中间没有出队的情况),第二行为序列A(空格分隔的n个整数)。当n等于0时,输入结束。

输出

对应每组数据输出一行。依次输出队列中所有的整数,每两个整数之间用空格分隔。

输入样例 1 

5
1 2 3 4 5
2
1 4
0

输出样例 1

1 2 3 4 5
1 4

 

#include<bits/stdc++.h>
using namespace std;
#define MAX 1000
typedef struct
{
    int data[MAX];
    int fro,rear;
}SqQueue;

void InitQueue(SqQueue &q)
{
    q.fro=q.rear=0;
}


bool EnQueue(SqQueue &q,int x)
{
    if((q.rear+1)%MAX==q.fro)
    {
        return false;
    }
    q.data[q.rear]=x;
    q.rear=(q.rear+1)%MAX;
    return true;
}
bool DeQueue(SqQueue &q,int &x)
{
    if(q.fro==q.rear)
    {
        return false;
    }
    x=q.data[q.fro];
    q.fro=(q.fro+1)%MAX;
    return true;
}
int main()
{
    int n;
    while(cin>>n&&n!=0)
    {
        int x;
        SqQueue q;
        InitQueue(q);
        for(int i=0;i<n;i++)
        {
            cin>>x;
            EnQueue(q,x);
        }
        for(int i=0;i<n-1;i++)
        {
            DeQueue(q,x);
            cout<<x<<" ";
        }
        DeQueue(q,x);
        cout<<x<<endl;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值