如何使用 BFS 算法指示生成树的先序

发布于 2024-12-26 21:06:08 字数 549 浏览 2 评论 0原文

我正在用 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);
}

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

I'm doing an implementation of the BFS algorithm in c++ to find a spanning tree, the output for a spanning tree should be shown in preorder, but I have a doubt in the implementation, how I can build a tree if not exactly know how many children have each node?. Considering a tree structure recursive The data structure of the tree can be written as:

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

But do not think it works this implementation as mentioned before.

This is my function to return the tree in preorder:

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

I also wonder if there is any way to do the preorder of the nodes without using a tree structure.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小霸王臭丫头 2025-01-02 21:06:08

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

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

稍微扩展一下第二点:树的预序遍历仅意味着每个节点在其子节点之前被处理。当您进行图搜索时,您想要遍历图的连接组件,仅访问每个节点一次,您就可以有效地创建一棵隐式树。也就是说,您的起始节点成为树的根节点。每当您访问一个节点时,您都​​会搜索尚未访问过的相邻节点,即未标记的节点。如果存在这样的节点,则关联边将成为树节点并标记该节点。由于总是只有一个节点被主动持有,因此您需要记住未处理的节点,但是,在某些数据结构中,例如堆栈或队列(而不是显式地使用堆栈,您可以执行递归来创建隐式堆栈)。现在,如果您在第一次看到节点时发出节点号,那么您显然会在其子节点之前处理它,即您最终会按照预序遍历的顺序写入节点号。

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

  • 带有空心圆圈的节点及其旁边的节点编号
  • 带有细线的边缘
  • 队列只是矩形,不包含现在

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

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

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

在使用图算法时,我发现可视化算法非常有帮助。虽然让计算机来维护绘图固然很好,但在纸上绘制东西并可能通过许多标记的铅笔指示活动节点的低技术替代方案即使不是更好,也同样有效。

只是对代码的评论:每当您读取任何输入时,请确保成功读取数据。顺便说一句,您的代码显然只是 C 而不是 C++ 代码:可变长度数组在 C++ 中不可用。在 C++ 中,您将使用 std::vector; followOrder(vertexNumber) 而不是 int followOrder[vertexNumber]。有趣的是,该代码也不是 C 语言,因为它使用例如 std::queue

I have seen two concrete questions in the posting:

  1. Is it possible to have a data structure using more than two children in a tree? Of course this is possible. Interestingly, it is even possible with the node structure you posted! Just consider the left pointer to be a pointer to the first child and the right pointer to point to the next sibling. Since breadth first search of a graph implicitly builds up a spanning tree, you can then walk this tree in preorder if you actually represent it somehow.
  2. Can you do a preorder walk without using a tree structure? Yes, this is possible, too. Essentially, DFS and BFS are conceptually no different for this: you just have a data structure maintaining the nodes to be visited next. For DFS this is a stack, for BFS this is a queue. You get a preorder walk of the tree (i.e. you visit all children of a node after the parent) if you emit the node number when you insert it into the data structure maintaining the nodes to be visited.

To expand a bit on the second point: a preorder walk of a tree just means that each node is processed prior to it child nodes. When you do a graph search you want to traverse through a connected component of a graph, visiting each node just once, you effectively create an implicit tree. That is, your start node become the root node of the tree. Whenever you visit a node you search for adjacent nodes which haven't been visited, i.e. which isn't marked. If there is such a node, the incident edge becomes a tree node and you mark the node. Since there is always only just one node being actively held you need to remember the nodes which aren't processed, yet, in some data structure, e.g. a stack or a queue (instead of using a stack explicitly you could do recursion which creates the stack implicitly). Now, if you emit the node number the first time you see a node you clearly process it prior to its children, i.e. you end up writing the node number the order of a preorder walk.

If you don't understand this, please whip out a sheet of paper and draw a graph and a queue:

  • the nodes with hollow circles and their node number next to them
  • the edges with thin lines
  • the queue is just rectangles which doesn't contain anything at the start

Now choose a node to become the start node of your search which is the same as the root node of your tree. Write its number into the first empty position in the queue and mark i.e. fill the node. Now proceed with the search:

  • look at the node indicated by front of the queue and find an adjacent node which isn't filled:
    • append the node at the back of the queue (i.e. right behind the last node in the rectangle)
    • mark (i.e. fill) the node
    • make the line connecting the two nodes thicker: it is a tree edge now
  • if there are no further unmarked adjacent nodes tick the front node in the queue off (i.e. remove it from the queue) and move on to the next node until there are no further nodes

Now the queue rectangle contains a preorder walk of the spanning tree implied by a breadth first search of the graph. The spanning tree is visible using the thicker lines. The algorithm would also work if you treated the rectangle for the queue as a stack but it would be a bit messier because you end up with ticked off nodes between nodes still to be processed: instead of looking at the first unticked node you would look at the last unticked node.

When working with graph algorithms I found it quite helpful to visualize the algorithm. Although it would be nice to have the computer maintain the drawing, the low-tech alternative of drawing things on paper and possibly indicating active nodes by a number of labeled pencils works as well if not better.

Just a comment on the code: whenever you are reading any input, make sure that you successfully read the data. BTW, your code is clearly only C and not C++ code: variable length arrays are not available in C++. In C++ you would use std::vector<int> followOrder(vertexNumber) instead of int followOrder[vertexNumber]. Interestingly, the code isn't C either because it uses e.g. std::queue<int>.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文