广度优先搜索C语言算法

Python010

广度优先搜索C语言算法,第1张

它没有固定的写法, 但是大框都差不多, 一定要使用队列, 因为队列的存在可以维护程序按照广度优先的方式进行搜索。即层次遍历

可以给你一份我作过的一个题的代码,大体上就是这个样子

/****************************************************\

*

* Title : Rescue

* From : HDU 1242

* AC Time : 2012.01.12

* Type : 广度优先搜索求最短步数

* Method :从目标结点向回搜索,初始结点有多个

*

\****************************************************/

#include <stdio.h>

#include <string.h>

#define DATASIZE 201

#define QUEUESIZE 65536

typedef struct

{

int x,y

}CPOINT

int bfs(char map[][DATASIZE], int n, int m, CPOINT cpa)

int direction[][2] = {{1,0},{-1,0},{0,1},{0,-1}}

int main(void)

{

int m,n,i,j,res

CPOINT cpa

char map[DATASIZE][DATASIZE]

freopen("c:\\in.data","r",stdin)

while(scanf("%d%d%*c",&n,&m) != EOF) {

for(i = 0 i <n i++) {

gets(map[i])

for(j = 0 j <m j++) {

if(map[i][j] == 'a') {

cpa.x = i

cpa.y = j

}

}

}

res = bfs(map, n, m, cpa)

if(res) {

printf("%d\n",res)

} else {

printf("Poor ANGEL has to stay in the prison all his life.\n")

}

}

return 0

}

int bfs(char map[][DATASIZE], int n, int m, CPOINT cpa)

{

CPOINT q[QUEUESIZE],u,np

int vis[DATASIZE][DATASIZE],step[DATASIZE][DATASIZE],i,front,rear,res

memset(q, 0, sizeof(q))

memset(vis, 0, sizeof(vis))

memset(step, 0, sizeof(step))

front = rear = res = 0

q[rear++] = cpa

vis[cpa.x][cpa.y] = 1

step[cpa.x][cpa.y] = 0

while(front <= rear) {

u = q[front++]

if(map[u.x][u.y] == 'r') {

res = step[u.x][u.y]

break

}

for(i = 0 i <4i++) {

np.x = u.x + direction[i][0]

np.y = u.y + direction[i][1]

if(np.x >= 0 &&np.x <n &&np.y >= 0 &&np.y <m &&!vis[np.x][np.y] &&map[np.x][np.y] != '#' ) {

vis[np.x][np.y] = 1

q[rear++] = np

step[np.x][np.y] = step[u.x][u.y] + 1

if(map[np.x][np.y] == 'x') {

++step[np.x][np.y]

}

}

}

}

return res

}

/*深度优先*/

#include<stdio.h>

#include<stdlib.h>

struct node/*图的顶点结构*/

{

int vertex

int flag

struct node *nextnode

}

typedef struct node *graph

struct node vertex_node[10]

void creat_graph(int *node,int n)

{

graph newnode,p/*定义一个新结点及指针*/

int start,end,i

for(i=0i<ni++)

{

start=node[i*2]/*边的起点*/

end=node[i*2+1]/*边的终点*/

newnode=(graph)malloc(sizeof(struct node))

newnode->vertex=end/*新结点的内容为边终点处顶点的内容*/

newnode->nextnode=NULL

p=&(vertex_node[start])/*设置指针位置*/

while(p->nextnode!=NULL)

p=p->nextnode/*寻找链尾*/

p->nextnode=newnode/*在链尾处插入新结点*/

}

}

void dfs(int k)

{

graph p

vertex_node[k].flag=1/*将标志位置1,证明该结点已访问过*/

printf("vertex[%d]",k)

p=vertex_node[k].nextnode/*指针指向下个结点*/

while(p!=NULL)

{

if(vertex_node[p->vertex].flag==0)/*判断该结点的标志位是否为0*/

dfs(p->vertex)/*继续遍历下个结点*/

p=p->nextnode/*若已遍历过p指向下一个结点*/

}

}

main()

