第三章 栈和队列
第三章 栈和队列
栈和队列是两个重要的线性数据结构,是操作受限的线性表
3.1栈和队列的定义和特点
3.1.1栈的定义和特点
- 栈是限定仅在表尾进行插入或者删除操作的线性表,操作受限的线性表,先进后出的线性表
- 栈顶是表尾端,栈底是表顶端
- 不含元素的空表是空栈
- 进栈和出栈的顺序是先进后出,进栈的时候如下图a1先进,其次a2,出栈的时候先出an,a(n-1)
- 如果需要按照保存数据时相反的顺序来使用数据, 则可以利用栈来实现。
- 栈跟线性表很像,有顺序栈和链栈
3.1.2队列的定义和特点
- 队列是先进先出的线性表
- 进队(插入)叫队尾,出队(删除)的叫队头
- 进队a1,a2,出队也是a1,a2这个顺序
3.3栈的表示和操作的实现
3.3.2顺序栈的表示和实现
顺序栈的定义
typedef struct
{
SElernType *base; //栈底指针
SElernType *top; //栈顶指针
int stacksize; //栈可用的最大容量
}Sqstack;
注意点
- 初始化完成后,栈底指针始终指向栈底元素,初始化完成前栈顶指针指向栈底元素,每入栈(插入)一个元素,栈顶指针自增1,出栈(删除)一个元素的时候栈顶指针自减1,当初始化完成后栈顶指针等于栈底指针则为空表
- 当栈底指针为NULL的时候表不存在,栈非空的时候,栈顶指针始终指向栈顶元素的上一位置
顺序栈的初始化
#include<iostream>
using namespace std;
#define MAXSIZE 100
#define OK "OK"
typedef string Status;
typedef int SElernType;
using namespace std;
typedef struct
{
SElernType *base; //栈底指针
SElernType *top; //栈顶指针
int stacksize; //栈可用的最大容量
}Sqstack;
int main()
{
Sqstack S;
Status InitStack(Sqstack &S);//初始化
cout << InitStack(S) << endl;
}
Status InitStack(Sqstack &S)
{
S.base=new SElernType[MAXSIZE];//申请空间
if(!S.base) exit(0);//空间分配失败
S.top=S.base;//栈顶和栈尾指针都指向栈尾
S.stacksize=MAXSIZE;//栈容量变量设置为MAXSIZE
return OK;
}
注意点
- 顺序表不是链表,直接在一个Sqstack类型的变量里面的栈底指针申请需要的内存,申请的类型则是自己需要的类型,这里我设置的是int类型
- 把栈顶指针和栈底指针都指向栈尾就可以了
顺序栈的入栈
Status Push(SqStack &s,SElemType e)
{
if(s.top-s.base==s.stacksize) return ERROR;
*s.top++=e;//入栈
return OK;
}
注意点
- 栈顶指针-栈尾指针的那个位移量把,就等于栈的元素个数,就算是栈满
顺序栈的出栈
Status Pop(SqStack &s,SElemType &e)
{
if(s.base==s.top) return ERROR;
e=*(--s.top);
return OK;
}
注意点
- 先指针减一,再赋值,因为第栈顶元素在栈顶指针指向的下一位
顺序栈的取栈顶元素
SElemType GetTop(SqStack S)
{
if(S.top!=S.base)
return *(S.top-1);
}
原理差不多
附本节实现代码
#include<iostream>
using namespace std;
#define MAXSIZE 100
#define OK "OK"
#define ERROR "ERROR"
typedef string Status;
typedef int SElemType;
using namespace std;
typedef struct
{
SElemType *base; //栈底指针
SElemType *top; //栈顶指针
int stacksize; //栈可用的最大容量
}SqStack;
int main()
{
SqStack S;
int e;
Status InitStack(SqStack &S);//初始化
Status Push(SqStack &s,SElemType e);//入栈
Status Pop(SqStack &s,SElemType &e);//出栈,每次出栈删除其栈顶元素
SElemType GetTop(SqStack S);//取栈顶元素,栈顶指针不变
cout << "初始化新栈:\n" <<InitStack(S) << endl;
cout << "入栈:\n" <<Push(S,20) << endl;
cout << "出栈:\n" <<Pop(S,e) << endl;
cout << "e:" << e << endl;
cout << "入栈:\n" <<Push(S,30) << endl;
cout << "取栈顶元素:\n" <<GetTop(S) << endl;
return 0;
}
Status InitStack(SqStack &S)
{
S.base=new SElemType[MAXSIZE];//申请空间
if(!S.base) exit(0);//空间分配失败
S.top=S.base;//栈顶和栈尾指针都指向栈尾
S.stacksize=MAXSIZE;//栈容量变量设置为MAXSIZE
return OK;
}
Status Push(SqStack &s,SElemType e)
{
if(s.top-s.base==s.stacksize) return ERROR;
*s.top++=e;//入栈
return OK;
}
Status Pop(SqStack &s,SElemType &e)
{
if(s.base==s.top) return ERROR;
e=*(--s.top);
return OK;
}
SElemType GetTop(SqStack S)
{
if(S.top!=S.base)
return *(S.top-1);
}
3.3.3栈链的表示与实现
定义
typedef struct StackNode
{
Elemtype data;
StackNode *next;
}StackNode, *LinkStack;
初始化
以链表的头部为栈顶,且不需要设置头结点,初始化空链表的时候只需要直接置空即可,操作栈的时候只需要在栈顶插入或者是删除,这样做也十分的方便
Status InitStack(LinkStack &L)
{
L= nullptr;//构造空栈,栈顶指针置空即可
return OK;
}
入栈
与顺序表不同,链式表在入栈的时候不需要考虑是否存满,只需分配一个结点空间即可,在栈顶插入,即将上一个元素往下挤
Status Push(LinkStack &L,int e)
{
auto p=new StackNode;//创建新结点
p->data=e;//结点赋值
p->next=L;//将之前一结点往下压
L=p;//设置栈顶
return OK;
}
出栈
出栈需要判断链表是否为空,同时释放后栈顶指针应该指向下一结点
Status Pop(LinkStack &L,Elemtype &e)
{
if(!L) return ERROR;//判断栈顶是否为空
LinkStack p;
e=L->data;//输出栈顶元素值
p=L;//存放栈顶指针,以便释放内存
L=L->next;//栈顶指针指向下一结点
delete p;//释放内存
return OK;
}
取栈顶元素
这个很简单,上面那个套过来
Status GetTop(LinkStack &L,Elemtype &e)
{
if(!L) return ERROR;
e=L->data;
return OK;
}
附完整代码
#include<iostream>
#define OK "OK"
#define ERROR "ERROR"
using namespace std;
typedef string Status;
typedef int Elemtype;
typedef struct StackNode
{
Elemtype data;
StackNode *next;
}StackNode, *LinkStack;
int main()
{
LinkStack L;
Elemtype e;
Status InitStack(LinkStack &L);//初始化操作
Status Push(LinkStack &L,Elemtype e);//入栈操作
Status Pop(LinkStack &L,Elemtype &e);//出栈操作
Status GetTop(LinkStack &L,Elemtype &e);//取栈顶元素
Status ClearStack(LinkStack &L);//清空栈,变为空栈
bool StackEmpty(LinkStack L);//判断栈是否为空
int StackLength(LinkStack L);//输出栈的长度
Status StackTraverse(LinkStack L);//遍历栈
Status DestroyStack(LinkStack &L);//破坏栈
cout << InitStack(L) << endl;
cout << Push(L,20) << endl;
cout << Push(L,30) << endl;
cout << Pop(L,e) << endl;
cout << e << endl;
cout << GetTop(L,e);
cout << e;
return 0;
}
Status InitStack(LinkStack &L)
{
L= nullptr;//构造空栈,栈顶指针置空即可
return OK;
}
Status Push(LinkStack &L,int e)
{
auto p=new StackNode;//创建新结点
p->data=e;//结点赋值
p->next=L;//将之前一结点往下压
L=p;//设置栈顶
return OK;
}
Status Pop(LinkStack &L,Elemtype &e)
{
if(!L) return ERROR;//判断栈顶是否为空
LinkStack p;
e=L->data;//输出栈顶元素值
p=L;//存放栈顶指针,以便释放内存
L=L->next;//栈顶指针指向下一结点
delete p;//释放内存
return OK;
}
Status GetTop(LinkStack &L,Elemtype &e)
{
if(!L) return ERROR;
e=L->data;
return OK;
}
Status ClearStack(LinkStack &L)
{
if(!L) return ERROR;
LinkStack p=L;
LinkStack q;
while(p)
{
q=p;
p=p->next;
delete q;
}
L= nullptr;
return OK;
}
bool StackEmpty(LinkStack L)
{
if(!L) return true;
else
return false;
}
int StackLength(LinkStack L)
{
LinkStack p=L;
int n=0;
while(p)
{
n++;
p=p->next;
}
return n;
}
Status StackTraverse(LinkStack L)
{
if(StackEmpty(L)) return ERROR;
LinkStack p=L;
while(p)
{
cout << p->data << endl;
p=p->next;
}
return OK;
}
Status DestroyStack(LinkStack &L)
{
if(!L) return ERROR;
LinkStack p=L;
LinkStack q;
while(p)
{
q=p;
p=p->next;
delete q;
}
return OK;
}
3.4栈与递归
3.4.1采用递归算法解决的问题
定义是递归的
分治法:对于某种复杂的问题,能够分解为几个简单的类似解法的子问题来求解,就程=称这种方法为递归求解,这种分解-求解的方法就叫做分治法
采用分治法求解递归需要满足三个条件:
- 能够将一个问题转换成一个新问题,新问题和原问题的解法类似或者相同,不同仅仅是处理对象不相同,并且吹处理对象更小或者是变化有规律
- 可以通过上述转换将问题简单化
- 必须有一个明确的递归出口,或者是一个递归的边界
viod p(参数表)
{
if(递归结束条件成立)可直接求解 //递归终止的条件
else p(较小的参数) //递归步骤
}
数据结构是递归的
链表是一种递归的数据结构
//遍历输出链表中各个结点的递归算法
void Display(LinkList L)
{
if(L)
{
cout << L->data << endl;
Display(L->next);
}
}
问题的解法是递归的
比如汉诺塔
3.4.2递归过程与递归工作栈
当有多个函数在嵌套调用的时候,采用先调用后返回的原则,上述函数之间的信息传递和控制转移通过栈来实现,整个系统运行时所需要的数据空间被安排在一个栈中,每调用一个函数,就在栈顶分配一个存储空间,当前运行的函数的数据区必须在栈顶
3.5队列的表示和操作的实现
3.5.1队列的类型定义
队列和栈不太一样,队列的删除在队列头部进行
下面是队列的基本操作,抽象数据类型定义
3.5.2 循环队列——队列的顺序表示和实现
队列顺序结构定义
#define MAXQSIZE 100//最大容量
typedef struct
{
QElemType *base;//存储空间基地址
int front;//头指针
int rear;//尾指针
};
队列插入删除操作图示
如图
- 初始化时,头指针和尾指针都在0的位置
- 入队时,尾指针增加一,且尾指针始终指向队尾元素的上一位
- 出队时,头指针增加一
注意:但是当出现图d这种情况时,再入队就会造成溢出,称为假溢出
循环队列——假溢出的解决方法
如图当第六个元素入队时,通过模运算,Q.rear=(Q.rear-1)%6
,得到Q.rear=0,此时J6存到最上面,而尾指针在最下面,达到循环队列解决假溢出的目的
弊端和解决办法
循环列表当头尾指针相同的时候,可能存在全空和全满两种状态,所以不能用头尾指针是否相同来判断队列是否满,
解决方法是少用一个元素空间, 即队列空间大小为m时,有m-1个元素就认为是队满。这样判断队
空的条件不变, 即当头、 尾指针的值相同时, 则认为队空;而当尾指针在循环意义上加1后是等
千头指针, 则认为队满。 因此, 在循环队列中队空和队满的条件是
Q.front=Q.rear//判断队空
(Q.rear+1)%MAXQSIZE=Q.front//判断队满
下面是具体的操作
初始化
Status InitQueue(SqQueue &Q)
{
Q.base=new QElemType [MAXQSIZE];//为队列分配足够的空间
if(!Q.base) exit(0);//分配失败
Q.front=Q.rear=0;//初始化置零
return OK;
}
Q.base存放用于队列的数据、
计算队列长度
int QueueLenth(SqQueue Q)
{
return (Q.rear-Q.front+MAXQSIZE)%MAXQSIZE;
}
对于非循环队列。其长度就是尾指针和头指针的差值,而对于循环队列,其长度等于尾指针和头指针的差值加上最大容量并取模长
入队
从队尾插入元素
Status EnQueue(SqQueue &Q,QElemType e)
{
if((Q.rear+1)%MAXQSIZE==Q.front)//判断是否队满
return ERROR;
Q.base[Q.rear]=e;//新元素插入队尾
Q.rear=(Q.rear+1)%MAXQSIZE;//作为循环队列,尾指针+1
return OK;
}
特殊方法尾指针+1,要记住
出队
出队从对头出,还要删除对应元素
Status DeQueue(SqQueue &Q,QElemType &e)
{
if(Q.rear==Q.front) return ERROR;//队空
e=Q.front;
Q.front=(Q.front+1)%MAXQSIZE;
return OK;
}
和入队相似
取队头元素
QElemType GetHead(SqQueue &Q)
{
if(Q.front!=Q.rear)
return Q.base[Q.front];
}
和出队相似,不改变队头指针
销毁
Status DestroyQueue(SqQueue &Q)//破坏队列
{
if(Q.base!= nullptr) //要判断是否为空
{
delete Q.base;
Q.base = nullptr;
}
Q.front=Q.rear=0;
return OK;
}
清除
Status ClearQueue(SqQueue &Q)//清除队列
{
delete Q.base;
Q.base=new QElemType[MAXQSIZE];
Q.front=Q.rear=0;
return OK;
}
判断是否为空
bool QueueEmpty(SqQueue Q)//判断是否为空
{
if(Q.rear==Q.front)
return true;
else return false;
}
遍历
Status QueueTraverse(SqQueue Q)//遍历
{
int i=Q.front;
while(i!=Q.rear)
{
cout << Q.base[i] << endl;
i=(i+1)%MAXQSIZE;
}
return OK;
}
附完整代码
#include<iostream>
#define OK "OK"
#define ERROR "ERROR"
#define MAXQSIZE 100
using namespace std;
typedef int QElemType;
typedef string Status;
typedef struct
{
QElemType *base;//存储空间基地址
int front;//头指针
int rear;//尾指针
}SqQueue;
Status InitQueue(SqQueue &Q)
{
Q.base=new QElemType [MAXQSIZE];//为队列分配足够的空间
if(!Q.base) exit(0);//分配失败
Q.front=Q.rear=0;//初始化置零
return OK;
}
int QueueLenth(SqQueue Q)
{
return (Q.rear-Q.front+MAXQSIZE)%MAXQSIZE;
}
Status EnQueue(SqQueue &Q,QElemType e)
{
if((Q.rear+1)%MAXQSIZE==Q.front)//判断是否队满
return ERROR;
Q.base[Q.rear]=e;//新元素插入队尾
Q.rear=(Q.rear+1)%MAXQSIZE;//作为循环队列,尾指针+1
return OK;
}
Status DeQueue(SqQueue &Q,QElemType &e)
{
if(Q.rear==Q.front) return ERROR;//队空
e=Q.base[Q.front];
Q.front=(Q.front+1)%MAXQSIZE;
return OK;
}
QElemType GetHead(SqQueue &Q)
{
if(Q.front!=Q.rear)
return Q.base[Q.front];
}
Status DestroyQueue(SqQueue &Q)//破坏队列
{
if(Q.base!= nullptr)
{
delete Q.base;
Q.base = nullptr;
}
Q.front=Q.rear=0;
return OK;
}
Status ClearQueue(SqQueue &Q)//清除队列
{
delete Q.base;
Q.base=new QElemType[MAXQSIZE];
Q.front=Q.rear=0;
return OK;
}
bool QueueEmpty(SqQueue Q)//判断是否为空
{
if(Q.rear==Q.front)
return true;
else return false;
}
Status QueueTraverse(SqQueue Q)//遍历
{
int i=Q.front;
while(i!=Q.rear)
{
cout << Q.base[i] << endl;
i=(i+1)%MAXQSIZE;
}
return OK;
}
int main()
{
SqQueue Q;
int e;
cout
<< InitQueue(Q) << endl
<< EnQueue(Q,4) << endl
<< EnQueue(Q,5) << endl
<< QueueTraverse(Q) << endl
<< QueueEmpty(Q) << endl
<< DeQueue(Q,e) <<endl
<< e << endl
<< ClearQueue(Q) << endl
<< QueueTraverse(Q) << endl;
return 0;
}
3.5.3链队——队列的链式表示与实现
链队的表示一般使用单链表,单链表的链式存储结构表示如下
结构定义
typedef struct QNode
{
QElemType data;
struct QNode *next;
}QNode,*QueuePtr;
typedef struct //这个结构体里面的每个变量都装上面的数据
{
QueuePtr front;//队头
QueuePtr rear;//队尾
}LinkQueue;
初始化
Status InitQueue(LinkQueue &Q)//初始化
{
Q.front=Q.rear=new QNode;//头尾结点指向相同的结点
Q.front->next= nullptr;//头结点指针域指针域
return OK;
}
入队
链表和顺序表一样,从尾部插入数据,头部输出
Status EnQueue(LinkQueue &Q,QElemType e)//入队
{
auto p=new QNode;//分配的新结点
p->data=e;//录入数据
p->next= nullptr;//指针域置空
Q.rear->next=p;//添加结点到链表
Q.rear=p;//尾指针指向最后一个结点,也就是新建的结点
return OK;
}
出队
注意出队的时候要判断链表是不是空链表,还需要释放队头元素占用的空间
Status DeQueue(LinkQueue &Q,QElemType &e)
{
if(Q.rear==Q.front) return ERROR;//判断是不是空链表
QueuePtr p=Q.front->next;//头指针的下一个元素
e=p->data;
Q.front->next=p->next;//头指针移动位置
if(Q.rear==p) Q.front=Q.rear;//当删除的是最后一个元素,需要头指针等于尾指针,表示空链表
delete p;
return OK;
}
取队头元素
QElemType GetHead(LinkQueue Q)//取队头元素
{
if(Q.rear!=Q.front)
return Q.front->next->data;//返回
}
销毁
Status DestroyQueue (LinkQueue &Q)//销毁
{
QueuePtr p=Q.front->next;//
QueuePtr q;
while(p)//删除
{
q=p;
p=p->next;
delete q;
}
return OK;
}
清除
Status ClearQueue (LinkQueue &Q)//清除
{
QueuePtr p=Q.front->next;//
QueuePtr q;
while(p)//删除,这里已经删除了头尾结点
{
q=p;
p=p->next;
delete q;
}
Q.front=Q.rear=new QNode;//重新创建
Q.front->next= nullptr;
return OK;
}
判断是否为空
bool QueueEmpty (LinkQueue Q)//判断是否为空
{
if(Q.rear==Q.front) return true;
else return false;
}
遍历
Status QueueTraverse(LinkQueue Q)//遍历
{
QueuePtr p=Q.front->next;
if(Q.front!=Q.rear)
{
while(p)
{
cout << p->data << endl;
p=p->next;
}
}
return OK;
}
附完整代码
#include<iostream>
#define OK "OK"
#define ERROR "ERROR"
using namespace std;
typedef int QElemType;
typedef string Status;
typedef struct QNode
{
QElemType data;
struct QNode *next;
}QNode,*QueuePtr;
typedef struct //这个结构体里面的每个变量都装上面的数据
{
QueuePtr front;//队头
QueuePtr rear;//队尾
}LinkQueue;
Status InitQueue(LinkQueue &Q)//初始化
{
Q.front=Q.rear=new QNode;//头尾结点指向相同的结点
Q.front->next= nullptr;//头结点指针域置空
return OK;
}
Status EnQueue(LinkQueue &Q,QElemType e)//入队
{
auto p=new QNode;//分配的新结点
p->data=e;//录入数据
p->next= nullptr;//指针域置空
Q.rear->next=p;//添加结点到链表
Q.rear=p;//尾指针指向最后一个结点,也就是新建的结点
return OK;
}
Status DeQueue(LinkQueue &Q,QElemType &e)//出队
{
if(Q.rear==Q.front) return ERROR;//判断是不是空链表
QueuePtr p=Q.front->next;//头指针的下一个元素
e=p->data;
Q.front->next=p->next;//头指针移动位置
if(Q.rear==p) Q.front=Q.rear;//当删除的是最后一个元素,需要头指针等于尾指针
delete p;
return OK;
}
QElemType GetHead(LinkQueue Q)//取队头元素
{
if(Q.rear!=Q.front)
return Q.front->next->data;
}
Status DestroyQueue (LinkQueue &Q)//销毁
{
QueuePtr p=Q.front->next;//
QueuePtr q;
while(p)//删除
{
q=p;
p=p->next;
delete q;
}
delete Q.front;//删除头指针
return OK;
}
Status ClearQueue (LinkQueue &Q)//清除
{
QueuePtr p=Q.front->next;//
QueuePtr q;
while(p)//删除,头尾都已经删除了
{
q=p;
p=p->next;
delete q;
}
delete Q.front;//删除头指针
Q.front=Q.rear=new QNode;//重新创建
Q.front->next= nullptr;
return OK;
}
bool QueueEmpty (LinkQueue Q)//判断是否为空
{
if(Q.rear==Q.front) return true;
else return false;
}
Status QueueTraverse(LinkQueue Q)//遍历
{
QueuePtr p=Q.front->next;
if(Q.front==Q.rear)
{
return ERROR;
}
while(p)
{
cout << p->data << endl;
p=p->next;
}
return OK;
}
int main()
{
LinkQueue Q;
int e;
cout
<< InitQueue(Q) << endl
<< EnQueue(Q,2) << endl
<< EnQueue(Q,3) << endl
<< QueueTraverse(Q) << endl
<< DeQueue(Q,e) << endl
<< e << endl
<< GetHead(Q) << endl
<< ClearQueue(Q) << endl
<< EnQueue(Q,6) << endl
<< QueueTraverse(Q);
return 0;
}
3.6案例分析与实现
3.6.1 数制转换
将十进制转换为八进制,将十进制数与八求余数压入栈中,这个数再变为其除以八,以此循环,直到N为0
算法实现
#include<iostream>
#define OK "OK"
#define ERROR "ERROR"
using namespace std;
typedef string Status;
typedef struct StackNode
{
int data;
StackNode *next;
}StackNode, *LinkStack;
Status IninStack(LinkStack &S)//初始化
{
S= nullptr;
return OK;
}
Status Push(LinkStack &S,int e)//入栈
{
auto p=new StackNode;
p->data=e;
p->next=S;
S=p;
return OK;
}
Status Pop(LinkStack &S,int &e)//出栈
{
if(!S) return ERROR;
LinkStack p;
p=S;
e=S->data;
S=S->next;
delete p;
return OK;
}
bool Isempty(LinkStack S)//判断是否为空
{
if(!S) return true;
else return false;
}
int main()
{
LinkStack S;
int e,a;
cout << IninStack(S) << endl;
cin >> a;
while(a)//入栈
{
cout << Push(S,(a%8)) << endl;
a=a/8;
}
while(!Isempty(S))//出栈
{
Pop(S,e);
cout << e;
}
return 0;
}
3.6.2括号匹配的检验
当有左括号的时候入栈,当有右括号的时候,与栈顶元素比较,符合则往下比较,不符合直接退出匹配失败,最后当所有括号扫描完,,每个都匹配成功的时候最后匹配成功
算法实现
#include<iostream>
#define OK "OK"
#define ERROR "ERROR"
using namespace std;
typedef string Status;
typedef char Elemtype;
typedef struct StackNode
{
Elemtype data;
StackNode *next;
}StackNode, *LinkStack;
Status IninStack(LinkStack &S)//初始化
{
S= nullptr;
return OK;
}
Status Push(LinkStack &S,Elemtype e)//入栈
{
auto p=new StackNode;
p->data=e;
p->next=S;
S=p;
return OK;
}
Status Pop(LinkStack &S,Elemtype &e)//出栈
{
if(!S) return ERROR;
LinkStack p;
p=S;
e=S->data;
S=S->next;
delete p;
return OK;
}
bool Isempty(LinkStack S)//判断是否为空
{
if(!S) return true;
else return false;
}
Elemtype GetTop(LinkStack S)
{
if(!Isempty(S))
return S->data;
else
return 0;
}
int main()
{
LinkStack S;
int flag=1;
char ch,x;
cout << IninStack(S) << endl;
cin >> ch;//输入括号表达式
while(ch!='#'&&flag)
{
switch(ch)//比较
{
case '[':
Push(S, ch);
break;
case '('://左括号入栈
Push(S, ch);
break;
case ')'://右括号符合条件出栈
if(!Isempty(S)&& GetTop(S)=='(')
Pop(S,x);
else
flag = 0;
break;
case ']':
if(!Isempty(S)&& GetTop(S)=='[')
Pop(S,x);
else
flag = 0;
break;
}
cin >> ch;
}
if(Isempty(S)&&flag) cout << "success";//最后比较
else cout << "fail";
return 0;
}
注意:case语句不需要写大括号,但是必须要有break语句,执行到break结束,default语句放在case后,当所有情况都不符合才会执行
3.6.3表达式求值(此题P78)
一个表达式都是由操作数,运算符,界限符组成,计算的时候还需要考虑各种运算符的优先级
- 操作数:数字,字符,常量,变量
- 运算符:+;-;*;/,算术运算符,关系运算符,逻辑运算符
- 界限符:括号等
#include<iostream>
#include<unordered_map>
#define OK "OK"
#define ERROR "ERROR"
using namespace std;
typedef string Status;
typedef char Elemtype;
char ch1;
typedef struct StackNode
{
Elemtype data;
StackNode *next;
}StackNode, *LinkStack;
Status IninStack(LinkStack &S)//初始化
{
S= nullptr;
return OK;
}
Status Push(LinkStack &S,Elemtype e)//入栈
{
auto p=new StackNode;
p->data=e;
p->next=S;
S=p;
return OK;
}
Status Pop(LinkStack &S,Elemtype &e)//出栈
{
if(!S) return ERROR;
LinkStack p;
p=S;
e=S->data;
S=S->next;
delete p;
return OK;
}
bool Isempty(LinkStack S)//判断是否为空
{
if(!S) return true;
else return false;
}
Elemtype GetTop(LinkStack S)
{
if(!Isempty(S))
return S->data;
else
return 0;
}
bool In(char ch)
{
if(ch=='+'||ch=='-'||ch=='*'||ch=='/'||ch=='('||ch==')'||ch=='#')
return true;
else return false;
}
char Precede(char c1,char c2)
{
unordered_map<char,int>hash_map{
{')',0},
{'#',-1},
{'+',1},
{'-',1},
{'*',2},
{'/',2},
{'(',3}
};
if((c1=='('&&c2==')')||(c1=='#'&&c2=='#'))
return '=';
else if(c1=='(')
return '<';
else if(c1==')')
return '>';
else if(hash_map[c1]<hash_map[c2])
return '<';
else if(hash_map[c1]>hash_map[c2])
return '>';
}
char Operate(char c1,char c2,char c3)
{
if(c2=='+')
return ch1=(c1-48)+(c3-48);
else if(c2=='-')
return ch1=(c1-48)-(c3-48);
else if(c2=='*')
return ch1=(c1-48)*(c3-48);
else if(c2=='/')
return ch1=(c1-48)/(c3-48);
}
int main()
{
char ch,theta,a,b,x;
LinkStack OPTR;
LinkStack OPND;
IninStack(OPND);
IninStack(OPTR);
Push(OPTR,'#');
cin >> ch;
while(ch!='#'|| GetTop(OPTR)!='#')
{
if(!In(ch)){Push(OPND,ch);cin >> ch;}
else
switch(Precede(GetTop(OPTR),ch))
{
case '<':
Push(OPTR,ch);cin>>ch;
break;
case '>':
Pop(OPTR,theta);
Pop(OPND,b);
Pop(OPND,a);
Push(OPND, Operate(a,theta,b));
break;
case '=':
Pop(OPTR,x);cin >> ch;
break;
}
}
cout << (int)GetTop(OPND);
return 0;
}
问题:复合运算的时候出现问题,暂时无法解决
3.6.4舞伴问题
舞伴配对问题用的是链队方法
#include<iostream>
#define OK "OK"
#define ERROR "ERROR"
#define MAXQSIZE 100
using namespace std;
typedef string Status;
typedef char QElemType;
typedef struct
{
string name;
char sex;
}Person;
typedef struct
{
Person* base;
int front;//队头
int rear;//队尾
}SqQueue;
Status InitQueue(SqQueue& Q)
{
Q.base = new Person[MAXQSIZE];
if (!Q.base) exit(0);
Q.front=Q.rear= NULL;
return OK;
}
Status EnQueue(SqQueue& Q, Person e)
{
if ((Q.rear + 1) % MAXQSIZE == Q.front)
return 0;
Q.base[Q.rear] = e;
Q.rear = (Q.rear + 1) % MAXQSIZE;
return OK;
}
Status DeQueue(SqQueue& Q, Person& e)
{
if (Q.front == Q.rear) return ERROR;
e = Q.base[Q.front];
Q.front = (Q.front + 1) % MAXQSIZE;
return OK;
}
Person GetHead(SqQueue Q)
{
if (Q.front != Q.rear)
return Q.base[Q.front];
}
bool QueueEmpty(SqQueue& Q)
{
if (Q.front == Q.rear) return true;
else return false;
}
void DancePartner(Person dancer[], int num)
{
Person p;
SqQueue Mdancers, Fdancers;
InitQueue(Mdancers);
InitQueue(Fdancers);
for (int i = 0; i < num; i++)
{
p = dancer[i];
if (p.sex == 'F') EnQueue(Fdancers, p);
else EnQueue(Mdancers, p);
}
while (!QueueEmpty(Fdancers) && !QueueEmpty(Mdancers))
{
DeQueue(Fdancers, p);
cout << p.name<<"-";
DeQueue(Mdancers, p);
cout << p.name<<endl;
}
if (!QueueEmpty(Fdancers))
{
p = GetHead(Fdancers);
cout << "The first woman to get a partner is:" << p.name << endl;
}
else if (!QueueEmpty(Mdancers))
{
p = GetHead(Mdancers);
cout << "The first man to get a partner is:" << p.name << endl;
}
}
int main()
{
SqQueue Mdancers, Fdancers;
int n;
Person dancer[MAXQSIZE];
cout << "请输入跳舞的人数:" << endl;
cin >> n;
for (int i=1; i<=n; i++)
{
cin >> dancer[i-1].name;
cin >> dancer[i-1].sex;
}
DancePartner(dancer, n);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)