Skip to content

2015年 408 数据结构 第 1 题

数据结构2015年选择题2分

题目

已知程序如下:

c
int S(int n) {
    return (n <= 0) ? 0 : S(n - 1) + n;
}

void main() {
    cout << S(1);
}

程序运行时使用栈来保存调用过程的信息,自栈底到栈顶保存的信息依次对应的是( )。

错因

B

把方向读反了——B 是自栈顶到栈底(也就是出栈顺序)。S(0) 是递归底,最先 return、最先出栈,所以它在栈顶;main 最先入栈、压在最底。题目问的是"自栈底到栈顶",应从 main 写起。先返回的恰恰是最晚进栈的,B 把整个序列倒了过来。

C

记得 main 在栈底(最先入栈),但把 S(1) 与 S(0) 的先后弄反了。S(0) 是 S(1) 内部调用产生的——必须先有 S(1) 在栈上、走到 S(n-1)+n 这一步才能调 S(0)。所以 S(1) 一定先于 S(0) 入栈,位置应在 S(0) 下面(更靠栈底)。选 C 的人可能直觉上觉得"参数小的先来",但函数调用顺序是由调用关系决定的,不看参数大小。

D

漏了 main 这一帧。程序入口就是 main,main 的活动记录最先压栈、压在栈最底,最后才弹出。任何函数调用都是在 main 已经在栈上的前提下发生的——栈底必然是 main。把 main 排在最后等于把它扔到了栈顶,与"程序入口最先入栈"矛盾。

总解析

关键概念:每次函数调用,系统会为该调用分配一个活动记录(也叫栈帧)压入运行时栈,记录返回地址、参数、局部变量等。函数返回时弹出该帧。栈遵循 LIFO:先进的压在底,后进的盖在顶。

本题的调用链(按时间顺序):

  1. 程序启动 → 进入 main()main 的活动记录入栈(位于栈底)。
  2. main 执行 cout << S(1) → 调用 S(1)S(1) 的活动记录入栈(压在 main 上方)。
  3. 在 S(1) 内:n=1>0,求值 S(n-1)+n = S(0)+1 → 调用 S(0)S(0) 的活动记录入栈(压在 S(1) 上方,此时位于栈顶)。
  4. S(0) 内:n=0≤0,返回 0 → S(0) 出栈。
  5. S(1) 拿到 0,计算 0+1=1,返回 1 → S(1) 出栈。
  6. main 输出 1,结束 → main 出栈。

S(0) 调用瞬间,栈的快照(自下而上):

位置
栈顶S(0)
中间S(1)
栈底main()

自栈底到栈顶 依次是:

方向陷阱:题目问"自栈到栈" = 入栈顺序 = main 在前。选项 B 给的是反方向(自栈顶到栈底,也就是出栈顺序),正好对应"先 return 的先写"。读题先认准"栈底/栈顶"或"进栈/出栈",方向反了立刻全错。

最终答案是 A(main() → S(1) → S(0))

最后更新:

🎬 可视化演示
加载中...

提示:可在可视化区直接操作播放、步进、修改参数