• [Algorithm] Write a Depth First Search Algorithm for Graphs in JavaScript


    Depth first search is a graph search algorithm that starts at one node and uses recursion to travel as deeply down a path of neighboring nodes as possible, before coming back up and trying other paths.

     
    const {createQueue} = require('./queue');
    
    function createNode(key) {
        let children = [];
        return {
            key,
            children,
            addChild(child) {
                children.push(child)
            }
        }
    }
    
    function createGraph(directed = false) {
        const nodes = [];
        const edges = [];
    
        return {
            nodes,
            edges,
            directed,
    
            addNode(key) {
                nodes.push(createNode(key))
            },
    
            getNode (key) {
                return nodes.find(n => n.key === key)
            },
    
            addEdge (node1Key, node2Key) {
                const node1 = this.getNode(node1Key);
                const node2 = this.getNode(node2Key);
    
                node1.addChild(node2);
    
                if (!directed) {
                    node2.addChild(node1);
                }
    
                edges.push(`${node1Key}${node2Key}`)
            },
    
            print() {
                return nodes.map(({children, key}) => {
                    let result = `${key}`;
    
                    if (children.length) {
                        result += ` => ${children.map(n => n.key).join(' ')}`
                    }
    
                    return result;
                }).join('
    ')
            },
            /**
             * Breadth First Search
             */
            bfs (startNodeKey = "", visitFn = () => {}) {
                /**
                 * Keytake away:
                 * 1. Using Queue to get next visit node
                 * 2. Enqueue the node's children for next run
                 * 3. Hashed visited map for keep tracking visited node
                 */
                const startNode =  this.getNode(startNodeKey);
               // create a hashed map to check whether one node has been visited
               const visited = this.nodes.reduce((acc, curr) => {
                   acc[curr.key] = false;
                   return acc;
               }, {});  
            
               // Create a queue to put all the nodes to be visited
               const queue = createQueue();
               queue.enqueue(startNode);
            
               // start process
               while (!queue.isEmpty()) {
                  const current = queue.dequeue();
            
                  // check wheather the node exists in hashed map
                  if (!visited[current.key]) {
                      visitFn(current);
                      visited[current.key] = true;
            
                      // process the node's children
                      current.children.map(n => {
                        if (!visited[n.key]) {
                            queue.enqueue(n);
                        }
                      });
                  }
               }
            },
    
            /**
             * Depth First Search
             */
            dfs (startNodeKey = "", visitFn = () => {}) {
                // get starting node
                const startNode = this.getNode(startNodeKey);
                // create hashed map
                const visited = this.nodes.reduce((acc, curr) => {
                    acc[curr] = false;
                    return acc;
                }, {});
                function explore(node) {
                    // if already visited node, return
                    if (visited[node.key]) {
                        return;
                    }
                    // otherwise call the callback function
                    visitFn(node);
                    // Set nodekey to be visited
                    visited[node.key] = true;
                    // Continue to explore its children
                    node.children.forEach(n => {
                        explore(n);
                    });
                }
                // start exploring
                explore(startNode);
            }
        }
    }
    
    const graph = createGraph(true)
    
    graph.addNode('Kyle')
    graph.addNode('Anna')
    graph.addNode('Krios')
    graph.addNode('Tali')
    
    graph.addEdge('Kyle', 'Anna')
    graph.addEdge('Anna', 'Kyle')
    graph.addEdge('Kyle', 'Krios')
    graph.addEdge('Kyle', 'Tali')
    graph.addEdge('Anna', 'Krios')
    graph.addEdge('Anna', 'Tali')
    graph.addEdge('Krios', 'Anna')
    graph.addEdge('Tali', 'Kyle')
    
    console.log(graph.print())
    
    
    
    const nodes = ['a', 'b', 'c', 'd', 'e', 'f']
    const edges = [
      ['a', 'b'],
      ['a', 'e'],
      ['a', 'f'],
      ['b', 'd'],
      ['b', 'e'],
      ['c', 'b'],
      ['d', 'c'],
      ['d', 'e']
    ]
    
    const graph2 = createGraph(true)
    nodes.forEach(node => {
        graph2.addNode(node)
      })
      
      edges.forEach(nodes => {
        graph2.addEdge(...nodes)
      })
    
      console.log('***Breadth first graph***')
      graph2.bfs('a', node => {
        console.log(node.key)
      })
    
      console.log('***Depth first graph***')
      graph2.dfs('a', node => {
        console.log(node.key)
      })

    So Depth first Search VS Breadth first Search:

    Using 'depth' in JS, we should remind ourselves recursion, which using Stack data structure, FILO; 

    Using 'breadth', we should remind ourselves Queue, it is FIFO data structure, we just need to enqueue the all the children.

  • 相关阅读:
    纯JS实现俄罗斯方块,打造属于你的游戏帝国
    Java 集合框架
    项目(1-2)ES32获取mpu9250传入数据库
    项目(1-1)ES32获取mpu9250数据网页交互显示
    开发(三)ESP32 硬件配置
    开发(二) ardunio批量固件上传地址
    项目(1-1)人脸识别
    海康相机开发(1) SDK安装和开发
    ARDUNIO IMU processing姿态数据可视化
    ESP8266 tcp透传AP+STA
  • 原文地址:https://www.cnblogs.com/Answer1215/p/10129339.html
Copyright © 2020-2023  润新知