1、算法设计与分析计算机与信息学院,2,使用教材,使用教材,作者:(美)Anany Levitin 译者:潘彦 出版社:清华大学 丛书名:国外经典教材 计算机科学与技术,第3章 蛮力法,概述选择排序冒泡排序顺序查找字符串匹配穷举查找,4,蛮力法概述,蛮力法概述 前面讨论了算法效率分析框架与方法。本章开始,讨论算法设计技术。 概念:蛮力法是一种简单直接的解决问题的方法,常常直接基于问题本身设计算法。可以用“直接干吧!”来描述蛮力法策略,通常是最容易想到和采用的一种简单直接的算法设计策略。 简单算例:给定数字 a 和非负整数 n ,计算 an 的值。蛮力法:据定义直接基于问题定义设计算法:直接把 a
2、和 a 相乘 n 次。 其他算例:1. 计算gcd(m,n)的连续整数检测算法;(效率不如欧氏算法)2. 用矩阵乘法定义直接计算大矩阵乘法。(效率不如斯特拉森算法),5,蛮力法概述(2),蛮力法特点:1. 算法设计较为简单直接,相对容易;2. 通常,算法效率不高。因此,高效算法一般很少来自于蛮力法。 蛮力法应用: 它仍然是一种重要的算法设计策略1. 可以解决广泛领域的各种问题,几乎是唯一一种解决各种问题的一般性方法。常用于一些非常基本而又十分重要的算法。比如:计算 n 个数的和; 求一个列表的最大元素,等等。2. 对于一些重要的算法(如排序、查找、矩阵乘法、字符串匹配),蛮力法可以产生一些合理
3、算法,多少具备一些实用价值 ,且并不限制问题的规模。3. 对于规模不大的问题,蛮力法的计算速度可以接受时,设计一个高效算法所花费的代价很可能不值得。(人力成本,算法复杂度)4. 蛮力法可为研究和教学服务,以它作为尺度,衡量该问题的其他算法的效率。,6,选择排序,选择排序 排序问题:给定一个可排序的 n 元素序列(如数字序列、字母序列),对它们按照非降序方式重新排列。 问题思考:解决该问题“直截了当”的方法是什么? 选择排序算法策略:从小到大,依次找到满足要求的各元素1. 扫描整个列表,找到最小元素,将其和第一个元素交换;2. 从第二个元素开始扫描列表,找到余下元素中的最小元素,将其和第二个元素
4、交换;3. 如此做下去,直到全部元素按要求排序为止。(找 n-1 遍即得),7,选择排序效率分析,选择排序效率分析: 输入规模:元素个数 n ; 基本操作:键值比较次数 Aj Amin; 效率情况:本算法键值比较次数与输入序列顺序无关,因此没有最佳最差、平均效率之分。 本算法为非递归,增长函数和增长率计算如下:结论: 1. 选择排序算法效率属于 类型; 2. 键的交换次数为 。这个特性使得选择排序算法超过了其他许多排序算法。,8,选择排序改进算法,冒泡排序 蛮力法在排序上的另一个应用,策略是:比较列表中两个相邻元素,如果它们是逆序的,就交换它们的位置。重复多次,最终,最大元素就“沉到”列表中的
5、最后一个位置。第二轮操作将第二大元素沉下去,这样做(n-1)轮,该列表就排好序了。,9,冒泡排序效率分析,冒泡排序效率分析: 输入规模:列表的元素个数 n ; 基本操作:键值比较次数 Aj+1 Aj; 效率情况:本算法键值比较次数与输入序列顺序无关,因此没有最佳最差、平均效率之分。 本算法为非递归,增长函数和增长率计算如下:结果: 1. 冒泡排序算法效率属于 类型;(与选择排序一样) 2. 键值交换次数在最坏情况下(输入降序列表,每次比较后均要交换)和键值比较次数一样即均为 ,这比选择排序差。因此,该算法在简单排序问题上不是一个好的选择。“如果不是因为它有一个好记的名字,我们很可能对它不会有任
6、何的了解”。,10,顺序查找,顺序查找键值的“查找” 前节讨论了蛮力法在排序问题上的两个应用。接下来两节讨论该策略对 查找问题的两个应用即顺序查找和字符串匹配。 查找问题: (经典问题)如何在给定列表中查找一个给定值(查找键)。 顺序查找的蛮力策略:将列表中元素一个个与查找键比较,直到找到匹配元素(成功查找),或者遍历整个列表也没找到匹配元素(失败查找)。实现顺序查找的一个小技巧:把查找键添加到列表的末尾,那么查找一定成功,避免了每次循环时对列表作边界检查。,最佳效率:Tbest (n) = 1; 最差效率:Tworst(n) = n+1; 如果给定序列是有序的,可作 一点改进:只要遇到一个大
7、于 或等于(小于或等于)查找键 的元素,就停止查找。,11,蛮力字符串匹配,蛮力字符串匹配 文本“查找” 文本(Text):n 个字符组成的串。 模式(Pattern):m 个字符组成的串。(mn) 串匹配:在文本中寻找匹配模式的子串位置,即 i 的值。蛮力算法策略:(滑动匹配)模式在文本上从左向右滑动一个字符,比较对应字符(从左到右),若全部 m 个字符都已匹配,算法停止。否则,继续滑动、比较。注意:最后一轮比较的起始位置在 (n-m) 处:(n-1)-(n-m)+1=m,12,蛮力字符串匹配 算法,字符串匹配 (String Matching) 的蛮力算法,注意: 考虑while循环结束时
8、 j 的值: 1. j m 2. j = m,输入规模:取决于 n 和 m 。基本操作:比较操作 Pj=Ti+j; 最差效率:滑动 (n-m)+1 次。每次滑动后,可能做足 m 次比较。 因此,最差效率 (n-m+1)m(mn)。但每次滑动后,都做足 m 次比较的可能性很小,所以,该算法的平均效率比最差效率要 好很多。事实表明,它能够显示出线性效率: (m+n)=(n)。,13,穷举查找,穷举查找 本节查找问题不同于前面的查找键,前述查找键是在一个集合中查找一个给定值(查找键)元素,本节查找问题是在一个集合中查找满足给定条件的一个子集,属于组合问题。或者说,本节的“元素”是一个扩展的概念,指一
9、个集合,该集合是原问题集的一个子集。穷举查找是一种简单的蛮力法。在实现时,它常常要求用一个算法来生成某些组合对象(候选集),本节假设生成算法已存在(在减治法讲)。旅行商问题 (Traveling Salesman Problem) 问题描述:给定 n 个城市,找出一条经过每个城市一次的最短路径。 哈密顿回路:图的每个顶点只经过一次的回路。(威廉.哈密顿爵士) 建模:加权图。顶点代表城市,边的权重表示城市间的距离。该问题表示为求一个图的最短哈密顿回路。 穷举法策略:哈密顿回路定义为 n+1个相邻顶点的一个序列:生成所有回路的中间(n-1)个顶点,计算各回路长度,得到最短路线。,第 i 条回路的相
10、邻顶点序列,14,穷举法解小规模旅行商问题例,穷举法解小规模旅行商问题例:,因为是通过全部顶点的一个回路,所以 任选一个顶点作为起点。本例为完全图, 路线总数是中间顶点的全排列数,即:这意味着除了规模非常小的问题以外, 穷举法几乎是不实用的。,n+1=5个顶点构成哈密 顿回路,要生成的中间 顶点数 n-1=3个,15,穷举法解背包问题,穷举法解背包问题 背包问题:给定 n 个总量为 w1, . , wn、价值为 v1, . , vn 的物品和一个承重为 W 的背包,求这些物品中一个最有价值的子集,并且能放入背包中。(01背包:每个物品不能被拆分) 穷举法策略:把背包承重作为约束条件,要求找出满
11、足约束条件的所有可行子集。这要求列举所有子集(幂集),并计算每个子集的总重量不超过背包承重量,最后计算各个子集的总价值,选价值最大的子集。n 元集的所有子集数:想一想:每次的组合数为何是一种和关系,而非乘积关系?因此,不论子集生成算法效率有多高,穷举查找的效率: 不论旅行商问题还是背包问题,穷举查找都是一个非常低效的算法。实际上,这两个问题就是NP(Nondeterminism Problem)困难问题中最著名的例子。目前没有已知的、效率可用多项式来表示的算法,且大多数计算机学家相信,这样的算法是不存在的(虽然尚未证实)。,16,穷举法解分配问题,穷举法解分配问题 分配问题:n 个任务分配给
12、n 个人完成,一人一个任务。已知第 i 个任务分配给第 j 个人的成本是 ci, j ,找出总成本最低的分配方案。,成本矩阵,约束条件:每行挑一个元素(任务),且不属于同一列(人)。失败策略:每行挑成本最小的,可能不满足约束条件:不在同一列。穷举策略:生成任务的全部可行组合,从中找到和最小的任务组合。组合问题:从组合角度看,第1人可4选1,第2人可3选1,第3人可2选1,第4人1选1。后选的任务与先被选的任务有关,换句话说,先选走不同的任务,得到不同的后选任务集。这样的任务组合数:想想:为何是乘积关系,17,穷举法解分配问题(续),排列问题:把任务按分配序表示为一种分配方案,有一种方案 3,
13、1, 4, 2 表示:任务3 给 第1人,任务1 给 第2人,任务4 给 第3人,任务2 给 第4人。分配集合的元素表示任务编号,左到右的顺序表示人员编号(固定序)。, 1, 2, 3, 4 cost = 9 + 4 + 1 + 4 = 18 1, 2, 4, 3 cost = 9 + 4 + 9 + 8 = 30 1, 3, 2, 4 cost = 9 + 8 + 3 + 4 = 24 1, 3, 4, 2 cost = 9 + 8 + 9 + 7 = 33 etc.,成本矩阵,可见,不同方案的元素(任务号)在集合中排列的位置不同。因此, 这是一个排列问题。n 个任务的排列数为:(全排列),