{

graph p

int node[100],i,sn,vn

printf("please input the number of sides:\n")

scanf("%d",&sn)/*输入无向图的边数*/

printf("please input the number of vertexes\n")

scanf("%d",&vn)

printf("please input the vertexes which connected by the sides:\n")

for(i=0i<4*sni++)

scanf("%d",&node[i])/*输入每个边所连接的两个顶点,起始及结束位置不同,每边输两次*/

for(i=1i<=vni++)

{

vertex_node[i].vertex=i/*将每个顶点的信息存入数组中*/

vertex_node[i].nextnode=NULL

}

creat_graph(node,2*sn)/*调用函数创建邻接表*/

printf("the result is:\n")

for(i=1i<=vni++)/*将邻接表内容输出*/

{

printf("vertex%d:",vertex_node[i].vertex)/*输出顶点内容*/

p=vertex_node[i].nextnode

while(p!=NULL)

{

printf("->%3d",p->vertex)/*输出邻接顶点的内容*/

p=p->nextnode/*指针指向下个邻接顶点*/

}

printf("\n")

}

printf("the result of depth-first search is:\n")

dfs(1)/*调用函数进行深度优先遍历*/

printf("\n")

}

/***************************广度优先*******************************/

#include <stdio.h>

#include <stdlib.h>

struct node

{

int vertex

struct node *nextnode

}

typedef struct node *graph

struct node vertex_node[10]

#define MAXQUEUE 100

int queue[MAXQUEUE]

int front = - 1

int rear = - 1

int visited[10]

void creat_graph(int *node, int n)

{

graph newnode, p/*定义一个新结点及指针*/

int start, end, i

for (i = 0i <ni++)

{

start = node[i *2]/*边的起点*/

end = node[i *2+1]/*边的终点*/

newnode = (graph)malloc(sizeof(struct node))

newnode->vertex = end/*新结点的内容为边终点处顶点的内容*/

newnode->nextnode = NULL

p = &(vertex_node[start])/*设置指针位置*/

while (p->nextnode != NULL)

p = p->nextnode

/*寻找链尾*/

p->nextnode = newnode/*在链尾处插入新结点*/

}

}

int enqueue(int value) /*元素入队列*/

{

if (rear >= MAXQUEUE)

return - 1

rear++/*移动队尾指针*/

queue[rear] = value

}

int dequeue() /*元素出队列*/

{

if (front == rear)

return - 1

front++/*移动队头指针*/

return queue[front]

}

void bfs(int k) /*广度优先搜索*/

{

graph p

enqueue(k)/*元素入队*/

visited[k] = 1

printf("vertex[%d]", k)

while (front != rear)

/*判断是否对空*/

{

k = dequeue()/*元素出队*/

p = vertex_node[k].nextnode

while (p != NULL)

{

if (visited[p->vertex] == 0)

/*判断其是否被访问过*/

{

enqueue(p->vertex)

visited[p->vertex] = 1/*访问过的元素置1*/

printf("vertex[%d]", p->vertex)

}

p = p->nextnode/*访问下一个元素*/

}

}

}

main()

{

graph p

int node[100], i, sn, vn

printf("please input the number of sides:\n")

scanf("%d", &sn)/*输入无向图的边数*/

printf("please input the number of vertexes\n")

scanf("%d", &vn)

printf("please input the vertexes which connected by the sides:\n")

for (i = 0i <4 *sni++)

scanf("%d", &node[i])

/*输入每个边所连接的两个顶点,起始及结束位置不同,每边输两次*/

for (i = 1i <= vni++)

{

vertex_node[i].vertex = i/*将每个顶点的信息存入数组中*/

vertex_node[i].nextnode = NULL

}

creat_graph(node, 2 *sn)/*调用函数创建邻接表*/

printf("the result is:\n")

for (i = 1i <= vni++)

/*将邻接表内容输出*/

{

printf("vertex%d:", vertex_node[i].vertex)/*输出顶点内容*/

p = vertex_node[i].nextnode

while (p != NULL)

{

printf("->%3d", p->vertex)/*输出邻接顶点的内容*/

p = p->nextnode/*指针指向下个邻接顶点*/

}

printf("\n")

}

printf("the result of breadth-first search is:\n")

bfs(1)/*调用函数进行深度优先遍历*/

printf("\n")

}

