上一课我们学会了线性回归:y = wx + b,一条直线。但现实世界大多不是直线:房价和面积的关系,可能先平缓后陡峭(不是直线)一张图是不是"猫",根本没法用一个线性公式判断一段文字的情感,和词频也不是线性关系这些都需要非线性。神经网络(Neural Network) 的核心,就是"把很多线性组合,叠加非线性激活,层层堆叠",从而拟合任意复杂的函数。这一课,我们亲手搭一个神经网络,看它怎么突破 …

从这一课起,我们进入第四阶段:内存管理。前面我们一直在问"谁先跑、怎么不打架",现在要问一个更底层的问题:程序到底"住"在内存的哪里? 你在 C 里打印出来的那个变量地址,是真实的内存条地址吗?答案会颠覆直觉——不是。这一课,我们就来搞懂"程序住在哪"这件事。从"你以为的地址"说起写 C 程序时,你会打印变量的地址:int x = 10; printf("%p", & …

上一课我们学会了用锁解决竞态。但锁这个东西,用不好会"反噬":你握着锁 A 等锁 B,对方握着锁 B 等锁 A——于是谁也不放,大家全卡死。这就是并发世界里最"优雅"、也最让人头疼的僵局——死锁(Deadlock)。从"窄桥相遇"说起想象一条窄得只能过一辆车的桥。桥的两头,各开来一辆车,在桥中间迎面相遇:甲车过不去,因为乙车挡着;乙车也过不去,因为甲车挡着;谁都不愿意倒车让路——于是两辆车都卡 …

上一课我们制造了一个"翻车现场":100 个线程同时 i++,结果随机丢数据。病确诊了,这一课开药——怎么让这些线程排好队,一个一个安全地进临界区?答案是一整套"排队工具":互斥锁、信号量、条件变量。它们各自解决一类问题,我们一个个来。从"洗手间"说起想象一间只有一个坑位的洗手间,外面排着一群人。规则很简单:进去的人锁门;别人看到门锁着,就排队等;里面的人用完,开锁出来;下一个进去,锁门……这 …

前 21 课,我们写的都是"规则明确"的算法:给你输入,程序按我们写死的步骤,算出输出。但现实中有大量问题没法写死规则:房子面积多大,能卖多少钱?一只 28×28 的像素图,是"猫"还是"狗"?这段文字,情感是正面还是负面?这些问题的共性:输入和输出之间有关系,但我们写不出"公式"。机器学习的核心想法来了——与其人工写规则,不如让算法从数据里"学"出这个关系。这一课,我们学机器学习最基础的两块 …

上一课模拟退火是单解型:一个解自己爬山,靠"温度"允许偶尔退一步。这一课换一条完全不同的思路——种群型:不放一个解,放一群解,让它们像生物一样选择、交叉、变异,一代一代演化,逼近最优。这就是遗传算法(Genetic Algorithm, GA)。它的灵感来自达尔文的自然选择:一个种群里的个体有好有坏,环境压力会淘汰差的、留下好的;好个体之间"交配"产生后代,后代还可能发生微小"变异"。反复很多 …

上一课我们搭了元启发算法的总纲,留下一个问题:贪心算法永远只接受"更好的解",于是会卡在局部最优。这一课的主角——模拟退火(Simulated Annealing, SA),就是解决这个问题的第一种经典方案。它的名字来自冶金退火:把金属加热到高温,再慢慢冷却,原子会逐渐排列成能量最低的稳定结构。如果冷却太快,会卡在亚稳态(对应算法的局部最优);慢慢冷却,才有机会到达全局最优。一、先看清敌人:局 …

前面 18 课,我们写的算法有一个共同点:确定性(deterministic)。同样的输入,走同样的步骤,永远得到同样的输出——排序、查找、Dijkstra、DP、回溯,都是这样。但现实里有一大类问题,确定性算法要么慢到算不出来,要么根本写不出精确步骤:圆周率 π 的精确值,怎么写个"确定性步骤"算出来?一个复杂积分,没有初等原函数,怎么求?一个 NP 难题(比如旅行商问题),穷举要算到宇宙毁 …

上一课我们讲了调度——"谁先跑"的问题。但真正的麻烦,是从"真的同时跑起来"这一刻才开始的。当 100 个线程同时去加同一个变量,结果会怎样?这一课,我们要亲手制造一个"并发翻车现场",看看计算机世界里最阴险的一类 bug——竞态条件。从一个"鬼故事"说起想象你有一张银行卡,余额 100 元。某天,你的两笔退款同时到账,各退 50 元。系统应该把你的余额变成 200 元,对吧?但如果程序写错了 …

上一课我们默认"只有一个 CPU 核"。但现实是:你的手机有 8 核,服务器有 64 核;而有些任务——比如无人机飞控、汽车刹车——晚一毫秒都可能出人命。这一课,我们进入调度的两个进阶战场:实时调度 和 多核调度。从"晚 10ms 会怎样"说起想象你在开一辆自动驾驶的车。前方突然出现行人,刹车系统必须在 10ms 内响应,晚一点点就撞上了。这时候,"平均表现不错"够用吗?完全不够。 哪怕 99 …