当前位置: 首页 > 知识库问答 >
问题:

使用广度优先搜索的生成树出图?

秦阳旭
2023-03-14

我正在尝试使用广度优先搜索来生成一个(生成)树,它是通过遍历一个图(无向和连通的)自然生成的,但是我很难修改算法来生成树。我用的是Java。

这是我的BFS算法

public void traverse(Node node){
    Queue queue= new Queue();
    node.visited= true;
    //Maybe do something here? 
    queue.enqueue(node);

    while (!queue.isEmpty()){
        Node r= queue.dequeue();
        for (int i= 0; i < r.childen.size(); i++){
            Node s= (Node)r.childen.get(i);
            if (s.visited == false){
                //And do something here? 
                s.visited= true;
                queue.enqueue(s);
            }
        }
    }
}

我的图形数据结构很简单(注意它是无向和连通的) :

< code >公共类图{ Node mainNode...

树数据结构也很简单:

公共类树{Node root;..

我的节点是这样的:

public class Node<T> {
    T data;
    boolean visited= false;
    ArrayList<Node> childen= new ArrayList<Node>();
    ...

我认为我的问题来自于我不能简单地将图中的某个< code >节点node直接添加到我的树中(因为这个< code >节点已经有了它的所有子节点)。相反,我必须创建一个< code >新节点(node.data),这样树中添加的节点就不会指向图中相同节点将指向的所有相邻节点。

所以我的问题是:当使用广度优先搜索遍历所述图时,我如何从图中生成(生成)树?

共有2个答案

冀鸿才
2023-03-14

我找到了一个简单的答案。我没有构建一棵树,而是删除了指向已经访问过的节点的边(这些信息是我们作为BFS算法的一部分免费获得的)。下面是我的实现(如果不想破坏最初的图形结构,它可能会被修改)。

public static Tree BFS(Node node){
    Queue queue= new Queue();
    node.visited= true;
    queue.enqueue(node);

    while (!queue.isEmpty()){
        Node r= queue.dequeue();
        for (int i= 0; i < r.childen.size(); i++){
            Node s= (Node)r.childen.get(i);
            if (s.visited == false){
                s.visited= true;
                queue.enqueue(s);
            }
            else{
                //Remove edge here
                r.childen.remove(i);
                i--;
            }
        }
    }
    Tree tree= new Tree(node);
    return tree;
}

编辑。下面是一个实现,它不会通过保持一个单独的队列来破坏初始的图形结构。

public static Tree BFS(Graph G, Node node){
    Queue queue= new Queue();
    Queue treeQueue= new Queue();
    ArrayList<Node> tempV= new ArrayList<Node>();
    tempV.add(node);
    queue.enqueue(node);
    Node root= new Node(node.data);
    treeQueue.enqueue(root);

    while (!queue.isEmpty()){
        Node r= queue.dequeue();
        Node t= treeQueue.dequeue();
        for (int i= 0; i < r.childen.size(); i++){
            Node s= (Node)r.childen.get(i);
            if (tempV.indexOf(s) < 0){
                tempV.add(s);
                Node child= new Node(s.data);
                t.childen.add(child);
                queue.enqueue(s);
                treeQueue.enqueue(child);
            }
        }
    }
    Tree tree= new Tree(root);
    return tree;
}
景高杰
2023-03-14

我将假设图既无向又有联系。话虽如此,我认为你走在正确的轨道上,但你还需要一些东西。首先,我强烈建议您将搜索状态和节点实现分开——换句话说,仅仅为了帮助您的搜索而存储私有成员变量Node.visible不是一个好主意。

您可以通过在搜索方法中维护一些额外的状态来避免这种情况,并使用递归私有帮助器方法对您的公共< code>traverse()方法的调用方隐藏该状态。为此,您需要在< code>Node类中正确实现< code>equals和< code>hashCode。

此外-如果您想创建一个具有不同节点的完全独立的,则需要在中创建每个节点的新的空实例,首先用对应节点的数据填充它们,然后使用克隆节点构建树。这就是说,这里有一些代码可以帮助您(我还没有测试过,但它应该让您知道该怎么做):

/**
 * This facade method traverses just the root of the new tree.  All recursion is
 * passed to the "traverseHelper(3)" recursive method.
 */
public Tree<T> traverse(Graph<T> g){
    if(g == null || g.mainNode == null) return null;
    Node<T> node = g.mainNode;
    Node<T> clone = new Node<T>(node.data); //this is the root of our new Tree
    Set<Node<T>> searched = new HashSet<Node<T>>(); //accumulates searched nodes
    searched.add(node);
    traverseHelper(node,clone,searched);
    return new Tree<T>(clone);
}

/**
 * Recursively performs BFS on all the children of the specified node and its
 * corresponding cloned instance.
 *
 * Assumes that "node" has been added to "searched" and that 
 * "searched.contains(node)" AND "searched.contains(clone)" will return true by 
 * the time this method is called.
 */
private void traverseHelper(Node<T> node, Node<T> clone, Set<Node<T>> searched){
    if(node.children == null) return;
    Map<Node<T>,Node<T>> toRecurseOn = new HashMap<Node<T>,Node<T>>();

    //This is the Breadth-First part - builds the next leaves in the tree:
    for(Node<T> child : node.children){
        if(child == null || searched.contains(child)) continue;
        Node<T> childClone = new Node<T>(child.data); //create leaf in the tree
        clone.children.add(childClone); //builds the current level in the tree
        childClone.children.add(clone); //maintains undirected-ness of the tree
        toRecurseOn.put(child,childClone); //lets us BFS later
    }

    //This is the Search part - builds the subtrees:
    Iterator<Node<T>> i = toRecurseOn.keySet().iterator();
    while(i.hasNext()){
        Node<T> child = i.next();
        Node<T> childClone = toRecurseOn.get(child);
        i.remove(); //Saves a little memory throughout the recursion
        traverseHelper(child,childClone,searched);
    }
}
 类似资料:
  • 主要内容:非连通图的生成森林,深度优先生成森林,广度优先生成森林前面已经给大家介绍了有关 生成树和生成森林的有关知识,本节来解决对于给定的无向图,如何构建它们相对应的生成树或者生成森林。 其实在对无向图进行遍历的时候,遍历过程中所经历过的图中的顶点和边的组合,就是图的生成树或者生成森林。 图 1 无向图   例如,图 1 中的无向图是由 V1~V7 的顶点和编号分别为 a~i 的边组成。当使用 深度优先搜索算法时,假设 V1 作为遍历的起始点,涉及到的顶点和边

  • 主要内容:深度优先搜索(简称“深搜”或DFS),广度优先搜索,总结前边介绍了有关图的 4 种存储方式,本节介绍如何对存储的图中的顶点进行遍历。常用的遍历方式有两种: 深度优先搜索和 广度优先搜索。 深度优先搜索(简称“深搜”或DFS) 图 1 无向图 深度优先搜索的过程类似于树的先序遍历,首先从例子中体会深度优先搜索。例如图 1 是一个无向图,采用深度优先算法遍历这个图的过程为: 首先任意找一个未被遍历过的顶点,例如从 V1 开始,由于 V1 率先访问过了,所以

  • 我正在研究BFS算法,我有一个关于如何将相邻节点插入队列的问题。 例如,假设我们正在处理一个无向图,我们希望执行BFS来输出图的内容,那么我们如何知道在从队列中取出一个初始节点后,相邻节点以什么顺序插入到队列中呢?还有,有没有办法修改邻居节点插入队列的方式? 任何帮助都将不胜感激,谢谢。

  • 我正在尝试在有向图上实现BFS。我完全确定我的算法是正确的,但是,下面的代码段返回错误: 图表。CPP文件: 以及在以下方面的实际BFS实施: 因此,除了源节点之外,队列中的其他节点都给出了错误的邻接列表。虽然队列顺序运行良好,但队列中的节点给出了错误的邻接。 我不确定为什么会发生这种情况,虽然我怀疑这是由于按值复制节点而不是引用。 这是我在很长一段时间后的CPP计划,所以如果我错过了什么,请启发

  • 二叉树上广度优先搜索的空间复杂度是多少?因为它一次只存储一个级别,我不认为它会是O(n)。

  • 本文向大家介绍什么是广度优先搜索?相关面试题,主要包含被问及什么是广度优先搜索?时的应答技巧和注意事项,需要的朋友参考一下 类似树的按层遍历,其过程为:首先访问初始点Vi,并将其标记为已访问过,接着访问Vi的所有未被访问过可到达的邻接点Vi1、Vi2……Vit,并均标记为已访问过,然后再按照Vi1、Vi2……Vit的次序,访问每一个顶点的所有未被访问过的邻接点,并均标记为已访问过,依此类推,直到图