数据结构——栈和队列

目录

3.1栈和队列的定义和特点

3.2案例引入

3.3栈的实现和操作的实现

顺序栈的表示

顺序栈初始化

顺序栈是否为空

顺序表长度

清空顺序栈

销毁顺序栈

顺序栈的入栈

顺序栈的出栈

链栈的表示

链栈的初始化

链栈是否为空

链栈的入栈

链栈的出栈

取栈顶元素

3.4栈和递归

3.5队列的表示和操作的实现

顺序队表示

链队表示

3.6案例分析与实现


3.1栈和队列的定义和特点

  • 栈和队列是两种常用的、重要的数据结构
  • 栈和队列是限定插入和删除只能在表的“端点”进行的线性表
    • 后进先出(FLFO)
    • 应用
      • 数据转换/括号匹配/行编辑顺序/迷宫求解/表达式求值/八皇后问题/函数调用/递归调用的实现
    • 数据结构——栈和队列_第1张图片
    • 栈仅在表尾进行插入、删除,表尾为栈顶(Top,表头为栈底(Base)
    • 插入元素到栈顶(表尾)的操作,称为入栈 = Push
    • 栈顶删除最后一个元素的操作,出栈 = Pop
    • 数据结构——栈和队列_第2张图片

  • 数据结构——栈和队列_第3张图片
  • 队列
    • 先进先出(FIFO)
    • 应用
      • 脱机打印输出/多用户系统排队/按用户优先级排队,每个优先级一个队列/实时控制系统/网络电文传输

3.2案例引入

    • 进制转换
    • 括号匹配的检验
    • 表达式求值
  • 队列
    • 舞伴问题

3.3栈的实现和操作的实现

  • 栈的顺序存储——顺序栈
  • 栈的链式存储——链栈
  • 到栈底的数据元素,栈底在低地址端
    • top指针,指示栈顶元素
    • base指针,指示栈底元素
    • 数据结构——栈和队列_第4张图片
    • top通常指示真正的栈顶元素之上的下标地址
    • stacksize表示栈可使用的最大容量
    • 数据结构——栈和队列_第5张图片
  • 使用数组作为顺序栈的特点
    • 简单,易产生溢出(数据大小固定)
    • 上溢:栈已经满,又要压入元素
    • 下溢:栈已经空,又要弹出元素

顺序栈的表示

#define MAXSIZE 100

typedef struct{

SElemType *base;

SElemType *top;

int stacksize;

}SqStack;

 

顺序栈初始化

Status InitStack(SqStack &S){

S.base = new SElemType[MAXSIZE];

if(!S.base) exit(OVERFLOW);

S.top = S.base;

S.stacksize = MAXSIZE;

return OK;

}

 

顺序栈是否为空

Status StackEmpty(SqStack S){

if(S.top == S.base)

return OK;

else

return FALSE;

}

 

顺序表长度

int StackLength(SqStack S){

return S.top - S.base;

}

 

清空顺序栈

Status ClearStack(SqStack S){

if(S.base) S.top = S.base;

return OK;

}

 

销毁顺序栈

Status DestoryStack(SqStack &S){

if(!S.base){

delete S.base;

S.stacksize = 0;

S.base = S.top = NULL;

}

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.top == S.base)

return ERROR;

e = *--S.top;

return OK;

}

 

链栈的表示

typedef struct StackNode{

SElemType data;

struct StackNode *next;

}StackNode,*LinkStack;

LinkStack S;

 

链栈的初始化

void InitStack(LinkStack &S){

S = NULL;

return OK;

}

 

链栈是否为空

Status StackEmpty(LinkStack S){

if(S==NULL) return TRUE;

else return FALSE;

}

 

链栈的入栈

Status Push(LinkStack &S,SElemType e){

p = new StackNode;

p->data = e;

p->next = S;

S = p;

return OK;

}

 

链栈的出栈

Status Pop(LinkStack &S,SElemType &e){

if(S==NULL) return ERROR;

e = S->data;

p = S;

S = S->next;

delete p;

return OK;

}

 

取栈顶元素

