如何用BFS算法表示生成树的预序

How to indicate preorder of a spanning tree using the algorithm BFS

本文关键字:生成树 表示 何用 BFS 算法      更新时间:2023-10-16

我正在c++中实现BFS算法,以找到生成树,生成树的输出应该按预序显示,但我在实现中有一个疑问,如果不确切地知道每个节点有多少个子节点,我如何构建树?。考虑树结构递归树的数据结构可以写成:

typedef struct node 
{
        int val;
        struct node *left, *right;
}*tree; //tree has been typedefed as a node pointer.

但不要认为它能像前面提到的那样在这个实现中起作用。

这是我在预购中返回树的函数:

void preorder(tree t) 
{
        if(t == NULL)
                return;
        printf("%d ", t->val);
        preorder(t->left);
        preorder(t->right);
}

我还想知道是否有任何方法可以在不使用树结构的情况下进行节点的预购。

我在帖子中看到了两个具体的问题:

  1. 是否可以在一棵树中使用两个以上的子级来创建数据结构?这当然是可能的。有趣的是,使用您发布的节点结构,这甚至是可能的!只需将left指针视为指向第一个子对象的指针,将right指针视为针对下一个同级对象的指针。由于图的广度优先搜索隐含地建立了一个生成树,所以如果你真的以某种方式表示它,你就可以按预序遍历这个树
  2. 你能在不使用树形结构的情况下进行预购步行吗?是的,这也是可能的。从本质上讲,DFS和BFS在概念上没有什么不同:您只需要一个数据结构来维护接下来要访问的节点。对于DFS来说,这是一个堆栈,对于BFS来说,这就是一个队列。如果在将节点号插入到维护要访问的节点的数据结构中时发出节点号,则可以获得树的预购遍历(即访问父节点之后的节点的所有子节点)

在第二点上展开:树的预序遍历只意味着每个节点在其子节点之前进行处理。当您进行图形搜索时,您希望遍历图形的连接组件,只访问每个节点一次,就可以有效地创建一个隐式树。也就是说,您的起始节点将成为树的根节点。每当您访问一个节点时,您都会搜索尚未访问的相邻节点,即未标记的节点。如果存在这样的节点,则偶发边将变为树节点,并标记该节点。由于总是只有一个节点处于活动状态,因此您需要记住尚未处理的节点,但在某些数据结构中,例如堆栈或队列(您可以进行递归,而不是显式使用堆栈,从而隐式创建堆栈)。现在,如果你第一次看到节点时发出节点号,你会在它的子节点之前清楚地处理它,也就是说,你最终会按照预购遍历的顺序写入节点号。

如果你不明白,请拿出一张纸,画一张图和一个队列:

  • 具有空心圆的节点及其旁边的节点编号
  • 有细线的边缘
  • 队列只是矩形,开始时不包含任何内容

现在选择一个节点作为搜索的起始节点,该节点与树的根节点相同。将其编号写入队列中的第一个空位置,并标记,即填充节点。现在继续搜索:

  • 查看队列前面指示的节点,找到一个未填充的相邻节点:
    • 将节点附加在队列的后面(即,就在矩形中最后一个节点的后面)
    • 标记(即填充)节点
    • 使连接两个节点的线变粗:现在是树边
  • 如果没有其他未标记的相邻节点,请勾选队列中的前一个节点(即从队列中删除它),然后移动到下一个节点,直到没有其他节点为止

现在,队列矩形包含由图的广度优先搜索所暗示的生成树的预序遍历。使用较粗的线可以看到生成树。如果您将队列的矩形视为堆栈,该算法也会起作用,但它会有点混乱,因为您最终会在仍有待处理的节点之间看到勾选的节点:您将查看最后一个未勾选的结点,而不是第一个未勾取的结点。

在使用图形算法时,我发现将算法可视化非常有帮助。虽然让计算机维护绘图是件好事,但在纸上绘图并可能用一些带标签的铅笔指示活动节点的低技术替代方案即使不是更好,也同样有效。

只是对代码的一个注释:无论何时读取任何输入,都要确保成功读取数据。顺便说一句,你的代码显然只有C,而不是C++代码:可变长度数组在C++中不可用。在C++中,您将使用std::vector<int> followOrder(vertexNumber)而不是int followOrder[vertexNumber]。有趣的是,该代码也不是C,因为它使用了例如std::queue<int>