1. 程式人生 > >演算法與資料結構之圖的相關知識,簡單易懂。

演算法與資料結構之圖的相關知識,簡單易懂。

一、    圖的理論基礎

1)  概要

本章介紹資料結構中圖的基本概念。

目錄

1. 圖的基本概念

2. 圖的儲存結構

2)  圖的基本概念

1. 圖的定義

定義:圖(graph)是由一些點(vertex)和這些點之間的連線(edge)所組成的;其中,點通常被成為"頂點(vertex)",而點與點之間的連線則被成為"邊或弧"(edege)。通常記為,G=(V,E)。

2. 圖的種類

根據邊是否有方向,將圖可以劃分為:無向圖和有向圖。

2.1 無向圖

上面的圖G0是無向圖,無向圖的所有的邊都是不區分方向的。G0=(V1,{E1})。其中,

(01) V1={A,B,C,D,E,F}。 V1表示由"A,B,C,D,E,F"幾個頂點組成的集合。

(02) E1={(A,B),(A,C),(B,C),(B,E),(B,F),(C,F),(C,D),(E,F),(C,E)}。 E1是由邊(A,B),邊(A,C)...等等組成的集合。其中,(A,C)表示由頂點A和頂點C連線成的邊。

2.2 有向圖

上面的圖G2是有向圖。和無向圖不同,有向圖的所有的邊都是有方向的! G2=(V2,{A2})。其中,

(01) V2={A,C,B,F,D,E,G}。 V2表示由"A,B,C,D,E,F,G"幾個頂點組成的集合。

(02)A2={<A,B>,<B,C>,<B,F>,<B,E>,<C,E>,<E,D>,<D,C>,<E,B>,<F,G>}。 E1是由向量<A,B>,向量<B,C>...等等組成的集合。其中,向量<A,B)表示由"頂點A"指向"頂點C"的有向邊。

3. 鄰接點和度

3.1 鄰接點

一條邊上的兩個頂點叫做鄰接點。

例如,上面無向圖G0中的頂點A和頂點C就是鄰接點。

在有向圖中,除了鄰接點之外;還有"入邊"和"出邊"的概念。

頂點的入邊,是指以該頂點為終點的邊。而頂點的出邊,則是指以該頂點為起點的邊。

例如,上面有向圖G2中的B和E是鄰接點;<B,E>是B的出邊,還是E的入邊。

3.2 度

在無向圖中,某個頂點的度是鄰接到該頂點的邊(或弧)的數目。

例如,上面無向圖G0中頂點A的度是2。

在有向圖中,度還有"入度"和"出度"之分。

某個頂點的入度,是指以該頂點為終點的邊的數目。而頂點的出度,則是指以該頂點為起點的邊的數目。

頂點的度=入度+出度。

例如,上面有向圖G2中,頂點B的入度是2,出度是3;頂點B的度=2+3=5。

4. 路徑和迴路

路徑:如果頂點(Vm)到頂點(Vn)之間存在一個頂點序列。則表示Vm到Vn是一條路徑。

路徑長度:路徑中"邊的數量"。

簡單路徑:若一條路徑上頂點不重複出現,則是簡單路徑。

迴路:若路徑的第一個頂點和最後一個頂點相同,則是迴路。

簡單迴路:第一個頂點和最後一個頂點相同,其它各頂點都不重複的迴路則是簡單迴路。

5. 連通圖和連通分量

連通圖:對無向圖而言,任意兩個頂點之間都存在一條無向路徑,則稱該無向圖為連通圖。 對有向圖而言,若圖中任意兩個頂點之間都存在一條有向路徑,則稱該有向圖為強連通圖。

連通分量:非連通圖中的各個連通子圖稱為該圖的連通分量。

6. 權

在學習"哈夫曼樹"的時候,瞭解過"權"的概念。圖中權的概念與此類似。

上面就是一個帶權的圖。

3)  圖的儲存結構

上面瞭解了"圖的基本概念",下面開始介紹圖的儲存結構。圖的儲存結構,常用的是"鄰接矩陣"和"鄰接表"。

1. 鄰接矩陣

鄰接矩陣是指用矩陣來表示圖。它是採用矩陣來描述圖中頂點之間的關係(及弧或邊的權)。

假設圖中頂點數為n,則鄰接矩陣定義為:

下面通過示意圖來進行解釋。

圖中的G1是無向圖和它對應的鄰接矩陣。

圖中的G2是無向圖和它對應的鄰接矩陣。

通常採用兩個陣列來實現鄰接矩陣:一個一維陣列用來儲存頂點資訊,一個二維陣列來用儲存邊的資訊。

鄰接矩陣的缺點就是比較耗費空間。

2. 鄰接表

鄰接表是圖的一種鏈式儲存表示方法。它是改進後的"鄰接矩陣",它的缺點是不方便判斷兩個頂點之間是否有邊,但是相對鄰接矩陣來說更省空間。

圖中的G1是無向圖和它對應的鄰接矩陣。

圖中的G2是無向圖和它對應的鄰接矩陣。

二、    鄰接矩陣無向圖之Java詳解

1)  概要

本文通過Java實現鄰接矩陣無向圖。

目錄

1. 鄰接矩陣無向圖的介紹

2. 鄰接矩陣無向圖的程式碼說明

3. 鄰接矩陣無向圖的完整原始碼

2)  鄰接矩陣無向圖的介紹

鄰接矩陣無向圖是指通過鄰接矩陣表示的無向圖。

上面的圖G1包含了"A,B,C,D,E,F,G"共7個頂點,而且包含了"(A,C),(A,D),(A,F),(B,C),(C,D),(E,G),(F,G)"共7條邊。由於這是無向圖,所以邊(A,C)和邊(C,A)是同一條邊;這裡列舉邊時,是按照字母先後順序列舉的。

上圖右邊的矩陣是G1在記憶體中的鄰接矩陣示意圖。A[i][j]=1表示第i個頂點與第j個頂點是鄰接點,A[i][j]=0則表示它們不是鄰接點;而A[i][j]表示的是第i行第j列的值;例如,A[1,2]=1,表示第1個頂點(即頂點B)和第2個頂點(C)是鄰接點。

3)  鄰接矩陣無向圖的程式碼說明

1. 基本定義

public class MatrixUDG {

   private char[] mVexs;       // 頂點集合

