《算法设计与分析》一一1.2 抽象算法设计

简介: 本节书摘来自华章出版社《算法设计与分析》一 书中的第1章,第1.2节,作者:黄宇 著 ,更多章节内容可以访问云栖社区“华章计算机”公众号查看。

1.2 抽象算法设计

算法设计源于我们面临一个有待解决的算法问题。为此,我们首先讨论算法问题的严格定义,其次讨论算法设计,主要讨论证明算法正确性的基本方法。
1.2.1 算法问题规约
基于RAM模型,我们主要讨论这样的算法:它接受有限的数据作为输入,进行相应的处理,在有限步内终止,并给出输出。因此我们可以将算法问题严格地定义为精确限定输入/输出的“规约”(specification)形式。
定义1.1(算法问题规约) 一个算法问题的规约主要包括两部分:
●输入:明确规定了算法接受的所有合法输入。
●输出:明确规定了对于每一个合法的输入值,相应的输出值应该是什么。
例如,“求最大公约数问题”这一算法问题我们可以给出其规约如下:
●输入:任意两个非负整数a、b。
●输出:a、b的最大公约数  ≌饫锛偕枳畲蠊 约数这一数学概念的定义是明确的。  ?
针对上述明确定义的算法问题,我们可以设计相应的算法来解决它。这里给出著名的欧几里得算法,又叫“辗转相除法”,如算法1所示。算法1:EUCLID(a, b)
1 if b=0 then
2 return a;
3 else
4 return EUCLID(b, a mod b);1.2.2 算法正确性证明:数学归纳法
有了算法问题的严格定义,我们就有了讨论算法正确性的(唯一)标准。要证明算法的正确性,就是要证明对于任意的合法的输入,算法的输出总是满足规约的要求。以欧几里得算法为例,我们要证明该算法的正确性就是要证明:对于任意两个非负整数的输入,算法输出的结果一定是输入的两个数的最大公约数。
根据上面的讨论,我们发现证明算法正确性的核心挑战在于:算法可能的输入有无穷多种,我们需要保证无穷多种输入对应的输出都必然是对的。显然,具体工程实现中常用的测试技术无法证明算法的正确性。无论对多大规模的输入进行测试,始终有无穷多的输入是我们无法覆盖到的。众所周知,测试只能证明程序是有错的,而不能证明程序是无错的。测试只能尽量减少算法中的错误。
要证明一个可数无穷多的集合中的每个元素均满足某种性质,主要的手段是数学归纳法。在实际使用中,我们经常将数学归纳法分为强、弱两种形式。
定义1.2(弱数学归纳法) 假设P是一个定义在自然数集合N上的命题 ?∮械那榭鱿拢 我们会定义P是定义在非负整数上的命题,这本质上是一样的。 ?H绻:
●P(1)为TRUE。
● ?∈N,P(k)→P(k+1)。
则对所有的自然数n,P(n)为TRUE。
定义1.3(强数学归纳法) 假设P是一个定义在自然数集合N上的命题。如果:
●P(1)为TRUE。
● ?∈N,P(1)∧P(2)∧…∧P(k)→P(k+1)。
则对所有的自然数n,P(n)为TRUE。
以数学归纳法为基本手段,证明算法正确性的关键是,将算法面对无穷多种输入,无穷多种可能的执行情况,按照某种原则变成关于自然数的无穷个命题P(1),P(2),…,P(n),…,然后再基于数学归纳法进行证明。需要指出的是这两种数学归纳法都可以看作源于更基本的良序原理(well-ordering principle)。强、弱数学归纳法和良序原理这3种形式不同的证明在本质上是等价的,只不过在不同的场景下,某一种证明方式使用起来更加便捷。关于数学归纳法与良序原理的详细讨论参见附录A。
下面以欧几里得算法为例,讨论算法的正确性证明。
定理1.4 EUCLID算法是正确的。
证明:要证明算法的正确性,就要证明:对于任意的非负整数输入a、b,算法输出的一定是a、b的最大公约数,记为gcd(a,b)。我们采用数学归纳法,对输入的第二个参数b进行归纳。为此,我们将要证明的结论转换成关于非负整数的无穷多个命题:P(0)= ?,算法对输入a、0给出正确输出

