日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

图(Graph)的学习

發布時間:2025/3/8 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 图(Graph)的学习 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 圖的認識
    • 圖的概念
      • 無向圖
      • 有向圖
      • 簡單圖
      • 完全圖
      • 子圖
      • 連通、連通圖、連通分量
      • 邊的權和網
      • 加權圖
      • 鄰接和關聯
      • 路徑
      • 簡單路徑、簡單回路
      • 頂點的度、入度和出度
      • 割點(關節點)
      • 橋(割邊)
      • 距離
      • 有向樹
    • 圖的表示
      • 鄰接列表
      • 鄰接矩陣
    • 圖的遍歷
      • 深度優先遍歷
      • 廣度優先遍歷
    • 生成樹

圖的認識

圖(Graph)是由頂點和連接頂點的邊構成的離散結構。一個圖就是一些頂點的集合,這些頂點通過一系列邊結對(連接)。頂點用圓圈表示,邊就是這些圓圈之間的連線。頂點之間通過邊連接。

注意:線性表可以是空表,樹可以是空樹,圖不可以是空圖,圖可以沒有邊,但是至少要有一個頂點。

圖是最靈活的數據結構之一,很多問題都可以使用圖模型進行建模求解。
樹可以說只是圖的特例,但樹比圖復雜很多

注意:頂點有時也稱為節點或者交點,邊有時也稱為鏈接。

圖有各種形狀和大小。邊可以有權重(weight),即每一條邊會被分配一個正數或者負數值。邊可以是有方向的。有方向的邊意味著是單方面的關系。從頂點 X 到 頂點 Y 的邊是將 X 聯向 Y,不是將 Y 聯向 X。

樹和鏈表,都可以被當成是樹,是一種更簡單的形式。他們都有頂點(節點)和邊(連接)。

圖的概念

圖是由頂點集合以及頂點間的關系集合組成的一種數據結構。
由頂點 V 集和邊 E 集構成,因此圖可以表示成 Graph = (V,E)
V是頂點的有窮非空集合;E是頂點之間關系的有窮集合,也叫邊集合。
圖按照邊或弧的多少分稀疏圖和稠密圖

無向圖

無向圖:頂點對<x,y>是無序的。
無向邊:若頂點Vi到Vj之間的邊沒有方向,則稱這條邊為無向邊,用無序偶對(Vi,Vj)來表示
無向圖頂點的邊數叫做度。
無向圖中,頂點的度就是與頂點相關聯的邊的數目,沒有入度和出度。

如果圖中任意兩個頂點時間的邊都是無向邊,則稱該圖為無向圖:
  
上圖是無向圖,所以連接頂點A與D的邊,可以表示為無序對(A,D),也可以寫成(D,A)
對于如上無向圖來說,G=(V,{E}) 其中頂點集合V={A,B,C,D};邊集合E={(A,B),(B,C),(C,D),(D,A),(A,C)}

完全無向圖:若有n個頂點的無向圖有n(n-1)/2 條邊, 則此圖為完全無向圖。

有向圖

如果任意兩個頂點之間都存在邊叫完全圖,有向的叫有向圖。

有向圖:具有方向性,頂點 (u,v)之間的關系和頂點 (v,u)之間的關系不同,后者或許不存在。

有向圖:頂點對<x,y>是有序的;

有向邊:若從頂點Vi到Vj的邊有方向,則稱這條邊為有向邊,也稱為弧。

用有序偶<Vi,Vj>來表示,Vi稱為弧尾,Vj稱為弧頭。

連接頂點A到D的有向邊就是弧,A是弧尾,D是弧頭,<A,D>表示弧。注意不能寫成<D,A>。
對于如上有向圖來說,G=(V,{E})其中頂點集合V={A,B,C,D};弧集合E={<A,D>,<B,A>,<C,A>,<B,C>}

圖中頂點之間有鄰接點。有向圖頂點分為入度和出度。

簡單圖

