图有两种标准的表示方法,即邻接矩阵和邻接表(通常邻接矩阵用于稠密图,邻接表用于稀疏图)。如下:
对于图的搜索有两种方法:深度优先搜索 & 广度优先搜索。
广度优先搜索(Breadth-first search)
广度优先搜索是将已发现和未发现顶点之间的边界沿其广度方向向外扩展。亦即算法首先会发现和s距离为k的所有点,然后才会发现和s距离为k+1的其他顶点。
伪代码:
EG:
运行时间:O(V+E)。
深度优先遍历(Depth-first search)
在深度优先搜索中,对于最新发现的顶点,如果他还有以此为起点而为探测到的变,就沿着此边继续探测下去。当顶点v的所有变都已被探寻后,搜索将回溯到发现顶点v有起始点那条边。
伪代码:
EG:
运行时间:O(V+E).
========================================================================================================================
广度优先搜索完整代码:
#include<iostream>
#include<queue>
#include<climits>
#define UDG 0
#define DG 1
#define WHITE 2
#define GRAY 3
#define BLACK 4
using namespace std;
typedef char vType;
typedef struct gEdge{
vType adjVertex; //the adjacency vertex pointed by this edge.
int weight; //the weight of this edge
gEdge *nextEdge; //Point to the next edge
}gEdge;
typedef struct gVertex{
vType key; // the key of the vertex
int color;
int d;
vType pai;
gEdge *firstEdge; // point to the first edge attached to the vertex;
}gVertex;
typedef struct ALGraph{
int Vnum;
int Enum;
int kind; //the kind of Graph
gVertex *HeadVertex;
}ALGraph;
typedef struct edge{
vType start;
vType end;
}edge;
int Locate(ALGraph &G,vType s)
{//locate the start vertex of one edge in head vertex of the graph
for(int i=0;i<G.Vnum;i++)
if(G.HeadVertex[i].key == s)
return i;
return -1;
}
void LinkEdgeToGraph(ALGraph &G, edge e)
{
gEdge *arc=new gEdge();
arc->adjVertex=e.end;
int headV_i=Locate(G,e.start);
arc->nextEdge=G.HeadVertex[headV_i].firstEdge;
G.HeadVertex[headV_i].firstEdge = arc;
}
void Graph_Create(ALGraph &G, vType V[], edge E[])
{
//init the head vertex
G.HeadVertex= new gVertex[G.Vnum];
for(int i=0;i<G.Vnum;i++){
G.HeadVertex[i].key=V[i];
G.HeadVertex[i].firstEdge=NULL;
}
//add edge to head vertex in order to create a graph
if(G.kind == DG) //undirected graph
for(int i=0; i<G.Enum; i++)
LinkEdgeToGraph(G,E[i]);
if(G.kind == UDG) // directed graph
for(int i=0; i<G.Enum; i++)
{
LinkEdgeToGraph(G,E[i]);
// link again after reversed
edge temp;
temp.start = E[i].end;
temp.end = E[i].start;
LinkEdgeToGraph(G,temp);
}
}
void Graph_Print(ALGraph G)
{
for(int i=0; i<G.Vnum; i++)
{
cout<<G.HeadVertex[i].key;
gEdge *p = G.HeadVertex[i].firstEdge;
while(p != NULL)
{
cout<<" --> "<< p->adjVertex;
p = p->nextEdge;
}
cout<<endl;
}
}
/*
void Q_Print(queue<vType> Q)
{
cout<<"The Q is:";
while(!Q.empty())
{
cout<<Q.front()<<" ";
Q.pop();
}
cout<<endl;
}
*/
vType *ALGraph_BFS(ALGraph &G, vType s)
{
queue<vType> Q;
vType *BFSResult=new vType[G.Vnum];
//label the vertex:the starting vertex becomes GRAY,the others become WHITE...
for(int i=0; i<G.Vnum; i++)
{
gVertex *hVertex=&G.HeadVertex[i];
hVertex->color = WHITE;
hVertex->d = INT_MAX;
hVertex->pai = '0';
if(hVertex->key == s)
{
hVertex->color = GRAY;
hVertex->d = 0;
}
}
//Clear the Q
while(!Q.empty()) // making the queue Q empty
Q.pop();
Q.push(s); // s enter queue Q
//Searching layer by layer
int r_i=0;
while(!Q.empty())
{
vType u,v;
u= Q.front();Q.pop(); //delete the front element of the Q
BFSResult[r_i] = u; //store the result into Array BFSResult
r_i++;
int h_i=Locate(G,u);
gVertex *hu = &G.HeadVertex[h_i];
gEdge *p = G.HeadVertex[h_i].firstEdge;
while(p)
{
v = p->adjVertex;
h_i = Locate(G,v);
gVertex *hv = &G.HeadVertex[h_i];
if(hv->color == WHITE)
{
hv->color = GRAY;
hv->d = hv->d+1;
hv->pai = u;
Q.push(v);
}
p = p->nextEdge;
}
hu->color = BLACK;
}
return BFSResult;
}
int main()
{
vType V[]={'s','w','r','v','t','x','u','y'};
edge E[]={{'r','v'},{'r','s'},{'s','w'},{'w','t'},{'w','x'},{'t','u'},{'t','x'},{'x','u'},{'x','y'},{'u','y'}};
ALGraph G;
G.Vnum=sizeof(V)/sizeof(vType);
G.Enum=sizeof(E)/sizeof(edge);
G.kind=UDG; //the kind of Graph
Graph_Create(G,V,E);
cout<<"---------------Create Graph-----------------"<<endl;
cout<<"The created graph is:"<<endl;
Graph_Print(G);
cout<<"---------------BFS Graph--------------------"<<endl;
cout<<"Please input the starting position:";
vType s;
cin>>s;
vType *BFSResult = new vType[G.Vnum];
BFSResult=ALGraph_BFS(G,s);
cout<<"The result of BFS is:"<<endl;
for(int i=0; i<G.Vnum; i++)
cout<<BFSResult[i]<<" ";
cout<<endl;
return 0;
}
运行结果:
深度优先搜索完整代码:
#include<iostream>
#include<iomanip>
using namespace std;
#define UDG 0
#define DG 1
#define WHITE 0
#define GRAY 1
#define BLACK 2
#define NONE 0
#define TREE 1
#define BACK 2
#define FORWARD 3
#define CROSS 4
typedef char vType;
typedef struct gEdge{
vType adjVertex; //the adjacency vertex pointed by this edge.
int weight; //the weight of this edge
int type; //the type of edge
gEdge *nextEdge; //Point to the next edge
}gEdge;
typedef struct gVertex{
vType key; // the key of the vertex
int color;
int d,f; // the discovered time and the finished time
vType pai; // the parent node's key after searching
gEdge *firstEdge; // point to the first edge attached to the vertex;
}gVertex;
typedef struct ALGraph{
int Vnum;
int Enum;
int kind; //the kind of Graph
gVertex *HeadVertex;
}ALGraph;
typedef struct edge{
vType start;
vType end;
}edge;
int Locate(ALGraph &G,vType s)
{//locate the start vertex of one edge in head vertex of the graph
for(int i=0;i<G.Vnum;i++)
if(G.HeadVertex[i].key == s)
return i;
return -1;
}
void LinkEdgeToGraph(ALGraph &G, edge e)
{
gEdge *arc=new gEdge();
arc->adjVertex=e.end;
int headV_i=Locate(G,e.start);
arc->nextEdge=G.HeadVertex[headV_i].firstEdge;
G.HeadVertex[headV_i].firstEdge = arc;
}
void Graph_Create(ALGraph &G, vType V[], edge E[])
{
//init the head vertex
G.HeadVertex= new gVertex[G.Vnum];
for(int i=0;i<G.Vnum;i++){
G.HeadVertex[i].key=V[i];
G.HeadVertex[i].firstEdge=NULL;
}
//add edge to head vertex in order to create a graph
if(G.kind == DG) //undirected graph
for(int i=0; i<G.Enum; i++)
LinkEdgeToGraph(G,E[i]);
if(G.kind == UDG) // directed graph
for(int i=0; i<G.Enum; i++)
{
LinkEdgeToGraph(G,E[i]);
// link again after reversed
edge temp;
temp.start = E[i].end;
temp.end = E[i].start;
LinkEdgeToGraph(G,temp);
}
}
void Graph_Print(ALGraph G)
{
for(int i=0; i<G.Vnum; i++)
{
cout<<G.HeadVertex[i].key;
gEdge *p = G.HeadVertex[i].firstEdge;
while(p != NULL)
{
cout<<" --> "<< p->adjVertex;
p = p->nextEdge;
}
cout<<endl;
}
}
void EdgeType_Print(ALGraph G)
{
for(int i=0; i<G.Vnum; i++)
{
gEdge *p = G.HeadVertex[i].firstEdge;
while(p)
{
cout<<G.HeadVertex[i].key<<"-->"<<p->adjVertex<<":";
switch(p->type)
{
case TREE:
cout<<"Tree edge"<<endl;
break;
case BACK:
cout<<"Back edge"<<endl;
break;
case FORWARD:
cout<<"Forward edge"<<endl;
break;
case CROSS:
cout<<"Cross edge"<<endl;
break;
}
p = p->nextEdge;
}
}
}
/*--------------------DFS Alogithms-----------------------*/
int time0;
int r_i=0;
void Graph_DFSVisit(ALGraph &G, gVertex *u, vType *r)
{
time0 = time0 +1; //white vertex u has just been discovered
u->d = time0 ;
u->color = GRAY;
gEdge *p = u->firstEdge;
while(p)
{
vType v = p->adjVertex;
int h_i=Locate(G,v);
gVertex *hv = &G.HeadVertex[h_i];
//classify the edge and recursive searching
if( hv->color == WHITE)
{
hv->pai = u->key;
Graph_DFSVisit(G,hv,r);
p->type = TREE; //Tree edge
}
else if(hv->color == GRAY){
p->type = BACK; //Back edge
}
else if(hv->color == BLACK)
{
if(u->d < hv->d)
p->type = FORWARD; //Forward edge
else
p->type = CROSS; //Cross edge
}
p = p->nextEdge;
}
u->color = BLACK; //backen u;it is finished
r[r_i++]=u->key; //store the dfs result into array r
time0 = time0 +1;
u->f = time0;
}
void ALGraph_DFS(ALGraph &G, vType *result)
{
//init all the vertex
gVertex *u;
for(int i=0; i<G.Vnum; i++)
{
u = &G.HeadVertex[i];
u->color = WHITE;
u->pai = '0';
}
time0 = 0; //time stamp
//explore every vertex
for(int i=0; i<G.Vnum; i++)
{
u = &G.HeadVertex[i];
if(u->color == WHITE)
Graph_DFSVisit(G,u,result);
}
}
/*----------------------------------------------*/
int main()
{
vType V[]={'u','x','v','y','w','z'};
edge E[]={{'u','x'},{'u','v'},{'x','v'},{'v','y'},{'y','x'},{'w','y'},{'w','z'},{'z','z'}};
ALGraph G;
G.Vnum=sizeof(V)/sizeof(vType);
G.Enum=sizeof(E)/sizeof(edge);
G.kind=DG; //the kind of Graph
Graph_Create(G,V,E);
cout<<"---------------Create Graph-----------------"<<endl;
cout<<"The created graph is:"<<endl;
Graph_Print(G);
cout<<"---------------DFS Graph--------------------"<<endl;
vType *DFSResult = new vType[G.Vnum];
ALGraph_DFS(G,DFSResult);
cout<<"The result of DFS is:"<<endl;
for(int i=0; i<G.Vnum; i++)
cout<<DFSResult[i]<<" ";
cout<<endl;
cout<<"The discovered time and finished time respectivly is:"<<endl;
for(int i=0; i<G.Vnum; i++)
cout<<G.HeadVertex[i].key<<setw(4)<<G.HeadVertex[i].d<<setw(4)<<G.HeadVertex[i].f<<endl;
cout<<"The Edge type information is:"<<endl;
EdgeType_Print(G);
cout<<"--------------------------------------------"<<endl;
return 0;
}
运行结果:
【注:若有错误,请指正~~~】