栈和队列的操作和应用

本节内容

1.栈和队列的特性

 栈:进先出

•栈:受限制的线性表,只允许从表的一端操作。这端称为栈顶,另一端为

•压入元素(push):往栈顶新增一个元素,新元素成为新栈顶。

•弹出元素(pop):移除栈顶元素,原栈顶的元素成为新栈顶/或栈变成空栈

•图片表示进出栈结果:

 *key1:栈是一种先进后出的数据结构,pop和push操作仅在栈顶进行

 队列:进先出

•队列:受限制的线性表,只允许从表的两端操作,一端是队首,一端是队尾。

•入队(enqueue):往队尾新增一个元素,新元素成为新队尾

•出队(dequeue):移出队首元素,下一个元素成为新队首/或队列变为空

•图文演示过程:

 2.栈和递归

 •栈后进先出的特点天然地和程序中函数调用关系相吻合

•程序执行时,在函数A中执行到调用另一个函数B的语句时,会发生什么?

        立刻进入被调函数B执行其代码,完成后返回到A的下一行继续执行A的剩余代码

•因此在操作系统执行代码时,函数间的调用-返回关系正是通过调用栈来维护

•函数的递归调用本质也是一个栈型调用,因此可以利用栈将一个递归函数改写为完全等价的非递归函数,避免了操作系统层面的调用栈开销。

 3.栈和队列的应用

栈的应用:括号匹配

•目的:判断一个字符串你中括号是否——匹配

•为什么可以用栈来解决这个问题?

•当遇到左括号时,我希望能立刻遇到它的另一半,但如果接着又遇到了一个左括号,那它的需求比我更紧迫,我需要处理来的这个左括号

•后来的需要先满足->后进先出问题->用栈解决

栈的应用

•表达式求值,如1+2*3

•进制转换

•非递归的深度优先遍历(DFS)

队列的应用:循环队列(循环队列基于顺序序列)

•你会怎样实现一个顺序序列?

'假溢出'现象:底层顺序表前部的可用空间无法再利用上了

•解决方法:循环队列

 4.代码实现

顺序栈实现

•顺序栈的底层是一个数组,低地址为栈底,高地址为栈顶,只能在栈顶操作

/*(顺序)栈*/
//栈数据结构定义
#define MAX_SIZE 10
typedef struct{
    Student *data;
    int size;
}Stack;
//往栈顶压入一个元素
bool Push(Stack &stk,const Student &s){
    if (stk.size==MAX_SIZE){
        return false;
}
int newTop=stk.size;
stk.data[newTop]=s;
stk.size++;
return true;
}
//弹出栈顶元素
bool Pop(Stack &stk){
    if(stk.size==0){
        return false;}
stk.size--;
return true;
}

*key1:顺序栈的底层是一个数组空间,并通过维护当前栈大小实现栈

*key2:顺序栈的当前栈顶元素下标和栈大小是top=size-1的关系

1.设Stack是顺序栈的一种实现,在(a)处应填入的代码为:___________.(stk.size--)

struct Stack{

        Elem data[MAX_SIZE];

        int size=0;

};

bool Pop(Stack &s){

        if (stk.size==0)return false;

        ___(a)____;

        return true;

}

循环队列实现

•循环队列的底层是一个数组,通过维护队头和队尾在此数组中的下标来实现

/*循环队列*/
//循环队列数据结构
#define M 10
typedef struct{
    Student data[M];
    int front;
    int back;//bcak表示队尾的下一个空位
}CQueue;//c=Circulative
//求循环队列元素个数
int GetSize(CQueue &queue){
    int size=(queue.back-queue.front+M)%M;
    return size;
}

*key1:循环队列的容量是MAX_SIZE-1

*key2:循环队列当前元素数量计算

1.假设一循环队列的底层数组为array[M],我们约定f表示为当前队首元素,b为当前队尾元素的后

一个元素,则当前队列内元素个数为()

A.b-f                B.(b-f+M)%M

C.b-f+M           D.(f-b+M)%M

分析:做循环队列题一定要把底层数组画出来模拟!

第一种情况:

 第二种情况:

 M=8,蓝色表示队列元素。

