栈(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 函数遍历链表并打印栈中的所有元素。

相关推荐
lly2024067 小时前
Bootstrap 警告框
开发语言
2601_949146538 小时前
C语言语音通知接口接入教程:如何使用C语言直接调用语音预警API
c语言·开发语言
你撅嘴真丑8 小时前
第九章-数字三角形
算法
曹牧8 小时前
Spring Boot:如何测试Java Controller中的POST请求?
java·开发语言
KYGALYX8 小时前
服务异步通信
开发语言·后端·微服务·ruby
uesowys8 小时前
Apache Spark算法开发指导-One-vs-Rest classifier
人工智能·算法·spark
zmzb01038 小时前
C++课后习题训练记录Day98
开发语言·c++
ValhallaCoder8 小时前
hot100-二叉树I
数据结构·python·算法·二叉树
董董灿是个攻城狮8 小时前
AI 视觉连载1:像素
算法
智驱力人工智能9 小时前
小区高空抛物AI实时预警方案 筑牢社区头顶安全的实践 高空抛物检测 高空抛物监控安装教程 高空抛物误报率优化方案 高空抛物监控案例分享
人工智能·深度学习·opencv·算法·安全·yolo·边缘计算