一开始我是用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; } }
至此,整篇文章能够结束了,有什么错误或者问题可在下方留言,
一块儿探讨
贴上测试效果图:
大家能够注意一下邻接表的输出跟我上面给的图是同样的
拜拜,我去作大保健了。