逐层打印二叉树

时间:2015-07-08 02:50:17

标签: c++ algorithm binary-tree

如我们所知,我们可以按级别或vertical

打印一个二叉树

我想逐层打印一个二叉树。让我通过一个例子解释一下。

                 1            
            /         \
          2              3       
       /      \       /     \
      4        5      6         7    
    /   \    /   \   /   \    /    \
   8    9  15    12 14   13  10     11

对于上面的一个二叉树,我希望输出像

1st layer: 8 4 2 1 3 7 11
2nd layer: 9 5 6 10 
3rd layer: 15 13
4th layer: 12 14

我的问题合理吗?如果是的话,怎么做?

编辑1:

解释layer

enter image description here

标记为绿色的圆圈是第一层,

标记为蓝色的圆圈是第二层,

标记为红色的圆圈是第三层。

4 个答案:

答案 0 :(得分:1)

一些澄清

  • 我会在答案中使用C#。将C#翻译为C++
  • 很容易
  • 我将拥有 0 数组,图层和行,因为C语言
  • 是常见的
  • 但是,我会在输出添加1以获得理想的输出
  • 我建议您将二叉树存储在大小为2n - 1的线性数组中,其中n是多行。 -1不存在的节点的值:

    [ 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, 12, 14, 13, 10, 11 ]
    

算法解决方案

让我们绘制一个适当的(层数,而不是设计)图层图片:

http://ideone.com/fL4XCx

如果我们用图层替换值,它将变为:

1
1 1
1 2 2 1
1 2 3 4 4 3 2 1
1 2 3 4 5 6 7 8 8 7 6 5 4 3 2 1

我们注意到:

  1. 每行n代表n \ 2层。
  2. 行中的第一个和最后一个节点始终属于第1层。
  3. 第二个和n - 1始终属于第2层,依此类推。
  4. 简单地说,图层ID从1增加到n \ 2,然后减少到1。
  5. 我们将如何解决这个问题:我们将根据这些规则逐级遍历二进制树级别和每个节点的计数层。

    解决方案代码

    实际上,树中包含的值不会影响解决方案。它仅在输出时需要。

    让我们宣布一些变量:

    我们的阵列:

    int[] arr = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, 12, 14, 13, 10, 11 };
    

    Dictionary<int, int>(C ++中的map<int,int>) 键值对意味着索引Key的节点属于层Value

    Dictionary<int, int> layers = new Dictionary<int, int>();
    

    一些变数:

    int n = arr.Length,              // Length of array (for convenience)
            nodesInRow = 1,          // How many nodes in current row
            currentNodeInRow = -1,   // Position of node in current row
            rowCenter,               // Center of array (for convenience)
            currentNodeLayer = 0,    // Layer of current node
            maxLayer = -1;           // Maximum layer (we should know how many to output)
    

    主循环:

    for (int i = 0; i < n; i++)
        {
            if (currentNodeInRow == nodesInRow - 1) // if we are at the end of row
            {
                nodesInRow *= 2; // the count of nodes in binary tree doubles with every row
                currentNodeInRow = 0; // reset to the beginning 
            } else currentNodeInRow++; // go to the following node
    
            if (i == 0) {
                // 0-th node is a special case as it is the only row with odd count of nodes
                layers.Add(0, 0); 
                continue;
            }
    
            rowCenter = nodesInRow / 2 - 1; // row center
    
            if (currentNodeInRow <= rowCenter) // calculate layer according to rules above
                currentNodeLayer = currentNodeInRow;
            else
                currentNodeLayer = nodesInRow - currentNodeInRow - 1;
    
            if (currentNodeLayer > maxLayer) maxLayer = currentNodeLayer;
            layers.Add(i, currentNodeLayer); 
    
            // Console.WriteLine("{0} => {1}", i, currentNodeLayer);
        }
    

    现在,我们有以下字典:

    {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 1}, {5, 1} ...}
    

    我们可以轻松输出它,因为我们知道树中的图层数量:

    for (int i = 0; i <= maxLayer; i++)
    {
        Console.Write("Layer {0}:", i + 1); // Here we add 1 for 1-based output
        foreach (var x in layers.Where((p) => p.Value == i)) // sorry for being too C#
            if (arr[x.Key] != -1) Console.Write("{0} ", arr[x.Key]); 
        Console.WriteLine();
    }
    

    请注意,在输出之前我们没有使用值数组,因为层不受数组内容的影响。

    结果,我们得到以下输出:

    Layer 1: 1 2 3 4 7 8 11 
    Layer 2: 5 6 9 10 
    Layer 3: 13 
    Layer 4: 12 14 
    

    这是IDEOne Working Demo

    如果你的二进制树不是存储在普通数组中而是存储在带有指向祖先的数组的数组中 - 你可以执行BFS以按顺序获取值并将其注入循环中。

答案 1 :(得分:0)

我已经检查过,但对我来说似乎是正确的,

图层编号等于分支上左右之间的最小计数。

如果您的树节点是R,R,L,R,R,L 那么R-cnt是4,而L-cnt是2
因此它的第2层......

欢呼声

答案 2 :(得分:0)

对于@Tomer W的回答我会添加两件事:

  1. 使用预订遍历(最左边是第一个)。
  2. 将所有节点(或对它的一些引用)+图层放在一个向量中,并使用stable_sort(在图层上)来保留相等层节点之间的遍历顺序

答案 3 :(得分:0)

我认为现在应该清楚简单。

首先,请按标准顺序重新索引节点:

            1            
        /         \
      2              3       
   /      \       /     \
  4        5      6         7    
 /  \    /   \   /   \    /   \
8    9  10   11 12   13  14    15

考虑一行,例如:

4, 5, 6, 7

第一个节点是2的幂,这个数字也是行的长度。

从左到右考虑上半部4, 5,我们有:

  • 4属于第1层
  • 5属于第2层

从右到左考虑下半场6, 7,我们有:

  • 7属于第1层
  • 6属于第2层

因此,在这一行中,可以根据从节点到第一个和最后一个节点的距离来计算节点的层索引。

以下是代码:

bool isPowerOfTwo(int x) {
    return (x & (x - 1)) == 0;
}

int getLayerIndex(int nodeIndex) {
    int firstNode = nodeIndex;
    while ( ! isPowerOfTwo(firstNode) ) {
        --firstNode;
    }
    // Now firstNode is power of 2
    // firstNode is also the length of current row
    int lastNode = firstNode + firstNode - 1;
    return min( nodeIndex - firstNode + 1, lastNode - nodeIndex + 1 );
}