深度优先搜索和广度优先搜索

系统 1436 0

一、深度优先搜索
深度优先搜索就是在搜索树的每一层始终先只扩展一个子节点,不断地向纵深前进直到不能再前进(到达叶子节点或受到深度限制)时,才从当前节点返回到上一级节点,沿另一方向又继续前进。这种方法的搜索树是从树根开始一枝一枝逐渐形成的。

深度优先搜索亦称为纵向搜索。由于一个有解的问题树可能含有无穷分枝,深度优先搜索如果误入无穷分枝(即深度无限),则不可能找到目标节点。所以,深度优先搜索策略是不完备的。另外,应用此策略得到的解不一定是最佳解(最短路径)。

二、 重排九宫问题游戏
在一个3乘3的九宫中有1-8的8个数及一个空格随机摆放在其中的格子里。如下面左图所示。现在要求实现这样的问题:将该九宫调整为如下图右图所示的形式。调整规则是:每次只能将与空格(上,下或左,右)相临的一个数字平移到空格中。试编程实现。

| 2 | 8 | 3 | | 1 | 2 | 3 |
-
| 1 | | 4 | | 8 | | 4 |

| 7 |6 | 5 | | 7 | 6 | 5 |

深度优先搜索的路径示意图:
深度优先搜索和广度优先搜索

三、广度优先搜索

在深度优先搜索算法中,是深度越大的结点越先得到扩展。如果在搜索中把算法改为按结点的层次进行搜索, 本层的结点没有搜索处理完时,不能对下层结点进行处理,即深度越小的结点越先得到扩展,也就是说先产生 的结点先得以扩展处理,这种搜索算法称为广度优先搜索法。

广度优先搜索路径示意图:
深度优先搜索和广度优先搜索

四、航班问题(来自《The Art of Java》)
一位顾客要预定一张从New York到Los Angeles的航班机票,下面是航班线路,请你为顾客找一种购票方案。

航班
距离
New York到Chicago
900英里
Chicago到Denver
1000英里
New York到Toronto
500英里
New York到Denver
1800英里
Toronto到Calgary
1700英里
Toronto到Los Angeles
2500英里
Toronto到Chicago
500英里
Denver到Urbana
1000英里
Denver到Houston
1000英里
Houston到Los Angeles
1500英里
Denver到Los Angeles
1000英里

下面是用深度优先搜索求解的程序:

// Findconnectionsusingadepth-firstsearch.
import java.util. * ;
import java.io. * ;

// Flightinformation.
class FlightInfo{
Stringfrom;
Stringto;
int distance;
boolean skip; // usedinbacktracking

FlightInfo(Stringf,Stringt,
int d){
from
= f;
to
= t;
distance
= d;
skip
= false ;
}
}

