栈又名堆栈,它是一种运算受限的线性表,限定仅在表尾进行插入和删除操作的线性表。队列也是一种特殊的线性表,特殊之处在于它只允许在表的前端进行删除操作,在表的后端进行插入操作,和栈一样,队列是一种操作受限制的线性表。

[TOC]

前言

栈又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。 而队列也是一种特殊的线性表,特殊之处在于它只允许在表的前端进行删除操作,在表的后端进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

一、栈

栈的概念

  • 插入或删除栈元素的运算只能在表的一端进行,称运算的一端为栈顶,另一端称为栈底。
  • 特点:后进先出LIFO

    栈的基本运算

  1. 初始化栈InitStack(&S)
    设置一个空栈S。
  2. 压栈Push(&S, e)
    将元素e插入栈S中,使x成为栈S的栈顶元素。
  3. 出栈Pop(&S, &e)
    当栈S不空时,由e返回栈顶元素,并从栈中删除栈顶元素
  4. 取栈顶元素GetTop(S,&e)
    若栈S不空,则由e返回栈顶元素。
    (此处传入函数参数加&的原因).

栈的分类

按照存储关系分类,栈可以分为顺序栈和链栈

1. 顺序栈

概念

栈的顺序存储结构简称为顺序栈。通常由一个一维数组和一个记录栈顶元素位置的变量组成。
结构图:
栈流程图

类型定义方式

创建一个结构体,表述当前栈顶,以及栈的基底,加上一个整型用于表示堆栈最大容量(非空栈的top指针始终在栈顶元素的上一个!!!)

1
2
3
4
5
6
typedef struct 
{
SElemType *base;//在构造前和销毁后,base值为NULL
SElemTyoe * top;//栈顶指针,top=base则为空栈
int stacksize;
}SqStack;

结构体用法复习

基本操作函数主体

  1. 初始化栈InitStack(&S)
    函数主体:
1
2
3
4
5
6
7
8
9
#define STACK_INIT_SIZE 100 //预先定义的初始化堆栈的容量
Status InitStack(SqStack &S)
{
S.base = (SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));
if(!S.base) exit (OVERFLOW)
S.top=S.base;
S.stacksize = STACK_INIT_SIZE
return OK;//分配完成
}
  1. 压栈Push(&S, e)
    插入e为新的栈顶元素
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #define STACK_INCREASE 10    //储存空间分配增量
    #define STACK_INIT_SIZE 100 //预先定义的初始化堆栈的容量
    Status Push(SqStack &S,SElemType e)
    {
    if(S.top - S.base >= S.stacksize)//判断剩余空间是否足够,不够则扩展栈的大小
    {
    S.base = (SElemType *)realloc(S.base,(S.stacksize+STACK_INCREASE)*sizeof(SElemType))
    if(!S.base)exit(OVERFLOW);//存储分配失败
    S.top = S.base + S.stcaksize
    S.stacksize+=STACK_INCREASE;
    }
    * S.top++=e;
    return OK;
    }
  2. 出栈Pop(&S, &e)
1
2
3
4
5
6
Status Pop(SqStack &S,SElemType &e)
{
if(S.top == S.base)return ERROR;//栈为空则报错
e = * --S.top;
return OK;
}
  1. 取栈顶元素GetTop(S,&e)
1
2
3
if(S.top == S.base)return ERROR;
e= *(S.top-1);
return OK;

2. 链栈

概念

栈的链式实现是以链表作为栈的存储结构,并在这种存储结构上实现栈的基本运算。栈的链式实现称为链栈
其结构示意图如下:
链栈结构图

类型定义方式

1
2
3
4
5
typedef struct snode {  //定义链栈结点类型
ElemType data;
struct snode *next;
}LinkSTACK;
LinkSTACK *top;

链栈不同状态结构图

链栈不同状态结构图

链栈基本函数

  1. 压栈Push(&S, e)
