无向图深度优先遍历(DFS)和广度优先遍历(BFS)算法
定义
深度优先遍历
(1)从图中某个初始顶点v出发,首先访问初始顶点v。
(2)选择一个与顶点v相邻且没被访问过的顶点w,再从w出发进行深度优先搜索,直到图中与当前顶点v邻接的所有顶点都被访问过为止。
(3) 利用递归实现,简单但是不好理解,时间复杂度 O(n+e)。
广度优先遍历
(1)访问初始点v,接着访问v的所有未被访问过的邻接点v1,v2,…,vt。
(2)按照v1,v2,…,vt的次序,访问每一个顶点的所有未被访问过的邻接点。
(3)依次类推,直到图中所有和初始点v有路径相通的顶点都被访问过为止。
(4) 利用队列实现, 时间复杂度 O(n+e).
实现代码
深度优先遍历算法
//深度优先遍历算法
void DFS(AdjGraph *G, int v)
{
ArcNode *p;
visited[v] = 1;
printf("%d ", v);
p = G->adjlist[v].firstarc;
while(p != NULL) //p == NULL is the break of circle
{
if(visited[p->adjvex] == 0)
DFS(G, p->adjvex);
p=p->nextarc;
}
}
广度优先遍历算法
//广度优先遍历算法
void BFS(AdjGraph *G, int v)
{
int w, i;
ArcNode *p;
SqQueue *qu;
InitQueue(qu);
int visited[MAXV];
for(i = 0; i < G->n; i++)
visited[i] = 0;
printf("%2d",v);
visited[v] = 1;
enQueue(qu, v);
while( !QueueEmpty(qu))
{
deQueue(qu, w);
p = G->adjlist[w].firstarc;
while(p!=NULL)
{
if(visited[p->adjvex] == 0)
{
printf("%2d", p->adjvex);
visited[p->adjvex] = 1;
enQueue(qu, p->adjvex);
}
p = p->nextarc;
}
}
printf("\n");
}
注意理解
- 注意,DFS是基于递归形式的, 主要是往深入的方向去遍历。 每次碰到可以读取输出的顶点就直接输出,并且将其视作是头节点数组,接着向它的下一个进行读取。
- BFS则比较憨厚,他是直接在一个头节点数组走到黑,一直到读取NULL才肯回头。这时候,需要利用队列来保存被它错过的路口,给他提供后悔药。回头时队列出栈,出一颗后悔药给他吃,让它接着往下一个方向一直走。一直等到它把后悔药都吃完,然后就遍历结束了。
全部代码
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#define ElemType int
#define maxsize 100
#define InfoType int
#define MAXV 100
#define MaxSize 100
#define INF 214748364
#define INFINITE INF
/////////////////////////////////////////////////
//邻接表的结构体定义
typedef struct ANode
{
int adjvex; //该边的邻接点的编号,即有向边指向的顶点编号
struct ANode *nextarc; //指向下一条边的指针
int weight; //边的相关的信息,如权值
} ArcNode; //边节点的类型
typedef struct Vnode
{
InfoType info; //顶点的其他信息
int count; //存放顶点入度
ArcNode *firstarc; //指向第一个边节点
} VNode; //邻接表的头节点的结构体类型
typedef struct
{
VNode adjlist[MAXV]; //头节点的数组
int n, e; //图的顶点数和边数
} AdjGraph; //整个邻接表的数据结构体类型
//////////////////////////////////////////////////
//邻接矩阵的结构体
typedef struct S
{
int no; //顶点的编号
InfoType info; //顶点的其他信息
} VertexType; //顶点的类型
typedef struct SS
{
int edges[MAXV][MAXV]; //邻接矩阵的数组
int n, e; //图的顶点数和边数
VertexType vexs[MAXV]; //存放顶点信息
} MatGraph;
///////////////////////////////////////////////////
typedef struct SSS
{
ElemType data[maxsize];
int front;
int rear;
} SqQueue; //队列的结构体
////////////////////////////////
//Kruskal算法需要的简化图的结构体
typedef struct head
{
int u; //边的起始顶点
int v; //边的终止顶点
int w; //边的权值
} Edge;
///////////////////////////////
///零零零零啦啦啦啦啦
int visited[MAXV] = {0};
///////////////////////////////
//队列的操作函数集合
//由于队列的函数在另一个文件
//所以需要声明一下
void InitQueue(SqQueue *&q);
void DestoryQueue(SqQueue *&q);
bool QueueEmpty(SqQueue *q);
bool enQueue(SqQueue *&q, ElemType e);
bool deQueue(SqQueue *&q, ElemType &e);
/////////////////////////////////////////////////////////////////
//后序遍历需要的一些队列的基本函数
void InitQueue(SqQueue *&q)
{
q = (SqQueue *)malloc(sizeof(SqQueue));
q->front = q->rear = 0;
}
void DestoryQueue(SqQueue *&q)
{
free(q);
}
bool QueueEmpty(SqQueue *q)
{
return (q->front == q->rear);
}
bool enQueue(SqQueue *&q, ElemType e)
{
if ((q->rear + 1) % maxsize == q->front)
return false;
q->rear = (q->rear + 1) % maxsize;
q->data[q->rear] = e;
return true;
}
bool deQueue(SqQueue *&q, ElemType &e)
{
if (q->front == q->rear)
return false;
q->front = (q->front + 1) % maxsize;
e = q->data[q->front];
return true;
}
/////////////////////////////////////////////
void CreateAdj(AdjGraph *&G, int A[MAXV][MAXV], int n, int e)
{
int i, j;
ArcNode *p;
G = (AdjGraph *)malloc(sizeof(AdjGraph));
for (i = 0; i < n; i++)
G->adjlist[i].firstarc = NULL;
for (i = 0; i < n; i++)
for (j = n - 1; j >= 0; j--)
if (A[i][j] != 0 && A[i][j] != INF)
{
p = (ArcNode *)malloc(sizeof(ArcNode));
p->adjvex = j;
p->weight = A[i][j];
p->nextarc = G->adjlist[i].firstarc;
G->adjlist[i].firstarc = p;
}
G->n = n;
G->e = e;
}
void DispAdj(AdjGraph *G) //输出邻接表G
{
int i;
ArcNode *p;
for (i = 0; i < G->n; i++)
{
p = G->adjlist[i].firstarc;
printf("%3d: ", i);
while (p != NULL)
{
if (p->weight != 2147483647) //2147483647
printf("%3d[%d]→", p->adjvex, p->weight);
p = p->nextarc;
}
printf("^\n");
}
}
void DestroyAdj(AdjGraph *&G) //销毁邻接表
{
int i;
ArcNode *pre, *p;
for (i = 0; i < G->n; i++) //扫描所有的单链表
{
pre = G->adjlist[i].firstarc; //p指向第i个单链表的首结点
if (pre != NULL)
{
p = pre->nextarc;
while (p != NULL) //释放第i个单链表的所有边结点
{
free(pre);
pre = p;
p = p->nextarc;
}
free(pre);
}
}
free(G); //释放头结点数组
}
//////////////////////////////////////////////////////////
//无向图邻接表的深度优先算法
void DFS(AdjGraph *G, int v)
{
ArcNode *p;
visited[v] = 1;
printf("%d ", v);
p = G->adjlist[v].firstarc;
while(p != NULL) //p == NULL is the break of circle
{
if(visited[p->adjvex] == 0)
DFS(G, p->adjvex);
p=p->nextarc;
}
}
//////////////////////////////////////////////////////
void BFS(AdjGraph *G, int v)
{
int w, i;
ArcNode *p;
SqQueue *qu;
InitQueue(qu);
int visited[MAXV];
for(i = 0; i < G->n; i++)
visited[i] = 0;
printf("%2d",v);
visited[v] = 1;
enQueue(qu, v);
while( !QueueEmpty(qu))
{
deQueue(qu, w);
p = G->adjlist[w].firstarc;
while(p!=NULL)
{
if(visited[p->adjvex] == 0)
{
printf("%2d", p->adjvex);
visited[p->adjvex] = 1;
enQueue(qu, p->adjvex);
}
p = p->nextarc;
}
}
printf("\n");
}
int main ()
{
int a[4][MAXV] = {{0, 1, 1, 1},
{1, 0, 1, 1},
{1, 1, 0, 0},
{1, 1, 0, 0}};
AdjGraph* g;
CreateAdj(g, a, 4, 5);
printf("这是原始邻接表的结构: \n");
DispAdj(g);
printf("\nthis is the Deep fist search (from '0'):\n");
DFS(g, 0);
printf("\nthis is the Broad fist search (from '0): \n");
BFS(g, 0);
system("pause");
return 0;
}
原始数据
原始数据以及运行结果