什麼是圖:
圖是由頂點集合及頂點間的關係組成的一種數據結構:G = (V , E), 其中頂點集合V={ x| x屬於某個數據對象集} 是有窮非空集合;E = {(x,y) | x,y屬於V } 或者 E = { (x , y ) | x,y屬於V && Path( x , y) }是頂點間關係的有窮集合,也叫做邊的集合。(x, y)表示 x 到 y 的一條雙向通路,即(x , y)是無方向的。
圖的相關概念:
(1)頂點和邊: 圖中節點稱爲頂點,第i個節點記作Vi 。兩個頂點Vi 和Vj 相關聯稱作頂點Vi 和頂點 Vj 之間有一條邊,圖中的第k條邊記作(Vi ,Vj)或 < Vi
,Vj>。
(2)有向圖和無向圖: 在有向圖中,頂點對< x, y >是有序的,頂點對< x , y>稱爲頂點x到頂點y 的一條邊,< x,y> 與 < y,x >是兩條不同的邊。 在無向圖中,頂點對< x,y>是無序的,< x, y> 與 < y,x >表示同一條邊。
(3)完全圖:在有n個頂點的無向圖中,若有 n*(n-1) / 2條邊,即任意兩個頂點之間有且僅有一條邊,則此圖爲無向完全圖。在n個頂點的有向圖中,若有 n *(n-1) 條邊,即任意兩個頂點之間有且僅有方向相反的邊,則稱此圖爲有向完全圖。
(4)鄰接頂點: 在無向圖G中,若( u,v) 是 E (G) 中的一條邊,則稱 u和 v 互爲鄰接頂點,並稱邊(u,v)依附於頂點u 和 v ;在有向圖G中,若< u,v >是E(G)中的一條邊,則稱頂點u鄰接到v,頂點v鄰接自頂點u,並稱邊< u,v>與頂點u和頂點v相關聯。
(5)頂點的度: 頂點v的度是指與它相關聯的邊的條數,記作deg(v) 。在有向圖中,頂點的度等於該頂點的入度與出度之和,其中頂點v的入度是以v爲終點的有向邊的條數,記作indev(v); 頂點v的出度是以v爲起始點的有向邊的條數,記作outdev(v) 。因此:dev(v)=indev(v)+outdev(v);
對於無向圖,頂點的度等於該頂點的入度和出度,即dev(v)=indev(v)=outdev(v)
(6) 路徑: 在圖G=( V , E )中,若從頂點Vi出發有一組邊使其可達到頂點Vj,則稱頂點Vi到頂點Vj的頂點序列爲從頂點Vi到頂點Vj的路徑。
(7) 權:邊附帶的數據信息。
(8)路徑長度: 對於不帶權的圖,一條路徑的路徑長度是指該路徑上的邊的條數;對於帶權的圖,一條路徑的路徑長度是指該路徑上各個邊權值的總和。
(9)簡單路徑與迴路:若路徑上各頂點V1,V2,V3,…,Vm均不重複,則稱這樣的路徑爲簡單路徑。若路徑上第一個頂點V1和最後一個頂點Vm重合,則稱這樣的路徑爲迴路或環。
(10)子圖: 設圖G={ V ,E}和圖G1={V1,E1},若V1屬於E,則稱G1是G的子圖。
(11)連通圖: 在無向圖中,若從頂點V1到頂點V2有路徑,則稱頂點V1與頂點V2是連通的。如果圖中任意一對頂點都是連通的,則稱此圖爲連通圖。
(12)強連通圖:在有向圖中,若在每一對頂點Vi和Vj之間都存在一條從Vi到Vj的路徑,也存在一條從Vj到Vi的路徑,則稱此圖是強連通圖。
(13)生成樹:一個連通圖的最小連通子圖稱作該圖的生成樹。有n個頂點的連通圖的生成樹有n個頂點和n-1條邊。
圖的模擬實現:
鄰接矩陣法:
將所有的頂點信息組織成一個頂點表,然後利用一個矩陣來表示各頂點之間的鄰接關係。
使用二維數組表示一個矩陣,G.Edge[n][n]。
w( i , j ) 表示的是權值。
代碼實現:
#pragma once
#include<iostream>
#include<vector>
#include<assert.h>
using namespace std;
//臨接矩陣法模擬實現圖
template<class V,class W,bool digraph=false>
class Graph
{
public:
Graph(V* array, size_t size)
:_v(array, array + size)
{
_edges.resize(size);
size_t i = 0;
for (i = 0; i < size; i++)
{
_edges[i].resize(size);
}
}
//添加邊源目標權值
void Addedges(const V& src, const V& dst, const W& w)
{
size_t srcIndex = GetVertexIndex(src);
size_t dstIndex = GetVertexIndex(dst);
_edges[srcIndex][dstIndex] = w; //賦權值
if (digraph == false) //是無向圖
{
_edges[dstIndex][srcIndex] = w;
}
}
//獲取頂點的度
int getCount(const V& v)
{
int count = 0;
size_t i = 0;
int set = GetVertexIndex(v);
for (i = 0; i < _v.size(); i++)
{
if (_edges[set][i] !=0)
count++;
}
return count;
}
//打印
void Display()
{
size_t i = 0,j=0;
size_t size= _v.size();
for (i = 0; i < size; i++)
{
for (j = 0; j < size; j++)
{
printf("%2d ",_edges[i][j]);
}
cout << endl;
}
cout << endl;
}
private:
//獲取頂點下標
size_t GetVertexIndex(const V& v)
{
size_t i = 0;
for (i = 0; i < _v.size(); i++)
{
if (v == _v[i])
return i;
}
assert(false);
return -1;
}
private:
vector<V> _v; //頂點集合
vector<vector<W>> _edges; //二維數組鄰接矩陣
};
void test()
{
char* p = "ABCDE";
Graph<char, int,true> g(p, strlen(p));
g.Addedges('A', 'D', 10);
g.Addedges('A', 'E', 20);
g.Addedges('B', 'C', 10);
g.Addedges('B', 'D', 20);
g.Addedges('B', 'E', 30);
g.Addedges('C', 'E', 40);
g.Display();
cout << g.getCount('B') << endl;
}
運行結果:
(有向圖)
(無向圖)