您的位置:首页 > 编程语言 > C语言/C++

C/C++代码实现图(有向图)的深度,广度优先遍历

2013-11-02 22:05 936 查看
<一>深度优先搜索(Depth-First Search—DFS)是指按照深度方向搜索,它类似于树的先根遍历,是树的先根遍历的推广。 

深度优先搜索图的基本思想是:

假设图G初态为所有顶点未被访问(visited[i]=false),从G中任选一顶点vi :

⑴、从该顶点vi出发,首先访问vi,并置visited [vi ]=true;

⑵、然后依次搜索vi的每一个邻接点vj ;

⑶、若vj未被访问过,则以vj为新的初始出发点,重复⑴

若vj已被访问过,则返回到vi另一个邻接点,重复⑶

⑷、如果经过⑴、⑵、⑶后,图中仍有未被访问的顶点,再从中任选一顶点,重复⑴、⑵、⑶,直至所有顶点都被访问过,遍历结束。









<二>广度优先搜索遍历图(树的层次遍历的推广)

1. 从图中某顶点v出发,在访问v之后,

2. 依次访问v的各个未曾被访问过的邻接点,

3. 然后分别从这些邻接点出发依次访问它们的邻接点,并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问,直至图中所有已经被访问的顶点的邻接点都被访问到;

4. 若图中尚有顶点未曾被访问,则另选图中一个未曾被访问的顶点作起始点,访问该顶点,继续过程2、3,直至图中所有顶点都被访问到为止。

(1)为避免重复访问, 需要一个辅助数组 visited[ n],给被访问过的顶点加标记。

(2)为了实现逐层(按顶点的路径长度递增)访问, 算法中需使用了一个队列,以记忆正在访问的这一层和下一层的顶点,以便于向下一层访问。
















代码如下:

#include<iostream.h>

#include<malloc.h>

#define MAX_VERTEX_NUM 20

typedef int InfoType;

typedef int VertexType;

typedef enum{DG,DN,UDG,UDN}GraphKind;

# define MAXQSIZE 100

typedef int QElemType ;//队列

typedef struct//队列

{

QElemType *base; // 动态分配存储空间

int front; // 头指针,指向队列头元素

int rear; // 尾指针,指向 队列尾元素的下一个位置

}SqQueue;

typedef struct ArcNode//图

{

int adjex;//该弧所指向的顶点的位置

struct ArcNode *nextarc;//指向下一条弧的指针

InfoType *info;//该弧相关信息的指针

}ArcNode;

typedef struct VNode

{

VertexType data;//顶点信息

ArcNode *firstarc;//指向第一条依附该顶点的弧的指针

}VNode,AdjList[MAX_VERTEX_NUM];

typedef struct

{

AdjList vertices;//顶点

int vexnum,arcnum;//图的当前顶点数和弧数

GraphKind kind;//图的种类标志

}ALGraph;

int LocateVex(ALGraph G, int v)//确定v在G中位置,即顶点在G.vertices中的序号

{

int i;

for(i=0;i<G.vexnum;i++)

{

if (G.vertices[i].data==v) return i;

}

return -1;

}

// ###################生成图G的存储结构-邻接表###############################################

void CreateGraph(ALGraph &G)

{

int k,sv,tv,i,j;

cout<<"请输入图的顶点数(eg:5)";

cin>>G.vexnum;

cout<<"请输入图的弧数(eg:6)";

cin>>G.arcnum;

// cout<<"请输入图的类型(eg:)";

// cin>>G.kind;// 输入顶点数、边数和图类:1

for(k=0;k<G.vexnum;k++)// 构造顶点数组:2

{

cout<<"请输入图的顶点信息";

cin>>G.vertices[k].data;// 输入顶点

G.vertices[k].firstarc=NULL;//初始化链表头指针为"空"

}

cout<<"请输入该图的弧(v1-->v2),例如:(v1=1,v2=3),(v1=2,v2=4)"<<endl;

for(k=0;k<G.arcnum;k++)// 输入各边并构造邻接表: 3

{

cout<<"请输入第"<<k+1<<"条弧的始点信息sv(0<sv<G.vexnum)";

cin>>sv;

cout<<"请输入第"<<k+1<<"条弧的终点信息tv(0<tv<G.vexnum)";

cin>>tv;// 输入一条边(弧)的始点和终点

cout<<endl<<endl;

i = LocateVex(G, sv);

j = LocateVex(G, tv); // (比较)确定sv和tv在G中位置,即顶点在G.vertices中的序号

while((i<0||i>=G.vexnum)||(j<0||j>=G.vexnum)) //if (sv,tv) illegal,again

{

cout<<"请输入第"<<k+1<<"条弧的始点信息sv(0<sv<G.vexnum)";

cin>>sv;

cout<<"请输入第"<<k+1<<"条弧的终点信息tv(0<tv<G.vexnum)";

cin>>tv;

cout<<endl<<endl;

i = LocateVex(G, sv);

j = LocateVex(G, tv); // (比较)确定sv和tv在G中位置,即顶点在G.vertices中的序号

} //while end

ArcNode *p;

p=(ArcNode*)malloc(sizeof(ArcNode));

if(!p)

{

cout<<"Overflow!"; // 存储分配失败

return ;

}

p->adjex=j;// 对弧结点赋邻接点"位置“

p->nextarc=G.vertices[i].firstarc;//头插法,将tv结点插入到第i个单链表中

p->info=NULL;

G.vertices[i].firstarc=p;// 插入链表G.vertices[i]

}

}

