要表示一個圖G=(V,E),有兩種標准的表示方法,即鄰接表和鄰接矩陣。這兩種表示法既可用於有向圖,也可用於無向圖。通常采用鄰接表表示法,因為用這種方法表示稀疏圖(圖中邊數遠小於點個數)比較緊湊。但當遇到稠密圖(|E|接近於|V|^2)或必須很快判別兩個給定頂點手否存在連接邊時,通常采用鄰接矩陣表示法,例如求最短路徑算法中,就采用鄰接矩陣表示。
圖G=<V,E>的鄰接表表示是由一個包含|V|個列表的數組Adj所組成,其中每個列表對應於V中的一個頂點。對於每一個u∈V,鄰接表Adj[u]包含所有滿足條件(u,v)∈E的頂點v。亦即,Adj[u]包含圖G中所有和頂點u相鄰的頂點。每個鄰接表中的頂點一般以任意順序存儲。
如果G是一個有向圖,則所有鄰接表的長度之和為|E|,這是因為一條形如(u,v)的邊是通過讓v出現在Adj[u]中來表示的。如果G是一個無向圖,則所有鄰接表的長度之和為2|E|,因為如果(u,v)是一條無向邊,那么u會出現在v的鄰接表中,反之亦然。鄰接表需要的存儲空間為O(V+E)。
鄰接表稍作變動,即可用來表示加權圖,即每條邊都有着相應權值的圖,權值通常由加權函數w:E→R給出。例如,設G=<V,E>是一個加權函數為w的加權圖。對每一條邊(u,v)∈E,權值w(u,v)和頂點v一起存儲在u的鄰接表中。
鄰接表C++實現:

