赞
踩
深度优先遍历(Depth_First_Search),也有称为深度优先搜索,简称DFS。话不多说,直接上个实例,它的原理也就大致清楚了。
我们对图1进行深度优先遍历。 深度优先遍历的过程如下:
这里先和大家回顾一下遍历的概念,在不重复经过某点的情况下,即每个点只能经过一次,依次走完所有点。就好比,你回老家给亲戚们拜年,他们住址都相隔不远,这时你规划一条路线,给你所有亲戚拜个年。好,回归正题,图2看不懂没关系,一共是八个步骤,每个步骤我都会详细和大家解释清楚,
typedef int Boolean;//Boolean是布尔类型,其值是TRUE或FALSE
Boolean visited[MAX];//访问标志的数组
//邻接矩阵的深度优先地柜算法
void DFS(MGraph G,int i)
{
int j;
visited[i]=TRUE;
cout<<G.vexs[i];//打印顶点,也可以其他操作
for(j=0;j<G.numVertexes;j++)
{
if(G.arc[i][j]==1&&!visited[j])
DFS(G,j);
}
}
//邻接矩阵的深度遍历操作
void DFSTraverse(MGraph G)
{
int i;
for(i=0;i<G.numVertexes;i++)
visited[i]=FALSE;//初始化所有顶点状态都是未访问过状态
for(i=0;i<G.numVertexes;i++)
if(!visited[i])//对未访问过的顶点调用DFS,若是连通图,只会执行一次
DFS(G,I);
}
如果图结构是邻接表结构,其DFSTraverse函数的代码是几乎相同的,只是在递归函数中因为将数组换成了链表而有所不同,代码如下。
typedef int Boolean;//Boolean是布尔类型,其值是TRUE或FALSE
Boolean visited[100];
//邻接表的深度优先递归算法
void DFS(GraphAdjList GL, int i) {
EdgeNode *p;
visited[i] = 1;
cout << GL.adjList[i].data << " ";//打印顶点,也可以其他操作
p = GL.adjList[i].firstedge;
while (p) {
if (!visited[p->adjvex])
DFS(GL, p->adjvex);//对未访问的邻接顶点递归调用
p = p->next;
}
}
//邻接表的深度遍历操作
void DFSTraverse(GraphAdjList GL) {
int i;
for (i = 0; i < GL.numVertexes; i++) {
visited[i] = 0;//初始所有顶点状态都是未访问过状态
}
for (i = 0; i < GL.numVertexes; i++) {
if (!visited[i])//对未访问过的顶点调用DFS,若是连通图,只会执行一次
DFS(GL, i);
}
}
对于n个顶点e条边的图来说,邻接矩阵由于是二维数组,要查找每个顶点需要访问矩阵中的所有元素,因此都需要O(n2)的时间。而邻接表做存储结构是,找邻接点所需的时间取决于顶点和边的数量,所以是O(n+e)。显然对于点多变少的稀疏图来说,邻接表结构使得算法在时间效率上大大提高。这里给出用邻接表存储图中数据,并遍历输出的实例,完整代码如下。
#include<iostream>
using namespace std;
#define MAXVEX 100
typedef char VertextType;//顶点类型应由用户定义
typedef int EdgeType;//边上的权值类型应由用户定义
typedef struct EdgeNode {//边表结点
int adjvex;//邻接点域,存储该顶点对应的下标
EdgeType weight;//用于存储权值,对于非网图可以不需要
struct EdgeNode *next;//链域,指向下一个邻接点
}EdgeNode;
typedef struct VertextNode {//顶点表结点
VertextType data;//顶点域,存储顶点信息
EdgeNode *firstedge;//边表头指针
}VertexNode,AdjList[MAXVEX];
typedef struct {
AdjList adjList;
int numVertexes, numEdges;//图中当前顶点数和边数
}GraphAdjList;
//建立图的邻接表结构
void CreateALGraph(GraphAdjList *G) {
int i, j, k;
EdgeNode *e;
cout << "输入顶点数和边数:" << endl;
cin >> G->numVertexes >> G->numEdges;//输入顶点数和边数
cout << "输入顶点信息" << endl;
for (i = 0; i < G->numVertexes; i++) {
cin >> G->adjList[i].data;//输入顶点信息
G->adjList[i].firstedge = NULL;//将边表置为空表
}
for (k = 0; k < G->numEdges; k++) {//建立边表
cout << "输入边(vi,vj)上的顶点序号:" << endl;
cin >> i >> j;//输入边(vi,vj)上的顶点序号
e = (EdgeNode *)malloc(sizeof(EdgeNode));//向内存申请空间,生成边表结点
e->adjvex = j;//邻接序号为j
e->next = G->adjList[i].firstedge;//将e指针指向当前顶点指向的结点
G->adjList[i].firstedge = e;//将当前顶点的指针指向e--------头插法
e = (EdgeNode *)malloc(sizeof(EdgeNode));//向内存申请空间,生成边表结点
e->adjvex = i;//邻接序号为i
e->next = G->adjList[j].firstedge;//将e指针指向当前顶点指向的结点
G->adjList[j].firstedge = e;//将当前顶点的指针指向e
}
}
typedef int Boolean;//Boolean是布尔类型,其值是TRUE或FALSE
Boolean visited[100];
//邻接表的深度优先递归算法
void DFS(GraphAdjList GL, int i) {
EdgeNode *p;
visited[i] = 1;
cout << GL.adjList[i].data << " ";//打印顶点,也可以其他操作
p = GL.adjList[i].firstedge;
while (p) {
if (!visited[p->adjvex])
DFS(GL, p->adjvex);//对未访问的邻接顶点递归调用
p = p->next;
}
}
//邻接表的深度遍历操作
void DFSTraverse(GraphAdjList GL) {
int i;
for (i = 0; i < GL.numVertexes; i++) {
visited[i] = 0;//初始所有顶点状态都是未访问过状态
}
for (i = 0; i < GL.numVertexes; i++) {
if (!visited[i])//对未访问过的顶点调用DFS,若是连通图,只会执行一次
DFS(GL, i);
}
}
int main() {
GraphAdjList *GL = (GraphAdjList*)malloc(sizeof(GraphAdjList));
CreateALGraph(GL);
DFSTraverse(*GL);
}
运行实例如下:
广度优先遍历(Breadth_First_Search),又称为广度优先搜索,简称BFS。我们也是先通过一个实例,演示过程来加深理解。
广度优先遍历的过程如下:
同样,这里会和大家解释广度优先遍历的每一步过程。
void BFSTraverse(MGraph G)
{
int i,j;
Queue Q;
for(i=0;i<G.numVertexes;i++)
visited[i]=0;
InitQueue(&Q);//初始化一辅助用的队列
for(i=0;i<G.numVertexes;i++)//对每一个顶点做循环,若是连通图,只会进行一次
{
if(!visited[i])
{
visited[i]=1;
cout<<G.vexs[i];//打印顶点,也可以其他操作
EnQueue(&Q,i);
while(!QueueEmpty(Q))//若当前队列不为空
{
DeQueue(&Q,i);//将队中元素出队列,赋值给i
for(j=0;j<G.numVertexes;j++)
{
//判断其他顶点若与当前顶点存在边且未访问过
if(G.arc[i][j]==1&&!visited[j])
{
visited[j]=1;//将找到的此顶点标记为已访问
cout<<G.vexs[j];//打印顶点
EnQueue(&Q,j);//将找到的此顶点入队列
}
}
}
}
}
}
对于邻接表的广度优先遍历,代码与邻接矩阵差异不大,下面给出完整的代码示例。
#include<iostream>
#include<queue>
using namespace std;
#define MAXVEX 100
typedef char VertextType;//顶点类型应由用户定义
typedef int EdgeType;//边上的权值类型应由用户定义
typedef struct EdgeNode {//边表结点
int adjvex;//邻接点域,存储该顶点对应的下标
EdgeType weight;//用于存储权值,对于非网图可以不需要
struct EdgeNode *next;//链域,指向下一个邻接点
}EdgeNode;
typedef struct VertextNode {//顶点表结点
VertextType data;//顶点域,存储顶点信息
EdgeNode *firstedge;//边表头指针
}VertexNode,AdjList[MAXVEX];
typedef struct {
AdjList adjList;
int numVertexes, numEdges;//图中当前顶点数和边数
}GraphAdjList;
//建立图的邻接表结构
void CreateALGraph(GraphAdjList *G) {
int i, j, k;
EdgeNode *e;
cout << "输入顶点数和边数:" << endl;
cin >> G->numVertexes >> G->numEdges;//输入顶点数和边数
cout << "输入顶点信息" << endl;
for (i = 0; i < G->numVertexes; i++) {
cin >> G->adjList[i].data;//输入顶点信息
G->adjList[i].firstedge = NULL;//将边表置为空表
}
for (k = 0; k < G->numEdges; k++) {//建立边表
cout << "输入边(vi,vj)上的顶点序号:" << endl;
cin >> i >> j;//输入边(vi,vj)上的顶点序号
e = (EdgeNode *)malloc(sizeof(EdgeNode));//向内存申请空间,生成边表结点
e->adjvex = j;//邻接序号为j
e->next = G->adjList[i].firstedge;//将e指针指向当前顶点指向的结点
G->adjList[i].firstedge = e;//将当前顶点的指针指向e--------头插法
e = (EdgeNode *)malloc(sizeof(EdgeNode));//向内存申请空间,生成边表结点
e->adjvex = i;//邻接序号为i
e->next = G->adjList[j].firstedge;//将e指针指向当前顶点指向的结点
G->adjList[j].firstedge = e;//将当前顶点的指针指向e
}
}
typedef int Boolean;//Boolean是布尔类型,其值是TRUE或FALSE
Boolean visited[100];
//邻接表的广度优先递归算法
void BFSTraverse(GraphAdjList GL) {
int i;
EdgeNode *p;
queue<int> Q;
for (i = 0; i < GL.numVertexes; i++)
visited[i] = 0;
for (i = 0; i < GL.numVertexes; i++) {
if (!visited[i]) {
visited[i] = 1;
cout << GL.adjList[i].data<<" ";//打印顶点,也可以是其他操作
Q.push(i);
while (!Q.empty()) {
i = Q.front();
Q.pop();
p = GL.adjList[i].firstedge;//找到当前顶点边表链表头指针
while (p) {
if (!visited[p->adjvex])//若此顶点未被访问
{
visited[p->adjvex] = 1;
cout << GL.adjList[p->adjvex].data<<" ";
Q.push(p->adjvex);//将此顶点入队列
}
p = p->next;//指针指向下一个邻接点
}
}
}
}
}
int main() {
GraphAdjList *GL = (GraphAdjList*)malloc(sizeof(GraphAdjList));
CreateALGraph(GL);
BFSTraverse(*GL);
}
运行实例如下:
对比图的深度优先遍历与广度优先遍历算法,你会发现,它们在时间复杂度上是一样的,不同之处仅仅在于对顶点访问的顺序不同。如果说图的深度优先遍历类似树的前序遍历,那么图的广度优先遍历就类似于树的层序遍历了。可见两者在全图遍历上是没有优劣之分的,只是视不同的情况选择不同的算法。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。