// bo7-2.cpp 图的邻接表存储(存储结构由c7-2.h定义)的基本操作(15个)

int LocateVex(ALGraph G,VertexType u)

{ // 初始条件: 图G存在,u和G中顶点有相同特征

// 操作结果: 若G中存在顶点u,则返回该顶点在图中位置否则返回-1

int i

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

if(strcmp(u,G.vertices[i].data)==0)

return i

return -1

}

Status CreateGraph(ALGraph &G)

{ // 采用邻接表存储结构,构造没有相关信息的图G(用一个函数构造4种图)

int i,j,k

int w// 权值

VertexType va,vb

ArcNode *p

printf("请输入图的类型(有向图:0,有向网:1,无向图:2,无向网:3): ")

scanf("%d",&G.kind)

printf("请输入图的顶点数,边数: ")

scanf("%d,%d",&G.vexnum,&G.arcnum)

printf("请输入%d个顶点的值(<%d个字符):\n",G.vexnum,MAX_NAME)

for(i=0i<G.vexnum++i) // 构造顶点向量

{

scanf("%s",G.vertices[i].data)

G.vertices[i].firstarc=NULL

}

if(G.kind==1||G.kind==3) // 网

printf("请顺序输入每条弧(边)的权值、弧尾和弧头(以空格作为间隔):\n")

else // 图

printf("请顺序输入每条弧(边)的弧尾和弧头(以空格作为间隔):\n")

for(k=0k<G.arcnum++k) // 构造表结点链表

{

if(G.kind==1||G.kind==3) // 网

scanf("%d%s%s",&w,va,vb)

else // 图

scanf("%s%s",va,vb)

i=LocateVex(G,va)// 弧尾

j=LocateVex(G,vb)// 弧头

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

p->adjvex=j

if(G.kind==1||G.kind==3) // 网

{

p->info=(int *)malloc(sizeof(int))

*(p->info)=w

}

else

p->info=NULL// 图

p->nextarc=G.vertices[i].firstarc// 插在表头

G.vertices[i].firstarc=p

if(G.kind>=2) // 无向图或网,产生第二个表结点

{

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

p->adjvex=i

if(G.kind==3) // 无向网

{

p->info=(int*)malloc(sizeof(int))

*(p->info)=w

}

else

p->info=NULL// 无向图

p->nextarc=G.vertices[j].firstarc// 插在表头

G.vertices[j].firstarc=p

}

}

return OK

}

void DestroyGraph(ALGraph &G)

{ // 初始条件: 图G存在。操作结果: 销毁图G

int i

ArcNode *p,*q

G.vexnum=0

G.arcnum=0

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

{

p=G.vertices[i].firstarc

while(p)

{

q=p->nextarc

if(G.kind%2) // 网

free(p->info)

free(p)

p=q

}

}

}

VertexType&GetVex(ALGraph G,int v)

{ // 初始条件: 图G存在,v是G中某个顶点的序号。操作结果: 返回v的值

if(v>=G.vexnum||v<0)

exit(ERROR)

return G.vertices[v].data

}

Status PutVex(ALGraph &G,VertexType v,VertexType value)

{ // 初始条件: 图G存在,v是G中某个顶点

// 操作结果: 对v赋新值value

int i

i=LocateVex(G,v)

if(i>-1) // v是G的顶点

{

strcpy(G.vertices[i].data,value)

return OK

}

return ERROR

}

int FirstAdjVex(ALGraph G,VertexType v)

{ // 初始条件: 图G存在,v是G中某个顶点

// 操作结果: 返回v的第一个邻接顶点的序号。若顶点在G中没有邻接顶点,则返回-1

ArcNode *p

int v1

v1=LocateVex(G,v)// v1为顶点v在图G中的序号

p=G.vertices[v1].firstarc

if(p)

return p->adjvex

else

return -1

}

int NextAdjVex(ALGraph G,VertexType v,VertexType w)

