一、基本術語:
Graph(V,E) V:頂點的有窮非空集合,E:邊的有窮集合
邏輯結構:多個對多個
無向圖:每條邊都沒有方向
有向圖:每條邊都有方向
完全圖:任意兩個點都有一條邊相連
稀疏圖:有很少邊或弧的圖;稠密圖:多
網:邊/弧帶權的圖
權:圖中邊/弧所具有的相關數,表明從一個頂點到另一個頂點的距離或耗費
鄰接:有邊/弧相鄰的兩個頂點之間的關係。存在(vi,vj),互爲鄰接點,存在<vi,vj>,vi鄰接到vj,vj鄰接於vi
關聯(依附):邊/弧與頂點之間的關係,存在(vi,vj)/<vi,vj>,則稱該邊/弧關聯於vi和vj
頂點的度:與該頂點相關聯的邊的數目,記爲TD(v)
有向圖中,頂點的度=該頂點的入度+出度=ID(v)+OD(v)(入度是以V爲終點的有向邊條數)
路徑:接續的邊構成的頂點序列
路徑長度:路徑上邊或弧的數目/權值之和
環(迴路):第一個頂點和最後一個頂點相同的路徑
簡單路徑:除路徑起點和終點可以相同以外,其餘頂點均不相同的路徑
簡單環(簡單迴路):除路徑起點和終點相同以外,其餘頂點均不相同的路徑
連通圖(強連通圖):在G=(V,{E})中,若對任意兩個頂點v,u都存在從v到u的路徑,則G是連通圖/強連通圖------有向圖稱爲強XX
子圖:G(V,E),G1(V1,E1)
連通子圖(強連通子圖):
無向圖G 的極大連通子圖稱爲G的連通分量。
極大連通子圖意思是:該子圖是 G 連通子圖,將G 的任何不在該子圖中的頂點加入,子圖不再連通。
極小連通子圖:該子圖是G的連通子圖,在該子圖中刪除任意一邊,子圖則不再連通
生成樹:包含無向圖G所有頂點的極小連通子圖
生成森林:對非連通圖,由各個連通分量的生成樹的集合
二、圖的存儲結構:
順序存儲結構:數組表示法(鄰接矩陣)
鏈式存儲結構:多重鏈表(鄰接表,鄰接多重表,十字鏈表)
1.數組表示法(鄰接矩陣)
<span style="font-size:14px;">//用兩個數組分別存儲頂點表和鄰接矩陣
#define MaxInt 32767//表示極大值 ∞
#define MVNum 100//最大定點數
typedef char VerTextType;//假設頂點的數據類型爲字符型
typedef int ArcType;//邊的權值類型爲整數型
struct AMGraph
{
VerTextType vexs[MVNum];//頂點表
ArcType arcs[MVNum][MVNum];//鄰接矩陣
int vexnum,arcnum;//圖的當前點數和邊數
};
</span>
轉載:C++ 中typedef用法總結詳見
http://www.cnblogs.com/charley_yang/archive/2010/12/15/1907384.html
2.鏈式表示法(鄰接表)
<span style="font-size:14px;">#define MVNum 100//最大頂點數
typedef char VerTextType;//假設頂點的數據類型爲字符型
//鄰接表的存儲表達
typedef struct ArcNode//邊結點
{
int adjvex;//該邊所指向的頂點的位置
struct ArcNode *nextarc;//指向下一條邊的指針
OtherInfo info;//和邊相關的信息
}ArcNode;
typedef struct VNode
{
VerTextType data;//頂點信息
ArcNode *firststare;//指向第一條依附於該頂點的邊的指針
}VNode,AdjList[MVNum];//AdjList表示鄰接表類型
typedef struct
{
AdjList vertices;//鄰接表
int vexnum,arcnum;//圖的當前頂點數和邊數
};
</span>
鄰接矩陣和鄰接表:
1. 聯繫:鄰接表中每個鏈表對應於鄰接矩陣中的一行,鏈表中結點個數等於一行中非零元素的個數。
2. 區別:
①對於任一確定的無向圖,鄰接矩陣是唯一的(行列號與頂點編號一致),但鄰接表不唯一(鏈接次序與頂點編號無關)。
②鄰接矩陣的空間複雜度爲O(n^2),而鄰接表的空間複雜度爲O(n+e)。
3. 用途:鄰接矩陣多用於稠密圖;而鄰接表多用於稀疏圖
三、圖的遍歷-圖的基本運算
搜索引擎兩種基本抓取策略-深度優先,廣度優先
兩種策略結合:先廣後深+權重優先
1.深度優先搜索DFS(Depth_FirstSearch)
仿樹的先序遍歷
在訪問圖中某一起始頂點 v 後,由 v 出發,訪問它的任一鄰接頂點 w1;
再從 w1 出發,訪問與 w1鄰接但還未被訪問過的頂點 w2;
然後再從 w2 出發,進行類似的訪問,…
如此進行下去,直至到達所有的鄰接頂點都被訪問過的頂點 u 爲止。
接着,退回一步,退到前一次剛訪問過的頂點,看是否還有其它沒有被訪問的鄰接頂點。
如果有,則訪問此頂點,之後再從此頂點出發,進行與前述類似的訪問;
如果沒有,就再退回一步進行搜索。重複上述過程,直到連通圖中所有頂點都被訪問過爲止。
<span style="font-size:14px;">//DFS實現-可用遞歸
void DFS(AMGraph G,int v)//G爲鄰接矩陣
{
cout<<v;
visited[v]=true;//訪問第v個頂點
for(int w=0;w<G.vexnum;w++)//依次檢查鄰接矩陣的v所在的行
{
if((G.arcs[v][w]!=0)&&(!visited[w]))
{
DFS(G,w);
}
}
}
void DFS(ALGraph G,int v)//G爲鄰接表類型
{
cout <<v;
visited[v]=true;
p=G.vertices[v].firststare;
while(p!=NULL)
{
w=p->adjex;//表示w是v的鄰接點
if(!visited[w])
DFS(G,w);
p=p->nextarc;//p指向下一個邊結點
}
}
</span>
2.廣度優先搜索BFS(Breadth_FirstSearch)
仿樹的層次遍歷過程
分層的,不回退,非遞歸
<span style="font-size:14px;">//廣義遍歷實現
void BFS(Graph G,int v)
{
queue<int > Q;
//訪問第v個頂點
cout<<v;
visited[v]=true;
InitQueue(Q);//輔助隊列Q初始化,置空
EnQueue(Q,v);//v進隊列
while(!QueueEmpty(Q))//隊列非空
{
DeQueue(Q,u);//出隊列並置爲u
for(int w=FirstAdjex(G,u);w>=0;w=NextAdjex(G,u,w))
{
if(!visited[w])//w爲u尚未訪問過的結點
{
cout<<w;
visited[w]=true;
EnQueue(Q,w);
}
}
}
}
</span>
DSF與BFS算法效率比較
空間複雜度相同,都是O(n)(借用了堆棧和隊列)
時間複雜度與存儲結構(鄰接矩陣或鄰接表)有關,而與搜索路徑無關
四、圖的應用
1.最小生成樹-無向圖的應用
如何求?
Prim算法:歸併頂點,與邊數無關,適於稠密網-加點法,選擇權值最小的先加上
Krustal算法:歸併邊,適於稀疏網—加邊法,選擇權值最小的先加上
貪心算法:找零錢,先找最大幣值的
2.最短路徑-有向圖的應用
與最小生成樹不同,不一定包含n個頂點
解決方法:
單源最短路徑-迪傑斯特拉算法-一頂點到其他各頂點
所有頂點間的最短距離-弗洛伊德算法-任意兩頂點之間
3.活動網絡-有向圖的應用
①AOV網(Activity On Vertices)—用頂點表示活動的網絡-拓撲排序算法
② AOE網(Activity On Edges)—用邊表示活動的網絡-關鍵路徑
拓撲有序序列:由AOV網中的所有頂點構成的一個線性序列,在這個序列中體現了所有頂點間的優先關係