算法 Algorithm
算法是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制
只有在后启示录世界,所有连接到互联网的计算机的硬盘都被炸了,所有基础学术论文和计算机科学教科书都化为灰烬,你才真正需要记住算法。
尝试理解并思考算法的本质,尝试去实现每一个你不论多糟糕的想法,尝试去向更为优秀的算法
算法基础概念
算法的特征
(以下是高德纳在他的著作《计算机程序设计艺术》里对算法的特征归纳)
输入:一个算法必须有零个或以上输入量。
输出:一个算法应有一个或以上输出量,输出量是算法计算的结果。
明确性:算法的描述必须无歧义,以保证算法的实际执行结果是精确地匹配要求或期望,通常要求实际运行结果是确定的。
有限性:依据图灵的定义,一个算法是能够被任何图灵完备[?]系统模拟的一串运算,而图灵机[?]只有有限个状态、有限个输入符号和有限个转移函数(指令)。而一些定义更规定算法必须在有限个步骤内完成任务。
有效性:又称可行性。能够实现,算法中描述的操作都是可以通过已经实现的基本运算执行有限次来实现。-
算法描述
自然语言描述
程序流程图/NS流程图
程序设计语言
伪代码- 1.变量的声明
算法中出现的数组、变量可以是以下类型:整数、实数、字符、位串或指针。
定义变量的语句不用写出来,但必须在注释中给出 - 2.指令的表示
指令:在算法中的某些指令或子任务可以用文字来叙述,
例如,”设x是A中的最大项”,这里A是一个数组;或者”将x插入L中”,这里L是一个链表。
这样做的目的是为了避免因那些与主要问题无关的细节使算法本身杂乱无章。 - 3.表达式
算术表达式 可以使用通常的算术运算符(+,-,*,/,以及表示幂的^。
逻辑表达式 可以使用关系运算符=,≠,<,>,≤和≥,
逻辑运算符 与(and),或(or),非(not)。 - 4.语句
赋值语句
- 1.变量的声明
a←b \\ 语句的含义是将b的值赋给a。
这里a是变量、数组项,b是算术表达式、逻辑表达式或指针表达式
变量交换
a<->b
若a和b都是变量、数组项,那么记号a<->b 表示a和b的内容进行交换。
5.goto语句
6 分支结构
条件语句:
if i=10
then xxxx
else xxxx //else 和 then 要对齐
if i=10
then xxxx //if 后面必定跟上then,else后面不用跟then
elseif i=9 //elseif 要连在一起写
then xxxx
yyyy
else xxxx //else 跟在elseif 的 then 对齐
- 8.循环结构
while
while time<10
do xxxxx //while后面必定要紧跟缩进的do
xxxxx
end
for
for var init to limit by incr do
xxxx
end
for i←0 to 10 //for、while、if 后面的条件语句都不用加括号
do ... //for后面必定要紧跟缩进的do
...
这里var是变量,init、limit和incr都是算术表达式,
而xxxx是由一个或多个语句组成的语句串。
初始时,var被赋予init的值。假若incr≥0,则只要var≤limit,就执行s并且将incr加到var上。
(假若incr<0,则只要var≥limit,就执行s并且将incr加到var上)。incr的符号不能由xxxx来该改变。
- 9.程序的结束
exit 可以在通常的结束条件满足之前,被用来结束while循环或者for循环的执行。exit导致转向到紧接在包含exit的(最内层)while或者for循环后面的一个语句。
return 用来指出一个算法执行的终点;如果算法在最后一条指令之后结束,它通常是被省略的;它被用得最多的场合是检测到不合需要的条件时。return的后面可以紧接被括在引号的信息。 - 10.注释风格
算法中的注释被括在/* */之中。诸如read和output之类的各种输入或者输出也在需要时被用到。 - 11.函数的编写
函数的伪代码格式例子为
search(A,name) //参数类型可以不给出,但必须在注释中说明
算法设计过程
1.问题分析
2.算法策略/建立计算模型
3.算法设计与描述
4.算法分析[算法选择]
5.算法实现
6.测试与结果分析
7.文档编制-
算法设计工具
循环
- 循环设计思路
自底向上的设计(Down - Top Design)
先找出某个问题的子问题或若干特殊问题,以定性、定量的方式去描述和解决这些子问题,然后,逐步合并子问题的解,最后得到大问题的解。
核心本质:合并
自顶向下的设计(Top-Down Design)
将复杂的大问题分解为相对简单的小问题,找出每个问题的关键、重点所在,然后用精确的思维定性、定量地去描述问题和解决问题。
核心本质:分解
递归:一个过程或函数在定义中直接或间接调用自身的一种方法。
设计关键:找出递归关系(方程)和递归终止(边界)条件。递归关系就是使问题向边界条件转化的规则。- 递归设计的步骤:
(1) 分析问题找到递归关系:找出大规模问题与小规模问题的关系,以便通过递归使问题规模变小。
(2) 设置终止条件控制递归:通过停止条件的设置,找出可解的最小规模问题。
(3) 设计函数确定数据传递方式。
- 循环设计思路
基本的数据结构
线性表
栈 FILO
队列 FIFO
树 (二叉树/B树/B+树)
图
算法基础概念
- 算法效率评价的指标 : 算法计算机资源的占用
时间复杂度 O 计算资源(时间)
空间复杂度 O 存储资源(内存)
数学基础
函数的渐近的界
利用极限求函数渐近的界
有用的求和级数及推导方法
基本效率类型
算法分析实例
非递归形式算法分析
递归形式算法分析(难点)
- 分析递归算法时,可遵循以下步骤
决定用哪些参数作为输入规模的度量标准
找出算法的核心操作,它通常是递推公式
检查一下,对于相同规模的不同输入,核心操作的执行次数是否可能不同。如果有这种可能,则必须对最差效率、平均效率以及最优效率做单独研究;
对于算法核心操作的执行次数,建立一个递推关系以及相应的边界条件;
解这个递推式,或者至少确定它的解的增长次数。
递推法分析时间复杂度 求n!
-
计算模型
算法分析
n为规模,也是计算规模
核心操作为n*F(n-1),是一次乘法操作
依据递推公式,每递推一次,执行一次乘法操作,因此有如下推导过程:
T(n) =1+T(n-1) =1+1+T(n-2)……=1+1+…+1+T(1)=1+1+…+1=n=Θ(n)
递推法分析时间复杂度 汉诺塔问题
- 计算模型
n为规模,也是计算规模
核心操作为移动盘子
依据递推公式,两次递推之间,执行一次移动操作,因此有如下推导过程:
T(n) =2T(n-1)+1
=2[2T(n-2)+1]+1=22T(n-2)+2+1
=22[2T(n-3)+1]+2+1=23T(n-2)+22+2+1
……
=2i[2T(n-i)+1]+2i-1+2i-2…+20=2iT(n-i)+ 2i-1
……
=2n-1T(n-(n-1))+ 2n-1-1=2n-1T(1)+ 2n-1-1=2n-1
主定理
主定理(Master Theorem) 设a≥1, b>1为常数,f(n)为函数,T(n)为非负整数,且 T(n)=aT(n/b)+f(n) 则有以下结果
迭代法
是一种不断用变量的旧值递推新值的过程
- 分类
- 精确迭代 (杨辉三角,内存移动算法)
- 近似迭代 (方程求解)
- 设计关键
- 确定迭代模型/迭代方程
- 控制迭代过程
杨辉三角
斐波那契数列
f(n) = f(n-1)+f(n-2)
内存移动问题
数组中有n个数据,要将它们顺序循环向后移k位,即前面的元素向后(右)移k位,后面的元素则循环向前移k位 后面的元素则循环向前移k位,例:0、1、2、3、4、5循环移3位后为: 3、4、5、0、1、2。考虑到n会很大,不允许用2n及以上个空间来完成此题*
解题思路 : 利用移动长度与数据个数的关系约简运算
求解方程的近似算法 (以9x2-sin x-1=0为例)
- 迭代方程 求解序列必须收敛
(1)选取适当的初值x0
(2)建立迭代方程,将方程f(x)=0转换成x=φ(x)的等价形式。
(3)运用迭代方程x=φ(x),反复计算,如x1=φ(x0), x2=φ(x1),…,xn=φ(xn-1),得到x的序列,若该数列收敛,则最终可以得到满足一定精度ε的解,即有|xn-xn-1|<ε。有时候也会用f(xn)<= ε或f(xn)=0来判断
- 二分法
零点定理
- 牛顿法
使用泰勒展开近似求解
线性代数方程组
-
Jacobi算法
-
Gauss-Seidel算法
线性规划问题
研究线性约束条件下线性目标函数的极值问题的数学理论和方法
- 单纯型表法求解
1 根据约束方程建立模型 (通过松弛变量等方法)
2 选择入基变量与离基变量
3 进行转轴变换,求最值
蛮力法/暴力法
直接基于问题的描述和所涉及的概念定义的进行算法设计,简单而直接。
枚举法
利用枚举所有的情况,或者其它大量运算又不用技巧的方式,来求解问题的方法。
- 猜数字问题
穷举查找
- 单词搜索问题
- 穷举求解背包问题 (注意更高效的生成一个全排列矩阵/树)
- 穷举求解旅行商问题 (traveling salesman problem,TSP)
旅行商由一个旅行商由某市出发,经过所有给定的n个城市后,再回到出发的城市。除了出发的城市外,其它城市只经过一回。这样的回路可能有多个,求其中路径成本最小的回路。-
问题分析与描述
- 计算模型
(1) 存储 图G(V, E)。以邻接矩阵的方式存储,设计如下
(2)计算 设起始点下标为0
生成排列树。设解空间为a,则其解空间的计算过程可描述为:
(3)求回路代价 设sumi是并入第i个结点的代价
-
伪代码描述
-
图的搜索
- 深度优先遍历 DFS
- 广度优先遍历 BFS
- 矩阵迷宫求解
分治法
把一个较大的问题分解成几个与原问题相似的子问题,找到求出这几个子问题的解法后,再以适当的方法组织,把它们合成求整个问题的解法。
- 分治法适用情景
该问题的规模缩小到一定的程度就可以容易地解决 - (前提) 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质
- (关键) 利用该问题分解出的子问题的解可以合并为该问题的解;
- (效率) 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。