有兩種常用的方法可用來搜尋圖:即深度優先搜尋和廣度優先搜尋。它們最終都會到達所有連通的頂點。深度優先搜尋通過棧來實現,而廣度優先搜尋通過隊列來實現。
深度優先搜尋:
下面圖中的數字顯示了深度優先搜尋頂點被訪問的順序。
為了實現深度優先搜尋,首先選擇一個起始頂點並需要遵守三個規則:
(1) 如果可能,訪問一個鄰接的未訪問頂點,標記它,並把它放入棧中。
(2) 當不能執行規則1時,如果棧不空,就從棧中彈出一個頂點。
(3) 如果不能執行規則1和規則2,就完成了整個搜尋過程。
廣度優先搜尋:
在深度優先搜尋中,演算法表現得好像要儘快地遠離起始點似的。相反,在廣度優先搜尋中,演算法好像要儘可能地靠近起始點。它首先訪問起始頂點的所有鄰接點,然後再訪問較遠的地區。它是用隊列來實現的。
下面圖中的數字顯示了廣度優先搜尋頂點被訪問的順序。
實現廣度優先搜尋,也要遵守三個規則:
(1) 訪問下一個未來訪問的鄰接點,這個頂點必須是當前頂點的鄰接點,標記它,並把它插入到隊列中。
(2) 如果因為已經沒有未訪問頂點而不能執行規則1時,那麼從隊列頭取一個頂點,並使其成為當前頂點。
(3) 如果因為隊列為空白而不能執行規則2,則搜尋結束。
下面是一個圖類的java代碼,dfs()為深度優先搜尋演算法,bfs()為廣度優先搜尋演算法:
//用於實現深度優先搜尋的棧類
class StackX{
private final int SIZE=20;
private int[] st;
private int top;
public StackX(){
st=new int[SIZE];
top=-1;
}
public void push(int j){
st[++top]=j;
}
public int pop(){
return st[top--];
}
public int peek(){
return st[top];
}
public boolean isEmpty(){
return top==-1;
}
}
//用於實現廣度優先搜尋的隊列類
class Queue{
private final int SIZE=20;
private int[] queArray;
private int front;
private int rear;
public Queue(){
queArray=new int[SIZE];
front=0;
rear=-1;
}
public void insert(int j){
if(rear==SIZE-1)
rear=-1;
queArray[++rear]=j;
}
public int remove(){
int temp=queArray[front++];
if(front==SIZE)
front=0;
return temp;
}
public boolean isEmpty(){
return ((rear+1==front)||(front+SIZE-1==rear));
}
}
//頂點類
class Vertex{
public char label;
public boolean wasVisited;
public Vertex(char lab){
label=lab;
wasVisited=false;
}
}
//圖類
public class Graph {
private final int MAX_VERTS=20;
private Vertex vertexList[];
private int adjMat[][];
private int nVerts;
private StackX theStack;
private Queue theQueue;
/** Creates a new instance of Graph */
public Graph() {
vertexList=new Vertex[MAX_VERTS];
adjMat=new int[MAX_VERTS][MAX_VERTS];
nVerts=0;
for (int j = 0; j < MAX_VERTS; j++) {
for (int k = 0; k < MAX_VERTS; k++) {
adjMat[j][k]=0;
}
}
theStack=new StackX();
theQueue=new Queue();
}
//增加一個頂點
public void addVertex(char lab){
vertexList[nVerts++]=new Vertex(lab);
}
//增加一條邊
public void addEdge(int start,int end){
adjMat[start][end]=1;
adjMat[end][start]=1;
}
public void displayVertex(int v){
System.out.print(vertexList[v].label);
}
//深度優先搜尋
public void dfs(){
vertexList[0].wasVisited=true;
displayVertex(0);
theStack.push(0);
while(!theStack.isEmpty()){
int v=getAdjUnvisitedVertex(theStack.peek());
if(v==-1)
theStack.pop();
else{
vertexList[v].wasVisited=true;
displayVertex(v);
theStack.push(v);
}
}
for(int j=0;j<nVerts;j++)
vertexList[j].wasVisited=false;
}
//得到與v頂點鄰接且未訪問過的頂點標號
public int getAdjUnvisitedVertex(int v){
for (int j = 0; j < nVerts; j++) {
if(adjMat[v][j]==1&&vertexList[j].wasVisited==false)
return j;
}
return -1;
}
//廣度優先搜尋
public void bfs(){
vertexList[0].wasVisited=true;
displayVertex(0);
theQueue.insert(0);
int v2;
while(!theQueue.isEmpty()){
int v1=theQueue.remove();
while((v2=getAdjUnvisitedVertex(v1))!=-1){
vertexList[v2].wasVisited=true;
displayVertex(v2);
theQueue.insert(v2);
}
}
for (int j = 0; j < nVerts; j++) {
vertexList[j].wasVisited=false;
}
}
}