Как построить неполное бинарное дерево из представления массива

если вход представляет собой массив, где null означает отсутствие узла.

Вход:

[1, 2, 3, null, 5, null, 7]

Предположим, что я уже проверил ввод.

Для каждого array[i] его родители array[i / 2] не будут null (рекурсивно, поэтому root не может быть null).

Как построить дерево с такой логической связью:

   1
 /    \
2      3
 \      \ 
  5      7

каждый узел должен быть представлен объектом TreeNode:

class TreeNode {
public:
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

Я нашел здесь блог, где полное дерево был построен

но если дерево неполное, как упоминалось выше, как это сделать аккуратно и эффективно?

Данные испытаний:

[входной массив]

[-64,12,18,-4,-53,null,76,null,-51,null,null,-93,3,null,-31,47,null,3,53,-81,33,4,null,-51,-44,-60,11,null,null,null,null,78,null,-35,-64,26,-81,-31,27,60,74,null,null,8,-38,47,12,-24,null,-59,-49,-11,-51,67,null,null,null,null,null,null,null,-67,null,-37,-19,10,-55,72,null,null,null,-70,17,-4,null,null,null,null,null,null,null,3,80,44,-88,-91,null,48,-90,-30,null,null,90,-34,37,null,null,73,-38,-31,-85,-31,-96,null,null,-18,67,34,72,null,-17,-77,null,56,-65,-88,-53,null,null,null,-33,86,null,81,-42,null,null,98,-40,70,-26,24,null,null,null,null,92,72,-27,null,null,null,null,null,null,-67,null,null,null,null,null,null,null,-54,-66,-36,null,-72,null,null,43,null,null,null,-92,-1,-98,null,null,null,null,null,null,null,39,-84,null,null,null,null,null,null,null,null,null,null,null,null,null,-93,null,null,null,98]


person Shihao Xu    schedule 21.06.2016    source источник
comment
Можно ли использовать специальные значения (например, -1 в вашем примере) для хранения нулей (пустых узлов)?   -  person karastojko    schedule 21.06.2016
comment
Не совсем уверен, чего вы пытаетесь достичь здесь   -  person Nick Zuber    schedule 21.06.2016
comment
Я полагаю, что он пытается представить дерево с помощью массива и нашел блог, в котором показан пример с полным деревом, поэтому ему интересно, как это сделать, когда дерево не завершено.   -  person karastojko    schedule 21.06.2016
comment
Будут ли у вас узлы выходить за пределы нулевых узлов? Или вы хотите, чтобы эти нулевые узлы были точками остановки для этой ветви?   -  person Mr. DROP TABLE    schedule 21.06.2016
comment
отредактировал мой вопрос, чтобы быть более ясным. Теперь ввод можно рассматривать как строку. После его разделения, если элемент может быть преобразован в значение int, создается узел. В противном случае пропустите.   -  person Shihao Xu    schedule 21.06.2016
comment
null означает, что узел не создан в этой логической позиции, ветвь останавливается там.   -  person Shihao Xu    schedule 21.06.2016
comment
как будет выглядеть дерево, если ввод будет [null, 2, 3, 4, 5, 6, 7]?   -  person Mr. DROP TABLE    schedule 21.06.2016
comment
Предположим, что я уже проверил ввод. Для каждого array[i] его родителиarray[i / 2] не будут null (рекурсивно, поэтому корень не должен быть null).   -  person Shihao Xu    schedule 22.06.2016


Ответы (4)


При реализации бинарного дерева в виде массива полезно иметь четкую визуализацию того, как два представления отражают друг друга, и просматривать математическую структуру, которая подчеркивает взаимосвязь.

Если мы рассмотрим массивы с индексом 0, математическое отношение можно разбить как таковое,

  • Корневой узел имеет индекс 0

Для узла i:th (i — это индекс массива) у нас есть это (проверьте)

  • Левый дочерний элемент узла имеет индекс 2i + 1
  • Правый дочерний узел имеет индекс 2(i + 1)
  • Родитель узла имеет индекс floor((i-1)/2)

Итак, для бинарного дерева

Бинарное дерево

если мы позволим - обозначать null, будет представлен как таковой

[0:a, 1:b, 2:c, 3:d, 4:e, 5:-, 6:-, 7:-, 8:-, 9:g, 10:-, 11:-, 12:-, 13:-, 14:-]

Итак, теперь, чтобы создать объектно-ориентированное представление из массива, вы просто применяете эти правила индексации. Итак, поскольку вы знаете, что корневой узел a, мы получаем его потомков по адресу:

