C++ BFS实现
我最近正在解决一个bfs问题,其中每个节点都是数组元素的不同排列。但我无法找到合适的数据结构来跟踪扩展树中访问的节点。通常,节点是不同的字符串,因此我们可以使用映射将节点标记为已访问,但在上述情况下,我应该使用什么DS?至少作为一个开始,您可以尝试使用/实现类似Java的array.toString()和映射。每种排列都会产生不同的字符串,因此它至少会有结果。至少作为一个开始,您可以尝试使用/实现Java的array.toString()之类的东西并使用映射。每种排列都会产生一个不同的字符串,因此它至少会有结果。考虑以下伪代码:C++ BFS实现,c++,data-structures,graph-algorithm,breadth-first-search,C++,Data Structures,Graph Algorithm,Breadth First Search,我最近正在解决一个bfs问题,其中每个节点都是数组元素的不同排列。但我无法找到合适的数据结构来跟踪扩展树中访问的节点。通常,节点是不同的字符串,因此我们可以使用映射将节点标记为已访问,但在上述情况下,我应该使用什么DS?至少作为一个开始,您可以尝试使用/实现类似Java的array.toString()和映射。每种排列都会产生不同的字符串,因此它至少会有结果。至少作为一个开始,您可以尝试使用/实现Java的array.toString()之类的东西并使用映射。每种排列都会产生一个不同的字符串,因
type Node; // information pertaining to a node
type Path; // an ordered list of nodes
type Area; // an area containing linked neighboring nodes
type Queue; // a FIFO queue structure
function Traverse(Area a, Node start, Node end) returns Path:
Queue q;
Node n;
// traverse backwards, from finish to start
q.push(end); // add initial node to queue
end.parent = end; // set first node's parent to itself
while (not q.empty()):
n = q.pop(); // remove first element
if (n == start) // if element is the final element, we're done
break;
for (Node neighbor in a.neighbors(n)): // for each neighboring node
if (neighbor.parent != Null): // if already visited, skip
continue;
neighbor.parent = n; // otherwise, visit
q.push(neighbor); // then add to queue
Path p; // prepare to build path from visited list
for (Node previous = Null, current = n;
previous != current;
previous = current, current = current.parent):
p.add(current); // for each node from start to end, add node to p
// Note that the first node's parent is itself
// thus dissatisfying the loop condition
return p;
“已访问列表”存储为节点的父节点。将此编码为C++,您可能会将大部分节点作为引用或指针处理,因为该伪代码依赖于引用行为。
从一个区域开始,这是一个节点字段。该区域知道每个节点相对于其他节点的位置。您从一个特定的节点“开始”节点开始,并将其推送到队列中
遍历该区域非常简单,只需从该区域获取相邻节点的列表,如果它们已经被访问,则跳过它们,否则设置它们的父节点并将它们添加到队列中。当从队列中移除的节点等于目标节点时,遍历结束。您可以通过在邻居循环期间(最初遇到节点时)执行此检查来稍微加快算法的速度
注意:在开始遍历之前,不需要生成区域内所有可能的节点,该区域只需要在创建节点后跟踪节点。这可能有助于您使用字符串或数组排列的情况:您可以将起始节点和结束节点推入该区域,并且可以动态生成和缓存邻居节点。您可以将它们存储为向量,可以使用==运算符根据它们的顺序和内容进行相等性比较
遍历是向后的,而不是向前的,因为它使重建路径更容易(而不是在结束节点处结束,每个父节点在它之前,你在开始节点处结束,每个父节点在它之后)
数据结构摘要
节点
需要跟踪足够的信息,以便区域
能够唯一地识别它(通过数组索引或名称等),以及父节点。在遍历之前,应该将父节点设置为NULL,以避免出现奇怪的行为,因为遍历将忽略具有父节点集的任何节点。这也会跟踪已访问状态:已访问相当于(parent!=NULL)。这样做还可以使您不必跟踪队列中的整个路径,这将非常需要计算
区域
需要维护一个节点列表
,并且需要一个邻居映射,或者哪个节点与哪个其他节点相邻的映射。这种映射可能是通过函数动态生成的,而不是从表或其他更典型的方法中查找。它应该能够向调用者提供节点的邻居。有一个helper方法可以清除每个节点的父节点,这可能会有所帮助
Path
基本上是一种列表类型,包含节点的有序列表
队列
是任何可用的FIFO队列。你可以用一个链表
我喜欢在我的Wuggytovasp++上突出显示语法的方式。考虑以下伪代码:
type Node; // information pertaining to a node
type Path; // an ordered list of nodes
type Area; // an area containing linked neighboring nodes
type Queue; // a FIFO queue structure
function Traverse(Area a, Node start, Node end) returns Path:
Queue q;
Node n;
// traverse backwards, from finish to start
q.push(end); // add initial node to queue
end.parent = end; // set first node's parent to itself
while (not q.empty()):
n = q.pop(); // remove first element
if (n == start) // if element is the final element, we're done
break;
for (Node neighbor in a.neighbors(n)): // for each neighboring node
if (neighbor.parent != Null): // if already visited, skip
continue;
neighbor.parent = n; // otherwise, visit
q.push(neighbor); // then add to queue
Path p; // prepare to build path from visited list
for (Node previous = Null, current = n;
previous != current;
previous = current, current = current.parent):
p.add(current); // for each node from start to end, add node to p
// Note that the first node's parent is itself
// thus dissatisfying the loop condition
return p;
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* @author VAISAKH N
*/
public class BFSME {
public static String path = "";
public static String add = "";
public static void findrec(String temp, String end, String[][] m, int j) {
if (temp.equals(m[j][1])) {
add = m[j][0] + temp + end + "/";
end = temp + end;
System.out.println(end);
path = path + add;
temp = "" + add.charAt(0);
System.out.println("Temp" + temp);
for (int k = 0; k < m.length; k++) {
findrec(temp, end, m, k);
}
}
}
public static void main(String[] args) {
String[][] data = new String[][]{{"a", "b"}, {"b", "c"}, {"b", "d"}, {"a", "d"}};
String[][] m = new String[data.length][2];
for (int i = 0; i < data.length; i++) {
String temp = data[i][0];
String end = data[i][1];
m[i][0] = temp;
m[i][1] = end;
path = path + temp + end + "/";
for (int j = 0; j < m.length; j++) {
findrec(temp, end, m, j);
}
}
System.out.println(path);
}
}
“已访问列表”存储为节点的父节点。将此编码为C++,您可能会将大部分节点作为引用或指针处理,因为该伪代码依赖于引用行为。
从一个区域开始,这是一个节点字段。该区域知道每个节点相对于其他节点的位置。您从一个特定的节点“开始”节点开始,并将其推送到队列中
遍历该区域非常简单,只需从该区域获取相邻节点的列表,如果它们已经被访问,则跳过它们,否则设置它们的父节点并将它们添加到队列中。当从队列中移除的节点等于目标节点时,遍历结束。您可以通过在邻居循环期间(最初遇到节点时)执行此检查来稍微加快算法的速度
注意:在开始遍历之前,不需要生成区域内所有可能的节点,该区域只需要在创建节点后跟踪节点。这可能有助于您使用字符串或数组排列的情况:您可以将起始节点和结束节点推入该区域,并且可以动态生成和缓存邻居节点。您可以将它们存储为向量,可以使用==运算符根据它们的顺序和内容进行相等性比较
遍历是向后的,而不是向前的,因为它使重建路径更容易(而不是在结束节点处结束,每个父节点在它之前,你在开始节点处结束,每个父节点在它之后)
数据结构摘要
节点
需要跟踪足够的信息,以便区域
能够唯一地识别它(通过数组索引或名称等),以及父节点。在遍历之前,应该将父节点设置为NULL,以避免出现奇怪的行为,因为遍历将忽略具有父节点集的任何节点。这也会跟踪已访问状态:已访问相当于(parent!=NULL)。这样做还可以使您不必跟踪队列中的整个路径,这将非常需要计算
区域
需要维护
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
//Adding node pair of a Edge in Undirected Graph
void addEdge( vector<int> adj[], int u, int v){
adj[u].push_back(v); // 1st push_back
adj[v].push_back(u); //2nd push_back
//for Directed Graph use only one push_back i.e., 1st push_back() rest is same
}
//Traversing through Graph from Node 0 in Adjacency lists way
void showGraph( vector<int>adj[], int size){
cout<<"Graph:\n";
for(int i=0; i<size ; i++){
cout<<i;
for( vector<int>::iterator itr= adj[i].begin() ; itr!=adj[i].end(); itr++){
cout<<" -> "<<*itr;
}
cout<<endl;
}
}
//Prints Array elements
void showArray(int A[]){
for(int i=0; i< 6; i++){
cout<<A[i]<<" ";
}
}
void BFS( vector<int>adj[], int sNode, int N){
// Initialization
list<int>queue; //Queue declaration
int color[N]; //1:White, 2:Grey, 3:Black
int parentNode[N]; //Stores the Parent node of that node while traversing, so that you can reach to parent from child using this
int distLevel[N]; //stores the no. of edges required to reach the node,gives the length of path
//Initialization
for(int i=0; i<N; i++){
color[i] = 1; //Setting all nodes as white(1) unvisited
parentNode[i] = -1; //setting parent node as null(-1)
distLevel[i] = 0; //initializing dist as 0
}
color[sNode] = 2; //since start node is visited 1st so its color is grey(2)
parentNode[sNode] = -1; //parent node of start node is null(-1)
distLevel[sNode] = 0; //distance is 0 since its a start node
queue.push_back(sNode); //pushing start node(sNode) is queue
// Loops runs till Queue is not empty if queue is empty all nodes are visited
while( !queue.empty()){
int v = queue.front(); //storing queue's front(Node) to v
// queue.pop_front();//Dequeue poping element from queue
//Visiting all nodes connected with v-node in adjacency list
for(int i=0; i<adj[v].size() ;i++){
if( color[ adj[v][i] ] == 1){// if node is not visited, color[node]==1 which is white
queue.push_back(adj[v][i]); //pushing that node to queue
color[adj[v][i]]=2; //setting as grey(2)
parentNode[ adj[v][i] ] = v; //parent node is stored distLevel[ adj[v][i] ] = distLevel[v]+1; //level(dist) is incremented y from dist(parentNode)
}
}//end of for
color[v]=3;
queue.pop_front();//Dequeue
}
printf("\nColor: \n");showArray(color);
printf("\nDistLevel:\n");showArray(distLevel);
printf("\nParentNode:\n");showArray(parentNode);
}
int main(){
int N,E,u,v;//no of nodes, No of Edges, Node pair for edge
cout<<"Enter no of nodes"<<endl;
cin>>N;
vector<int> adj[N]; //vector adjacency lists
cout<<"No. of edges"<<endl;
cin>>E;
cout<<"Enter the node pair for edges\n";
for( int i=0; i<E;i++){
cin>>u>>v;
addEdge(adj, u, v); //invoking addEdge function
}
showGraph(adj,N); //Printing Graph in Adjacency list format
BFS(adj,0,N); /invoking BFS Traversal
}