使用 O(1) 空间以 BFS 方式打印二叉树
我想知道是否可以在仅使用 O(1) 空间的情况下以广度优先顺序打印二叉树?
困难的部分是,我们必须使用额外的空间来记住要遍历的下一个级别,并且该空间随着 n 的增加而增长。
由于我们没有对时间部分进行任何限制,也许有一些低效(就时间而言)的方法可以实现这一目标?
有什么想法吗?
I was wondering if it's possible to print a binary tree in breadth first order while using only O(1) space?
The difficult part is that one have to use additional space to memorize the next level to traverse, and that grows with n.
Since we haven't place any limitation on the time part, maybe there are some inefficient (in terms of time) ways that can achieve this?
Any idea?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这将取决于一些更细粒度的定义,例如边缘是否有反向链接。然后就很容易了,因为您只需沿着树上的反向链接即可。否则,我无法立即想出一种没有 O(lg 节点数) 空间的方法,因为您至少需要记住“上面”的节点。
更新
哦等等,当然可以通过时空交易在 O(1) 空间 中完成。无论您想要在哪里进行反向链接,您都可以保存您的位置并执行 BFS,跟踪最近的节点,直到找到您的节点。然后备份到最近访问的节点并继续。
问题是,空间复杂度为 O(1),时间复杂度为 O(n^2)。
另一个更新
假设我们已经到达节点 n_i,并且想要到达该节点的父节点,我们将其称为 wlg n_j。我们已经识别出显着的根节点n_0。
修改呼吸优先搜索算法,以便当它遵循有向边 (n_x,n_y) 时,存储传出或“传入”节点。因此,当您遵循 (n_x,n_y) 时,您将保存 n_x。
当您从 n_0 再次启动 BFS 时,可以保证(假设它确实是一棵树)在某个点,您将转换边 (n_j,n_i)。那时你会发现你回到了n_i。您已经存储了 n_j,因此您知道反向边是 (n_i,n_j)。
因此,您只需两个额外的单元即可获得单个回溯,一个用于 n_0,一个用于“已保存”节点。这是 O(1)
我不太确定 O(n^2) ——现在已经很晚了,而且这是艰难的一天,所以我不想写证明。我确定它是 O((|N|+|E|)^2) 其中 |N|和|E|分别是顶点集和边集的大小。
This is going to depend on some finer-grained definitions, for example if the edges have back-links. Then it's easy, because you can just follow a back link up the tree. Otherwise I can't think off hand of a way to do it without O(lg number of nodes) space, because you need to remember at least the nodes "above".
Update
Oh wait, of course it can be done in O(1) space with a space time trade. Everywhere you would want to do a back link, you save your place and do BFS, tracking the most recent node, until you find yours. Then back up to the most recently visited node and proceed.
Problem is, that's O(1) space but O(n^2) time.
Another update
Let's assume that we've reached node n_i, and we want to reach the parent of that node, which we'll call wlg n_j. We have identified the distinguished root node n_0.
Modify the breath-first search algorithm so that when it follows a directed edge (n_x,n_y), the efferent or "incoming" node is stored. Thus when you follow (n_x,n_y), you save n_x.
When you start the BFS again from n_0, you are guaranteed (assuming it really is a tree) that at SOME point, you will transition the edge (n_j,n_i). At that point you observe you're back at n_i. You've stored n_j and so you know the reverse edge is (n_i,n_j).
Thus, you get that single backtrack with only two extra cells, one for n_0 and one for the "saved" node. This is O(1)
I'm not so sure of O(n^2) -- it's late and it's been a hard day so I don't want to compose a proof. I'm sure it's O((|N|+|E|)^2) where |N| and |E| are the size of the sets of vertices and edges respectively.
一个有趣的特殊情况是堆。
来自
heapq
文档:树在内存中的表示方式(数组的索引):
在这种情况下,数组中的节点已经以广度优先顺序存储。
空间中的 O(1)。
An interesting special case is heaps.
From
heapq
docs:How a tree represented in memory (indexes of the array):
In this case nodes in the array are already stored in a breadth first order.
O(1) in space.
我知道这严格来说不是问题的答案,但是可以使用 O(d) 空间以广度优先顺序访问树的节点,其中 d 是树的深度,通过递归迭代加深深度优先搜索 (IDDFS)。当然,堆栈需要空间。对于平衡树,d = O(lg n),其中 n 是节点数。老实说,如果没有 @Charlie Martin 建议的反向链接,我真的不知道如何在恒定的空间中做到这一点。
I know that this is strictly not an answer to the question, but visiting the nodes of a tree in breadth-first order can be done using O(d) space, where d is the depth of the tree, by a recursive iterative deepening depth first search (IDDFS). The space is required for the stack, of course. In the case of a balanced tree, d = O(lg n) where n is the number of nodes. I honestly don't see how you'd do it in constant space without the backlinks suggested by @Charlie Martin.
很容易实现递归方法来获取给定级别的树的所有节点。因此,我们可以计算树的高度并获得所有节点和每个级别。这是树的
层序遍历
。但是,时间复杂度是O(n^2)
。下面是 Java 实现(源代码)。It is easy to implement a recursive method to get all the nodes of a tree at a given level. Hence, we could calculate the height of the tree and get all the nodes and each level. This is
Level Order Traversal
of the tree. But, the time complexity isO(n^2)
. Below is the Java implementation (source).