Functions to convert between depth first and breadth first traversals of a complete tree

笑着哭i 提交于 2019-12-04 06:28:10

You don't actually need to construct the tree. You can do the depth first traversal using just the BFS labels instead of pointers to actual nodes.

Using BFS position labels to represent the nodes in k-ary tree:

  • The root is 0
  • The first child of any node n is k*n + 1
  • The right sibling of a node n, if it has one, is n+1

in code it looks like this:

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);
    }
}

This is actually used all the time to represent a binary heap in an array -- the nodes are the array elements in BFS order, and the tree is traversed by performing these operations on indexes.

lazy dog

You can use the standard DFS and BFS algorithms, but instead of getting the child nodes of a particular node from a pre-built tree structure, you can compute them as needed.

For a BFS-numbered, complete K-ary tree of height H, the i-th child of a node N at depth D is:

K*N + 1 + i

A derivation of this formula when i = 0 (first child) is provided here.

For a DFS-numbered, complete K-ary tree of height H, the i-th child of a node N at depth D is given by a much uglier formula:

N + 1 + i*step where step = (K^(H - D) - 1) / (K - 1)

Here is a rough explanation of this formula:

For a node N at depth D in a DFS-numbered K-ary tree of height H, its first child is simply N+1 because it is the next node to be visited in a depth-first traversal. The second child of N will be visited directly after visiting the entire sub-tree rooted at the first child (N+1), which is itself a complete K-ary tree of height H - (D + 1). The size of any complete, K-ary tree is given by the sum of a finite geometric series as explained here. The size of said sub-tree is the distance between the first and second children, and, in fact, it is the same distance between all siblings since each of their sub-trees are the same size. If we call this distance step, then:

1st child is N + 1 2nd child is N + 1 + step 3rd child is N + 1 + step + step ...and so on.

Below is a Python implementation (note: the dfs function uses the BFS formula, because it is converting from DFS to BFS, and vice-versa for the bfs function.):

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)))

The above will print:

[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]

Here's some javascript that seems to solve the problem.

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);

It's a depth-first search that calculates the BFS label of each node on the way down.

It calculates the label of a node using the current depth dep, the horizontal position in the current row (pos) and the label of the first node in the row (rowstart).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!