1、2019/7/26,LingJie/GDUT,1,算法设计与分析 The Design and Analysis of Algorithms,2019/7/26,LingJie/GDUT,2,第1章 绪 论,主要内容:1.1 算法的概念1.2 算法问题求解的基础1.3 重要问题类型1.4 基本数据结构,2019/7/26,LingJie/GDUT,3,1.1 算法的概念,1、算法概念 没有一个统一的严谨的定义。一般而言,对于计算机算法的概念是这样描述的:算法是在有限步骤内求解某一问题所使用的一组定义明确的指令。 本书采用的定义:An algorithm is a sequence of una
2、mbiguous instructions for solving a problem=算法是求解某一问题所使用的一系列清晰的指令。,2019/7/26,LingJie/GDUT,4,2、算法的概念图,注意:计算机发明以前也有算法,2019/7/26,LingJie/GDUT,5,3、算法的三个要素1).数据: 运算序列中作为运算对象和结果的数据.2).运算: 运算序列中的各种运算:赋值,算术和逻辑运算 3).控制和转移: 运算序列中的控制和转移.,2019/7/26,LingJie/GDUT,6,4、算法的一般特征1).有穷性 finiteness算法必须在执行有穷步后终止,且每一步均在有限
3、时间内完成2).确定性 definiteness 算法的每个步骤必须有明确的意义,对每种可能的情况,算法都要给出确定的操作.3).能行性effectiveness算法中的每个步骤是能够实现的,算法执行结果要达到预期目的 4).有0个或多个输入项,至少有一个输出项.,2019/7/26,LingJie/GDUT,7,举例: 计算最大公约数的欧几里德算法,ALGORITHM Euclid(m,n) /计算两个整数m、n的最大公约数gcd(m,n) / 输入:非负整数m,n,其中m,n不同时为零 / 输出:m,n的最大公约数 while n 0 dor m mod nm nn r return m,
4、2019/7/26,LingJie/GDUT,8,求gcd(m,n)的原理: (结构化的描述) 第一步:如果n=0,返回m的值作为结果,结束;否则进入 第二步。 第二步:用n除m,余数赋值给r,进入第三步。 第三步:将n的值赋给m,将r的值赋给n,返回第一步。例:gcd(60,24)=? 1-1、m=60, n=241-2、60 mod 24=12, r=12,1-3、m=24, n=122-1、24 mod 12=0,r=02-2、m=12, n=02-3、条件“n=0”满足,返回gcd(m, n)=m=12,2019/7/26,LingJie/GDUT,9,求gcd(m,n)的其他算法,算
5、法二:连续整数检测法 第一步:将minm,n赋值给t。 第二步:m除以t,如果余数为0,进入第三步,否则进入第四步。 第三步:n除以t,如果余数为0,返回t的值;否则进入第四步。 第四步:把t的值减1,返回第三步。例:gcd(60, 24) t=min60, 24=24, m=60, n=2460mod24=120, t=23, 24 mod 23=1 0 t=22, 24 mod 22=2 0 t=21, 24 mod 21=3 0 t=12, 24 mod 12=0, 返回gcd(m, n)=t=12,2019/7/26,LingJie/GDUT,10,算法三:质因数分解法 第一步:找出m
6、的所有质因数。 第二步:找出n的所有质因数。 第三步:从第一步求得的m的质因数分解式和第二步求得的n 的质因数分解式中,找出所有公因数。 第四步:将第三步找到的公因数相乘,结果为所求的 gcd(m,n) 例: m=60=2235n=24=2223公因数为 223结果为 gcd(m,n)=12存在问题:如何求所有的质因数/素因子?,2019/7/26,LingJie/GDUT,11,求连续素数序列的筛法,问题:求不大于n=25的质数 序列。 筛法: 1、取 p=2,消去p的倍数。 2、取 p=3,消去p的倍数。 直至 p=? 结束,2019/7/26,LingJie/GDUT,12,2019/7
7、/26,LingJie/GDUT,13,求连续素数序列的筛法,Sieve(n) For p=2 to n do /设立数组A2AnAp=p For p=2 to do / if Ap0, j=p*pwhile j=n doAj=0j=j+p i=0 / 将A中剩余的元素复制到数组L供连续输出 For p=2 to n doif Ap0,Li=Api=i+1 Return L,2019/7/26,LingJie/GDUT,14,5、算法的分类,从解法上分: 优化算法:算法中的基本运算为逻辑运算。 数值算法:算法中的基本运算为算术运算。从处理方式上分: 串行算法:串行计算机上执行的算法。 并行算法
8、:并行计算机上执行的算法。,2019/7/26,LingJie/GDUT,15,1.2 算法问题求解基础,观点: 算法是问题的程序化解决方案 算法设计与分析过程的典型步骤:1、了解问题的内容2、了解计算设备的性能3、在精确解法和近似解法之间选择4、确定适当的数据结构5、算法设计技术6、详细表述算法的方法7、证明算法的正确性8、分析算法9、为算法写代码,2019/7/26,LingJie/GDUT,16,图1.2 算法设计与分析的过程,2019/7/26,LingJie/GDUT,17,1.2.1 了解问题的内容,当遇到一个问题时,首先要清楚这个问题的所有内容。如果这个问题已经给出了明显的要求,
9、如对成绩排序,那么只需要看看它是属于那一类的问题,然后参考相关的资料。 了解问题内容这个步骤是十分重要的,因为只有知道了问题具有什么样的输入,需要得到什么样的输出,问题的解决才可能进行下去。理解了问题是问题求解的关键。,2019/7/26,LingJie/GDUT,18,1.2.2 了解计算设备的能力,在清楚了解了问题的内容之后,下一步是确定用于解决问题的设备的能力。目前一般使用的计算机都是冯诺依曼(von Neumann)体系架构的。它的一个最重要假设是,程序指令的执行是顺序的。针对这一类计算机设计的算法被称为串行算法(sequential algorithms)。与之相区别的是所谓的并行计
10、算机以及并行算法(parallel algorithms)。指令能够并行的执行,效率当然会大大提高,额外需要考虑的则是指令执行顺序以及同步等问题。并行算法的设计有相应的理论,这里仅考虑串行算法。,2019/7/26,LingJie/GDUT,19,1.2.3 选择精确或者近似的算法,解决问题下一步要考虑的是使用精确的还是近似的算法。并不是每一个可解的问题都有精确的算法,例如求一个数的平方根,求非线性方程的解等。有时候一个问题有精确的解法但是算法的执行效率很差,例如旅行家问题。因此如果待处理的问题涉及到上述那些方面,则要考虑是选择精确的还是近似的算法。,2019/7/26,LingJie/GDU
11、T,20,1.2.4 确定合适的数据结构,许多程序设计的教程都提到:程序设计算法数据结构(Programs = Algorithms + Data Structures),由此可以看出数据结构对算法的重要性。例如在处理搜索问题时,对于仅仅进行搜索的算法只需要用到简单的数组即可,如果搜索后伴随着插入删除操作时,那么用链表以及堆等复杂的数据结构的算法更加可取。,2019/7/26,LingJie/GDUT,21,1.2.5 选择算法设计技术,算法设计技术(algorithm design technique)或者算法设计策略(strategy)指的是解决一系列不同问题的通用设计思想。常用的设计技术
12、包括分治法(Divide and Conquer),贪婪法(Greedy Technique),动态规划(Dynamic Programming),回溯法(Backtracking),分支限定法(Branch and Bound)等。,2019/7/26,LingJie/GDUT,22,1.2.6 详细表述该算法的方法,可以用到的工具有自然语言(nature language)、伪代码(pseudocode)以及程序流程图(flow chart)等。 当对一个问题有了概要的理解后,下面的工作就是把这个问题的想法进行细化。所谓的细化就是把它们表示成算法的步骤。,2019/7/26,LingJie
13、/GDUT,23,1.2.7 确认算法的正确性,当给算法一个合法输入,而该算法给出一个错误的结果时,可以证明这个算法是错误的。但如果证明一个算法是正确,情况就不是那样地简单。算法的测试有一套完整的理论,这里不作详细叙述。 特别需要提出的是,所谓算法的正确性指的是:对于任意合法的输入在有限时间内都能得到正确的结果。如果算法是一个近似算法,那么正确性则是指输出结果与理论结果之间的误差在一个可以接受的范围内。,2019/7/26,LingJie/GDUT,24,1.2.8 对算法的分析,时空的观点 发展的观点:算法的适应性(generality)最强 设计的观点:算法的设计时间最少 交流的观点:算法
14、最容易理解(simplicity),2019/7/26,LingJie/GDUT,25,1.2.9 为算法写代码,目前而言,大部分的算法最后还是需要通过程序语言进行实现。针对不同的问题,还需要考虑什么样的程序语言才是最适合的,这与个人的知识组成以及程序语言本身的特性等有关。 部分的程序语言可能需要对算法进行修改以适应这种语言本身。例如广泛用于科学计算的Matlab语言,它是基于矩阵的语言,提供了大量数值计算的函数,然而它的循环计算能力相对较弱,所以如果把算法中涉及循环的过程通过向量的形式进行,那么最终的效率将能得到很大的提高。,2019/7/26,LingJie/GDUT,26,1.3 重要问
15、题的类型,排序问题(Sorting) 查找/搜索问题(Searching) 串处理问题(String problems) 图论问题(Graph problems) 组合问题(Combinatorial problems) 几何问题(Geometric problems) 数值计算问题(Numerical problems) 加密问题(Encrpytion problems),2019/7/26,LingJie/GDUT,27,1.3.1 排序问题,所谓的“排序”就是把一组杂乱的数据按照一定的规律顺次排列起来。排序是很重要的,因为它可以使得以后的工作更加地容易。目前,计算机科学家发明了很多的排序
16、算法,然而这些排序算法中并不存在一种算法是绝对最优的。这里介绍几个与“排序”相关的重要概念:数据表 、关键字 、主关键字 、排序的稳定性 、内排序与外排序 。,2019/7/26,LingJie/GDUT,28,1.3.2 查找/搜索问题,所谓查找/搜索,就是在数据集合中寻找满足某种条件的数据对象。一般的形式是先给出一个特定值,然后在数据集合中找出关键字等于该特定值的对象。对于搜索问题,通常需要返回的结果可能有两种。一种是简单的搜索成功或者失败的信息;另一种是返回满足搜索条件的对象所在位置,如果找不到则返回不存在信息。,2019/7/26,LingJie/GDUT,29,1.3.3 串处理问题
17、,对于字符串处理的问题,这里只是对其中一类特殊的问题进行讨论,即字符串模式匹配问题(string matching)。问题是这样表述的:在一篇文章或文章的一部分中找出单词第一次出现的位置。本书把字符串匹配问题作为一种特殊的搜索问题考虑,因为两者是有相似之处的。最大的区别在于,一般搜索问题是单一的关键字的搜索,而字符串匹配可以看作是几个关键字组成一种模式的搜索过程,因此对模式的分析有助于算法效率的提高。,2019/7/26,LingJie/GDUT,30,1.3.4 图论问题,图论问题主要是与图或树相关的问题。这里所谓的“图”指的是一些顶点(Vertex)与边(Edge)的集合。图有着非常重要与
18、丰富的实际应用,如通信网络,交通网络,工程计划等。本书所涉及到的图论问题主要包括了图的遍历问题(Graph Traversal),最短路径问题以及图的特例树结构的排序、搜索中的应用问题。,2019/7/26,LingJie/GDUT,31,1.3.5 组合问题,现代的组合数学所涉及的领域更加广阔,其中的问题出自抽象代数、拓扑学、数学基础、图论、博弈论、线性规划以及其他许多领域。值得注意的是,这些来源不同的问题不能在一个统一的理论体系中得到有效的解决,而且随着问题的输入量的增加,问题的规模急剧增长至计算机的处理能力的极限,所以可以说组合数学问题是最难的一类问题。,2019/7/26,LingJi
19、e/GDUT,32,1.3.6 几何问题,几何问题是几何数学上与点、线、多边形相关的问题。当然,这不是一本几何学的书,所以这里只会涉及如直线段的表示、相交判断等基本问题。同时还会给出最近邻点问题与凸包问题这两个重要问题的介绍。它们都有穷举法与分治法的算法版本,通过比较,可以深入体会到其中所用到的算法设计思想。,2019/7/26,LingJie/GDUT,33,1.3.7 数值问题,数值计算问题是另一大类问题,它要解决的问题包括:求解方程或者方程组,求数值积分等。这些问题常常只能给出一个近似的结果,而不是精确的解析解。并且这些问题常涉及到具体的数据,由于计算机对数字表示的精度问题,所以还需要考虑可能带来的误差以及这些误差对算法稳定性的影响。,