数据结构:栈

数据结构中的栈(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原则,适合处理需要后进先出的场景。栈的基本操作包括压栈、出栈、查看栈顶和判断栈空/满。栈可以通过数组或链表实现,数组实现适合小规模数据处理,链表实现适合动态调整大小。栈在函数调用、括号匹配、表达式计算等场景中有广泛的应用。

相关推荐
CSCN新手听安27 分钟前
list的常用操作
数据结构·list
梅茜Mercy2 小时前
数据结构:链表(经典算法例题)详解
数据结构·链表
青春男大2 小时前
java栈--数据结构
java·开发语言·数据结构·学习·eclipse
Zer0_on2 小时前
数据结构栈和队列
c语言·开发语言·数据结构
一只小bit2 小时前
数据结构之栈,队列,树
c语言·开发语言·数据结构·c++
我要学编程(ಥ_ಥ)3 小时前
一文详解“二叉树中的深搜“在算法中的应用
java·数据结构·算法·leetcode·深度优先
szuzhan.gy5 小时前
DS查找—二叉树平衡因子
数据结构·c++·算法
一只码代码的章鱼5 小时前
排序算法 (插入,选择,冒泡,希尔,快速,归并,堆排序)
数据结构·算法·排序算法
青い月の魔女5 小时前
数据结构初阶---二叉树
c语言·数据结构·笔记·学习·算法
我要出家当道士6 小时前
Nginx单向链表 ngx_list_t
数据结构·nginx·链表·c