1. 程式人生 > 實用技巧 >資料結構與演算法-圖

資料結構與演算法-圖

圖的概念

https://www.cnblogs.com/iwehdio/p/12356299.html

  • 圖 G = ( V ;E )。
    V 是頂點集,E 是連邊集。用 n 來表示頂點的數量,用 e 來表示連邊的數量。在圖中,兩個頂點之間具對應關係則稱為鄰接,用兩個頂點間的連邊表示。而兩個頂點與這條連邊具的關係成為關聯。

  • 有無向
    如果鄰接頂點 u 和 v 的次序無所謂則( u,v )為無向邊。如果鄰接頂點 u 和 v 的方向被規定了,則( u,v )為有向邊。所邊均無方向的圖,稱為無向圖。所邊均方向的圖,稱為向圖。向邊與無向邊混合的成為混合圖。向圖可以表示無向圖和混合圖。

  • 有無環
    路徑是,一系列的頂點按照鄰接關係構成的序列。如果一條路徑中不含重複的節點,則稱為簡單路徑。如果路徑的起始節點都是一個節點,則稱為環路。如果一個有向圖中不包含任何環路,則稱為有向無環圖。尤拉環路:經過所的向邊恰好一次的環路。哈密爾頓環路:經過所有的頂點恰好一次的環路

  • 最小支撐樹
    為每一邊e指定一個權重,比如wt(e)
    即為邊e的權重。各邊均帶權重的圖,稱作帶權圖,時也簡稱網路(network,記作G(V, E, wt())。
    同一網路的支撐樹中權重最小的為最小支撐樹

圖的實現

鄰接矩陣

鄰接矩陣:描述兩個頂點之間的鄰接關係。如果圖中 n 個頂點,對於有向圖是 n 行 n 列的方陣,第 i 行第 j 列的元素,表徵了第 i 個頂點與第 j 個頂點是否鄰接。如果是帶權圖,只需將元素的值改為權值。

package com.atguigu.prefect;
import java.util.LinkedList;
import java.util.List;
/**
 * @anthor shkstart
 * @create 2020-08-06 19:48
 */
public class AdjMatrixGraph<T> {
	protected List<T> vertexlist;
	//順序表儲存的頂底集合
	protected int[][] adjmatrix;
	//圖的鄰接矩陣,用二維陣列表示
	private final int MAX_WEIGHT = 99999;
	//設定最大權值,設定成常量
	public AdjMatrixGraph(int size){
		size = size<10?10:size;
		this.vertexlist = new LinkedList<>();
		//構造容量為size的空順序表
		this.adjmatrix = new int[size][size];
		for (int i=0;i<size;i++){
			//初始化鄰接矩陣
			for (int j=0;j<size;j++){
				this.adjmatrix[i][j] = (i==j)?0:MAX_WEIGHT;
			}
		}
	}
	public AdjMatrixGraph(T[] vertices,Edge[] edges){
		this(vertices.length);
		if(vertices == null)
		            return;
		for (int i=0;i<vertices.length;i++)
		            insertVertex(vertices[i]);
		if(edges!=null)
		            for (int j=0;j<edges.length;j++)
		                insertEdge(edges[j]);
	}
	public int vertexCount(){
		return this.vertexlist.size();
	}
	//返回定點順序表的元素個數
	public T get(int i){
		return this.vertexlist.get(i);
	}
	//返回第i個定點的元素
	public int getWeight(int i,int j){
		return this.adjmatrix[i][j];
	}
	//返<vi,vj>邊的權值
	public String toString(){
		String str = "頂點集合:"+this.vertexlist.toString()+"n鄰接矩陣:n";
        int n = this.vertexCount();
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++)
                str += this.adjmatrix[i][j] == MAX_WEIGHT?" $":" "+this.adjmatrix[i][j];
            str +="n";
        }
        return str;
    }
    public int insertVertex(T x){
        this.vertexlist.add(x);				//順序表追加元素,自動擴充
        if(this.vertexCount()>this.adjmatrix.length){		//若二維陣列不足,則擴充
            int temp[][] = adjmatrix,i,j;					//定義了局部變數i,j;
            this.adjmatrix = new int[temp.length*2][temp.length*2];		//二維陣列擴充2倍
            for(i=0;i<temp.length;i++){
                for(j=0;j<temp.length;j++)
                    this.adjmatrix[i][j] = temp[i][j];
                for(j=temp.length;j<temp.length*2;j++)
                    this.adjmatrix[i][j] = MAX_WEIGHT;
            }
            for(i=temp.length;i<temp.length*2;i++)
                for(j=0;j<temp.length*2;j++)
                    this.adjmatrix[i][j] = (i == j)?0:MAX_WEIGHT;
        }
        return this.vertexlist.size()-1;					//返回插入頂點的序號
    }
    public void  insertEdge(int i,int j,int weight){       //插入一條邊
        int n = this.vertexCount();
        if(i>=0&&i<n&&j>=0&&j<n&&this.adjmatrix[i][j]==MAX_WEIGHT&&i!=j)
            this.adjmatrix[i][j] = weight;
    }
    public void insertEdge(Edge edge){
        this.insertEdge(edge.start, edge.dest, edge.weight);
    }
    public void removeEdge(int i,int j){					//刪除一條邊
        if(i>=0&&i<vertexCount()&&j>=0&&j<vertexCount()&&i!=j)
            this.adjmatrix[i][j] = MAX_WEIGHT;
    }
    public void removeVertex(int i){						//刪除頂點以及和頂點有關係的邊
        int n = this.vertexCount();
        if(i<0||i>n)
            return;
        this.vertexlist.remove(i);
        for(int j=0;j<i;j++)
            for(int k=i+1;k<n;k++)
                this.adjmatrix[j][k-1] = this.adjmatrix[j][k];		//元素向左移一行
        for(int j=i+1;j<n;j++)
            for(int k=0;k<i;k++)
                this.adjmatrix[j-1][k] = this.adjmatrix[j][k];		//元素向上移一行
        for(int j=i+1;j<n;j++)
            for(int k=i+1;k<n;k++)
                this.adjmatrix[j-1][k-1] = this.adjmatrix[j][k];
    }
    static class Edge implements Comparable<Edge> {
        public int start,dest,weight;
        public Edge(int start,int dest,int weight){
            this.start = start;
            this.dest = dest;
            this.weight = weight;
        }
        public String toString(){
            return "("+start+","+dest+","+weight+")";
        }
        public int compareTo(Edge e) {
            // TODO Auto-generated method stub
            if(this.start!=e.start)
                return this.start - e.start;
            return this.dest - e.dest;
        }
    }
    public static void main(String[] args){
        String[] verices = {"A","B","C","D","E"};
        Edge edges[] = {new Edge(0,1,5),new Edge(0,3,2),new Edge(1,0,5),
                new Edge(1,2,7),new Edge(1,3,6),new Edge(2,1,7),
                new Edge(2,3,8),new Edge(2,4,3),new Edge(3,0,2),
                new Edge(3,1,6),new Edge(3,2,8),new Edge(3,4,9),
                new Edge(4,2,3),new Edge(4,3,9)};
        AdjMatrixGraph<String> graph = new AdjMatrixGraph<String>(verices,edges);
        System.out.println("帶權無向圖"+graph.toString());
        System.out.println("插入頂點F,插入邊(A,F,9),刪除頂點C,刪除邊(D,E)");
        int i = graph.insertVertex("F");
        graph.insertEdge(0,i,9);
        graph.insertEdge(i,0,9);
        graph.removeVertex(2);
        graph.removeEdge(2, 3);
        graph.removeEdge(3, 2);
        System.out.println(graph.toString());
    }
}

