C语言seqstack如何实现栈的基本操作?

99ANYc3cd6
预计阅读时长 18 分钟
位置: 首页 C语言 正文

顺序栈是数据结构中“栈”的一种具体实现方式,我们将从以下几个方面来理解它:

c语言seqstack
(图片来源网络,侵删)
  1. 什么是栈?
  2. 什么是顺序栈?
  3. 顺序栈的 C 语言实现(完整代码)
  4. 核心操作的时间复杂度分析
  5. 顺序栈的优缺点
  6. 一个更完整的实践示例

什么是栈?

栈是一种后进先出的线性数据结构,你可以把它想象成一个只有一个开口的箱子或者一摞盘子。

  • LIFO (Last-In, First-Out):最后放进去的元素,最先被取出来。
  • 基本操作
    • push (入栈/压栈):将一个新元素放到栈顶。
    • pop (出栈/弹栈):从栈顶取出一个元素。
    • peek (查看栈顶元素):只看栈顶的元素是什么,但不把它取出来。
    • isEmpty (判空):检查栈是否为空。
    • isFull (判满):检查栈是否已满(对于固定大小的栈很重要)。

什么是顺序栈?

顺序栈是使用数组作为底层存储结构来实现栈,它通过一个数组来存放栈中的所有元素,并用一个变量(通常是 top)来记录当前栈顶元素的位置。

  • 核心思想:利用数组的连续存储空间和下标访问的便利性。
  • 关键变量
    • data[]: 存储元素的数组。
    • top: 栈顶指针,它通常指向栈顶元素所在位置的下一个空位,或者指向栈顶元素本身,我们这里采用更常见的“指向下一个空位”的方式,这样 top 的初始值就是 0,表示栈为空时,第一个元素可以放在 data[0]

顺序栈的 C 语言实现(完整代码)

下面是一个完整的、包含注释的顺序栈实现。

1 定义顺序栈的结构体

我们定义一个结构体来封装栈的所有信息:数组、最大容量和栈顶指针。

c语言seqstack
(图片来源网络,侵删)
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h> // 为了使用 bool 类型
// 定义栈中元素的最大容量
#define MAX_SIZE 100
// 定义顺序栈的结构体
typedef struct {
    int data[MAX_SIZE]; // 存储元素的数组
    int top;            // 栈顶指针,指向栈顶元素的下一个位置
} SeqStack;

2 核心操作的函数实现

我们为这个栈结构实现各种基本操作。

2.1 初始化栈

创建一个空栈,只需将 top 指针设置为 0 即可。

// 初始化栈
void initStack(SeqStack *s) {
    s->top = 0; // top 指向数组第一个位置,表示栈为空
}

2.2 判断栈是否为空

top 为 0,说明没有任何元素被压入,栈为空。

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

2.3 判断栈是否已满

top 等于 MAX_SIZE,说明数组已经全部用完,栈已满。

c语言seqstack
(图片来源网络,侵删)
// 判断栈是否已满
bool isFull(SeqStack *s) {
    return s->top == MAX_SIZE;
}

2.4 入栈操作

将一个元素压入栈顶,需要先检查栈是否已满。

// 入栈操作
bool push(SeqStack *s, int value) {
    if (isFull(s)) {
        printf("栈已满,无法入栈!\n");
        return false; // 入栈失败
    }
    s->data[s->top] = value; // 将元素存入 top 指向的位置
    s->top++;               // top 指针向上移动,指向下一个空位
    return true;             // 入栈成功
}

2.5 出栈操作

从栈顶弹出一个元素,需要先检查栈是否为空。

// 出栈操作
bool pop(SeqStack *s, int *value) {
    if (isEmpty(s)) {
        printf("栈为空,无法出栈!\n");
        return false; // 出栈失败
    }
    s->top--;               // top 指针先向下移动,指向栈顶元素
    *value = s->data[s->top]; // 获取栈顶元素的值
    return true;             // 出栈成功
}

2.6 查看栈顶元素

与出栈类似,只是不移动 top 指针。

// 查看栈顶元素
bool peek(SeqStack *s, int *value) {
    if (isEmpty(s)) {
        printf("栈为空,无栈顶元素!\n");
        return false;
    }
    // top 指向下一个空位,所以栈顶元素在 top-1 的位置
    *value = s->data[s->top - 1];
    return true;
}

