您好,欢迎访问三七文档
2010暑假培训7.20~7.26第一阶段主要内容1.枚举算法2.深度优先搜索3.广度优先搜索(BroadFirstSearch)4.双向广度优先搜索5.A*(A-Star)算法6.搜索树7.归并排序8.基数排序9.桶排序1.枚举算法枚举法是最简单的搜索策略,由于它只是将可能取到的值一一列举,所以运算量很大,这是枚举法最大的弱点。在有可能的情况下,采取一定措施进行优化:如:利用加强约束条件改进的枚举算法利用数学分析改进的枚举算法2.深度优先遍历如算法名称那样,深度优先搜索所遵循的搜索策略是尽可能“深”地搜索树。在深度优先搜索中,对于当前发现的结点,如果它还存在以此结点为起点而未探测到的边,就沿此边继续搜索下去,若当结点的所有边都己被探寻过,将回溯到当前结点的父结点,继续上述的搜索过程直到所有结点都被探寻为止。它所实施的数据前提是一个状态树。2.深度优先遍历这是一棵状态树有两个特点:1.结点之间是树状关系2.结点是“状态”3.广度优先遍历广度优先搜索(BFS)与DFS不同,BFS是最先产生的节点,最后扩展。堆栈在这里就不适用了。因此,我们选用队列为BFS的主要数据结构。广度优先会扩展出很多结点,这是一个负面的问题。3.广度优先遍历3.广度优先遍历4.双向广度优先广度优先搜索遵循从初始结点开始一层层扩展直到找到目标结点的搜索规则,它只能较好地解决状态不是太多的情况,承受力很有限。如果扩展结点较多,而目标结点又处在较深层,采用前文叙述的广度搜索解题,搜索量巨大是可想而知的,往往就会出现内存空间不够用的情况。双向搜索和A算法对广度优先的搜索方式进行了改良或改造,加入了一定的“智能因素”,使搜索能尽快接近目标结点,减少了在空间和时间上的复杂度。4.双向广度优先4.双向广度优先5.A*算法我们现在这个主题“搜索”即是对状态空间搜索:如果按专业点的说法就是将问题求解过程表现为从初始状态到目标状态寻找这个路径的过程。通俗点说,就是在解一个问题时,找到一条解题的过程可以从求解的开始到问题的结果。5.A*算法由于求解问题的过程中分枝有很多,主要是求解过程中求解条件的不确定性,不完备性造成的,使得求解的路径很多这就构成了一个图,我们说这个图就是状态空间。问题的求解实际上就是在这个图中找到一条路径可以从开始到结果。这个寻找的过程就是状态空间搜索。5.A*算法常用的状态空间搜索有深度优先和广度优先。有一个很大的缺陷就是他们都是在一个给定的状态空间中穷举。这在状态空间不大的情况下是很合适的算法,可是当状态空间十分大,且不预测的情况下就不可取了。他的效率实在太低,甚至不可完成。在这里就要用到启发式搜索了。5.A*算法启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估,得到最好的位置,再从这个位置进行搜索直到目标。这样可以省略大量无畏的搜索路径,提到了效率。在启发式搜索中,对位置的估价是十分重要的。采用了不同的估价可以有不同的效果。我们先看看估价是如何表示的。5.A*算法我们先看看估价是如何表示的。启发中的估价是用估价函数表示的,如:f(n)=g(n)+h(n)其中f(n)是节点n的估价函数,g(n)实在状态空间中从初始节点到n节点的实际代价,h(n)是从n到目标节点最佳路径的估计代价。在这里主要是h(n)体现了搜索的启发信息,因为g(n)是已知的。如果说详细点,g(n)代表了搜索的广度的优先趋势。但是当h(n)g(n)时,可以省略g(n),而提高效率。5.A*算法启发式搜索其实有很多的算法,比如:局部择优搜索法、最好优先搜索法等等。当然A*也是。这些算法都使用了启发函数,但在具体的选取最佳搜索节点时的策略不同。5.A*算法象局部择优搜索法,就是在搜索的过程中选取“最佳节点”后舍弃其他的兄弟节点,父亲节点,而一直得搜索下去。这种搜索的结果很明显,由于舍弃了其他的节点,可能也把最好的节点都舍弃了,因为求解的最佳节点只是在该阶段的最佳并不一定是全局的最佳。5.A*算法最好优先就聪明多了,他在搜索时,便没有舍弃节点(除非该节点是死节点),在每一步的估价中都把当前的节点和以前的节点的估价值比较得到一个“最佳的节点”。这样可以有效的防止“最佳节点”的丢失。那么A*算法又是一种什么样的算法呢?其实A*算法也是一种最好优先的算法。只不过要加上一些约束条件罢了。5.A*算法先下个定义,如果一个估价函数可以找出最短的路径,我们称之为可采纳性。A*算法是一个可采纳的最好优先算法。A*算法的估价函数可表示为:f'(n)=g'(n)+h'(n)5.A*算法f‘(n)是估价函数,g’(n)是起点到终点的最短路径值,h‘(n)是n到目标的最短路径的启发值。由于这个f’(n)其实是无法预先知道的,所以我们用前面的估价函数f(n)做近似。g(n)代替g‘(n),但g(n)=g’(n)才可(大多数情况下都是满足的,可以不用考虑),h(n)代替h‘(n),但h(n)=h’(n)才可(这一点特别的重要)。可以证明应用这样的估价函数是可以找到最短路径的,也就是可采纳的。我们说应用这种估价函数的最好优先算法就是A*算法。5.A*算法其实广度优先算法就是A*算法的特例。其中g(n)是节点所在的层数,h(n)=0,这种h(n)肯定小于h'(n),所以由前述可知广度优先算法是一种可采纳的。实际也是。当然它是一种最臭的A*算法。5.A*算法关于h(n)启发函数的信息性:h(n)的信息性通俗点说其实就是在估计一个节点的值时的约束条件;如果信息越多或约束条件越多则排除的节点就越多,估价函数越好或说这个算法越好。这就是为什么广度优先算法的那么臭的原因了,谁叫它的h(n)=0,一点启发信息都没有但在有的算法中,由于算法本身的特点,h(n)的信息很多,它的计算量也很大,耗费的时间就很多。就应该适当的减小h(n)的信息,即减小约束条件。但算法的准确性就差了,这里就有一个平衡的问题。6.搜索树在计算机许多应用领域中,查找操作都是十分重要的研究技术。查找效率的好坏直接影响应用软件的性能。比如说:⑴全文检索技术中对文本建立索引之后,对索引的查找效率将决定搜索引擎的质量。⑵mysql数据库的索引就是B+树结构,查找效率极高。⑶WindowsOS的文件系统结构也是采用B+树进行存储的。6.搜索树查找有两大类:静态查找和动态查找。静态查找有如下几种常用:1.顺序查找:大家都知道,最简单的查找方法就是顺序查找(一个接一个得查下去)。这种线性结构的查找效率是最低的,时间复杂度在O(N)数量级,最坏的情况莫过于所有数据都找遍了,还是没找到。(疑惑:难道真的每一个数据都必须找一次吗?)6.搜索树2.折半查找:很显然的一个例子就是利用折半查找(二分查找)法对有序的线性数据进行查找。每一次都找(前一次查找范围的)1/2的部分,查找次数当然就大大减少了。时间复杂度在O(log2N)数量级上。折半查找实际就是一颗二叉树遍历,其中最中间的数据就是二叉树的根。但是问题又来了,如果这个根数据一年才查找一次,而这棵树的叶子数据1秒钟需要查找1W次(考虑数据的查找概率)。这种折半查找的效率又不行了?6.搜索树3.静态最优查找树/次优查找树:考虑到上面折半查找在概率问题下的效率不行,我们就想能不能把折半查找二叉树中概率最大的数据放在根的位置上或者放在离根较近的位置上?基于此,静态最优查找树/次优查找树的思想就是在折半查找二叉树的基础上求解一个带权(数据被查找概率)路径长度最小/近视最小的树。总体上说,静态最优/次优查找树的时间复杂度也在O(log2N)数量级上(特别是在数据具有查找概率的情况下也能保证这个效率)。6.搜索树此外,还有一些别的静态查找结构:索引顺序表的分块查找,线性冲突再散列的hash表的查找等。上面介绍查找表都属于静态查找结构,也就是说当需要查找的数据集合动态变化的时候,这些结构都很不方便。比如:折半查找:当查找过程中没有发现元素A的时候,需要动态添加元素A,此时整个有序表将面临重新排序的问题。6.搜索树静态最优查找树:新增元素不光要重新排序,而且原有的整棵带权路径长度最小值的树也将重建(最优解变化了)。这在代价上是沉重的,这也是为什么静态最优查找树并不适合实际应用的巨大缺陷了。本节要介绍的搜索树等均属于动态查找的范畴。动态查找包括:二叉查找树,平衡二叉树,红黑树,B-树/B+树。6.1二叉搜索树(BST)6.1二叉搜索树(BST)搜索(查找)树(BinarySearchTree),或者是一棵空树,或者是具有下列性质的二叉树:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;它的左、右子树也分别为二叉排序树。6.1二叉搜索树(BST)我们中序遍历这三棵树发现一个有序的数据序列:【12345678】6.1二叉搜索树(BST)二叉查找树的操作比较简单,下面分别介绍。1.插入操作:2.删除操作:3.二叉查找树的效率分析6.1二叉搜索树(BST)总结一下:最坏情况下,构成的二叉排序树蜕变为单支树,树的深度为n,其查找时间复杂度与顺序查找一样O(N)。最好的情况是二叉排序树的形态和折半查找的判定树相同,其平均查找长度和log2N成正比(O(log2n))。这说明:同样一组数据集合,不同的添加顺序会导致查找树的结构完全不一样,直接影响了查找效率。那么如何解决这个问题呢?——平衡二叉树。6.2平衡二叉搜索树(AVL)1.平衡二叉树(AVL——发明者为Adel'son-Vel'skii和Landis)的定义:除了具备二叉查找树的基本特征之外,还具有一个非常重要的特点:它的左子树和右子树都是平衡二叉树,即左子树和右子树的深度之差的绝对值(平衡因子)不超过1。也就是说AVL树每个节点的平衡因子只可能是-1、0和1(左子树高度减去右子树高度)。6.2平衡二叉搜索树(AVL)那么如何是二叉查找树在添加数据的同时保持平衡呢?基本思想就是:①在二叉排序树中插入一个节点;②检查是否因插入而破坏了平衡;③若破坏,则找出其中的最小不平衡二叉树,在保持二叉排序树特性的情况下,调整最小不平衡子树中节点之间的关系,以达到新的平衡。(所谓最小不平衡子树指离插入节点最近且以平衡因子的绝对值大于1的节点作为根的子树。)6.2平衡二叉搜索树(AVL)插入操作:在平衡二叉树中插入结点与二叉查找树最大的不同在于要随时保证插入后整棵二叉树是平衡的。那么调整不平衡树的基本方法就是:旋转。下面我们归纳一下平衡旋转的4中情况:1)绕某元素左旋转分析一下:在插入数据100之前,a图的BST树只有80节点的平衡因子是-1(左高-右高),但整棵树还是平衡的。加入100之后,80节点的平衡因子就成为了-2,此时平衡被破坏。需要左旋转成b图。6.2平衡二叉搜索树(AVL)2)绕某元素右旋转6.2平衡二叉搜索树(AVL)3)绕某元素的左子节点左旋转,接着再绕该元素自己右旋转。此情况下就是左旋与右旋的结合,具体操作时可以分解成这两种操作,只是围绕点不一样而已。6.2平衡二叉搜索树(AVL)4)绕某元素的右子节点右旋转,接着再绕该元素自己左旋转。此情况下就是右旋与左旋的结合,具体操作时可以分解成这两种操作,只是围绕点不一样而已。6.2平衡二叉搜索树(AVL)平衡二叉树性能分析A.平衡二叉树的性能优势:很显然,平衡二叉树的优势在于不会出现普通二叉查找树的最差情况。其查找的时间复杂度为O(log2N)。6.2平衡二叉搜索树(AVL)平衡二叉树的缺陷:(1)很遗憾的是,为了保证高度平衡,动态插入和删除的代价也随之增加。因此,我们在面讲解“红黑树”这种更加高效的查找结构。(2)所有二叉查找树结构的查找代价都与树高是紧密相关的,能否通过减少树高来进一步降低查找代价呢。我们可以通过多路查找树的结构来做到这一点,在后面将讲解“多路查找树/B-树/
本文标题:ACM培训
链接地址:https://www.777doc.com/doc-4853797 .html