数据结构与算法-栈和队列-顺序栈(Sequence Stack)

2 栈和队列(Stack and Queue)

栈 (stack) 是限定仅在表尾进行插入或删除操作的线性表。栈来说,表尾端有其特殊含义,称为栈顶 (top),相应地表头端称为栈底 (bottom)。不含元素的空表称为空栈
在这里插入图片描述
和栈相反,队列(queue)是一种先进先出(First I n First Out, FIFO)的线性表。它只允许在表的一端进行插入,而在另一端删除元素。

在这里插入图片描述
和线性表类似,也有两种存储表示方法,分别称为顺序栈链栈队列也有两种存储表示,顺序表示和链式表示。下面逐一用代码进行实现。

2.1 顺序栈(Sequence Stack)

书中顺序栈的基本操作有4个:初始化、入栈、出栈、获取栈顶元素,视频在此基础上增加了4个:销毁栈、判断栈是否为空、获取栈的大小、清空栈操作。我这里把8个都实现了。

同前面一样,有一些基础代码:

// 声明一些常量
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define TRUE 1
#define FALSE 0

// Status 是函数返回值类型, 其值是函数结果状态代码。
typedef int Status;
// Boolean 定义布尔型,值就是 TRUE 和 FALSE。
typedef int Boolean;

栈元素结构和栈结构:

#define MAXSIZE 100 // 顺序栈存储空间的初始分配量

// 栈元素类型定义
typedef struct
{
    int data; // 栈元素的数据
} SElemType;

// 顺序栈的结构体定义
typedef struct
{
    SElemType *top;
    SElemType *base; // 栈顶指针和栈底指针
    int stackSize;   // 栈的当前大小
} SqStack;

在编写代码过程中,经常需要查看栈内的内容,因此需要一个方法可以遍历栈,并打印其中的内容:

// 遍历栈
void TraverseStack(SqStack S)
{
    SElemType *p = S.base;
    while (p < S.top)
    {
        printf("%d ", p->data);
        p++;
    }
    printf("\n");
}

2.1.1 初始化

顺序栈的初始化操作就是为顺序栈动态分配一个预定义大小的数组空间。

【算法步骤】

  1. 为顺序栈动态分配一个最大容量为 MAXSIZE 的数组空间,使 base 指向这段空间的基地址,即栈底。
  2. 栈顶指针 top 初始为 base,表示栈为空。
  3. stacksize 置为栈的最大容量 MAXSIZE。

【代码实现】

// 初始化栈
Status InitStack(SqStack *S)
{
    S->base = (SElemType *)malloc(MAXSIZE * sizeof(SElemType));
    if (!S->base) // 分配失败
        return OVERFLOW;
    S->top = S->base;       // 栈顶指针指向栈底
    S->stackSize = MAXSIZE; // 初始化栈大小
    return OK;
}

【算法分析】

需要提前分配一个 MAXSIZE 大小的空间。

2.1.2 入栈

入栈操作是指在栈顶插入一个新的元素。

【算法步骤】

  1. 判断栈是否满,若满则返回 ERROR。
  2. 将新元素压人栈顶,栈顶指针加1。

【代码实现】

// 入栈
Status Push(SqStack *S, SElemType e)
{
    if (S->top - S->base >= S->stackSize) // 栈满
        return ERROR;
    *(S->top) = e; // 将元素压入栈顶
    S->top++;      // 栈顶指针上移
    return OK;
}

2.1.3 出栈

出栈操作是将栈顶元素删除。

【算法步骤】

  1. 判断栈是否空, 若空则返回ERROR。
  2. 栈顶指针减1, 栈顶元素出栈。

【代码实现】

// 出栈
Status Pop(SqStack *S, SElemType *e)
{
    if (S->top == S->base) // 栈空
        return ERROR;
    S->top--;             // 栈顶指针下移
    *e = *(S->top);       // 将栈顶元素赋值给 e
    return OK;
}

2.1.4 获取栈顶元素

当栈非空时, 此操作返回当前栈顶元素的值, 栈顶指针保待不变。

【算法步骤】

  1. 判断栈是否空, 若空则返回ERROR。
  2. 栈顶指针减1, 栈顶元素出栈。

【代码实现】

// 获取栈顶元素
Status GetTop(SqStack S, SElemType *e)
{
    if (S.top == S.base) // 栈空
        return ERROR;
    *e = *(S.top - 1); // 获取栈顶元素
    return OK;
}

2.1.5 销毁栈

销毁栈就是将整个栈从内存中移除。清空栈只是移除栈内的元素,但是top和base指针都还在。

【算法步骤】

  1. 检测栈是否已经分配了空间(base指针有值)。
  2. 释放已分配的空间。
  3. 将 base 和 top 指针置为 NULL。

【代码实现】

// 销毁栈
Status DestroyStack(SqStack *S)
{
    if (S->base) // 如果栈底指针不为空
    {
        // 因为栈元素并没有动态分配的内存,
        // 所以这里不需要遍历栈元素进行释放,我们只需要释放栈底指针所指向的内存。
        free(S->base); // 释放栈底指针所指向的内存
        S->base = NULL; // 将栈底指针置为 NULL
        S->top = NULL;  // 将栈顶指针置为 NULL
        S->stackSize = 0; // 栈大小置为 0
    }
    return OK;
}

2.1.6 判断栈是否为空

// 判断栈是否为空
Boolean IsEmpty(SqStack S)
{
    return S.top == S.base; // 如果栈顶指针等于栈底指针,则栈为空
}

2.1.7 获取栈的大小

// 获取栈的大小
int StackSize(SqStack S)
{
    return S.top - S.base; // 栈的大小等于栈顶指针和栈底指针的差值
}

2.1.8 清空栈操作

// 清空栈
Status ClearStack(SqStack *S)
{
    if (S->base) // 如果栈底指针不为空
    {
        S->top = S->base; // 将栈顶指针重置为栈底指针
        return OK;
    }
    return ERROR; // 栈已经为空
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

晴空闲雲

感谢家人们的投喂

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

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

打赏作者

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

抵扣说明:

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

余额充值