欢迎来到算法的世界!
欢迎!在本章关于算法建模(Modelling with Algorithms)的学习中,我们将探索数学世界中的“食谱”。无论你是使用 GPS 寻找回家的最快路线,还是电脑在整理数以百万计的文件,背后都有一个算法(Algorithm)在运作。
别担心,即使你从未写过程序,或者觉得“大 O 符号(Big O notation)”听起来像天书,也不用紧张。我们会将这些概念拆解成任何人都能跟上的简单逻辑步骤。让我们开始吧!
1. 什么是算法?
简单来说,算法就是解决特定问题的一系列有限指令。把它想象成烤蛋糕的食谱:你准备好材料(输入/Input),按照顺序执行步骤(处理/Process),最后得到一个蛋糕(输出/Output)。
关键组成部分:
- 初始状态(Initial State):你开始的地方。
- 输入(Input):你提供给算法的数据(例如:一串数字)。
- 输出(Output):算法最终产出的结果。
- 变量(Variable):一个用来储存数值的“盒子”,随着算法执行,里面的值会改变(例如:“令 \(i = i + 1\)”意思是更新标记为 \(i\) 的盒子里的数值)。
- 有限性(Finite):这点至关重要!算法必须在有限步骤内结束,不能无限执行下去。
类比:想象你在教一台机器人泡茶。你不能只说“泡茶”,你必须说:1. 把水煮沸。2. 将茶包放入杯中。3. 倒水。如果你忘了叫它停止倒水,你的厨房就会淹水了!这就是为什么终止(Termination)是算法的核心。
快速回顾:一个算法必须有清晰的开始、明确的步骤,以及确定的结束点。
2. 跟着地图走:流程图与伪代码
算法通常以两种主要方式呈现:流程图(Flowcharts)(可视化地图)和伪代码(Pseudocode)(类似英语的指令)。
需要记住的流程图符号:
- 椭圆形:开始或结束。
- 矩形:处理或指令(例如:“将 \(x\) 加 1”)。
- 菱形:决策或“如果(if)”语句(例如:“\(x > 10\) 吗?”)。这类符号总有两条路径出来:“是”或“否”。
理解逻辑:
算法经常使用迭代过程(Iterative processes)(循环)。这意味着重复执行一组步骤,直到满足特定条件为止。
示例:“当水尚未煮沸时,持续加热水壶。”
记忆小撇步:在伪代码中,片语“令 \(i = i + 1\)”非常常见。不要把它当成代数方程式(那样 \(i\) 就会消掉了!),要把它想成一条指令:“用新值(旧值 + 1)来取代 \(i\) 的旧值。”
总结:流程图适合视觉型学习者;伪代码适合喜欢列表的人。两者完成的工作是一样的!
3. 算法复杂度:电脑运作得有多辛苦?
并非所有算法都生而平等。有些算法速度很快,有些则在问题规模变大时非常缓慢。我们使用复杂度(Complexity)来衡量这一点。
“大 O”符号(Big O Notation)
我们使用阶数符号(Order Notation)(例如 \(O(n)\) 或 \(O(n^2)\))来描述算法所需的运算时间随问题规模(\(n\))增长的方式。
- 线性复杂度 \(O(n)\):如果你将项目数量增加一倍,所需时间也会加倍(例如:逐一搜索列表)。
- 二次复杂度 \(O(n^2)\):如果你将项目数量增加一倍,所需时间会变成原来的四倍(\(2^2 = 4\))。当你在一个循环中又套用另一个循环时,就会发生这种情况!
你知道吗?我们通常关注最坏情况(Worst Case)。这能确保无论输入的数据有多不理想,我们都知道该算法所需的最长时间。
快速回顾练习:如果一个 \(O(n^2)\) 算法处理 100 个项目需要 5 秒,那么处理 200 个项目需要多久?
规模翻倍(\(\times 2\)),因此时间增加 \(2^2 = 4\) 倍。
新时间 = \(5 \times 4 = 20\) 秒。
4. 排序算法:将事物按顺序排列
课程大纲特别强调了快速排序(Quick Sort)算法。这是一种“分治法(Divide and Conquer)”的排序方式。
快速排序如何运作:
- 选择一个枢纽(Pivot)(通常是列表中的第一个或最后一个项目)。
- 将其他所有项目与枢纽进行比较。
- 将小于枢纽的项目移至左侧,大于枢纽的项目移至右侧。
- 现在枢纽已经位于其最终正确的位置。
- 对左侧和右侧的“子列表”重复上述过程。
常见错误:当手动进行快速排序时,学生常会忘记一旦枢纽被选中并用于拆分列表后,该枢纽就已经“锁定”在位了。下次再进行拆分时,千万别再移动它!
要点:像快速排序这样的排序算法,其最坏情况的复杂度通常为 \(O(n^2)\)。
5. 装箱算法与启发式方法
有时候,找到“完美”的答案需要太长时间。在现实世界中,“足够好且快速”往往比“完美但缓慢”更好。这就是启发式方法(Heuristics)发挥作用的地方。
装箱问题(Bin Packing):
想象你在把箱子装进货车。你希望使用的箱子数量越少越好。
- 首次适应法(First Fit):按照给出的顺序逐个取出物品,放入第一个能装得下的箱子中。
- 递减首次适应法(First Fit Decreasing, FFD):先将物品按大小降序排列,然后再使用“首次适应法”。这通常效果更好,因为你先处理了那些大而难装的物品!
- 满箱法(Full Bin):寻找物品组合,使其恰好填满一个箱子的策略。
重要观点:这些都是启发式算法。它们高效且快速(复杂度为 \(O(n^2)\)),但不保证能得到最少箱子数量的绝对最佳解。它们只是给出一个非常好的估算值。
总结:追求速度用“首次适应法”;想要更好的结果用“递减首次适应法”(但记得要先排序!)。
6. 证明算法
我们如何确定一个算法确实有效?
- 穷举证明(Proof by Exhaustion):测试每一个可能的案例(只适用于非常小的问题!)。
- 反例否定(Disproof by Counter-example):如果你找到一个算法失败的案例,就证明该算法是不正确的。
鼓励:如果这些证明看起来很抽象,别担心!大多数考试题目只会要求你解释某个步骤为何有效,或者提供一个简单的例子,说明为什么某个启发式算法无法给出最佳答案。
本章重点小结:
算法是用于提升效率的逻辑工具。通过理解它们的结构(流程图/伪代码)、效率(复杂度)以及局限性(启发式方法),你就能有系统地建模并解决现实世界中的复杂问题。