03笔记 数据结构——栈和队列—— 基于《数据结构》(C语言版) 第2版 (严蔚敏等)和《数据结构教程》蔡子经,施伯乐

1.1 栈和基本运算

栈:只允许在一端进行插入和删除的线性表
栈顶:允许插入和删除的一端
栈底:不允许……

s_0是栈底节点,s_{n-1}是栈顶结构
特性:先进后出(后进先出)LIFO(Last In First Out)

栈顶指针:一般用一个指针top来指向数组存放的位置。

栈的实现

#include<iostream>
using namespace std;
typedef int data;
const int MAXN = 1000;

struct static_stack
{
    data ptr[MAXN];
    int num = 0;

    int push(data a)
    {
        if(num == MAXN)
        {
            return 0;//满
        }
        
        ptr[num++] = a;
        return 1;
    }

    int pop()
    {
        if(num == 0)
        return 0;

        num--;
        return 1;
    }
};

struct stack
{
    data* ptr;
    int num;
    int cap;

    stack(int n = 100)
    {
        ptr = new data[n];
        for(int i = 0; i < n; i++)
            ptr[i] = 0;
        cap = n;
        num = 0;
    }

    int resize(int n)
    {
        data*temp = new data[n];
        int times;
        if(n <= cap) times = n;
        else times = cap;

        for(int i = 0; i < times; i++)
        {
            temp[i] = ptr[i];
        }
        delete[] ptr;

        ptr = temp;
    }

    int push(data a)
    {
        if(num == MAXN)
        {
            return 0;//满
        }
        
        ptr[num++] = a;
        return 1;
    }

    int pop()
    {
        if(num == 0)
        return 0;

        num--;
        return 1;
    }
};


1.2 队列和基本运算

队列:只允许在一端插入,在另一端删除的线性表
队首:允许删除的一端
队尾:允许插入的一端
入队:队列的插入
出队:队列的删除

先进先出表 FIFO(Fisrt In First Out)

不难发现这个十分类似于栈实现

#include<iostream>
using namespace std;
typedef int data;

const int MAXN = 1000;

struct queue
{
    data ptr[MAXN];
    int head;
    int tail;

    queue()
    {
        for(int i = 0; i < MAXN; i++)
            ptr[i] = 0;
        head = -1;
        tail = -1;
    }

    int en_queue(data a)
    {
        if(tail == MAXN -1)
            return 0;

        ptr[tail++] = a;
        return 1;
    }

    int de_queue()
    {
        if(head == tail)
            return 0;
        
        head++;
        return 1;
    }

};

1.3 环形队列

但是我们在使用这种队列的时候会有一些惊讶的发现:当尾部入列满,且头部也有一部分出列的时候(也就是数组还有空位的时候),我们无法再插入新的元素,就会造成空间上的浪费

于是我们可以使用环形队列:
尾部插满的时候,继续循环插入头部,如何实现呢?利用%运算

但是出现一个新的问题,当tail == head的时候,到底是队满还是队空呢?
有两种解决方法
第一种是增加一个标识符flag来判断,倘若是入队之后tail == head就有flag = 1,反之为0,但是这种处理方法就会导致程序增加多一个判断操作和数据操作
第二种的话我们可以让tail和head在插入的时候“永远不相等”,先让tail++,若tail == head,说明栈满,再tail–,而当tail == head 的时候只能是队空,保证了一一对应(通过减少一个空间的储存来避免这种判断操作)

int cir_enqueue(data d)
    {
        tail = (tail + 1) % MAXN;
        if(tail == head)
        {
            if(tail)
                tail--;
            else 
                tail = MAXN - 1;
            
            return 0;//插入错误
        }

        ptr[tail] = d;
        return 1;
    }
    int cir_dequeue()
    {
        if(head == tail)
            return 0;//栈空
        
        head = (head + 1) % MAXN;
        return 1;
    }

1.4 双向队列

便是让两端都可以进行插入或删除
可以产生许多变体:俩端可插入但只在一端删除……环形双线队列

1.5 栈的应用

课后作业

在这里插入图片描述
就是普通的栈考虑上尾端,然后特殊判断一下用栈1还是栈2

#include<iostream>
using namespace std;

typedef int data;

struct shared_stack
{
    data* head;
    int cap;
    int head_num;
    int end_num;

    shared_stack(int n)
    {
        head = new data[n];
        cap = n;
        end_num = 0;
        head_num = 0;
    }

    int push(data d, int index)
    {
        if(end_num + head_num == cap)
        return 0; //满

        switch (index)
        {
        case 1:
            head[head_num++] = d;
            break;
        
        default:
            head[cap - end_num - 1] = d;
            end_num++;
            break;
        }

        return 1;
    }

    int pop(int index)
    {
        if(1 == index)
        {
            if(head_num <= 0)
                return 0;
            head_num--;
        }
        else
        {
            if(end_num <= 0)
                return 0;
            end_num--;
        }

        return 1;

    }

};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值