這節,我們說一說,圖的基本源代碼的源代碼實現。具體情況,請聽我一一給大家娓娓道來。
圖的基本操作用一個接口來表示,為表示圖的基本操作,同時給出了頂點類的實現。由於頂點只保存自身信息,所以頂點類 Node<T>很簡單,里面只有一個字段 data。
頂點的類 Node<T>的實現如下所示。
public Class Node<T>
{
private T data; //數據域
//構造器
public Node(T v)
{
data = v;
}
//數據域屬性
public T Data
{
get
{
return data;
}
set
{
data = value;
}
}
結構如圖所示:

}
圖的接口IGraph<T>的定義如下所示。
public interface IGraph<T>
{
//獲取頂點數
int GetNumOfVertex();
初始條件:圖存在;
操作結果:返回圖中的頂點數 由於用到循環的計數的方式。所以其算法的時間的復雜度是O(n2) 如圖所示:

//獲取邊或弧的數目
int GetNumOfEdge();
初始條件:圖存在;
操作結果:返回圖中的邊或弧的數目.由於用到循環的計數的方式。所以其算法的時間的復雜度是O(n2) 如圖所示:

//在兩個頂點之間添加權為v的邊或弧
void SetEdge(Node<T> v1, Node<T> v2, int v);
初始條件:圖存在,頂點 v1 和 v2 是圖的兩個頂點;
操作結果:在頂點 v1 和 v2 之間添加一條邊或弧並設邊或弧的值為 v。由於用到循環的發送方式,時間復雜度是O(n2) 如圖所示:

//刪除兩個頂點之間的邊或弧
void DelEdge(Node<T> v1, Node<T> v2);
初始條件:圖存在,頂點 v1 和 v2 是圖的兩個頂點並且 v1 和 v2 之間有一條邊或弧;
操作結果:刪除頂點 v1 和 v2 之間的邊或弧。 如圖所示:

//判斷兩個頂點之間是否有邊或弧
bool IsEdge(Node<T> v1, Node<T> v2);
初始條件:圖存在,頂點 v1 和 v2 是圖的兩個頂點;
操作結果:如果 v1 和 v2 之間有一條邊或弧,返回 true,否則返回 false。 由於用到了循環,算法的時間的復雜度是O(n2),如圖所示:

}
討論了這些圖的結源代碼基本實現,我們進入了下一個議題,討論了圖的存儲結構。
圖是一種復雜的數據結構,頂點之間是多對多的關系,即任意兩個頂點之間都可能存在聯系。 所以, 無法以頂點在存儲區的位置關系來表示頂點之間的聯系,即順序存儲結構不能完全存儲圖的信息,但可以用數組來存儲圖的頂點信息。要存儲頂點之間的聯系必須用鏈式存儲結構或者二維數組。圖的存儲結構有多種,這里只介紹兩種基本的存儲結構:鄰接矩陣和鄰接表。
什么是鄰接矩陣,所謂鄰接矩陣(Adjacency Matrix)是用兩個數組來表示圖,一個數組是一維數組,存儲圖中頂點的信息,一個數組是二維數組,即矩陣,存儲頂點之間相鄰的信息,也就是邊(或弧)的信息,這是鄰接矩陣名稱的由來。
假設圖G=(V,E)中有n個頂點,即V={v0,v1,…,vn-1},用矩陣A[i][j]表示邊
(或弧)的信息。矩陣A[i][j]是一個n×n的矩陣,矩陣的元素為:
A[i][j]=1若(v[i],v[j])是E(G)的邊和元素
A[i][j]=0若(v[i],v[j])不是E(G)的邊和元素
若 G 是網,則鄰接矩陣可定義為:
A[i][j]=wij若(v[i],v[j])是E(G)的邊和元素
A[i][j]=∞若(v[i],v[j])不是E(G)的邊和元素
其中,wij 表示邊(vi,vj)或弧<vi,vj>上的權值;∞表示一個計算機允許的大於
所有邊上權值的數。