2.7 打印栈中所有元素

这个操作在标准的栈定义中不是必须的,但为了方便调试和演示,我们通常会实现它。

// 打印栈中所有元素(从栈底到栈顶)
void printStack(SeqStack *s) {
    if (isEmpty(s)) {
        printf("栈为空,\n");
        return;
    }
    printf("栈内元素 (从栈底到栈顶): ");
    for (int i = 0; i < s->top; i++) {
        printf("%d ", s->data[i]);
    }
    printf("\n");
}

核心操作的时间复杂度分析

  • initStack: O(1) - 只是一个简单的赋值操作。
  • isEmpty, isFull: O(1) - 只是比较一个整数值。
  • push, pop, peek: O(1) - 这些操作都只涉及对 top 指针和数组的单个元素访问,不涉及循环或遍历。

顺序栈的所有基本操作都是常数时间,效率非常高。


顺序栈的优缺点

优点

  1. 实现简单:基于数组,逻辑直观,代码容易编写和理解。
  2. 效率高:所有核心操作的时间复杂度都是 O(1)。
  3. 内存访问连续:数组在内存中是连续存储,CPU 缓存命中率较高,访问速度比链式实现的栈(基于链表)可能更快。

缺点

  1. 大小固定:数组的大小在编译时或初始化时就已经确定(MAX_SIZE),如果元素数量超过这个限制,就会发生栈溢出
  2. 空间浪费:如果栈中元素很少,但 MAX_SIZE 设置得很大,就会浪费内存空间,反之,如果设置得太小,又不够用。

一个更完整的实践示例

下面是一个 main 函数,演示如何使用上面定义的顺序栈。

int main() {
    SeqStack myStack;
    int value;
    // 1. 初始化
    initStack(&myStack);
    printf("栈已初始化,\n");
    // 2. 入栈操作
    printf("\n--- 入栈操作 ---\n");
    push(&myStack, 10);
    push(&myStack, 20);
    push(&myStack, 30);
    printStack(&myStack); // 预期输出: 10 20 30
    // 3. 查看栈顶元素
    printf("\n--- 查看栈顶元素 ---\n");
    if (peek(&myStack, &value)) {
        printf("栈顶元素是: %d\n", value); // 预期输出: 30
    }
    // 4. 出栈操作
    printf("\n--- 出栈操作 ---\n");
    if (pop(&myStack, &value)) {
        printf("出栈元素: %d\n", value); // 预期输出: 30
    }
    if (pop(&myStack, &value)) {
        printf("出栈元素: %d\n", value); // 预期输出: 20
    }
    printStack(&myStack); // 预期输出: 10
    // 5. 再次出栈
    printf("\n--- 继续出栈 ---\n");
    if (pop(&myStack, &value)) {
        printf("出栈元素: %d\n", value); // 预期输出: 10
    }
    printStack(&myStack); // 预期输出: 栈为空。
    // 6. 尝试从空栈出栈
    printf("\n--- 尝试从空栈出栈 ---\n");
    pop(&myStack, &value); // 应该打印 "栈为空,无法出栈!"
    // 7. 测试栈满
    printf("\n--- 测试栈满 ---\n");
    for (int i = 0; i < MAX_SIZE; i++) {
        push(&myStack, i + 1);
    }
    printStack(&myStack); // 预期输出 1 到 100
    push(&myStack, 101);  // 应该打印 "栈已满,无法入栈!"
    return 0;
}

顺序栈是学习栈和数组这两个基础概念的一个绝佳结合,它通过一个简单的结构体和几个核心函数,高效地实现了“后进先出”的逻辑,虽然它有大小固定的局限性,但在许多场景下(如表达式求值、函数调用栈、括号匹配等)都非常实用,如果需要动态大小的栈,可以考虑使用链式栈

-- 展开阅读全文 --
头像
dede软件发布不了怎么办?
« 上一篇 04-22
织梦友情链接不显示,问题出在哪?
下一篇 » 04-22

相关文章

取消
微信二维码
支付宝二维码

目录[+]