   private int[][] mMatrix;    // 鄰接矩陣

   ...

}

MatrixUDG是鄰接矩陣對應的結構體。mVexs用於儲存頂點,mMatrix則是用於儲存矩陣資訊的二維陣列。例如,mMatrix[i][j]=1,則表示"頂點i(即mVexs[i])"和"頂點j(即mVexs[j])"是鄰接點;mMatrix[i][j]=0,則表示它們不是鄰接點。

2. 建立矩陣

這裡介紹提供了兩個建立矩陣的方法。一個是用已知資料,另一個則需要使用者手動輸入資料。

2.1 建立圖(用已提供的矩陣)

/*

 * 建立圖(用已提供的矩陣)

 *

 * 引數說明:

 *    vexs  -- 頂點陣列

 *    edges -- 邊陣列

 */

public MatrixUDG(char[] vexs, char[][]edges) {

   // 初始化"頂點數"和"邊數"

   int vlen = vexs.length;

   int elen = edges.length;

   // 初始化"頂點"

   mVexs = new char[vlen];

   for (int i = 0; i < mVexs.length; i++)

       mVexs[i] = vexs[i];

   // 初始化"邊"

   mMatrix = new int[vlen][vlen];

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

       // 讀取邊的起始頂點和結束頂點

       int p1 = getPosition(edges[i][0]);

       int p2 = getPosition(edges[i][1]);

       mMatrix[p1][p2] = 1;

       mMatrix[p2][p1] = 1;

    }

}

該函式的作用是利用已知資料來建立一個鄰接矩陣無向圖。 實際上,在本文的測試程式原始碼中,該方法建立的無向圖就是上面圖G1。具體的呼叫程式碼如下:

char[] vexs = {'A', 'B', 'C', 'D', 'E','F', 'G'};

char[][] edges = new char[][]{

   {'A', 'C'},

   {'A', 'D'},

   {'A', 'F'},

   {'B', 'C'},

   {'C', 'D'},

   {'E', 'G'},

   {'F', 'G'}};

MatrixUDG pG;

pG = new MatrixUDG(vexs, edges);

2.2 建立圖(自己輸入)

/*

 * 建立圖(自己輸入資料)

 */

public MatrixUDG() {

   // 輸入"頂點數"和"邊數"

   System.out.printf("input vertex number: ");

   int vlen = readInt();

   System.out.printf("input edge number: ");

   int elen = readInt();

   if ( vlen < 1 || elen < 1 || (elen > (vlen*(vlen - 1)))) {

       System.out.printf("input error: invalid parameters!\n");

       return ;

    }

   // 初始化"頂點"

   mVexs = new char[vlen];

   for (int i = 0; i < mVexs.length; i++) {

       System.out.printf("vertex(%d): ", i);

       mVexs[i] = readChar();

    }

   // 初始化"邊"

   mMatrix = new int[vlen][vlen];

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

       // 讀取邊的起始頂點和結束頂點

       System.out.printf("edge(%d):", i);

       char c1 = readChar();

       char c2 = readChar();

       int p1 = getPosition(c1);

       int p2 = getPosition(c2);

       if (p1==-1 || p2==-1) {

           System.out.printf("input error: invalid edge!\n");

           return ;

       }

       mMatrix[p1][p2] = 1;

       mMatrix[p2][p1] = 1;

    }

}

該函式是通過讀取使用者的輸入,而將輸入的資料轉換成對應的無向圖。

4)  鄰接矩陣無向圖的完整原始碼

/**

 *Java: 鄰接矩陣表示的"無向圖(ListUndirected Graph)"

 *

 *@author skywang

 *@date 2014/04/19

 */

import java.io.IOException;

import java.util.Scanner;

public class MatrixUDG {

   private char[] mVexs;       // 頂點集合

   private int[][] mMatrix;    // 鄰接矩陣

   /*

    * 建立圖(自己輸入資料)

    */

   public MatrixUDG() {

       // 輸入"頂點數"和"邊數"

       System.out.printf("input vertex number: ");

       int vlen = readInt();

       System.out.printf("input edge number: ");

       int elen = readInt();

       if ( vlen < 1 || elen < 1 || (elen > (vlen*(vlen - 1)))) {

           System.out.printf("input error: invalid parameters!\n");

           return ;

       }

       // 初始化"頂點"

       mVexs = new char[vlen];

       for (int i = 0; i < mVexs.length; i++) {

           System.out.printf("vertex(%d): ", i);

           mVexs[i] = readChar();

       }

       // 初始化"邊"

       mMatrix = new int[vlen][vlen];

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

           // 讀取邊的起始頂點和結束頂點

           System.out.printf("edge(%d):", i);

           char c1 = readChar();

           char c2 = readChar();

           int p1 = getPosition(c1);

           int p2 = getPosition(c2);

           if (p1==-1 || p2==-1) {

                System.out.printf("inputerror: invalid edge!\n");

                return ;

           }

           mMatrix[p1][p2] = 1;

           mMatrix[p2][p1] = 1;

       }

    }

   /*

    * 建立圖(用已提供的矩陣)

     *

    * 引數說明:

    *     vexs  -- 頂點陣列

    *     edges -- 邊陣列

    */

   public MatrixUDG(char[] vexs, char[][] edges) {

       // 初始化"頂點數"和"邊數"

       int vlen = vexs.length;

       int elen = edges.length;

       // 初始化"頂點"

       mVexs = new char[vlen];

       for (int i = 0; i < mVexs.length; i++)

           mVexs[i] = vexs[i];

       // 初始化"邊"

       mMatrix = new int[vlen][vlen];

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

           // 讀取邊的起始頂點和結束頂點

           int p1 = getPosition(edges[i][0]);

           int p2 = getPosition(edges[i][1]);

           mMatrix[p1][p2] = 1;

           mMatrix[p2][p1] = 1;

       }

    }

   /*

    * 返回ch位置

    */

   private int getPosition(char ch) {

       for(int i=0; i<mVexs.length; i++)

           if(mVexs[i]==ch)

                return i;

       return -1;

    }

   /*

    * 讀取一個輸入字元

    */

   private char readChar() {

       char ch='0';

       do {

           try {

                ch = (char)System.in.read();

           } catch (IOException e) {

                e.printStackTrace();

           }

       } while(!((ch>='a'&&ch<='z') ||(ch>='A'&&ch<='Z')));

       return ch;

    }

   /*

    * 讀取一個輸入字元

    */

   private int readInt() {

       Scanner scanner = new Scanner(System.in);

       return scanner.nextInt();

    }

   /*

    * 列印矩陣佇列圖

    */

   public void print() {

       System.out.printf("Martix Graph:\n");

       for (int i = 0; i < mVexs.length; i++) {

           for (int j = 0; j < mVexs.length; j++)

                System.out.printf("%d", mMatrix[i][j]);

           System.out.printf("\n");

       }

    }

   public static void main(String[] args) {

       char[] vexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};

       char[][] edges = new char[][]{

           {'A', 'C'},

           {'A', 'D'},

           {'A', 'F'},

           {'B', 'C'},

           {'C', 'D'},

           {'E', 'G'},

           {'F', 'G'}};

       MatrixUDG pG;

       // 自定義"圖"(輸入矩陣佇列)

       //pG = new MatrixUDG();

       // 採用已有的"圖"

       pG = new MatrixUDG(vexs, edges);

       pG.print();   // 列印圖

    }

}

