`

(转贴)深度优先搜索和广度优先搜索

阅读更多

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

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

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

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

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

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


<script type="text/javascript"><!----></script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"> </script>


 

三、广度优先搜索

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

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

 

四、航班问题(来自《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英里

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

// 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.\n");
  }

  // 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>

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

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

// 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.\n");
  }

  // 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>java Breadth
From? New York
To? Los Angeles
New York to Toronto to Los Angeles
Distance is 3000

C:\java>

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

 

 

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

相关推荐

    [转贴]Symbian编程VC开发环境设置 (方便个人学习用,转载自 rocklys的专栏,转贴请搜索原作者) - waferham的专栏 - CSDNBlog.mht

    [转贴]Symbian编程VC开发环境设置 (方便个人学习用,转载自 rocklys的专栏,转贴请搜索原作者) - waferham的专栏

    动易系统的论坛转贴工具

    《动易系统的论坛转贴工具详解与应用》 在互联网信息交流日益频繁的今天,论坛作为用户互动的重要平台...通过深入理解和熟练运用,我们可以更好地利用论坛转贴工具,推动内容的广泛传播,实现互联网信息的共享与繁荣。

    易语言动网转贴

    3. **搜寻**:在编程中,搜索功能用于在数据或文本中查找特定的信息。在易语言中,可以使用字符串处理函数进行搜索操作。 4. **文件处理**:文件处理是编程中的基本操作,包括打开、读取、写入、关闭文件等。在转贴...

    易语言源码动网转贴.rar

    3. **用户身份验证**:为了确保用户权限和安全性,动网转贴功能可能涉及到用户登录状态的检查和验证,这可能需要用到Cookie、Session或Token等技术。 4. **界面设计**:在用户界面方面,需要设计友好的操作界面,让...

    动网转贴.e.rar

    动网论坛的用户可能经常进行帖子的分享和转贴,这些信息可能包括帖子的文本内容、图片、链接和其他附件。.rar文件格式是一种常见的压缩格式,用于将多个文件打包在一起,减少存储空间并方便传输。 【标签】"动网...

    BFC UBB转贴器

    由于现在流行的转贴工具都是基于浏览器的,转换速度比较慢,还得打开浏览器才能使用(同时受到浏览器版本限制)。 &lt;br&gt; 而这个小程序则完全不依赖于浏览器,以BFC采集器的UBB转换模块为基础,转换速度超快,...

    易语言动网转贴.rar

    "动网转贴"可能是基于易语言编写的一个功能模块或者工具,用于在论坛或者网站之间转移帖子数据。由于压缩包文件名为“易语言动网转贴.rar”,我们可以推测这可能是一个软件开发资源,包含了一些源代码、教程或者是...

    动网转贴.zip易语言项目例子源码下载

    在“动网转贴”项目中,用户可能可以通过界面浏览帖子,搜索特定内容,甚至进行简单的互动操作。 作为学习和参考的实例,这个项目能帮助你掌握易语言的基本语法和编程技巧,了解网络编程的基本流程,以及如何设计和...

    Html处理软件、转贴工具(源代码)

    去除Html中的干扰码等(样例中以轻之国度的干扰码为例) 配置文件语法: 方法类型(整数) 最大匹配长度(整数) 字符串1(删除开头) 字符串2(删除结尾) 方法类型: 1:删除单行 2:删除行与行之间的

    ZZ: 时间管理方法(转贴)

    【时间管理方法(转贴)】 时间管理是个人和团队高效工作的关键,它涉及到如何规划、组织和执行任务,以确保在限定的时间内达成目标。本文将深入探讨时间管理的重要性和一些常用的方法。 时间管理的重要性在于它能...

    jquery的转贴功能实现

    在网页开发中,jQuery是一个非常流行的JavaScript库,它极大地简化了DOM操作、事件处理和Ajax交互等任务。在本主题中,我们将深入探讨如何利用jQuery实现“转贴”功能,这是一种常见的社交媒体分享功能,允许用户将...

    电子政务-导电泡棉转贴装置.zip

    综上所述,"导电泡棉转贴装置"在电子政务中的应用涉及到硬件设计、设备维护、电磁兼容性和法规遵从等多个方面,是保障电子政务系统稳定运行的关键技术之一。通过阅读"行业分类-电子政务-导电泡棉转贴装置.pdf"这份...

    关于嵌入式系统方向!【转贴】.doc

    3. 跨学科要求:嵌入式开发需要同时掌握硬件和软件知识,这对个人的知识广度和深度提出更高要求。 4. 孤独感:由于工作范围相对狭窄,开发者可能长时间专注于某一特定领域,缺乏多样性,可能会感到工作内容单调。 ...

    东度极品论坛转贴工具

    东度极品论坛转贴工具东度极品论坛转贴工具

    论坛专用屏蔽干扰码转贴工具

    标题中的“论坛专用屏蔽干扰码转贴工具”指的是一个专为论坛设计的软件,它的主要功能是处理并转换论坛上常见的干扰码,以便用户能够顺利地复制和粘贴信息。在论坛交流中,有时为了防止恶意爬虫或者保护内容不被搜索...

    行业分类-设备装置-FPC吸附胶纸转贴组件.zip

    合适的胶纸类型和转贴工艺能够有效防止FPC在使用过程中发生松动、脱落,甚至损坏,从而保证设备的稳定运行和信号传输的可靠性。 FPC吸附胶纸转贴组件在各种设备装置中都有应用,例如智能手机、平板电脑、医疗设备、...

    windows 下的grep,转贴

    标题中的“windows 下的grep,转贴”表明我们要讨论的是如何在Windows操作系统中使用grep命令,这个命令通常在Unix或Linux环境中用于搜索文本文件中的特定模式。在Windows中,由于默认命令行环境(CMD)不支持grep,...

    电子功用-导电胶配对模切对半转贴加工方法

    本篇将详细探讨“电子功用-导电胶配对模切对半转贴加工方法”,这是一种高效的生产工艺,旨在提高电子产品的性能和可靠性。 导电胶主要由导电填料(如金属颗粒)、树脂基体和添加剂组成。它的特性在于既能保持良好...

Global site tag (gtag.js) - Google Analytics