{ // 初始条件: 图G存在,v是G中某个顶点,w是v的邻接顶点

// 操作结果: 返回v的(相对于w的)下一个邻接顶点的序号。

// 若w是v的最后一个邻接点,则返回-1

ArcNode *p

int v1,w1

v1=LocateVex(G,v)// v1为顶点v在图G中的序号

w1=LocateVex(G,w)// w1为顶点w在图G中的序号

p=G.vertices[v1].firstarc

while(p&&p->adjvex!=w1) // 指针p不空且所指表结点不是w

p=p->nextarc

if(!p||!p->nextarc) // 没找到w或w是最后一个邻接点

return -1

else // p->adjvex==w

return p->nextarc->adjvex// 返回v的(相对于w的)下一个邻接顶点的序号

}

void InsertVex(ALGraph &G,VertexType v)

{ // 初始条件: 图G存在,v和图中顶点有相同特征

// 操作结果: 在图G中增添新顶点v(不增添与顶点相关的弧,留待InsertArc()去做)

strcpy(G.vertices[G.vexnum].data,v)// 构造新顶点向量

G.vertices[G.vexnum].firstarc=NULL

G.vexnum++// 图G的顶点数加1

}

Status DeleteVex(ALGraph &G,VertexType v)

{ // 初始条件: 图G存在,v是G中某个顶点

// 操作结果: 删除G中顶点v及其相关的弧

int i,j

ArcNode *p,*q

j=LocateVex(G,v)// j是顶点v的序号

if(j<0) // v不是图G的顶点

return ERROR

p=G.vertices[j].firstarc// 删除以v为出度的弧或边

while(p)

{

q=p

p=p->nextarc

if(G.kind%2) // 网

free(q->info)

free(q)

G.arcnum--// 弧或边数减1

}

G.vexnum--// 顶点数减1

for(i=ji<G.vexnumi++) // 顶点v后面的顶点前移

G.vertices[i]=G.vertices[i+1]

for(i=0i<G.vexnumi++) // 删除以v为入度的弧或边且必要时修改表结点的顶点位置值

{

p=G.vertices[i].firstarc// 指向第1条弧或边

while(p) // 有弧

{

if(p->adjvex==j)

{

if(p==G.vertices[i].firstarc) // 待删结点是第1个结点

{

G.vertices[i].firstarc=p->nextarc

if(G.kind%2) // 网

free(p->info)

free(p)

p=G.vertices[i].firstarc

if(G.kind<2) // 有向

G.arcnum--// 弧或边数减1

}

else

{

q->nextarc=p->nextarc

if(G.kind%2) // 网

free(p->info)

free(p)

p=q->nextarc

if(G.kind<2) // 有向

G.arcnum--// 弧或边数减1

}

}

else

{

if(p->adjvex>j)

p->adjvex--// 修改表结点的顶点位置值(序号)

q=p

p=p->nextarc

}

}

}

return OK

}

Status InsertArc(ALGraph &G,VertexType v,VertexType w)

{ // 初始条件: 图G存在,v和w是G中两个顶点

// 操作结果: 在G中增添弧<v,w>,若G是无向的,则还增添对称弧<w,v>

ArcNode *p

int w1,i,j

i=LocateVex(G,v)// 弧尾或边的序号

j=LocateVex(G,w)// 弧头或边的序号

if(i<0||j<0)

return ERROR

G.arcnum++// 图G的弧或边的数目加1

if(G.kind%2) // 网

{

printf("请输入弧(边)%s→%s的权值: ",v,w)

scanf("%d",&w1)

}

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

p->adjvex=j

if(G.kind%2) // 网

{

p->info=(int*)malloc(sizeof(int))

*(p->info)=w1

}

else

p->info=NULL

p->nextarc=G.vertices[i].firstarc// 插在表头

G.vertices[i].firstarc=p

if(G.kind>=2) // 无向,生成另一个表结点

{

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

p->adjvex=i

if(G.kind==3) // 无向网

{

p->info=(int*)malloc(sizeof(int))

*(p->info)=w1

}

else

p->info=NULL

p->nextarc=G.vertices[j].firstarc// 插在表头

G.vertices[j].firstarc=p

}

return OK

}

Status DeleteArc(ALGraph &G,VertexType v,VertexType w)

