【问题标题】:Level order insertion into a binary tree?将级别顺序插入二叉树?
【发布时间】:2011-09-27 04:39:41
【问题描述】:

假设给定一个级别顺序遍历输出。如何根据正确位置的数据构建二叉树?

请注意,我不是试图从给定的遍历输出中绘制树,而是从数组中读取遍历数据,然后通过 C 中的实际编码用它填充二叉树。

例如:

设 a[] = {A, B, C, D, E, F, G}; //数组中的遍历输出

所以层序树看起来像这样:

            A
           / \ 
          B   C
        / \  / \
       D   E F  G

假设有一个像这样的树节点结构:

typedef struct node
{
    char data;
    struct node* left;
    struct node* right;
}tree;

现在我正在尝试读取 a[] 值并对这棵树进行编码,使其看起来像图表。有许多级别顺序遍历的例子,但找不到与二叉树构造的实际编码相关的任何内容。这是一种“逆向遍历”。

另外请注意,这不是家庭作业,但如果更多人会注意到它,我没有问题标记它。 :)

【问题讨论】:

  • 在我看来,最简单的机制是将传入的数据存储到 heap 中。传入的数据是否适合堆属性?还是这棵树是二叉搜索树?
  • 奇怪...通常根据一些比较填充二叉树。这显然不是这里的情况。
  • 几乎总是有不止一棵树要从水平顺序遍历中构造出来。无法保证会再次生成创建遍历的确切树。
  • @DeepYellow,不,一个 二叉树 每个节点最多只有 2 个子节点。 二叉搜索树对节点进行排序。
  • @Bart,我意识到这棵树是二元的,不需要排序来满足定义。我的观点是,在没有排序要求的情况下使用二进制结构是不寻常的。我从来没有遇到过实际应用,你呢?

标签: c algorithm data-structures binary-tree


【解决方案1】:

一种可能的解决方案:

char a[SIZE] = {A,B,C,D,E,F,G}; 
    node* func(int index){
        if(index < SIZE){
            node *tmp = new node();
            tmp->data = a[index];
            tmp->left = func(2*index + 1);
            tmp->right = func(2*index + 2);
        }
        return tmp;
    }

树的堆栈跟踪:

                                     A->a[0]
          B->func(2*0 + 1)=[1]                              C->func(2*0 + 2)=[2]
D->func(2*1 + 1)=[3]    E->func(2*1 + 2)=[4]        F->func(2*2 + 1)=[5]     G->func(2*2 + 2)=[6]

【讨论】:

    【解决方案2】:

    这就像一个BFS,所以你可以使用一个队列

    请注意,您总是分配左孩子,然后立即分配右孩子。 所以从一个包含根的队列开始。在每次迭代中,从队列中弹出节点,然后从数组(或流)中读取接下来的两个值。使第一个成为弹出节点的左子节点并将其推入队列。然后使第二个成为正确的孩子并将其推入队列。以此类推,直到数组(或流)中没有元素为止。

    【讨论】:

      【解决方案3】:

      对于完整(或填充)二叉树,很容易将级别遍历转换为任何遍历,因为 n 位置的节点的子节点位于 2n2n+1 时数组以 1 为索引,当数组以 0 为索引时位于 2n+12n+2

      因此,您可以轻松地使用该公式将其转换为您最喜欢的遍历顺序,以便将节点插入树中(如预排序)。

      例如递归伪代码:

      void fill( TreeNode* node, char a[], int arrayLength, int n ){
          // n is the position of the current "node" in the array
          if( n < arrayLength ){
              node->data = a[n];
              fill( node->left, a, arrayLength, 2n+1 );
              fill( node->right, a, arrayLength, 2n+2 );
          }
      }
      

      【讨论】:

        【解决方案4】:

        如果您使用一些额外的存储空间,您可以很容易地以迭代方式执行此操作,从而节省递归解决方案的调用开销。这就是我会做的:

        node* theTree (char[] a, int arraylength) {
           if (arraylength == 0) return NULL;
        
           node** nodes = new node*[arraylength];
           nodes[0] = new node();
           nodes[0]->data = a[0];
        
           for (int i = 0, j = 0; TRUE ; j++) {
              if (++i >= arraylength) return nodes[0];
        
              nodes[i] = new node();
              nodes[i]->data = a[i];
              nodes[j]->left = nodes[i];
        
              if (++i >= arraylength) return nodes[0];
        
              nodes[i] = new node();
              nodes[i]->data = a[i];
              nodes[j]->right = nodes[i];
           }
        }
        

        可能的改进包括通过在 i > arraylength/2 时覆盖指针数组的部分来将所需内存减少两倍,并且可能自己一次在数组中预分配所有节点(尽管您需要然后小心释放)。

        【讨论】:

        • 谢谢。递归删除绝对是一件好事,但目前对我来说不是必需的 - 代码紧凑性现在就可以了。
        猜你喜欢
        • 2012-10-21
        • 1970-01-01
        • 2016-07-17
        • 2021-03-17
        • 1970-01-01
        • 1970-01-01
        • 2011-06-22
        • 2017-08-01
        • 1970-01-01
        相关资源
        最近更新 更多