1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 5 #define maxn 100 //最大頂點個數 6 int n, m; //頂點數,邊數 7 8 struct arcnode //邊結點 9 { 10 int vertex; //與表頭結點相鄰的頂點編號 11 int weight = 0; //連接兩頂點的邊的權值 12 arcnode * next; //指向下一相鄰接點 13 arcnode() {} 14 arcnode(int v,int w):vertex(v),weight(w),next(NULL) {} 15 arcnode(int v):vertex(v),next(NULL) {} 16 }; 17 18 struct vernode //頂點結點,為每一條鄰接表的表頭結點 19 { 20 int vex; //當前定點編號 21 arcnode * firarc; //與該頂點相連的第一個頂點組成的邊 22 }Ver[maxn]; 23 24 void Init() //建立圖的鄰接表需要先初始化,建立頂點結點 25 { 26 for(int i = 1; i <= n; i++) 27 { 28 Ver[i].vex = i; 29 Ver[i].firarc = NULL; 30 } 31 } 32 33 void Insert(int a, int b, int w) //尾插法,插入以a為起點,b為終點,權為w的邊,效率不如頭插,但是可以去重邊 34 { 35 arcnode * q = new arcnode(b, w); 36 if(Ver[a].firarc == NULL) 37 Ver[a].firarc = q; 38 else 39 { 40 arcnode * p = Ver[a].firarc; 41 if(p->vertex == b) //如果不要去重邊,去掉這一段 42 { 43 if(p->weight < w) 44 p->weight = w; 45 return ; 46 } 47 while(p->next != NULL) 48 { 49 if(p->next->vertex == b) //如果不要去重邊,去掉這一段 50 { 51 if(p->next->weight < w); 52 p->next->weight = w; 53 return ; 54 } 55 p = p->next; 56 } 57 p->next = q; 58 } 59 } 60 void Insert2(int a, int b, int w) //頭插法,效率更高,但不能去重邊 61 { 62 arcnode * q = new arcnode(b, w); 63 if(Ver[a].firarc == NULL) 64 Ver[a].firarc = q; 65 else 66 { 67 arcnode * p = Ver[a].firarc; 68 q->next = p; 69 Ver[a].firarc = q; 70 } 71 } 72 73 void Insert(int a, int b) //尾插法,插入以a為起點,b為終點,無權的邊,效率不如頭插,但是可以去重邊 74 { 75 arcnode * q = new arcnode(b); 76 if(Ver[a].firarc == NULL) 77 Ver[a].firarc = q; 78 else 79 { 80 arcnode * p = Ver[a].firarc; 81 if(p->vertex == b) return; //去重邊,如果不要去重邊,去掉這一句 82 while(p->next != NULL) 83 { 84 if(p->next->vertex == b) //去重邊,如果不要去重邊,去掉這一句 85 return; 86 p = p->next; 87 } 88 p->next = q; 89 } 90 } 91 void Insert2(int a, int b) //頭插法,效率跟高,但不能去重邊 92 { 93 arcnode * q = new arcnode(b); 94 if(Ver[a].firarc == NULL) 95 Ver[a].firarc = q; 96 else 97 { 98 arcnode * p = Ver[a].firarc; 99 q->next = p; 100 Ver[a].firarc = q; 101 } 102 } 103 void Delete(int a, int b) //刪除以a為起點,b為終點的邊 104 { 105 arcnode * p = Ver[a].firarc; 106 if(p->vertex == b) 107 { 108 Ver[a].firarc = p->next; 109 delete p; 110 return ; 111 } 112 while(p->next != NULL) 113 if(p->next->vertex == b) 114 { 115 p->next = p->next->next; 116 delete p->next; 117 return ; 118 } 119 } 120 121 void Show() //打印圖的鄰接表(有權值) 122 { 123 for(int i = 1; i <= n; i++) 124 { 125 cout << Ver[i].vex; 126 arcnode * p = Ver[i].firarc; 127 while(p != NULL) 128 { 129 cout << "->(" << p->vertex << "," << p->weight << ")"; 130 p = p->next; 131 } 132 cout << "->NULL" << endl; 133 } 134 } 135 136 void Show2() //打印圖的鄰接表(無權值) 137 { 138 for(int i = 1; i <= n; i++) 139 { 140 cout << Ver[i].vex; 141 arcnode * p = Ver[i].firarc; 142 while(p != NULL) 143 { 144 cout << "->" << p->vertex; 145 p = p->next; 146 } 147 cout << "->NULL" << endl; 148 } 149 } 150 int main() 151 { 152 int a, b, w; 153 cout << "Enter n and m:"; 154 cin >> n >> m; 155 Init(); 156 while(m--) 157 { 158 cin >> a >> b >> w; //輸入起點、終點 159 Insert(a, b, w); //插入操作 160 Insert(b, a, w); //如果是無向圖還需要反向插入 161 } 162 Show(); 163 return 0; 164 }
鄰接表表示法也有潛在的不足之處,即如果要確定圖中邊(u,v)是否存在,只能在頂點u鄰接表Adj[u]中搜索v,除此之外沒有其他更快的辦法。這一不足可通過圖的鄰接矩陣表示法來彌補,但要(在漸進意義下)以占用更多的存儲空間為代價。
在圖G=(V,E)的臨界矩陣表示法中,假定各頂點按某種任意的方式編號為1,2,···,|V|,那么G的鄰接矩陣為一個|V|*|V|的矩陣A=(a[i][j]),它滿足:
觀察無向圖的鄰接矩陣會發現,它是沿主對角線對稱的。在一個無向圖中,(u,v)和(v,u)表示同一條邊,故無向圖的鄰接矩陣A的轉置矩陣就是它本真。在某些應用中,可以只存儲鄰接矩陣的對角線以及對角線以上的部分,這樣一來,圖所占用的存儲空間幾乎可以減少一半。
鄰接矩陣也可以用來表示加權圖。例如,如果G=<V,E>是一個加權圖,其權值函數為w,對於邊(u,v)∈E,其權值w(u,v)就可以簡單地存儲在鄰接矩陣的第u行第v列的元素中。如果邊不存在,則可以在矩陣的相應元素中存一個NIL值,在很多問題中,對這樣的元素賦0或∞會更為方便些。
鄰接矩陣C++實現:

1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 5 #define maxn 100 6 #define INF 1xffffff //預定於的最大值 7 int n, m; //頂點數、邊數 8 int g[maxn][maxn]; //鄰接矩陣表示 9 10 void Init() 11 { 12 for(int i = 1; i <= n; i++) 13 for(int j = 1; j <= n; j++) 14 g[i][j] = 0; //講所有頂點度數置零,若為帶權圖,則置為INF 15 } 16 void Show() //打印鄰接矩陣 17 { 18 for(int i = 1; i <= n; i++) 19 { 20 for(int j = 1; j <= n; j++) 21 cout << g[i][j] << " "; 22 cout << endl; 23 } 24 } 25 int main() 26 { 27 int a, b; 28 cout << "Enter n and m:"; 29 cin >> n >> m; 30 while(m--) 31 { 32 cin >> a >> b; //輸入為邊的始點、終點,若有權,還需輸入權w 33 g[a][b] = 1; //a、b間存在邊,將g[a][b]置1,若有權,則將其置為權值 34 g[b][a] = 1; //對於無向圖,還要插入邊(b,a) 35 } 36 Show(); 37 return 0; 38 }
(文章以及相關代碼參考算法導論編寫)