文章目录
第三章栈和队列
3.1栈(Stack)
是只允许在一端进行插入或者删除操作的线性表
特点:先进后出 Last in First out(LIFO)
顺序栈
定义与初始化
//顺序栈的定义
#define MaxSize[10]
typedef struct{
ElemType data[MaxSize];
int top;
}SqStack;
//初始化栈
bool InitStack(SqStack &S){//初始化栈顶指针
S.top=-1;//这里面top指向的栈顶元素,如果top的初始值是0,那么top指向的就是栈顶元素的下一个元素
}
//栈的判空
bool StackEmpty(SqStack S){
return(top=-1);
}
void testStack(){
SqStacck S;//先声明再使用
InitStack(&S);
}
进栈Push
bool Push(SqStack &S,ElemType e){
if(S.top==MaxSize-1)//栈满
return false;
S.top=S.top+1;
S.data[top]=e;
return true;
}
出栈Pop
bool Pop(SqStack &S,ElemType e){
if(S.top==-1)
return false;
e=S.data[S.top];
S.top=S.top-1;
return true;
}
读栈顶元素
bool GetTop(SqStack S,ElemType &e){
if(S.top==-1)
return false;
e=S.data[S.top];
return true;
}
共享栈
define MaxSize 10//共享栈的定义
tyepdef struct{
ElemType data[MaxSize];
int top0;
int top1;
}
bool InitStack(){
top0=-1;
top1=MaxSize;
}
//栈满的条件是top0+1=top1;
链栈
定义与初始化
typedef struct StrackNode{//栈的定义
ElemType data;
struct StrackNode *next;
}StrackNode,*LinkStrack;
入栈
bool Push(LinkStrack &S,ElemType e){
p=new StrackNode;
p->data=e;
p->next=S;
S=p;
return true;
}
出栈
bool Pop(LinkStrack &S,ElemType e){
if(S==null)
return false;
e=S->data;
StrackNode *p;
p=S;
S=S->next;
delete p;
return true;
}
取栈顶元素
bool GetTop(LinkStrack S,ElemType e){
if(S==null)
return null;
e=S->data;
return true;
}
3.2队列
一端2插入一端删除的线性表。First in First out (FIFO)
循环队列(顺序实现)
为什么要实现循环的队列呢,其实主要原因是会出现假溢出的现象,如下图所示
1 | 2 | 3 | 4 |
---|
队头 队尾
此时由于队尾不能再继续插入元素,再插入元素就会出现数组下标越界的情况,但是队头却是空的,由此会出现假溢出的现象,此时使用循环队列就会十分恰当。
定义与初始化
dedine MaxSize 10//队列的定义
typedef struct{
ElemType data[MaxSize];
int front;
int rear;
}SqQueue;
bool InitQueue(SqQueue &Q){
Q.front=Q.rear=0//注意,这里面rear指向的队尾元素的下一个元素,若是定义的时候,rear=MaxSize-1;此时,rear表示的是队尾元素,下面都采用rear表示队尾元素的下一个元素
}
入队
bool EnQueue(SqQueue &Q,ElemType e){
if((Qrear+1)%MaxSize==Q.front)
return false;
Q.data[Q.rear]=e;
Q.rear=(Q.rear+1)%MaxSize;
return ture;
}
出队
bool DeQueue(SqQueue &Q,ElemType e){
if(Q.front==Q.rear)
return false;
e=Q.data[Q.front];
Q.front=(Q.front+1)%MaxSize;
return true;
}
判断队列已满/已空
bool QueueEnough(SqQueue &Q){//判断队列已满
return (Q.rear+1)%MaxSize==Q.front;
}
bool QueueEmpty(SqQueue &Q){//判断队列已空
return Q.front==Q.rear;
}
取队首元素
bool GetFront(SqQueue &Q,ElemType e){
if(Q.front==Q.rear)
return false;
e=Q.data[Q.front];
return true;
}
不准浪费队列存储空间
其实上面所采用的方法是空出一个存储空间,来区分队列已满还是已空,假如出试卷的老师要求我们不准浪费存储空间,又该如何答题呢
- 在定义队列的时候加上一个size变量,用来表示当前队列中的元素个数,当size=0,则表示空。当size=MaxSize,则表示满
- 当队列空的时候,那么队列上一次进行的操作一定是出队,反之满的时候应当是入队。那么在定义队列的时候,可以加上一个tag变量,当进行出队操作的时候tag=0,当入对的时候tag=1,即frontrear&&tag0就表示空,frontrear&&tag1就表示满
链队
定义与初始化
typedef struct QNode{//链表的初始化
Elemtype data;
struct QNode *next;
}QNode,*QueuePtr;
typedef struct{
QueuePtr front;
QueuePtr rear;
}LinkQueue;
//初始化
bool InitQueue(LinkQueue &Q,ElemType e){//带头结点
Q.front=Q.rear=new QNode;
Q.front->next=null;
return true;
}
bool InitQueue(LinkQueue &Q,ElemType e){//不带头结点
Q.front=Q.rear=null;
return true;
}
入队
bool enqueue(LinkQueue &Q,ElemType e){//带头结点
p=new QNode;
p->data=e;
p->next=null;
Q.rear->next=p;
Q.rear=p;
return true;
}
bool enqueue(LinkQueue &Q,ElemType e){//不带头结点
p=new QNode;
p->data=e;
p->next=null;
if(Q.front==Q.rear){
Q.front=p;
Q.rear=p;
return true;
}
else{
Q.rear->next=p;
Q.rear=p;
return true;
}
}
出队
bool DuQueue(LinkQueue &Q,ElemType &e{//带头结点
if(Q.front==Q.rear)
return false;
e=Q.front->next-data;
LNode *p;
p=Q.front->next;
Q.front->next=p->next;
if(p==Q.rear)
Q.front=Q.rear;
free (p);
return true;
}
bool DuQueue(LinkQueue &Q,ElemType &e{//不带头结点
if(Q.front==Q.rear)
return false;
LNode *p;
p=Q.front;
e=p->data;
Q.front=p->next;
if(p==Q.rear)
Q.front=Q.rear=null;
free (p);
return true;
}
取队头元素
bool GetTop(LinkQueue Q,ElemType e){//带头结点
if(Q.front==Q.rear)
return false;
e=Q.front->next->data;
return true;
}
bool GetTop(LinkQueue Q,ElemType e){//不带头结点
if(Q.front==Q.rear)
return false;
e=Q.front->data;
return true;
}
双端队列
其实有一类题目考察的是输出序列合法性的
- 栈:先进后出 队:先进先出 很容易
- 输入受限的双端队列:两端可以删除,一端能插入,也比较容易写
Q,ElemType e){//带头结点
if(Q.front==Q.rear)
return false;
e=Q.front->next->data;
return true;
}
bool GetTop(LinkQueue Q,ElemType e){//不带头结点
if(Q.front==Q.rear)
return false;
e=Q.front->data;
return true;
}
#### 双端队列
其实有一类题目考察的是输出序列合法性的
- 栈:先进后出 队:先进先出 很容易
- 输入受限的双端队列:两端可以删除,一端能插入,也比较容易写
- 输出受限的双端队列:两端都可以插入,一端能删除,由于两个口都可以插入元素,所以要根据输出结果把比当前数字及以后的数逆序(一直到比当前数字大,或者数结束为止),然后看看能不能得到这样的输入,能得到就继续判断,一直到所有数字判断结束。