有两种常用的方法可用来搜索图:即深度优先搜索和广度优先搜索。它们最终都会到达所有连通的顶点。深度优先搜索通过栈来实现,而广度优先搜索通过队列来实现。
深度优先搜索:
下面图中的数字显示了深度优先搜索顶点被访问的顺序。
为了实现深度优先搜索,首先选择一个起始顶点并需要遵守三个规则:
(1) 如果可能,访问一个邻接的未访问顶点,标记它,并把它放入栈中。
(2) 当不能执行规则1时,如果栈不空,就从栈中弹出一个顶点。
(3) 如果不能执行规则1和规则2,就完成了整个搜索过程。
广度优先搜索:
在深度优先搜索中,算法表现得好像要尽快地远离起始点似的。相反,在广度优先搜索中,算法好像要尽可能地靠近起始点。它首先访问起始顶点的所有邻接点,然后再访问较远的区域。它是用队列来实现的。
下面图中的数字显示了广度优先搜索顶点被访问的顺序。
实现广度优先搜索,也要遵守三个规则:
(1) 访问下一个未来访问的邻接点,这个顶点必须是当前顶点的邻接点,标记它,并把它插入到队列中。
(2) 如果因为已经没有未访问顶点而不能执行规则1时,那么从队列头取一个顶点,并使其成为当前顶点。
(3) 如果因为队列为空而不能执行规则2,则搜索结束。
下面是一个图类的java代码,dfs()为深度优先搜索算法,bfs()为广度优先搜索算法:
深度优先搜索:
下面图中的数字显示了深度优先搜索顶点被访问的顺序。
为了实现深度优先搜索,首先选择一个起始顶点并需要遵守三个规则:
(1) 如果可能,访问一个邻接的未访问顶点,标记它,并把它放入栈中。
(2) 当不能执行规则1时,如果栈不空,就从栈中弹出一个顶点。
(3) 如果不能执行规则1和规则2,就完成了整个搜索过程。
广度优先搜索:
在深度优先搜索中,算法表现得好像要尽快地远离起始点似的。相反,在广度优先搜索中,算法好像要尽可能地靠近起始点。它首先访问起始顶点的所有邻接点,然后再访问较远的区域。它是用队列来实现的。
下面图中的数字显示了广度优先搜索顶点被访问的顺序。
实现广度优先搜索,也要遵守三个规则:
(1) 访问下一个未来访问的邻接点,这个顶点必须是当前顶点的邻接点,标记它,并把它插入到队列中。
(2) 如果因为已经没有未访问顶点而不能执行规则1时,那么从队列头取一个顶点,并使其成为当前顶点。
(3) 如果因为队列为空而不能执行规则2,则搜索结束。
下面是一个图类的java代码,dfs()为深度优先搜索算法,bfs()为广度优先搜索算法:
//用于实现深度优先搜索的栈类
1 class StackX{ 2 private final int SIZE=20; 3 private int[] st; 4 private int top; 5 public StackX(){ 6 st=new int[SIZE]; 7 top=-1; 8 } 9 public void push(int j){ 10 st[++top]=j; 11 } 12 public int pop(){ 13 return st[top--]; 14 } 15 public int peek(){ 16 return st[top]; 17 } 18 public boolean isEmpty(){ 19 return top==-1; 20 } 21 } 22 //用于实现广度优先搜索的队列类 23 class Queue{ 24 private final int SIZE=20; 25 private int[] queArray; 26 private int front; //父节点 27 private int rear; //子节点 28 public Queue(){ 29 queArray=new int[SIZE]; 30 front=0; 31 rear=-1; 32 } 33 public void insert(int j){ //扩展此父节点的儿子 34 if(rear==SIZE-1) 35 rear=-1; 36 queArray[++rear]=j; 37 } 38 public int remove(){ //换下一个父节点 39 int temp=queArray[front++]; 40 if(front==SIZE) 41 front=0; 42 return temp; 43 } 44 public boolean isEmpty(){ 45 return ((rear+1==front)||(front+SIZE-1==rear)); 46 } 47 } 48 //顶点类 49 class Vertex{ 50 public char label; 51 public boolean wasVisited; 52 public Vertex(char lab){ 53 label=lab; 54 wasVisited=false; 55 } 56 } 57 //图类 58 public class Graph { 59 60 private final int MAX_VERTS=20; 61 private Vertex vertexList[]; 62 private int adjMat[][]; 63 private int nVerts; 64 private StackX theStack; 65 private Queue theQueue; 66 67 /** Creates a new instance of Graph */ 68 public Graph() { 69 vertexList=new Vertex[MAX_VERTS]; 70 adjMat=new int[MAX_VERTS][MAX_VERTS]; 71 nVerts=0; 72 for (int j = 0; j < MAX_VERTS; j++) { 73 for (int k = 0; k < MAX_VERTS; k++) { 74 adjMat[j][k]=0; 75 } 76 } 77 theStack=new StackX(); 78 theQueue=new Queue(); 79 } 80 //增加一个顶点 81 public void addVertex(char lab){ 82 vertexList[nVerts++]=new Vertex(lab); 83 } 84 //增加一条边 85 public void addEdge(int start,int end){ 86 adjMat[start][end]=1; 87 adjMat[end][start]=1; 88 } 89 public void displayVertex(int v){ 90 System.out.print(vertexList[v].label); 91 } 92 //深度优先搜索 93 public void dfs(){ 94 vertexList[0].wasVisited=true; 95 displayVertex(0); 96 theStack.push(0); 97 while(!theStack.isEmpty()){ 98 int v=getAdjUnvisitedVertex(theStack.peek()); 99 if(v==-1) 100 theStack.pop(); 101 else{ 102 vertexList[v].wasVisited=true; 103 displayVertex(v); 104 theStack.push(v); 105 } 106 } 107 for(int j=0;j<nVerts;j++) 108 vertexList[j].wasVisited=false; 109 } 110 //得到与v顶点邻接且未访问过的顶点标号 111 public int getAdjUnvisitedVertex(int v){ 112 for (int j = 0; j < nVerts; j++) { 113 if(adjMat[v][j]==1&&vertexList[j].wasVisited==false) 114 return j; 115 } 116 return -1; 117 } 118 //广度优先搜索 119 public void bfs(){ 120 vertexList[0].wasVisited=true; 121 displayVertex(0); 122 theQueue.insert(0); 123 int v2; 124 while(!theQueue.isEmpty()){ 125 int v1=theQueue.remove(); 126 while((v2=getAdjUnvisitedVertex(v1))!=-1){ 127 vertexList[v2].wasVisited=true; 128 displayVertex(v2); 129 theQueue.insert(v2); 130 } 131 } 132 for (int j = 0; j < nVerts; j++) { 133 vertexList[j].wasVisited=false; 134 } 135 } 136 137 }