若無重復的邊或頂點到自身的邊則叫簡單圖。
1)不存在重復邊
2)不存在頂點到自身的邊
所以上面的有向圖和無向圖都是簡單圖。與簡單圖相對的是多重圖,即:兩個結點直接邊數多于一條,又允許頂點通過同一條邊與自己關聯。

完全圖

無向圖中任意兩點之間都存在邊,稱為無向完全圖;
有向圖中任意兩點之間都存在方向向反的兩條弧,稱為有向完全圖
完全有向圖:有n個頂點的有向圖有n(n-1)條邊, 則此圖為完全有向圖。

子圖

若有兩個圖G=(V,E),G1=(V1,E2),若V1是V的子集且E2是E的子集,稱G1是G的子圖。

連通、連通圖、連通分量

1.連通
在無向圖中,兩頂點有路徑存在,就稱為連通的。

2.連通圖
若圖中任意兩頂點都連通,同此圖為連通圖。
如果對于任意兩個頂點都是連通的,則稱該圖是連通圖。
對于有向圖,如果圖中每一對頂點Vi和Vj是雙向連通的,則該圖是強連通圖。
連通:無向圖中每一對不同的頂點之間都有路徑。如果這個條件在有向圖里也成立,那么是強連通的。如果從頂點v到頂點v’有路徑或從頂點v’到頂點v有路徑,則稱頂點v和頂點v’是連通的。

有向圖的連通分支:將有向圖的方向忽略后,任何兩個頂點之間總是存在路徑,則該有向圖是弱連通的。有向圖的子圖是強連通的,且不包含在更大的連通子圖中,則可以稱為圖的強連通分支。

上圖, a 、e沒有到 { b , c , d } 中的頂點的路徑,所以各自是獨立的連通分支。因此,上圖有三個強連通分支,用集合寫出來就是: { { a } , { e } , { b , c , d } }

3.連通分量
無向圖中的極大連通子圖稱為連通分量。

雙連通圖:不含任何割點的圖。

邊的權和網

圖上的邊和弧上帶權則稱為網
圖中每條邊上標有某種含義的數值,該數值稱為該邊的權值。這種圖稱為帶樹圖,也稱作網。

加權圖

加權圖:與加權圖對應的就是無權圖,又叫等權圖。如果一張圖不含權重信息,我們認為邊與邊之間沒有差別。

鄰接和關聯

鄰接(adjacency):鄰接是兩個頂點之間的一種關系。如果圖包含 (u,v),則稱頂點v 與頂點u鄰接。在無向圖中,這也意味著頂點 u 與頂點 v 鄰接。

關聯(incidence):關聯是邊和頂點之間的關系。在有向圖中,邊 (u,v)從頂點 u開始關聯到 v,或者相反,從v關聯到u。在有向圖中,邊不一定是對稱的,有去無回是完全有可能的。

路徑

兩頂點之間的路徑指頂點之間經過的頂點序列,經過路徑上邊的數目稱為路徑長度。若有n個頂點,且邊數大于n-1,此圖一定有環。

路徑(path):依次遍歷頂點序列之間的邊所形成的軌跡。

路徑:非空序列V0 E1 V1 E2 ... Vk稱為頂點V0到頂點Vk的一條路徑。

樹中根節點到任意節點的路徑是唯一的,但是圖中頂點與頂點之間的路徑卻不是唯一的。
路徑的長度是路徑上的邊或弧的數目。
無權圖的路徑長是路徑包含的邊數。
有權圖的路徑長要乘以每條邊的權。

簡單路徑、簡單回路

簡單路徑:沒有重復頂點的路徑稱為簡單路徑。
除第一個頂點和最后一個頂點外,其余頂點不重復出現的回路稱為簡單回路。

:包含相同的頂點兩次或者兩次以上。上圖序列 <1,2,4,3,1>,1出現了兩次,當然還有其它的環,比如<1,4,3,1>。

