栈(stack)--c语言实现版

目录

1.栈的基本操作

2.栈的实现

2.1基于数组

2.2基于链表


栈是一种数据结构,像一个倒立的容器。想象一下,把物品一个个放进去,但每次只能从最上面取出物品。也就是说,最后放进去的物品会最先被取出来,这种顺序叫做后进先出(LIFO)。在栈中,有两个主要操作:

1.栈的基本操作

**入栈(Push):**将元素压入栈顶。

出栈(Pop):从栈顶移除元素。

查看栈顶(Peek 或 Top):获取栈顶元素,但不移除它。

检查栈是否为空(IsEmpty):判断栈中是否还有元素

2.栈的实现

栈可以通过以下两种方式实现:

2.1基于数组

用固定大小的数组,直接通过索引操作栈顶元素,但需要手动管理栈的大小。

objectivec 复制代码
#include <stdio.h>
#include <stdlib.h>

#define MAX_SIZE 100  // 定义栈的最大容量

// 栈结构体
typedef struct {
    int data[MAX_SIZE];  // 存储栈元素的数组
    int top;              // 栈顶指针,指向栈顶元素
} Stack;

// 初始化栈
void initStack(Stack *s) {
    s->top = -1;  // 栈为空时,栈顶指针为-1
}

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

// 判断栈是否满
int isFull(Stack *s) {
    return s->top == MAX_SIZE - 1;
}

// 入栈操作
void push(Stack *s, int value) {
    if (isFull(s)) {
        printf("Stack Overflow!\n");
        return;
    }
    s->data[++(s->top)] = value;  // 将值放入栈顶并更新栈顶指针
}

// 出栈操作
int pop(Stack *s) {
    if (isEmpty(s)) {
        printf("Stack Underflow!\n");
        return -1;  // 返回一个表示错误的值
    }
    return s->data[(s->top)--];  // 返回栈顶元素并更新栈顶指针
}

// 查看栈顶元素
int peek(Stack *s) {
    if (isEmpty(s)) {
        printf("Stack is empty!\n");
        return -1;  // 返回一个表示错误的值
    }
    return s->data[s->top];
}

// 打印栈的内容
void printStack(Stack *s) {
    if (isEmpty(s)) {
        printf("Stack is empty!\n");
        return;
    }
    for (int i = 0; i <= s->top; i++) {
        printf("%d ", s->data[i]);
    }
    printf("\n");
}

int main() {
    Stack s;
    initStack(&s);  // 初始化栈

    push(&s, 10);
    push(&s, 20);
    push(&s, 30);

    printf("Stack after pushing 10, 20, 30: ");
    printStack(&s);

    printf("Popped element: %d\n", pop(&s));
    printf("Stack after pop: ");
    printStack(&s);

    printf("Top element: %d\n", peek(&s));

    return 0;
}

注意事项:

  • ++(s->top) 确保栈顶指针在插入之前递增。
  • (s->top)++ 先插入元素,再递增栈顶指针。

栈为空的条件不再是 top == -1,而是 top == 0。如果栈初始化为 0,那么后续遍历的范围也应该变化。

2.2基于链表

动态分配内存,插入和删除操作更灵活,基于链表实现栈的方式相比基于数组的实现,具有更好的灵活性,因为链表不需要事先定义大小,内存分配是动态的。链表实现的栈可以随时扩展或收缩,插入和删除元素的时间复杂度均为 O(1),非常高效。

objectivec 复制代码
#include <stdio.h>
#include <stdlib.h>

// 栈的节点结构体
typedef struct Node {
    int data;           // 存储栈的值
    struct Node *next;  // 指向下一个节点
} Node;

// 栈的结构体
typedef struct {
    Node *top;  // 栈顶指针,指向栈顶元素
} Stack;

// 初始化栈
void initStack(Stack *s) {
    s->top = NULL;  // 初始化时,栈为空
}

// 判断栈是否为空
int isEmpty(Stack *s) {
    return s->top == NULL;  // 栈顶指针为NULL时栈为空
}

