问题:考虑一个具有l级的完整k-ary树,其节点在广度优先遍历中按其等级标记。按照深度优先遍历中遍历的顺序计算标签列表。
例如,对于具有3个级别的二叉树,所需的列表是: [0 1 3 7 8 4 9 10 2 5 11 12 6 13 14]
实现此目的的一种方法是实际构建树结构并遍历两次;第一次遍历是广度优先,标记节点0,1,2,..当你去。第二次遍历是深度优先,报告标签0,1,3,7,..当你去。
我对避免在内存中构建树的方法感兴趣。我意识到这种树的大小与输出的大小相当,但我希望解决方案允许“流”输出(即不需要完全存储在内存中)。
我也对伴侣问题感兴趣;从根据深度优先遍历标记的树开始,并生成广度优先遍历的标签。我想在某种意义上,这个问题的解决方案将是第一个问题的双重解决方案。
答案 0 :(得分:3)
您实际上不需要构建树。您可以仅使用BFS标签而不是指向实际节点的指针来执行深度优先遍历。
使用BFS位置标签表示k-ary树中的节点:
0
n
的第一个孩子都是k*n + 1
n
的正确兄弟(如果有)n+1
看起来像这样:
class Whatever
{
static void addSubtree(List<Integer> list, int node, int k, int levelsleft)
{
if (levelsleft < 1)
{
return;
}
list.add(node);
for (int i=0; i<k; i++)
{
addSubtree(list, node*k+i+1, k, levelsleft-1);
}
}
public static void main (String[] args) throws java.lang.Exception
{
int K = 2, LEVELS = 4;
ArrayList<Integer> list = new ArrayList<>();
addSubtree(list, 0, K, LEVELS);
System.out.println(list);
}
}
这实际上一直用于表示数组中的二进制堆 - 节点是BFS顺序的数组元素,并且通过对索引执行这些操作来遍历树。
答案 1 :(得分:2)
您可以使用标准DFS和BFS算法,但不是从预先构建的树结构中获取特定节点的子节点,而是可以根据需要计算它们。
对于BFS编号的完整 K - 树高 H , i - 节点的子节点深度 D 的N 是:
K*N + 1 + i
在提供i = 0
(第一个孩子)here时推导出此公式。
对于DFS编号的完整 K - 树高 H ,节点的 i 子节点深度 D 的N 由更加丑陋的公式给出:
N + 1 + i*step where step = (K^(H - D) - 1) / (K - 1)
以下是对此公式的粗略解释:
对于高度 H 的DFS编号的 K - 树中深度为 D 的节点 N ,它的第一个孩子只是 N + 1 ,因为它是深度优先遍历中要访问的下一个节点。在访问以第一个孩子( N + 1 )为根的整个子树之后,将直接访问 N 的第二个孩子,这个子树本身就是一个完整的 K - 高度为
H - (D + 1)
的树。任何完整的 K - 树的大小由有限几何级数的总和给出,如here所述。所述子树的大小是第一和第二子节点之间的距离,并且实际上,所有兄弟节点之间的距离相同,因为它们的每个子树具有相同的大小。如果我们将此距离称为step
,则:第一个孩子是
N + 1
第二个孩子是N + 1 + step
第3个孩子是N + 1 + step + step
......等等。
下面是一个Python实现(注意:dfs
函数使用BFS公式,因为它正在从DFS转换为BFS,反之亦然bfs
函数。):
def dfs(K, H):
stack = list()
push, pop = list.append, list.pop
push(stack, (0, 0))
while stack:
label, depth = pop(stack)
yield label
if depth + 1 > H: # leaf node
continue
for i in reversed(range(K)):
push(stack, (K*label + 1 + i, depth + 1))
def bfs(K, H):
from collections import deque
queue = deque()
push, pop = deque.append, deque.popleft
push(queue, (0, 0))
while queue:
label, depth = pop(queue)
yield label
if depth + 1 > H: # leaf node
continue
step = (K**(H - depth) - 1) // (K - 1)
for i in range(K):
push(queue, (label + 1 + i*step, depth + 1))
print(list(dfs(2, 3)))
print(list(bfs(2, 3)))
print(list(dfs(3, 2)))
print(list(bfs(3, 2)))
以上将打印:
[0, 1, 3, 7, 8, 4, 9, 10, 2, 5, 11, 12, 6, 13, 14]
[0, 1, 8, 2, 5, 9, 12, 3, 4, 6, 7, 10, 11, 13, 14]
[0, 1, 4, 5, 6, 2, 7, 8, 9, 3, 10, 11, 12]
[0, 1, 5, 9, 2, 3, 4, 6, 7, 8, 10, 11, 12]
答案 2 :(得分:1)
这里有一些似乎可以解决问题的JavaScript。
var arity = 2;
var depth = 3;
function look(rowstart, pos, dep) {
var number = rowstart + pos;
console.log(number);
if (dep < depth-1) {
var rowlen = Math.pow(arity, dep);
var newRowstart = rowstart + rowlen;
for (var i = 0; i < arity; i++) {
look(newRowstart, pos*arity + i, dep+1);
}
}
}
look(0, 0, 0);
这是深度优先搜索,用于计算每个节点的BFS标签。
使用当前深度dep
计算节点的标签,当前行中的水平位置(pos
)和行中第一个节点的标签(rowstart
)。