上一节介绍了深度优先搜索,本节将基于上一节介绍的基本数据结构和方法来介绍宽度优先搜索,宽度优先基本原理如下:
宽度优先不太适合递归, 这里利用队列queue来实现宽度优先搜素,queue只能在队尾插入队首删除,该特性用来保证宽度优先搜索。先给出宽度优先的函数实现,这里用邻接表表示图结构,每个节点通过结构体VertexNode(更具体可参考上一节)表示,代码如下:
vectorgraphBfs(vector >& graph, const int& start) { vector discovered(graph.size(), false); // 记录各个顶点是否被发现 queue q; //记录顶点按照宽度优先的访问顺序 vector 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#include #include #include #include #include #include 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 graphBfs(vector >& graph, const int& start) { vector discovered(graph.size(), false); // 记录各个顶点是否被发现 queue q; //记录顶点按照宽度优先的访问顺序 vector 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 graphMap; // 图节点名和编号的Map vector > 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 indexName = vector (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 visited = vector (graphMap.size(), false); vector 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