// 入栈操作
void push(Stack *s, int value) {
    // 创建一个新的节点
    Node *newNode = (Node *)malloc(sizeof(Node));
    if (newNode == NULL) {
        printf("Memory allocation failed!\n");
        return;
    }
    newNode->data = value;
    newNode->next = s->top;  // 新节点指向当前栈顶
    s->top = newNode;        // 更新栈顶指针
}

// 出栈操作
int pop(Stack *s) {
    if (isEmpty(s)) {
        printf("Stack Underflow!\n");
        return -1;  // 返回一个表示错误的值
    }
    Node *temp = s->top;      // 保存栈顶节点
    int value = temp->data;   // 获取栈顶值
    s->top = s->top->next;    // 更新栈顶指针
    free(temp);               // 释放栈顶节点的内存
    return value;             // 返回栈顶元素
}

// 查看栈顶元素
int peek(Stack *s) {
    if (isEmpty(s)) {
        printf("Stack is empty!\n");
        return -1;  // 返回一个表示错误的值
    }
    return s->top->data;  // 返回栈顶元素
}

// 打印栈的内容
void printStack(Stack *s) {
    if (isEmpty(s)) {
        printf("Stack is empty!\n");
        return;
    }
    Node *current = s->top;
    while (current != NULL) {
        printf("%d ", current->data);
        current = current->next;
    }
    printf("\n");
}

// 主函数
int main() {
    Stack s;
    initStack(&s);  // 初始化栈

    push(&s, 10);
    push(&s, 20);
    push(&s, 30);

    printf("Stack after pushing 10, 20, 30: ");
    printStack(&s);

    printf("Popped element: %d\n", pop(&s));
    printf("Stack after pop: ");
    printStack(&s);

    printf("Top element: %d\n", peek(&s));

    return 0;
}

节点结构体 :Node 结构体包含一个 data 字段用于存储栈的元素,以及一个 next 指针指向下一个节点。链表结构就是通过这些节点组成的。

栈结构体 :Stack 结构体只有一个成员 top,它是一个指向栈顶节点的指针。

初始化栈 :initStack 函数将栈顶指针 top 初始化为 NULL,表示栈为空。

判断栈是否为空 :isEmpty 函数检查栈顶指针是否为 NULL 来判断栈是否为空。

入栈操作 :push 函数首先为新元素分配内存,然后将它插入到链表的头部。新节点的 next 指向当前的栈顶元素,然后更新栈顶指针。

出栈操作 :pop 函数删除栈顶节点,更新栈顶指针,并返回被删除节点的数据。释放栈顶节点的内存。

查看栈顶元素 :peek 函数返回栈顶元素的值,但不删除该元素。

打印栈内容 :printStack 函数遍历链表并打印栈中的所有元素。

相关推荐
夏幻灵4 小时前
JavaScript this 面试:五种绑定规则、优先级与常见面试陷阱
开发语言·javascript·面试
程序猿编码4 小时前
榨干 RTX5090 算力!Qwen3 专用单卡推理引擎,手写C++/CUDA 算子实现 MTP 推测解码
开发语言·c++·大模型推理·qwen3·多模态推理
bkspiderx6 小时前
Qt 插件机制:动态扩展应用功能的核心框架
开发语言·qt·元数据·qt 插件·qpluginloader
程序员老陆6 小时前
深入理解 C++ thread_local:线程私有存储的正确打开方式
开发语言·c++·程序设计
沐晓时光6 小时前
C语言入门,深入理解指针(3)
c语言·开发语言
信奥卷王6 小时前
[GESP202609 六级] 分树规划
算法
夏幻灵6 小时前
LeetCode 21:合并两个有序链表——双指针与哑节点详解
算法·leetcode·链表
码云数智-园园7 小时前
unique_ptr 还是 shared_ptr?C++ 智能指针选型与内存泄漏实战分析
java·开发语言
禾小西7 小时前
07丨Redis 哨兵机制:主库故障后,如何恢复服务?
java·开发语言·redis