我想知道是否可以在仅使用O(1)空间的情况下以广度优先打印二叉树?
困难的部分是必须使用额外的空间来记忆下一个级别来遍历,并且随着n的增长而增长。
由于我们没有对时间部分施加任何限制,可能会有一些效率低下(在时间上)的方法可以达到这个目的吗?
有什么想法吗?
答案 0 :(得分:4)
这取决于一些更精细的定义,例如,如果边有后向链接。然后它很容易,因为你可以按照树上的后退链接。否则,如果没有O(lg 节点数)空间,我就无法想办法,因为你需要至少记住“上面”的节点。
<强>更新强>
哦等等,当然可以在O(1) space 中进行空格时间交易。在任何地方你都想做一个反向链接,你保存你的位置并做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 |是顶点和边集的大小。
答案 1 :(得分:1)
我知道这绝对不是问题的答案,但是可以使用O( d )空间以广度优先的顺序访问树的节点,其中 d 是树的深度,由递归iterative deepening depth first search(IDDFS)组成。当然,堆栈需要空间。在平衡树的情况下, d = O(lg n )其中 n 是节点数。老实说,如果没有@Charlie Martin建议的反向链接,你不会在恒定的空间里看到它。
答案 2 :(得分:1)
一个有趣的特例是堆。
来自heapq
docs:
堆是二进制树,每个父节点的值都小于 超过或等于任何一个孩子。此实现使用数组 对于所有k,
heap[k] <= heap[2*k+1]
和heap[k] <= heap[2*k+2]
, 从零开始计算元素。为了比较,不存在 元素被认为是无限的。一个有趣的属性 heap是它的最小元素始终是根heap[0]
。 [FrançoisPinard的解释]
如何在内存中表示树(数组的索引):
0
1 2
3 4 5 6
7 8 9 10 11 12 13 14
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
在这种情况下,数组中的节点已经以广度第一顺序存储。
for value in the_heap:
print(value)
O(1)在太空中。
答案 3 :(得分:0)
很容易实现一种递归方法,以在给定级别获得树的所有节点。因此,我们可以计算树的高度并获得所有节点和每个级别。这是树的Level Order Traversal
。但是,时间复杂度为O(n^2)
。以下是Java实现(source)。
class Node
{
int data;
Node left, right;
public Node(int item)
{
data = item;
left = right = null;
}
}
class BinaryTree
{
Node root;
public BinaryTree()
{
root = null;
}
void PrintLevelOrder()
{
int h = height(root);
int i;
for (i=1; i<=h; i++)
printGivenLevel(root, i);
}
int Height(Node root)
{
if (root == null)
return 0;
else
{
int lheight = height(root.left);
int rheight = height(root.right);
}
}
void PrintGivenLevel (Node root ,int level)
{
if (root == null)
return;
if (level == 1)
System.out.print(root.data + " ");
else if (level > 1)
{
printGivenLevel(root.left, level-1);
printGivenLevel(root.right, level-1);
}
}
}