C/C++实现栈

​ 与前面的线性表相似,栈作为一种新的数据结构,也是用来保存数据的,同时栈可以使用顺序表和链表来进行实现。但是栈与线性表不同的是,栈是限定仅在表尾进行插入和删除操作的线性表

​ 栈是一种特殊的线性表,可以将它想象成一个薯片筒,只有一个开口。在栈中,将可以放入和拿出数据的一端称为栈顶,而另一端被称为栈底。由于栈依旧是线性表,所以栈中的元素也有前驱和后继的关系。

​ 根据上述对于栈特点的介绍,可以知道栈在线性表的基础上,限定了插入的位置和删除的位置,只能在栈顶进行插入和删除。先插入的数据被压在更接近栈底的位置,后插入的数据被压在更接近栈顶的位置。故可以知道先删除的元素是最后插入的元素,即“先压入,后弹出”或**“后进先出”**。
在这里插入图片描述

数组栈Stack

​ 接下来使用顺序表,也就是简单的一维数组来实现栈的功能。首先也是需要一个一维数组来表示栈的数据域,其次需要一个栈顶指针用于指向目前的栈顶。故数据结构如下所示。

#include <iostream>
#include <stdio.h>
#include <stack>
using namespace std;

#define MAX_SIZE 20 // 栈的最大容量
typedef int Element;    // 元素重定义

typedef struct Stack    // 数组栈
{
    Element data[MAX_SIZE]; // 数据域
    int top;    // 栈顶指针

    Stack()
    {
        for (int i = 0; i < MAX_SIZE; i++)  // 初始化数据域为0
            data[i] = 0;
        top = -1;    // 栈底初始化为-1
    }
}Stack;

​ 如上述代码所示,在构造函数中,将栈中所有元素初始化为0,并默认当前栈是一个空栈,即 t o p = − 1 top=-1 top=1。栈的各种情况以及对应的栈顶指针的情况如下所示。
在这里插入图片描述

压入push

​ 之后对于栈中的压入操作,也就是线性表中的插入操作。由于栈的特殊性,只能从栈顶进行插入,而栈顶永远指向最后一个压入的元素,所以在压入元素的时候,需要先将栈顶指针进行移动,指向一个空的区域,之后再将新元素放入即可。
在这里插入图片描述

​ 代码实现就很简单,如下所示。

// 压入元素
bool Push(Stack* s, Element element)
{
    if (s->top + 1 < MAX_SIZE)  // 栈未满则加入
    {
        s->top++;   // 移动栈指针
        s->data[s->top] = element;  // 加入新元素
        return true;
    }
    return false;   // 栈满
}

弹出pop

​ 对于栈中的弹出操作pop,其实就是线性表中的删除,但是同样由于栈的特殊性,只能从栈顶弹出。同时考虑到这是一个数组栈,不能释放空间,故只能以移动栈指针的方法来实现元素的删除,根据前面的分析,栈指针减一即可。

// 弹出元素
bool Pop(Stack* s)
{
    if (s->top >= 0)    // 栈不空才可弹出元素
    {
        s->top--;   // 栈顶指针下移即可
        return true;
    }
    return false;   // 栈空
}

获取栈顶元素top

​ 由于栈的特殊性,每次也就只能获取栈顶元素的值,而不能获取中间元素的值,如果想获取中间元素的值,需要先将上面的元素移开,将想观察的元素移动到栈顶即可。

// 获取栈顶元素
Element Top(Stack* s)
{
    if (s->top >= 0)    // 要确保里面有元素
        return s->data[s->top];
    return -1;
}

判断是否为空isEmpty

​ 在之后的一些操作中,例如使用栈来实现递归操作,需要判断栈是否为空,因为栈空时是不能继续访问栈顶元素的,这里也是使用栈指针来进行判断。

// 判断栈是否为空
bool isEmpty(Stack *s)
{
    return s->top == -1;
}

返回栈的元素个数size

​ 接下来补充一个功能,也就是获取栈中已经压入的元素的个数,根据前面的图解结合栈指针即可简单计算得到。

// 获取栈的容量
int Size(Stack* s)
{
    return s->top + 1;
}

链表栈LinkStack

​ 链表栈就是以链表作为数据域的数据存放方式,来实现栈的基础功能。在前面对于栈的功能有了一个简单的理解之后,可以得知在使用链表时,是可以不需要头结点的,只需要使用一个头指针即可,同时也可以使用该头指针来代替整个栈的栈顶指针。

​ 而根据栈“先进后出”的特点,可以使用链表中的头插法,每次都从头指针位置处进行插入,删除时也是只需要删除头指针指向的结点即可。
在这里插入图片描述

压入push

​ 压入部分参考链表中的头插法即可。

// 压入元素push
bool LinkPush(LinkStack* s, Element element)
{
    if (s->size + 1 == MAX_SIZE)    // 栈满
        return false;   // 报错
    StackNode* p = new StackNode(); // 创建新节点
    p->data = element;  // 赋值
    p->next = s->top;     // 头插法
    s->top = p; // 更新头结点
    
    s->size++;  // 节点数加一
    return true;
}

弹出pop

​ 删除部分参考链表的删除即可。

// 弹出元素pop
bool LinkPop(LinkStack* s)
{
    if (s->size == 0)   // 判断是否为空
        return false;   // 空栈不能弹出元素
    StackNode* p = s->top;  // 栈顶结点
    s->top = s->top->next;  // 更新栈顶指针
    delete(p);  // 删除结点
    s->size--;
    return true;
}
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值