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

相关推荐
两个人的幸福online38 分钟前
记录一次 用php 调用ai用stream返回
开发语言·php
漂流瓶6666661 小时前
Scala的模式匹配变量类型
开发语言·后端·scala
夏天吃哈密瓜1 小时前
Scala中的正则表达式01
大数据·开发语言·后端·正则表达式·scala
2401_833788051 小时前
Scala的模式匹配(2)
java·开发语言
Lbs_gemini06031 小时前
C++研发笔记14——C语言程序设计初阶学习笔记12
c语言·开发语言·c++·笔记·学习
ac-er88882 小时前
GD库如何根据颜色生成纯色背景图
开发语言·php
叁散2 小时前
PTA--数据结构预习报告: 考试排名汇总
数据结构
悠悠龙龙3 小时前
框架模块说明 #05 权限管理_03
java·开发语言·spring
霖大侠3 小时前
Adversarial Learning forSemi-Supervised Semantic Segmentation
人工智能·算法·机器学习
阿华的代码王国4 小时前
【算法】——前缀和(矩阵区域和详解,文末附)
java·开发语言·算法·前缀和