BFS implementation

BFS implementation

本文关键字:implementation BFS      更新时间:2023-10-16

我最近解决了一个bfs问题,其中每个节点都是数组元素的不同排列。但我无法想出一个合适的数据结构来跟踪扩展树中的访问节点。通常,节点是不同的字符串,所以我们可以使用映射将节点标记为已访问,但在上述情况下,我应该使用什么DS?

考虑以下伪代码:

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++,您可能会将大多数节点作为引用或指针处理,因为此伪代码依赖于引用行为。

您从一个区域开始,该区域是一个节点字段。该区域知道每个节点相对于其他节点的位置。您从一个特定的节点开始,即"开始"节点,并将其推入队列。

遍历该区域非常简单,只需从区域中获取相邻节点的列表,如果它们已经访问过,则跳过它们,否则设置它们的父节点并将它们添加到队列中。当从队列中删除的节点等于目标节点时,遍历结束。当最初遇到节点时,可以通过在邻居循环期间进行此检查来稍微加快算法的速度。

注意:在开始遍历之前,您不需要在区域内生成所有可能的节点,area只需要在创建节点后跟踪它。这可能有助于您使用字符串或数组排列的情况:您可以将起始节点和结束节点推送到area中,并且它可以动态生成和缓存邻居节点。您可以将它们存储为向量,可以使用==运算符根据它们的顺序和内容对它们进行相等性比较。请参见此示例。

遍历是向后的,而不是向前的,因为它使重建路径变得更容易(而不是最终在结束节点,每个父节点在它之前,你最终在开始节点,每个母节点在它之后)

数据结构摘要

Node需要跟踪足够的信息,以便Area唯一地识别它(通过数组索引或名称等)以及父节点。父节点应该在遍历之前设置为NULL,以避免出现奇怪的行为,因为遍历将忽略任何具有其父集的节点。这也跟踪了visited状态:visited相当于(parent!=NULL)。这样做还可以使您不必跟踪队列中的整个路径,这将是非常密集的计算。

Area需要维护Node的列表,并且需要邻居映射,或者哪些节点与哪些其他节点相邻的映射。这种映射可能是用函数动态生成的,而不是从表或一些更典型的方法中查找。它应该能够向调用者提供节点的邻居。有一个助手方法可以清除每个节点的父节点,这可能会有所帮助。

Path基本上是一种列表类型,包含节点的有序列表。

Queue是可用的任何FIFO队列。你可以用链表来完成。

我喜欢语法高亮显示在我的Wuggythovasp++上的工作方式。

至少作为一个开始,您可以尝试使用/实现类似Java的Arrays.toString()的东西并使用映射。每种排列都会产生不同的字符串,因此它至少会有所进展。

/*
 * 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#中)

  private void Breadth_First_Travers(Node node)
  {
        // First Initialize a queue - 
        // it's retrieval mechanism works as FIFO - (First in First Out)
        Queue<Node> myQueue = new Queue<Node>();
        // Add the root node of your graph into the Queue
        myQueue.Enqueue(node);
        // Now iterate through the queue till it is empty
        while (myQueue.Count != 0)
        {
            // now, retrieve the first element from the queue 
            Node item = myQueue.Dequeue();
            Console.WriteLine("item is " + item.data);
            // Check if it has any left child   
            if (item.left != null)
            {
                // If left child found - Insert/Enqueue into the Queue
                myQueue.Enqueue(item.left);
            }
            // Check if it has right child 
            if (item.right != null)
            {
                // If right child found Insert/Enqueue into the Queue  
                myQueue.Enqueue(item.right);
            }
            // repeat the process till the Queue is empty
        }
   }

这里的示例代码是参考http://en.wikipedia.org/wiki/Binary_tree树本身就是一种图。

以下是使用C++STL(邻接列表)实现Graph的BFS。这里使用三个Array和一个Queue来完成实现。

#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 edgesn";
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
}