三、    鄰接表無向圖之Java詳解

1)  概要

本文通過Java實現鄰接表無向圖。

目錄

1. 鄰接表無向圖的介紹

2. 鄰接表無向圖的程式碼說明

3. 鄰接表無向圖的完整原始碼

2)  鄰接表無向圖的介紹

鄰接表無向圖是指通過鄰接表表示的無向圖。

上面的圖G1包含了"A,B,C,D,E,F,G"共7個頂點,而且包含了"(A,C),(A,D),(A,F),(B,C),(C,D),(E,G),(F,G)"共7條邊。

上圖右邊的矩陣是G1在記憶體中的鄰接表示意圖。每一個頂點都包含一條連結串列,該連結串列記錄了"該頂點的鄰接點的序號"。例如,第2個頂點(頂點C)包含的連結串列所包含的節點的資料分別是"0,1,3";而這"0,1,3"分別對應"A,B,D"的序號,"A,B,D"都是C的鄰接點。就是通過這種方式記錄圖的資訊的。

3)  鄰接表無向圖的程式碼說明

1. 基本定義

public class ListUDG {

   // 鄰接表中表對應的連結串列的頂點

   private class ENode {

       int ivex;       // 該邊所指向的頂點的位置

       ENode nextEdge; // 指向下一條弧的指標

    }

   // 鄰接表中表的頂點

   private class VNode {

       char data;          // 頂點資訊

       ENode firstEdge;    // 指向第一條依附該頂點的弧

   };

   private VNode[] mVexs;  // 頂點陣列

   ...

}

(01) ListUDG是鄰接表對應的結構體。mVexs則是儲存頂點資訊的一維陣列。

(02) VNode是鄰接表頂點對應的結構體。 data是頂點所包含的資料,而firstEdge是該頂點所包含連結串列的表頭指標。

(03) ENode是鄰接表頂點所包含的連結串列的節點對應的結構體。 ivex是該節點所對應的頂點在vexs中的索引,而nextEdge是指向下一個節點的。

2. 建立矩陣

這裡介紹提供了兩個建立矩陣的方法。一個是用已知資料,另一個則需要使用者手動輸入資料。

2.1 建立圖(用已提供的矩陣)

/*

 * 建立圖(用已提供的矩陣)

 *

 * 引數說明:

 *    vexs  -- 頂點陣列

 *    edges -- 邊陣列

 */

public ListUDG(char[] vexs, char[][] edges){

   // 初始化"頂點數"和"邊數"

   int vlen = vexs.length;

   int elen = edges.length;

   // 初始化"頂點"

   mVexs = new VNode[vlen];

   for (int i = 0; i < mVexs.length; i++) {

       mVexs[i] = new VNode();

       mVexs[i].data = vexs[i];

       mVexs[i].firstEdge = null;

    }

   // 初始化"邊"

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

       // 讀取邊的起始頂點和結束頂點

       char c1 = edges[i][0];

       char c2 = edges[i][1];

       // 讀取邊的起始頂點和結束頂點

       int p1 = getPosition(edges[i][0]);

       int p2 = getPosition(edges[i][1]);

       // 初始化node1

        ENode node1 = new ENode();

       node1.ivex = p2;

       // 將node1連結到"p1所在連結串列的末尾"

       if(mVexs[p1].firstEdge == null)

         mVexs[p1].firstEdge = node1;

       else

           linkLast(mVexs[p1].firstEdge, node1);

       // 初始化node2

       ENode node2 = new ENode();

       node2.ivex = p1;

       // 將node2連結到"p2所在連結串列的末尾"

       if(mVexs[p2].firstEdge == null)

         mVexs[p2].firstEdge = node2;

       else

           linkLast(mVexs[p2].firstEdge, node2);

    }

}

該函式的作用是建立一個鄰接表無向圖。實際上,該方法建立的無向圖,就是上面圖G1。呼叫程式碼如下:

char[] vexs = {'A', 'B', 'C', 'D', 'E','F', 'G'};

char[][] edges = new char[][]{

   {'A', 'C'},

   {'A', 'D'},

   {'A', 'F'},

   {'B', 'C'},

   {'C', 'D'},

   {'E', 'G'},

   {'F', 'G'}};

ListUDG pG;

pG = new ListUDG(vexs, edges);

2.2 建立圖(自己輸入)

/*

 * 建立圖(自己輸入資料)

 */

public ListUDG() {

   // 輸入"頂點數"和"邊數"

   System.out.printf("input vertex number: ");

   int vlen = readInt();

   System.out.printf("input edge number: ");

   int elen = readInt();

   if ( vlen < 1 || elen < 1 || (elen > (vlen*(vlen - 1)))) {

       System.out.printf("input error: invalid parameters!\n");

       return ;

    }

   // 初始化"頂點"

   mVexs = new VNode[vlen];

   for (int i = 0; i < mVexs.length; i++) {

       System.out.printf("vertex(%d): ", i);

       mVexs[i] = new VNode();

       mVexs[i].data = readChar();

       mVexs[i].firstEdge = null;

    }

   // 初始化"邊"

   //mMatrix = new int[vlen][vlen];

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

       // 讀取邊的起始頂點和結束頂點

       System.out.printf("edge(%d):", i);

       char c1 = readChar();

       char c2 = readChar();

       int p1 = getPosition(c1);

       int p2 = getPosition(c2);

       // 初始化node1

       ENode node1 = new ENode();

       node1.ivex = p2;

       // 將node1連結到"p1所在連結串列的末尾"

       if(mVexs[p1].firstEdge == null)

         mVexs[p1].firstEdge = node1;

       else

           linkLast(mVexs[p1].firstEdge, node1);

       // 初始化node2

       ENode node2 = new ENode();

       node2.ivex = p1;

       // 將node2連結到"p2所在連結串列的末尾"

       if(mVexs[p2].firstEdge == null)

         mVexs[p2].firstEdge = node2;

       else

           linkLast(mVexs[p2].firstEdge, node2);

    }

}

