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

相关推荐
Tony Bai2 小时前
“我曾想付钱给 Google 去工作”—— Russ Cox 深度访谈:Go 的诞生、演进与未来
开发语言·后端·golang
sali-tec2 小时前
C# 基于halcon的视觉工作流-章66 四目匹配
开发语言·人工智能·数码相机·算法·计算机视觉·c#
小明说Java2 小时前
常见排序算法的实现
数据结构·算法·排序算法
hnlgzb3 小时前
安卓app开发,如何快速上手kotlin和compose的开发?
android·开发语言·kotlin
行云流水20193 小时前
编程竞赛算法选择:理解时间复杂度提升解题效率
算法
无敌最俊朗@3 小时前
STL-deque面试剖析(面试复习4)
开发语言
APIshop3 小时前
用 Python 把“API 接口”当数据源——从找口子到落库的全流程实战
开发语言·python
Java Fans4 小时前
Qt Designer 和 PyQt 开发教程
开发语言·qt·pyqt
RwTo4 小时前
【源码】-Java线程池ThreadPool
java·开发语言
兮动人4 小时前
EMT4J定制规则版:Java 8→17迁移兼容性检测与规则优化实战
java·开发语言·emt4j