關聯矩陣

描述頂點與邊之間的關聯關係。如果圖中 n 個頂點、e 條邊,則為 n 行 e 列的矩陣,第 i 行第 j 列的元素,表徵了第 i 個頂點是否與第 j 條邊關聯。每一列中只有兩個元素不為0。(下面程式碼只是表示一下什麼是關聯矩陣)

package com.atguigu.prefect;
import java.util.Scanner;
public class InciMatrix {
	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		int n = s.nextint();
		int m = s.nextint();
		int[][] x = new int[n+1][m+1];
		for (int j = 1; j <= m; j++) {
			int a = s.nextint();
			int b = s.nextint();
			x[a][j] = 1;
			x[b][j] = -1;
		}
		for (int i = 1; i < n; i++) {
			for (int j = 1; j <= m; j++) {
				System.out.print(x[i][j] + " ");
			}
			System.out.println();
		}
	}
}

鄰接表

描述每個頂點的鄰接關係。如果圖中 n 個頂點,則為規模為 n 的向量。向量中的元素為列表,內容為該頂點所指向的鄰接頂點。

package com.atguigu.prefect.form;
import java.util.*;
/**
 * @anthor shkstart
 * @create 2020-08-06 17:06
 */
public class LinkGraph {
	Vertex[] vertex;
	int[] parent;
	//有參構造器
	public LinkGraph(char[] vert,Edge[] edge) {
		//讀入頂點,並初始化
		vertex = new Vertex[vert.length];
		parent = new int[vert.length];
		for (int i=0;i<vertex.length;i++) {
			vertex[i]=new Vertex();
			vertex[i].data=vert[i];
			//頂點值
			vertex[i].firstEdge=null;
			//還沒有鄰接點,當然沒有邊了
		}
		//初始化邊
		for (int i=0;i<edge.length;i++) {
			char start=edge[i].start;
			char end=edge[i].end;
			//獲取頂點對應的序號
			int p1=getPosition(start);
			int p2=getPosition(end);
			//1.把p2連線在以p1為頭的連結串列中
			Node node1=new Node();
			node1.index=p2;
			node1.weight=edge[i].weight;
			linkedLast(p1,node1);
			//2.因為是無向圖,所以還需要把p1連線在以p2為頭的連結串列中
			Node node2=new Node();
			node2.index=p1;
			node2.weight=edge[i].weight;
			linkedLast(p2,node2);
		}
	}
	//獲取某個頂點對應的序號
	public int getPosition(char v) {
		for (int i=0;i<vertex.length;i++) {
			if(vertex[i].data==v) {
				return i;
			}
		}
		//不存在這樣的頂點則返回-1
		return -1;
	}
	//尾插法,將頂點連線到連結串列的尾巴
	public void linkedLast(int index,Node node) {
		if(vertex[index].firstEdge==null) {
			vertex[index].firstEdge=node;
		} else {
			Node tmp=vertex[index].firstEdge;
			while(tmp.nextNode!=null) {
				tmp=tmp.nextNode;
			}
			tmp.nextNode=node;
		}
	}
	//列印圖
	public void print() {
		System.out.println("鄰接表儲存的圖:");
		for (int i=0;i<vertex.length;i++) {
			System.out.print(vertex[i].data+"-->");
			//如果存在鄰接點
			Node tmp=vertex[i].firstEdge;
			while(tmp.nextNode!=null) {
				System.out.print(vertex[tmp.index].data+"-->");
				tmp=tmp.nextNode;
			}
			System.out.print(vertex[tmp.index].data);
			System.out.println();
		}
	}
	//深度優先搜尋,從第一個頂點開始遍歷
	public void DFS() {
		Boolean[] visited=new Boolean[vertex.length];
		//預設為false;
		int[] path=new int[vertex.length];
		//記錄遍歷的頂點序號
		int index=0;
		//path[]的索引
		Stack stack=new Stack();
		visited[0]=true;
		stack.push(0);
		path[index++]=0;
		while(!stack.isEmpty()) {
			int v=getUnVisitedAdjVertex((Integer) stack.peek(),visited);
			//如果不存在沒有訪問的鄰接點,就出棧,原路返回
			if(v==-1) {
				stack.pop();
			}
			//否則,存在還沒有訪問過的鄰接點,入棧,並標註已訪問 else {
				path[index++]=v;
				//訪問鄰接點
				visited[v]=true;
				//標誌已訪問
				stack.push(v);
				//入棧
			}
		}
		//列印DFS路徑
		System.out.println("DFS路徑:");
		for (int i=0;i<path.length;i++) {
			System.out.print(vertex[path[i]].data+" ");
		}
	}
	//查詢某個點的還沒有被訪問的鄰接點的序號
	public int getUnVisitedAdjVertex(int v,Boolean[] visited) {
		Node tmp=vertex[v].firstEdge;
		//如果存在鄰接點
		while(tmp!=null) {
			//並且鄰接點還沒有訪問過,就返回該鄰接點的序號
			if(visited[tmp.index]==false) {
				return tmp.index;
			}
			tmp=tmp.nextNode;
		}
		//不存在沒有被訪問的鄰接點
		return -1;
	}
	//廣度優先搜尋,從第一個頂點開始遍歷
	public void BFS() {
		Boolean[] visited=new Boolean[vertex.length];
		//預設為false;
		int[] path=new int[vertex.length];
		//記錄遍歷的頂點序號
		int index=0;
		//path[]的索引
		Queue queue=new LinkedList<Integer>();
		visited[0]=true;
		queue.add(0);
		path[index++]=0;
		while(!queue.isEmpty()) {
			int v=getUnVisitedAdjVertex((Integer) queue.peek(), visited);
			//如果不存在沒有訪問的鄰接點,就出隊
			if(v==-1) {
				queue.remove();
			}
			//否則,存在還沒有訪問過的鄰接點,入隊,並標註已訪問 else {
				path[index++]=v;
				//訪問鄰接點
				visited[v]=true;
				//標誌已訪問
				queue.add(v);
				//入隊
			}
		}
		//列印BFS路徑
		System.out.println("BFS路徑:");
		for (int i=0;i<path.length;i++) {
			System.out.print(vertex[path[i]].data+" ");
		}
	}
	//作為某個點的鄰接點的頂點資訊
	class Node{
		int index;
		//頂點的序號
		int weight;
		//以該頂點為終點的邊的權值
		Node nextNode;
		//指向下一個頂點
	}
	//輸入的所有頂點的型別,是任意一條連結串列的起點
	class Vertex{
		char data;
		//頂點值
		Node firstEdge;
		//指向第一條邊
	}
	//邊的型別
	static class Edge{
		char start;
		//起點
		char end;
		//終點
		int weight;
		//邊的權值
		public Edge(char start,char end,int weight) {
			this.start=start;
			this.end=end;
			this.weight=weight;
		}
	}
	public static void main(String[] args) {
		char[] vexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
		//頂點
		Edge[] edges = {                                   //邊
		// 起點      終點    權
		new Edge('A', 'B', 12),
		                new Edge('A', 'F', 16),
		                new Edge('A', 'G', 14),
		                new Edge('B', 'C', 10),
		                new Edge('B', 'F',  7),
		                new Edge('C', 'D',  3),
		                new Edge('C', 'E',  5),
		                new Edge('C', 'F',  6),
		                new Edge('D', 'E',  4),
		                new Edge('E', 'F',  2),
		                new Edge('E', 'G',  8),
		                new Edge('F', 'G',  9),
	}
	;
	LinkGraph graph=new LinkGraph(vexs,edges);
	//列印圖的鄰接表
	graph.print();
	//深度優先搜尋
	graph.DFS();
	System.out.println();
	//廣度優先搜尋
	graph.BFS();
}
}

