你在终端跑着一个程序,眼看它卡住了,你下意识按下 Ctrl+C——它停了。又或者,你发现某个进程怎么都杀不掉,于是掏出 kill -9,它立刻毙命。这些"远程遥控"背后,靠的都是同一个机制:信号(Signal)。这一课,我们认识这个进程之间的"通知系统"。从"按 Ctrl+C"说起你正跑着一个死循环程序,屏幕上刷着一行行输出。你按 Ctrl+C,程序停了。这一瞬间到底发生了什么?很简单:你的按 …

上一课结尾我留了个问题:你在 shell 里敲下 ls,那个 ls 进程是怎么"变"出来的?答案是一对黄金搭档——fork 和 exec。一个负责"复制",一个负责"变身"。这一课,我们把这对搭档彻底拆开。从"敲下 ls 的瞬间"说起你敲下 ls -l,回车。屏幕上列出了一堆文件。你有没有想过:ls 是一个躺在磁盘上的程序,它是怎么变成一个正在运行的进程的?难道 shell 自己"变身"成 l …

前面几课我们都在跟"数据结构"和"算法套路"较劲。这一课换个口味,聊点纯数学——但别慌,是程序员真正用得上的那部分,叫数论(Number Theory)。数论听起来高冷,实际上你早就天天在用:密码学的 RSA 加密靠质数,哈希表取模靠余数,加密与随机数生成靠最大公约数。哪怕是 LeetCode 上,也有一大类题直接考质数、公约数、模运算。这一课的目标:给你一个"算术工具箱",装进四件最常用的工 …

上一课讲排序时,我们偷偷用了一个"作弊"的招数:归并排序里,函数自己调用了自己——merge_sort 里面又调 merge_sort。这招有个正式的名字,叫递归(recursion)。它是算法世界里最优雅、也最让人头疼的思想之一:写对了代码短得惊人,写错了递归爆栈、死循环。这一课,我们把递归和它最经典的搭档——分治——彻底讲透。一、递归是什么:函数自己调用自己先看一个最简单的例子——算阶乘 …

排序,可能是你这一辈子写得最多的算法。给它排个序、给排行榜排个名、把数据从小到大理一理——无处不在。但排序真正的价值,不是"把数字排整齐"这么简单,而是它教会我们"快"到底是怎么炼成的:同样是排序,笨办法 O(n²),聪明办法 O(n log n),数据一大,一个要等一天,一个一秒完事。这一课,我们从最笨的冒泡讲起,一路升级到快排,亲手摸一遍"快"的门道。一、先立个靶子:排序到底在解决什么排序 …

上一课我们用哈希表秒杀了"两数之和",享受了一把"查找 O(1)"的快感。但你可能没意识到:你写代码、读文件、处理用户输入、爬网页、调 API 时,碰到最多的数据类型,其实是字符串。字符串很"狡猾":它看起来最简单——不就是一串字符吗?但里面藏着的坑和门道一点不比哈希表少。面试里那些"最长回文子串""无重复字符的最长子串""字符串匹配",全是围绕它转的。这一课,我们把字符串这层窗户纸捅破:它到 …

从这一课开始,我们进入第二个阶段——系统编程入门。前面我们站在高处看操作系统,现在要蹲下来,摸一摸它最常用的"零件"。第一个要认识的,是贯穿整个 Unix/Linux 世界的一个哲学:一切皆文件。而连接你程序和这些"文件"的,是一张小小的号码牌——文件描述符。从"程序怎么读写文件"说起你现在写一个 C 程序,要往硬盘上写点东西。你会怎么写?int fd = open("hello.t …

本课属于 第一阶段 · 走进操作系统(第 1~5 课)。上一课我们认识了进程——那个"正在运行的程序"。但你有没有想过一个问题:一个浏览器,怎么做到一边渲染网页、一边下载图片、一边响应你的点击?它好像会"分身术"一样。这一课的主角,就是进程里的这些"分身"——线程。从"浏览器一边……一边……"说起你打开一个网页,盯着进度条看:图片在慢慢加载、文字已经先显示出来了、你还能随时滚动、点击链接。如果 …

第 2 课我们认识了四种线性数据结构,并且得出一条关键结论:数组"按下标读"是 O(1),但它"按值找"是 O(n)。想想这件事有多憋屈:你有一个存了 100 万个人名的列表,想知道"张三在不在里面",只能从头一个个比过去——最坏要翻 100 万次。难道就没有一种结构,既能"按名字直接定位",又不用事先排好顺序吗?有。它就是这一课的主角——哈希表(hash table)。它是工程界和面试里出现 …

上一课我们玩的是指针——两个指针一快一慢,就把链表的问题拆得干干净净。这一课我们往更底层钻一层:直接跟计算机的"母语"打交道,也就是位(bit)。你可能会嘀咕:我都用 Python 了,还要懂位运算干嘛?——好问题。但事实是,位运算在很多地方是绕不开的快车道:判断一个数是不是 2 的幂、在 O(1) 空间里找一个只出现一次的数、用一个整数优雅地表示"哪些开关被打开了"……这些题,不懂位运算,你 …