JAVA數據結構——利用圖的廣度優先遍歷搜索算法確定無向連通圖的連通分量

分析:

如果這個無向圖是非連通圖的時候,從圖的一個頂點沒法訪問這個圖的所有頂點,只能訪問包含該頂點的連通分量中的所有頂點。所以從無向圖的每個連通分量中的一個頂點開始遍歷圖,則可求得無向圖的所有連同分量。

如圖則是非連通的無向圖,我們只需要從第一個和第二個連通分量進行遍歷即可,先了解一下基礎設想。

從1-2-...n,我們可以把這個思路無限制擴大下去,實現若干個非連通圖如何實現。

我們採用廣度優先遍歷搜索算法來實現這個功能。

廣度優先遍歷搜索(BFS):

廣度優先遍歷,屬於一種盲目搜尋法,目的是系統地展開並檢查圖中的所有節點,以找尋結果。換句話說,它並不考慮結果的可能位置,徹底地搜索整張圖,直到找到結果爲止。

已知圖G=(V,E)和一個源頂點s,寬度優先搜索以一種系統的方式探尋G的邊,從而“發現”s所能到達的所有頂點,並計算s到所有這些頂點的距離(最少邊數),該算法同時能生成一棵根爲s且包括所有可達頂點的寬度優先樹。對從s可達的任意頂點v,寬度優先樹中從s到v的路徑對應於圖G中從s到v的最短路徑,即包含最小邊數的路徑。該算法對有向圖和無向圖同樣適用。
之所以稱之爲寬度優先算法,是因爲算法自始至終一直通過已找到和未找到頂點之間的邊界向外擴展,就是說,算法首先搜索和s距離爲k的所有頂點,然後再去搜索和S距離爲k+l的其他頂點。
       爲了保持搜索的軌跡,寬度優先搜索爲每個頂點着色:白色、灰色或黑色。算法開始前所有頂點都是白色,隨着搜索的進行,各頂點會逐漸變成灰色,然後成爲黑色。在搜索中第一次碰到一頂點時,我們說該頂點被發現,此時該頂點變爲非白色頂點。因此,灰色和黑色頂點都已被發現,但是,寬度優先搜索算法對它們加以區分以保證搜索以寬度優先的方式執行。若(u,v)∈E且頂點u爲黑色,那麼頂點v要麼是灰色,要麼是黑色,就是說,所有和黑色頂點鄰接的頂點都已被發現。灰色頂點可以與一些白色頂點相鄰接,它們代表着已找到和未找到頂點之間的邊界。
       在寬度優先搜索過程中建立了一棵寬度優先樹,起始時只包含根節點,即源頂點s.在掃描已發現頂點u的鄰接表的過程中每發現一個白色頂點v,該頂點v及邊(u,v)就被添加到樹中。在寬度優先樹中,我們稱結點u 是結點v的先輩或父母結點。因爲一個結點至多隻能被發現一次,因此它最多隻能有--個父母結點。相對根結點來說祖先和後裔關係的定義和通常一樣:如果u處於樹中從根s到結點v的路徑中,那麼u稱爲v的祖先,v是u的後裔。

代碼實現利用廣度優先遍歷搜索確定無向圖的連通分量: 

1. 圖類型:

package com.usts.edu.graphic;

// 圖的種類 有向圖、有向網、無向圖、無向網
public enum GraphKind {
	UDG, // 無向圖(UnDirected Graph)
	DG, // 有向圖(Directed Graph)
	UDN, // 無向網(UnDirected Network)
	DN; // 有向網(Directed Network)
}

2. 圖的接口 

package com.usts.edu.graphic;

//圖的接口
public interface IGraph {
	void createGraph();//創建一個圖

	int getVexNum(); // 返回頂點數

	int getArcNum();// 返回邊數

	Object getVex(int v) throws Exception;// 返回v表示結點的值, 0 <= v < vexNum

	int locateVex(Object vex);// 給定頂點的值vex,返回其在圖中的位置,如果圖中不包含此頂點,則返回-1

	int firstAdjVex(int v) throws Exception; // 返回v的第一個鄰接點,若v沒有鄰接點,則返回-1,其中0≤v<vexNum

	int nextAdjVex(int v, int w) throws Exception;// 返回v相對於w的下一個鄰接點,若w是v的最後一個鄰接點,則返回-1,其中0≤v, w<vexNum

}

 3. 創建圖:

package com.usts.edu.graphic;

import java.util.Scanner;


public class MGraph implements IGraph {
	public final static int INFINITY = Integer.MAX_VALUE;

	private GraphKind kind;

	private int vexNum, arcNum;

	private Object[] vexs;

	private int[][] arcs;

	public MGraph() {
		this(null, 0, 0, null, null);
	}

	public MGraph(GraphKind kind, int vexNum, int arcNum, Object[] vexs,
			int[][] arcs) {
		this.kind = kind;
		this.vexNum = vexNum;
		this.arcNum = arcNum;
		this.vexs = vexs;
		this.arcs = arcs;
	}

	public void createGraph() {
		Scanner sc = new Scanner(System.in);
		System.out.println("請輸入圖的類型");
		GraphKind kind = GraphKind.valueOf(sc.next());
		switch (kind) {
		case UDG:
			createUDG();
			return;
		case DG:
			createDG();
			return;
		case UDN:
			createUDN();
			return;
		case DN:
			createDN();
			return;
		}
	}

	private void createUDG() {
	};

	private void createDG() {
	};