1
2
3
4
5
6
7
8
9
Status Push(LinkSTACK **top,ElemType e)
{
LinkSTACK *s;
s=(LinkSTACK *)malloc(sizeof(LinkSTACK));
s->data=e;
s->next=(*top)->next;
(*top)->next=e;
return OK;
}
  1. 出栈Pop(&S, &e)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Status Pop(LinkSTACK **top, ElemType *e) 
{
LinkSTACK *s;
if(!top)
{
printf("\n stack is free!");
return ERROR;
}
s=(*top)->next;
*e=s->data;
(*top)->next=s->next;
free(s);
return OK;
}
  1. 取栈顶元素GetTop(S,&e)
1
2
3
4
5
6
7
8
9
10
Status GetTop(LinkSTACK **top,ElemType *e)
{
if(!top)
{
printf("\n stack is free!");
return Error;
}
*e=(*top)->next->data;
return OK;
}

栈的应用

  1. 迷宫求解
  2. 表达式求值
  3. 括号匹配的检验
  4. 递归的实现

二、队列

队列的定义

队列也是一种运算受限的线性表。在这种线性表上,插入限定在表的某一端进行,删除限定在表的另一端进行。允许插入的一端称为队尾(rear),允许删除的一端称为队头(front)。
特点:队列中数据元素的入队和出队过程是按照“先进先出” 的原则进行的。因此,队列又称为“先进先出”的线性表,简称FIFO表。
队列结构图如下:
队列图

队列的基本运算

  1. 队列初始化InitQueue(&Q)
    设置一个空队列Q。
  2. 入队列EnQueue(&Q,e)
    将e插入到队列Q的队尾。
  3. 出队DeQueue(&Q,e)
    将队头元素赋给e,并删除队头元素。
  4. 取队头元素GetHead(Q,&e)
    由e返回队头结点的值。

    队列的分类(按存储方式分)

    1. 顺序队

    定义:

    顺序队是用一维数组依次存放队列中的元素和分别指示队列的首端和队列的尾端的两个变量组成。这两个变量分别称为“队头指针”和“队尾指针”。结构图如下:
    顺序队

数据类型定义

1
2
3
4
5
6
#define MaxSize <最大容量>  
typedef struct
{
ElemType data[MaxSize];
int front,rear;//front队首 rear队尾
}SQUEUE;

基本操作函数主体

2.链式队

定义

队列的链式存储结构简称为链队。是一个同时带有首指针和尾指针的单链表。头指针指向表头结点,尾指针则指向队尾元素。
结构图:
链式队

数据类型定义

1
2
3
4
5
6
7
8
9
10
11
typedef struct QNode
{
QElemType data;
struct QNode *next;
}QNode,*QueuePtr;

typedef struct
{
QueuePtr front;//队头
QueuePtr rear; //队尾
}LinkQueue;

基本操作函数主体

  1. 队列初始化InitQueue(&Q)
1
2
3
4
5
6
7
Status InitQueue(LinkQueue &Q) 
{
Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));
if(!Q.front)exit(OVERFLOW);
Q.front->next = NULL;
return OK;
}
  1. 入队列EnQueue(&Q,e)
1
2
3
4
5
6
7
8
9
10
Status EnQueue(LinkQueue &Q,QElemType e) 
{
p= (QueuePtr)malloc(sizeof(QNode));
if(!p)exit(OVERFLOW);
p->data = e;
p->next = NULL;
Q.rear-> next = p;
Q.rear = p;
return OK;
}
  1. 出队DeQueue(&Q,e)
1
2
3
4
5
6
7
8
9
10
11
12
Status DeQueue(LinkQueue &Q,QElemType &e) 
{

if(Q.rear==Q.front)
return ERROR;
p= Q.front->next;
e=p->data;
Q.front->next = p->next;
if(Q.rear == p) Q.rear = Q.front;
free(p);//释放空间
return OK;
}

总结

栈和队列知识内容笔记还未整理完全,栈和队列的基本函数实体没有整理完毕,最主要的是他们的应用场景没有详细展开。