前言:
栈和队列可以称为操作受限的线性表。
目录:
一、栈
1.栈的定义
限定仅在表尾进行插入和删除的线性表。表尾端称为栈顶 (top),表顶端称为栈底 (bottom)。a1称为栈底元素,an称为栈顶元素。
如图所示,我们不难看出:栈是一个“后进先出,先进后出”的线性表。
注:栈除了存储数据元素外,还记录了数据元素入栈的次序。(考试必考点)
例:现有元素a、b、c、d、e、f 依次进栈,允许出栈、退栈操作交替进行。但不允许连续三次进行退栈操作,则不可能得到的出栈序列是:
A. dcebfa B. cbdaef C. bcaefd D.afedcb
解析:D选项中当 f 入栈前有 bcde 依次出栈,超过了限定条件连续三次退栈操作。
2.栈的表示和实现
① 顺序栈
//顺序栈的定义
typedef char SElemType; //这里char根据具体变量类型进行更改
#define STACK_INIT_SIZE 100;
#define STACKINCREMENT 10;
typedef struct {
SElemType *base; //栈底指针
SElemType *top; //栈顶指针
int stacksize; //存储容量
} SqStack;
//顺序栈的初始化
#define OVERFLOW -1;
void InitStack(SqStack *S)
{
S->base = (SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));
if(!S->basse){ //分配空间失败,则进行报错并结束程序
printf("分配空间失败!");
exit(OVERFLOW);
}
S->top = S->base;
S->stacksize = STACK_INIT_SIZE;
}
//顺序栈的入栈操作
void Push(SqStack *S, SElemType e)
{
if((S->top - S->base) >= S->stacksize){ //栈满判定
S->base = (SElemType *)realloc(S->base,
(S->stacksize+STACKINCREMENT)*sizeof(SElemType));
if(!S->basse){ //分配空间失败,则进行报错并结束程序
printf("分配空间失败!");
exit(OVERFLOW);
}
S->top = S->base + S->stacksize;
S->stacksize = S->stacksize + STACKINCREMENT;
}
*S->top++ = e;
}
//顺序栈的出栈操作
void Pop(SqStack *S, SElemType *e)
{
if(S->top == S->base){
printf("栈空!");
return -1;
}
*e = *--S->top;
}
栈底指针指向分配空间的第一个单元,栈顶指针指向栈顶元素后的一个单元。
上溢:当栈满时再做入栈运算必定产生空间溢出;
下溢:当栈空时再做出栈运算也将产生溢出。
②双向栈
在一个程序中同时使用两个数据类型相同的栈,可以考虑采用双向栈。
//双向栈的定义
#define STACKSIZE 100;
typedef char SElemType;
typedef struct {
int top[2]; //栈顶指针
SElemType *base; //存储基址
int stacksize;
}DqStack;
//双向栈的初始化
void InitStack(DqStack *S)
{
S->top[0] = -1;
S->top[1] = STACKSIZE;
S->stacksize = STACKSIZE;
S->base = (SELemType *)malloc(STACKSIZE*sizeof(SElemType));
}
//双向栈的进栈操作
#define ERROR -1
void Push(DqStack *S, int e, int i) //进i号栈
{
if(S->top[1] - S->top[0] == 1){
printf("栈满!");
return ERROR;
}
switch(i){
case 0:
++S->top[0];
S->base[S->top[0]] = e;
break;
case 1:
--S->top[1];
S->base[S->top[1]] = e;
break;
default:
break;
}
}
//双向栈的出栈操作
#define ERROR -1;
void Pop(DqStack *S, int *e, int i) //出i号栈
{
switch(i){
case 0:
if(S->top[0] == -1){
printf("栈空!");
return ERROR;
}
*e = S->base[--S->top[0]];
break;
case 1:
if(S->top[1] == STACKSIZE){
printf("栈空!");
return ERROR;
}
*e = S->base[++S->top[1]];
break;
default:
break;
}
}
③链栈
//链栈的定义
typedef struct SNode{
SElemType data;
struct SNode *next;
} *LinkStack;
二、队列
1.队列的定义
限定在表的一端进行插入,在表的另一端进行删除的线性表。表插入端称为队尾;表删除端称为队头。a1称为队头元素,an称为队尾元素。
如图所示,我们不难看出:队列是一个“先进先出,后进后出”的线性表
注:跟栈一样,我们仍然可以从队列中得到元素的入队次序。(考试必考点)
例:某队列允许在两端进行入队操作,但仅允许在一端进行出队操作,若元素a,b,c,d,e依次入队列后再进行出队列,则不可能得到出对序列是:
A. bacde B. dbace C. dbcae D. ecbad
2.队列的表示和实现
①循环队列
//循环队列的定义
typedef char QElemType;
#define MAXQSIZE 100
typedef struct {
QElemType *base; //存储基址
int front; //头指针
int rear; //尾指针
} SqQueue;
//循环队列的初始化
#define OVERFLOW -1;
void InitQueue(SqQueue *Q)
{
Q->base = (QElemType *)malloc(MAXQSIZE*sizeof(QElemType));
if(!Q->base){
printf("分配空间失败!");
exit(OVERFLOW);
}
Q->front = Q->rear = 0;
}
//循环队列的入队操作
#define ERROR -1;
void EnQueue(SqQueue *Q, QElemType e)
{
if((Q->rear+1)%MAXQSIZE == Q->front){
printf("队满!");
return ERROR;
}
Q->base[Q->rear] = e;
Q->rear = (Q->rear+1) % MAXQSIZE;
}
//循环队列的出队操作
void DeQueue(SqQueue *Q, QElemType *e)
{
if(Q->front == Q->rear){
printf("队空!");
return ERROR;
}
*e = Q->base[Q->front];
Q->front = (Q->front + 1) % MAXQSIZE;
}
②链栈
//链队的定义
typedef char QElemType;
typedef struct QNode {
QElemType data; //数据域
struct QNode *next; //指针域
} QNode, *QueuePtr;
typedef struct {
QueuePtr front; //队头指针
QueuePtr rear; //队尾指针
} LinkQueue;
//链队的初始化
#defint OVERFLOW -1;
void InitQueue(LinkQueue *Q)
{
Q->front = Q->rear = (QueuePtr)malloc(sizeof(QNode));
if(!Q->front){
printf("分配空间失败!");
exit(OVERFLOW);
}
Q->front->next = NULL;
}
//链队的入队操作
void EnQueue(LinkQueue *Q, QElemType e)
{
QueuePtr p = (QueuePtr)malloc(sizeof(QNode));
if(!p){
printf("分配空间失败!");
exit(OVERFLOW);
}
p->data = e;
p->next = NULL;
Q->rear->next = p;
Q->rear = p;
}
//链队的出队操作
#define ERROR -1;
void DeQueue(LinkQueue *Q, QElemType *e)
{
if(Q->rear == Q->front){
printf("队空!");
return ERROR;
}
QueuePtr p = Q->front->next;
*e = p->data;
Q->front->next = p->next;
if(Q->rear ==p) Q->rear = Q->front;
}