收藏 分享(赏)

LUNWEN.DOC

上传人:hwpkd79526 文档编号:7468589 上传时间:2019-05-19 格式:DOC 页数:5 大小:57.50KB
下载 相关 举报
LUNWEN.DOC_第1页
第1页 / 共5页
LUNWEN.DOC_第2页
第2页 / 共5页
LUNWEN.DOC_第3页
第3页 / 共5页
LUNWEN.DOC_第4页
第4页 / 共5页
LUNWEN.DOC_第5页
第5页 / 共5页
亲,该文档总共5页,全部预览完了,如果喜欢就下载吧!
资源描述

1、论程序设计中搜索的优化苏 展(金陵中学初一 6 班)【关键字】程序设计、搜索、时间与空间【摘要】本文作者利用搜索的一般知识结合自身经验,介绍了程序设计中搜索及其优化的一般方法。开始介绍 搜索的方法及其存在的问题,然后重点介绍了作者归纳的一些解决方法,通过时间和空间两部分加以分类。同时,在附录里介绍了 PASCAL对内存空间的分配。一、 引言在一时找不出解决问题的更好途径(指从数学上找到求解公式或规则)时,可以对问题的状态进行逐一的查找,直到找到目标状态或到达目标状态的过程。这种方法叫做“搜索”或“穷举” 。一般情况下, “搜索”是对于问题的状态进行基于队列的广度优先的搜寻。由于它是对问题的所有

2、状态进行搜寻,所以它不易做错,但这也带来了一个问题:对运算的空间与时间带来了很大的压力。由于搜索要对问题的大部分甚至所有状态进行搜寻,要存储它们,必然需要极多的内存空间。就拿“魔板问题”来说吧,它一共有 40320 种状态,最坏情况下,要全部搜索完,恐怕小小的 64K 数据段空间是远远不够的。再则,搜索每一种状态都需要时间,还说“魔板问题” ,在最坏情况下,即便一毫秒搜索两种状态,也要三分钟多。这种等待往往让人难以忍受,在大部分竞赛中,这是拿不到分的。由于上述考虑,我们在程序中需要对搜索进行优化,以解决时间与空间不足的问题。二、 利用队列进行搜索的一般方法利用队列进行搜索一般是解决求一种状态通

3、过几种规定的操作以最少次数变换到另一种状态的方法,本文也是以研究利用队列进行的搜索的优化为主。搜索用队列的数据结构如下:DATA(状态) 初始状态初始状态经A 操作的结果初始状态经B 操作的结果初始状态经两次A 操作的结果OP(由何种操作变换而来) - A B APRE(由何种状态变换而来) 0 1 1 2由于找到目标值后,还需根据 PRE 值回溯得到由初始状态到达目标值的最短序列,所以还要准备一个辅助栈,其元素类型与 DATA 或 OP 一样。下面是 队列头指针 队列尾指针利用队列搜索的一般步骤(设共有 N 种变换操作): 初始状态入队。 I:=1。 对队列首部的状态进行第 I 种操作,存储

4、结果。 检查结果是否出现过,若未出现过,则此结果进队,DATA 记下此结果,OP 记下 I 的值,PRE 记下变换至此结果的元素(即当前队列首部元素)的位置(下标) 。 若结果即为所求,至步骤 若 I=N,队列第一个元素出队,至步骤;否则,I:=I+1,至步骤。 J:=当前元素下标 队列中第 J 个元素的 OP 或 DATA 进辅助栈 若 J1 ,J:= 队列中第 J 个元素的 PRE,至步骤。 全部弹栈,按出栈顺序输出。不过,在搜索过程中, “出队”的元素必须一直保留,不能删除(最后回溯时要用到) 。三、 空间的解决方案 判重“判重”即指判断一个新搜索到的状态以前是否出现过,如出现过就去掉它

5、。判重一般用于用队列进行搜索,而且用队列进行搜索的程序几乎全都用到这种方法。虽然判重需要增加时间,而且一次最多只能去掉一种状态,但这种状态所产生的众多无用状态所浪费的时间与空间将远远大于判重本身所需要的时间。 利用 “免费 ”资源这里的“免费”资源指的是那些不占用空间却可以表示信息的单位。数组下标就是一种完全不占空间的单位。我们往往可以用数组下标来表示所有的状态,这一状态的信息就直接存储在下标所对应的数组元素里,方可大大节省空间。另外,内存地址也是一种免费资源。不过,使用时须小心,万一动了系统的内存,可能会产生意想不到的严重情况。 重复利用举一个不恰当的例子:在没有通自来水的时候,大家用水桶从

6、井里打水;通上了自来水,水桶不要了,可改成垃圾桶(尽管不太合适) 。同理,有时候,变量重复利用,可节省不少空间。比如利用队列搜索,辅助栈会占去不少空间。如果不用辅助栈,将 PRE 再次利用,使它变化方向,反过来指向所变换成的元素,就等于进行了回溯,也就不需辅助栈,节省了空间。但重复利用变量,往往会降低程序的可读性。 使用动态数据类型动态数据类型,其实就是指针类型。因为指针类型占用的是堆空间(有关PASCAL 的内存管理请见附录 PASCAL 的内存分配 ) ,堆空间理论上有 640K之多(一般能用到 289K 左右) ,是栈或数据段空间的十倍,所以使用指针类型可大大缓解空间紧张问题。另外,指针

