数据结构第五篇——栈和队列

目录

前言

一、栈的定义和特点

二、栈的逻辑结构以及基本操作

2.1 用抽象数据类型来定义栈的数据结构

2.2 顺序栈的定义及其特点

2.3 顺序存储结构对栈基本操作的实现

2.4 链栈的定义及其特点

2.5 链式存储结构对栈基本操作的实现

三、队列的定义和特点

四、队列的逻辑结构以及基本操作

4.1 用抽象数据类型来定义队列的数据结构

4.2 顺序队列的定义及其特点

4.3 顺序存储结构对队列基本操作的实现

4.4 链式队列的定义及其特点

4.5 链式存储结构对队列基本操作的实现

4.6 双端队列的用法

五、栈的经典应用

5.1 栈的经典应用1:括号匹配问题

5.2 栈的经典应用:表达式求值问题

5.2.1 中缀表达式转后缀表达式(类似手算过程)

5.2.2 中缀表达式转后缀表达式(机算)

5.2.3 用栈实现后缀表达式的计算(机算)

5.2.4 用栈实现中缀表达式的计算(机算)

5.2.5 中缀表达式转前缀表达式(手算方法)

5.2.6 用栈实现前缀表达式的计算

5.3 理解递归调用和栈之间的关系

六、队列应用

6.1 队列应用:树的层次遍历

6.2 队列应用:图的广度优先遍历

6.3 队列在操作系统中的应用

6.4 队列应用:打印数据缓冲区


前言

每接触一种数据结构类型,就要从逻辑结构,物理结构,数据的运算这三个方面进行考虑,深入理解定义

一、栈的定义和特点

栈(stack)是只允许在一端进行插入或删除操作的线性表。

  1. 栈顶(top):允许插入删除的一端(一般是表尾)
  2. 栈底(bottom):不允许插入删除的一端(一般是表头)
  3. 空栈:不含任何元素的空表。
  4. 原则:后进先出 (Last In First Out, LIFO) 。

可以类比叠盘子。

超纲了解:卡特兰数

一个n个元素皆不相同的序列,给定入栈顺序,但出栈与入栈同时进行,出栈的排列总共有(卡特兰数Catalan)。

问题:入栈顺序a->b->c->d->f, 在入栈的同时出栈,哪些出栈顺序是合法的?

二、栈的逻辑结构以及基本操作

2.1 用抽象数据类型来定义栈的数据结构

2.2 顺序栈的定义及其特点

顺序栈是指利用顺序存储结构实现的栈。

即利用一组地址连续的存储单元依次存放自栈底到 栈顶的数据元素,同时附设指针top指示栈顶元素在顺序栈中的位置。

2.3 顺序存储结构对栈基本操作的实现

与顺序表类似,顺序栈类型的表示方法有两种:静态分配和动态分配。静态分配:用静态的“数组”存放数据;动态分配:用指针指向一片连续的区域。

栈顶用从0记的话初始化top为-1;

栈顶用从1记的话初始化top为0;

声明顺序栈类型:

静态分配方式

#define Maxsize 10 //定义栈中最多元素

typedef struct

{

        int data[Maxsize]; //存放栈中元素

        int top;// 栈顶指针

}SStack;

静态分配方式,大小固定不变;

顺序栈;栈顶指针类型与数据域类型相同。

//初始化

void InitStack(SStack *S){

        S.top=-1;

}

// 初始化2

void InitStack(SStack *S){

        S.top = 0;

}

由于data[i]

(0<=i<=Maxsize-1)

数据都是有效的所以这里初始化top为-1,

// 清空栈

bool ClearStack(SStack *S){

    S.top=-1;

        return true;

}

// 清空栈

bool ClearStack(SStack *S){

    S.top=0;

        return true;

}

如果top初始化为0,那么top指向的就是下一个可以插入的位置。也就是top[0]可入栈。

//进栈

bool Push(SStack *S,int x){

        if(S.top==Maxsize-1)

return false;// 栈满,报错

        S.data[++S.top] = x;

        return true;

}