該函式是讀取使用者的輸入,將輸入的資料轉換成對應的無向圖。

4)  鄰接表無向圖的完整原始碼

/**

 *Java: 鄰接表表示的"無向圖(ListUndirected Graph)"

 *

 *@author skywang

 *@date 2014/04/19

 */

import java.io.IOException;

import java.util.Scanner;

public class ListUDG {

   // 鄰接表中表對應的連結串列的頂點

   private class ENode {

       int ivex;       // 該邊所指向的頂點的位置

        ENode nextEdge; // 指向下一條弧的指標

    }

   // 鄰接表中表的頂點

   private class VNode {

       char data;          // 頂點資訊

       ENode firstEdge;    // 指向第一條依附該頂點的弧

   };

   private VNode[] mVexs;  // 頂點陣列

   /*

    * 建立圖(自己輸入資料)

    */

   public ListUDG() {

       // 輸入"頂點數"和"邊數"

       System.out.printf("input vertex number: ");

       int vlen = readInt();

       System.out.printf("input edge number: ");

       int elen = readInt();

       if ( vlen < 1 || elen < 1 || (elen > (vlen*(vlen - 1)))) {

           System.out.printf("input error: invalid parameters!\n");

           return ;

       }

       // 初始化"頂點"

       mVexs = new VNode[vlen];

       for (int i = 0; i < mVexs.length; i++) {

           System.out.printf("vertex(%d): ", i);

           mVexs[i] = new VNode();

           mVexs[i].data = readChar();

           mVexs[i].firstEdge = null;

       }

       // 初始化"邊"

       //mMatrix = new int[vlen][vlen];

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

           // 讀取邊的起始頂點和結束頂點

           System.out.printf("edge(%d):", i);

           char c1 = readChar();

           char c2 = readChar();

           int p1 = getPosition(c1);

           int p2 = getPosition(c2);

           // 初始化node1

           ENode node1 = new ENode();

           node1.ivex = p2;

           // 將node1連結到"p1所在連結串列的末尾"

           if(mVexs[p1].firstEdge == null)

              mVexs[p1].firstEdge = node1;

           else

                linkLast(mVexs[p1].firstEdge,node1);

           // 初始化node2

           ENode node2 = new ENode();

           node2.ivex = p1;

           // 將node2連結到"p2所在連結串列的末尾"

           if(mVexs[p2].firstEdge == null)

              mVexs[p2].firstEdge = node2;

           else

                linkLast(mVexs[p2].firstEdge,node2);

       }

    }

   /*

    * 建立圖(用已提供的矩陣)

    *

    * 引數說明:

    *     vexs  -- 頂點陣列

    *     edges -- 邊陣列

    */

   public ListUDG(char[] vexs, char[][] edges) {

       // 初始化"頂點數"和"邊數"

       int vlen = vexs.length;

       int elen = edges.length;

       // 初始化"頂點"

       mVexs = new VNode[vlen];

       for (int i = 0; i < mVexs.length; i++) {

           mVexs[i] = new VNode();

           mVexs[i].data = vexs[i];

           mVexs[i].firstEdge = null;

       }

       // 初始化"邊"

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

           // 讀取邊的起始頂點和結束頂點

           char c1 = edges[i][0];

           char c2 = edges[i][1];

           // 讀取邊的起始頂點和結束頂點

           int p1 = getPosition(edges[i][0]);

           int p2 = getPosition(edges[i][1]);

           // 初始化node1

           ENode node1 = new ENode();

           node1.ivex = p2;

           // 將node1連結到"p1所在連結串列的末尾"

           if(mVexs[p1].firstEdge == null)

              mVexs[p1].firstEdge = node1;

           else

                linkLast(mVexs[p1].firstEdge,node1);

           // 初始化node2

           ENode node2 = new ENode();

           node2.ivex = p1;

           // 將node2連結到"p2所在連結串列的末尾"

           if(mVexs[p2].firstEdge == null)

              mVexs[p2].firstEdge = node2;

           else

                linkLast(mVexs[p2].firstEdge,node2);

       }

    }

   /*

    * 將node節點連結到list的最後

    */

   private void linkLast(ENode list, ENode node) {

       ENode p = list;

       while(p.nextEdge!=null)

           p = p.nextEdge;

       p.nextEdge = node;

    }

   /*

    * 返回ch位置

    */

   private int getPosition(char ch) {

       for(int i=0; i<mVexs.length; i++)

           if(mVexs[i].data==ch)

                return i;

       return -1;

    }

   /*

    * 讀取一個輸入字元

    */

   private char readChar() {

       char ch='0';

       do {

           try {

                ch = (char)System.in.read();

           } catch (IOException e) {

                e.printStackTrace();

           }

       } while(!((ch>='a'&&ch<='z') ||(ch>='A'&&ch<='Z')));

       return ch;

    }

   /*

    * 讀取一個輸入字元

    */

   private int readInt() {

       Scanner scanner = new Scanner(System.in);

       return scanner.nextInt();

    }

   /*

    * 列印矩陣佇列圖

    */

   public void print() {

       System.out.printf("List Graph:\n");

       for (int i = 0; i < mVexs.length; i++) {

           System.out.printf("%d(%c): ", i, mVexs[i].data);

           ENode node = mVexs[i].firstEdge;

           while (node != null) {

                System.out.printf("%d(%c)", node.ivex, mVexs[node.ivex].data);

                node = node.nextEdge;

           }

           System.out.printf("\n");

       }

    }

   public static void main(String[] args) {

       char[] vexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};

       char[][] edges = new char[][]{

           {'A', 'C'},

           {'A', 'D'},

           {'A', 'F'},

           {'B', 'C'},

           {'C', 'D'},

           {'E', 'G'},

           {'F', 'G'}};

       ListUDG pG;

       // 自定義"圖"(輸入矩陣佇列)

       //pG = new ListUDG();

       // 採用已有的"圖"

       pG = new ListUDG(vexs, edges);

       pG.print();   // 列印圖

    }

}