class Depth{
final int MAX = 100 ;

// Thisarrayholdstheflightinformation.
FlightInfoflights[] = new FlightInfo[MAX];

int numFlights = 0 ; // numberofentriesinflightarray

StackbtStack
= new Stack(); // backtrackstack

public static void main(Stringargs[])
{

Stringto,from;
Depthob
= new Depth();
BufferedReaderbr
= new
BufferedReader(
new InputStreamReader(System.in));

ob.setup();

try {
System.out.print(
" From? " );
from
= br.readLine();
System.out.print(
" To? " );
to
= br.readLine();

ob.isflight(from,to);

if (ob.btStack.size() != 0 )
ob.route(to);
}
catch (IOExceptionexc){
System.out.println(
" Erroroninput. " );
}
}

// Initializetheflightdatabase.
void setup()
{
addFlight(
" NewYork " , " Chicago " , 900 );
addFlight(
" Chicago " , " Denver " , 1000 );
addFlight(
" NewYork " , " Toronto " , 500 );
addFlight(
" NewYork " , " Denver " , 1800 );
addFlight(
" Toronto " , " Calgary " , 1700 );
addFlight(
" Toronto " , " LosAngeles " , 2500 );
addFlight(
" Toronto " , " Chicago " , 500 );
addFlight(
" Denver " , " Urbana " , 1000 );
addFlight(
" Denver " , " Houston " , 1000 );
addFlight(
" Houston " , " LosAngeles " , 1500 );
addFlight(
" Denver " , " LosAngeles " , 1000 );
}

// Putflightsintothedatabase.
void addFlight(Stringfrom,Stringto, int dist)
{

if (numFlights < MAX){
flights[numFlights]
=
new FlightInfo(from,to,dist);

numFlights
++ ;
}
else System.out.println( " Flightdatabasefull. " );
}

// Showtherouteandtotaldistance.
void route(Stringto)
{
Stackrev
= new Stack();
int dist = 0 ;
FlightInfof;
int num = btStack.size();

// Reversethestacktodisplayroute.
for ( int i = 0 ;i < num;i ++ )
rev.push(btStack.pop());

for ( int i = 0 ;i < num;i ++ ){
f
= (FlightInfo)rev.pop();
System.out.print(f.from
+ " to " );
dist
+= f.distance;
}

System.out.println(to);
System.out.println(
" Distanceis " + dist);
}

/* Ifthereisaflightbetweenfromandto,
returnthedistanceofflight;
otherwise,return0.
*/
int match(Stringfrom,Stringto)
{
for ( int i = numFlights - 1 ;i > - 1 ;i -- ){
if (flights[i].from.equals(from) &&
flights[i].to.equals(to)
&&
! flights[i].skip)
{
flights[i].skip
= true ; // preventreuse
return flights[i].distance;
}
}

return 0 ; // notfound
}

// Givenfrom,findanyconnection.
FlightInfofind(Stringfrom)
{

for ( int i = 0 ;i < numFlights;i ++ ){
if (flights[i].from.equals(from) &&
! flights[i].skip)
{
FlightInfof
= new FlightInfo(flights[i].from,
flights[i].to,
flights[i].distance);
flights[i].skip
= true ; // preventreuse

return f;
}
}

return null ;
}

// Determineifthereisaroutebetweenfromandto.
void isflight(Stringfrom,Stringto)
{
int dist;
FlightInfof;

// Seeifatdestination.
dist = match(from,to);
if (dist != 0 ){
btStack.push(
new FlightInfo(from,to,dist));
return ;
}

// Tryanotherconnection.
f = find(from);
if (f != null ){
btStack.push(
new FlightInfo(from,to,f.distance));
isflight(f.to,to);
}
else if (btStack.size() > 0 ){
// Backtrackandtryanotherconnection.
f = (FlightInfo)btStack.pop();
isflight(f.from,f.to);
}
}
}

深度优先搜索和广度优先搜索

解释:isflight()方法用递归方法进行深度优先搜索,它先调用match()方法检查航班的数据库,判断在from和to之间有没有航班可达。如果有,则获取目标信息,并将该线路压入栈中,然后返回(找到一个方案)。否则,就调用find()方法查找from与任意其它城市之间的线路,如果找到一条就返回描述该线路的FlightInfo对象,否则返回null。如果存在这样的一条线路,那么就把该线路保存在f中,并将当前航班信息压到栈的顶部,然后递归调用isflight()方法 ,此时保存在f.to中的城市成为新的出发城市.否则就进行回退,弹出栈顶的第一个节点,然后递归调用isflight()方法。该过程将一直持续到找到目标为止。

程序运行结果:


C:\java>java Depth
From? New York
To? Los Angeles
New York to Chicago to Denver to Los Angeles
Distance is 2900

C:\java>

深度优先搜索能够找到一个解,同时,对于上面这个特定问题,深度优先搜索没有经过回退,一次就找到了一个解;但如果数据的组织方式不同,寻找解时就有可能进行多次回退。因此这个例子的输出并不具有普遍性。而且,在搜索一个很长,但是其中并没有解的分支的时候,深度优先搜索的性能将会很差,在这种情况下,深度优先搜索不仅在搜索这条路径时浪费时间,而且还在向目标的回退中浪费时间。

再看对这个例子使用广度优先搜索的程序:

程序运行结果:

C:\java>java Breadth
From? New York
To? Los Angeles
New York to Toronto to Los Angeles
Distance is 3000

// Findconnectionsusingabreadth-firstsearch.
import java.util. * ;
import java.io. * ;

// Flightinformation.
class FlightInfo{
Stringfrom;
Stringto;
int distance;
boolean skip; // usedinbacktracking

FlightInfo(Stringf,Stringt,
int d){
from
= f;
to
= t;
distance
= d;
skip
= false ;
}
}