死搬c++

enum EStatus {
	UNDETERMINED, TREE, CROSS, FORWARD, BACKWARD
}
enum VStatus {
	UNDISCOVERED, DISCOVERED, VISITED
}
public class Edge<Te> {
	Te data;
	int weight;
	EStatus status;
	public Edge() {
	}
	public Edge(Te data, int weight) {
		this.data = data;
		this.weight = weight;
		this.status = EStatus.UNDETERMINED;
	}
	public Te getData() {
		return data;
	}
	public void setData(Te data) {
		this.data = data;
	}
	public int getWeight() {
		return weight;
	}
	public void setWeight(int weight) {
		this.weight = weight;
	}
	public EStatus getStatus() {
		return status;
	}
	public void setStatus(EStatus status) {
		this.status = status;
	}
}
public class Vertex<Tv> {
	private Tv data;
	private int inDegree,outDegree;
	private VStatus status;
	private int dTime,fTime;
	private int parent;
	/*int priority;*/
	//不知道如何設定
	public Vertex() {
	}
	public Vertex(Tv data) {
		this.data = data;
		this.inDegree = 0;
		this.outDegree = 0;
		this.status = VStatus.UNDISCOVERED;
		this.dTime = -1;
		this.fTime = -1;
		this.parent = -1;
	}
	public Tv getData() {
		return data;
	}
	public void setData(Tv data) {
		this.data = data;
	}
	public int getInDegree() {
		return inDegree;
	}
	public void setInDegree(int inDegree) {
		this.inDegree = inDegree;
	}
	public int getOutDegree() {
		return outDegree;
	}
	public void setOutDegree(int outDegree) {
		this.outDegree = outDegree;
	}
	public VStatus getStatus() {
		return status;
	}
	public void setStatus(VStatus status) {
		this.status = status;
	}
	public int getdTime() {
		return dTime;
	}
	public void setdTime(int dTime) {
		this.dTime = dTime;
	}
	public int getfTime() {
		return fTime;
	}
	public void setfTime(int fTime) {
		this.fTime = fTime;
	}
	public int getParent() {
		return parent;
	}
	public void setParent(int parent) {
		this.parent = parent;
	}
}
public class Graph1<Tv,Te> implements GraphImpl<Tv,Te>{
	private Vertex<Tv>[] V ;
	private Edge<Te>[][] E ;
	private int n;
	private int e;
	public Graph1() {
	}
	public Graph1(Vertex<Tv>[] v, Edge<Te>[][] e, int n, int e1) {
		V = v;
		E = e;
		this.n = n;
		this.e = e1;
	}
	@Override
	    public Tv vertex(int i) {
		return V[i].getData();
	}
	@Override
	    public int inDegree(int i) {
		return V[i].getInDegree();
	}
	@Override
	    public int outDegree(int i) {
		return V[i].getOutDegree();
	}
	@Override
	    public int firstNbr(int i) {
		return nextNbr(i,n);
		//首個鄰接頂點
	}
	@Override
	    public int nextNbr(int i,int j) {
		while ((-1 < j) && !exists(i , --j));
		return j;
	}
	@Override
	    public VStatus status(int i) {
		return V[i].getStatus();
	}
	@Override
	    public int dTime(int i) {
		return V[i].getdTime();
	}
	@Override
	    public int fTime(int i) {
		return V[i].getfTime();
	}
	@Override
	    public int parent(int i) {
		return V[i].getParent();
	}
	@Override
	    public int insert(Tv vertex) {
		//插入頂點,返回編號
		V[n] = (Vertex<Tv>) vertex;
		n++;
		return n-1;
	}
	@Override
	    public Tv remove(int i) {
		Tv vBak = vertex(i);
		for (int t = i - 1;t+1 < n;t++){
			for (int j = 0; j < n; j++){
				E[t][j] = E[t + 1][j];
				E[j][t] = E[j][t + 1];
			}
			V[t] = V[t+1];
		}
		n--;
		return vBak;
	}
	@Override
	    public Boolean exists(int i, int j) {
		return (0 <= i) &&(i < n) && (0 <= j)&& (j < n) && (E[i][j] != null);
	}
	@Override
	    public EStatus status(int i, int j) {
		return E[i][j].getStatus();
	}
	@Override
	    public Te edge(int i, int j) {
		return E[i][j].getData();
	}
	@Override
	    public int weight(int i, int j) {
		return E[i][j].getWeight();
	}
	@Override
	    public void insert(Te edge, int w, int i, int j) {
		if (exists(i,j)) return;
		E[i][j] = new Edge<Te>(edge, w);
		e++;
		int a = V[i].getInDegree();
		int b = V[j].getOutDegree();
		V[i].setInDegree(a+1);
		V[j].setInDegree(b+1);
	}
	@Override
	    public Te remove(int i, int j) {
		Te eBak = edge(i,j);
		E[i][j] = null;
		e--;
		int a = V[i].getInDegree();
		int b = V[j].getOutDegree();
		V[i].setInDegree(a-1);
		V[j].setInDegree(b-1);
		return eBak;
	}
	public void dfs(int s){
		int clock = 0;
		int v = s;
		do{
			if (V[v].getStatus() == VStatus.UNDISCOVERED){
				DFS(v,clock);
			}
		}
		while (s != (v = (++v % n)));
	}
	public void DFS(int v,int clock){
		//assert: 0 <= v < n
		V[v].setdTime(++clock);
		System.out.print(V[v].getData());
		V[v].setStatus(VStatus.DISCOVERED);
		for (int u = firstNbr(v);-1 < u;u = nextNbr(v,u)){
			switch (V[u].getStatus()){
				case UNDISCOVERED:
				                    E[v][u].setStatus(EStatus.TREE);
				V[u].setParent(v);
				DFS(u,clock);
				break;
				case DISCOVERED:
				                    E[v][u].setStatus(EStatus.BACKWARD);
				break;
				default:
				                    E[v][u].setStatus(dTime(v) < dTime(u)?EStatus.FORWARD:EStatus.CROSS);
				break;
			}
			V[v].setStatus(VStatus.VISITED);
			V[v].setfTime(++clock);
		}
	}
	public void bfs(int s){
		int clock = 0;
		int v = s;
		do {
			if (status(v) == VStatus.UNDISCOVERED){
				BFS(v,clock);
			}
		}
		while (s != (v = (++v % n)));
		//這裡逐一的方式
	}
	public void BFS(int v,int clock){
		Queue<Integer> Q = new LinkedList<Integer>();
		//引入輔劣佇列
		V[v].setStatus(VStatus.DISCOVERED);
		Q.add(v);
		while (!Q.isEmpty()){
			v = Q.poll();
			System.out.print(V[v].getData());
			V[v].setdTime(++clock);
			for (int u = firstNbr(v); -1 < u;u = nextNbr(v,u)){
				if (status(u) == VStatus.UNDISCOVERED){
					V[u].setStatus(VStatus.DISCOVERED);
					Q.add(u);
					E[v][u].setStatus(EStatus.TREE);
					V[u].setParent(v);
				} else {
					E[v][u].setStatus(EStatus.CROSS);
				}
				V[v].setStatus(VStatus.VISITED);
			}
		}
	}
}

