目录
一、栈
1.顺序栈
#include <stdio.h>
#define Maxsize 10
typedef struct
{
ElemType data[Maxsize];
int top;
}Sqstack;
void InitStack(Sqstack &q) //初始化栈 只需要把栈顶指针变为-1就行
{
q.top=-1;
}
bool textStack(Sqstack &q) //判断栈是否为空栈
{
if(q.top ==-1)
return true; //栈空
else
return false; //栈非空 或者简写成return (q.top==-1)
}
bool Push(Sqstack &q,ElemType x)//进栈操作
{
if(q.top ==Maxsize-1)
return false;
q.data [++q.top ]=x;
return true;
}
bool Pop(Sqstack &q,ElemType &x) //出栈操作
{
if(q.top ==-1)
return false;
x=q.data [q.top --];
return false;
}
bool GetTop(Sqstack &q,ElemType &x) //获取栈顶元素
{
if(q.top ==-1) //若栈为空栈 则返回false
return false;
x=q.data [q.top ];
return true; //注意top记得加q.top 还有++q.top和q.top--的用法
}
注意top记得加q.top和++q.top和q.top--的用法
这里的初始化操作是将top的值默认化为-1
另一种方式是将top的值化为0,注意此时入栈操作就是q.top++,出栈操作就是--q.top,还有判断空栈的条件
注意题目要求
2.共享栈(也就是有两个栈顶指针,为了节约内存空间)
#include <stdio.h>
#define Maxsize 10
typedef struct
{
ElemType data[Maxsize];
int top0;
int top1;
}Shstack;
void InitStack(Shstack &q) //初始化共享栈
{
q.top0=-1;
q.top1=Maxsize;
}
bool TextStack(Shstack &q) //判断栈是否满
{
if(q.top0+1==q.top1)
return true;
else
return false;
}
注意一点 就是以静态分配内存的方式 函数运行结束后会自动回收内存
而动态分配内存的方式 就需要malloc和free函数
3.链栈
这里的链栈是以有带头结点来实现的 而链栈最好还是用不带结点的来实现
1.带头结点
#include <stdio.h>
#include <stdlib.h>
typedef struct StackNode
{
ElemType data;
struct StackNode* next;
}StackNode,*LinkStack;
bool InitStack(LinkStack &q)
{
q=(StackNode *)malloc(sizeof(StackNode)); //这里是有头结点的类型
if(q==NULL)
return false;
q->next=NULL;
return true;
}
bool PushStack(LinkStack &q,ElemType x) //进栈操作
{
StackNode *p;
p=(StackNode *)malloc(sizeof(StackNode));
if(p==NULL)
return false;
p->data=x;
p->next=q;
q=p;
return true;
}
bool PopStack(LinkStack &q,ElemType &x)
{
if(q->next==NULL)
return false;
StackNode *p;
p=q; //用p来储存栈顶指针以便栈顶指针被释放
x=q->data;
q=q->next;
free(p);
return true;
}
2.不带头结点
#include <stdio.h>
#include <stdlib.h>
typedef struct StackNode
{
ElemType data;
struct StackNode* next;
}StackNode,*LinkStack;
void InitStack(LinkStack &q)
{
q=NULL;
return 0;
}
bool PushStack(LinkStack &q,ElemType x)
{
StackNode *p;
p=(LinkStack)malloc(sizeof(StackNode));
if(p==NULL)
return false;
p->data=x;
if(q==NULL)
{
p->next=NULL;
q=p;
}
p->next=q;
q=p;
return true;
}
bool PopStack(LinkStack &q,ElemType &x)
{
if(q==NULL)
return false;
x=q->data;
StackNode *p;
p=q;
q=q->next;
free(p);
return true;
}
二、队列的顺序实现
1.入队时的逻辑
因为是队列 所以总该有人出队 总有人入队 入队的人插到队尾
简写成FIFO(First in First out)
所以出队时front上移 有空的空间 当队尾的值到达最大长度时
就要回到下面来 看看还有没有剩余的空间 所以在这里要用到%符号
%的意思就是:比如说 x%10 也就是(x%10)这个表达式的值的范围就是0~9
所以具体的代码实现就是
typedef struct Queue
{
ElemType data[Maxsize];
int front;
int rear;
}Queue;
bool PushQueue(Queue &Q,ElemType x)
{
if((Q.rear+1)%Maxsize==Q.front)
return false;
Q.data[Q.rear]=x;
Q.rear=(Q.rear+1)%Maxsize;
return true;
}
这实际上就是把队列逻辑上变成一个环形的队列 使队尾指针无限在0~(Maxsize-1)的范围一直 循环直到队列已满
由于我的代码是 Q.data[Q.rear]=x;
Q.rear=(Q.rear+1)%Maxsize;是先赋值然后再进行队尾指针的后移
也就是 我的队尾指针永远指向接下来要插入的元素的位置
所以队满的条件就是 当再进行队尾指针后移的时候和队头指针的值相同
也就是(Q.rear+1)%Maxsize==Q.front;
这时候就要返回一个错误
更形象化的就是 如右图:
但是这样判断队满条件的缺点就是会白白浪费一个存储空间
具体的进队操作如下
#include <stdio.h>
#include <stdlib.h>
#define Maxsize 10
typedef struct Queue
{
ElemType data[Maxsize];
int front;
int rear;
int length;
}Queue;
bool InitQueue(Queue &Q)
{
Q.front=0;
Q.rear=0;
Q.length=0;
return true;
}
bool TestQueue(Queue &Q) //判断是否是为空队列
{
if(Q.front==Q.rear)
return true;
else
return false;
}
bool PushQueue(Queue &Q,ElemType x) //入队操作
{
if(Q.length==Maxsize)
return false; //队列已满
Q.data[Q.rear]=x;
Q.rear=(Q.rear+1)%Maxsize; //注意这个'%'符号 将逻辑变成环形的 好好品
Q.length++;
return true;
}
2.判断队满条件
注:一下情况都是队尾指针指向下一个元素插入时的位置 而不是队列的尾部
1.损失一个空间法
如上面所说的队满条件判断
具体实现就是 if((Q.rear+1)%Maxsize==Q.front);
return false;
2.size法
就是在定义队列的结构体的内容中加一个int变量的来记录队列的长度
typedef struct Queue
{
ElemType data[Maxsize];
int front;
int rear;
int length; //lenght变量来记录队列的长度
}Queue;
所以同样的在初始化队列的同时也要将lenght变量的值赋值为0
具体实现就是 if(Q.lenght==Maxsize)
return false;
3.0/1方法
定义一个tag变量来记录操作的是入队还是出队
入队就是1 出队就是0
所以如果要判断队满的条件那就是要tag的值为1同时Q.rear==Q.front
typedef struct Queue
{
ElemType data[Maxsize];
int front;
int rear;
int tag; //最近进行的是插入/删除
}Queue;
具体实现就是 if(Q.tag=1&&Q.rear==Q.front)
return false;
3.出栈&获取队头元素
#include <stdio.h>
#include <stdlib.h>
#define Maxsize 10
typedef struct Queue
{
ElemType data[Maxsize];
int front;
int rear;
}Queue;
void InitQueue(Queue &Q)
{
Q.front=0;
Q.rear=0;
return 0;
}
bool PopQueue(Queue &Q,ElemType &x) //出栈操作
{
if(Q.front==Q.rear) //判断是否为空队列
return false;
x=Q.data[Q.front];
Q.front=(Q.front+1)%Maxsize;
return false;
}
bool GetTop(Queue &Q,ElemType &x) //获取队头元素
{
if(Q.front==Q.rear) //队空则报错
return false;
x=Q.data[Q.front];
return true;
}
三、队列的链式实现
头指针都是指向第一个元素
1.带头结点的运算
这里的头指针是指向头结点 而不是队头元素
#include <stdio.h>
#include <stdlib.h>
typedef struct ListQueue
{
ElemType data;
struct ListQueue* next;
}QueueNode,*ListQueue;
typedef struct
{
ListQueue front;
ListQueue rear;
}LQueue;
bool InitQueue(LQueue &Q)
{
Q.front=(ListQueue)malloc(sizeof(QueueNode));
Q.rear=(ListQueue)malloc(sizeof(QueueNode));
if(Q.front==NULL||Q.rear==NULL)
return false;
Q.front=Q.rear;
Q.front->next=NULL;
return true;
}
bool PushQueue(LQueue &Q,ElemType x) //入队操作
{
ListQueue p;
p=(ListQueue)malloc(sizeof(QueueNode));
if(p==NULL)
return false;
p->data=x;
p->next=Q.rear->next; //也可以写成 p->next=NULL;一样的
Q.rear=p;
return true;
}
bool PopQueue(LQueue &Q,ElemType &x) //出队操作
{
if(Q.rear==Q.front)
return false;
x=Q.front->data;
ListQueue p;
p=(ListQueue)malloc(sizeof(QueueNode));
p=Q.front->next;
Q.front->next=p->next;
if(Q.rear==p) //当这个结点是最后一个元素的时候 要将Q.rear和Q.front相同 也就是空队
Q.rear=Q.front;
free(p);
return true;
}
2.不带头结点的运算
#include <stdio.h>
#include <stdlib.h>
typedef struct QueueNode
{
ElemType data;
struct QueueNode* next;
}QueueNode,*LinkQueue;
typedef struct
{
LinkQueue front;
LinkQueue rear;
}LQueue;
void InitQueue(LQueue &Q)
{
Q.front=NULL;
Q.rear=NULL;
return 0;
}
bool PushQueue(LQueue &Q,ElemType x)
{
LinkQueue p;
p=(LinkQueue)malloc(sizeof(QueueNode));
if(p==NULL)
return false;
p->data=x; //将新结点的数据存入
p->next=NULL; //将新结点的地址改为NULL
if(Q.front==NULL) //空队时单独讨论
{
Q.front=p; //队头指针都是指向第一个结点 注意带头结点的是有空结点的
Q.rear=p;
}
else
{
Q.rear->next=p; //新的结点插入队尾
Q.rear=p; //修改新的队尾指针
}
return true;
}
bool PopQueue(LQueue &Q,ElemType &x)
{
if(Q.front=NULL) //空队
return false;
x=Q.front->data;
LinkQueue p;
p=Q.front;
if(p==Q.rear)
{
Q.front=NULL;
Q.rear=NULL;
}
Q.front=Q.front->next;
free(p);
return true;
}
不带头结点的队列中 仅存一个元素的条件是 Q.front==Q.rear注意和带头结点的区分
四、双端队列
双端队列分为三种
只要记住判断输出序列合法性的考法就行