class Breadth{
final int MAX = 100 ;

// Thisarrayholdstheflightinformation.
FlightInfoflights[] = new FlightInfo[MAX];

int numFlights = 0 ; // numberofentriesinflightarray

StackbtStack
= new Stack(); // backtrackstack

public static void main(Stringargs[])
{
Stringto,from;
Breadthob
= new Breadth();
BufferedReaderbr
= new
BufferedReader(
new InputStreamReader(System.in));

ob.setup();

try {
System.out.print(
" From? " );
from
= br.readLine();
System.out.print(
" To? " );
to
= br.readLine();

ob.isflight(from,to);

if (ob.btStack.size() != 0 )
ob.route(to);
}
catch (IOExceptionexc){
System.out.println(
" Erroroninput. " );
}
}

// Initializetheflightdatabase.
void setup()
{
addFlight(
" NewYork " , " Chicago " , 900 );
addFlight(
" Chicago " , " Denver " , 1000 );
addFlight(
" NewYork " , " Toronto " , 500 );
addFlight(
" NewYork " , " Denver " , 1800 );
addFlight(
" Toronto " , " Calgary " , 1700 );
addFlight(
" Toronto " , " LosAngeles " , 2500 );
addFlight(
" Toronto " , " Chicago " , 500 );
addFlight(
" Denver " , " Urbana " , 1000 );
addFlight(
" Denver " , " Houston " , 1000 );
addFlight(
" Houston " , " LosAngeles " , 1500 );
addFlight(
" Denver " , " LosAngeles " , 1000 );
}

// Putflightsintothedatabase.
void addFlight(Stringfrom,Stringto, int dist)
{
if (numFlights < MAX){
flights[numFlights]
=
new FlightInfo(from,to,dist);

numFlights
++ ;
}
else System.out.println( " Flightdatabasefull. " );
}

// Showtherouteandtotaldistance.
void route(Stringto)
{
Stackrev
= new Stack();
int dist = 0 ;
FlightInfof;
int num = btStack.size();

// Reversethestacktodisplayroute.
for ( int i = 0 ;i < num;i ++ )
rev.push(btStack.pop());

for ( int i = 0 ;i < num;i ++ ){
f
= (FlightInfo)rev.pop();
System.out.print(f.from
+ " to " );
dist
+= f.distance;
}

System.out.println(to);
System.out.println(
" Distanceis " + dist);
}

/* Ifthereisaflightbetweenfromandto,
returnthedistanceofflight;
otherwise,return0.
*/
int match(Stringfrom,Stringto)
{
for ( int i = numFlights - 1 ;i > - 1 ;i -- ){
if (flights[i].from.equals(from) &&
flights[i].to.equals(to)
&&
! flights[i].skip)
{
flights[i].skip
= true ; // preventreuse
return flights[i].distance;
}
}

return 0 ; // notfound
}

// Givenfrom,findanyconnection.
FlightInfofind(Stringfrom)
{
for ( int i = 0 ;i < numFlights;i ++ ){
if (flights[i].from.equals(from) &&
! flights[i].skip)
{
FlightInfof
= new FlightInfo(flights[i].from,
flights[i].to,
flights[i].distance);
flights[i].skip
= true ; // preventreuse

return f;
}
}

return null ;
}

/* Determineifthereisaroutebetweenfromandto
usingbreadth-firstsearch.
*/
void isflight(Stringfrom,Stringto)
{
int dist,dist2;
FlightInfof;

// Thisstackisneededbythebreadth-firstsearch.
StackresetStck = new Stack();

// Seeifatdestination.
dist = match(from,to);
if (dist != 0 ){
btStack.push(
new FlightInfo(from,to,dist));
return ;
}

/* Followingisthefirstpartofthebreadth-first
modification.Itchecksallconnectingflights
fromaspecifiednode.
*/
while ((f = find(from)) != null ){
resetStck.push(f);
if ((dist = match(f.to,to)) != 0 ){
resetStck.push(f.to);
btStack.push(
new FlightInfo(from,f.to,f.distance));
btStack.push(
new FlightInfo(f.to,to,dist));
return ;
}
}

/* Thefollowingcoderesetstheskipfieldssetby
precedingwhileloop.Thisisalsopartofthe
breadth-firstmodifiction.
*/
int i = resetStck.size();
for (;i != 0 ;i -- )
resetSkip((FlightInfo)resetStck.pop());

// Tryanotherconnection.
f = find(from);
if (f != null ){
btStack.push(
new FlightInfo(from,to,f.distance));
isflight(f.to,to);
}
else if (btStack.size() > 0 ){
// Backtrackandtryanotherconnection.
f = (FlightInfo)btStack.pop();
isflight(f.from,f.to);
}
}

// Resetskipfieldofspecifiedflight.
void resetSkip(FlightInfof){
for ( int i = 0 ;i < numFlights;i ++ )
if (flights[i].from.equals(f.from) &&
flights[i].to.equals(f.to))
flights[i].skip
= false ;
}
}

C:\java>

它找到了一个合理的解,但这不具有一般性。因为找到的第一条路径取决于信息的物理组织形式。

深度优先搜索和广度优先搜索

如果目标在搜索空间中隐藏得不是太深,那么广度优先搜索的性能会很好。

深度优先搜索和广度优先搜索


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论