bool Push(SStack *S,int x){

        // 栈满,报错

        if(S.top==Maxsize)

                 return false;

        S.data[S.top++]=x;

        return true;

}

// 出栈

bool Pop(SStack *S,int &x){

        if(S.top==-1) return false;// 栈空,报错

        x = S.data[S.top--];

        return true;

}

bool Pop(SStack *S,int &x){

        // 栈空报错

        if(S.top==0)

                 return false;

        x = S.data[--S.top];

        return true;

}

// 判断栈空

bool StackEmpty(SStack S){

        if(S.top==-1) return true;

        else

                 return false;

}

// 判断栈空

bool StackEmpty(SStack S){

        if(S.top==0) return true;

        else

                 return false;

}

共享栈:利用栈底位置相对不变的特性,可以让两个顺序栈共享一个数据空间,将两个栈的栈底分别设置在共享空间的两端,两个栈顶项共享空间的中间延伸。

栈满的标志是top0==top1-1;

2.4 链栈的定义及其特点

链栈:采用链式存储方式实现的栈。

链栈的优点是:便于多个栈共享存储空间和提高其效率,且不存在栈满溢出的情况。

链栈的内容与链表相似,但也都有带头结点,与不带头结点的区别,注意区别。

2.5 链式存储结构对栈基本操作的实现

暂略。

三、队列的定义和特点

队列:只允许在一端进行插入,而在另一端进行删除的线性表。

  1. 队尾(rear):允许插入的一端;
  2. 队头(front):允许删除的一端;
  3. 空队列:
  4. 原则(特点,先进先出):先进先出(First In First Out,FIFO)。

四、队列的逻辑结构以及基本操作

4.1 用抽象数据类型来定义队列的数据结构

4.2 顺序队列的定义及其特点

在队列的顺出存储结构中,除了用一组地址连续的存储单元一次存放从队头到队尾的元素外,还需要附设连个整形变量front和rear分别指示队头元素和队尾元素的位置(后面分别称为头指针和尾指针)。

4.3 顺序存储结构对队列基本操作的实现

声明队列类型:

静态数组形式

#define Maxsize 10

typedef struct{

        int data[Maxsize];

        int front;

        int rear;

}SQ;

初始化队列

void InitQ(SQ *Q){

        Q->front = 0;// 指向队头

        Q->rear = 0;// 队尾指向下一个要插入的位置(下一个应该插入的位置)

}

队列是否为空

bool Empty(SQ Q){

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

        else

                 return false;

}

入队

bool EnQueue(SQ *Q,int x){

        if((Q->rear+1)%Maxsize==Q.front)

                 return false;

        Q->data[Q.rear]=x;//插入队尾

        Q->rear=(Q->rear+1)%Maxsize;//队尾指针后移

        return true;

}

因为这里判断队列是否为满的方法是:当前队尾(下一个要插入的位置)的下一节点是否为队头,容易注意到这里Q->rear是下一个要插入的位置,然而如果我们直接用Q->rear%Maxsize==Q->front去判断是否为满,因为这个判断方式与判断队空是等价的,所以会产生冲突,所以就选择了牺牲循环队列队头的前一个元素的空间,(Q->rear+1)%Maxsize==Q.front,如果这个下一个要插入元素的下一个元素是队头,那么我们就不能入队,也就是下一个的下一个如果是队头,所以实际上最多只能存放9个有效数据。

由于队列的特性,可能即使队尾是Maxsize也是非空。

利用取余运算,模运算将无限的整数域映射到有限的整数集合上{0,1,2,...,b-1}上。

{0,1,2,..,Maxsize-1}将存储空间在逻辑上变成了“环状”。

如果Q->rear==9那么(Q->rear+1)%Maxsize==0

即使(Q->rear+1)%Maxsize==0,也不能说明是队满,因为队列的环状结构,让队头的位置可能已经不再是0下标的位置

所以下一个要插入的位置如果是队头Q.front,那么这就满了。

所以队列不像栈一样,将值设为-1,而是将Q.front直接指向第一个结点。再看左边是关键:为什么会浪费一个结点?

出队

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

从零开始的智障生活

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值