在第十一和第十二週的學習中,我瞭解到了有關圖的一些知識,圖是一種比線性表和樹更為複雜的資料結構,她不像線性表一樣,資料元素之間具有線性關係,每個元素對應一個前驅和一個後繼,她也不像樹一樣,資料元素之間有明顯的層次關係,簡而言之,在圖結構中,結點之間的關係可以是任意的,圖中任意兩個資料元素之間都可能相關。感覺自己這一週有點鬆懈了,pta上面的題目都只是看一遍題目覺得不會就去翻書,或是求助同學,缺少獨立思考!!!欸,還是先講講有關圖的一些基本知識吧。
1、 圖的定義
圖是由頂點的有窮非空集合和頂點之間邊的集合組成,通過表示為G(V,E),其中,G標示一個圖,V是圖G中頂點的集合,E是圖G中邊的集合。
無邊圖:若頂點Vi到Vj之間的邊沒有方向,則稱這條邊為無項邊(Edge),用序偶對(Vi,Vj)標示。
對於下圖無向圖G1來說,G1=(V1, {E1}),其中頂點集合V1={A,B,C,D};邊集合E1={(A,B),(B,C),(C,D),(D,A),(A,C)}:
有向圖:若從頂點Vi到Vj的邊是有方向的,則成這條邊為有向邊,也稱為弧(Arc)。用有序對(Vi,Vj)標示,Vi稱為弧尾,Vj稱為弧頭。如果任意兩條邊之間都是有向的,則稱該圖為有向圖。
有向圖G2中,G2=(V2,{E2}),頂點集合(A,B,C,D),弧集合E2={<A,D>,{B,A},<C,A>,<B,C>}.
權(Weight):有些圖的邊和弧有相關的數,這個數叫做權(Weight)。這些帶權的圖通常稱為網(Network)。
2、 圖的儲存結構
鄰接矩陣:圖的鄰接矩陣儲存方式是用兩個陣列來標示圖。一個一位陣列儲存圖頂點的資訊,一個二維陣列(稱為鄰接矩陣)儲存圖中邊或者弧的資訊。
設圖G有n個頂點,則鄰接矩陣是一個n*n的方陣,定義為:
圖的鄰接矩陣儲存表示:
#define MaxInt 10000 //表示極大值,即∞ #define MVNum 100 //最大頂點數 typedef char VerTexType;//假設頂點的資料型別為字元型 typedef int ArcType; //假設邊的權值型別為整型 typedef struct { VerTexType Vexs[MVNum]; //頂點表 ArcType arcs[MVNum] [MVNum]; //鄰接矩陣 int vexnum,arcnum; //圖的當前點數和邊數 }AMGraph;
鄰接表:圖的鏈式儲存結構
#define MvNum 100 //最大頂點數 typedef struct ArcNode //邊結點 { int adjvex; //該邊所指向的頂點的位置 struct ArcNode *nextarc;//指向下一條邊的指標 }ArcNode; typedef struct VNode //頂點資訊 { VertexType data; ArcNode *firstarc; //指向第一條依附該頂點的邊的指標 }VNode,AdjList[MvNum]; //AdjList表示鄰接表型別 typedef struct { AdjList Vertices; //一維陣列 int vexnum,arcnum; //圖的當前頂點數和邊數 }Graph;
採用鄰接表表示法建立無向圖:
Void CreateUDG(ALGraph &G) {/*採用鄰接表表示法建立無向圖G*/ cin>>G.vexnum>>G.arcnum;/*輸入總頂點數,總邊數*/ for(i=0;i<G.vexnum;++i) { cin>>G.vertices[i].data;/*頂點值*/ G.vertices[i].firstarc=NULL; } for(k=0;k<G.arcnum;++k) {/*輸入各邊,構造鄰接表*/ cin>>v1>>v2;/*一條邊對應的兩個頂點*/ i=LocateVex(G,v1); j=LocateVex(G,v2);/*確定v1,v2在G.vertices[i]的序號*/ p1=new ArcNode; p1->adjvex=j; p1->nextarc=G.vertices[i].firstarc; G.vertices[i].firstarc=p1; p2=new ArcNode; p2->adjvex=i; p2->nextarc=G.vertices[j].firstarc; G.vertices[j].firstarc=p1 } }
3、圖的遍歷
(1)深度優先搜尋遍歷
深度優先搜尋遍歷連通圖是一個遞迴的過程(劃重點?)
輔助陣列:vi[i]--訪問標誌陣列,賦初值為"false"(若已被訪問,則將相應的分量置為true。
鄰接矩陣表示的深度優先搜尋遍歷
void DFS(Graph a,int b) //深度優先搜尋 { visited[b]=true; //令頂點對應的visited陣列為true,表示該頂點已被訪問過 cout<<b<<" "; //輸出頂點編號及空格 for(int i=0;i<a.vexnum;i++) { if(a.arcs[b][i]==1 && visited[i]==false)DFS(a,i); //若頂點對應的鄰接點未被訪問,則遞迴呼叫DFS函式 } }
(2)廣度優先搜尋遍歷
特點:儘可能先對橫向進行搜尋
輔助陣列:visited[i]-訪問標誌陣列!!!
void BFS(Graph a,int b) //廣度優先搜尋 { int temp; //定義引數 while(!q.empty()) //若佇列不為空 { temp=q.front(); //取隊頭元素值為temp q.pop(); //隊頭元素出隊 cout<<temp<<" "; //輸出temp值及空格 for(int i=0;i<a.vexnum;i++) { if(a.arcs[temp][i]==1 && visited[i]==false) //若頂點對應的鄰接點未被訪問,則鄰接點入隊 { q.push(i); //鄰接點入隊 visited[i]=true; //鄰接點對應的visited陣列取true,表示已被訪問 } } visited[b]=true; //第一次入隊的頂點對應的visited陣列值取true,表示已被訪問 } }
4、圖的應用
(1)最小生成樹--在一個連通的所有生成樹之中,各邊權值之和最小的那個生成樹
a 普里姆演算法(從名字上就能看出非常的高大上)又稱為“加點法”(逐步增加U中的頂點)
輔助陣列:clsoedge[i]--記錄從U到U-V具有最小權值的邊(lowcost+adjvex)
struct{ VerTexType adjvex; ArcType lowcost; }closedge[MVNUM];
b 克魯斯卡爾演算法---“加邊法”(逐步增加生成樹的邊)
輔助陣列:Edge[i]--儲存邊的資訊
struct{
VerTexType Head;
VerTexType Tail;
ArcType lowcost;
}Edge[arcnum];
Vexset[i]--標識各個頂點所屬的連通分量
int VexSet[MVNUM];
(2)最短路徑--從源點到其餘各頂點的最短路徑
迪傑斯特拉演算法(按照路徑長短遞增的次序產生最短路徑)
目標的完成情況:
這幾週上課沒能集中精力,沒有及時複習上一章的內容,被上次的小測成績打擊到了,有點遺憾,平時打的練習題還不夠多。這兩週都有儘量去pta上答題,可是效率不高,遇到程式設計題就不會,沒有思路,結果到現在還沒完成。
接下來的目標:這幾天深夜加班爆肝一下,嘗試自己把題目弄懂,必要時多多借鑑同學的部落格,看別人在遇到問題時是怎樣解決的。
參考資料:大話資料結構-圖論 https://www.cnblogs.com/w-wanglei/p/figure.html