程序设计方法选
- 格式:pdf
- 大小:46.01 KB
- 文档页数:11
常见的程序设计方法常见的程序设计方法1.概述程序设计是计算机科学中非常重要的一门学科,它主要涉及将问题转化为计算机可以理解和执行的指令集合,以达到完成特定任务的目的。
本文将介绍几种常见的程序设计方法,供参考使用。
2.面向过程程序设计面向过程程序设计是一种基于顺序执行的方法。
它将程序看作一系列的步骤或过程,每个步骤依次执行,直至达到预期的结果。
这种方法主要关注于问题的解决过程,而不是问题本身的抽象和封装。
2.1 定义函数在面向过程程序设计中,函数是重要的组织单元。
通过将代码逻辑组织为函数,可以实现代码的重用和模块化管理。
定义函数时,应该明确函数的输入和输出,以及函数内部的具体实现。
2.2 控制结构面向过程程序设计中的控制结构主要包括顺序结构、选择结构和循环结构。
顺序结构表示代码按照自上而下的顺序执行。
选择结构通过条件判断来选择执行不同的代码块。
循环结构可以重复执行代码块,直到满足退出条件。
3.面向对象程序设计面向对象程序设计是一种以对象为中心的方法。
它将程序看作一组对象的集合,每个对象都有自己的属性和方法。
通过对对象进行抽象和封装,可以更好地模拟现实世界的问题,提高代码的可读性和可维护性。
3.1 类和对象3.2 封装、继承和多态封装是面向对象程序设计的核心思想之一,它将数据和方法封装在一个对象中,提高了代码的安全性和可复用性。
继承允许创建新类从已有类中继承属性和方法,减少了代码的重复工作。
多态允许同一对象以不同的方式呈现,根据当前上下文来选择调用不同的方法。
4.函数式程序设计函数式程序设计是一种基于数学函数的方法。
它将程序视为一系列函数的组合和应用,强调函数的纯粹性和不可变性,避免副作用的产生。
4.1 高阶函数函数式程序设计中的高阶函数指的是可以接受函数作为参数或返回函数的函数。
通过使用高阶函数,可以实现代码的简化和灵活性的增加。
4.2 不可变性和副作用函数式程序设计强调函数的不可变性,即函数的结果只由输入决定,不受外部状态的影响。
程序设计的三种方法程序设计是指通过编写计算机程序来解决问题的过程。
在程序设计中,有许多不同的方法可以使用。
本文将介绍三种常见的程序设计方法:结构化程序设计、面向对象程序设计和函数式程序设计。
1. 结构化程序设计结构化程序设计是一种以结构为基础的编程方法。
它强调将程序分解为较小的、可重用的模块,并使用顺序、选择和循环等控制结构来组织代码。
结构化程序设计帮助开发者编写清晰、易于理解和维护的代码。
特点:•模块化:将程序分解为较小的模块,每个模块负责一个特定的任务。
•顺序性:按照特定顺序执行语句,确保正确的流程。
•选择性:使用条件语句(如if语句)根据不同情况执行相应操作。
•循环性:使用循环语句(如for循环)重复执行一段代码。
优点:•结构清晰:代码分解为模块,易于理解和修改。
•可维护性高:模块化使得代码易于维护和调试。
•可重用性好:模块可以在不同项目中重复使用。
缺点:•不适合大型项目:结构化程序设计对于大型项目的管理和维护较为困难。
•难以处理复杂逻辑:结构化程序设计可能导致嵌套过深的if语句,使得代码难以理解。
2. 面向对象程序设计面向对象程序设计是一种以对象为基础的编程方法。
它将数据和操作封装到对象中,通过定义类和创建实例来组织代码。
面向对象程序设计强调数据的抽象和封装,以及对象之间的交互。
特点:•类:定义了对象的属性和方法。
•对象:类的实例化,具有特定的属性和方法。
•继承:允许一个类继承另一个类的属性和方法。
•多态性:同一个方法可以根据不同的对象产生不同的行为。
优点:•可重用性好:面向对象程序设计通过继承和多态提供了代码重用机制。
•易于扩展:通过添加新类或修改现有类,可以方便地扩展功能。
•更好的抽象能力:面向对象程序设计允许开发者将真实世界中的概念映射到代码中。
缺点:•学习曲线陡峭:面向对象程序设计需要掌握类、对象、继承等概念,对初学者来说可能较难理解。
•性能开销:相比于结构化程序设计,面向对象程序设计可能有一定的性能开销。
常见的程序设计方法在计算机程序设计中,常见的程序设计方法有许多种。
程序设计是将问题转化为计算机可以理解和执行的指令或代码的过程,而不同的问题和需求通常需要使用不同的程序设计方法来解决。
下面将介绍一些常见的程序设计方法。
1. 顺序程序设计顺序程序设计是最基础的程序设计方法之一。
顺序程序设计按照指令的顺序逐步执行,从上到下,从左到右。
开发者需要按照问题的逻辑和需求,将指令按照正确的顺序编写。
这种方法简单明了,适用于一些简单的问题,但对于复杂的问题可能会显得不够灵活。
2. 分支程序设计分支程序设计基于条件语句,根据不同的条件选择不同的执行路径。
常见的条件语句有if语句和switch语句。
开发者可以根据不同的条件,执行不同的代码块,从而实现问题的不同分支。
分支程序设计适用于需要根据条件进行不同操作的问题,可以增加程序的灵活性和适应性。
3. 循环程序设计循环程序设计允许程序根据需要重复执行一段代码块。
循环语句的常见形式有for循环、while循环和do-while循环。
循环程序设计可以逐次迭代一个过程,直到满足退出条件为止。
这种方法适用于需要重复执行相同或类似操作的问题,提高了程序的效率和可重用性。
4. 递归程序设计递归程序设计是指一个函数或过程在执行过程中调用自身的方法。
通过递归,一个复杂的问题可以被拆分为多个相同或类似的子问题,从而简化解决步骤。
递归程序设计适用于问题可以自我分解为更小规模问题的情况,但需要注意递归深度和终止条件以避免无限循环。
5. 面向对象程序设计面向对象程序设计是一种以对象和类为基本单位的程序设计方法。
它将数据和操作这些数据的函数封装成对象,通过对象之间的交互来解决问题。
面向对象程序设计具有抽象、封装、继承和多态等特性,可以更好地模拟和解决现实世界中的问题。
面向对象程序设计适用于复杂的问题,提高了代码的可读性和可维护性。
6. 函数式程序设计函数式程序设计是一种基于数学函数概念的程序设计方法。
程序设计的主要方法
编程或程序设计的主要方法主要包括结构化编程、面向对象编程和面向过程编程等三种。
结构化编程,这是早期程序设计的主要方法,重点是减少代码的复杂性,提高程序的可读性。
它主要包括顺序、选择和循环等三种基本控制结构。
常见的结构化编程语言有C,Pascal等。
面向对象编程是一种热门的编程方法,强调通过抽象的对象模型以模拟世界中的对象。
这种方法的核心思想是数据抽象、封装、多态和继承。
面向对象编程语言具有良好的扩展性和复用性,是现代大多数复杂应用程序的首选设计方法。
常见的面向对象编程语言有Java,C++等。
面向过程编程是一种以过程为中心的编程方法,强调通过算法来解决问题。
这种编程方法以任务的完成为目标,每个过程都被看作是一个独立的实体。
过程之间通过输入和输出数据进行交流。
常见的面向过程编程语言有Fortran,C等。
此外,还有一些较新的程序设计方法,例如函数式编程、逻辑编程等。
函数式编程是一种以函数为主导的编程方法,逻辑编程则是一种以逻辑推理为基础的编程方法。
这些程序设计方法相互之间并不排斥,往往在实际应用中会结合使用。
程序设计学习方法程序设计是当今信息技术领域的核心技能之一,掌握良好的程序设计学习方法对于提高编程能力和解决问题至关重要。
本文将探讨几种有效的程序设计学习方法,并提供一些建议以帮助读者提高编程技能。
一、理论学习与实践相结合程序设计是一门实践性很强的学科,理论学习和实践应该相互结合。
只有理解了基本的概念和原则,才能更好地进行实践。
因此,推荐在学习过程中将理论知识和实际编程相结合。
一方面,读者可以通过阅读书籍、参与在线课程、观看教学视频等方式获取理论知识;另一方面,可以通过编写小型项目、参与开源项目以及解决实际问题等方式进行实践。
二、建立编程思维编程思维是程序设计学习的核心。
它包括逻辑思考、问题分析和解决能力等方面。
为了培养编程思维,读者可以通过解决逻辑谜题、进行数学推理、参与编程竞赛等方式进行锻炼。
此外,学习数据结构和算法也是培养编程思维的重要途径。
理解数据结构的特点和算法的原理,能够帮助读者更好地解决问题。
三、掌握合适的编程语言程序设计语言是开发程序的工具,选择一个合适的编程语言对于学习和实践都是至关重要的。
对于初学者来说,推荐选择易于学习的语言,如Python、JavaScript等。
这些语言具有简单易懂的语法结构和丰富的开发资源,能够迅速入门,并进行实践。
同时,也应根据自己的兴趣和实际需求,选择适合自己的编程语言。
四、注重源码分析在学习程序设计的过程中,源码分析是一种非常有效的方法。
通过阅读和理解开源项目的源码,可以学习到实际应用场景下的编程技巧和设计思想。
读者可以选择一些知名的开源项目,如Linux、MySQL 等进行分析,同时参与到社区中,与其他开发者进行交流和讨论,提高自己的编程水平。
五、不断实践和练习程序设计学习是一个渐进的过程,需要不断地实践和练习。
通过编写小型项目或解决实际问题,可以巩固之前学到的知识,并提高解决问题的能力。
此外,借助在线编程平台和社区,可以参与编程竞赛和项目实践,与其他开发者共同合作,相互学习和成长。
常见的程序设计方法结构化程序设计方法是一种按照顺序、选择和循环等基本结构来组织程序的设计方法。
它强调模块化设计,将程序划分为多个模块,每个模块负责一个特定的功能,并通过参数和返回值进行交互。
结构化程序设计方法可以提高程序的可读性、可维护性和可重用性。
面向对象程序设计方法是一种将程序看作对象的集合,并通过定义对象的属性和行为来实现程序的设计方法。
它强调封装、继承和多态等面向对象的特性,通过创建类和对象来组织程序的结构。
面向对象程序设计方法可以提高程序的模块化程度,并且具有良好的扩展性和复用性。
3.领域驱动设计方法领域驱动设计方法是一种将程序设计与问题领域建模相结合的设计方法。
它通过深入理解问题领域,将问题领域中的概念和过程进行抽象和建模,然后通过设计模型来实现程序的功能。
领域驱动设计方法可以提高程序的可理解性和可维护性,并且更加贴近实际需求。
响应式程序设计方法是一种以事件驱动和异步编程为基础的设计方法。
它通过定义事件和事件处理函数,实现程序对外部事件的响应和处理。
响应式程序设计方法适用于需要处理多个并发事件的场景,可以提高程序的响应速度和并发性能。
函数式程序设计方法是一种将程序看作函数的集合,并通过定义函数的输入和输出来实现程序的设计方法。
它强调函数的纯粹性和不变性,避免使用可变状态和副作用。
函数式程序设计方法可以提高程序的可测试性和可靠性,并且具有良好的扩展性。
除了上面列举的几种常见的程序设计方法,还有其他一些特定的设计方法,如基于规则的程序设计方法、递归程序设计方法、分布式程序设计方法等。
不同的程序设计方法适用于不同的场景,程序员可以根据实际需求选择合适的程序设计方法来设计程序。
常见的程序设计方法程序设计是指将问题拆解为一系列可执行的指令或算法,并将其转化为计算机能够识别和执行的代码。
常见的程序设计方法包括顺序、选择、循环、递归、分治和动态规划等。
1.顺序:顺序是最简单和最常见的程序设计方法。
顺序程序设计是按照定义的顺序依次执行一系列的语句或指令,每个语句按照顺序执行,直到程序结束。
顺序程序设计常用于简单的计算和数据处理任务。
2.选择:选择是根据特定条件选择不同的执行路径。
常见的选择结构有if语句和switch语句。
if语句根据条件的真假执行不同的代码块,而switch语句根据不同的表达式值执行相应的代码块。
选择结构常用于根据用户的输入或条件的满足来决定程序的执行逻辑。
3.循环:循环是根据特定条件重复执行段代码。
常见的循环结构有while循环、do-while循环和for循环。
这些循环结构可根据循环条件的真假来确定循环的执行次数,从而实现重复执行特定操作的功能。
循环结构常用于处理大量数据或重复需要进行的任务。
4.递归:递归是指在函数或算法的实现中,调用自身来解决更小规模的同类问题。
递归算法是将一个复杂问题分解为更简单的子问题,并通过反复调用自身来解决子问题,最终达到解决原问题的目的。
递归常用于解决具有相似结构的问题,如数学问题、图形问题等。
5.分治:分治是指将问题划分成独立的子问题,对每个子问题进行求解,最后将子问题的解合并成原问题的解。
分治算法的核心思想是将复杂问题分解成多个规模较小且结构相同的子问题,并通过递归地解决这些子问题,最终得到整个问题的解。
分治算法常用于解决问题、排序问题等。
6.动态规划:动态规划是一种将问题划分为重叠子问题并缓存子问题解的方法。
与分治算法不同的是,动态规划算法会通过缓存已求解的子问题的解来避免重复计算,从而提高算法的效率。
动态规划常用于解决优化问题,如背包问题、最短路径问题等。
除以上常见的程序设计方法外,还有一些高级的方法如面向对象编程、函数式编程和事件驱动编程等。
选择结构程序设计选择结构程序设计在程序设计中,选择结构是一种非常重要的控制结构。
通过选择结构,我们可以根据程序的运行情况来决定执行不同的代码块。
选择结构能够实现条件判断和分支选择,为程序的灵活性和可扩展性提供了极大的便利。
本文将介绍选择结构的概念、语法和几种常用的选择结构程序设计方法。
选择结构的概念选择结构是指程序根据不同的条件执行不同的代码块。
在选择结构中,通常会使用条件判断来确定程序执行的路径。
根据条件表达式的返回值(真或假),程序会决定执行真值分支(True branch)或者假值分支(False branch)。
选择结构的出现可以使程序更具有灵活性和可扩展性。
选择结构的语法在大多数编程语言中,选择结构通常有两种形式:`if`语句和`switch`语句。
if语句`if`语句是最基本的选择结构语句。
它可以根据某个条件的真假来执行不同的代码块。
`if`语句的语法如下:```markdownif (condition) {// 如果条件为真,执行这里的代码块} else {// 如果条件为假,执行这里的代码块}```其中`condition`是一个条件表达式,它能够返回一个布尔值(真或假)。
如果`condition`为真,程序会执行`if`后面的代码块;如果`condition`为假,程序会执行`else`后面的代码块。
switch语句`switch`语句是另一种常用的选择结构语句。
它可以根据一个表达式的值,选择性地执行多个代码块中的一个。
`switch`语句的语法如下:```markdownswitch (expression) {case value1:// 如果`expression`的值等于`value1`,执行这里的代码块break;case value2:// 如果`expression`的值等于`value2`,执行这里的代码块break;default:// 如果`expression`的值不等于任何一个`case`中的值,执行这里的代码块break;}````expression`是一个表达式,它的值和`case`后面的值进行比较。
程序设计的三种方法程序设计是指按照一定的设计思路和方法,将问题转化为可执行的计算机程序的过程。
在程序设计中,有多种不同的方法可以用来解决问题。
本文将介绍并比较三种常见的程序设计方法:结构化程序设计、面向对象程序设计和函数式程序设计。
1. 结构化程序设计结构化程序设计是一种将程序分解为较小的、可管理的模块,通过顺序、选择和重复来控制程序的执行流程的方法。
它强调程序的逻辑结构应该清晰、简单、易于理解和修改。
结构化程序设计常用的工具包括顺序结构、选择结构和循环结构。
顺序结构是指程序按照代码的先后顺序依次执行。
选择结构通过条件判断来选择执行不同的代码块。
循环结构则通过控制条件的真假来重复执行一段代码。
这些结构可以相互组合,形成复杂的程序逻辑。
结构化程序设计通过合理地使用这些结构,使得程序的流程清晰可见,易于理解和维护。
2. 面向对象程序设计面向对象程序设计(OOP)是一种将程序中的数据和操作封装成对象的方法。
在面向对象程序设计中,程序被看作是一组相互交互的对象的集合。
每个对象都有自己的状态(属性)和行为(方法),对象之间通过消息传递来进行通信和协作。
面向对象程序设计有四个基本概念:封装、继承、多态和抽象。
封装将数据和操作封装在对象中,使得对象的内部细节对外部不可见。
继承允许通过创建子类来继承父类的属性和方法,实现代码的重用和扩展。
多态允许不同类型的对象对同一消息做出不同的响应。
抽象则将对象的共同特征提取出来,形成类的概念,用于创建对象的模板。
面向对象程序设计通过将现实世界中复杂的问题分解成简单的对象,使得程序的设计和实现更加模块化和灵活。
它强调代码的重用性、可扩展性和可维护性。
3. 函数式程序设计函数式程序设计是一种将程序视为一系列函数的组合,通过函数之间的调用和返回值来实现程序的计算过程。
函数是函数式程序设计的基本单位,它接收输入参数并返回输出结果,不依赖于程序的状态和副作用。
函数式程序设计强调函数的纯粹性和不可变性。
结构化程序设计的方法
结构化程序设计是一种将程序分解为更小的、可管理的子问题的方法,这些子问题可以被独立地测试和调试,最后再组合起来形成完整的程序。
以下是常用的结构化程序设计方法:
1. 顺序结构:按照程序的顺序依次执行语句和操作。
2. 选择结构:根据条件的真假选择不同的执行路径。
常用的选择结构有if语句和switch语句。
3. 循环结构:重复执行某一段代码,直到满足特定条件才停止执行。
常用的循环结构有while循环、do-while循环和for循环。
4. 模块化设计:将程序分解为更小的模块,每个模块负责完成特定的任务。
这样可以提高代码的重用性和可维护性。
5. 层次化设计:将程序分解为多个层次,每个层次负责处理不同的功能和抽象层次。
这样可以使程序更加清晰、易于理解和扩展。
6. 分层抽象:将问题分解为多个层次的抽象,每个层次都只关心当前问题的部分,而不需要了解整个系统的细节。
这样可以简化复杂问题的处理。
7. 自顶向下设计:从整体到细节的方式进行设计,先设计出整体的框架和主要功能,再逐步展开细节。
这样可以使设计更加清晰和全面。
8. 自底向上实现:从细节到整体的方式进行实现,先实现最基本的功能和模块,然后逐步组合成更复杂的功能。
这样可以提高代码的可测试性和可维护性。
以上方法可以结合使用,根据具体问题的需求选择合适的方法来进行程序设计。
在设计过程中,还需考虑代码的可读性、可扩展性、性能等因素,以确保最终的程序符合要求。
程序设计方法选摘选自"从标准Pascal 到Delphi 4.0 —— 计算引论和程序设计基础",张铭,黄维通,北京大学出版社, 1999年1月。
一、穷举法例:猴子分桃子有一堆桃子和甲、乙两组猴子,甲组有3只猴子,乙组有5只。
甲组先看到桃子,第一只猴子把桃子均分成3堆,结果剩下2个,它吃了这两个,又拿了一堆便走了。
第二、第三只猴子亦照样办理。
甲组走后,乙组又看到了桃子,第一只猴子把桃子均分成5堆,结果剩下1个,它吃了这一个,又拿了一堆便走了。
第二、第三、第四、第五只猴子亦照样办理。
8只猴子分别来过之后,至少还剩多少个桃子?原来至少有多少个桃子?分析:最容易想到的是穷举法,桃子的数目一个个地增加,直到猴子能按条件取桃子时为止。
但这样简单的穷举效率太低,我们应该尽量利用已知条件,减少穷举的计算次数。
设原来至少有total个桃子,最后还剩rest个桃子。
我们穷举的模拟方向可以是变化total,直到满足条件为止;也可以变化rest,直到满足条件。
由于rest << total,采用rest作为模拟的变量效率一定更高。
所以可以用“倒退法”,从数据的最后形式出发,反方向模拟。
再者由于最后还剩4堆桃子,也就是最后剩余桃子的数目是4的倍数,rest的变化步长可以是4的倍数,这样数据模拟的速度提高了许多。
由于最后的计算结果是rest=8188,total=84371,超出了标准Pascal的整数范围,所以把它们定义为实型。
我们按拿桃子的顺序把猴子分为第一只到第八只。
最后剩rest个,而rest可以均匀分为4堆,每堆有rest/4个桃子,这个猴子已吃过一堆和另外的一个,所以轮到第八只猴子拿桃子时,共有5*(rest/4)+1个,即rest*5/4+1个桃子。
可利用变量total存放该值,total=rest*5/4+1。
并把total的初值设为rest,则上式改为total=total*5/4+1。
这其实是“迭代法”的算法技巧。
轮到第七只、第六只、第五只、第四只猴子拿桃子时,分别在前述的total计算基础上共有total=total*5/4+1个桃子。
而轮到第三只、第二只、第一只猴子拿桃子时,分别在前述的total 计算基础上共有total=total*3/2+1个桃子。
最后计算出的total结果即为所求解。
值得注意的是,在八次迭代计算total时,如果结果不是整数,则要抛弃,可以用条件“total <> Trunc(total)”来判断。
(此处也可以用“total <> Round(total)”来判断total是否是整数值。
) 算法是一个二重循环,外层循环变量为rest,按步长4递增变化,内层是对取桃子的猴子序数seq从8至1循环,每一步迭代计算total值,直至total不合法(非整数)。
外层循环直至找到合法的total为止。
PROGRAM Peach(Input, Output);VAR total, rest : REAL;seq : INTEGER;BEGINrest := 0;REPEATrest := rest + 4;total := rest;seq := 8;REPEATIF seq >= 4THEN total := total * 5 / 4 + 1 { 第二组猴子}ELSE total := total * 3 /2 + 2; { 第一组}seq := seq - 1;UNTIL (seq < 1) OR ( total <> trunc(total))UNTIL total = trunc(total);Writeln(rest:15:0, total:15:0)END.讨论:请注意程序中的初值赋成了0,因为第一次进入Repeat循环体时,先给rest做了一次增加4的操作。
内层的循环用REPEAT结构比用FOR结构好,因为用FOR结构不便于在发现total不是整数时及时退出内层循环,这样很可能由于累积计算反而使后来的运算修正了小数值,而得出错误的结果。
思考题:1. 编程序解“百钱买百鸡”问题。
这是我国古代一道有名的难题:“鸡翁一,值钱五,鸡母一,值钱三,鸡雏三,值钱一。
百钱买百鸡,问鸡翁、母、雏各几何?”。
意思是说,一只公鸡5元钱,一只母鸡3元钱,3只小鸡一元钱,现有100元钱,要正好买100只鸡,可以买多少只公鸡、母鸡和小鸡各多少只。
2. 韩信点兵。
相传三齐王韩信从不直接清点自己军队的人数,只是让士兵先后以三人一排、五人一排、七人一排地变换队形,而他每次只掠一眼队伍的排尾就知道总数了(不超过100人)。
也就是一个正整数,分别被3,5,7除,余数为k,m,n,求满足此条件的最小数。
“孙子算经”中的口诀是:三人同行七十稀,五树梅花廿一枝。
七子团圆正月半,除百零五便得知。
韩信点兵的快捷方法可以用下列代数式表示:x = 70 * k + 21 * m + 15 * n - 105 * r (r=0,1,2,…)r从0开始以步长1增长,所求得的最小的正整数x则为解。
但是这个方法并不通用。
假设一个正整数n,分别被d1,d2,d3除,余数为r1,r2,r3, (其中d1>r1>=0,d2>r2>=0, d3>r3>=0),且d1,d2,d3的数值(可能为32位十进制数)超出Pascal的整数表示范围(16位二进制计算机系统的整数范围是-32768 ~ 32767)。
编写一个程序,用带表头的循环双链表,能够精确地计算出满足条件的最小正整数。
提示:请参看《从标准Pascal 到Delphi 4。
0 —— 计算引论和程序设计基础》P130提示。
二、回溯法例:八皇后问题。
要求在8×8格的国际象棋棋盘上摆放8个皇后,使其不能互相攻击。
由于皇后的走棋法是可以横走或直走或走斜线,每次走任意格数,所以要求这八个皇后中的任意两个都不处于同一行、同一列或同一斜线上。
问有多少种摆法?分析:这是一个古老的问题,著名的数学家高斯认为有76种方案,后来有人用图论方法解出有92种方案。
如果没有适当的方法,只是简单地采取“穷举法”,8个皇后各占一行,穷举每一行上的皇后所可能占有的列,再排除那些不合条件的情况,只输出合理的解。
那么所有的那么将是8重循环,执行次数为88≈1.7×107次,如果每秒执行7000次循环体,则共需40分钟才能找到所有的解。
为了分析问题方便,我们简化为4皇后问题。
4个皇后可以一行一行地放置。
如果第1行的第一个放置在第1列上,若放置第2个皇后时,也把它放在第1列上,那么我们立即就知道这是非法的,此时第3~第4行的其它2个皇后的82种情况完全不用考虑了。
这时候,我们应该把第2个皇后换一个位置,试试把它放在第2列如何,这一步也不合理;继续试探把第2个皇后换一个位置,放在第3列,这一步成功,可以继续试探第3个皇后。
第3个皇后就没有合适的位置可摆了,那么必须退一步修改第2个皇后的位置,可以把它改为放在第4列;第3个皇后可以放在第2列;但是第4个皇后又没有位置了。
因此有必须去修改第3个皇后的位置,而此时第3个皇后也没有合适的位置,必须回溯修改第1个皇后的位置(第2个皇后已无法修改了)。
…经过反复的试探、回溯,求出4后问题的一个解。
刚才的搜索过程如下:1 1 1 1●● 2 2 2●●●●● 3(a) (b) (c) (d)1 1 1 22 ●●● 2 23 3●●●●●● 4(e) (f) (g) (h)回溯法的主要思想是:“可行则进,不行则换、换不成则退”。
例14.8给出了一般的算法。
如果问题的解能够表达成一个n元组(x1, x2,…,x n),则递归算法可以表示为:PROCEDURE rectry(k);BEGIN置X[k]为第一个可能值;WHILE X[k]可能值没有试完 DOBEGIN设置X[k]所涉及的标记;IF (X[1], X[2],…,X[k]) 是解THEN 打印一组解;ELSE rectry(k+1);回溯,抹去X[k]涉及的标记; { 有无解都回溯}取下一个可能的X[k]值ENDEND;这种算法的非递归形式为:PROCEDURE try(n);BEGINk := 1; 置X[k]为第一个可能值;WHILE (k>0) AND (k<=n) DOBEGINIF 还存在没有试探过的X[k]THEN BEGIN设置X[k]所涉及的标记;IF (X[1], X[2],…,X[k]) 是解THEN BEGIN打印一组解;抹去X[k]涉及的标记{也是回溯} ENDELSE k := k + 1ENDELSE BEGINk := k-1; { 回溯 }抹去X[k]涉及的标记ENDEND { OF 'WHILE k > 0' }END;现在我们可以利用计算机,用“回溯法”来解决。
而且可以方便地推广为n皇后问题。
我们给棋盘的行和列依次编上1, 2,…,8号,同时也给八个皇后也依次编为1至8号。
由于要求每个皇后占有不同的行,可以令占有第i行的皇后编号为i。
于是八后问题的全部解向量就可有形如(x1, x2,…,x8)的8元组来表示。
其中x i表示皇后i所处的列数。
对于任何1≤i,j≤8,及i≠j,有x i≠x j,且没有两个皇后在同一斜线上,这样问题就缩小为在8!个可能解中寻找。
问题的关键就在于怎样判断两个皇后不在同一条斜率为±1 的线上。
八皇后的一个解如下:1 2 3 4 5 6 7 81 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q如果我们用一个二维整型数组A[1..n, 1..n]来表示n×n棋盘上的格,行号从上至下、列号从左到右依次编号为1, 2,…,n。
那么,从左上角到右下角的主对角线及平行线(即斜率为-1的各斜线)上,元素的两个下标值的差(行号- 列号)相等,从左到右的15条直线这种差值分别为7, 6, 5, …,0,-1, -2,…,-7;同理,从右上角到左下角的主对角线及平行线(即斜率为+1的各斜线)上,元素的两个下标值的和(行号 + 列号)相等,从左到右的15条直线的这种和值分别为2, 3, 4, (16)我们从第1行开始,逐步地安排每一行的皇后,每一行的皇后都处于不同的列。
对于每个皇后(设为第i个)的安排,都是从第一列开始寻找位置,逐个查找直到找到正确的位置(设为第j列,则a[j]、b[i+j]、c[i-j]都没有被占用)为止。
如果找到了一个合适的位置,则标记a[j]、b[i+j]、c[i-j]为被占用状态,并继续安排下一个皇后(第i+1个);否则,如果找不到合适的位置,则说明前面的安排不太合理,应该退回(即“回溯”)到第i-1行的皇后,重新安排它。