算法与数据结构讲义三(搜索算法)
《数据结构与算法》PPT课堂课件-集合和搜索

int Set :: Contains ( const int x ) { assert ( x >= 0 && x < MaxSize ); return bitVector[x];
}
Set& Set :: operator + ( Set& right ) { assert ( MaxSize == right.MaxSize ); Set temp ( MaxSize ); for ( int i = 0; i < MaxSize; i++ ) temp.bitVector[i] = bitVector[i] || right.bitVector[i]; return temp;
}
this 0 1 1 1 0 0 0 0 1 1 0
right 0 0 1 0 0 1 0 1 0 1 0
temp 0 1 0 1 0 0 0 0 1 0 0
int Set :: operator == ( Set& right ) { assert ( MaxSize == right.MaxSize ); for ( int i = 0; i < MaxSize; i++) if ( bitVector[i] != right.bitVector[i] ) return 0; return 1;
}
this 0 0 1 1 0 0 0 0 1 1 0
right 0 0 1 0 0 1 0 1 0 1 0 i
int Set :: SubSet (Set& right ) { assert ( MaxSize == right.MaxSize ); for ( int i = 0; i < MaxSize; i++) if (bitVector[i] && ! right.bitVector[i]) return 0; return 1;
数据结构与算法-查找

数据结构与算法-查找目录一、查找的定义二、线性表的查找 2.1 、顺序查找 2.2、二分查找 2.3、分块查找三、树表查找 3.1 、二叉排序树 3.2 、平衡二叉树一、查找的定义查找又称检索,是数据处理中经常使用的一种重要运算。
采用何种查找方法,首先取决于使用哪种数据结构来表示“表”,及表中的数据元素按何种方式组织。
查找有内查找和外查找之分。
若整个查找过程都在内存进行,则称为内查找;反之,若查找过程需要访问外存,则称为外查找。
关键字是指数据元素(记录)中一些项或组合项的值,用它可以标识一个数据元素(记录)。
能唯一确定一个数据元素(记录)的关键字,称为主关键字;而不能唯一确定一个数据元素(记录)的关键字,称为次关键字。
查找表是指由具有同一类型(属性)的数据元素(记录)组成的集合。
分为静态查表和动态查找表。
静态查找是指仅对查找表进行查找操作,而不改变查找表中的数据元素。
动态查找是指除进行查找操作外,可能还要进行向表中插入或删除数据元素的操作。
平均查找长度二、线性表的查找2.1 、顺序查找顺序查找( Sequential Search) 是一种最基本也是最简单的查找方法。
它的基本思想是蛮力法,从表的一端开始,顺序扫描线性表,逐个进行结点关键字值与给定的值k相比较,若当前扫描到的结点关键字与k相等,则查找成功;若扫描整个表后,仍未找到关键字与给定值k相等的结点,则查找失败。
顺序查找方法既适用于线性表的顺序存储结构,也适用于线性表的链式存储结构。
使用单链表作存储结构时,查找必须从头指针开始,因此只能进行顺序查找。
顺序查找代码如下:顺序查找算法的时间复杂度为O(n)。
顺序查找的优点是算法简单,且对表的结构无任何要求,无论用顺序表还是链表来存放结点,也无论结点是否按关键字有序,都同样适用。
顺序查找的缺点是查找效率低,当n 较大时,不宜采用顺序查找。
对于线性链表,只能进行顺序查找。
2.2 、二分查找二分查找( Binary Search)又称折半查找,是一种效率较高的查找方法。
(完整版)《搜索算法》知识点总结

(完整版)《搜索算法》知识点总结1. 搜索算法的概念搜索算法是计算机科学中的一类算法,用于在一个数据集合中查找指定的数据项。
搜索算法的目标是通过最少的计算操作来找到目标数据项,以提高效率。
2. 常见的搜索算法2.1 线性搜索线性搜索是最简单的搜索算法之一,它从数据集合的第一个元素开始逐个比较,直到找到目标数据项或者遍历整个数据集合。
线性搜索的时间复杂度为O(n),其中n为数据集合的大小。
2.2 二分搜索二分搜索是一种高效的搜索算法,它适用于有序的数据集合。
它将数据集合分为两部分,并与目标数据项进行比较,然后根据比较结果确定继续搜索的方向。
通过每次排除一半的数据,二分搜索的时间复杂度为O(log n),其中n为数据集合的大小。
2.3 哈希搜索哈希搜索通过将数据项映射到哈希表中的特定索引位置来进行搜索。
通过哈希函数,可以快速找到目标数据项所在的位置。
哈希搜索的时间复杂度为O(1),但需要额外的存储空间来存储哈希表。
2.4 深度优先搜索深度优先搜索是一种递归的搜索算法,它从起始点开始一直沿着一个路径搜索,直到找到目标数据项或者无法继续搜索。
如果搜索失败,则回溯到上一个节点,并探索其他路径。
深度优先搜索在有向图和无向图中均适用。
2.5 广度优先搜索广度优先搜索是一种逐层扩展的搜索算法,它从起始点开始,先访问所有直接相邻的节点,然后再访问相邻节点的邻居节点。
通过队列数据结构,广度优先搜索可以按层次进行遍历,直到找到目标数据项。
广度优先搜索适用于无权图和加权图。
3. 搜索算法的应用场景搜索算法在各种领域和实际问题中广泛应用,包括但不限于以下几个方面:- 文本搜索:在大规模的文本数据集中查找关键字或短语。
- 图像搜索:根据图像特征找到相似的图像。
- 数据库查询:根据指定条件查询数据库中的记录。
- 路径规划:在地图上找到最短路径或最优路径。
- 推荐系统:根据用户的兴趣和偏好推荐相关的内容。
- 人工智能:在机器研究和深度研究中的搜索空间优化等。
搜索算法

For I:=1 to TotalExpendMethod do(扩展一层子节点)
Begin
New-S:=ExpendNode(Close[closeL].Situation,I);
If Not (New-S in List) then
展速度保持一定的平衡,从而减少总扩展节点的个数,加快搜索速度。
二、分支定界
分支定界实际上是A*算法的一种雏形,其对于每个扩展出来的节点给出一个预期值,如果这个预期值不
如当前已经搜索出来的结果好的话,则将这个节点(包括其子节点)从解答树中删去,从而达到加快搜索速度
的目的。
范例:在一个商店中购物,设第I种商品的价格为Ci。但商店提供一种折扣,即给出一组商品的组合,如果一
1。添加一张节点表,作为反向扩展表。
2。在while循环体中在正向扩展代码后加入反向扩展代码,其扩展过程不能与
正向过程共享一个for循环。
3。在正向扩展出一个节点后,需在反向表中查找是否有重合节点。反向扩展时
与之相同。
对双向广度搜索算法的改进:
略微修改一下控制结构,每次while循环时只扩展正反两个方向中节点数目较少的一个,可以使两边的发
(扩展出的节点从未出现过)
Begin
openL:=openL+1;
Open[openL].Situation:=New-S;
Open[openL].Level:=Close[closeL].Level+1;
For I:=1 to TotalExpendMethod do(扩展一层子节点)
Begin
New-S:=ExpendNode(List[close].Situation,I);
数据结构与算法-查找

数据结构与算法-查找数据结构与算法查找在计算机科学的世界里,数据结构和算法就像是建筑师手中的蓝图和工具,帮助我们有效地组织和处理数据。
而查找,作为其中的一个重要环节,在各种程序和应用中都有着广泛的应用。
当我们面对大量的数据时,如何快速准确地找到我们需要的信息,就成了一个关键的问题。
查找算法就是为了解决这个问题而诞生的。
让我们先从最简单的顺序查找说起。
想象一下,你有一个长长的名单,上面写满了名字,而你要找到其中一个特定的名字。
你会怎么做?最直接的方法就是从名单的开头一个一个地看下去,直到找到为止。
这就是顺序查找的基本思路。
顺序查找不需要对数据进行任何预处理,实现起来非常简单。
但它的效率并不高,特别是当数据量很大时,可能需要检查很多个元素才能找到目标。
不过,在某些情况下,顺序查找还是很有用的。
比如,数据是无序的,而且查找的频率不高,或者数据量比较小的时候。
接下来,我们来看看二分查找。
二分查找就像是在猜数字游戏中,通过不断缩小范围来快速猜出答案。
假设我们有一个已经排好序的数列,要查找一个特定的数字。
我们先比较目标数字和中间的数字,如果目标数字比中间数字大,那就只在中间数字的右边继续查找;如果目标数字比中间数字小,就在左边查找。
通过不断地将查找范围缩小一半,我们能够快速地找到目标数字。
二分查找的效率比顺序查找高很多,尤其是对于大规模的数据。
但它有一个前提,那就是数据必须是有序的。
除了这两种常见的查找算法,还有一些其他的查找方法,比如哈希查找。
哈希查找就像是给数据分配了一个独特的“房间号码”,通过这个“房间号码”,我们可以直接找到对应的数据,而不需要进行逐个比较。
哈希函数是实现哈希查找的关键。
它将数据映射到一个特定的位置,也就是哈希表中的“槽”。
但有时候会出现哈希冲突,就是不同的数据被映射到了同一个“槽”里。
这时候就需要一些解决冲突的方法,比如链地址法或者开放地址法。
在实际应用中,我们需要根据具体的情况选择合适的查找算法。
数据结构 -第12周查找第3讲-二叉排序树.pdf

以二叉树或树作为表的组织形式,称为树表,它是一类动态查找表,不仅适合于数据查找,也适合于表插入和删除操作。
常见的树表:二叉排序树平衡二叉树B-树B+树9.3.1 二叉排序树二叉排序树(简称BST)又称二叉查找(搜索)树,其定义为:二叉排序树或者是空树,或者是满足如下性质(BST性质)的二叉树:❶若它的左子树非空,则左子树上所有节点值(指关键字值)均小于根节点值;❷若它的右子树非空,则右子树上所有节点值均大于根节点值;❸左、右子树本身又各是一棵二叉排序树。
注意:二叉排序树中没有相同关键字的节点。
二叉树结构满足BST性质:节点值约束二叉排序树503080209010854035252388例如:是二叉排序树。
66不试一试二叉排序树的中序遍历序列有什么特点?二叉排序树的节点类型如下:typedef struct node{KeyType key;//关键字项InfoType data;//其他数据域struct node*lchild,*rchild;//左右孩子指针}BSTNode;二叉排序树可看做是一个有序表,所以在二叉排序树上进行查找,和二分查找类似,也是一个逐步缩小查找范围的过程。
1、二叉排序树上的查找Nk< bt->keybtk> bt->key 每一层只和一个节点进行关键字比较!∧∧p查找到p所指节点若k<p->data,并且p->lchild=NULL,查找失败。
若k>p->data,并且p->rchild=NULL,查找失败。
查找失败的情况加上外部节点一个外部节点对应某内部节点的一个NULL指针递归查找算法SearchBST()如下(在二叉排序树bt上查找关键字为k的记录,成功时返回该节点指针,否则返回NULL):BSTNode*SearchBST(BSTNode*bt,KeyType k){if(bt==NULL||bt->key==k)//递归出口return bt;if(k<bt->key)return SearchBST(bt->lchild,k);//在左子树中递归查找elsereturn SearchBST(bt->rchild,k);//在右子树中递归查找}在二叉排序树中插入一个关键字为k的新节点,要保证插入后仍满足BST性质。
算法与数据结构讲课课件

2.模型一旦建立起来,就要选择合适的算法, 并将解题步骤表述出来
3.用计算机语言将步骤转化为计算机可以“读 懂”的计算机程序,即所谓的“编程”
4.进行测试和修改
本章着重讨论解决问题的核心--算法以及 算法的处理对象--数据的结构
递推法
所谓递推法,它的数学公式也是递归的 (如:f(n)=n!=n*(n-1)!=n*f(n-1) )。只是 在实现计算时迭代方向相反。从给定边界 出发逐步迭代到达指定计算参数。它不需 反复调用自己(节省了很多调用参数匹配 开销),效率较高
递推操作是提高递归函数执行效率最有效 的方法,科技计算中最常见
5x+3y+z/3=100
三层循环嵌套
迭代法
重复同样步骤,可以逐次求得更精确的值。这一 过程即为迭代过程
使用迭代法构造算法的基本方法是:首先确定一 个合适的迭代公式,选取一个初始近似值以及解 的误差,然后用循环处理实现迭代过程,终止循 环过程的条件是前后两次得到的近似值之差的绝 对值小于或等于预先给定的误差。并认为最后一 次迭代得到的近似值为问题的解。这种迭代方法 称为逼近迭代
常用流程图符号
开始
结束
(a) 起止框、连接框
A A
输入a,b
(b) 输入输出框
N>10 true
false
(c) 判断框
i+1→i
N为正整数
(d) 处理框
(e) 注释框
(f) 流向线
流程图简明直观、便于交流
N-S图
Nassi和Shneiderman提出了一种符合结构化程序设 计原则的图形描述工具,叫做盒图,也叫做N-S图
数据结构与算法讲义

第十三页,课件共122页
计算机专业学生的必修课程
课程编号
C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11 C12
课程名称
程序设计基础 离散数学 数据结构 汇编语言
算法分析与设计 计算机组成原理
编译原理 操作系统 高等数学 线性代数 普通物理 数值分析
需要的先导课程 编号 无 C1
存储地址 1345 1346 ……. 1400 ……. 1536
存储内容 元素1 元素4
…….. 元素2
…….. 元素3
指针 1400 ∧ ……. 1536 ……. 1346
第二十五页,课件共122页
h
链式存储
1345
元素1 1400 元素2 1536 元素3 1346 元素4 ∧
链接存储结构特点:
顺序存储结构常用于线性 数据结构,将逻辑上相邻 的数据元素存储在物理上 相邻的存储单元里。
顺序存储结构的三个弱点:
1.作插入或删除操作时,需移动大量元数。
2.长度变化较大时,需按最大空间分配。
3.表的容量难以扩充。
存储内容
元素1 元素2
……..
元素i …….. 元素n
第二十三页,课件共122页
h
第三十五页,课件共122页
顺序存储结构示意图(顺序表):
首地址
起始地址
存储地址 内存状态
b
元素a1
基地址
b+m
元素a2
……..
b+(i-1)*m
元素ai ……..
b+(maxlen-1)*m
元素an
Loc(元素i)=b +(i-1)*m
第三十六页,课件共122页
算法与数据结构查找详解演示文稿

算法与数据结构查找详解演示文稿一、引言在计算机科学中,算法与数据结构是两个非常重要的概念。
算法是指解决问题的步骤或方法,而数据结构则是组织数据的方式。
在算法中,查找是一种常见的操作,它用于在给定的数据集合中寻找特定的元素。
二、线性查找1.基本思想线性查找是最简单和直观的查找方法。
它从数据集合的第一个元素开始逐个比较,直到找到目标元素或遍历完整个集合。
2.代码示例```def linear_search(arr, target):for i in range(len(arr)):if arr[i] == target:return ireturn -1```3.复杂度分析线性查找的时间复杂度为O(n),其中n是数据集合的大小。
三、二分查找1.基本思想二分查找也称为折半查找,它只适用于已经排序的数据集合。
具体步骤如下:-将数据集合按照升序或降序排列-取中间元素与目标元素进行比较-如果中间元素等于目标元素,则查找成功-如果中间元素大于目标元素,则在左半部分继续查找-如果中间元素小于目标元素,则在右半部分继续查找-重复以上步骤,直到找到目标元素或左边界大于右边界2.代码示例```def binary_search(arr, target):left = 0right = len(arr) - 1while left <= right:mid = (left + right) // 2if arr[mid] == target:return midelif arr[mid] < target:left = mid + 1else:right = mid - 1return -1```3.复杂度分析二分查找的时间复杂度为O(logn),其中n是数据集合的大小。
四、哈希查找1.基本思想哈希查找利用哈希函数将元素映射到哈希表中。
哈希表是一种数据结构,它将键与值进行映射。
具体步骤如下:-根据哈希函数将目标元素映射到哈希表中的一个位置-如果该位置为空,则目标元素不存在-如果该位置不为空,则遍历查找目标元素2.代码示例```class HashTable(object):def __init__(self):self.size = 100self.table = [None] * self.sizedef hash_func(self, key):return key % self.sizedef insert(self, key, value):index = self.hash_func(key)if self.table[index] is None:self.table[index] = [(key, value)] else:for i in range(len(self.table[index])): if self.table[index][i][0] == key: self.table[index][i] = (key, value) breakelse:self.table[index].append((key, value)) def search(self, key):index = self.hash_func(key)if self.table[index] is None:return Nonefor i in range(len(self.table[index])):if self.table[index][i][0] == key:return self.table[index][i][1]return None```3.复杂度分析哈希查找的平均时间复杂度为O(1),具有很高的查找效率。
搜索算法 PPT

28
深度优先搜索 DFS
• 深度优先搜索就是在搜索树的每一层始 终先只扩展一个子节点,不断地向纵深 前进直到不能再前进(到达叶子节点或 受到深度限制)时,才从当前节点返回 到上一级节点,从其它子节点处继续扩 展前进。
• 这种方法的搜索树是从树根开始一枝一 枝逐渐形成的。英语中用Depth-FirstSearch表示,所以我们也把深度优先搜 索法简称为DFS。
29
1
2
3
4
5
6
7
8
30
1
2
3
4
5
6
7
8
31
1
2
3
4
5
6
7
8
32
1
2
3
4
5
6
7
8
33
1
2
3
4
5
6
7
8
34
1
2
3
4
5
6
7
8
35
1
2
3
4
5
6
7
பைடு நூலகம்
8
36
1
2
3
4
5
6
7
8
37
1
2
3
4
5
6
7
8
38
每次搜索指定点,对于其所有未 访问过的近邻,每搜索到一个则先 去搜索其近邻,待对其近邻的 DFS完以后再搜索剩下的那些近 邻。
• 问题的一个可行解就是一条从起始节点 出发到目标状态集合中任意一个节点的 路径。
13
搜索算法课件

搜索算法
如果是深度优先搜索,按最初数据的深度为优先;如果是广度优先搜索,按最初数据 的浅度为优先。也可以根据数据所在的位置和内容导入独立的评价公式,来重新指定 搜索顺序。这就叫做最佳优先搜索。
搜索算法
是贯通程序与人工智能的基础, 是有条不紊地处理数据的符号式算法的典型。
用程序搜索数据、人类在大 脑中回忆、人工智能进行回 忆,时长思考这三者之间的 关系,是比较与考量机器、 人工智能、人类智能的基础。
搜索算法
什么是搜索算法?
搜索算法,是指从给出的数据中寻找指定数据的程序。
例1:从给出的10个数字中找 出最大的数字。 例2:从名字和身高组合的数 据中找到某位同学的身高
搜索的必要性
程序
搜索是程序的基础
只有依靠数据运转,程序才会运行。
人工 智能
搜索是人工智能运用自己知识的 基本能力。
搜索算法
搜索的必要性
人工 智能
搜索是人工智能运用自己知识的 基本能力。
苹果是什么 苹果的样子 苹果的颜色 苹果…… 苹果……
搜索算法需要以数 据的形式和组合来 思考
搜索算法
搜索算法
例:给出数值和顺序
1:假如每一次都按照从 大到小的顺序排列,那 么最大的数据通常会被 放置在一端。
最大
最小
2:给出很多数据时,会 以树状数据保存。使数据 拥有几何学的构造,搜索 会更加容易。
搜索算法
数据结构和搜索算法,是表现“数据和程序之间关系”的基础。 在人工智能领域,这一关系成为叫作“思考与知识表示”的基本构造。
最佳优先搜索
搜索算法的效率,是根据以怎样的顺序搜索数据来决定的。
[极力推荐]搜索算法讲稿(带例题)
![[极力推荐]搜索算法讲稿(带例题)](https://img.taocdn.com/s3/m/af177379168884868762d60a.png)
当程序运行后,输出结果: 当程序运行后,输出结果: 6=1+2+3 28 = 1 + 2 + 4 + 7 + 14 496 =1 + 2 + 4 + 8 + 16 + 31 + 62 + 124 + 248 例题2 一根 厘米长的尺子 只允许在上面刻七个刻度 要能用它量 厘米长的尺子, 例题 一根29厘米长的尺子 只允许在上面刻七个刻度, 出 1~29 厘米的各种长度.试问这根尺的刻度应该怎样选择 ~ 厘米的各种长度.试问这根尺的刻度应该怎样选择? 分析: 分析: (1) 从 1~29 厘米中选择七个刻度的所有可能情况数是: ~ 厘米中选择七个刻度的所有可能情况数是 C= 292826252423 = 299265223= 29262390= 1560780 1234567 (2) 对于每一组刻度的选择都需要判断是否能将 1~29 厘米的各种 ~ 刻度量出来, 例如选择的刻度为: 刻度量出来 例如选择的刻度为 a1,a2,a3,a4,a5a,6,a7 那6 6, 5, 3, 23 10, 9, 7, 4, 19 15, 14, 12, 9, 5, 14 21, 20, 18, 15, 11, 6, 8 28, 27, 25, 22, 18, 13, 7, 1 缺 16,17,24 ( 29 即尺子长度 ) 如果找出了刻度a1, a2, a3, a4, a5, a6, a7 那么我们可以利用其对 如果找出了刻度 也是一组解, 称性 29-a1,29-a2,29-a3,29-a4,29-a5,29-a6,29-a7, 也是一组解 所 的情况. 以求解过程中可仅考虑 a1<a2<a3<a4<a5<a6<a7 的情况.
算法与数据结构第9章 查找

数据表 城市名 Beijing Shanghai Wuhan Xian Nanjing 区号 010 021 027 029 025 说明 首都 直辖市 湖北省省会 陕西省省会 江苏省省会
2. 分块查找 性能: 介于顺序查找和二分查找之间的查找方法。 思路: (1)将数据表R[0..n-1]均分为b块,前b-1块中记录个数为 s=n/b,最后一块即第b块的记录数小于等于s; (2)每一块中的关键字不一定有序,但前一块中的最大关 键字必须小于后一块中的最小关键字,即要求表是“分块有序” 的; (3)抽取各块中的最大关键字及其起始位臵构成一个索 引表IDX[0..b-1],即IDX[i](0≤i≤b-1)中存放着第i块的最大关键 字及该块在表R中的起始位臵。由于表R是分块有序的,所以索 引表是一个递增有序表。
9.2 线性表的查找
在表的组织方式中 ,线性表是最简单的一种。三种在线性表 上进行查找的方法: (1) 顺序查找 (2) 二分查找 (3) 分块查找。 因为不考虑在查找的同时对表做修改 ,故上述三种查找操作 都是在静态查找表上实现的。
查找与数据的存储结构有关,线性表有顺序和链式两种存储
结构。本节只介绍以顺序表作为存储结构时实现的顺序查找算 法。定义被查找的顺序表类型定义如下:
9.2.3 索引存储结构和分块查找
1.索引存储结构
索引存储结构=数据表+索引表 索引表中的每一项称为索引项,索引项的一般形式是: (关键字,地址) 关键字唯一标识一个结点,地址作为指向该关键字对 应结点的指针,也可以是相对地址。
索引表 地址 300 310 320 330 340 关键字 010 021 025 027 029 地址 100 130 210 160 190 地址 100 130 160 190 210
数据结构与算法分析之查找技术PPT课件( 75页)

的数据域存储空间KEY(1:m)与指针域存储空间 K(1:m);被查元素x。 输出:被查元素x在线性表L中的序号j(即使L(j) =x的j)。如果x不在线性表L中,则置j=-1。
9.3 分块查找
PROCEDURE INSERCH(V,n,KEY,K,m,x,j)
9.2 有序表的对分查找
有序线性表在顺序存储结构下的对分查找
输入:有序线性表长度n以及线性表的存储空间V;被查找的元素x。 输出:被查找元素x在有序线性表中的序号k。如果在线性表中不存
在元素x,则输出k=-1。 PROCEDURE BSERCH(V,n,x,k) i=1; j=n WHILE (i<=j) DO
9.4 二叉排序树查找
9.4 二叉排序树查找
插入元素68
9.4 二叉排序树查找
插入元素71
9.4 二叉排序树查找
插入元素77
9.4 二叉排序树查找
插入元素88
9.4 二叉排序树查找
二叉排序树的另一种形态
9.4 二叉排序树查找
由无序序列构造二叉排序树
输入:长度为n的无序序列A(1:n)。
(2)即使是有序线性表,如果采用链式 存储结构,也只能用顺序查找。
9.1 顺序查找
线性表在顺序存储结构下的顺序查找
输入:线性表长度n以及线性表的存储空间V; 被查找的元素x。
输出:被查找元素x在线性表中的序号k。 如果在线性表中不存在元素x,则输出k=-1。
PROCEDURE SERCH(V,n,x,k) k=1 WHILE (k≤n)and(V(k)≠x) DO k=k+1 IF (k=n+1) THEN k=-1 RETURN
搜索算法

类似树的按层遍历,其过程为:首先访问初始点Vi,并将其标记为已访问过,接着访问Vi的所有未被访问过 可到达的邻接点Vi1、Vi2……Vit,并均标记为已访问过,然后再按照Vi1、Vi2……Vit的次序,访问每一个顶 点的所有未被访问过的邻接点,并均标记为已访问过,依此类推,直到图中所有和初始点Vi有路径相通的顶点都 被访问过为止。
(1)减少节点数,思想:尽可能减少生成的节点数
(2)定制回溯边界,思想:定制回溯边界条件,剪掉不可能得到最优解的子树
在很多情况下,我们已经找到了一组比较好的解。但是计算机仍然会义无返顾地去搜索比它更“劣”的其他 解,搜索到后也只能回溯。为了避免出现这种情况,我们需要灵活地去定制回溯搜索的边界。
在深度优先搜索的过程当中,往往有很多走不通的“死路”。假如我们把这些“死路”排除在外,不是可以 节省很多的时间吗?打一个比方,前面有一个路径,别人已经提示:“这是死路,肯定不通”,而你的程序仍然 很“执着”地要继续朝这个方向走,走到头来才发现,别人的提示是正确的。这样,浪费了很多的时间。针对这 种情况,我们可以把“死路”给标记一下不走,就可以得到更高的搜索效率。
Rabin-Karp字符串搜索算法是一个相对快速的字符串搜索算法,它所需要的平均搜索时间是O(n).这个算法 是创建在使用散列来比较字符串的基础上的。
优化
利用回溯算法进行优化:回溯和深度优先相似,不同之处在于对一个节点扩展的时候,并不将所有的子节点 扩展出来,而只扩展其中的一个。因而具有盲目性,但内存占用少。
运算原理
图一搜索算法实际上是根据初始条件和扩展规则构造一棵“解答树”并寻找符合目标状态的节点的过程。所 有的搜索算法从最终的算法实现上来看,都可以划分成两个部分——控制结构(扩展节点的方式)和产生系统 (扩展节点),而所有的算法优化和改进主要都是通过修改其控制结构来完成的。其实,在这样的思考过程中, 我们已经不知不觉地将一个具体的问题抽象成了一个图论的模型——树,即搜索算法的使用第一步在于搜索树的 建立。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第十三课搜索算法12.0 搜索树引例:在一个4*4的棋盘上的左下角有一个马,按照国际象棋的规则,将这个马跳到右上角。
为(4,4)。
按照马的移动规则,假定当前马的位置坐标为(x,y),则移动方法有:(1)x’=x+1; y’=y+2(2)x’=x+1; y’=y-2;(3)x’=x+2; y’=y+1;(4)x’=x+2; y’=y-1;(5)x’=x-1; y’=y+2;(6)x’=x-1; y’=y-2;(7)x’=x-2; y’=y+1;(8)x’=x-2; y’=y-1图中表示:由(1,1)可以跳到(2,3)和(3,2)两个点(其它移动规则由于边界限制无法到达);(2,3)又可以跳到(1,1)、(4,4)、(4,2)、(3,1)四个点,(3,2)可以跳达(1,1)、(1,3)、(2,4)、(4,4)四个点,……。
搜索树:按照数据元素的产生式规则建立起来的数据元素逻辑关系。
特点:(1)数据之间的逻辑关系为一对多。
(2)每个结点数据的下一级子结点是由该结点的产生式规则生成。
(3)目标结点(答案数据)一定在搜索树中能够出现。
(4)对于数据规模较大的问题,搜索树的结点将是海量的。
(5)搜索树可能是无穷无尽的(因为很多结点回重复出现)。
12.1 搜索算法的基本原理:从搜索树中可以看出,一个问题从起始状态,通过穷举的方式建立起搜索树后,目标状态一定能在搜索树中出现。
因此,只要建立起搜索树,就可以在其中搜索到目标状态(数据、路径、位置等)。
搜索算法要解决的问题:产生式规则:由当前状态按照问题的需求和限制,生成新的状态的方法集合。
搜索树的生成和存储:一般采用一边生成,一边搜索;存储方法有:集合、栈。
搜索的方法:按行搜索:即从上到下,逐层搜索双向按行搜索:一边从上往下(起始状态到中间状态),一边从下往上逐层搜索(从目标状态到中间状态),找到相同的中间状态即可。
回朔法搜索:优先向更深层结点查找,走不通则换一条路,无法换则退回到上一层。
搜索状态的减少:在生成搜索树时,对于已搜过的中间状态的再次出现,是否需要再次加入到树中重新搜索。
12.2 广度优先搜索(bfs)又称宽度优先搜索,是一种从搜索树的根结点开始,沿着树的宽度遍历树的结点。
如果所有节点均被访问,则算法中止。
一般用于求从起始状态到目标状态所需的最少步骤数。
算法过程:1、首先将根结点放入队列中。
2、从队首取出一个结点,按照产生式规则逐个生成新的结点数据,对新数据:如果如果是目标结点,则结束算法并返回结果。
如果不是目标结点,则检查它是否已在搜索树中出现过,未出现就将它作为尚未检查过的子结点加入到队列的队尾(特殊情况下,也有已出现过的结点重新入队的)。
3、重复步骤2。
4、若队列为空,表示整张图都检查过了,即目标无法达到,结束算法并返回“找不到目标”的信息。
算法细化:1、用哈希数组判断新生成的结点数据是否已出现过。
2、队列经常要多开一行,记录新结点的父亲(即该结点由上一层的哪个结点扩展而来),用于最后输出过程。
3、如数据规模过大,需要使用循环队列(后果是无法记录父亲)。
算法框架:function creat(i)begincase i of1:creat:=按照第一产生式规则生成新状态数据;2:creat:=按照第二产生式规则生成新状态数据;...end;end;////////////////////////////////////////////////////////////////procedure bfs;beginjoin(起始状态);while not(队空) dobegin当前处理状态:=deq;for i:=第一产生式规则 to 最大产生式规则 dobegin新状态:=creat(i);if 新状态=目标状态 thenbeginprint;exit;endelse if not(haxi[新状态]) thenbeginjoin(新状态);haxi[新状态]:=true;end;end;end;end;空间复杂度:线性队列:O(最大可能状态数)循环队列:O(最大可能状态数/2)时间复杂度:最差情形下,BFS必须寻找所有到可能结点的所有路径。
O(最大可能状态数)完全性:广度优先搜索算法具有完全性。
只要目标存在,则BFS一定会找到。
但是,若目标不存在,且问题规模为无限大,则BFS将不收敛(不会结束)。
适用范围:广度优先搜索是找到第一个解的算法,即距离根结点的边数最少的解。
如果所有边的权值都相等(即所有产生新状态的代价相同),则这个解也是最优解。
例一:将一个马从M*N的棋盘的左下角跳到右上角,需要的最少步数是多少?分析:1、用一个[1..2,1..m*n]的数组作为工作队列,用于存储搜索树。
2、使用m*n的二维哈希数组判重。
3、生成搜索树的同时,记录父节点的序号和新结点的层数。
4、最后从目标结点向起始结点回朔,用一个栈存储回朔的中间状态。
例二:在一个2n+1的一维棋盘上,有n个黑色棋子和n个白色棋子,初始状态如图:Array规定棋子移动规则如下:1、如果某棋子的旁边正好为空,这枚棋子可以移动到空位置上。
2、如果某棋子的一侧有棋子,二那枚棋子的另一侧为空位置,这枚棋子可以跳过那枚棋子到空位置上。
问:最少经过多少步,可以将棋盘状态变成分析:1、用2n+1位三进制数表示状态,如初始状态为:222201111,目标状态为111102222。
转化为十进制进行存储,另记录空格位置。
2、产生式规则:将棋子移动转化为空格的移动。
(1)空格向左移动(2)空格向右移动(3)空格向左跳动(4)空格向右跳动3、用一个[1..3^2n+1]的哈希数组判重。
例三:八数码问题。
在一个3×3的九宫中有1-8这8个数及一个空格随机的摆放在其中的格子里,如图1所示。
现在要求实现这个问题:将该九宫格调整为如图2 所示的形式。
调整的规则是:每次只能将与空格(上、下、或左、右)相邻的一个数字平移到空格中。
试编程实现这一问题的求解。
图二分析:1、字符串表达状态,另开一变量w记录空格位置。
2、空格移动规则:(1)向下移动:w’=w+3。
(2)向上移动:w’=w-3。
(3)向左移动:w’=w-1。
(4)向右移动:w’=w+1。
3、用穷举法判重。
(将来可以用排序二叉树判重)12.3 深度优先搜索(dfs)深度优先搜索是从根结点出发,沿着树的深度遍历树的结点。
如果当前新产生的结点还有以此为根的下一层结点,则沿此路继续下去,直到无法再深入访问时,回朔到上一层的结点,选另一条路继续深入访问。
反复此过程,直到所有结点都被访问到为止。
算法过程:1、首先将根结点放入栈中。
2、取出栈顶结点,按照产生式规则生成新的结点数据,每产生一个:检查是否是目标结点,如果是且比保存的数据更优,刷新所保存的数据。
检查该结点是否已搜过,如果是且比已保存的数据更优,则刷新所保存的数据,然后该结点进栈;如没有搜过,则保存数据并进栈。
3、转第二步。
4、如果栈空,则算法结束。
细化说明:1、一般用回朔法,利用递归使用系统栈。
2、哈希数组不仅用于判断新结点是否出现过,还用于保存到达该结点时的中间数据。
算法框架:procedure dfs(结点数据);var i:integer;beginfor i:=产生式规则一to 最大产生式规则dobegin新结点数据:=creat(i);if (新结点数据没有搜到过)or(新结点数据虽已搜过但本次搜索结果更优)thenbegin更新新结点搜索结果;dfs(新结点数据);end;end;procedure dfs(结点数据);var i:longint;beginfor i:=1 to 最大产生式规则dobegin新结点:=creat(i);if 新结点是目标结点thenbegin传回新结点;t:=true;exit;end;if 新结点更优thenbegin更新新结点数据;dfs(新结点);if t then exit;end;end;end;空间复杂度:O(最大状态数) (主要用于存储各结点搜索结果)时间复杂度:O(最大产生式规则数^最大状态数)深度优先搜索的理论依据是建立在穷举基础上的,所以时间是几何级数级的,其优化剪枝是非常必要的,因此,深搜的主要算法设计是在于如何剪枝,如何既高效地抛弃不必要的子树,又不至于将最优解剪掉,将是深搜的最大难点。
适用范围:在缺乏有效的数学方法、递推算法,不符合动态规划要求,也没有专用算法可以应对,一般考虑使用深搜;得分情况将取决于优化剪枝的技巧(30-100分)。
例一:有A、B、C、D、E 5本书,要分给张、王、刘、赵、钱5位同学,每人只能选1本。
每个人都将自己喜爱的书填写在下表中。
请你设计一个程序,打印出让每个人都满意的所有分书方案。
┌──┬───┬───┬───┬───┬───┐│ │ A│B│C│D│E│├──┼───┼───┼───┼───┼───┤│ 张│ │ │ √ │ √ │ │ 0 0 1 1 0├──┼───┼───┼───┼───┼───┤│ 王│ √ │ √ │ │ │ √ │ 1 1 0 0 1├──┼───┼───┼───┼───┼───┤│ 刘│ │ √ │ √ │ │ │ 0 1 1 0 0├──┼───┼───┼───┼───┼───┤│ 赵│ │ │ │ √ │ │ 0 0 0 1 0├──┼───┼───┼───┼───┼───┤│ 钱│ │ √ │ │ │ √ │ 0 1 0 0 1└──┴───┴───┴───┴───┴───┘分析:1、朴素的穷举法:产生5本书的所有全排列,共有5!=120个,逐个检查各种排列是否符合所有人的要求,符合则输出,否则丢弃。
穷举法的改进:例如产生一个全排列12345时,第一个数1表示将第一本书给小张。
但从表中可以看出,这是不可能的,因为小张只喜欢第三、第四本书。
也就是说,1X X X X这一类分法是不符合条件的。
由此使我们想到,如果选定第一本书后,就立即检查一下是否符合条件,当发现第一个数的选择不符合条件时,就不必再产生后面的4个数了,这样做可以减少很多的运算量。
换句话说,第一个数只在3和4中选择,这样就可以减少3/5的运算量。
同理,在选定了第一个数后,其他4个数字的选择也可以用类似的方法处理,即选择第二个数后,立即检查是否符合条件。
例如,第一个数选3,第二个数选4后,立即进行检查,发现不符合条件,就另选第二个数。
这样就又把34XXX一类的分法删去了,从而又减少了一部分运算量。
3、建立如上搜索树,每一层分发一本书,未向下扩展的结点为当前层已不合理,故剪去。
参考程序:program dfs1;const a:array[1..5,1..5]of boolean=((false,false,true,true,false),(true,true,false,false,true),(false,true,true,false,false),(false,false,false,true,false),(false,true,false,false,true));var outf:text;c:array[1..5]of integer;hx:array[1..5]of boolean;/////////////////////////////////////////////////////////////////procedure print;var i:integer;beginfor i:=1 to 5 docase c[i]of1:write(outf,'张');2:write(outf,'王');3:write(outf,'刘');4:write(outf,'赵');5:write(outf,'钱');end;end;/////////////////////////////////////////////////////////////////procedure dfs(n:integer);var i:integer;beginfor i:=1 to 5 doif (a[i,n])and(not(hx[i])) thenbeginc[n]:=i;if n=5 then print;hx[i]:=true;dfs(n+1);hx[i]:=false;end;end;/////////////////////////////////////////////////////////////////beginassign(outf,'dfs_1.out'); rewrite(outf);dfs(1);close(outf);end.例二:跳马问题:在半张中国象棋盘上(5*9),有一匹马自左下角往右上角跳,今规定只许往右跳,不许往左跳。