{ // 初始条件: 图G存在,v和w是G中两个顶点

// 操作结果: 在G中删除弧<v,w>,若G是无向的,则还删除对称弧<w,v>

ArcNode *p,*q

int i,j

i=LocateVex(G,v)// i是顶点v(弧尾)的序号

j=LocateVex(G,w)// j是顶点w(弧头)的序号

if(i<0||j<0||i==j)

return ERROR

p=G.vertices[i].firstarc// p指向顶点v的第一条出弧

while(p&&p->adjvex!=j) // p不空且所指之弧不是待删除弧<v,w>

{ // p指向下一条弧

q=p

p=p->nextarc

}

if(p&&p->adjvex==j) // 找到弧<v,w>

{

if(p==G.vertices[i].firstarc) // p所指是第1条弧

G.vertices[i].firstarc=p->nextarc// 指向下一条弧

else

q->nextarc=p->nextarc// 指向下一条弧

if(G.kind%2) // 网

free(p->info)

free(p)// 释放此结点

G.arcnum--// 弧或边数减1

}

if(G.kind>=2) // 无向,删除对称弧<w,v>

{

p=G.vertices[j].firstarc// p指向顶点w的第一条出弧

while(p&&p->adjvex!=i) // p不空且所指之弧不是待删除弧<w,v>

{ // p指向下一条弧

q=p

p=p->nextarc

}

if(p&&p->adjvex==i) // 找到弧<w,v>

{

if(p==G.vertices[j].firstarc) // p所指是第1条弧

G.vertices[j].firstarc=p->nextarc// 指向下一条弧

else

q->nextarc=p->nextarc// 指向下一条弧

if(G.kind==3) // 无向网

free(p->info)

free(p)// 释放此结点

}

}

return OK

}

Boolean visited[MAX_VERTEX_NUM]// 访问标志数组(全局量)

void(*VisitFunc)(char* v)// 函数变量(全局量)

void DFS(ALGraph G,int v)

{ // 从第v个顶点出发递归地深度优先遍历图G。算法7.5

int w

VertexType v1,w1

strcpy(v1,GetVex(G,v))

visited[v]=TRUE// 设置访问标志为TRUE(已访问)

VisitFunc(G.vertices[v].data)// 访问第v个顶点

for(w=FirstAdjVex(G,v1)w>=0w=NextAdjVex(G,v1,strcpy(w1,GetVex(G,w))))

if(!visited[w])

DFS(G,w)// 对v的尚未访问的邻接点w递归调用DFS

}

void DFSTraverse(ALGraph G,void(*Visit)(char*))

{ // 对图G作深度优先遍历。算法7.4

int v

VisitFunc=Visit// 使用全局变量VisitFunc,使DFS不必设函数指针参数

for(v=0v<G.vexnumv++)

visited[v]=FALSE// 访问标志数组初始化

for(v=0v<G.vexnumv++)

if(!visited[v])

DFS(G,v)// 对尚未访问的顶点调用DFS

printf("\n")

}

typedef int QElemType// 队列类型

#include"c3-2.h"

#include"bo3-2.cpp"

void BFSTraverse(ALGraph G,void(*Visit)(char*))

{//按广度优先非递归遍历图G。使用辅助队列Q和访问标志数组visited。算法7.6

int v,u,w

VertexType u1,w1

LinkQueue Q

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

visited[v]=FALSE// 置初值

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

for(v=0v<G.vexnumv++) // 如果是连通图,只v=0就遍历全图

if(!visited[v]) // v尚未访问

{

visited[v]=TRUE

Visit(G.vertices[v].data)

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

while(!QueueEmpty(Q)) // 队列不空

{

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

strcpy(u1,GetVex(G,u))

for(w=FirstAdjVex(G,u1)w>=0w=NextAdjVex(G,u1,strcpy(w1,GetVex(G,w))))

if(!visited[w]) // w为u的尚未访问的邻接顶点

{

visited[w]=TRUE

Visit(G.vertices[w].data)

EnQueue(Q,w)// w入队

}

}

}

printf("\n")

}

void Display(ALGraph G)

