第六章 圖

一、基本術語:

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>

DSFBFS算法效率比較

空間複雜度相同,都是O(n)(借用了堆棧和隊列)

時間複雜度與存儲結構(鄰接矩陣或鄰接表)有關,而與搜索路徑無關

 

四、圖的應用

1.最小生成樹-無向圖的應用

如何求?

Prim算法:歸併頂點,與邊數無關,適於稠密網-加點法,選擇權值最小的先加上

Krustal算法:歸併邊,適於稀疏網—加邊法,選擇權值最小的先加上

貪心算法:找零錢,先找最大幣值的

 

2.最短路徑-有向圖的應用

與最小生成樹不同,不一定包含n個頂點

解決方法:

單源最短路徑-迪傑斯特拉算法-一頂點到其他各頂點

所有頂點間的最短距離-弗洛伊德算法-任意兩頂點之間

 

3.活動網絡-有向圖的應用

①AOV網(Activity  On Vertices)—用頂點表示活動的網絡-拓撲排序算法

② AOE網(Activity  On Edges)—用邊表示活動的網絡-關鍵路徑

拓撲有序序列:由AOV網中的所有頂點構成的一個線性序列,在這個序列中體現了所有頂點間的優先關係

 





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章