無環圖:沒有環的圖,其中,有向無環圖有特殊的名稱(DAG(Directed Acyline Graph)

頂點的度、入度和出度

頂點的度為以該頂點為一個端點的邊的數目。

對于無向圖,頂點的邊數為度,度數之和是頂點邊數的兩倍。
對于有向圖,入度是以頂點為終點,出度相反。有向圖的全部頂點入度之和等于出度之和且等于邊數。頂點的度等于入度與出度之和。

割點(關節點)

割點:如果移除某個頂點將使圖或者分支失去連通性,則稱該頂點為割點。某些特定的頂點對于保持圖或連通分支的連通性有特殊的重要意義。

割點的重要性不言而喻。如果你想要破壞互聯網,你就應該找到它的關節點。同樣,要防范敵人的攻擊,首要保護的也應該是關節點

橋(割邊)

橋(割邊):和割點類似,刪除一條邊,就產生比原圖更多的連通分支的子圖,這條邊就稱為割邊或者橋。

距離

若兩頂點存在路徑,其中最短路徑長度為距離。

有向樹

有一個頂點的入度為0,其余頂點的入度均為1的有向圖稱作有向樹。

圖的表示

鄰接列表

鄰接列表:在鄰接列表實現中,每一個頂點會存儲一個從它這里開始的邊的列表。比如,如果頂點A 有一條邊到B、C和D,那么A的列表中會有3條邊,鄰接列表只描述了指向外部的邊。A 有一條邊到B,但是B沒有邊到A,所以 A沒有出現在B的鄰接列表中。

優點:
(1) 便于增加和刪除結點。
(2) 便于統計邊的數目,按頂點表順序掃描所有邊表可得到邊的數目,時間復雜度為O(n+e)。
(3)空間效率高。對于一個具有n個頂點e條邊的圖G,若圖G是無向圖,則在鄰接表表示中有n個頂點表結點和2n個邊表結點。若G是有向圖,則在它的鄰接表表示或逆鄰接表表示中均有n個頂點表結點和e個邊表結點。因此,鄰接表的空間復雜度為O(n+e)。
缺點:
(1) 不便于判斷頂點之間是否有邊,要判斷vi 和vj之間是否有邊,就需掃描第i個邊表,最換情況下要耗費O(n)時間。
(2) 不便于計算有向圖各個頂點的度。

鄰接矩陣

圖最常見的表示形式為鄰接鏈表和鄰接矩陣

特點:
⑴0表示這兩個頂點之間沒有邊,1表示有邊
⑵頂點的度是行內數組之和
⑶求頂點的鄰接點,遍歷行內元素即可

鄰接矩陣,一個存儲著邊的信息的矩陣,而頂點則用矩陣的下標表示。對于一個鄰接矩陣M,如果M(i,j)=1,則說明頂點i和頂點j之間存在一條邊,對于無向圖來說,M (j ,i) = M (i, j),所以其鄰接矩陣是一個對稱矩陣;對于有向圖來說,則未必是一個對稱矩陣。鄰接矩陣的對角線元素都為0。下圖是一個無向圖和對應的鄰接矩陣:


需要注意的是,當邊上有權值的時候,稱之為網圖,則鄰接矩陣中的元素不再僅是0和1了,鄰接矩陣M中的元素定義為:

鄰接矩陣:在鄰接矩陣實現中,由行和列都表示頂點,由兩個頂點所決定的矩陣對應元素表示這里兩個頂點是否相連、如果相連這個值表示的是相連邊的權重。例如,如果從頂點A到頂點B有一條權重為 5.6 的邊,那么矩陣中第A行第B列的位置的元素值應該是5.6:

優點:
(1) 便于判斷兩個頂點之間是否有 邊,即根據A[i][j] = 0或1來判斷。
(2) 便于計算各頂點的度。對于無向圖,鄰接矩陣的第i行元素之和就是頂點i的度。對于有向圖,第i行元素之和就是頂點i的出度,第i列元素之和就是頂點i的入度。

缺點: (1) 不便于增加刪除頂點。 (2)空間復雜度高。如果是有向圖,n個頂點需要n*n個單元存儲邊。如果無向圖,其鄰接矩陣是對稱的,所以對規模較大的鄰接矩陣可以采用壓縮存儲的方法,僅存儲下三角元素,這樣需要n(n-1)/2個單元。無論哪種存儲方式,鄰接矩陣表示法的空間復雜度均為0(n*n)

區別:

鄰接列表在表示稀疏圖時非常緊湊而成為了通常的選擇,但稀疏圖表示時使用鄰接矩陣,會浪費很多內存空間,遍歷的時候也會增加開銷。
如果圖是稠密圖,可以選擇更加方便的鄰接矩陣。
還有,頂點之間有多種關系的時候,也不適合使用矩陣。因為表示的時候,矩陣中的每一個元素都會被當作一個表

圖的遍歷

深度優先遍歷

在深度優先搜索中,保存候補節點是棧,棧的性質就是先進后出,即最先進入該棧的候補節點就最后進行搜索。

深度優先遍歷,也有稱為深度優先搜索(Depth_First_Search),簡稱DFS。其實,就像是一棵樹的前序遍歷。
它從圖中某個結點v出發,訪問此頂點,然后從v的未被訪問的鄰接點出發深度優先遍歷圖,直至圖中所有和v有路徑相通的頂點都被訪問到。若圖中尚有頂點未被訪問,則另選圖中一個未曾被訪問的頂點作起始點,重復上述過程,直至圖中的所有頂點都被訪問到為止。

#include<iostream> using namespace std; int n,m,x,y,a[105][105],book[105][105]= {}; int minn = 999999; void dfs(int starx,int stary,int step) {int nx,ny;if(starx==x&&stary==y) {if(minn > step) {minn = step;}return ;}int next[4][2]= {0,1,0,-1,1,0,-1,0};for(int i=0; i<4; i++) {nx = starx+next[i][0]; ny = stary+next[i][1];if(nx>n||nx<1||ny>m||ny<1)continue;if(a[nx][ny]==0&&book[nx][ny]==0) {book[nx][ny]=1;dfs(nx,ny,step+1);book[nx][ny]=0;}}return ; } int main() {cin>>n>>m>>x>>y;for(int i=1; i<=n; i++) {for(int j=1; j<=m; j++) {cin>>a[i][j];}}book[1][1]=1;dfs(1,1,0);cout<<"最小值為=";cout<<minn<<endl;return 0; } /* 5 4 4 3 0 0 1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1 */

鄰接矩陣表達方式:

#define MAXVEX 100 //最大頂點數 typedef int Boolean; //Boolean 是布爾類型,其值是TRUE 或FALSE Boolean visited[MAXVEX]; //訪問標志數組 #define TRUE 1 #define FALSE 0//鄰接矩陣的深度優先遞歸算法 void DFS(Graph g, int i) {int j;visited[i] = TRUE;printf("%c ", g.vexs[i]); //打印頂點,也可以其他操作for(j = 0; j < g.numVertexes; j++){if(g.arc[i][j] == 1 && !visited[j]){DFS(g, j); //對為訪問的鄰接頂點遞歸調用}} }//鄰接矩陣的深度遍歷操作 void DFSTraverse(Graph g) {int i;for(i = 0; i < g.numVertexes; i++){visited[i] = FALSE; //初始化所有頂點狀態都是未訪問過狀態}for(i = 0; i < g.numVertexes; i++){if(!visited[i]) //對未訪問的頂點調用DFS,若是連通圖,只會執行一次{DFS(g,i);}} }

鄰接表存儲結構:

//鄰接表的深度遞歸算法 void DFS(GraphList g, int i) {EdgeNode *p;visited[i] = TRUE;printf("%c ", g->adjList[i].data); //打印頂點,也可以其他操作p = g->adjList[i].firstedge;while(p){if(!visited[p->adjvex]){DFS(g, p->adjvex); //對訪問的鄰接頂點遞歸調用}p = p->next;} }//鄰接表的深度遍歷操作 void DFSTraverse(GraphList g) {int i;for(i = 0; i < g.numVertexes; i++){visited[i] = FALSE;}for(i = 0; i < g.numVertexes; i++){if(!visited[i]){DFS(g, i);}} }

對比兩個不同的存儲結構的深度優先遍歷算法,對于n個頂點e條邊的圖來說,鄰接矩陣由于是二維數組,要查找某個頂點的鄰接點需要訪問矩陣中的所有元素,因為需要O(n2)的時間。而鄰接表做存儲結構時,找鄰接點所需的時間取決于頂點和邊的數量,所以是O(n+e)。顯然對于點多邊少的稀疏圖來說,鄰接表結構使得算法在時間效率上大大提高。

廣度優先遍歷

廣度優先搜索和深度優先搜索一樣,都是對圖進行搜索的算法,都是從起點開始順著邊搜索,此時并不知道圖的整體結構,直到找到指定節點(即終點)。在此過程中每走到一個節點,就會判斷一次它是否為終點。

廣度優先搜索會根據離起點的距離,按照從近到遠的順序對各節點進行搜索。而深度優先搜索會沿著一條路徑不斷往下搜索直到不能再繼續為止,然后再折返,開始搜索下一條路徑。

在廣度優先搜索中,有一個保存候補節點的隊列,隊列的性質就是先進先出,即先進入該隊列的候補節點就先進行搜索。
廣度優先搜索:將點存儲到隊列中
廣度優先遍歷(Breadth_First_Search),又稱為廣度優先搜索,簡稱BFS。
深度遍歷類似樹的前序遍歷,廣度優先遍歷類似于樹的層序遍歷。

鄰接矩陣的廣度遍歷算法:

void BFSTraverse(Graph g) {int i, j;Queue q;for(i = 0; i < g.numVertexes; i++){visited[i] = FALSE;}InitQueue(&q);for(i = 0; i < g.numVertexes; i++)//對每個頂點做循環{if(!visited[i]) //若是未訪問過{visited[i] = TRUE;printf("%c ", g.vexs[i]); //打印結點,也可以其他操作EnQueue(&q, i); //將此結點入隊列while(!QueueEmpty(q)) //將隊中元素出隊列,賦值給{int m;DeQueue(&q, &m); for(j = 0; j < g.numVertexes; j++){//判斷其他頂點若與當前頂點存在邊且未訪問過if(g.arc[m][j] == 1 && !visited[j]){visited[j] = TRUE;printf("%c ", g.vexs[j]);EnQueue(&q, j);}}}}} }

鄰接表的廣度優先遍歷:

void BFSTraverse(GraphList g) {int i;EdgeNode *p;Queue q;for(i = 0; i < g.numVertexes; i++){visited[i] = FALSE;}InitQueue(&q);for(i = 0; i < g.numVertexes; i++){if(!visited[i]){visited[i] = TRUE;printf("%c ", g.adjList[i].data); //打印頂點,也可以其他操作EnQueue(&q, i);while(!QueueEmpty(q)){int m;DeQueue(&q, &m);p = g.adjList[m].firstedge; 找到當前頂點邊表鏈表頭指針while(p){if(!visited[p->adjvex]){visited[p->adjvex] = TRUE;printf("%c ", g.adjList[p->adjvex].data);EnQueue(&q, p->adjvex);}p = p->next;}}}} }

對比圖的深度優先遍歷與廣度優先遍歷算法,會發現,它們在時間復雜度上是一樣的,不同之處僅僅在于對頂點的訪問順序不同??梢妰烧咴谌珗D遍歷上是沒有優劣之分的,只是不同的情況選擇不同的算法。

生成樹

生成樹的性質
一個有n個頂點的連通圖的生成樹有且僅有n-1條邊
一個連通圖的生成樹并不唯一

總結

以上是生活随笔為你收集整理的图(Graph)的学习的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。