您的位置:首页 > 其它

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

2007-04-19 19:07 405 查看
一、深度优先搜索

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

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

二、 重排九宫问题游戏

在一个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的航班机票,下面是航班线路,请你为顾客找一种购票方案。

[align=center]航班[/align]
[align=center]距离[/align]
New York到Chicago[align=center]900英里[/align]
Chicago到Denver[align=center]1000英里[/align]
New York到Toronto[align=center]500英里[/align]
New York到Denver[align=center]1800英里[/align]
Toronto到Calgary[align=center]1700英里[/align]
Toronto到Los Angeles[align=center]2500英里[/align]
Toronto到Chicago[align=center]500英里[/align]
Denver到Urbana[align=center]1000英里[/align]
Denver到Houston[align=center]1000英里[/align]
Houston到Los Angeles[align=center]1500英里[/align]
Denver到Los Angeles[align=center]1000英里[/align]
下面是用深度优先搜索求解的程序:

// Find connections using a depth-first search.

import java.util.*;

import java.io.*;

// Flight information.

class FlightInfo {

String from;

String to;

int distance;

boolean skip; // used in backtracking

FlightInfo(String f, String t, int d) {

from = f;

to = t;

distance = d;

skip = false;

}

}

class Depth {

final int MAX = 100;

// This array holds the flight information.

FlightInfo flights[] = new FlightInfo[MAX];

int numFlights = 0; // number of entries in flight array

Stack btStack = new Stack(); // backtrack stack

public static void main(String args[])

{

String to, from;

Depth ob = new Depth();

BufferedReader br = 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 (IOException exc) {

System.out.println("Error on input.");

}

}

// Initialize the flight database.

void setup()

{

addFlight("New York", "Chicago", 900);

addFlight("Chicago", "Denver", 1000);

addFlight("New York", "Toronto", 500);

addFlight("New York", "Denver", 1800);

addFlight("Toronto", "Calgary", 1700);

addFlight("Toronto", "Los Angeles", 2500);

addFlight("Toronto", "Chicago", 500);

addFlight("Denver", "Urbana", 1000);

addFlight("Denver", "Houston", 1000);

addFlight("Houston", "Los Angeles", 1500);

addFlight("Denver", "Los Angeles", 1000);

}

// Put flights into the database.

void addFlight(String from, String to, int dist)

{

if(numFlights < MAX) {

flights[numFlights] =

new FlightInfo(from, to, dist);

numFlights++;

}

else System.out.println("Flight database full.
");

}

// Show the route and total distance.

void route(String to)

{

Stack rev = new Stack();

int dist = 0;

FlightInfo f;

int num = btStack.size();

// Reverse the stack to display route.

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("Distance is " + dist);

}

/* If there is a flight between from and to,

return the distance of flight;

otherwise, return 0. */

int match(String from, String to)

{

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; // prevent reuse

return flights[i].distance;

}

}

return 0; // not found

}

// Given from, find any connection.

FlightInfo find(String from)

{

for(int i=0; i < numFlights; i++) {

if(flights[i].from.equals(from) &&

!flights[i].skip)

{

FlightInfo f = new FlightInfo(flights[i].from,

flights[i].to,

flights[i].distance);

flights[i].skip = true; // prevent reuse

return f;

}

}

return null;

}

// Determine if there is a route between from and to.

void isflight(String from, String to)

{

int dist;

FlightInfo f;

// See if at destination.

dist = match(from, to);

if(dist != 0) {

btStack.push(new FlightInfo(from, to, dist));

return;

}

// Try another connection.

f = find(from);

if(f != null) {

btStack.push(new FlightInfo(from, to, f.distance));

isflight(f.to, to);

}

else if(btStack.size() > 0) {

// Backtrack and try another connection.

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

// Find connections using a breadth-first search.

import java.util.*;

import java.io.*;

// Flight information.

class FlightInfo {

String from;

String to;

int distance;

boolean skip; // used in backtracking

FlightInfo(String f, String t, int d) {

from = f;

to = t;

distance = d;

skip = false;

}

}

class Breadth {

final int MAX = 100;

// This array holds the flight information.

FlightInfo flights[] = new FlightInfo[MAX];

int numFlights = 0; // number of entries in flight array

Stack btStack = new Stack(); // backtrack stack

public static void main(String args[])

{

String to, from;

Breadth ob = new Breadth();

BufferedReader br = 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 (IOException exc) {

System.out.println("Error on input.");

}

}

// Initialize the flight database.

void setup()

{

addFlight("New York", "Chicago", 900);

addFlight("Chicago", "Denver", 1000);

addFlight("New York", "Toronto", 500);

addFlight("New York", "Denver", 1800);

addFlight("Toronto", "Calgary", 1700);

addFlight("Toronto", "Los Angeles", 2500);

addFlight("Toronto", "Chicago", 500);

addFlight("Denver", "Urbana", 1000);

addFlight("Denver", "Houston", 1000);

addFlight("Houston", "Los Angeles", 1500);

addFlight("Denver", "Los Angeles", 1000);

}

// Put flights into the database.

void addFlight(String from, String to, int dist)

{

if(numFlights < MAX) {

flights[numFlights] =

new FlightInfo(from, to, dist);

numFlights++;

}

else System.out.println("Flight database full.
");

}

// Show the route and total distance.

void route(String to)

{

Stack rev = new Stack();

int dist = 0;

FlightInfo f;

int num = btStack.size();

// Reverse the stack to display route.

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("Distance is " + dist);

}

/* If there is a flight between from and to,

return the distance of flight;

otherwise, return 0. */

int match(String from, String to)

{

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; // prevent reuse

return flights[i].distance;

}

}

return 0; // not found

}

// Given from, find any connection.

FlightInfo find(String from)

{

for(int i=0; i < numFlights; i++) {

if(flights[i].from.equals(from) &&

!flights[i].skip)

{

FlightInfo f = new FlightInfo(flights[i].from,

flights[i].to,

flights[i].distance);

flights[i].skip = true; // prevent reuse

return f;

}

}

return null;

}

/* Determine if there is a route between from and to

using breadth-first search. */

void isflight(String from, String to)

{

int dist, dist2;

FlightInfo f;

// This stack is needed by the breadth-first search.

Stack resetStck = new Stack();

// See if at destination.

dist = match(from, to);

if(dist != 0) {

btStack.push(new FlightInfo(from, to, dist));

return;

}

/* Following is the first part of the breadth-first

modification. It checks all connecting flights

from a specified node. */

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;

}

}

/* The following code resets the skip fields set by

preceding while loop. This is also part of the

breadth-first modifiction. */

int i = resetStck.size();

for(; i!=0; i--)

resetSkip((FlightInfo) resetStck.pop());

// Try another connection.

f = find(from);

if(f != null) {

btStack.push(new FlightInfo(from, to, f.distance));

isflight(f.to, to);

}

else if(btStack.size() > 0) {

// Backtrack and try another connection.

f = (FlightInfo) btStack.pop();

isflight(f.from, f.to);

}

}

// Reset skip field of specified flight.

void resetSkip(FlightInfo f) {

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>

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



如果目标在搜索空间中隐藏得不是太深,那么广度优先搜索的性能会很好。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: