【问题标题】:convert array to binary tree with recursive strategy使用递归策略将数组转换为二叉树
【发布时间】:2021-09-13 15:56:21
【问题描述】:

我需要从包含一些零的向量开始创建一个二叉树,其中零表示不存在的节点。例如,如果我得到:

int a[] = {10,4,7,2,3,-1,8,9,-1,2,4,5};

我想要这样的输出:

         10
        /   \
       4     7
      / \     \
     2   3     8
    /   / \   /
   9   2   4 5  

我的结构:

  typedef struct node {
   int n;
   struct node * dx;
   struct node * sx;
  } *Bit_node;          

搭建一个节点的方法:

  Bit_node bit_new(int n) {
    Bit_node new_node = malloc(sizeof(struct node));
    new_node -> n = n;
    return new_node;
  }   

构建整棵树的方法:

  Bit_node bit_arr2tree(int a[], int size, int i) {
  if (i>= size) {
      return NULL;
  }
  if(a[i] != -1) {
   Bit_node new_node = bit_new(a[i]);
   new_node -> sx = bit_arr2tree(a, size, i*2 +1);
   new_node -> dx = bit_arr2tree(a, size, i*2 +2);
  }
  
  return new_node;
} 

但是在我的实现中,我的树是在不考虑“漏洞”的情况下构建的。有没有办法考虑它们,保持递归策略?

【问题讨论】:

    标签: c algorithm recursion binary-tree


    【解决方案1】:

    鉴于输入数据结构不保证父子关系为i*2+1i*2+2,因此并不真正需要递归解决方案。输入序列表示广度优先顺序,因此以广度优先顺序构建树会更自然。

    附带说明:函数bit_new 还应该初始化sxdx 成员:您不想留下未定义值的那些。

    以下是您编写算法的方法:

    Bit_node bit_new(int n) {
        Bit_node new_node = malloc(sizeof(struct node));
        new_node -> n = n;
        new_node -> sx = NULL;
        new_node -> dx = NULL;
        return new_node;
    }   
    
    
    Bit_node bit_arr2tree(int a[], int size) {
        if (size == 0) {
            return NULL;
        }
        // Create a temporary array to store the node pointers
        Bit_node nodes[size];
        // Create the nodes
        for (int i = 0; i < size; i++) {
            nodes[i] = a[i] == -1 ? NULL : bit_new(a[i]);
        }
        // To link the nodes, use two indexes: parent and child
        for (int child = 1, parent = 0; child < size; child += 2, parent++) {
            // Here we "skip the gaps": a parent cannot be NULL:
            while (nodes[parent] == NULL) {
                parent++;
            }
            nodes[parent] -> sx = nodes[child];
            if (child + 1 < size) {
                nodes[parent] -> dx = nodes[child + 1];
            }
        }
        return nodes[0];
    }
    

    【讨论】:

      【解决方案2】:

      首先,int a[] = {10,4,7,2,3,-1,8,9,-1,2,4,5}; 不应该生成您期望的树,5 作为 8 的左子节点。由于 8 位于索引 6,它的左子节点将位于索引 6 * 2 + 1 == 13。所以你的输入可能应该是int a[] = {10,4,7,2,3,-1,8,9,-1,2,4,-1,-1,5};,在数组末尾有两个额外的-1,将5推到正确的索引。

      您的实现无法工作,因为在模式中:

      {
          Bit_node new_node = malloc(...)
      }
      return new_node;
      

      new_node 不在范围内时被访问。如果遇到 -1,您希望返回 NULL,就像您在数组越界时所做的一样。返回 NULL 表示“这里没有孩子”,这正是您想要与父框架通信的内容,以便它将丢失的孩子设置为 NULL。

      修复应该非常简单:

      Bit_node bit_arr2tree(int a[], int size, int i) {
          if (i>= size || a[i] < 0) {
          //           ^^^^^^^^^^^
              return NULL;
          }
      
          Bit_node new_node = bit_new(a[i]);
          new_node->sx = bit_arr2tree(a, size, i * 2 + 1);
          new_node->dx = bit_arr2tree(a, size, i * 2 + 2);
          return new_node;
      } 
      

      顺便说一句,我会提醒against typedeffing away pointers。这会降低代码的可读性并隐藏信息。

      这是一个可运行的概念证明:

      #include <stdio.h>
      #include <stdlib.h>
      
      struct Node {
          int data;
          struct Node *left;
          struct Node *right;
      };
      
      struct Node *arr2tree(int arr_len, int *arr, int i) {
          if (i >= arr_len || arr[i] < 0) {
              return NULL;
          }
      
          struct Node *node = malloc(sizeof(*node));
          node->data = arr[i];
          node->left = arr2tree(arr_len, arr, i * 2 + 1);
          node->right = arr2tree(arr_len, arr, i * 2 + 2);
          return node;
      }
      
      void print_tree(struct Node *root, int depth) {
          if (root) {
              print_tree(root->right, depth + 4);
      
              for (int i = 0; i < depth; i++) {
                  printf(" ");
              }
      
              printf("%d\n", root->data);
              print_tree(root->left, depth + 4);
          }
      }
      
      void free_tree(struct Node *root) {
          if (root) {
              free_tree(root->left);
              free_tree(root->right);
              free(root);
          }
      }
      
      int main() {
          int a[] = {10,4,7,2,3,-1,8,9,-1,2,4,-1,-1,5};
          struct Node *root = arr2tree(sizeof(a) / sizeof(a[0]), a, 0);
          print_tree(root, 0);
          free_tree(root);
          return 0;
      }
      

      输出:

              8
                  5
          7
      10
                  4
              3
                  2
          4
              2
                  9
      

      【讨论】:

      • 我不明白为什么通过放置 or 条件不会停止对第一个 -1 值的递归:(
      • 确实在第一个 -1 值处停止递归,但仅针对递归的那个分支。每一帧都会产生两个调用——如果一个因为那个孩子不存在而提前返回 NULL(即是 -1 或超出数组的范围),另一个可能会继续递归。您可能想使用调试器并尝试使用具有 3-4 个节点的更简单的树。
      猜你喜欢
      • 2013-11-13
      • 2011-11-24
      • 2015-05-07
      • 1970-01-01
      • 2016-08-15
      • 1970-01-01
      • 2013-04-17
      • 2020-08-24
      • 2016-04-19
      相关资源
      最近更新 更多