图算法入门2:宽度优先搜索实现

上一节介绍了深度优先搜索,本节将基于上一节介绍的基本数据结构和方法来介绍宽度优先搜索,宽度优先基本原理如下:

宽度优先不太适合递归, 这里利用队列queue来实现宽度优先搜素,queue只能在队尾插入队首删除,该特性用来保证宽度优先搜索。先给出宽度优先的函数实现,这里用邻接表表示图结构,每个节点通过结构体VertexNode(更具体可参考上一节)表示,代码如下:

vector<int> graphBfs(vector<vector<VertexNode> >& graph,  const int& start) {
	vector<bool> discovered(graph.size(), false);
	// 记录各个顶点是否被发现
	queue<int> q;
	//记录顶点按照宽度优先的访问顺序
	vector<int> order;
	discovered[start] = true;
	q.push(start);
	while(!q.empty()) {
		int here = q.front();
		//每次拿到最顶端的顶点,即队列queue最前面的元素
		q.pop();
		order.push_back(here);
		for (int i = 0; i < graph[here].size(); ++i) {
			int there = graph[here][i].index;
			if (!discovered[there]) { //如果还没被发现
				q.push(there);
				discovered[there] = true;
			}
		}
	}
	return order;
}

可以看到,深度优先没有通过递归实现,而是走:节点->弹出存储在顺序队列的顶点->发现与弹出节点相连的节点这样的一个循环,从而迭代实现。下面给出完整的代码,图结构读写方法与上一节一样,图结构存储文件:

s a
a s b g
g a h i
i g
h g
b a c d e
e b f
f e
d b
c b

完整代码:

#include<iostream>
#include<vector>
#include<fstream>
#include<sstream>
#include<string>
#include<queue>
#include<unordered_map>
using namespace std;
typedef struct Vertex{
	string name;
	int index;
	Vertex(string inputName, int inputIndex):name(inputName),index(inputIndex){}
	Vertex():name(""),index(0){}
} VertexNode;
vector<int> graphBfs(vector<vector<VertexNode> >& graph,  const int& start) {
	vector<bool> discovered(graph.size(), false);
	// 记录各个顶点是否被发现
	queue<int> q;
	//记录顶点按照宽度优先的访问顺序
	vector<int> order;
	discovered[start] = true;
	q.push(start);
	while(!q.empty()) {
		int here = q.front();
		//每次拿到最顶端的顶点,即队列queue最前面的元素
		q.pop();
		order.push_back(here);
		for (int i = 0; i < graph[here].size(); ++i) {
			int there = graph[here][i].index;
			if (!discovered[there]) { //如果还没被发现
				q.push(there);
				discovered[there] = true;
			}
		}
	}
	return order;
}
int main() {
	unordered_map<string ,int> graphMap; // 图节点名和编号的Map
	vector<vector<VertexNode> > adjGraph; // 图的连接表表示法
	ifstream graphRdFile("graph_struct.txt");
	if(!graphRdFile.good()) {
		cout << "open graph file failed!" << endl;
		return -1;
	}
	string line;
	int index = 0;
	string vertexName;
	// 首先对Vertex Name进行编码
	while(graphRdFile >> vertexName) {
		if (graphMap.find(vertexName) == graphMap.end()) {
			graphMap.insert(make_pair(vertexName, index++));
		}
	}
	// 编码与Vertex的反映射
	vector<string> indexName = vector<string>(graphMap.size(),"");
	for(auto itr=graphMap.begin();itr!=graphMap.end();itr++) {
		indexName[itr->second] = itr->first;
	}
	// 重新读
	graphRdFile.clear();
	graphRdFile.seekg(0,std::ios::beg);
	adjGraph.resize(graphMap.size());
	int currentIndex = 0; // 当前图节点的编号
	while (getline(graphRdFile, line)) { //按行读,每一行是一个图节点的连接情况
		istringstream ss(line);
		string tmp;
		bool firstFlag = true;
		while(ss >> tmp) {
			if (firstFlag) {
				if (graphMap.find(tmp) != graphMap.end()) {
					currentIndex = graphMap[tmp];
				} else {
					break;
				}
				firstFlag = false;
				continue;
			}
			if (graphMap.find(tmp) != graphMap.end()) {
				adjGraph[currentIndex].emplace_back(VertexNode(tmp,graphMap[tmp]));
			}
		}
	}
	// 深度优先搜索测试
	vector<bool> visited = vector<bool>(graphMap.size(), false);
	vector<int> order = graphBfs(adjGraph, 0);
	for(int i = 0; i < order.size(); ++i) {
		cout << indexName[order[i]] << endl;
	}
	return 0;
}

执行结果如下:

s
a
b
g
c
d
e
h
i
f

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值