【问题标题】:How to deveplop a custom traversal algorithm that traverses the graph depth-first and breadth-next?如何开发一个自定义的遍历图深度优先和广度后继的遍历算法?
【发布时间】:2019-11-21 10:10:03
【问题描述】:

问题

您好,我是 DFS 和 BFS 的新手。今天一个新问题让我感到困惑:这个问题要求我开发一个自定义遍历算法,遍历图的深度优先和广度其次。这意味着你必须这样做: 遍历是深度优先的,直到它到达一个叶节点。当它这样做时,它选择的下一个节点是开始遍历的根的下一个子节点。换句话说,选择类似于广度优先,即按顺序选择根的孩子。

我的想法

如果我有这样的图表:

[
 [1, 1, 2],
 [2, 3, 4], 
 [3, 5, 6], 
 [4],
 [5],
 [6],
 [7]
 ];

我认为应该像这样遍历图表: The graph

然而

但是,我不知道如何编写代码,因为我不知道: 1.如何知道遍历是否到达叶子节点? 2、我可以直接调用BFS()DFS()函数写代码吗?

如果你能帮助我,我将不胜感激!

【问题讨论】:

    标签: algorithm graph


    【解决方案1】:
    1. 如果你解决图问题,你应该知道图的边,如果你知道边,你可以找到没有任何边的节点,即叶子节点。

    2. 不,我认为不会。如果您调用 BFS 和 DFS,如果您不做任何更改,BFS 和 DFS 只会遍历您的所有图表。

      我认为您只需要基于 BFS 和 DFS 构建自己的算法。我可以提供一个。这里有一些用 C# 编写的代码示例,试图做你的问题中描述的 rhat,深度优先,广度其次。

    public static List<Node> DepthFirstBreathNext(Node startNode)
    {
        var visitedNodes = new HashSet<Node>();
        var orderedVisited = new List<Node>();
        var depthStack = new Stack<Node>();
        var breadthQueue = new Queue<Node>();
        depthStack.Push(startNode);
        while (depthStack.Count > 0 || breadthQueue.Count > 0)
        {
    
            // Do depth-first while don't get to leaf
            while (depthStack.Count > 0)
            {
                var currentNode = depthStack.Pop();
                visitedNodes.Add(currentNode);
                orderedVisited.Add(currentNode);
                if (currentNode.PointTo == null || currentNode.PointTo.Where(x => !visitedNodes.Contains(x)).Count() == 0)
                    break;
    
                // Push first node to the stack for depth-first
                depthStack.Push(currentNode.PointTo.Where(x => !visitedNodes.Contains(x)).First());
    
                // Push other nodes to the queue for breadth-next
                foreach (var node in currentNode.PointTo.Where(x => !visitedNodes.Contains(x)).Skip(1))
                {
                    breadthQueue.Enqueue(node);
                }
            }
    
            // Do the breadth-next. Push to the stack first node from breadth queue.  
            if (breadthQueue.Count > 0)
            {
                while (visitedNodes.Contains(breadthQueue.Peek()))
                {
                    breadthQueue.Dequeue();
                }
    
                if (breadthQueue.Count > 0)
                {
                    depthStack.Push(breadthQueue.Dequeue());
                }
            }
        }
    
        return orderedVisited;
    }
    

    【讨论】:

      【解决方案2】:

      假设你有传统的bfsdfs

      dfs(G, node, visited):
        if node in visited:
          return
        visited.mark(child)
        for children in node:
          dfs(G, child, visited)
      
      bfs(G, queue, visited):
        node = queue.dequeue()
        if node in visited:
          return bfs(G, queue, visited)
      
        visited.mark(node)
        for children in node not in visited:
          queue.enqueue(child)
      
        # explore next node
        bfs(G, queue, visited)
      

      我们可以同时修改它们。

      • dfs 有一个布尔标志 onleaf,它基本上中止了它的探索
      • bfs 有一个钩子:dfs(本身!),它在 bfs 探索下一个节点之前调用
      #dfs stops exploration if he found a leaf
      dfs(G, node, visited):
        if node in visited:
          return
        visited.mark(child)
      +  if node has no children
      +    onleaf = true
      +    return onleaf
      
        for children in node:
      +    hasleaf = dfs(G, child, visited)
      +    if hasleaf:
      +      return true
      
      bfs(G, queue, visited):
        node = queue.dequeue()
        if node in visited:
           return bfs(G, queue, visited)
      
        visited.mark(node)
        for children in node not in visited:
          queue.enqueue(child)
      
      +   # explore next node
      +   # current node has setted the next candidates, just dfs it
      +   dfs(G, node, visited)
      +   #process to explore the queue as usual
      +   bfs(G, queue, visited)
      

      js下面

      /* useless just to get some data and debugging info */
      const makeTree = (d => {
        let id = 0
        const rec = (depth = 4) => {
          if (depth == 0) return {id: id++, children:[]}
          return node = {
            id: id++,
            children: Array(1 + Math.floor(Math.random()*5))
              .fill(0)
              .map(rec.bind(null, depth-1))
          }
        }
        return _ => ({ tree: rec(), id })
      })()
      const proxy = s => {
        const old = s.add
        s.add = function(node){
          console.log('visit ', node.id)
          return old.apply(this, arguments)
        }
        return s
      }
      /* ---------------end of useless ---------------------*/
      let visited = proxy(new Set())
      
      const dfs = node => {
        if (visited.has(node)) { return }
        visited.add(node)
        if (!node.children.length) { return true }
        return node.children.some(dfs)
      }
      
      const bfs = (queue) => {
        if(!queue.length) { return }
        const node = queue.shift()
        if (visited.has(node)) { return bfs(queue) }
        visited.add(node)
        queue.push(...node.children)
        dfs(node)
        bfs(queue)
      }
      
      const {tree, id} = makeTree()
      bfs([tree])
      console.log('explored', visited.size, 'expect', id)

      【讨论】:

        猜你喜欢
        • 2019-08-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-12
        相关资源
        最近更新 更多