SElemType GetTop(LinkStack S){

if(S!-NULL){

return S->data;

}

}

 

 

3.4栈和递归

  • 递归定义:
    • 若一个对象部分包含它自己,或用它自己给自己定义,称这个对象是递归的
    • 若一个过程直接的或间接的调用自己,称这个过程是递归的过程
  • 二叉树、广义表等都有用递归
  • 递归就是把一个问题化成基本项归纳项
  • 数据结构——栈和队列_第6张图片
  • 递归优缺点
    • 优点:结构清晰、程序易读
    • 缺点:时间开销大
  • 解决方法
    • 用循环结构代替递归
    • 自用栈模拟系统的运行时栈

3.5队列的表示和操作的实现

  • 插入元素称为入队,删除元素称为出队
  • 队列的存储结构为链队和顺序队(循环顺序队)

顺序队表示

  • 队列表示
    • 代码

#define MAXQSIZE 100

typedef struct{

QElemType *base;

int front;//头指针

int rear;//尾指针

}SqQueue;

  • 存在假溢出问题,解决方法
    • 使用循环队列
    • 数据结构——栈和队列_第7张图片
    • Base[0]接在base[MAXQSIZE-1]之后,若rear+1==M,则令rear = 0;(利用模运算)
    • 插入
      • Q.base[Q.rear]=x;
      • Q.rear=(Q.rear+1)%MAXSIZE;
    • 删除
      • X = Q.base[s.front];
      • Q.front=(Q.front+1)%MAXSIZE
    • 对空
      • Front == rear
    • 队满
      • (Rear+1)%MAXQSIZE==front
  • 队列的初始化
    • 代码

Status InitQueue(SqQueue &Q){

Q.base = new QElemType[MAXQSIZE];

if(!Q.base) exit(OVERFLOW);

Q.front = Q.rear = 0;

return OK;

}

  • 队列长度
    • 代码

int QueueLength(SqQueue Q){

return ((Q.rear-Q.front+MAXQSIZE)%MAXQSIZE);

}

  • 循环队列入队
    • 代码

Status EnQueue(SqQueue &Q,QElemType e){

if((Q.rear+1)%MAXSIZE==Q.front) return ERROR;

Q.base[Q.rear] = e;

Q.rear = (Q.rear + 1) % MAXQSIZE;

return OK;

}

  • 循环队列出队
    • 代码

Status DeQueue(SqQueue &Q,QElemType &e){

if(Q.front==Q.rear) return ERROR;

e = Q.base[Q.front];

Q.front = (Q.front+1)%MAXQSIZE;

return OK;

}

  • 取队头元素
    • 代码

SElemType GetHead(SqQueue Q){

if(Q.front != Q.rear)

return Q.base[Q.front];

}

链队表示

  • 无法估计所用队列的长度,就用链队列

  • 链队类型定义
    • 代码

#define MAXQSIZE 100

typedef struct Onode{

QElemType data;

struct Qnode *next;

}QNode, *QuenePtr;

  • 链队初始化
    • 代码

Status InitQueue(LinkQueue &Q){

Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));

if(!Q.front) exit(OVERFLOW);

Q.front->next = NULL;

return OK;

}

 

  • 销毁链队列
    • 代码

Status DestoryQueue(LinkQueue &Q){

while(Q.front){

p = Q.front->next;

free(Q.front);

Q.front = p;

}

return OK;

}

 

  • 入队
    • 代码

Status EnQueue(LinkQueue &Q,QElemType e){

p = (QueuePtr)malloc(sizeof(QNode));

if(!p) exit(OVERFLOE);

p->data = e;p->next = NULL;

Q.rear->next = p;

Q.rear = p;

return OK;

}

 

  • 出队
    • 代码

Status DeQueue(LinkQueue &Q,QElemType &e){

if(Q.front==Q.rear) return ERROR;

p = Q.front->next;

e = p->data;

Q.front->next = p->next;

if(Q.rear == p)Q.rear = Q.front;

delete p;

return OK;

}

3.6案例分析与实现

你可能感兴趣的:(数据结构,数据结构,算法)