数据结构:栈

数据结构中的栈(Stack)

栈是一种重要的线性数据结构,遵循"后进先出"(Last In, First Out, LIFO)的原则。这意味着最后一个进入栈的元素将是第一个被弹出的元素。栈通常用于深度优先搜索、逆波兰表达式计算、函数调用栈等场景。

栈的基本定义

栈的基本操作包括:

  1. Push(压栈):将元素添加到栈的顶部。

  2. Pop(出栈):从栈的顶部移除元素。

  3. Peek(或 Top):查看栈顶的元素,但不移除它。

  4. IsEmpty(判空):检查栈是否为空。

  5. IsFull(判满):检查栈是否已满(如果栈的大小有限)。

栈的实现方式

栈可以通过数组或链表来实现。以下是两种实现方式的详细介绍:

1. 数组实现栈

数组实现的栈是一种静态栈,其大小在初始化时确定。数组实现栈的好处是简单易用,适合小规模数据处理。

示例代码(数组实现栈):
cpp 复制代码
#include <stdio.h>
#include <stdbool.h>

#define MAX_SIZE 100

typedef struct {
    int data[MAX_SIZE];
    int top;
} Stack;

// 初始化栈
void initStack(Stack *s) {
    s->top = -1;
}

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

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

// 压栈操作
void push(Stack *s, int value) {
    if (isFull(s)) {
        printf("栈已满,无法压栈\n");
        return;
    }
    s->top++;
    s->data[s->top] = value;
}

// 出栈操作
int pop(Stack *s) {
    if (isEmpty(s)) {
        printf("栈为空,无法出栈\n");
        return -1;  // 返回一个无效值表示错误
    }
    int value = s->data[s->top];
    s->top--;
    return value;
}

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

int main() {
    Stack s;
    initStack(&s);

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

    printf("栈顶元素: %d\n", peek(&s));
    printf("出栈元素: %d\n", pop(&s));
    printf("栈顶元素: %d\n", peek(&s));

    return 0;
}
输出:
cpp 复制代码
栈顶元素: 30
出栈元素: 30
栈顶元素: 20
2. 链表实现栈

链表实现的栈是一种动态栈,其大小可以根据需要动态调整。链表实现栈的好处是可以灵活处理大规模数据,适合需要频繁插入和删除操作的场景。

示例代码(链表实现栈):
cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

// 定义链表节点结构
struct Node {
    int data;
    struct Node* next;
};

typedef struct {
    struct Node* top;
} Stack;

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

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

// 压栈操作
void push(Stack *s, int value) {
    struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = value;
    newNode->next = s->top;
    s->top = newNode;
}

// 出栈操作
int pop(Stack *s) {
    if (isEmpty(s)) {
        printf("栈为空,无法出栈\n");
        return -1;  // 返回一个无效值表示错误
    }
    struct Node* temp = s->top;
    int value = temp->data;
    s->top = temp->next;
    free(temp);
    return value;
}

// 查看栈顶元素
int peek(Stack *s) {
    if (isEmpty(s)) {
        printf("栈为空,无法查看栈顶\n");
        return -1;  // 返回一个无效值表示错误
    }
    return s->top->data;
}

int main() {
    Stack s;
    initStack(&s);

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

    printf("栈顶元素: %d\n", peek(&s));
    printf("出栈元素: %d\n", pop(&s));
    printf("栈顶元素: %d\n", peek(&s));

    return 0;
}
输出:
cpp 复制代码
栈顶元素: 30
出栈元素: 30
栈顶元素: 20
栈的应用案例
  1. 函数调用栈:在程序执行过程中,函数的调用和返回使用栈来管理。每次调用一个函数时,当前的执行状态(如返回地址、局部变量等)会被压入栈中,函数返回时再从栈中弹出。

  2. 括号匹配:在编译器中,栈可以用于检查括号是否匹配。例如,左括号压入栈,右括号出栈,最后栈为空则表示括号匹配。

  3. 逆波兰表达式计算:栈可以用于计算后缀表达式(逆波兰表达式)。操作数压入栈,遇到操作符时弹出栈顶的两个操作数进行计算,结果再压入栈。

  4. 浏览器历史记录:浏览器的前进和后退按钮可以使用栈来实现。后退时将当前页面地址出栈,前进时将之前出栈的页面地址重新压入栈。

总结

栈是一种简单但强大的数据结构,遵循LIFO原则,适合处理需要后进先出的场景。栈的基本操作包括压栈、出栈、查看栈顶和判断栈空/满。栈可以通过数组或链表实现,数组实现适合小规模数据处理,链表实现适合动态调整大小。栈在函数调用、括号匹配、表达式计算等场景中有广泛的应用。

相关推荐
不知道取啥耶2 小时前
C++ 滑动窗口
数据结构·c++·算法·leetcode
Murphy_lx3 小时前
数据结构(树)
数据结构
tt5555555555553 小时前
每日一题——三道链表简单题:回文,环形合并有序
数据结构·链表
小六子成长记4 小时前
C语言数据结构之顺序表
数据结构·链表
ChinaRainbowSea8 小时前
MySQL 索引的数据结构(详细说明)
java·数据结构·数据库·后端·mysql
白晨并不是很能熬夜9 小时前
【JVM】字节码指令集
java·开发语言·汇编·jvm·数据结构·后端·javac
*.✧屠苏隐遥(ノ◕ヮ◕)ノ*.✧9 小时前
C语言_数据结构总结7:顺序队列(循环队列)
c语言·开发语言·数据结构·算法·visualstudio·visual studio
橘颂TA9 小时前
每日一练之合并两个有序链表
数据结构·链表
LIUJH12339 小时前
数据结构——单调栈
开发语言·数据结构·c++·算法
shylyly_10 小时前
list的模拟实现
数据结构·c++·链表·迭代器·list·list的模拟实现