測試

public void test2(){
	Vertex<Character>[] v = new Vertex[10];
	Edge<Integer>[][] e = new Edge[10][10];
	v[0] = new Vertex<>('A');
	v[1] = new Vertex<>('B');
	v[2] = new Vertex<>('C');
	v[3] = new Vertex<>('D');
	v[4] = new Vertex<>('E');
	int n = 5;
	//點
	int m = 6;
	//邊
	e[0][4] = new Edge<Integer>(1,6);
	e[1][0] = new Edge<Integer>(1,9);
	e[1][2] = new Edge<Integer>(1,3);
	e[2][0] = new Edge<Integer>(1,2);
	e[2][3] = new Edge<Integer>(1,5);
	e[3][4] = new Edge<Integer>(1,1);
	Graph1<Character,Integer> graph = new Graph1<>(v,e,n,m);
	/* graph.BFS(1,0);*/
	System.out.println();
	graph.DFS(1,0);
	/*graph.dfs(0);*/
}
  • 原理

廣度優先搜尋

https://blog.csdn.net/hehuanchun0311/article/details/80168109

原理

資料結構的簡化分析:圖遍歷得到樹,樹遍歷得到向量

廣度優先搜尋:對於訪問始自頂點為 s 的圖。

  • 訪問頂點 s 。
  • 依次訪問 s 所有尚未訪問的鄰接頂點。
  • 依次訪問上述頂點尚未訪問的鄰接頂點。
  • 如此反覆直至沒尚未訪問的鄰接頂點。

