1搜索框架-Search
Android搜索框架提供两种搜索输入模式,第一种是搜索对话框(search dialog),第二种是搜索插件(search view)。不论使用哪种方式,Android系统都会通过一个指定的Activity 去执行查询,并显示搜索结果。
通过这两种搜索模式,你可以:
1.启用语音搜索
2.根据最近用户的查询提供搜索建议
3.根据应用程序的数据,匹配实际的搜索结果来提供搜索建议
4.在系统级的快速搜索框中,提供应用程序搜索建议
1.1创建搜索接口
为应用程序添加一个搜索接口,一般需要做3步工作:
1.创建一个搜索配置文件
2.创建一个执行搜索的activity
3.显示搜索结果
1.1.1 基本概念
1.1.2 创建搜索配置文件
第一步需要做的就是创建一个搜索配置文件,习惯上命名为searchable.xml,并且必须放在res/xml文件夹下。
searchable.xml主要描述了搜索对话框或搜索插件的UI方面的参数,以及配置搜索建议和语音搜索等特点。
注:系统在使用这个配置文件的时候,将其转换成SearchableInfo对象,你不能再运行时自己创建这个对象,必须写成xml文件。
searchable.xml必须以
源,应与应用程序同名。android:label的值对用户是不可见的,除非你为快速搜索框启用搜索建议,label的值才会在系统settings->search->searchable item中可见。
?android:hint string resource,搜索框内的提示,例如:搜索歌曲和歌手。
?android:searchMode keywords当自定义的建议获得焦点的时候,查询文本如何变化。
value:”queryRewriteFromText”----使用SUGGEST_COLUMN_TEXT_1
字段的值重写查询文本。
“queryRewriteFromData”----。
?android:searchButtonText string resource,
?android:inputType 定义输入法,例如:textAutoComplete
?android:imeOptions 输入法的附加选项
?android:searchSuggestAuthority
?android:searchSuggestPath
?android:searchSuggestSelection
?android:searchSuggestIntentAction
?android:searchSuggestIntentData
?android:searchSuggestThreshold
?android:includeInGlobalSearch
?android:searchSettingsDescription
?android:queryAfterZeroResults
?android:voiceSearchMode
?android:voiceLanguageModel
?android:voicePromptText
?android:voiceLanguage
?android:voiceMaxResults
为搜索结果定义一个快捷键行为。例如:在联系人中按“搜索”按钮,搜索到符合条件的联系人后,当某一条数据获得焦点时,按“呼叫”键就会呼叫该联系人。
并不是所有设备上的快捷键都有效,也不一定所有的快捷键都允许以这种方式使用。
例如:Home键
此节点必须定义android:keycode属性,并且至少定义其他3个属性中的一个。
?android:keycode常量,键值,封装在KeyEvent类中,例如:KEYCODE_CALL
?android:queryActionMsg 当用户输入查询条件的时候按到了快捷键,此动作消息将会放到Intent中,然后发送到searchable activity,在searchable activity 中通过getStringExtra(SearchManager.ACTION_MSG)获得此消息
?android:suggestActionMsg当某一搜索结果获得焦点的时候,用户按下快捷键,此值将被放到Intent中,然后发送到searchable activity, 通过getStringExtra(SearchManager.ACTION_MSG)获得。此属性仅仅用在所有的建议都支持此快捷键,否则用android:suggestActionMsgColumn代替此属性。
?android:suggestActionMsgColumn
1.1.3 创建搜索Activity
一个可搜索的activity就是指一个能够基于查询条件进行搜索并把搜索结果显示出来的activity。
当用户执行一个搜索的时候,系统会通过Intent启动searchable activity,该Intent的action为ACTION_SEARCH,searchable activity通过SearchManager.QUERY从Intent中获得查询条件。
1.1.3.1 声明searchable activity
1.添加ACTION_SEARCH
2.
android:reource属性表示引用搜索配置文件。
注:searchable activity的 android:name=”android.intent.category.DEFAULT”/>,因为系统在启动searchable activity的时候使用的是显式Intent。 1.1.3.2执行搜索 1.获取查询条件 2.搜索数据 3.显示搜索结果 1.1.3. 2.1获取查询条件 action为ACTION_SEARCH的Intent总是包含字符串数据SearchManager.QUERY; 1.1.3. 2.2搜索数据 根据保存数据的方式不同,分为: a.数据存在本地数据库 b.网络数据 1.1.3. 2.3显示搜索结果 一般使用ListView进行显示。 1.1.4 使用搜索框 搜索框是一个浮动的、带有应用程序图标的输入框,可提供搜索建议。当用户执行搜索的时候,系统跳转到searchable activity进行搜索数据、显示。Android3.0及以上版本支持search widget。 搜索框一直处于隐藏状态,知道用户按下“search”按钮激活,或者调用onSearchRequested()方法。 为一个activity指定searchable activity,需要在Mainfast.xml中添加 注:searchable activity默认为自己提供搜索框,所以不需要添加 如果想为应用中的每一个activity都启用搜索框,则为 1.1.4.1激活搜索框 通过在activity中调用onSearchRequested激活搜索框,或者按“search”按钮。 1.1.4.2搜索框对activity生命周期的影响 搜索框对activity的声明周期无影响(activity堆栈、onPause),只是在搜索框激活的时候,activity失去输入焦点。如果你想在搜索框激活的时候做一些操作,如:暂停游戏,重写activity的onSearchRequested方法: 当用户按下“返回”按钮的时候,取消搜索,搜索框消失,activity获得输入焦点,如果想在搜索框消失的时候做一些操作,如:继续游戏,为SearchManager添加监听器: 调用SearchManager的setOnDismissListener()或者setOnCancelListener()注册监听器。onDismissListener在搜索框每次消失时都触发,onCancelListener只有在搜索框真正消失并退出的时候触发。 如果当前的activity不是searchable activity,执行搜索的时候,当前activity的声明周期为onPause,onStop….. 如果当前的activity是searchable activity,再次执行搜索的时,一个新的searchable activity 实例被创建,并放于stack顶部,这样stack中就会有两个searchable activity实例。所以,searchable activity的启动模式一般设为singleTop,这样当再次执行搜索的时候,不会创建新的searchable activity实例,而是条用onNewIntent方法。 1.1.5 使用搜索插件 1.1.6添加语音搜索 1.2 添加最近查询建议 在使用搜索框的时候,你可以提供基于最近的搜索条件的建议。 1.2.1基本概念 当用户点击一个查询建议的时候,系统就会通过ACTION_SEARCH Intent启动searchable activity。 为了提供最近的查询建议功能,你需要做以下3步: 1.实现一个searchable activity 2.创建一个继承自RecentSuggestionsProvider的类,并在Manifest.xml里声明 3.修改搜索配置文件 4.每一次搜索的时候保存查询条件到provider。 当系统提供一个查询建议的时候,系统执行的程序流是: 1.系统根据用户的输入,从content provider中查询符合条件的建议。 2.content provider返回一个指向所有符合条件的建议Cursor对象。 3.系统根据content provider返回的Cursor 显示查询建议。 当查询建议显示出来的时候,可能会发生以下的事情: 1.如果用户改变了查询条件,则以上3个步骤重复执行,并更新建议列表。 2.如果用户执行搜索,系统通过正常的ACTION_SEARCH Intent跳转到searchable activity 3.如果用户选择一个建议,系统把查询建议放到ACTION_SEARCH Intent中,然后跳转 到searchable activity。 1.2.2创建一个ContentProvider 创建一个Content provider,继承自RecentSuggestionsProvider,该类已为你做好大多数工作,你需要做的就是添加一个构造方法,和一行代码,如下: 通过setupSUggestions()方法,传入AUTHORITY和数据库模式。MODE必须包含DATABASE_MODE_QUERIES,另外可以包含DATA_BASE_2LINES,在一个建议里面提供两行数据。 在Manifest.xml中声明CotnentProvider 1.2.3修改搜索配置文件 为搜索配置文件中的 android:searchSuggestSelection的值必须是一个问号,并且在前面加1个空格,在执行查询的时候会被查询条件替换。 1.2.4保存搜索条件 通过调用SearchRecentSuggestionsProvider的saveRecentQuery方法保存查询条件,当数据库模式为DATABASE_MODE_QUERIES的时候,第一个参数即为查询条件;当数据库模式为DATABASE_MODE_QUERIES|DATABASE_MODE_2LINES的时候,第二个参数作为建议的第二行数据。 1.2.5清空搜索建议数据 1.3 添加自定义查询建议 在使用搜索对话框或搜索插件的时候,你可以根据应用程序的数据自定义查询建议,也可以为其他应用程序提供查询建议。 1.3.1 基本概念 当用户选择一个自定义搜索建议的时候,系统会发送Intent到searchable activity。一般,Intent的类型是ACTION_SEARCH,你可以为自定义的搜索建议定义Intent,比如ACTION_VIEW 类型的或其他任何类型。 要提供一个自定义的搜索建议,必须实现以下几步: 1.实现一个searchable activity 2.修改搜索配置文件 3.为建议创建一个表,并且使用需要的字段格式化这个表 4.创建一个content provider,用来访问包含建议数据的表,并且在Manifest.xml中声 明 5.当用户选择一个自定义建议的时候,定义要发送的Intent的类型,包括自定义 ACTION和自定义DATA 当用户输入查询文本的时候和建议显示之后的事件流参照“1.2添加最近查询建议”。 1.3.2 修改搜索配置文件 1.3.3 创建ContentProvider 提供搜索建议的ContentProvider与普通的ContentProvider没什么不同,但是包含在Cursor中的每一行建议数据,必须包含系统能够识别、且能够用来格式化搜索建议的列。 用户每输入一个字符,系统就会调用一次ContentProvider的query()方法,并返回指向结果的Cursor。 1.3.3.1处理建议查询——系统如何发送请求到ContentProvider,及如何处理 系统请求ContentProvider的时候,调用其query()获得建议数据。所以,你必须在query()方法中实现查询,并返回Cursor对象。 下面是传入query()方法中的URI参数小结: uri 默认的行为是传入这样一个URI,并把查询文本添加到URI里,如下: optional.suggest.path只有在搜索配置文件中设置android:searchSuggestPath的时候存在,只有当多个searchable activity同时使用一个contentProvider的时候才有意义。 projection 始终为null selection 搜索配置文件中android:searchSuggestSelection属性的值,如果没有此属性则为null selectionArgs 字符串数组,如果声明了android:searchSuggestSelection属性,则为仅包含查询文本的字符串数组,如果为声明android:searchSuggestSelection则为null。 sortOrder 始终为null 系统可通过两种方式发送查询文本: 1.系统默认把查询文本放到URI中 2.通过设置android:searchSuggestSelection属性,selectionAgrs中的第一个元素即为查 询文本 获得查询文本的方法: 提示:如果不想使用selection参数,但又想从selectionArgs中获得查询文本,你可以为android:searchSuggestSelection提供一个非空的值,这样你就可以从selectionArgs中获得查询文本,又不必去管selection参数。通过这种方式,你可以替代定义实际的selection子句,为了不让contentprovider去处理它。 1.3.3.2建立建议数据表——如何定义系统期望在Cursor中返回的列 系统返回指向建议数据集的Cursor的时候,系统期望每行数据包含指定的列。所以,不论你的数据存在什么地方,必须按照系统期望的格式格式化每行数据,最终返回Cursor。 系统能够解释多个列字段,只有两个是必须的: ?_ID 一个Integer类型的唯一标识符,在ListView中显示建议的时候需要 ?SUGGEST_COLUMN_TEXT_1 字符串类型,用来显示建议 以下字段为可选字段: ?SUGGEST_COLUMN_TEXT_2 字符串类型,如果Cursor包含这个字段,则建议会以两行的格式显示,该字段对应的值会显示在SUGGEST_COLUMN_TEXT_1字段对应的值下边,并以小字体显示,可以为null。 ?SUGGEST_COLUMN_ICON_1 图片资源或文件的URI,如果Cursor包含此字段,则建议会以ICON加文本的形式显示,ICON在文本的左边,可以为null。 ?SUGGEST_COLUMN_ICON_2 图片资源或文件URI,如果Cursor包含此字段,则建议会以ICON在文本的右边的形式显示,可以为null。 ?SUGGEST_COLUMN_INTENT_ACTION 字符串类型,如果该字段存在且包含一个值,那么用户选择此建议的时候发送的Intent的action为此字段对应的值。如果该字段不存在,则action为android:searchSuggestIntentAction属性的值。如果每一个建议对应的Intent 的action都相同,为了提高效率,建议使用android:searchSuggestIntentAction。 ?SUGGEST_COLUMN_INTENT_DATA URI数据字符串,同SUGGEST_COLUMN_INTENT_ACTION。 ?SUGGEST_COLUMN_INTENT_DATA_ID URI路径字符串,如果存在并包含一个值,”/”和该字段的值将被添加到Intent的data字段。仅在android:searchSuggetIntentData属性被赋值的时候起作用。 ?SUGGEST_COLUMN_INTENT_EXTRA_DATA ?SUGGEST_COLUMN_QUERY ?SUGGEST_COLUMN_SHORTCUT_ID ?SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING 1.3.4 声明Intent 当用户选择一个建议的时候,系统会发送一个自定义的Intent到searchable activity,所以必须声明Intent的action和data。 1.3.4.1声明Intent的action 最常用的action为ACTION_VIEW,也是当你想打开某些东西的时候较合适的,也可以为其他任意action。 基于是否为每一个建议对应的Intent都设置相同的action,有两种设置方法: 1.在搜索配置文件中设置 SUGGEST_COLUMN_INTENT_ACTION指定的值会覆盖掉android:searchSuggestIntentAction的值。 注:如果没有指定android:searchSuggestIntentAction属性,则必须为每一个suggestion指定SUGGEST_COLUMN_INTENT_ACTION字段的值,否则Intent会失败。 1.3.4.2声明Intent的data 当用户选择一个suggestion时,系统会发送一个Intent到searchable activity,这个Intent 的action之前已经讨论过,为了能让activity知道哪个suggestion被选中了,Intent中必须要有一个能够唯一标识一个suggestion的data,例如,一般是数据表中的ID字段。可以通过getData()或getDataString()获得这个data。 有两种方式定义Intent中的data: a.通过SUGGEST_COLUMN_INTENT_DATA为每一个suggestion定义一个data 提示:最简单的方式是使用数据表中的ID字段作为data,因为它是唯一的。而且最简单的方式是使用SUGGESTION_INTENT_DATA作为ID的一个别名。 b.把URI分成两部分:公共的部分是为所有的suggestion,唯一的部分对应一个 suggestion。然后把公共的部分放到android:searchSuggestionIntentData属性中,唯一的部分放到SUGGESTION_COLUMN_INTENT_DATA_ID字段。 例如: 当用户选择一个suggestion的时候,系统从android:searchSuggestionIntentData中取 出URI的公共部分,然后加上”/”,然后再加上SUGGEST_COLUMN_INTENT_DATA_ID 字段的值。可以通过getData()获得URI。 如果想在Intent中添加更多的数据,可以为添加 SUGGEST_COLUMN_INTENT_EXTRA_DATA字段,附加的数据会保存在键 SearchManager.EXTRA_DATA_KEY对应的值中。 1.3.5 处理Intent 注意:不需要在Manifest.xml中为searchable activity中的intent-filter添加android:searchSuggestIntentAction属性中定义的action或SUGGEST_COLUMN_INTENT_ACTION 字段对应的action,因为系统通过显式Intent启动searchable activity。 1.3.6 重置查询文本 默认情况下,在用户使用方向键或轨迹球选择suggestion的时候,搜索文本框中的文本是不变的。但是可以通过以下几步使得文本框中的查询文本随suggestion焦点的改变而改变: a.设置android:searchMode属性的值为”queryRewriteFromText”,这种情况下, SUGGESTION_COLUM_TEXT_1字段对应的值显示在搜索框。 b.设置android:searchMode属性的值为”queryRewriteFromData”,这种情况下, SUGGESTION_COLUMN_INTENT_DATA字段对应的值显示在搜索框中。这种情况一般用在DATA是URI或HTTP URL的时候。 c.为SUGGEST_COLUMN_QUERY字段提供一个唯一的字符串值,这个值将会显示在搜索框 中,并且会覆盖上面两种情况。 1.3.7 暴漏搜索建议给快速搜索框 为了让系统快速搜索框架能够使用你自定义的搜索,设置android:includeInGlobalSearch 为true即可。 当你的ContentProvider的需要一个读的权限的时候,为 在这个例子中,provider限制了/search_suggest_query路径下的读和写的权限。android:readPermission=”android.permission.GLOABLE_SEARCH”表示,系统搜索框架在/search_suggest_query路径下具有读的权限。 如果provider为设置读写权限,则系统搜索框架默认拥有对provider读的权限。 1.3.7.1启用suggestions settings→search→searchable items→app 为searchable item添加描述: 深度优先与广度优先 (一)深度优先搜索的特点是:(1)从上面几个实例看出,可以用深度优先搜索的方法处理的题目是各种各样的。有的搜索深度是已知和固定的,如例题2-4,2-5,2-6;有的是未知的,如例题2- 7、例题2-8;有的搜索深度是有限制的,但达到目标的深度是不定的。但也看到,无论问题的内容和性质以及求解要求如何不同,它们的程序结构都是相同的,即都是深度优先算法(一)和深度优先算法 (二)中描述的算法结构,不相同的仅仅是存储结点数据结构和产生规则以及输出要求。(2)深度优先搜索法有递归以及非递归两种设计方法。一般的,当搜索深度较小、问题递归方式比较明显时,用递归方法设计好,它可以使得程序结构更简捷易懂。当搜索深度较大时,如例题2- 5、2-6。当数据量较大时,由于系统堆栈容量的限制,递归容易产生溢出,用非递归方法设计比较好。(3)深度优先搜索方法有广义和狭义两种理解。广义的理解是,只要最新产生的结点(即深度最大的结点)先进行扩展的方法,就称为深度优先搜索方法。在这种理解情况下,深度优先搜索算法有全部保留和不全部保留产生的结点的两种情况。而狭义的理解是,仅仅只保留全部产生结点的算法。本书取前一种广义的理解。不保留全部结点 的算法属于一般的回溯算法范畴。保留全部结点的算法,实际上是在数据库中产生一个结点之间的搜索树,因此也属于图搜索算法的范畴。(4)不保留全部结点的深度优先搜索法,由于把扩展望的结点从数据库中弹出删除,这样,一般在数据库中存储的结点数就是深度值,因此它占用的空间较少,所以,当搜索树的结点较多,用其他方法易产生内存溢出时,深度优先搜索不失为一种有效的算法。(5)从输出结果可看出,深度优先搜索找到的第一个解并不一定是最优解。例如例题2-8得最优解为13,但第一个解却是17。如果要求出最优解的话,一种方法将是后面要介绍的动态规划法,另一种方法是修改原算法:把原输出过程的地方改为记录过程,即记录达到当前目标的路径和相应的路程值,并与前面已记录的值进行比较,保留其中最优的,等全部搜索完成后,才把保留的最优解输出。 二、广度优先搜索法的显著特点是:(1)在产生新的子结点时,深度越小的结点越先得到扩展,即先产生它的子结点。为使算法便于实现,存放结点的数据库一般用队列的结构。(2)无论问题性质如何不同,利用广度优先搜索法解题的基本算法是相同的,但数据库中每一结点内容,产生式规则,根据不同的问题,有不同的内容和结构,就是同一问题也可以有不同的表示方法。(3)当结点到跟结点的费用(有的书称为耗散值)和结点的深度成正比时,特别是当每一结点到根结点的费用等于深度时,用广度优先法得到的解是最优解,但如果不成正比,则得到的解不一 算法设计:深度优先遍历和广度优先遍历实现 深度优先遍历过程 1、图的遍历 和树的遍历类似,图的遍历也是从某个顶点出发,沿着某条搜索路径对图中每个顶点各做一次且仅做一次访问。它是许多图的算法的基础。 深度优先遍历和广度优先遍历是最为重要的两种遍历图的方法。它们对无向图和有向图均适用。 以下假定遍历过程中访问顶点的操作是简单地输出顶点。 2、布尔向量visited[0 ..n-1] 的设置图中任一顶点都可能和其它顶点相邻接。在访问了某顶点之后,又可能顺着某条回路又回到了该顶点。为了避免重复访问同一个顶点,必须记住每个已访问的顶点。为此,可设一布尔向量visited[0 ..n-1] ,其初值为假,一旦访问了顶点Vi 之后,便将visited[i] 置为真。 深度优先遍历(Depth-First Traversal) 1.图的深度优先遍历的递归定义 假设给定图G的初态是所有顶点均未曾访问过。在G中任选一顶点V为初始出发 点(源点),则深度优先遍历可定义如下:首先访问出发点V ,并将其标记为已访问过;然后依次从V出发搜索V的每个邻接点W。若W未曾访问过,则以W为新的出发点继续进行深度优先遍历,直至图中所有和源点V 有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止。若此时图中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,直至图中所有顶点均已被访问为止。 图的深度优先遍历类似于树的前序遍历。采用的搜索方法的特点是尽可能先对纵深方向进行搜索。这种搜索方法称为深度优先搜索(Depth-First Search) 。相应地,用此方法遍历图就很自然地称之为图的深度优先遍历。 2、深度优先搜索的过程 设x 是当前被访问顶点,在对x 做过访问标记后,选择一条从x 出发的未检测过的 有两种常用的方法可用来搜索图:即深度优先搜索和广度优先搜索。它们最终都会到达所有 连通的顶点。深度优先搜索通过栈来实现,而广度优先搜索通过队列来实现。 深度优先搜索: 深度优先搜索就是在搜索树的每一层始终先只扩展一个子节点,不断地向纵深前进直到不能再前进(到达叶子节点或受到深度限制)时,才从当前节点返回到上一级节点,沿另一方向又继续前进。这种方法的搜索树是从树根开始一枝一枝逐渐形成的。 下面图中的数字显示了深度优先搜索顶点被访问的顺序。 "* ■ J 严-* 4 t C '4 --------------------------------- --- _ 为了实现深度优先搜索,首先选择一个起始顶点并需要遵守三个规则: (1) 如果可能,访问一个邻接的未访问顶点,标记它,并把它放入栈中。 (2) 当不能执行规则1时,如果栈不空,就从栈中弹出一个顶点。 (3) 如果不能执行规则1和规则2,就完成了整个搜索过程。 广度优先搜索: 在深度优先搜索算法中,是深度越大的结点越先得到扩展。如果在搜索中把算法改为按结点的层次进行搜索,本层的结点没有搜索处理完时,不能对下层结点进行处理,即深度越小的结点越先得到扩展,也就是说先产生的结点先得以扩展处理,这种搜索算法称为广度优先搜索法。 在深度优先搜索中,算法表现得好像要尽快地远离起始点似的。相反,在广度优先搜索中, 算法好像要尽可能地靠近起始点。它首先访问起始顶点的所有邻接点,然后再访问较远的区 域。它是用队列来实现的。 下面图中的数字显示了广度优先搜索顶点被访问的顺序。 实现广度优先搜索,也要遵守三个规则: ⑴ 访问下一个未来访问的邻接点,这个顶点必须是当前顶点的邻接点,标记它,并把它插入到队列中。(2)如果因为已经没有未访问顶点而不能执行规则1 一、深度优先搜索和广度优先搜索的深入讨论 (一)深度优先搜索的特点是: (1)从上面几个实例看出,可以用深度优先搜索的方法处理的题目是各种各样的。有的搜索深度是已知和固定的,如例题2-4,2-5,2-6;有的是未知的,如例题2-7、例题2-8;有的搜索深度是有限制的,但达到目标的深度是不定的。 但也看到,无论问题的内容和性质以及求解要求如何不同,它们的程序结构都是相同的,即都是深度优先算法(一)和深度优先算法(二)中描述的算法结构,不相同的仅仅是存储结点数据结构和产生规则以及输出要求。 (2)深度优先搜索法有递归以及非递归两种设计方法。一般的,当搜索深度较小、问题递归方式比较明显时,用递归方法设计好,它可以使得程序结构更简捷易懂。当搜索深度较大时,如例题2-5、2-6。当数据量较大时,由于系统堆栈容量的限制,递归容易产生溢出,用非递归方法设计比较好。 (3)深度优先搜索方法有广义和狭义两种理解。广义的理解是,只要最新产生的结点(即深度最大的结点)先进行扩展的方法,就称为深度优先搜索方法。在这种理解情况下,深度优先搜索算法有全部保留和不全部保留产生的结点的两种情况。而狭义的理解是,仅仅只保留全部产生结点的算法。本书取前一种广义的理解。不保留全部结点的算法属于一般的回溯算法范畴。保留全部结点的算法,实际上是在数据库中产生一个结点之间的搜索树,因此也属于图搜索算法的范畴。 (4)不保留全部结点的深度优先搜索法,由于把扩展望的结点从数据库中弹出删除,这样,一般在数据库中存储的结点数就是深度值,因此它占用的空间较少,所以,当搜索树的结点较多,用其他方法易产生内存溢出时,深度优先搜索不失为一种有效的算法。 (5)从输出结果可看出,深度优先搜索找到的第一个解并不一定是最优解。例如例题2-8得最优解为13,但第一个解却是17。 如果要求出最优解的话,一种方法将是后面要介绍的动态规划法,另一种方法是修改原算法:把原输出过程的地方改为记录过程,即记录达到当前目标的路径和相应的路程值,并与前面已记录的值进行比较,保留其中最优的,等全部搜索完成后,才把保留的最优解输出。 二、广度优先搜索法的显著特点是: (1)在产生新的子结点时,深度越小的结点越先得到扩展,即先产生它的子结点。为使算法便于实现,存放结点的数据库一般用队列的结构。 (2)无论问题性质如何不同,利用广度优先搜索法解题的基本算法是相同的,但数据库中每一结点内容,产生式规则,根据不同的问题,有不同的内容和结构,就是同一问题也可以有不同的表示方法。 (3)当结点到跟结点的费用(有的书称为耗散值)和结点的深度成正比时,特别是当每一结点到根结点的费用等于深度时,用广度优先法得到的解是最优解,但如果不成正比,则得到的解不一定是最优解。这一类问题要求出最优解,一种方法是使用后面要介绍的其他方法求解,另外一种方法是改进前面深度(或广度)优先搜索算法:找到一个目标后,不是立即退出,而是记录下目标结点的路径和费用,如果有多个目标结点,就加以比较,留下较优的结点。把所有可能的路径都搜索完后,才输出记录的最优路径。 (4)广度优先搜索算法,一般需要存储产生的所有结点,占的存储空间要比深度优先大得多,因此程序设计中,必须考虑溢出和节省内存空间得问题。 (5)比较深度优先和广度优先两种搜索法,广度优先搜索法一般无回溯操作,即入栈和出栈的操作,所以运行速度比深度优先搜索算法法要快些。 DFS与BFS的比较 姓名:班级:学号: 一、图的遍历 1.图的遍历的含义 图的遍历是指从图中某结点出发,按某既定方式访问图中各个可访问到的结点,使每个可访问到的结点恰被访问一次。 2.图的遍历方式:深度优先与广度优先 二、DFS与BFS的区别 1.概念 深度优先遍历可定义如下:首先访问出发点v,并将其标记为已访问过;然后依次从v出发搜索v的每个邻接点w。若w未曾访问过,则以w为新的出发点继续进行深度优先遍历,直至图中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止。若此时图中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,直至图中所有顶点均已被访问止。 广度优先遍历可定义如下:假设从图中某顶点v出发,在访问了v之后依次访问v的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使“先被访问的顶点的邻接点”先与“后被访问的顶点的邻接点”被访问,直至图中所有已被访问的顶点的邻接点都被访问到。若此时图中尚有顶点未被访问,则另选图中一个曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。 2. 路径 深度优先就是,从初始点出发,不断向前走,如果碰到死路了,就往回走一步,尝试另一条路,直到发现了目标位置。这种方法,即使成功也不一定找到一条好路,但是需要记住的位置比较少。 广度优先就是,从初始点出发,把所有可能的路径都走一遍,如果里面没有目标位置,则尝试把所有两步能够到的位置都走一遍,看有没有目标位置;如果还不行,则尝试所有三步可以到的位置。这种方法,一定可以找到一条最短路径,但需要记忆的内容实在很多,要量力而行。 3.算法实现 (1) 图的深度优先算法的一般性描述: long DFS(图s,结点v。) { // 从结点v。出发,深度优先遍历图s,返回访问到的结点总数 int nNodes; //寄存访问到的结点数目 访问v。; #include "string.h" #include "stdlib.h" #include "malloc.h" #include "stdio.h" #define MAX_VERTEX_NUM 10 #define MAXQSIZE 10 int visited[MAX_VERTEX_NUM]; typedef struct Node{ int adjvex; struct Node *next; }EdgeNode; typedef struct VNode{ int vertex; EdgeNode *firstedge; }V ertexNode; typedef V ertexNode AdjList[MAX_VERTEX_NUM]; typedef struct{ AdjList adjlist; int n,e; }ALGraph; typedef struct{ int *base; int front; int rear; }SqQueue; int InitQueue(SqQueue *Q) { Q->base=(int *)malloc(MAXQSIZE*sizeof(int)); if(!Q->base) return 0; Q->front=Q->rear=0; return 1; } int EnQueue(SqQueue *Q,int e) { if((Q->rear+1)%MAXQSIZE==Q->front) return 0; Q->base[Q->rear]=e; Q->rear=(Q->rear+1)%MAXQSIZE; return 1; } int DeQueue(SqQueue *Q) { int i; i=Q->base[Q->front]; Q->front=(Q->front+1)%MAXQSIZE; return i; } int QueueEmpty(SqQueue *Q) { if(Q->front==Q->rear) return 1; return 0; } void BFS(ALGraph *G,int k) 《数据结构课程设计》报告题目:深度与广度优先搜索 --迷宫问题 专业计算机科学与技术 学生姓名李柏 班级B计算机115 学号1110704512 指导教师巩永旺 完成日期2013年1月11日 目录 1简介 (1) 2算法说明 (1) 3测试结果 (3) 4分析与探讨 (7) 5小结 (9) 附录 (10) 附录1 源程序清单 (10) 迷宫问题 1 简介 1、图的存储结构 图的存储结构又称图的表示,其最常用的方法是邻接矩阵和邻接表。无论采用什么存储方式,其目标总是相同的,既不仅要存储图中各个顶点的信息,同时还要存储顶点之间的所有关系。 2、图的遍历 图的遍历就是从指定的某个顶点(称其为初始点)出发,按照一定的搜索方法对图中的所有顶点各做一次访问过程。根据搜索方法不同,遍历一般分为深度优先搜索遍历和广度优先搜索遍历。 本实验中用到的是广度优先搜索遍历。即首先访问初始点v i,并将其标记为已访问过,接着访问v i的所有未被访问过的邻接点,顺序任意,并均标记为已访问过,以此类推,直到图中所有和初始点v i有路径相通的顶点都被访问过为止。鉴于广度优先搜索是将所有路径同时按照顺序遍历,直到遍历出迷宫出口,生成的路径为最短路径。因此我们采用了广度优先搜索。 无论是深度优先搜索还是广度优先搜索,其本质都是将图的二维顶点结构线性化的过程,并将当前顶点相邻的未被访问的顶点作为下一个顶点。广度优先搜索采用队列作为数据结构。 本实验的目的是设计一个程序,实现手动或者自动生成一个n×m矩阵的迷宫,寻找一条从入口点到出口点的通路。具体实验内容如下: 选择手动或者自动生成一个n×m的迷宫,将迷宫的左上角作入口,右下角作出口,设“0”为通路,“1”为墙,即无法穿越。假设一只老鼠从起点出发,目的为右下角终点,可向“上、下、左、右、左上、左下、右上、右下”8个方向行走。如果迷宫可以走通,则用“■”代表“1”,用“□”代表“0”,用“☆”代表行走迷宫的路径。输出迷宫原型图、迷宫路线图以及迷宫行走路径。如果迷宫为死迷宫,则只输出迷宫原型图。 2算法说明 迷宫中存在通路和障碍,为了方便迷宫的创建,可用0表示通路,用1表示障碍,这样迷宫就可以用0、1矩阵来描述。设置迷宫的长为n、宽为m,范围为49×49,用int maze[N+2][M+2]来表示,这样相当于在迷宫外层包了一层1,即防止搜索路径时跳出迷宫。 (1)手动生成迷宫 《数据结构课程设计》报告 题目:深度与广度优先搜索 --迷宫问题 专业 计算机科学与技术 学生姓名 李柏 班级 B 计算机115 学 号 1110704512 指导教师 巩 永 旺 完成日期 2013年1月11日 目录 1简介 (1) 2算法说明 (1) 3测试结果 (3) 4分析与探讨 (7) 5小结 (8) 附录 (10) 附录1 源程序清单 (10) 迷宫问题 1 简介 1、图的存储结构 图的存储结构又称图的表示,其最常用的方法是邻接矩阵和邻接表。无论采用什么存储方式,其目标总是相同的,既不仅要存储图中各个顶点的信息,同时还要存储顶点之间的所有关系。 2、图的遍历 图的遍历就是从指定的某个顶点(称其为初始点)出发,按照一定的搜索方法对图中的所有顶点各做一次访问过程。根据搜索方法不同,遍历一般分为深度优先搜索遍历和广度优先搜索遍历。 本实验中用到的是广度优先搜索遍历。即首先访问初始点v i,并将其标记为已访问过,接着访问v i的所有未被访问过的邻接点,顺序任意,并均标记为已访问过,以此类推,直到图中所有和初始点v i有路径相通的顶点都被访问过为止。鉴于广度优先搜索是将所有路径同时按照顺序遍历,直到遍历出迷宫出口,生成的路径为最短路径。因此我们采用了广度优先搜索。 无论是深度优先搜索还是广度优先搜索,其本质都是将图的二维顶点结构线性化的过程,并将当前顶点相邻的未被访问的顶点作为下一个顶点。广度优先搜索采用队列作为数据结构。 本实验的目的是设计一个程序,实现手动或者自动生成一个n×m矩阵的迷宫,寻找一条从入口点到出口点的通路。具体实验内容如下: 选择手动或者自动生成一个n×m的迷宫,将迷宫的左上角作入口,右下角作出口,设“0”为通路,“1”为墙,即无法穿越。假设一只老鼠从起点出发,目的为右下角终点,可向“上、下、左、右、左上、左下、右上、右下”8个方向行走。如果迷宫可以走通,则用“■”代表“1”,用“□”代表“0”,用“☆”代表行走迷宫的路径。输出迷宫原型图、迷宫路线图以及迷宫行走路径。如果迷宫为死迷宫,则只输出迷宫原型图。 2算法说明 迷宫中存在通路和障碍,为了方便迷宫的创建,可用0表示通路,用1表示障碍,这样迷宫就可以用0、1矩阵来描述。设置迷宫的长为n、宽为m,范围为49×49,用int maze[N+2][M+2]来表示,这样相当于在迷宫外层包了一层1,即防止搜索路径时跳出迷宫。 (1)手动生成迷宫 1 数据结构课程设计 深度与广度优先搜索:迷宫问题 专业 计算机科学与技术(网络技术) 学生姓名 班级 学 号 指导教师 完成日期 目录 1.课程设计的目的 (3) 2.简介 (3) 3.算法说明 (4) 4.测试结果 (5) 5.分析与探讨 (6) 6.小结 (8) 7.参考文献 (9) 8.附录........................................................................,,,..10 附录1 源程序清单. (10) 一.课程设计的目的 数据结构课程设计是为数据结构课程独立开设的实践性教学环节。数据结构课程设计对于巩固数据结构知识,加强学生的实际动手能力和提高学生综合素质是十分必要的。课程设计的目的: 1.要求学生达到熟练掌握C语言的基本知识和技能。 2.了解并掌握数据结构与算法的设计方法,具备初步的独立分析和设计能力。 3.提高程序设计和调试能力。学生通过上机实习,验证自己设计的算法的正确性。学会有效利用基本调试方法,迅速找出程序代码中的错误并且修改。 4.培养算法分析能力。分析所设计算法的时间复杂度和空间复杂度,进一步提高程序设计水平。 5.初步掌握软件开发过程的问题分析、系统设计、程序编码、测试等基本方法和技能。 二.简介 1.图的存储结构 图的存储结构又称图的表示,其最常用的方法是邻接矩阵和邻接表。无论采用什么存储方式,其目的总是相同的,即不仅要存储图中各个顶点的信息,同时还要存储顶点之间的所有关系。 2.图的遍历 图的遍历就是从指定的某个顶点(称其为初始点)出发,按照一定的搜索方法对图中所有顶点各做一次访问的过程。根据搜索的方法不同,遍历有如下两种。 (1)深度优先搜索遍历:深度优先搜索(DFS)是一个递归过程。首先访问一个顶点Vi并将其标记为已访问过,然后从Vi的任意一个未被访问的邻接点出发进行深度优先搜索遍历。如此执行,当Vi的所有邻接点均被访问过时,则退回到上一个顶点Vk,从Vk的另一未被访问过的邻接点出发进行深度优先搜索遍历。如此执行,直到退回到初始点并且没有违背访问过的邻接点为止。 (2)广度优先搜索遍历:广度优先搜索过程(BFS)为:首先访问初始点Vi,并将其标记为已访问过,接着访问Vi的所有未被访问过的邻接点,其访问顺序可以任意,假定依次为Vi1,Vi2,…..Vin,并均被标记为已访问过,然后按照Vi1,Vi2,…..Vin,的次序,访问每一个顶点的所有未被访问过的邻接点,并均标记为已访问过,以此类推,直到图中所有和初始点Vi有路径相通的顶点都被访问过为止。 无论是深度优先搜索还是广度优先搜索,其本质都是将图的二维顶点结构线性化的过程,并将当前顶点相邻的未被访问的顶点作为下一个顶点,由于与当前顶点相邻的顶点可能多于一个,而每次只能选择其中一个作为下一个顶点,这样势必要 3 标题:图的深度和广度优先遍历时限: 2000 ms 内存限制: 5000 K 总时限: 3000 ms 描述:以邻接矩阵给出一张以整数编号为顶点的图,其中0表示不相连,1表示相连。按深度和广度优先进行遍历,输出全部结果。要求,遍历时优先较小的顶点。如,若顶点0与顶点2,顶点3,顶点4相连,则优先遍历顶点2. 输入:顶点个数邻接矩阵 输出:DFS 深度遍历输出WFS 广度遍历输出 输入样例: 3 0 1 1 1 0 1 1 1 0 输出样例:DFS 0 1 2 1 0 2 2 0 1 WFS 0 1 2 1 0 2 2 0 1 提示:顶点整数从0 开始 来源:教材 #include "stdlib.h" #include "stdio.h" #define STACK_INIT_SIZE 100 #define STACKINCREMENT 10 #define MAXQSIZE 100 typedef struct { int amount; int *vex; int **matrix; } Graph; typedef struct { int *base; int *top; int stacksize; } SqStack; void InitStack(SqStack &S) { S.base = (int*)calloc(STACK_INIT_SIZE,sizeof(int)); S.top = S.base; S.stacksize = STACK_INIT_SIZE; } void Push(SqStack &S,int e) { if(S.top - S.base >= S.stacksize) { S.base = (int*)realloc(S.base,(STACKINCREMENT + S.stacksize)*sizeof(int)); S.top = S.base + S.stacksize; S.stacksize += STACKINCREMENT; } *S.top++ = e; } bool Pop(SqStack &S,int &e) { if(S.top == S.base) { puts("This is an empty stack!"); return false; } else { e = *--S.top; return true; } } bool GetTopS(SqStack S,int &e) { 数据结构课程设计 深度与广度优先搜索:迷宫问题 专业 Xxxxx 学生姓名 xxxxxx 班级 xxxxxxxxx 学 号 xxxxxxxxxxxxxxxx 目录 1设计题目 (1) 2设计分析 (1) 3设计实现 (3) 4测试方法 (3) 4.1测试目的 (8) 4.2测试输入 (8) 4.3正确输出 (9) 4.4实际输出 (9) 4.5错误原因 (10) 5分析与探讨 (10) 5.1测试结果分析 (10) 5.2探讨与改进 (11) 6设计小结 (11) 7 参考文献 1 设计题目 a)迷宫问题求解的目标:寻找一条从入口点到出口点的通路。(迷宫可表示为一个二维平面图形,将迷宫的左上角作入口,右下角作出口。)例如,可以设计一个8*8矩阵maze[8][8]来表示迷宫,如下所示: 0 1 0 0 0 0 1 1 0 0 0 1 0 0 1 0 1 0 1 0 1 0 1 1 1 0 1 0 1 1 0 1 0 1 1 1 1 1 1 0 1 0 0 1 1 0 0 0 1 0 1 0 0 0 1 1 1 0 1 1 0 1 0 0 左下角maze[0][0]为起点,右下角maze[7][7]为终点;设“0”为通路,“1”为墙,既无法穿越。假设一只老鼠从起点出发,目的为右下角终点,可向“上、下、左、右、左上、左下、右上、右下”8个方向行走。 b)设计程序要求:能自动生成或者手动生成这样一个8*8矩阵;针对这个矩阵,程序判断是否能从起点经过迷宫走到终点。如果不能,请指出;如果能,请用图形界面标出走出迷宫的路径。 2 设计分析 a)首先明确题目中的已知条件: ·迷宫是一个8*8大小的矩阵。 ·从迷宫的左上角进入,右下角为迷宫的终点。 ·maze[i][j]=0代表第i+1行第j+1列的点是通路;maze[i][j]=1代表该点是墙,无法通行。 ·迷宫有两种生成方式:手工设定和自动生成。 ·当老鼠处于迷宫中某一点的位置上,它可以向8个方向前进,分别是:“上、下、左、右、左上、左下、右上、右下”8个方向。 ·要实现这个程序,首先要考虑如何表示这个迷宫。在实例程序中使用二维数组,maze[N+2][N+2]来表示这个迷宫,其中N为迷宫的行、列数。当值为“0”时表示该点是通路,当值为“1”时表示该点是墙。老鼠在迷宫中的位置在任何时候都可以用行号row和列号col表示。 搜索算法——深度优先(DFS)、广度优先(BFS) 1.深度优先搜索 所谓深度优先搜索,其思想概括如下: (1)在每个阶段的决策时,采取能深则深的原则试探所有的方案,一旦深入一层则保存当前操作引起的状态。 (2)一旦试探失败,为了摆脱当前失败的状态,采取回到上一阶段尝试一下方案的策略(回溯策略);或则在求解所有解时,求得一个解后,回溯到上一阶段尝试 下一方案,以求解下一个解。 (3)在各个阶段尝试方案时,采取的是穷举的思想。 2.广度优先 在深度优先搜索法中,深度越大的结点优先得到扩展,若把它改为深度越小的结点越先得到扩展,就是广度优先搜索法。 由于广度优先搜索先将所有与上一层结点相邻接的结点搜索完之后,再继续往下搜索与该层所有邻接而又没有访问过的结点,可以看作是分层次搜索的。因此,当某一层出现目标结点时,这时所进行的步骤是最少的。所以,广度优先搜索管饭应用于求解问题的最短路径、最少步骤、最优方法等方面。 【11-4-1】米宫问题(maze)(广度优先BFS) 问题描述: 在一个由n*m(n,m<=5)个方格组成的迷宫中,设有t处障碍,在每一个格子中,只能上下左右移动,当然障碍处不可通过。如果给定出发点和目标点的坐标,要求每个方格最多经过1次,能否走出迷宫,如果能输出最短路径长度,否则输出-1。 输入格式: 第一行三个用空格分隔的数字n、m和t。其中n为行,m为列,t为障碍总数。 第二行四个空格分隔的数字,分别表示出发点和目标点的坐标。 接下来t行,每行为一个障碍点的坐标。 输出格式: 一个数字,表示最短路径长度(不能到达则输出-1)。 【11-4-2】零点游戏(zerosum)(深度优先DFS) 问题描述: 玩过24点的人都知道:游戏是对于给定的4个数字运用四则运算,使其最终计算结果为24. 现在有人在此基础上发明了零点游戏:对于给定的数字n(2 【题目1】N皇后问题(八皇后问题的扩展) 【题目2】排球队员站位问题 【题目3】把自然数N分解为若干个自然数之和。 【题目4】把自然数N分解为若干个自然数之积。 【题目5】马的遍历问题。 【题目6】加法分式分解 【题目7】地图着色问题 【题目8】在n*n的正方形中放置长为2,宽为1的长条块, 【题目9】找迷宫的最短路径。(广度优先搜索算法) 【题目10】火车调度问题 【题目11】农夫过河 【题目12】七段数码管问题。 【题目13】把1-8这8个数放入下图8个格中,要求相邻的格(横,竖,对角线)上填的数不连续. 【题目14】在4×4的棋盘上放置8个棋,要求每一行,每一列上只能放置2个. 【题目15】迷宫问题.求迷宫的路径.(深度优先搜索法) 【题目16】一笔画问题 【题目17】城市遍历问题. 【题目18】棋子移动问题 【题目19】求集合元素问题(1,2x+1,3X+1类) 【题目】N皇后问题(含八皇后问题的扩展,规则同八皇后):在N*N的棋盘上,放置N个皇后,要求每一横行 每一列,每一对角线上均只能放置一个皇后,问可能的方案及方案数。 const max=8; var i,j:integer; a:array[1..max] of 0..max; {放皇后数组} b:array[2..2*max] of boolean; {/对角线标志数组} c:array[-(max-1)..max-1] of boolean; {\对角线标志数组} col:array[1..max] of boolean; {列标志数组} total:integer; {统计总数} procedure output; {输出} var i:integer; begin 佛山科学技术学院 实验报告 课程名称数据结构 实验项目实现深度优先搜索与广度优先搜索算法 专业班级姓名学号 指导教师肖祥慧成绩日期 2012年11月16日 一、实验目的 1、通过本实验,掌握图,无向图的基本概念,掌握图的遍历; 2、掌握图的深度优先搜索(DFS)与广度优先搜索(BFS)算法。 二、实验内容 1、建立图的存储方式; 2、图的深度优先搜索算法; 3、图的广度优先搜索算法。 三、实验原理 图的遍历是图的算法中一种非常重要的算法,通过建立图的存储结构,采用深度优先搜索与广度优先搜索算法可以进行图的遍历; 深度优先遍历是树的先根遍历的推广,是将某一条枝上的所有节点都搜索到了之后,才转向搜索另一条枝上的所有节点; 广度优先遍历与深度优先遍历的区别在于:广度优先遍历是以层为顺序,将某一层上的所有节点都搜索到了之后才向下一层搜索。 四、实验步骤 1、调试下列程序“创建图程序一”,掌握无向图的构造算法和实现方法。 2、在此程序的基础上,完成图的深度优先搜索(DFS)和广度优先搜索算法,并输出遍历结果。 3、可以采用菜单形式进行显示与选择;从键盘输入边的信息已构建一个无向图。以(a,b)的形式输入边的信息;对此无向图进行深度优先搜索和广度优先搜索,并输出正确的序列。 五、程序源代码及注释 #include struct ArcNode *next1; }ArcNode; /************链表结点的结构用于创建栈或是队列**************/ typedef struct LinkNode { ArcNode *parc; //存储指针地址 struct LinkNode *next2; //指向一下个结点 }LinkNode; typedef struct VNode { char Data; //顶点元素值 ArcNode *firstarc; //指向第一条依附于该点的边 }VNode,AdjList[MAX]; typedef struct { AdjList vertices; int vexnum; //图的当前顶点数和弧数 int arcnum; }ALGraph; int Visited[MAX]; int graphprintf(ALGraph *pag) { //将生成的图打印出来以便确认正确性 int i; ArcNode *p; printf("\n打印图表:\n"); printf("No\tdata\tnext2\tnext2\t.....\n"); for(i=0; i #include 数据结构课程设计报告 深度与广度优先搜索:迷宫问 题的设计 目录 1设计内容 (1) 2设计分析 (1) 3设计实践 (3) 4测试方法 (4) 5程序运行效果 (6) 6设计心得 (8) 7附录 (9) 数据结构课程设计报告(2017) 深度与广度优先搜索:迷宫问题的设计 1设计内容 一般的迷宫可表示为一个二维平面图形,将迷宫的左上角作入口,右下角作出口。迷宫问题求解的目标是寻找一条从入口点到出口点的通路。 例如,可以设计一个8*8矩阵maze[8][8]来表示迷宫,如下所示: 0 1 0 0 0 0 1 1 0 0 0 1 0 0 1 0 1 0 1 0 1 0 1 1 1 0 1 0 1 1 0 1 0 1 1 1 1 1 1 0 1 0 0 1 1 0 0 0 1 0 1 0 0 0 1 1 1 0 1 1 0 1 0 0 左上角maze[0][0]为起点,右下角maze[7][7]为终点;设“0”为通路,“1”为墙,即无法穿越。假设一只老鼠从起点出发,目的为右下角终点,可向“上,下,左,右,左上,左下,右上,右下”8个方向行走。 设计一个程序,能自动生存或者手动生成这样一个8*8矩阵,针对这个矩阵,程序判断是否能从起点经过迷宫走到终点。如果不能,指出;如果能,用图形界面标出走出迷宫的路径。 2 设计分析 首先明确题目中的已知条件: (1)迷宫是一个8*8大小的矩阵。 (2)从迷宫的左上角进入,右下角为迷宫的终点。 maze[i][j]=0代表第i+1行第j+1列的点是通路;maze[i][j]=1代表该点是墙,无法通行。 (3)迷宫有两种生成方式:手工设定和自动生成。 (4)当老鼠处于迷宫中某一点的位置上,它可以向8个方向前进,分别是:“上、下、左、右、左上、左下、右上、右下”8个方向。 要实现这个程序,首先要考虑如何表示这个迷宫。在实例程序中使用二维数组maze[N+2][N+2]来表示这个迷宫,其中N为迷宫的行,列数。当值为“0”时表示该点是通路,当值为“1”时表示该点是墙。老鼠在迷宫中的位置在任何时候都可以由行号row和列号col表示。 为什么指定maze[N+2][N+2]来表示迷宫,而不是使用maze[N][N]来表示迷宫?原因是当老鼠跑到迷宫的边界点时就有可能跳出迷宫,而使用maze[N+2][N+2]就可以把迷宫的外面再包一层“1”,这样就能阻止老鼠走出格。 老鼠在每一点都有8种方向可以走,分别是:North,NorthEast,East,SouthEast,South,SouthWest,West,NorthWest。可以用数组move[8]来表示在每一个方向上的横纵坐标的偏移量,见表3.1。根据这个数组,就很容易计算出沿某个方向行走的下一点的坐标。 图的深度和广度优先算法 一.图的遍历 假设初始状态是图中所有顶点都未被访问,则深度优先搜索方法的步骤是:1)选取图中某一顶点Vi为出发点,访问并标记该顶点; 2)以Vi为当前顶点,依次搜索Vi的每个邻接点Vj,若Vj未被访问过,则访问和标记邻接点Vj,若Vj已被访问过,则搜索Vi的下一个邻接点; 3)以Vj为当前顶点,重复步骤2),直到图中和Vi有路径相通的顶点都被访问为止; 4)若图中尚有顶点未被访问过(非连通的情况下),则可任取图中的一个未被访问的顶点作为出发点,重复上述过程,直至图中所有顶点都被访问。 二.广度优先搜索算法 使用计算机求解的问题中,有许多问题是无法用数学公式进行计算推导采用模拟方法来找出答案的。这样的问题往往需要我们根据问题所给定的一些条件,在问题的所有可能解中用某种方式找出问题的解来,这就是所谓的搜索法或搜索技术。 通常用搜索技术解决的问题可以分成两类:一类问题是给定初始结点,要求找出符合约束条件的目标结点;另一类问题是给出初始结点和目标结点,找出一条从初始结点到达目标结点的路径。 常见的搜索算法有枚举法、广度优先搜索法、深度优先搜索法、双向广度优先搜索法,A*算法、回溯法、分支定界法等。这里来讨论一下广度优先搜索法。 一般来说,可以采用搜索算法解决的这类问题的特点是: 1.有一组具体的状态,状态是问题可能出现的每一种情况。全体状态所构成的状态空间是有限的,问题规模较小。 2.在问题的解答过程中,可以从一个状态按照问题给定的条件,转变为另外的一个或几个状态。 3.可以判断一个状态的合法性,并且有明确的一个或多个目标状态。 4.所要解决的问题是:根据给定的初始状态找出目标状态,或根据给定的初始状态和结束状态,找出一条从初始状态到结束状态的路径。 采用广度优先搜索算法解答问题时,需要构造一个表明状态特征和不同状态之间关系的数据结构,这种数据结构称为结点。根据问题所给定的条件,从一个结点出发,可以生成一个或多个新的结点,这个过程通常称为扩展。结点之间的关系一般可以表示成一棵树,它被称为解答树。搜索算法的搜索过程实际上就是根据初始条件和扩展规则构造一棵解答树并寻找符合目标状态的结点的过程。 广度优先搜索算法中,解答树上结点的扩展是沿结点深度的“断层”进行,也就是说,结点的扩展是按它们接近起始结点的程度依次进行的。首先生成第一层结点,同时检查目标结点是否在所生成的结点中,如果不在,则将所有的第一层结点逐 #include }VNode,AdjList[MAX_VERTEX_NUM]; typedef struct { AdjList vertices; int vexnum,arum; int kind; }ALGraph; int LocateVex(MGraph G,VertexType v1) { int i; for(i=0;i深度优先与广度优先
算法设计:深度优先遍历和广度优先遍历
广度优先搜索和深度优先搜索
深度优先搜索和广度优先搜索的深入讨论
深度优先算法与广度优先算法的比较
广度优先与深度优先搜索
深度与广度优先搜索:迷宫问题
深度与广度优先搜索:迷宫问题
数据结构课程设计 深度与广度优先搜索:迷宫问题
数据结构图的深度和广度优先遍历
[数据结构]深度与广度优先搜索:迷宫问题
搜索算法——深度-广度
广度优先搜索和深度优先搜索训练题
实现深度优先搜索与广度优先搜索算法
二叉树的广度优先搜索和深度优先搜索
#include
>&adj_lists, intstart_node) { queue
深度与广度优先搜索:迷宫问题的设计
图的深度和广度优先算法
图的广度优先遍历和深度优先遍历