四、    鄰接矩陣有向圖之Java詳解

1)  概要

本文通過Java實現鄰接矩陣有向圖。

目錄

1. 鄰接矩陣有向圖的介紹

2. 鄰接矩陣有向圖的程式碼說明

3. 鄰接矩陣有向圖的完整原始碼

2)  鄰接矩陣有向圖的介紹

鄰接矩陣有向圖是指通過鄰接矩陣表示的有向圖。

上面的圖G2包含了"A,B,C,D,E,F,G"共7個頂點,而且包含了"<A,B>,<B,C>,<B,E>,<B,F>,<C,E>,<D,C>,<E,B>,<E,D>,<F,G>"共9條邊。

上圖右邊的矩陣是G2在記憶體中的鄰接矩陣示意圖。A[i][j]=1表示第i個頂點到第j個頂點是一條邊,A[i][j]=0則表示不是一條邊;而A[i][j]表示的是第i行第j列的值;例如,A[1,2]=1,表示第1個頂點(即頂點B)到第2個頂點(C)是一條邊。

3)  鄰接矩陣有向圖的程式碼說明

1. 基本定義

public class MatrixDG {

   private char[] mVexs;       // 頂點集合

   private int[][] mMatrix;    // 鄰接矩陣

    ...

}

MatrixDG是鄰接矩陣有向圖對應的結構體。

mVexs用於儲存頂點,mMatrix則是用於儲存矩陣資訊的二維陣列。例如,mMatrix[i][j]=1,則表示"頂點i(即mVexs[i])"和"頂點j(即mVexs[j])"是鄰接點,且頂點i是起點,頂點j是終點。

2. 建立矩陣

這裡介紹提供了兩個建立矩陣的方法。一個是用已知資料,另一個則需要使用者手動輸入資料。

2.1 建立圖(用已提供的矩陣)

/*

 * 建立圖(用已提供的矩陣)

 *

 * 引數說明:

 *    vexs  -- 頂點陣列

 *    edges -- 邊陣列

 */

public MatrixDG(char[] vexs, char[][]edges) {

   // 初始化"頂點數"和"邊數"

   int vlen = vexs.length;

   int elen = edges.length;

   // 初始化"頂點"

   mVexs = new char[vlen];

   for (int i = 0; i < mVexs.length; i++)

       mVexs[i] = vexs[i];

   // 初始化"邊"

   mMatrix = new int[vlen][vlen];

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

       // 讀取邊的起始頂點和結束頂點

       int p1 = getPosition(edges[i][0]);

       int p2 = getPosition(edges[i][1]);

       mMatrix[p1][p2] = 1;

    }

}

該函式的作用是建立一個鄰接矩陣有向圖。實際上,該方法建立的有向圖,就是上面的圖G2。它的呼叫方法如下:

char[] vexs = {'A', 'B', 'C', 'D', 'E','F', 'G'};

char[][] edges = new char[][]{

   {'A', 'B'},

   {'B', 'C'},

   {'B', 'E'},

   {'B', 'F'},

   {'C', 'E'},

   {'D', 'C'},

   {'E', 'B'},

   {'E', 'D'},

   {'F', 'G'}};

MatrixDG pG;

pG = new MatrixDG(vexs, edges);

2.2 建立圖(自己輸入)

/*

 * 建立圖(自己輸入資料)

 */

public MatrixDG() {

   // 輸入"頂點數"和"邊數"

   System.out.printf("input vertex number: ");

   int vlen = readInt();

   System.out.printf("input edge number: ");

   int elen = readInt();

   if ( vlen < 1 || elen < 1 || (elen > (vlen*(vlen - 1)))) {

       System.out.printf("input error: invalid parameters!\n");

       return ;

    }

   // 初始化"頂點"

   mVexs = new char[vlen];

   for (int i = 0; i < mVexs.length; i++) {

       System.out.printf("vertex(%d): ", i);

       mVexs[i] = readChar();

    }

   // 初始化"邊"

   mMatrix = new int[vlen][vlen];

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

       // 讀取邊的起始頂點和結束頂點

       System.out.printf("edge(%d):", i);

       char c1 = readChar();

       char c2 = readChar();

       int p1 = getPosition(c1);

       int p2 = getPosition(c2);

       if (p1==-1 || p2==-1) {

           System.out.printf("input error: invalid edge!\n");

           return ;

       }

       mMatrix[p1][p2] = 1;

    }

}

該函式是讀取使用者的輸入,將輸入的資料轉換成對應的有向圖。

4)  鄰接矩陣有向圖的完整原始碼

/**

 *Java: 鄰接矩陣圖

 *

 *@author skywang

 *@date 2014/04/19

 */

import java.io.IOException;

import java.util.Scanner;

public class MatrixDG {

   private char[] mVexs;       // 頂點集合

   private int[][] mMatrix;    // 鄰接矩陣

   /*

    * 建立圖(自己輸入資料)

    */