7、类型可以根据实际需要分配内存空间,比数组更灵活。但是,使用指针类型需要注意几点:指针本身也占空间 不仅指针所指向的资料占空间,指针本身也是占空间的。一个指针将占去四个字节的内存空间。堆空间是以八个字节为一个单位 与硬盘用簇来作为存储文件的最小单位类似,Pascal 也将为每一个指针类型在堆中分配八的整倍数字节(例如 15 个字节的数据类型将占用 16 个字节的堆空间) ,无论指针指向的是字节类型还是数组类型。 利用文件如果其它方法都使用了,空间仍然不够。那么就要考虑使用文件了。硬盘上几十兆的空间任你用,空间问题自然是迎刃而解。但硬盘的访问速度要比内存慢的多,这又容易造成时间不够,所以不到必要时

8、候,不要使用文件。程序中一般是使用类型文件,这是因为类型文件具有较好的灵活性,可以象数组一样快速定位访问文件内容,可以存储任何除文件类型或包含文件类型的构造类型外的任何一种类型。当然,也可使用无类型文件。它的特点是可以从中一次读取一批资料至所需的任何数据类型,适用于高速输入输出及在文件中存储多种数据类型的场合。四、 时间的解决方案 判重就是前面的那个判重。它减少了所需存储的状态,自然减少了搜索的时间。判重是一种既节省空间,又节省时间的算法,应此成为了每个搜索程序中都用到的算法。 分枝定界在搜索中用一些约束条件将一些不必要的状态去掉,以去掉这个状态可能涎生的许许多多种分枝状态,就象砍树一样,故名

9、“分枝定界” 。它在深度优先搜索中效果明显。前面提到的判重实际也是分枝定界。分枝定界也是搜索程序中常用的算法之一。在使用分枝定界的时候, 有时候不但使用题目给出的约束条件,还要从问题中找出隐含的约束条件。例如跳马问题,表面上并未给出任何约束条件,实际上也有不少约束条件,比如棋盘上不能有一个完全封闭(跳不进去)的点、不能同时出现两个只有一个点可跳入的点等等。当然,剪枝的过程也会增加一定时间,所以一个好的约束条件可以大大节省空间与时间,不好的也可能使空间紧张问题火上浇油。 设计估价函数在搜索中,每一步都有很多状态需要搜索,往往状态选得好,就能减少搜索次数,也就减少搜索时间,这一点在深度优先搜索中体

10、现较明显。究竟怎样才能使程序自动选择状态呢?我们需要设计一个估价函数,用它来对每一步搜索作评价,选出应先搜索哪些状态,后搜索哪些状态。怎样设计估价函数是一堆段栈段数据段代码段最大 640K最大约 64K最大约 64K最大约 64K个很值得探讨的问题,它将广泛涉及相关学科的知识,特别是数学的基础知识。深度优先搜索中最常用的估价方法就是检查分支数量,分支较少的就较优。这是因为分支少,一般来说搜索的时间就较少。如果搜索不到,浪费的时间也比较少。它也适用于广度优先搜索,但效果不明显。 牺牲空间,换取时间这个方法一看就明白,不需多讲。它一般通过牺牲空间减少计算量来取得时间。不过,使用这个方法有个小窍门,

11、就是前面曾提到过,指针类型一占就是八个字节,不妨将变量定义成八(或八的倍数)个字节的指针类型,这样既不浪费空间,又减少了时间。 其它的小方面 用递归代替多重循环虽然会增加程序可读性,但会减慢程序运行速度。 如果多重循环用单层循环代替(不增加循环次数) ,可以提高程序速度。五、 结语优化搜索主要是求得减少时间和空间消耗的方案,本文就列举出了几种方案,它们可以帮助大家在搜索中节省不少时间和空间。当然,还有许多种本文所没有举出的方案,它们需要读者自己来发掘。我只希望这几个方案能使大家的搜索程序更快一些、更好一些。当然,要想彻底解决搜索所存在的种种问题,就要利用别的、更好的方法(例如动态规划)替代搜索。这需要大家利用自己的知识与经验来寻求。六、 附录 PASCAL 的内存分配PASCAL 采用堆栈结构管理内存。其内存分配映像略图如下:动态变量动态变量 1动态变量 2局部变量全程变量程序代码PASCAL 内存分配映像略图如图,PASCAL 将指针变量安排在堆中,箭头表示堆向上生长,即先分配的指针地址较靠前,后分配的反之;局部变量安排在栈中,箭头表示栈向下生长,即先来的变量地址较靠后,后来的反之。其它图上均已标出,不必多讲。 参考书目1蒋新儿,算法设计,全国青少年计算机课外活动辅导员培训教材编委会,1996.102姚庭宝、张帜,Turbo Pascal 大全,电子工业出版社,1995.11

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报