前言:
我們所討論的圖模型中,邊僅僅是兩個頂點之間的連接。一般使用0-(V-1)來表示一張含有V個頂點的圖中的各個頂點。用v-w的記法表示v點和w點之間的邊(又可以寫成w-v)。
特殊的兩種圖:
自環: 一條連接一個頂點和其自身的邊。
平行邊: 連接同一對頂點的兩條邊。
以下所說的圖兩個頂點之間僅含有一條邊。
相關術語:
當邊連接兩個頂點時,我們說頂點彼此 相鄰。
頂點的度數為依附於他的邊的總數。
子圖是一幅圖所有被邊的一個子集(包括他們所依附的頂點)。
路徑是由邊連接的頂點序列,沒有重復的邊。
簡單路徑是沒有重復頂點的路徑。
環是一條至少含有一條邊且起點和終點相同的路徑。
簡單環是一條(除了起點和終點必須相同之外)不含重復頂點和邊的環。
路徑或環的長度為其包含的邊數。
如果從任意一個頂點都存在一條路徑到達另一個任意頂點,則稱這幅圖是連通圖。
一個非連通圖由若干連通圖組成,它們都是極大連通子圖。
無環圖是一個不包含環的圖。
樹是一副無環連通圖。互不相連的樹組成森林。連通圖的生成樹是他的一副子圖,它含有圖中的所有頂點且是一顆樹。圖的生成森林是他的所有連通子圖的生成樹的集合。
關於樹的定義,以下五種說法是等價的:(一副含有V個頂點的圖G)
1:G有V-1條邊並且不含環。
2:G有V-1條邊並且是聯通的
3:G是連通的且刪除任意一條邊都會使他不連通。
4:G是無環圖且添加任意一條邊都會使他產生一條環。
5:G中任意一對頂點間僅存在一條簡單路徑。
我們定義以下圖的基本操作API:
Public class Graph
Graph(int V) //創建一個含有V個頂點但不含邊的圖
Graph(InputStream in) //從標准輸入流中讀取一個圖
int V() //頂點數
int E() //邊數
void addEdge(int v,int w) //添加邊V-W
Iterable<Integer> adj(int v) //遍歷與v相鄰的頂點
String toString() // @Override
相關實現:
計算V的度數:
public static int degree(Graph g,int v)
{ int degree=0;
for(int w: g.adj(v)) degree++;
return degree;
}
計算所有頂點的最大度數:
public static int maxDegree(Graph g)
{ int max=0;
for(int v=0;v<g.v();v++)
if(degree(g,v)>max)
max=degree(g,v);
return max; }
計算自環的個數:
public static int numberOfSefLoops(Graph g)
{ int count=0;
for(int v=0;v<g.v();v++)
for(int w:g.adj(v))
if(w==v) count++;
return count/2;
}
//覆寫toString方法@Override
public String toString()
{
String s=V+”vertices”+E+” edges\n”;//建議你用StringBuilder
for(int v=0;v<g.v();v++)
{ s+=v+”: ”;
for(int w:this.adj(v))
s+=“\n”;
}
return s;
}
圖的幾種表示方法:
要求: 1、必須為各種情況下遇到的圖預留足夠空間。
2、快。
鄰接矩陣:
用一個V * V的Boolean矩陣表示,1代表相連。
//不滿足第一種要求。
邊的數組:
使用一個Edge類,含有兩個int變量。
/不滿足第二個要求,比如調用adj方法。
鄰接表數組:(推薦)
使用以頂點為索引的列表數組,其中每個元素都是和該頂點相連的頂點列表。如下圖:
要連接一條v到w的邊,我們要將w添加到v的鄰接表中並把v添加到w的臨界表中。因此這種結構中每條邊都會出現兩次。
代碼實現:
//我們使用前面介紹過的Bag,Stack實現,相關代碼請看數據結構之隊列、棧。

1 public class Graph { 2 3 private final int V; 4 private int E; 5 private Bag<Integer> adj[]; 6 7 @SuppressWarnings("unchecked") 8 public Graph(int V) 9 { if (V < 0) throw new IllegalArgumentException("Number of vertices must be nonnegative"); 10 this.V=V; 11 this.E=0; 12 adj= (Bag<Integer>[])new Bag[V]; 13 for(int i=0;i<V;i++) 14 { 15 adj[i]=new Bag<Integer>(); 16 } 17 } 18 19 public Graph(Graph G) { 20 this(G.V()); 21 this.E = G.E(); 22 for (int v = 0; v < G.V(); v++) { 23 24 Stack<Integer> reverse = new Stack<Integer>(); 25 for (int w : G.adj[v]) { 26 reverse.push(w); 27 } 28 for (int w : reverse) { 29 adj[v].add(w); 30 } 31 } 32 } 33 34 public int V() 35 { 36 return this.V; 37 } 38 39 public int E() 40 { 41 return this.E; 42 } 43 44 private void validateVertex(int v) { 45 if (v < 0 || v >= V) 46 throw new IllegalArgumentException("vertex " + v + " is not between 0 and " + (V-1)); 47 } 48 49 public void addEdge(int v,int w) 50 { validateVertex(v); 51 validateVertex(w); 52 adj[v].add(w); 53 adj[w].add(v); 54 E++; 55 } 56 57 public Iterable<Integer> adj(int v) { 58 validateVertex(v); 59 return adj[v]; 60 } 61 62 public int degree(int v) { 63 validateVertex(v); 64 return adj[v].size(); 65 } 66 67 public String toString() { 68 StringBuilder s = new StringBuilder(); 69 s.append(V + " vertices, " + E + " edges " ); 70 for (int v = 0; v < V; v++) { 71 s.append(v + ": "); 72 for (int w : adj[v]) { 73 s.append(w + " "); 74 } 75 s.append("\r"); 76 } 77 return s.toString(); 78 } 79 80 }