   public MatrixDG() {

       // 輸入"頂點數"和"邊數"

       System.out.printf("input vertex number: ");

       int vlen = readInt();

       System.out.printf("input edge number: ");

       int elen = readInt();

       if ( vlen < 1 || elen < 1 || (elen > (vlen*(vlen - 1)))) {

           System.out.printf("input error: invalid parameters!\n");

           return ;

       }

       // 初始化"頂點"

       mVexs = new char[vlen];

       for (int i = 0; i < mVexs.length; i++) {

           System.out.printf("vertex(%d): ", i);

           mVexs[i] = readChar();

       }

       // 初始化"邊"

       mMatrix = new int[vlen][vlen];

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

           // 讀取邊的起始頂點和結束頂點

           System.out.printf("edge(%d):", i);

           char c1 = readChar();

           char c2 = readChar();

           int p1 = getPosition(c1);

           int p2 = getPosition(c2);

           if (p1==-1 || p2==-1) {

                System.out.printf("inputerror: invalid edge!\n");

                return ;

           }

           mMatrix[p1][p2] = 1;

       }

    }

   /*

    * 建立圖(用已提供的矩陣)

    *

    * 引數說明:

    *     vexs  -- 頂點陣列

    *     edges -- 邊陣列

    */

   public MatrixDG(char[] vexs, char[][] edges) {

       // 初始化"頂點數"和"邊數"

       int vlen = vexs.length;

       int elen = edges.length;

       // 初始化"頂點"

       mVexs = new char[vlen];

       for (int i = 0; i < mVexs.length; i++)

           mVexs[i] = vexs[i];

       // 初始化"邊"

       mMatrix = new int[vlen][vlen];

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

           // 讀取邊的起始頂點和結束頂點

           int p1 = getPosition(edges[i][0]);

            int p2 = getPosition(edges[i][1]);

           mMatrix[p1][p2] = 1;

       }

    }

   /*

    * 返回ch位置

    */

   private int getPosition(char ch) {

       for(int i=0; i<mVexs.length; i++)

           if(mVexs[i]==ch)

                return i;

       return -1;

    }

   /*

    * 讀取一個輸入字元

    */

   private char readChar() {

       char ch='0';

       do {

           try {

                ch = (char)System.in.read();

           } catch (IOException e) {

                e.printStackTrace();

           }

       } while(!((ch>='a'&&ch<='z') ||(ch>='A'&&ch<='Z')));

       return ch;

    }

   /*

    * 讀取一個輸入字元

    */

   private int readInt() {

       Scanner scanner = new Scanner(System.in);

       return scanner.nextInt();

    }

   /*

    * 列印矩陣佇列圖

    */

   public void print() {

       System.out.printf("Martix Graph:\n");

       for (int i = 0; i < mVexs.length; i++) {

           for (int j = 0; j < mVexs.length; j++)

                System.out.printf("%d", mMatrix[i][j]);

           System.out.printf("\n");

       }

    }

   public static void main(String[] args) {

       char[] vexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};

       char[][] edges = new char[][]{

           {'A', 'B'},

           {'B', 'C'},

           {'B', 'E'},

           {'B', 'F'},

           {'C', 'E'},

           {'D', 'C'},

           {'E', 'B'},

           {'E', 'D'},

           {'F', 'G'}};

       MatrixDG pG;

       // 自定義"圖"(輸入矩陣佇列)

       //pG = new MatrixDG();

       // 採用已有的"圖"

       pG = new MatrixDG(vexs, edges);

       pG.print();   // 列印圖

    }

}

五、    鄰接表有向圖之Java詳解

1)  概要

本文通過Java實現鄰接表有向圖。

目錄

1. 鄰接表有向圖的介紹

2. 鄰接表有向圖的程式碼說明

3. 鄰接表有向圖的完整原始碼

2)  鄰接表有向圖的介紹

鄰接表有向圖是指通過鄰接表表示的有向圖。

上面的圖G2包含了"A,B,C,D,E,F,G"共7個頂點,而且包含了"<A,B>,<B,C>,<B,E>,<B,F>,<C,E>,<D,C>,<E,B>,<E,D>,<F,G>"共9條邊。

上圖右邊的矩陣是G2在記憶體中的鄰接表示意圖。每一個頂點都包含一條連結串列,該連結串列記錄了"該頂點所對應的出邊的另一個頂點的序號"。例如,第1個頂點(頂點B)包含的連結串列所包含的節點的資料分別是"2,4,5";而這"2,4,5"分別對應"C,E,F"的序號,"C,E,F"都屬於B的出邊的另一個頂點。

3)  鄰接表有向圖的程式碼說明

1. 基本定義

public class ListDG {

   // 鄰接表中表對應的連結串列的頂點

   private class ENode {

       int ivex;       // 該邊所指向的頂點的位置

       ENode nextEdge; // 指向下一條弧的指標

    }

   // 鄰接表中表的頂點

   private class VNode {

       char data;          // 頂點資訊

       ENode firstEdge;    // 指向第一條依附該頂點的弧

   };

   private VNode[] mVexs;  // 頂點陣列

   ...

}

(01) ListDG是鄰接表對應的結構體。 mVexs則是儲存頂點資訊的一維陣列。

(02) VNode是鄰接表頂點對應的結構體。 data是頂點所包含的資料,而firstEdge是該頂點所包含連結串列的表頭指標。

(03) ENode是鄰接表頂點所包含的連結串列的節點對應的結構體。 ivex是該節點所對應的頂點在vexs中的索引,而nextEdge是指向下一個節點的。

2. 建立矩陣

這裡介紹提供了兩個建立矩陣的方法。一個是用已知資料,另一個則需要使用者手動輸入資料。

2.1 建立圖(用已提供的矩陣)

/*

 * 建立圖(用已提供的矩陣)

 *

 * 引數說明:

 *    vexs  -- 頂點陣列

 *    edges -- 邊陣列

 */

public ListDG(char[] vexs, char[][] edges){

   // 初始化"頂點數"和"邊數"

   int vlen = vexs.length;

   int elen = edges.length;

   // 初始化"頂點"

   mVexs = new VNode[vlen];

   for (int i = 0; i < mVexs.length; i++) {

       mVexs[i] = new VNode();

       mVexs[i].data = vexs[i];

       mVexs[i].firstEdge = null;

    }

   // 初始化"邊"

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

       // 讀取邊的起始頂點和結束頂點

       char c1 = edges[i][0];

       char c2 = edges[i][1];

       // 讀取邊的起始頂點和結束頂點

       int p1 = getPosition(edges[i][0]);

       int p2 = getPosition(edges[i][1]);

       // 初始化node1

       ENode node1 = new ENode();

       node1.ivex = p2;

       // 將node1連結到"p1所在連結串列的末尾"

       if(mVexs[p1].firstEdge == null)

         mVexs[p1].firstEdge = node1;

       else

           linkLast(mVexs[p1].firstEdge, node1);

    }

}

該函式的作用是建立一個鄰接表有向圖。實際上,該方法建立的有向圖,就是上面的圖G2。該函式的呼叫方法如下:

char[] vexs = {'A', 'B', 'C', 'D', 'E','F', 'G'};

