目录

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

本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
C语言小火车21 分钟前
QT面试题:内存管理与对象生命周期
开发语言·qt·面试
雾月554 小时前
LeetCode 941 有效的山脉数组
java·开发语言·数据结构·算法·leetcode·职场和发展
晨曦5432105 小时前
函数和模式化——python
开发语言·python
leluckys5 小时前
swift-08-属性、汇编分析inout本质
开发语言·汇编·swift
uhakadotcom5 小时前
归因工具:了解国内外顶级产品
算法·面试·github
嘤国大力士6 小时前
C++11&QT复习 (十六)
java·开发语言·c++
念九_ysl7 小时前
Java中的列表(List):操作与实现详解
java·开发语言·list
阿昆的科研日常7 小时前
Matlab进阶绘图第74期-带填充纹理的单组柱状图
开发语言·matlab·可视化·论文插图