分析:对于第一种情况直接=b-f,第二种情况等于b-f+M

统一一下答案:由于b-f>0,所以加上M再对M取余正好消去M。第二个由于b-f<0,b-f+M<M

所以对M取余不起作用。总结答案选择为B选项

循环队列实现

•循环队列的底层是一个数组,通过维护队头和队尾在此数组中的下标来实现

//循环队列入列
bool Enqueue_CQ(CQueue &queue,const Student &s){
    int newBack=(queue.back+1)%M;
    if(newBack==queue.front){
        return false;//头尾相接表示队列满了}
    queue.data[queue.back]=s;//放入队尾
    queue.back=newBack;
    return true;
}
//循环队列出列
bool Dequeue_CQ(CQueue &queue){
    if (queue.front==queue.back){
        return false;//头尾重合表示队列为空
}   queue.front=(queue.front+1)%M;
    return true;
    
    }

*key3:循环队列判满条件为(back+1)%MAX_SIZE==front ''首尾相接''

*key4:循环队列判空条件为back==front                                     ''首尾重合''

1.(a)处应填入的代码为:______________.(queue.front ==queue.back)

bool Dequeue_CQ(CQueue &queue){

        if (___(a)____)

                return false;//头尾重合表示队列为空

}queue.front=(queue.front +1)%queue.capacity;

return true;                

}

练习:

 

 

 

完整代码: 

/*
Ch3 栈和队列
*/
// 实例数据元素:学生
typedef struct {
    char id[10];
    int age;
    double score;
} Student;
/* (顺序)栈 */
// 栈数据结构定义
#define MAX_SIZE 10
typedef struct {
    Student *data;
    int size;
} Stack;
// 初始化栈
Stack Create() {
    Stack stk;
    stk.data = new Student[MAX_SIZE];
    stk.size = 0;
    return stk;
}
// 获取栈顶元素
bool Top(Stack &stk, Student &res) {
    if (stk.size == 0) {
        return false;
    }
    int top = stk.size - 1;
    res = stk.data[top];
    return true;
}
// 弹出栈顶元素
bool Pop(Stack &stk) {
    if (stk.size == 0) {
        return false;
    }
    stk.size--;
    return true;
}
// 往栈顶压入一个元素
bool Push(Stack &stk, const Student &s) {
    if (stk.size == MAX_SIZE) {
        return false;
    }
    int newTop = stk.size;
    stk.data[newTop] = s;
    stk.size++;
    return true;
}
/* 栈的应用:括号匹配 */
#include <stack>
#include <string>
bool IsParenthesesMatch(std::string s) {
    std::stack<char> stk;
    for (int i = 0; i < s.length(); ++i) {
        switch (s[i]) {
        case '(':
        case '[':
        case '{':
            stk.push(s[i]);
            break;
        case ')':
            if (stk.empty() || stk.top() != '(') {
                return false;
            }
            stk.pop();
            break;
        case ']':
            if (stk.empty() || stk.top() != '[') {
                return false;
            }
            stk.pop();
            break;
        case '}':
            if (stk.empty() || stk.top() != '}') {
                return false;
            }
            stk.pop();
            break;
        }
    }
    return stk.empty();
}
/* 循环队列 */
// 循环队列数据结构
#define M 10
typedef struct {
    Student data[M];
    int front;
    int back;  // back表示队尾的下一个空位
} CQueue;      // C = Circulative
// 循环队列入队
bool Enqueue_CQ(CQueue &queue, const Student &s) {
    int newBack = (queue.back + 1) % M;
    if (newBack == queue.front) {
        return false;  // 头尾相接表示队列满了
    }
    queue.data[queue.back] = s;  // 放入队尾
    queue.back = newBack;        // 移动back
    return true;
}
// 循环队列出队
bool Dequeue_CQ(CQueue &queue) {
    if (queue.front == queue.back) {
        return false;  // 头尾重合表示队列为空
    }
    queue.front = (queue.front + 1) % M;
    return true;
}
// 求循环队列元素个数
int GetSize(CQueue &queue) {
    int size = (queue.back - queue.front + M) % M;
    return size;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

阳光少年.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值