//################有向表的深度优先遍历#####################################################################

void DFS(ALGraph G,int v,int visited[])

{

int w;

ArcNode *p;

cout<<G.vertices[v].data<<"->";//访问第v+1个顶点;

visited[v]=1;

p=G.vertices[v].firstarc;

if(p!=NULL)

w=p->adjex;//w是v的下一个邻接点的位置,即第v+1个顶点的下一个顶点是第w+1个顶点;

if (p!=NULL)//如果有邻接点w

{

if(visited[w]==0)//如果w没访问过

{

DFS(G,w,visited);

}

else//若访问过,则访问v的下一个邻接点,并返回至判断是否存在该邻接点

{

p=p->nextarc;//G.vertices[v].firstarc=G.vertices[v].firstarc->nextarc;

if(p!=NULL) w=p->adjex;//w=G.vertices[v].firstarc->adjex;

}

}

}

void DFSTraverse(ALGraph G)

{

int v,visted[MAX_VERTEX_NUM];

for (v=0;v<G.vexnum;v++)

{

visted[v]=0;

}

for (v=0;v<G.vexnum;v++)

{

if(visted[v]==0)

DFS(G,v,visted);

}

}

//#############广度优先搜索遍历######################################################################

//~~~~~~~~~~~~辅助队列~~~~~~~~~~~~~~~~~~~~~~~~~

int InitQueue (SqQueue &Q)// 构造一个空队列Q

{

Q.base=(QElemType*)malloc(MAXQSIZE*sizeof(QElemType));

if(!Q.base)

{

cout<<endl<<"Overflow ! "; // 存储分配失败

return 0;

}

Q.front=Q.rear=0;

return 1;

}

int EnQueue(SqQueue &Q,QElemType e)// 插入元素e为Q的新的队尾元素

{

if ((Q.rear+1)%MAXQSIZE==Q.front)//①判满

{

cout<<"Error ! The SqQeueu is full ! ";

return 0;

}

Q.base[Q.rear]=e;// ②插入队尾

Q.rear=(Q.rear+1)%MAXQSIZE;//③队尾指针后移

return 1;

}

int DeQueue(SqQueue &Q,QElemType &e)// 若队列不空,则删除Q的队头元素,用e返回其值,并返回OK; 否则返回ERROR

{

if (Q.rear==Q.front)

{

cout<<endl<<"Error ! It's empty!";

return 0;

}

e=Q.base[Q.front];

Q.front=(Q.front+1)%MAXQSIZE;

return(e);

}

int QueueEmpty(SqQueue Q)

{

if(Q.front==Q.rear)

return (1);

else

return (0);

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

void BFS(ALGraph G,int v,int visited[],SqQueue &Q)

{

int u,w;

ArcNode *p;

cout<<G.vertices[v].data<<"->";//访问第v+1个顶点;

visited[v]=1;

EnQueue(Q,v);// v入队列

while (!QueueEmpty(Q))

{

DeQueue(Q,u);// 队头元素出队并置为u

p=G.vertices[v].firstarc;

if(p!=NULL)

w=p->adjex;

for (;p!=NULL;)

{

if (visited[w]==0)

{

cout<<G.vertices[w].data<<"->";

visited[w]=1;

EnQueue(Q, w); // 访问的顶点w入队列

}

p=p->nextarc;

if (p!=NULL)

w=p->adjex;

}

}

}

void BFSTraverse(ALGraph G)

{

SqQueue Q;

int v,visted[MAX_VERTEX_NUM];

for (v=0;v<G.vexnum;v++)

{

visted[v]=0;//初始化访问标志

}

InitQueue(Q);// 置空的辅助队列Q

for ( v=0; v<G.vexnum; ++v )

{

if(visted[v]==0)// v 尚未访问

BFS(G,v,visted,Q);// 调用BFS()

}

}

//###############main函数#################

void main()

{

ALGraph G;

CreateGraph(G);

cout<<"深度优先遍历如下:"<<endl;

DFSTraverse(G);

cout<<"End !"<<endl<<endl<<"...OK!...";

cout<<endl<<endl<<"广度优先遍历如下:"<<endl;

BFSTraverse(G);

cout<<"End !"<<endl<<endl<<"...OK!...";

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: