使用递归策略将数组转换为二叉树

Posted

技术标签:

【中文标题】使用递归策略将数组转换为二叉树【英文标题】: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;
 

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

【问题讨论】:

【参考方案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 个节点的更简单的树。

以上是关于使用递归策略将数组转换为二叉树的主要内容,如果未能解决你的问题,请参考以下文章

树二叉树森林之间的转换

java编写非递归与递归创建有序的二叉树

二叉树二叉树基本操作通用接口

Leetcode练习(Python):树类:第108题:将有序数组转换为二叉搜索树:将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的

编程将二叉树(子女右兄弟链)转换为树然后将树转换为二叉树(直接修改) 非递归实现

平衡二叉树---将有序数组转换为二叉搜索树