P(k-1)= ?,算法对输入a、k-1给出正确输出
P(k)= ?, 算法对输入a、k给出正确输出首先对基础情况P(0)进行证明。根据算法的实现,无论第一个参数a的取值是多少,EUCLID(a,0)总是返回a,这一结果符合我们对最大公约数的定义,所以P(0)为TRUE。
归纳假设当第二个输入参数b≤k-1时,算法总是正确的,即 ?≤k-1,P(b)为TRUE。下面考虑P(k)的情况。根据算法实现,对于输入(a,k),算法将返回EUCLID(k,a mod k)。根据归纳假设,由于a mod k≤k-1,所以算法总能正确计算b和a mod b的最大公约数。根据最大公约数的性质,有gcd(a,k)=gcd(k,a mod k)。我们将上述相等关系串联起来,如下面的公式所示:EUCLID(a,k) = 根据算法实现EUCLID(k,a mod k) = 根据归纳假设gcd(k,a mod k) = 根据最大公约数性质gcd(a,k)由此,我们就证明了对于任意的a,算法总能正确计算a、k的最大公约数,即证明了P(k)。 
根据数学归纳法,我们证明了对任意非负整数n,命题P(n)为TRUE,即证明了EUCLID算法是正确的。

相关文章
|
8月前
|
关系型数据库 MySQL 中间件
MySQL 中如何实现分库分表?常见的分库分表策略有哪些?
在MySQL中,分库分表(Sharding)通过将数据分散到多个数据库或表中,以应对大量数据带来的性能和扩展性问题。常见策略包括:哈希分片(分布均匀,查询效率高)、范围分片(适合范围查询)、列表分片(适用于特定值查询)、复合分片(灵活性高)和动态分片(灵活应对负载变化)。每种策略各有优劣,需根据业务需求选择。常用工具如MyCAT、ShardingSphere和TDDL可简化实现过程。
|
10月前
|
存储 安全 算法
SSL和TLS部署实践
【10月更文挑战第28天】在TLS中,服务器的加密身份和强大私钥是安全基础,2048位RSA密钥足以满足大多数需求。保护私钥需在可信环境生成、加密存储、使用HSM、及时撤销旧证书、每年更新证书。确保证书覆盖所有域名,选择可靠CA,使用SHA256签名算法,配置完整证书链,禁用不安全加密套件,启用前向保密,使用会话重用机制,启用OCSP Stapling,加密整个网站,删除混合内容,安全设置Cookie,配置HSTS和CSP。
749 1
|
12月前
|
存储 NoSQL MongoDB
MongoDB使用方法
MongoDB使用方法
384 2
|
算法 Java 测试技术
算法设计(动态规划实验报告) 基于动态规划的背包问题、Warshall算法和Floyd算法
这篇文章介绍了基于动态规划法的三种算法:解决背包问题的递归和自底向上实现、Warshall算法和Floyd算法,并提供了它们的伪代码、Java源代码实现以及时间效率分析。
算法设计(动态规划实验报告) 基于动态规划的背包问题、Warshall算法和Floyd算法
|
人工智能 监控 Serverless
如何基于ACK Serverless快速部署AI推理服务
通过上述步骤,可以在ACK Serverless上快速部署AI推理服务,实现高可用、弹性扩展的服务架构。
370 1
|
缓存 Android开发 数据安全/隐私保护
android开发,使用kotlin学习HTTP访问网络
android开发,使用kotlin学习HTTP访问网络
333 0
|
存储 缓存 运维
【运维知识进阶篇】集群架构-NFS网络文件系统
【运维知识进阶篇】集群架构-NFS网络文件系统
744 0
|
算法 Java Apache
面向Java开发者的Echarts饼图百分比计算方法
面向Java开发者的Echarts饼图百分比计算方法
303 0
|
SQL 前端开发 关系型数据库
探索MySQL-Cluster奥秘系列之SQL节点故障测试(10)
在这一小节中,我继续来对MySQL-Cluster集群环境的高可用性进行测试,接下来我们来看下当SQL节点出现故障时,MySQL-Cluster集群环境是如何保障其高可用性的。
464 0
|
安全 Android开发 网络架构
如何快捷轻松完成手机备份,这 5 种方法你该知道
手机储存着越来越多的重要文件,一台手机丢失了,让人伤心的不单单只是手机本身,更重要的是手机里面装着的东西,特别是一些珍贵的照片,如果手机丢了,照片也“拍”不回来了。
995 0
如何快捷轻松完成手机备份,这 5 种方法你该知道