char[][] edges = new char[][]{

   {'A', 'B'},

   {'B', 'C'},

   {'B', 'E'},

   {'B', 'F'},

   {'C', 'E'},

   {'D', 'C'},

   {'E', 'B'},

    {'E', 'D'},

   {'F', 'G'}};

ListDG pG;

pG = new ListDG(vexs, edges);

2.2 建立圖(自己輸入)

/*

 * 建立圖(自己輸入資料)

 */

public ListDG() {

   // 輸入"頂點數"和"邊數"

   System.out.printf("input vertex number: ");

   int vlen = readInt();

   System.out.printf("input edge number: ");

   int elen = readInt();

   if ( vlen < 1 || elen < 1 || (elen > (vlen*(vlen - 1)))) {

       System.out.printf("input error: invalid parameters!\n");

       return ;

    }

   // 初始化"頂點"

   mVexs = new VNode[vlen];

   for (int i = 0; i < mVexs.length; i++) {

       System.out.printf("vertex(%d): ", i);

       mVexs[i] = new VNode();

       mVexs[i].data = readChar();

       mVexs[i].firstEdge = null;

    }

   // 初始化"邊"

   //mMatrix = new int[vlen][vlen];

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

       // 讀取邊的起始頂點和結束頂點

       System.out.printf("edge(%d):", i);

       char c1 = readChar();

       char c2 = readChar();

       int p1 = getPosition(c1);

       int p2 = getPosition(c2);

       // 初始化node1

       ENode node1 = new ENode();

       node1.ivex = p2;

       // 將node1連結到"p1所在連結串列的末尾"

       if(mVexs[p1].firstEdge == null)

         mVexs[p1].firstEdge = node1;

       else

           linkLast(mVexs[p1].firstEdge, node1);

    }

}

4)  鄰接表有向圖的完整原始碼

/**

 *Java: 鄰接矩陣圖

 *

 *@author skywang

 *@date 2014/04/19

 */

import java.io.IOException;

import java.util.Scanner;

public class ListDG {

   // 鄰接表中表對應的連結串列的頂點

   private class ENode {

       int ivex;       // 該邊所指向的頂點的位置

       ENode nextEdge; // 指向下一條弧的指標

    }

   // 鄰接表中表的頂點

   private class VNode {

       char data;          // 頂點資訊

       ENode firstEdge;    // 指向第一條依附該頂點的弧

   };

   private VNode[] mVexs;  // 頂點陣列

   /*

    * 建立圖(自己輸入資料)

    */

   public ListDG() {

       // 輸入"頂點數"和"邊數"

       System.out.printf("input vertex number: ");

       int vlen = readInt();

       System.out.printf("input edge number: ");

       int elen = readInt();

       if ( vlen < 1 || elen < 1 || (elen > (vlen*(vlen - 1)))) {

           System.out.printf("input error: invalid parameters!\n");

           return ;

       }

       // 初始化"頂點"

       mVexs = new VNode[vlen];

       for (int i = 0; i < mVexs.length; i++) {

           System.out.printf("vertex(%d): ", i);

           mVexs[i] = new VNode();

           mVexs[i].data = readChar();

           mVexs[i].firstEdge = null;

       }

       // 初始化"邊"

       //mMatrix = new int[vlen][vlen];

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

           // 讀取邊的起始頂點和結束頂點

           System.out.printf("edge(%d):", i);

           char c1 = readChar();

           char c2 = readChar();

           int p1 = getPosition(c1);

           int p2 = getPosition(c2);

           // 初始化node1

           ENode node1 = new ENode();

           node1.ivex = p2;

           // 將node1連結到"p1所在連結串列的末尾"

           if(mVexs[p1].firstEdge == null)

              mVexs[p1].firstEdge = node1;

           else

                linkLast(mVexs[p1].firstEdge,node1);

       }

    }

   /*

    * 建立圖(用已提供的矩陣)

    *

    * 引數說明:

    *     vexs  -- 頂點陣列

    *     edges -- 邊陣列

    */

   public ListDG(char[] vexs, char[][] edges) {

       // 初始化"頂點數"和"邊數"

       int vlen = vexs.length;

       int elen = edges.length;

       // 初始化"頂點"

       mVexs = new VNode[vlen];

       for (int i = 0; i <mVexs.length; i++) {

           mVexs[i] = new VNode();

           mVexs[i].data = vexs[i];

           mVexs[i].firstEdge = null;

       }

       // 初始化"邊"

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

           // 讀取邊的起始頂點和結束頂點

            char c1 = edges[i][0];

           char c2 = edges[i][1];

           // 讀取邊的起始頂點和結束頂點

           int p1 = getPosition(edges[i][0]);

           int p2 = getPosition(edges[i][1]);

           // 初始化node1

           ENode node1 = new ENode();

           node1.ivex = p2;

           // 將node1連結到"p1所在連結串列的末尾"

           if(mVexs[p1].firstEdge == null)

              mVexs[p1].firstEdge = node1;

           else

                linkLast(mVexs[p1].firstEdge,node1);

       }

    }

   /*

    * 將node節點連結到list的最後

    */

   private void linkLast(ENode list, ENode node) {

       ENode p = list;

       while(p.nextEdge!=null)

           p = p.nextEdge;

       p.nextEdge = node;

    }

   /*

    * 返回ch位置

    */

   private int getPosition(char ch) {

       for(int i=0; i<mVexs.length; i++)

           if(mVexs[i].data==ch)

                return i;

       return -1;

    }

   /*

    * 讀取一個輸入字元

    */

   private char readChar() {

       char ch='0';

       do {

           try {

                ch = (char)System.in.read();

           } catch (IOException e) {

                e.printStackTrace();

           }

       } while(!((ch>='a'&&ch<='z') ||(ch>='A'&&ch<='Z')));

       return ch;

    }

    /*

    * 讀取一個輸入字元

    */

   private int readInt() {

       Scanner scanner = new Scanner(System.in);

       return scanner.nextInt();

    }

   /*

    * 列印矩陣佇列圖

    */

   public void print() {

       System.out.printf("List Graph:\n");

       for (int i = 0; i < mVexs.length; i++) {

           System.out.printf("%d(%c): ", i, mVexs[i].data);

           ENode node = mVexs[i].firstEdge;

           while (node != null) {

                System.out.printf("%d(%c)", node.ivex, mVexs[node.ivex].data);

                node = node.nextEdge;

           }

           System.out.printf("\n");

       }

    }

   public static void main(String[] args) {

       char[] vexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};

       char[][] edges = new char[][]{

           {'A', 'B'},

           {'B', 'C'},

           {'B', 'E'},

           {'B', 'F'},

           {'C', 'E'},

           {'D', 'C'},

           {'E', 'B'},

           {'E', 'D'},

           {'F', 'G'}};

       ListDG pG;

        // 自定義"圖"(輸入矩陣佇列)

       //pG = new ListDG();

       // 採用已有的"圖"

       pG = new ListDG(vexs, edges);

       pG.print();   // 列印圖

    }

}

