[Algorithm] Breadth First JavaScript Search Algorithm for Graphs

Breadth first search is a graph search algorithm that starts at one node and visits neighboring nodes as widely as possible before going further down any other path. This algorithm requires the use of a queue to keep track of which nodes to visit, so it might be worth your time to brush up on that data structure before watching this lesson.

 
复制代码
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('\n')
        },
        /**
         * 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);
                    }
                  });
              }
           }
        } 
    }
}

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)
  })

  graph2.bfs('a', node => {
    console.log(node.key)  //a,b,e,f,d,c
  })
复制代码

 

 

A more general function:

复制代码
        bfs (startNodeKey, predFn = () => {}, cb = () => {}) {
            const startNode = this.getNode(startNodeKey);
            const visited = createVistedMap(this.nodes);
            const queue = createQueue();
            startNode.children.forEach((n) => {
                queue.enqueue(n);
            });
            while (!queue.isEmpty()) {
                const current = queue.dequeue();
                if (!visited[current.key]) {
                    if (predFn(current)) return cb(current);
                    else {
                        visited[current.key] = true;
                    }
                }
            }
            cb(null)
        },
复制代码
复制代码
let graph3 = createGraph(true)
const tyler = {key: 'tyler', dog: false};
const henry = {key: 'henry', dog: false};
const john = {key: 'john', dog: false};
const aimee = {key: 'aimee', dog: true};
const peggy = {key: 'peggy', dog: false};
const keli = {key: 'keli', dog: false};
const claire = {key: 'claire', dog: false};

graph3.addNode('tyler', tyler);
graph3.addNode('henry', henry);
graph3.addNode('john', john);
graph3.addNode('claire', claire);
graph3.addNode('aimee', aimee);
graph3.addNode('peggy', peggy)
graph3.addNode('keli', keli);

graph3.addEdge('tyler', 'henry')
graph3.addEdge('tyler', 'john')
graph3.addEdge('tyler', 'aimee')
graph3.addEdge('henry', 'keli')
graph3.addEdge('henry', 'peggy')
graph3.addEdge('john', 'john')
graph3.addEdge('keli', 'claire')


graph3.bfs2('tyler', (node) => {
    return node.dog;
}, (node) => {
    if (node) console.log(`${node.key} has a dog`)
    else console.log('Tyler friends has no dog')
})
复制代码

 

Time Complexity: O(V+E) where V is number of vertices in the graph and E is number of edges in the graph.

posted @   Zhentiw  阅读(486)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
历史上的今天:
2017-12-15 [Python] Read and plot data from csv file
2017-12-15 [React] Make Controlled React Components with Control Props
2016-12-15 [JS Compose] 6. Semigroup examples
2016-12-15 [JS Compose] 5. Create types with Semigroups
2014-12-15 [AngularJS] $http cache
2014-12-15 [AngularJS+ GSAP] Greensock TimelineLite Animation Sequences
点击右上角即可分享
微信分享提示