王道数据结构C语言实战:线性表与栈的5个高频面试题解析

王道数据结构C语言实战:线性表与栈的5个高频面试题解析

准备数据结构面试,尤其是针对考研复试或大厂校招,很多人会陷入一个误区:把教材上的概念背得滚瓜烂熟,但一遇到需要动手写代码的题目就卡壳。我当年备考时也踩过这个坑,直到在面试现场被要求在白板上实现一个“两栈共享空间”时,才发现自己理解的“掌握”和实际能写出来的“掌握”完全是两码事。这篇文章不会重复那些你已经看过无数遍的理论定义,而是聚焦于五个在面试中反复出现、又容易写错的线性表和栈的C语言实战题目。我会带你一步步拆解思路,给出可以直接运行的代码,并重点分析那些教科书上不会明说、但实际编码时一定会遇到的“坑”。

1. 两栈共享空间:如何优雅地“一石二鸟”

两栈共享空间这个题目,几乎成了数据结构面试的“保留节目”。它考察的不仅仅是你对栈的理解,更是对顺序存储结构内存管理的敏感度。核心思想很简单:一个数组,两个栈,一个从数组头部开始增长(栈1),一个从数组尾部开始增长(栈2),向中间靠拢。听起来容易,但实现时细节决定成败。

首先,我们需要一个结构体来管理这个共享空间。很多同学在这里会犯第一个错误:栈顶指针的初始化。

#define MAXSIZE 100  // 共享栈的最大容量

typedef struct {
    int data[MAXSIZE];
    int top1;  // 栈1的栈顶指针
    int top2;  // 栈2的栈顶指针
} DoubleStack;

初始化时,top1 应该设为 -1,表示栈1为空;top2 应该设为 MAXSIZE,表示栈2为空。这里 top2 指向的是栈顶元素的下一个位置,这是一种常见的实现方式,但你必须非常清楚它的含义,因为这会直接影响判满和判空的条件。

栈满的条件是面试官最喜欢追问的地方。不是 top1 == top2,而是 top1 + 1 == top2。为什么?因为 top1 指向的是栈1的栈顶元素,top2 指向的是栈2的栈顶元素的下一个位置。当两个栈的栈顶元素相邻时,数组就满了。下面是一个完整的初始化及入栈函数实现:

// 初始化双栈
void InitDoubleStack(DoubleStack *S) {
    S->top1 = -1;
    S->top2 = MAXSIZE;
}

// 向栈1压入元素
int Push1(DoubleStack *S, int e) {
    if (S->top1 + 1 == S->top2) { // 栈满判断
        printf("栈满,无法压入元素 %d\n", e);
        return 0; // 失败
    }
    S->data[++(S->top1)] = e; // 先移动指针,再赋值
    return 1; // 成功
}

// 向栈2压入元素
int Push2(DoubleStack *S, int e) {
    if (S->top2 - 1 == S->top1) { // 另一种等价的栈满判断
        printf("栈满,无法压入元素 %d\n", e);
        return 0;
    }
    S->data[--(S->top2)] = e; // 先移动指针,再赋值
    return 1;
}

注意:在 Push2 中,我们使用 --(S->top2) 是因为栈2是反向增长的。top2 初始为 MAXSIZE,减1后指向数组最后一个有效位置(MAXSIZE-1),这正是栈2的栈底。随着元素压入,top2 会逐渐减小。

出栈操作相对简单,但务必记得先判空。栈1空的条件是 top1 == -1,栈2空的条件是 top2 == MAXSIZE。我见过不少同学在面试紧张时,把判空条件写反。

这种结构的优缺点非常明显:

  • 优点:在需要两个相同类型的栈,且此消彼长(一个栈增长时另一个栈在减少)的场景下,能有效利用存储空间,避免一个栈满另一个栈还空着的情况。
  • 缺点:必须事先预估两个栈可能的最大容量总和。如果两个栈同时快速增长,仍然会很快栈满。并且,这种结构只适用于两个栈,扩展性差。

2. 循环队列:告别“假溢出”的经典陷阱

顺序队列的“假溢出”问题——即队列头部有空闲位置,但尾部指针已到数组末尾,导致无法再入队——是面试中的经典考点。循环队列是解决这个问题的标准方案,但它的实现细节堪称“陷阱重重”,尤其是队空和队满的判定。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值