一開始我是用c寫的,後面才發現廣搜要用到隊列,因此我就直接使用c++的STL隊列來寫,c++
由於不想再寫多一個隊列了。此次實驗寫了兩個多鍾,由於要邊寫邊思考,太菜了哈哈。算法
主要參考《大話數據結構》這本書,而後加上本身的一些東西改編,此次實驗算是完成了;數組
--------------------------------------------------------------------------------數據結構
首先咱們來看一下鄰接表是怎麼存儲圖的,好比說下面有一個無向圖函數
則它的鄰接表是這樣的,鄰接表有兩個部分,一個是頂點表,一個是邊表。頂點表長這樣測試
而後就看,它有好多個頂點,因此,咱們給它開個數組,長這樣spa
那個下標是輸入頂點的順序,就是一個位置3d
上面這一坨就是鄰接表的頂點表,顧名思義,就是用來存它的頂點的一個表指針
而後接下來是邊表,邊表是用來幹什麼的呢?邊表就是用來存一個頂點的鄰接點,blog
如剛纔的無向圖,
頂點v0的鄰接點就是v1,v3了,v2的鄰接點就是v1,v3,v4
因此由此咱們可得出邊表的樣子,長這樣
邊表就是這樣子,用來存頂點的鄰接點的,每一行都是一個邊表,因此一個頂點對應一個邊表
那些箭頭就是指針,指向下一個結點,而後null表示爲空
如今頂點表有了,邊表也有了,咱們把它合併起來就很清楚,look;
這個就是一個圖的鄰接表了,若是是有向圖,則在adjvex和next中間加多一個weight用來存儲權值就好了,但在這我就再也不講了
好了,圖出來了,看看代碼怎麼實現;
首先,咱們得定義好頂點表和邊表的結構,由於它們都是一種新的數據類型
代碼以下:
//邊表節點結構,一個adjvex用來存儲鄰接點的位置,一個next指針用來指向下一個節點 typedef struct EdgeNode { int adjvex; struct EdgeNode * next; } EdgeNode; //頂點表節點結構,一個data用來存儲數據,一個firstedge是用來指向邊表的第一個節點 typedef struct { string data; EdgeNode * firstedge; } AdjList;
而後咱們就能夠定義一個圖的鄰接表了,這樣
//裏面的adjList[15]表示我給頂點表開了15的單位大小,而後numVertex,numEdge是一個圖的頂點數和邊數 typedef struct { AdjList adjList[15]; int numVertex,numEdge; } GraphAdjList;
因此後面咱們想定義一個新的圖的鄰接表,能夠直接 GraphAdjList G 就好了;
重點來了,定義圖的鄰接表咱們搞定了,接下來就是建立了
在此以前咱們得先看看一個東西
那就是寫一個函數,用來返回一個頂點所在的位置,這個會有用到
代碼以下:
//這個函數是這樣的,它會遍歷圖的頂點,而後返回一個位置(其實也就是它所在的下標) int local(GraphAdjList G,string val) { for(int i=0; i<G.numVertex; i++) { if(G.adjList[i].data==val) return i; } return -1; } //好比v2的位置是在2 這個能夠看上面的頂點表圖
接下來就是建立一個圖的鄰接表,我會邊用代碼邊用圖來表示,這樣就能夠更好的理解代碼了
建立圖的代碼以下
void CreateGraph(GraphAdjList & G) { int i,j,k; string v1,v2; EdgeNode * e,* p,*q; cout<<"請輸入頂點數和邊數,並以空格隔開:"<<endl; cin>>G.numVertex>>G.numEdge; cout<<"請輸入頂點的信息:"<<endl; for(i=0; i<(G.numVertex); i++) { cout<<"第"<<i+1<<"個頂點:"<<endl; cin>>G.adjList[i].data; G.adjList[i].firstedge=NULL; } for(k=0; k<(G.numEdge); k++) { cout<<"請輸入邊(Vi,Vj)上的頂點信息:"<<endl; cin>>v1>>v2; i=local(G,v1); j=local(G,v2); if(G.adjList[i].firstedge==NULL) { e= new EdgeNode; e->adjvex=j; e->next=NULL; G.adjList[i].firstedge=e; } else { p=G.adjList[i].firstedge; while(p->next!=NULL) { p=p->next; } e = new EdgeNode; e->adjvex=j; e->next=NULL; p->next=e; } if(G.adjList[j].firstedge==NULL) { e= new EdgeNode; e->adjvex=i; e->next=NULL; G.adjList[j].firstedge=e; } else { p=G.adjList[j].firstedge; while(p->next!=NULL) { p=p->next; } e = new EdgeNode; e->adjvex=i; e->next=NULL; p->next=e; } } }
接下來咱們拆分一些主要代碼,看看是怎麼實現的;
①
cin>>G.adjList[i].data;
G.adjList[i].firstedge=NULL;
這裏是往頂點表插入頂點,並把firstedge域置空,如圖:
②
cin>>v1>>v2;
i=local(G,v1);
j=local(G,v2);
輸入每條邊的兩端的頂點,通常咱們是從小到大輸入的,例如這裏咱們
先是輸入v0 v1 , v0 v3這樣的,而後它會返回位置分別是0 1,0 3
而後後面邊表的插入方法時,我用的是尾插法,由於這樣才能達到跟圖片同樣的效果
否則用頭插法的話,那個邊表的順序是反的;
當咱們執行完這個CreateGraph函數的時候,就已經建立了以下圖所示的鄰接表了;
建立完成後,咱們就能夠把鄰接表輸出了,並且是按照圖中所示同樣的輸出
代碼以下:
void Prin(GraphAdjList G) { cout<<"所創建的鄰接表如如下所示:"<<endl; for(int i=0; i<G.numVertex; i++) { cout<<G.adjList[i].data; //先輸出頂點信息 EdgeNode * e = G.adjList[i].firstedge; while(e) //而後就開始遍歷輸出每一個邊表所存儲的鄰接點的下標 { cout<<"-->"<<e->adjvex; e=e->next; } cout<<endl; } }
至此,咱們建立一個圖的鄰接表並能夠輸出該鄰接表了,接下來咱們
就是廣度優先遍歷和深度優先遍歷了
關於這兩個遍歷的定義我也很少講了,大家能夠查資料,我直接就貼
上代碼就行了
①深度優先遍歷
這個遍歷的重點就是它的算法
void DFS(GraphAdjList G,int i) { EdgeNode * p; DFSvisited[i]=true; cout<<G.adjList[i].data<<" "; p=G.adjList[i].firstedge; while(p) { if(!DFSvisited[p->adjvex]) DFS(G,p->adjvex); p=p->next; } }
而後就是使用這個算法了
void DFSTraverse(GraphAdjList G) { for(int i=0; i<G.numVertex; i++) DFSvisited[i]=false; for(int i=0; i<G.numVertex; i++) { if(!DFSvisited[i]) DFS(G,i); } }
因此這兩部分代碼結合起來就是深度優先遍歷了
對了,那個DFSvisited[i]是一個bool型的數組,
用來標記是否遍歷過的,能夠在前面加上
bool DFSvisited[50]; //用於深搜的標記數組 bool BFSvisited[50]; //用於廣搜的標記數組
②廣度優先遍歷
這個遍歷直接一個函數就能搞定,須要用到隊列,
相信大家既然在看圖的部分的話,那麼隊列確定
也早已學會了,嘿嘿。
void BFSTraverse(GraphAdjList G) { EdgeNode * p; queue<int>q; for(int i=0; i<G.numVertex; i++) BFSvisited[i]=false; for(int i=0; i<G.numVertex; i++) { if(!BFSvisited[i]) { BFSvisited[i]=true; cout<<G.adjList[i].data<<" "; q.push(i); while(!q.empty()) { int count =q.front(); q.pop(); p=G.adjList[count].firstedge; while(p) { if(!BFSvisited[p->adjvex]) { BFSvisited[p->adjvex]=true; cout<<G.adjList[p->adjvex].data<<" "; q.push(p->adjvex); } p=p->next; } } } } }
啊咧咧,還有一個銷燬圖的操做
void DestoryGraph(GraphAdjList & G) { EdgeNode * p = NULL; for(int i=0; i<G.numVertex; i++) { p=G.adjList[i].firstedge; while(p) { EdgeNode * temp = p; p=p->next; delete temp; } G.adjList[i].firstedge=NULL; } }
至此,整篇文章能夠結束了,有什麼錯誤或者問題可在下方留言,
一塊兒探討
貼上測試效果圖:
大家能夠注意一下鄰接表的輸出跟我上面給的圖是同樣的
拜拜,我去作大保健了。