一、链栈
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;
}