{ // 输出图的邻接矩阵G

int i

ArcNode *p

switch(G.kind)

{

case DG: printf("有向图\n")

break

case DN: printf("有向网\n")

break

case AG: printf("无向图\n")

break

case AN: printf("无向网\n")

}

printf("%d个顶点:\n",G.vexnum)

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

printf("%s ",G.vertices[i].data)

printf("\n%d条弧(边):\n",G.arcnum)

for(i=0i<G.vexnumi++)

{

p=G.vertices[i].firstarc

while(p)

{

if(G.kind<=1) // 有向

{

printf("%s→%s ",G.vertices[i].data,G.vertices[p->adjvex].data)

if(G.kind==DN) // 网

printf(":%d ",*(p->info))

}

else // 无向(避免输出两次)

{

if(i<p->adjvex)

{

printf("%s-%s ",G.vertices[i].data,G.vertices[p->adjvex].data)

if(G.kind==AN) // 网

printf(":%d ",*(p->info))

}

}

p=p->nextarc

}

printf("\n")

}

}

// c7-2.h 图的邻接表存储表示

#define MAX_VERTEX_NUM 20

enum GraphKind{DG,DN,AG,AN}// {有向图,有向网,无向图,无向网}

struct ArcNode

{

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

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

InfoType *info// 网的权值指针

}// 表结点

typedef struct

{

VertexType data// 顶点信息

ArcNode *firstarc// 第一个表结点的地址,指向第一条依附该顶点的弧的指针

}VNode,AdjList[MAX_VERTEX_NUM]// 头结点

struct ALGraph

{

AdjList vertices

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

int kind// 图的种类标志

}

// c3-2.h 单链队列--队列的链式存储结构

typedef struct QNode

{

QElemType data

QNode *next

}*QueuePtr

struct LinkQueue

{

QueuePtr front,rear// 队头、队尾指针

}

// bo3-2.cpp 链队列(存储结构由c3-2.h定义)的基本操作(9个)

Status InitQueue(LinkQueue &Q)

{ // 构造一个空队列Q

if(!(Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode))))

exit(OVERFLOW)

Q.front->next=NULL

return OK

}

Status DestroyQueue(LinkQueue &Q)

{ // 销毁队列Q(无论空否均可)

while(Q.front)

{

Q.rear=Q.front->next

free(Q.front)

Q.front=Q.rear

}

return OK

}

Status ClearQueue(LinkQueue &Q)

{ // 将Q清为空队列

QueuePtr p,q

Q.rear=Q.front

p=Q.front->next

Q.front->next=NULL

while(p)

{

q=p

p=p->next

free(q)

}

return OK

}

Status QueueEmpty(LinkQueue Q)

{ // 若Q为空队列,则返回TRUE,否则返回FALSE

if(Q.front==Q.rear)

return TRUE

else

return FALSE

}

int QueueLength(LinkQueue Q)

{ // 求队列的长度

int i=0

QueuePtr p

p=Q.front

while(Q.rear!=p)

{

i++

p=p->next

}

return i

}

Status GetHead(LinkQueue Q,QElemType &e)

{ // 若队列不空,则用e返回Q的队头元素,并返回OK,否则返回ERROR

QueuePtr p

if(Q.front==Q.rear)

return ERROR

p=Q.front->next

e=p->data

return OK

}

Status EnQueue(LinkQueue &Q,QElemType e)

{ // 插入元素e为Q的新的队尾元素

QueuePtr p

if(!(p=(QueuePtr)malloc(sizeof(QNode)))) // 存储分配失败

exit(OVERFLOW)

p->data=e

p->next=NULL

Q.rear->next=p

Q.rear=p

return OK

}

Status DeQueue(LinkQueue &Q,QElemType &e)

{ // 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR

QueuePtr p

if(Q.front==Q.rear)

return ERROR

p=Q.front->next

e=p->data

Q.front->next=p->next

if(Q.rear==p)

Q.rear=Q.front

free(p)

return OK

}

Status QueueTraverse(LinkQueue Q,void(*vi)(QElemType))

{ // 从队头到队尾依次对队列Q中每个元素调用函数vi()。一旦vi失败,则操作失败

QueuePtr p

p=Q.front->next

while(p)

{

vi(p->data)

p=p->next

}

printf("\n")

return OK

}