zoukankan      html  css  js  c++  java
  • 广度优先和深度优先

      1 package test;
      2 
      3 import java.util.ArrayList;
      4 import java.util.LinkedList;
      5 
      6 public class Graph {
      7     private int[][] edges;
      8     private ArrayList vertexList;
      9     private boolean[] isVisited;
     10     private int numVertex;
     11 
     12     public Graph(int n) {
     13         edges = new int[n][n];
     14         vertexList = new ArrayList(n);
     15         isVisited = new boolean[n];
     16         numVertex = n;




    17 // 每个顶点初始化为false 18 for (int i = 0; i < n; i++) { 19 isVisited[i] = false; 20 } 21 } 22 23 public void insertVertex(String vertex) { 24 vertexList.add(vertex); 25 } 26 27 public void insertEdge(int v1, int v2, int weight) { 28 edges[v1][v2] = weight; 29 } 30 31 public void depthFirstSearch() { 32 for (int i = 0; i < numVertex; i++) { 33 if (!isVisited[i])// 如果某个点没访问的话,那么去遍历 34 { 35 depthFirstSearch(isVisited, i); 36 } 37 } 38 } 39 40 public int getFirstNeighbor(int index) { 41 for (int j = 0; j < numVertex; j++) { 42 if (edges[index][j] > 0) { 43 return j; 44 } 45 } 46 return -1;// 表示此点没有与之相邻的点 47 } 48 49 // 从v2开始检查,可以减少计算量 50 public int getNextNeighbor(int v1, int v2) { 51 for (int j = v2 + 1; j < numVertex; j++) { 52 if (edges[v1][j] > 0) { 53 return j; 54 } 55 } 56 return -1; 57 } 58 59 public void depthFirstSearch(boolean[] isVisited, int i) { 60 // 61 System.out.print(vertexList.get(i) + " "); 62 isVisited[i] = true; 63 int newStartNode = getFirstNeighbor(i); 64 while (newStartNode != -1) { 65 if (!isVisited[newStartNode])// 如果这个点没有被访问 66 { 67 depthFirstSearch(isVisited, newStartNode); 68 } 69 newStartNode = getNextNeighbor(i, newStartNode); 70 } 71 } 72 73 // 广度优先 74 public void broadFirstSearch() { 75 for (int i = 0; i < numVertex; i++) { 76 broadFirstSearch(isVisited, i); 77 } 78 } 79 80 private void broadFirstSearch(boolean[] isVisited, int i) { 81 int currentVisitedNode, adjacentCurrentVisitedNode; 82 LinkedList queue = new LinkedList(); 83 // 访问该节点 84 System.out.print(vertexList.get(i) + " "); 85 isVisited[i] = true; 86 // 节点入队列 87 queue.add(i); 88 while (!queue.isEmpty()) { 89 currentVisitedNode = ((Integer) queue.removeFirst()).intValue();// 移除队列的第一个元素,即头 90 adjacentCurrentVisitedNode = getFirstNeighbor(currentVisitedNode); 91 92 while (adjacentCurrentVisitedNode != -1) { 93 if (!isVisited[adjacentCurrentVisitedNode]) { 94 // 访问该节点 95 System.out.print(vertexList.get(adjacentCurrentVisitedNode) + " "); 96 // 标记该节点 97 isVisited[adjacentCurrentVisitedNode] = true; 98 // 入队列 99 queue.addLast(adjacentCurrentVisitedNode); 100 } 101 // 寻找下一个邻接节点 102 adjacentCurrentVisitedNode = getNextNeighbor(currentVisitedNode, adjacentCurrentVisitedNode); 103 } 104 } 105 106 } 107 }
     1 package test;
     2 
     3 public class TestSearch {
     4     public static void main(String args[]) {
     5 
     6         String labels[] = { "1", "2", "3", "4", "5" };// 结点的标识
     7         int n = labels.length;
     8         Graph graph = new Graph(n);
     9         for (String label : labels) {
    10             graph.insertVertex(label);// 插入结点
    11         }
    12         // 插入四条边
    13         graph.insertEdge(0, 1, 1);
    14         graph.insertEdge(0, 2, 1);
    15         graph.insertEdge(1, 3, 1);
    16         graph.insertEdge(1, 4, 1);
    17 
    18         System.out.println("深度优先搜索序列为:");
    19         graph.depthFirstSearch();
    20         
    21          System.out.println();
    22          System.out.println("广度优先搜索序列为:");
    23          graph.broadFirstSearch();
    24     }
    25 }

    运行结果如下:

    深度优先搜索序列为:
    1 2 4 5 3
    广度优先搜索序列为:
    1 2 3 4 5

    总的来说,BFS多用于寻找最短路径的问题,DFS多用于快速发现底部节点。

    DFS的思想是从一个顶点V0开始,沿着一条路一直走到底,如果发现不能到达目标解,那就返回到上一个节点,然后从另一条路开始走到底。

    DFS适合此类题目:给定初始状态跟目标状态,要求判断从初始状态到目标状态是否有解。

    深度与广度的比较:

    我们搜索一个图是按照树的层次来搜索的。

    我们假设一个节点衍生出来的相邻节点平均的个数是N个,那么当起点开始搜索的时候,队列有一个节点,当起点拿出来后,把它相邻的节点放进去,那么队列就有N个节点,当下一层

    的搜索中再加入元素到队列的时候,节点数达到了N/2,你可以想象,一旦N是一个比较大的数的时候,这个树的层次又比较深,那这个队列就需要很大的内存空间了。

    于是广度优先搜索的缺点出来了:在树的层次较深或子节点数较多的情况下,消耗内存十分严重。广度优先搜索适用于节点的子节点数量不多,并且树的层次不会太深的情况。

    那么深度优先就可以克服这个缺点,因为每次搜的过程,每一层只需维护一个节点。但回过头想想,广度优先能够找到最短路径,那深度优先能否找到呢?深度优先的方法是一条路走到黑,

    那显然无法知道这条路是不是最短的,所以你还得继续走别的路去判断是否是最短路?

    于是深度优先搜索的缺点也出来了:难以寻找最优解,只能寻找有解。其优点就是内存消耗小,克服了刚刚说的广度优先搜索的缺点。

    递归版深度优先

     1 public class DFSTest
     2 {
     3     private int vertexNum;//顶点个数
     4     private int[][] adjacent;//邻接矩阵
     5     private boolean[] isVisited;//顶点是否经过的标记
     6     private char[] nodeName;//顶点名称
     7     
     8     //图的初始化
     9     public DFSTest(int n)
    10     {
    11         vertexNum=n;
    12         adjacent=new int[vertexNum][vertexNum];
    13         isVisited=new boolean[vertexNum];
    14         for (int i=0;i<vertexNum;i++)
    15         {
    16             for (int j=0;j<vertexNum;j++)
    17             {
    18                 adjacent[i][j]=0;
    19             }
    20         }
    21         
    22         for (int k=0;k<n;k++)
    23         {
    24             isVisited[k]=false;
    25         }
    26     }
    27     
    28     public void setNodeName(char[] a)
    29     {
    30         nodeName=new char[vertexNum];
    31         for (int i=0;i<a.length;i++)
    32         {
    33             nodeName[i]=a[i];
    34         }
    35     }
    36     
    37     //无向图
    38     public void setAdjacent(int i,int j)
    39     {
    40         adjacent[i][j]=1;
    41         adjacent[j][i]=1;
    42     }
    43     
    44     
    45     
    46     //遍历
    47     public void dfsTraverse()
    48     {
    49         for (int i=0;i<vertexNum;i++)
    50         {
    51             if (isVisited[i]==false)
    52             {
    53                 dfs(i);
    54             }
    55         }
    56     }
    57     
    58     public void dfs(int n)
    59     {
    60         isVisited[n]=true;//
    61         //可利用每次遍历的节点的个数来判断此路是否有解
    62         System.out.println(nodeName[n]);
    63         for (int i=0;i<vertexNum;i++)
    64         {
    65             if (adjacent[n][i]==1&&isVisited[i]==false)
    66             {
    67                 dfs(i);
    68             }
    69         }
    70     }
    71     
    72     
    73     public static void main(String[] args)
    74     {
    75         int n=4;//表示图中顶点的个数
    76         DFSTest dfsTest=new DFSTest(n);
    77         //给顶点赋名字
    78         char[] name={'A','B','C','D'};
    79         dfsTest.setNodeName(name);
    80         //加边
    81         dfsTest.setAdjacent(0, 1);
    82         dfsTest.setAdjacent(1, 3);
    83         dfsTest.setAdjacent(2, 3);
    84         
    85         dfsTest.dfsTraverse();
    86         
    87     }
    88 }
  • 相关阅读:
    自定义TypeConverter把基础类型转换为复杂类型
    自学MVC看这里——全网最全ASP.NET MVC 教程汇总
    C#枚举器接口IEnumerator的实现
    nopCommerce架构分析系列(二)数据Cache
    NET下三种缓存机制(Winform里面的缓存使用 )
    【RequireJS--API学习笔记】
    Linux文件的所有权与权限
    ftp服务及其实现之vsftpd
    计算机传输层端口分类
    命令:tr
  • 原文地址:https://www.cnblogs.com/xh0102/p/5312951.html
Copyright © 2011-2022 走看看