六、    圖的遍歷之深度優先搜尋和廣度優先搜尋

1)  概要

本章會先對圖的深度優先搜尋和廣度優先搜尋進行介紹

目錄

1. 深度優先搜尋的圖文介紹

1.1 深度優先搜尋介紹

1.2 深度優先搜尋圖解

2. 廣度優先搜尋的圖文介紹

2.1 廣度優先搜尋介紹

2.2 廣度優先搜尋圖解

3. 搜尋演算法的原始碼

2)  深度優先搜尋的圖文介紹

1. 深度優先搜尋介紹

圖的深度優先搜尋(Depth First Search),和樹的先序遍歷比較類似。

它的思想:假設初始狀態是圖中所有頂點均未被訪問,則從某個頂點v出發,首先訪問該頂點,然後依次從它的各個未被訪問的鄰接點出發深度優先搜尋遍歷圖,直至圖中所有和v有路徑相通的頂點都被訪問到。 若此時尚有其他頂點未被訪問到,則另選一個未被訪問的頂點作起始點,重複上述過程,直至圖中所有頂點都被訪問到為止。

顯然,深度優先搜尋是一個遞迴的過程。

2. 深度優先搜尋圖解

2.1 無向圖的深度優先搜尋

下面以"無向圖"為例,來對深度優先搜尋進行演示。

對上面的圖G1進行深度優先遍歷,從頂點A開始。

第1步:訪問A。

第2步:訪問(A的鄰接點)C。

    在第1步訪問A之後,接下來應該訪問的是A的鄰接點,即"C,D,F"中的一個。但在本文的實現中,頂點ABCDEFG是按照順序儲存,C在"D和F"的前面,因此,先訪問C。

第3步:訪問(C的鄰接點)B。

    在第2步訪問C之後,接下來應該訪問C的鄰接點,即"B和D"中一個(A已經被訪問過,就不算在內)。而由於B在D之前,先訪問B。

第4步:訪問(C的鄰接點)D。

    在第3步訪問了C的鄰接點B之後,B沒有未被訪問的鄰接點;因此,返回到訪問C的另一個鄰接點D。

第5步:訪問(A的鄰接點)F。

    前面已經訪問了A,並且訪問完了"A的鄰接點B的所有鄰接點(包括遞迴的鄰接點在內)";因此,此時返回到訪問A的另一個鄰接點F。

第6步:訪問(F的鄰接點)G。

第7步:訪問(G的鄰接點)E。

因此訪問順序是:A -> C -> B -> D -> F-> G -> E

2.2 有向圖的深度優先搜尋

下面以"有向圖"為例,來對深度優先搜尋進行演示。

對上面的圖G2進行深度優先遍歷,從頂點A開始。

第1步:訪問A。

第2步:訪問B。

    在訪問了A之後,接下來應該訪問的是A的出邊的另一個頂點,即頂點B。

第3步:訪問C。

    在訪問了B之後,接下來應該訪問的是B的出邊的另一個頂點,即頂點C,E,F。在本文實現的圖中,頂點ABCDEFG按照順序儲存,因此先訪問C。

第4步:訪問E。

    接下來訪問C的出邊的另一個頂點,即頂點E。

第5步:訪問D。

    接下來訪問E的出邊的另一個頂點,即頂點B,D。頂點B已經被訪問過,因此訪問頂點D。

第6步:訪問F。

    接下應該回溯"訪問A的出邊的另一個頂點F"。

第7步:訪問G。

因此訪問順序是:A -> B -> C -> E -> D-> F -> G

3)  廣度優先搜尋的圖文介紹

1. 廣度優先搜尋介紹

廣度優先搜尋演算法(Breadth First Search),又稱為"寬度優先搜尋"或"橫向優先搜尋",簡稱BFS。

它的思想是:從圖中某頂點v出發,在訪問了v之後依次訪問v的各個未曾訪問過的鄰接點,然後分別從這些鄰接點出發依次訪問它們的鄰接點,並使得“先被訪問的頂點的鄰接點先於後被訪問的頂點的鄰接點被訪問,直至圖中所有已被訪問的頂點的鄰接點都被訪問到。如果此時圖中尚有頂點未被訪問,則需要另選一個未曾被訪問過的頂點作為新的起始點,重複上述過程,直至圖中所有頂點都被訪問到為止。

換句話說,廣度優先搜尋遍歷圖的過程是以v為起點,由近至遠,依次訪問和v有路徑相通且路徑長度為1,2...的頂點。

2. 廣度優先搜尋圖解

2.1 無向圖的廣度優先搜尋

下面以"無向圖"為例,來對廣度優先搜尋進行演示。還是以上面的圖G1為例進行說明。

第1步:訪問A。

第2步:依次訪問C,D,F。

    在訪問了A之後,接下來訪問A的鄰接點。前面已經說過,在本文實現中,頂點ABCDEFG按照順序儲存的,C在"D和F"的前面,因此,先訪問C。再訪問完C之後,再依次訪問D,F。

第3步:依次訪問B,G。

    在第2步訪問完C,D,F之後,再依次訪問它們的鄰接點。首先訪問C的鄰接點B,再訪問F的鄰接點G。

第4步:訪問E。

    在第3步訪問完B,G之後,再依次訪問它們的鄰接點。只有G有鄰接點E,因此訪問G的鄰接點E。

因此訪問順序是:A -> C -> D -> F -> B-> G -> E

2.2 有向圖的廣度優先搜尋

下面以"有向圖"為例,來對廣度優先搜尋進行演示。還是以上面的圖G2為例進行說明。

第1步:訪問A。

第2步:訪問B。

第3步:依次訪問C,E,F。

    在