数据结构与算法:栈与递归

栈的基本概念

栈(Stack)是一种遵循后进先出(LIFO)原则的线性数据结构。栈的插入和删除操作仅在栈顶进行,核心操作包括:

  • 压栈(Push):将元素添加到栈顶。
  • 弹栈(Pop):移除并返回栈顶元素。
  • 查看栈顶(Peek):获取栈顶元素但不移除。
  • 判空(IsEmpty):检查栈是否为空。
C语言实现栈(数组版本)
#define MAX_SIZE 100

typedef struct {
    int data[MAX_SIZE];
    int top; // 栈顶指针
} Stack;

void initStack(Stack *s) {
    s->top = -1;
}

int isEmpty(Stack *s) {
    return s->top == -1;
}

void push(Stack *s, int value) {
    if (s->top >= MAX_SIZE - 1) {
        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];
}


递归的基本概念

递归是函数直接或间接调用自身的编程技巧,需满足两个条件:

  1. 基线条件(Base Case):递归终止的条件。
  2. 递归条件(Recursive Case):问题分解为更小的子问题。
经典递归示例:阶乘
int factorial(int n) {
    if (n == 0) return 1;      // 基线条件
    return n * factorial(n - 1); // 递归条件
}


栈与递归的关系

递归的本质是隐式使用系统调用栈

  • 每次递归调用时,系统将函数参数、局部变量和返回地址压栈。
  • 返回时,从栈顶恢复上下文。
递归转非递归(手动维护栈)

以下是将递归阶乘改为栈实现的例子:

int factorialIterative(int n) {
    Stack s;
    initStack(&s);
    int result = 1;
    push(&s, n);

    while (!isEmpty(&s)) {
        int current = pop(&s);
        if (current == 0) continue;
        result *= current;
        push(&s, current - 1);
    }
    return result;
}


递归的应用场景

  1. 分治算法:如归并排序、快速排序。
  2. 树遍历:前序、中序、后序遍历。
  3. 动态规划:问题分解为重叠子问题(需记忆化优化)。
示例:斐波那契数列(递归 vs 动态规划)
// 递归版(效率低,存在重复计算)
int fib(int n) {
    if (n <= 1) return n;
    return fib(n - 1) + fib(n - 2);
}

// 动态规划版(优化)
int fibDP(int n) {
    int dp[n + 1];
    dp[0] = 0; dp[1] = 1;
    for (int i = 2; i <= n; i++) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    return dp[n];
}


栈的典型应用

  1. 表达式求值:处理括号匹配、中缀转后缀表达式。
  2. 函数调用:系统调用栈管理函数执行顺序。
  3. 回溯算法:如迷宫求解、八皇后问题。
示例:括号匹配检查
int isBalanced(char *expr) {
    Stack s;
    initStack(&s);
    for (int i = 0; expr[i] != '\0'; i++) {
        if (expr[i] == '(') {
            push(&s, expr[i]);
        } else if (expr[i] == ')') {
            if (isEmpty(&s)) return 0;
            pop(&s);
        }
    }
    return isEmpty(&s);
}


总结

  1. 是LIFO结构,适用于需要反转顺序的场景(如函数调用、表达式求值)。
  2. 递归通过自我调用简化问题,但需注意栈溢出和重复计算问题。
  3. 递归与栈可相互转化:递归隐式使用系统栈,复杂递归可显式用栈实现。
  4. 实际应用中,递归代码简洁但可能低效,栈更灵活但需手动管理状态。

掌握栈与递归的核心思想,能有效解决许多经典算法问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值