谁发明了Stack?一段来自德国教授的计算机传奇

161 阅读5分钟

我们写程序的时候,几乎都会接触到“栈”(Stack)这个词:函数调用的时候会“压栈”,返回时会“出栈”;你调试程序时能看到“调用栈”;甚至很多面试题都是“用栈解决括号匹配”……

栈已经成为程序世界中最基础的概念之一了。

但你有没有想过:这个“栈”是谁发明的?又是为什么发明的?

一切要从 1950 年代的德国说起……

那时候,计算机刚刚开始进入人们的视野。没有 Python、没有 Java,甚至 C 都还没诞生。程序员是拿打孔卡片在写程序,机器只有几个 KB 的内存,运行速度非常慢,而且还容易“搞混”执行顺序。

这个时候,有一个德国数学家/计算机先驱:Friedrich Ludwig Bauer(弗里德里希·路德维希·鲍尔),提出了一个想法,彻底改变了程序的组织方式—— “用栈来管理程序运行过程中的数据和指令。”

堆栈这个概念是怎么来的?

Friedrich Bauer 出生于 1924 年,是二战后德国恢复高等教育体系的第一批数学毕业生之一。他在战后进入了慕尼黑工业大学(TUM)做研究,当时主要研究数学、逻辑推理和新兴的“自动计算”技术。

在 1950 年代初,他和同事 Klaus Samelson 一起在研究如何让机器更高效地执行数学表达式。他们发现,如果把一个表达式写成“逆波兰式”(Reverse Polish Notation,简称 RPN)——也就是把运算符写在操作数后面,例如:

scss
复制编辑
(2 + 3) * (4 + 5)

写成:

复制编辑
2 3 + 4 5 + *

这个表达式就可以非常容易地用一个“后进先出”的数据结构来一步一步计算出来——这就是他们最初提出“堆栈”想法的起点。

注意:这里的“后进先出”,就是你最后放进去的数据,最先被拿出来,这就是栈的精髓。

为什么这个想法这么重要?

你可以试着想象早期程序员要写一个支持子程序(也就是函数)调用的程序。每次调用函数,都需要保存当前执行位置,跳到新函数执行,再跳回来。问题是,如果你还套了好几个函数(A 调 B,B 调 C),你该怎么知道返回顺序?

Bauer 想:“我们为什么不做一个‘栈’结构,把每一次调用时的返回地址、局部变量等都压进去?然后函数返回的时候再把它们按顺序弹出来?”

这就是今天每一个程序员都在用的**“调用栈”(Call Stack)**。

第一次正式出现“堆栈”的概念是在什么时候?

1957 年,Friedrich Bauer 和 Klaus Samelson 在研究编译器技术的时候,系统性地提出了栈的概念。当时他们试图设计一个更合理的表达式求值方式,并且用这种方式实现了一种早期编程语言——Algol

后来在 1959 年和 1960 年,Bauer 是 Algol 58 和 Algol 60 语言设计小组的核心成员。在 Algol 中,函数调用、嵌套作用域等机制都是基于栈来实现的。这也是栈第一次成为语言标准的一部分。

Algol 语言本身虽然现在已经没人用了,但它是 C、Pascal、JavaScript、Go 等现代语言的祖宗,而它的**“用栈管理函数调用和数据”**的思想,从那时起就成为主流编程范式的核心。

那 Friedrick Bauer 是个什么样的人?

Friedrich L. Bauer 并不只是“提出了栈”的人,他其实是整个计算机科学发展的重要推动者:

  • 他是最早推动将数学逻辑引入程序设计的人之一;
  • 他参与创建了德国最早的计算机研究机构;
  • 他是编译器领域的先驱,在语法分析、抽象语法树(AST)、上下文无关文法等方面都有贡献;
  • 他提出了著名的口号:“程序 = 算法 + 数据结构”(这个公式后来被 Knuth 宣扬成名言);
  • 他帮助德国慕尼黑工业大学建立了最早的计算机科学系。

更有趣的是,他的教学风格很风趣幽默,许多德国学生回忆说 Bauer 教课像讲故事一样,是那种让人“爱上编程的老师”。

他于 2015 年去世,享年 90 岁。他的学生、同行、学术界都给予他极高的评价,有人称他为“德国的 Alan Turing”。

栈的影响到底有多大?

你今天能使用递归、函数嵌套、作用域隔离、异常处理、协程切换……这一切的背后,都有“栈”的支持:

  • 编译器 会生成“函数调用栈帧”,用来保存局部变量和返回地址;
  • 虚拟机(如 JVM、.NET CLR)都有自己的“操作数栈”,实现表达式计算;
  • 调试工具 用“栈回溯”展示程序崩溃点;
  • 现代 CPU 的指令集里都有“PUSH”、“POP”、“CALL”、“RET”等操作,就是原生支持栈的运作;
  • 高级语言中的递归函数、闭包,甚至异步函数的栈帧管理,全都离不开栈的概念。

可以说,栈已经深入计算机系统的每一层,从硬件指令、编译器中间码,到你写的每一行代码。

今天我们说起“stack”,可能只是调试工具里的一个 tab、数据结构课程里的一个章节。但正是 Friedrich L. Bauer 和他的同行们,在 70 多年前提出了这个看似简单却非常优雅的想法,让程序的运行逻辑变得清晰、可预测,也让复杂的函数调用成为可能。

这不是“发明一个数据结构”这么简单,而是“为计算机找到了组织思维的方式”。