例項

實現

public void dfs(int s){
	int clock = 0;
	int v = s;
	do{
		if (V[v].getStatus() == VStatus.UNDISCOVERED){
			DFS(v,clock);
		}
	}
	while (s != (v = (++v % n)));
}
public void DFS(int v,int clock){
	//assert: 0 <= v < n
	V[v].setdTime(++clock);
	System.out.print(V[v].getData());
	V[v].setStatus(VStatus.DISCOVERED);
	for (int u = firstNbr(v);-1 < u;u = nextNbr(v,u)){
		switch (V[u].getStatus()){
			case UNDISCOVERED:
			                    E[v][u].setStatus(EStatus.TREE);
			V[u].setParent(v);
			DFS(u,clock);
			break;
			case DISCOVERED:
			                    E[v][u].setStatus(EStatus.BACKWARD);
			break;
			default:
			                    E[v][u].setStatus(dTime(v) < dTime(u)?EStatus.FORWARD:EStatus.CROSS);
			break;
		}
		V[v].setStatus(VStatus.VISITED);
		V[v].setfTime(++clock);
	}
}

上層主函式bfs()的作用,正在於處理多個連通分量或可達分量並存的情況。具體地,在逐個 檢查頂點的過程中,只要發現某一頂點尚未被發現,則意味著其所屬的連通分量或可達分量尚未 觸及,故可從該頂點出發再次啟動BFS(),以遍歷其所屬的連通分量或可達分量。