  • Слева: 2*0 + 1 = 1 => b
  • Справа: 2*(0 + 1) = 2 => c

Псевдокод

for (int idx = 0; 2*(idx + 1) < len(arr); idx++) {
    if (arr[idx] == null) {
        // There is no node to add for this index
        continue;
    }

    TreeNode t = null;

    if (idx == 0) {
        // Root node case
        t = TreeNode(val: arr[idx]);
        binary_tree.add(id: idx, node: t);
    }

    // We do not know if these exist yet
    int left_idx = 2*idx + 1; 
    int right_idx = 2*(idx + 1);

    if (left_idx >= len(arr)) {
        // left_idx is out of bounds with respect to the array, 
        // and by extension so would the right node be
        continue;
    }

    TreeNode left = null;
    TreeNode right = null;

    if (arr[left_idx] != null) {
        // This node has never been encountered before
        // and it is non-null so it must be created.
        //
        // Since we know we have a root node then there is
        // no need to check if the tree already contains this
        // node, it simply is not possible. Ditto for the right
        // node.
        left = TreeNode(val: arr[left_idx]);
        binary_tree.add(id: left_idx, node: left);
    }

    if (right_idx >= len(arr)) {
        // There cannot be a right child
        continue;
    }

    if (arr[right_idx] != null) {
        // This node has never been encountered before
        // and it is non-null so it must be created.
        right = TreeNode(val: arr[right_idx]);
        binary_tree.add(id: right_idx, right);
    }

    // It does not matter if left or right is null
    t.set_left(left)
    t.set_right(right)    
}
person Filip Allberg    schedule 26.06.2016

Я думаю, что этот пример может объяснить, что у вас на уме.

array : [5,4,8,11,null,17,4,7,null,null,null,5]
Tree : 

                      5
                     /  \
                    4    8
                   /    / \
                  11   17  4
                 /        /
                7        5

Все приведенные выше ответы относятся к входному массиву как к полному дереву. Таким образом, left.child=2idx+1 , right.child = 2idx+2, но на самом деле это неправильно. потому что те

[5,4,8,11,null,17,4,7,null,null,null,5]
[5,4,8,11,null,17,4,7,null,null,null,null,null,5,null]

разные

вот мое решение

public static TreeNode createTree(Integer[] array) {
    if (array == null || array.length==0) {
        return null;
    }

    Queue<TreeNode> treeNodeQueue = new LinkedList<>();
    Queue<Integer> integerQueue = new LinkedList<>();
    for (int i = 1; i < array.length; i++) {
        integerQueue.offer(array[i]);
    }

    TreeNode treeNode = new TreeNode(array[0]);
    treeNodeQueue.offer(treeNode);

    while (!integerQueue.isEmpty()){
        Integer leftVal = integerQueue.isEmpty() ? null : integerQueue.poll();
        Integer rightVal = integerQueue.isEmpty() ? null : integerQueue.poll();
        TreeNode current = treeNodeQueue.poll();
        if (leftVal !=null) {
                TreeNode left = new TreeNode(leftVal);
                current.left = left;
                treeNodeQueue.offer(left);
        }
        if (rightVal !=null){
                TreeNode right = new TreeNode(rightVal);
                current.right = right;
                treeNodeQueue.offer(right);
        }
    }
    return treeNode;
}
person Steven    schedule 11.06.2019
comment
ах здорово! именно то, что я ищу! Спасибо - person Christie Chen; 22.04.2021

Просто используйте рекурсию для обхода узлов, используя индекс массива, и используйте Integer, чтобы разрешить нуль.

private TreeNode array2Tree(Integer[] data,TreeNode root, int index){

    if(index >= data.length){
      return root;
    }

    if(data[index] != null){
      TreeNode temp =  new TreeNode(data[index]);
      root = temp;
      root.left = array2Tree(data,root.left,2*index+1);
      root.right = array2Tree(data,root.right,2*index+2);
    }

    return root;
}
person akshay padmanabhan    schedule 09.12.2017
comment
Нет. Это не сработает. Это позволило бы создать поддерево из корневого узла, который является нулевым, а это не то, о чем просил OP. - person Louis Duran; 26.04.2020

В Java:

public class TreeNode {
    public int val;
    public TreeNode left;
    public TreeNode right;
    public TreeNode() {}
    public TreeNode(int val) { this.val = val; }
    public TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }

    /**
     * Create a tree from array using levels i.e {-2,3,4,null,null,5,null,null,null,null,null, 6 } becomes 2 le-> 3, 2 re->4, 4 le->5, 5 le->6
     * @param arr the arr to be converted to a tree
     * @return
     */
    public static TreeNode createTreeFromArray(Integer[] arr){
        TreeNode root = new TreeNode();
        return  insertLevelOrder(arr, root, 0);
    }


    static TreeNode insertLevelOrder(Integer[] arr, TreeNode root,
                                 int i)
    {

        // Base case for recursion
        if (i < arr.length) {
            if(arr[i] == null)
                return null;
            TreeNode temp = new TreeNode(arr[i]);
            root = temp;

            // insert left child
            root.left = insertLevelOrder(arr, root.left,
                     2* i + 1);

            // insert right child
            root.right = insertLevelOrder(arr, root.right,
                     2* i + 2);
        }
        return root;
    }
}
person Snedden27    schedule 17.05.2021