程序算法设计论文

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

综上, 我们可以发现, 深度优先遍历和广度优先遍历两种算法有着十分明显的优点——易于 理解和实现, 以上面提到的几个问题为例, 只要我们能够理解题目要求并能够清晰地将递归 关系以程序语言实现, 那么问题基本上可以迎刃而解。 但是这两种算法的缺点也是显而易见 的,那就是运算量大,耗时极长。以《N 皇后问题》为例,当皇后数目在 8-10 个时,计算 机尚可较为快速的完成求解,当其规模达到 13 个皇后时,计算时间已经达到了近 10 秒,而 当规模进一步扩大时, 计算时间更是几何倍数的增长, 于是这就对我们的算法提出了进一步
浅谈递归与几种搜索在程 序设计中的应用
暨程序设计专题训练结业论文
南京航空航天大学 10 级计算机软件培优班 041040124 马晓林 指导教师:刘邵翰
摘要
本文主要按照我的认知顺序,并结合实际应用案例分别就深度优先遍历、广 度优先遍历、记忆化搜索的概念、优缺点、实现方法等简单的谈了自己的理解, 并将几种算法进行了比较。
优化要求。在我们进一步研究时容易发现,在这两种算法的执行过程中,由于函数递归的使 用, 出现了极多的重复子问题, 即同一状态对应的运算结果在不同的求解过程中需要重复计 算。这方面最典型的例子就是斐波那契额数列的计算过程,在计算a4 时,我们需要计算一次 a3 =a2 +a1 =1+1=2, 在计算a5 时我们因为需要a4 和a3 的值, 所以我们又需要再计算两次a3 的值, 同理当我们计算a6 时,我们需要共计 3 次计算a3 的值,计算a7 时,调用结果的次数就达到了 5 次,在计算第 10 项、第 30 和第 40 项项时,调用a3 的次数就分别达到了 21 次、317811 次和 39088169 次。可见随着下标的不断增大,对a3 结果的调用次数将会飞速的增长。于是 我们自然想到了将那些需要重复使用的中间计算结果储存下来, 以便让计算机在需要调用这 些结果时只需直接提取结果而不需要再次计算。这种想法就是记忆化搜索思路的核心。
3 记忆化搜索 ○
记忆化搜索是在以上基础算法的基础上大大的进行优化的一种算法, 他通过一定的方法对已 经运行过的结果进行“记忆” ,避免了大量的重复计算,从而数以亿计倍的极大程度的减小 了程序的计算规模,缩短了运行时间,应用价值十分重大。 如上文所述,该算法核心是将需要多次使用的中间计算结果储存在一个专门的数组中, 在每次计算时先在该数组中对该结果进行搜索,若能够找到则直接调用储存的结果。 以《N 皇后问题》为例,在解题过程中,当计算 13 皇后问题时,在线评判系统会判定 其计算超时。但是当我们使用动态规划对改程序进行一定改进时,问题就迎刃而解了。 先举一个简单的例子来说明记忆化方法对提高递归函数运算效率的巨大作用。 仍然是计 算斐波那契额数列,其求解函数 fun 如下: int f[1000]={0}; int fun(int n) { int x; if (f[x]!=0) return f[x]; if(n==1||n==2) x=1; else x=fun(n-1)+fun(n-2); f[n]=x; } 显然, 以上函数对于数列中具有相同下标的项仅仅进行了一次求解, 这就极大的提高了 运算效率。 实践证明, 在求解a240 时该方法的运算时间仅仅是普通递归的百亿分之一数量级。 刚刚的斐波那契额数列求解仅仅是使用了记忆化方法,并没有体现其再搜索中的应用, 所以并不能算作是记忆化搜索。 那么下面请看一个较为复杂的真正的记忆化搜索案例: 求解 最长公共子序列问题。其主要递归函数 calc 如下: int a[1000][1000] return x; //用于存放已经求出的结果
if ( [i+dx[v],j+dy[v] 该点点可以到达,并且在迷宫内 dfs(i+dx[v],j+dy[v],k+1); } } 注:dx 和 dy 为代表四个行进方向的方向向量横纵坐标
2 广度优先遍历 ○
顾名思义, 广度优先遍历就是优先向同级的广度方向延伸的一种搜索算法, 其核心是每次优 先走同一级的分支, 在同一级分支走完后在向下一级深入, 最终综合的问题要求, 求得结果。 因为在此算法中大多使用“队列”这一概念和方法,所以该算法在处理和寻找最优解时有着 DFS 所无法比拟优势。仍然以迷宫问题为例,程序大体如下: head = tail = 0; while(head <= tail) { (x,y) = q[head]; for (v=0; v<4;v++) { getnew(xx,yy); if (xx,yy 不重复) { if (xx,yy) == 终点 {输出; 结束;} tail++;(xx,yy)入队; } } head++; } //判断是否存在重复情况
int calc(int i, int j) { int x = 0; if (a[i][j] != 0) return (a[i][j]); if (i==0 || j==0) return 0; x = max(calc(i - 1, j), x); x = max(calc(i, j - 1), x); if (str1[i-1] == str2[j-1]) x = max(calc(i - 1, j - 1) + 1, x); a[i][j] = x; return x; } 虽然记忆化搜索在计算时间和计算效率上相对于一般的算法有了巨大飞跃, 但是考虑到 其执行过程中的递归的不断调用, 我们还是能够发现其中比较明显的问题。 那就是在递归时 需不断的对栈中的数据进行读取和写入, 并因此有着极大的开销。 所以在我们解决问题的过 程当中,在递推的动态规划较为容易实现时,还是应该尽量使用递推以提高程序效率。 最后,感谢刘邵翰老师在本学期对我和我们班同学的悉心教导与辛勤付出!
1 深度优先遍历 ○
深度优先遍历顾名思义就是优先向深处延伸的一种搜索算法, 其核心是将每一个分支情况一 直走到尽头而后在考虑其他分支,最终比较求得满足问题要求的解Fra Baidu bibliotek以迷宫问题为例,本题 在思路上就是自出发点开始, 向不同方向的满足条件的下一个点前进, 直到到达目的地为止。 深搜 dfs 函数如下: void dfs(int i,int j,int k) { int v; if (i==m && j==n) printf(“可以到达指定地点\n”); else { for (v=0; v<4; v++)
关键词
递归 遍历 动态规划 图论 搜索 广度优先遍历 效率 算法优化 深度优先 重复字问题 记忆化搜索
浅谈递归与搜索在程序设计中的应用 暨程序设计专题训练结业论文
本学期的程序设计算法专题训练主要集中在递归递推算法的使用, 并以此为基础对深度 搜索、广度搜索、动态规划以及记忆化搜索进行了一定的研究。下面我将按照我对这一系列 算法的认知先后顺序谈谈我对它们的理解。 在这门课最开始, 我们首先更加深入的理解了递归算法运行背后的原理和关于图论的基 本知识。我认为这两部分知识是之后学习的基础,意义十分重大。首先,如深度、广度搜索 等算法是完全基于递归而完成的, 所以只有掌握好递归才能真正学好这门课。 而对于谈到图 论, 由于这是一门深奥广博的学科, 而我们仅仅学到了皮毛的皮毛, 我在这里也就不再累述, 我仅仅在这里重申,在今后解决问题的过程中,我们大多需要将问题转化成图,然后再通过 各种算法加以解决。 下面我将通过实际应用案例(你在哪、N 皇后问题、迷宫问题、最长子序列问题)分别 就深度优先遍历、广度优先遍历、记忆化搜索简单的谈一下自己的理解。其中,由于老师在 上课时已经比较详细、清晰的讲解过深度优先遍历与广度优先遍历,所以在此仅简单介绍。 而对于上课未曾系统提及的记忆化搜索,我将进行较为详细的阐述。
相关文档
最新文档