從圖的鄰接矩陣表示法可以看出這種表示法的特點是:
(1)無向圖或無向網的鄰接矩陣一定是一個對稱矩陣。因此,在具體存放鄰接矩陣時只需存放上(或下)三角矩陣的元素即可。
(2)可以很方便地查找圖中任一頂點的度。對於無向圖或無向網而言,頂點 vi 的度就是鄰接矩陣中第 i 行或第 i 列中非 0 或非∞的元素的個數。對於有向圖或有向網而言,頂點 vi 的入度是鄰接矩陣中第 i 列中非 0 或非∞的元素的個數,頂點 vi 的出度是鄰接矩陣中第 i 行中非 0 或非∞的元素的個數。
(3)可以很方便地查找圖中任一條邊或弧的權值,只要 A[i][j]為 0 或∞,就說明頂點 vi 和 vj 之間不存在邊或弧。但是,要確定圖中有多少條邊或弧,則必須按行、按列對每個元素進行檢測,所花費的時間代價是很大的。這是用鄰接矩陣存儲圖的局限性。
下面以無向圖的鄰接矩陣類的實現來說明圖的鄰接矩陣表示的類的實現。
無向圖鄰接矩陣類 GraphAdjMatrix<T>中有三個成員字段, 一個是 Node<T>類型的一維數組 nodes,存
無向圖鄰接矩陣類 GraphAdjMatrix<T>的實現如下所示。
public class GraphAdjMatrix<T> : IGraph<T>
{
private Node<T>[] nodes; //頂點數組
private int numEdges; //邊的數目
private int[ ,] matrix; //鄰接矩陣數組
如圖所示:
//構造器
public GraphAdjMatrix (int n)
{
nodes = new Node<T>[n];
matrix = new int[n,n];
numEdges = 0;
}
//獲取索引為index的頂點的信息
public Node<T> GetNode(int index)
{
return nodes[index];
}
//設置索引為index的頂點的信息 算法的復雜度的是O(1)
public void SetNode(int index, Node<T> v)
{
nodes[index] = v;
}
//邊的數目屬性
public int NumEdges
{
get
{
return numEdges;
}
set
{
numEdges = value;
}
}
//獲取matrix[index1, index2]的值 算法的復雜度是O(1)
public int GetMatrix(int index1, int index2)
{
return matrix[index1, index2];
}
//設置matrix[index1, index2]的值 算法的復雜度是O(1)
public void SetMatrix(int index1, int index2)
{
matrix[index1, index2] = 1;
}
//獲取頂點的數目 算法的復雜度是O(1)
public int GetNumOfVertex()
{
return nodes.Length;
}
//獲取邊的數目 算法的復雜度是O(1)
public int GetNumOfEdge()
{
return numEdges;
}
//判斷v是否是圖的頂點 算法的復雜度是O(n)
public bool IsNode(Node<T> v)
{
//遍歷頂點數組
foreach (Node<T> nd in nodes)
{
//如果頂點nd與v相等,則v是圖的頂點,返回true
if (v.Equals(nd))
{
return true;
}
}
return false;
}
//獲取頂點v在頂點數組中的索引 算法的復雜度是O(n)
public int GetIndex(Node<T> v)
{
int i = -1;
//遍歷頂點數組
for (i = 0; i < nodes.Length; ++i)
{
//如果頂點v與nodes[i]相等,則v是圖的頂點,返回索引值i。
if (nodes[i].Equals(v))
{
return i;
}
}
return i;
}
//在頂點v1和v2之間添加權值為v的邊 算法是O(n2)
public void SetEdge(Node<T> v1, Node<T> v2,int v)
{
//v1或v2不是圖的頂點
if (!IsNode(v1) || !IsNode(v2))
{
Console.WriteLine("Node is not belong to Graph!");
return;
}
//不是無向圖
if(v != 1)
{
Console.WriteLine("Weight is not right!");
return;
}
//矩陣是對稱矩陣
matrix[GetIndex(v1), GetIndex(v2)] = v;
matrix[GetIndex(v2), GetIndex(v1)] = v;
++numEdges;
}
//刪除頂點v1和v2之間的邊
public void DelEdge(Node<T> v1, Node<T> v2)
{
//v1或v2不是圖的頂點
if (!IsNode(v1) || !IsNode(v2))
{
Console.WriteLine("Node is not belong to Graph!");
return;
}
//頂點v1與v2之間存在邊
if (matrix[GetIndex(v1), GetIndex(v2)] == 1)
{
//矩陣是對稱矩陣
matrix[GetIndex(v1), GetIndex(v2)] = 0;
matrix[GetIndex(v2), GetIndex(v1)] = 0;
--numEdges;
}
}
//判斷頂點v1與v2之間是否存在邊 算法的復雜度是O(1)
public bool IsEdge(Node<T> v1, Node<T> v2)
{
//v1或v2不是圖的頂點
if (!IsNode(v1) || !IsNode(v2))
{
Console.WriteLine("Node is not belong to Graph!");
return false;
}
//頂點v1與v2之間存在邊
if (matrix[GetIndex(v1), GetIndex(v2)] == 1)
{
return true;
}
else //不存在邊
{
return false;
}
}
如圖所示:

}
二。連接存儲:
鄰接表 (Adjacency List) 是圖的一種順序存儲與鏈式存儲相結合的存儲結構,類似於樹的孩子鏈表表示法。 順序存儲指的是圖中的頂點信息用一個頂點數組來存儲,一個頂點數組元素是一個頂點結點,頂點結點有兩個域,一個是數據域data,存放與頂點相關的信息,一個是引用域 firstAdj,存放該頂點的鄰接表的第一個結點的地址。頂點的鄰接表是把所有鄰接於某頂點的頂點構成的一個表,它是采用鏈式存儲結構。所以,我們說鄰接表是圖的一種順序存儲與鏈式存儲相結合的存儲結構。其中,鄰接表中的每個結點實際上保存的是與該頂點相關的邊或弧的信息,它有兩個域,一個是鄰接頂點域 adjvex,存放鄰接頂點的信息,實際上就是鄰接頂點在頂點數組中的序號;一個是引用域 next,存放下一個鄰接頂點的結點的地址。頂點結點和鄰接表結點的結構如下圖所示。