	private void createUDN() {
		Scanner sc = new Scanner(System.in);
		vexNum = sc.nextInt();
		arcNum = sc.nextInt();
		vexs = new Object[vexNum];
		for (int v = 0; v < vexNum; v++)
			vexs[v] = sc.next();

		arcs = new int[vexNum][vexNum];
		for (int v = 0; v < vexNum; v++)
			for (int u = 0; u < vexNum; u++)
				arcs[v][u] = INFINITY;

		for (int k = 0; k < arcNum; k++) {
			int v = locateVex(sc.next());
			int u = locateVex(sc.next());
			arcs[v][u] = arcs[u][v] = sc.nextInt();
		}
	}

	private void createDN() {
		Scanner sc = new Scanner(System.in);
		vexNum = sc.nextInt();
		arcNum = sc.nextInt();
		vexs = new Object[vexNum];
		for (int v = 0; v < vexNum; v++)
			vexs[v] = sc.next();

		arcs = new int[vexNum][vexNum];
		for (int v = 0; v < vexNum; v++)
			for (int u = 0; u < vexNum; u++)
				arcs[v][u] = INFINITY;

		for (int k = 0; k < arcNum; k++) {
			int v = locateVex(sc.next());
			int u = locateVex(sc.next());
			arcs[v][u] = sc.nextInt();
		}

	}

	public int getVexNum() {
		return vexNum;
	}

	public int getArcNum() {
		return arcNum;
	}

	public int locateVex(Object vex) {
		for (int v = 0; v < vexNum; v++)
			if (vexs[v].equals(vex))
				return v;
		return -1;
	}

	public Object getVex(int v) throws Exception {
		if (v < 0 && v >= vexNum)
			throw new Exception("第" + v + "個頂點不存在!");
		return vexs[v];
	}

	public int firstAdjVex(int v) throws Exception {
		if (v < 0 && v >= vexNum)
			throw new Exception("第" + v + "個頂點不存在!");

		for (int j = 0; j < vexNum; j++)
			if (arcs[v][j] != 0 && arcs[v][j] < INFINITY)
				return j;

		return -1;
	}

	public int nextAdjVex(int v, int w) throws Exception {
		if (v < 0 && v >= vexNum)
			throw new Exception("第" + v + "個頂點不存在!");

		for (int j = w + 1; j < vexNum; j++)
			if (arcs[v][j] != 0 && arcs[v][j] < INFINITY)
				return j;

		return -1;
	}

	public GraphKind getKind() {
		return kind;
	}

	public int[][] getArcs() {
		return arcs;
	}

	public Object[] getVexs() {
		return vexs;
	}

	public void setArcNum(int arcNum) {
		this.arcNum = arcNum;
	}

	public void setArcs(int[][] arcs) {
		this.arcs = arcs;
	}

	public void setKind(GraphKind kind) {
		this.kind = kind;
	}

	public void setVexNum(int vexNum) {
		this.vexNum = vexNum;
	}

	public void setVexs(Object[] vexs) {
		this.vexs = vexs;
	}

}

4. 實現搜索:

 

package com.usts.edu.graphic;

import com.usts.edu.Queue.LinkQueue;

/**
 * Created by Guanzhong Hu
 * Date :2020/3/30
 * Description :
 * Version :1.0
 */
public class GDSeach {
        public final static int INFINITY = Integer.MAX_VALUE;

        public static void CC_BFS(IGraph G) throws Exception {
            boolean[] visited = new boolean[G.getVexNum()];
            for (int v = 0; v < G.getVexNum(); v++)

                visited[v] = false;
            LinkQueue Q = new LinkQueue();
            LinkQueue P = new LinkQueue();
            int i = 0;
            for (int v = 0; v < G.getVexNum(); v++) {
                P.clear();
                if (!visited[v]) {
                    visited[v] = true;
                    P.offer(G.getVex(v));
                    Q.offer(v);
                    while (!Q.isEmpty()) {
                        int u = (Integer) Q.poll();
                        for (int w = G.firstAdjVex(u); w >= 0; w = G.nextAdjVex(u,
                                w)) {
                            if (!visited[w]) {
                                visited[w] = true;
                                P.offer(G.getVex(w));
                                Q.offer(w);
                            }
                        }
                    }
                    System.out.println("圖的第" + ++i + "個連通分量爲:");
                    while (!P.isEmpty())
                        System.out.print(P.poll().toString() + " ");
                    System.out.println();
                }
            }
        }

        public static void main(String[] args) throws Exception {
            Object vexs[] = { "A", "B", "C", "D", "E", "F", "G" };
            int[][] arcs = { { 0, 1, INFINITY, 1, INFINITY, INFINITY, INFINITY },
                    { 1, 0, 1, INFINITY, INFINITY, INFINITY, INFINITY },
                    { INFINITY, 1, 0, 1, INFINITY, INFINITY, INFINITY },
                    { 1, INFINITY, 1, 0, INFINITY, INFINITY, INFINITY },
                    { INFINITY, INFINITY, INFINITY, INFINITY, 0, 1, INFINITY },
                    { INFINITY, INFINITY, INFINITY, INFINITY, 1, 0, 1 },
                    { INFINITY, INFINITY, INFINITY, INFINITY, INFINITY, 1, 0 }, };
            MGraph G = new MGraph(GraphKind.UDG, 7, 6, vexs, arcs);
            CC_BFS(G);
        }
}

無向圖的連通分量搜索是一種廣度優先遍歷的應用,當然還有如Dijkstra單源最短路徑算法和Prim最小生成樹算法都採用了和寬度優先搜索類似的思想。

源碼地址:https://gitee.com/jockhome/data_structure

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章