数据结构复习 ---- 广度优先遍历(BFS)

試著忘記壹切 提交于 2020-02-02 21:31:52

一、广度优先遍历的定义

广度优先遍历(Breadth_First_Search),又称为广度优先搜索,简称BFS;如果说深度优先遍历类似树的前序遍历,那么广度优先遍历就类似于树的层序遍历;不过相对于深度优先遍历,广度优先遍历借助了一个队列来辅助,利用队列先进先出的性质实现广度优先,看似复杂一些,其实也很好理解;先看代码~

二、广度优先的实现

  • 邻接矩阵

该算法的整体思路是先初始化标志数组,然后用双重循环各顶点;第一层循环,防止图不连通;二层循环是广度优先的核心,将顶点i的所有邻接顶点都放入队列,然后对队列进行出队操作,出队时返回出队顶点在顶点表中的位置,然后再将该出队顶点的邻接顶点入队,知道队列为空,这样该连通范围内的所有顶点都被遍历到了;
bool visited[MAXVEX];与深度优先同样的标志数组,去重;
函数OutQueue,为了能够返回出队顶点的位置;

bool visited[MAXVEX];

int OutQueue(Graph &graph, queue<char> &queue) {
	char tempVex = queue.front();
	for(int i = 0; i < graph.numVertexes; ++i) {
		if(tempVex == graph.vexs[i]) {
			queue.pop();
			return i;
		}
	}
}

void BFSTraverse(Graph &graph) {
	queue<char> queue;
	for(int i = 0; i < graph.numVertexes; ++i) {
		visited[i] = false;
	}
	for(int i = 0; i < graph.numVertexes; ++i) {
		if(!visited[i]) {
			visited[i] = true;
			cout << graph.vexs[i] << "  ";
			queue.push(graph.vexs[i]);
			while(!queue.empty()) {
				int i = OutQueue(graph, queue);
				for(int j = 0; j < graph.numVertexes; ++j) {
					if(graph.arc[i][j] && !visited[j]) {
						visited[j] = true;
						cout << graph.vexs[j] << "  ";
						queue.push(graph.vexs[j]);
					}
				}
			}
		}
	}
}
  • 邻接表

大体上思路是一样的,只不过区别在于对邻接顶点表的遍历方式不一样,邻接表自然用的是链表的遍历方式,关于辅助队列的用法也是一样的;

bool visited[MAXVEX];

int OutQueue(Graph &graph, queue<char> &queue) {
	char tempVex = queue.front();
	for(int i = 0; i < graph.vexNum; ++i) {
		if(tempVex == graph.vexArr[i].vexName) {
			queue.pop();
			return i;
		}
	}
}

void BFSTraverse(Graph &graph) {
	queue<char> queue;
	eNode* p;
	for(int i = 0; i < graph.vexNum; ++i) {
		visited[i] = false;
	}
	
	for(int i = 0; i < graph.vexNum; ++i) {
		if(!visited[i]) {
			visited[i] = true;
			cout << graph.vexArr[i].vexName << "  ";
			queue.push(graph.vexArr[i].vexName);
			while(!queue.empty()) {
				int i = OutQueue(graph, queue);
				p = graph.vexArr[i].vNext;
				while(p) {
					if(!visited[p->vexOrderNum]) {
						visited[p->vexOrderNum] = true;
						cout << graph.vexArr[p->vexOrderNum].vexName << "  ";
						queue.push(graph.vexArr[p->vexOrderNum].vexName);						
					}
					p = p->next;
				}
			}
		}
	}
}

三、测试

#include<iostream>
#include<queue>

using namespace std;

#define MAXVEX 20
#define INFINITY 0	//用于初始化时填充邻接矩阵 

typedef struct Graph {
	char vexs[MAXVEX];
	int arc[MAXVEX][MAXVEX];
	int numVertexes, numEdges;
}*pGraph; 

void CreateGraph(Graph &graph) {
	cout << "输入顶点数和边数:";
	cin >>  graph.numVertexes >> graph.numEdges;
	
	//建立顶点表 
	for(int i = 0; i < graph.numVertexes; ++i) {
		cout << "请输入第" << i + 1 << "个顶点名:"; 
		cin >> graph.vexs[i];
	}
	
	//初始化邻接矩阵
	for(int i = 0; i < graph.numVertexes; ++i) {
		for(int j = 0; j < graph.numVertexes; ++j) {
			graph.arc[i][j] = INFINITY;
		}
	} 
	
	//建立邻接矩阵
	int x, y, w;
	for(int i = 0; i < graph.numEdges; ++i) {
		cout << "输入边的下标x,y和权值w:";
		cin >> x >> y >> w;
		graph.arc[x][y] = w;
		graph.arc[y][x] = w;
	}
}

bool visited[MAXVEX];

int OutQueue(Graph &graph, queue<char> &queue) {
	char tempVex = queue.front();
	for(int i = 0; i < graph.numVertexes; ++i) {
		if(tempVex == graph.vexs[i]) {
			queue.pop();
			return i;
		}
	}
}

void BFSTraverse(Graph &graph) {
	queue<char> queue;
	for(int i = 0; i < graph.numVertexes; ++i) {
		visited[i] = false;
	}
	for(int i = 0; i < graph.numVertexes; ++i) {
		if(!visited[i]) {
			visited[i] = true;
			cout << graph.vexs[i] << "  ";
			queue.push(graph.vexs[i]);
			while(!queue.empty()) {
				int i = OutQueue(graph, queue);
				for(int j = 0; j < graph.numVertexes; ++j) {
					if(graph.arc[i][j] && !visited[j]) {
						visited[j] = true;
						cout << graph.vexs[j] << "  ";
						queue.push(graph.vexs[j]);
					}
				}
			}
		}
	}
}

int main() {
	Graph graph;
	CreateGraph(graph);
	
	for(int i = 0; i < graph.numVertexes; ++i) {
		cout << "\t" << graph.vexs[i];
	}
	cout << "\n\n";
	for(int i = 0; i < graph.numVertexes; ++i) {
		cout << graph.vexs[i] << "\t";
		for(int j = 0; j < graph.numVertexes; ++j) {
			cout << graph.arc[i][j] << "\t";
		}
		cout << "\n\n";
	}
	
	cout << "广度优先遍历结果:";
	BFSTraverse(graph);
	
	getchar();
	return 0;
}
  • 邻接矩阵

在这里插入图片描述

  • 邻接表

在这里插入图片描述

四、总结

其实广度优先遍历和深度优先遍历的区别就是,深度优先是类似于树的前序遍历,一直往下走,直到走到底再递归返回,重复往下深入遍历;而广度优先是先将一个顶点所有邻接顶点放入队列,然后按顺序一个一个出队列,出队列的同时也会将该顶点的所有邻接顶点再入队列,通过顶点的相关性来遍历整个图,两种算法的特点还是很明显不同的;
对比两种遍历算法,他们在时间复杂度上是一样的,不过如果图的顶点和边特别多的时候,不能在短时间完成遍历,遍历的目的是为了寻找合适的顶点,那么选择哪种遍历方式就要仔细斟酌了;深度优先更适合目标比较明确,以找到目标为主要的情况,而广度优先更适合在不断扩大遍历范围时找到相对最优解的情况~

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!