深度優先搜尋

原理

  • 訪問頂點 s 。
  • 若 s 有尚未被訪問的鄰接,則任選其一 u ,遞迴執行深度優先搜尋。
  • 否則,返回上一頂點。

實現

public void bfs(int s){
	int clock = 0;
	int v = s;
	do {
		if (status(v) == VStatus.UNDISCOVERED){
			BFS(v,clock);
		}
	}
	while (s != (v = (++v % n)));
	//這裡逐一的方式
}
public void BFS(int v,int clock){
	Queue<Integer> Q = new LinkedList<Integer>();
	//引入輔劣佇列
	V[v].setStatus(VStatus.DISCOVERED);
	Q.add(v);
	while (!Q.isEmpty()){
		v = Q.poll();
		System.out.print(V[v].getData());
		V[v].setdTime(++clock);
		for (int u = firstNbr(v); -1 < u;u = nextNbr(v,u)){
			if (status(u) == VStatus.UNDISCOVERED){
				V[u].setStatus(VStatus.DISCOVERED);
				Q.add(u);
				E[v][u].setStatus(EStatus.TREE);
				V[u].setParent(v);
			} else {
				E[v][u].setStatus(EStatus.CROSS);
			}
			V[v].setStatus(VStatus.VISITED);
		}
	}
}

概念

  • 活躍期

  • 邊的分類

其他

拓撲排序

雙聯通域分解

優先順序搜尋

最小支撐樹

最短路徑