как построить двоичное дерево из обходов предзаказа и inorder

Я выполняю задание по построению двоичного дерева из предзаказа и обхода inorder (символ в каждом узле), и я пытаюсь обернуть свой мозг вокруг того, как построить фактическое дерево.

вот мой мыслительный процесс о том, как добиться этого:

  1. сохраните первую запись в предзаказе как корневой узел
  2. поиск inorder для этой записи.
  3. возьмите символы слева от корневого узла и сохраните их как символ матрица.
  4. возьмите символы справа от корневого узла и сохраните их как массив символов.
  5. создать новое дерево с корнем в качестве родителя и 2 детей левой и правой char массивы.
  6. продолжайте рекурсивно, пока длина предзаказа не будет равна 0.

У меня есть шаги 1-4, но я не слишком уверен, как правильно построить мое дерево, и было интересно, есть ли у кого-нибудь указатели. Спасибо.

5 ответов


выполните рекурсию перед построением нового дерева. Итак, ваш список будет выглядеть так:

  1. если массивы имеют длину 1, просто верните листовой узел с этим единственным элементом в нем. (Это основа рекурсии.) (O (1))
  2. сохраните первую запись в массиве предзаказа в качестве корневого узла. (O (1))
  3. Поиск массива inorder для этой записи. (O (n))
  4. возьмите символы слева от корня узел в массиве inorder и сохраните их как массив char. Возьмите такое же количество символов из массива предзаказа (после корня). (O(n) или O (1), когда просто бросают указатели/индексы вокруг.)
  5. возьмите символы справа от корневого узла и сохраните их как массив символов. Возьмите такое же количество символов из массива предзаказа (после первой части – это должна быть только оставшаяся часть). (O (n) или O (1), когда просто бросают указатели / индексы вокруг.)
  6. рекурсивно создайте дерево из обоих левых массивов символов.
  7. рекурсивно создайте дерево из обоих правых массивов символов.
  8. объединить оба дерева с корневым узлом. (O (1).)

нерекурсивные части могут быть выполнены в o(n) в целом, и суммирование их для каждого уровня рекурсии также O(n) каждый. Таким образом, общее время выполнения зависит от количества уровней рекурсии. Если у вас есть приблизительно сбалансированное дерево, глубина является O(log n), таким образом, мы получаем O (N · log n) вообще. Поскольку единственная обязательно медленная часть-это поиск корневого узла в массиве inorder, я думаю, мы могли бы оптимизировать это еще немного, если бы мы знали больше о дереве.

в худшем случае у нас есть один уровень рекурсии для каждого узла в дереве, доходящий до сложности O(n·n).

пример: предварительный заказ ABCDEF, Inorder FEDCBA, Tree:

                                   +---+
                                   | A |
                                   ++--+
                                    |
                            +---+   |
                            | B +<--+
                            ++--+
                             |
                     +---+   |
                     | C +<--+
                     ++--+
                      |
              +---+   |
              | D +<--+
              ++--+
               |
       +---+   |
       | E +<--+
       ++--+
        |
+---+   |
| F +<--+
+---+

посмотреть мои ответ этой вопрос. Дерево строится путем добавления узлов в последовательности предварительного заказа, но с использованием позиции inorder в качестве компаратора.


вы можете использовать ниже код, я просто написал для той же проблемы. Это работает на меня.

public class TreeFromInorderAndPreOrder {

public static List<Integer> inOrder = new ArrayList<Integer>();
public static List<Integer> preOrder = new ArrayList<Integer>();

public static void main(String[] args) {

    Node root = new Node();
    root.createRoot(5);
    for(int i = 0 ; i < 9 ; i++){
        if(i != 5){
            root.insert(i);
        }
    }

    inOrder(root);
    preOrder(root);
    for(Integer temp : inOrder){
        System.out.print(temp +  " ");
    }

    System.out.println();
    for(Integer temp : preOrder){
        System.out.print(temp + " ");
    }

    Node node1 = null;
    node1 = reConstructTree(root, (ArrayList<Integer>) inOrder, true);

    System.out.println();
    inOrder(node1);
    for(Integer temp : inOrder){
        System.out.print(temp +  " ");
    }

    System.out.println();

    for(Integer temp : preOrder){
        System.out.print(temp + " ");
    }

}

public static void inOrder(Node node){

    if(node!= null){
        inOrder(node.leftchild);
        inOrder.add(node.key);
        inOrder(node.rightChild);
    }

}

public static void preOrder(Node node){

    if(node != null){
        preOrder.add(node.key);
        preOrder(node.leftchild);
        preOrder(node.rightChild);
    }

}

public static Node reConstructTree(Node root, ArrayList<Integer> inOrder, 
    boolean  isLeft){

    if(preOrder.size() != 0 && inOrder.size() != 0){
        return null;
    }

    Node node = new Node();
    node.createRoot(preOrder.get(0));
    if(root != null && isLeft){
        root.leftchild = node;          
    }else if(root != null && !isLeft){
        root.rightChild = node;
    }
    int indx = inOrder.get(preOrder.get(0));
    preOrder.remove(0);
    List<Integer> leftInorder = getSublist(0, indx);
    reConstructTree(node, (ArrayList<Integer>) leftInorder, true);
    List<Integer> rightInorder = getSublist(indx+1, inOrder.size());
    reConstructTree(node, (ArrayList<Integer>)rightInorder, false);
    return node;

}

public static ArrayList<Integer> getSublist(int start, int end){
    ArrayList<Integer> list = new ArrayList<Integer>();
    for(int i = start ; i < end ; i++){
        list.add(inOrder.get(i));
    }

    return list;
}
}

Я написал пример программы с использованием подхода divide and conquer с использованием рекурсии в java

import java.util.LinkedList;
import java.util.Queue;

public class BinaryTreeNode {

private char data;
public char getData() {
    return data;
}
public void setData(char data) {
    this.data = data;
}
public BinaryTreeNode getLeft() {
    return left;
}
public void setLeft(BinaryTreeNode left) {
    this.left = left;
}
public BinaryTreeNode getRight() {
    return right;
}
public void setRight(BinaryTreeNode right) {
    this.right = right;
}
private BinaryTreeNode left;
private BinaryTreeNode right;

public static void levelTravesal(BinaryTreeNode node)
{
    Queue queue = new LinkedList();

    if(node == null)
        return;
    queue.offer(node);
    queue.offer(null);
    int level =0;
    while(!queue.isEmpty())
    {
        BinaryTreeNode temp = (BinaryTreeNode) queue.poll();

        if(temp == null)
        {
            System.out.println("Level: "+level);
            if(!queue.isEmpty())
                queue.offer(null);
            level++;
        }else {

        System.out.println(temp.data);

        if(temp.getLeft()!=null)
            queue.offer(temp.getLeft());

        if(temp.getRight()!=null)
            queue.offer(temp.getRight());
        }

    }
}

static int preIndex = 0;

public static void main(String[] args) {

    if(args.length < 2)
    {
        System.out.println("Usage: preorder inorder");
        return;
    }

    char[] preOrderSequence = args[0].toCharArray();
    char[] inOrderSequence = args[1].toCharArray();

    //char[] preOrderSequence = {'A','B','D','E','C','F'};
    //char[] inOrderSequence = "DBEAFC".toCharArray();

    if(preOrderSequence.length != inOrderSequence.length)
    {
        System.out.println("Pre-order and in-order sequences must be of same length");
        return;
    }

    BinaryTreeNode root = buildBinaryTree(preOrderSequence, inOrderSequence, 0, preOrderSequence.length-1);

    System.out.println();
    levelTravesal(root);


}

static BinaryTreeNode buildBinaryTree(char[] preOrder, char[] inOrder, int start, int end)
{
    if(start > end)
        return null;
    BinaryTreeNode rootNode = new BinaryTreeNode();
    rootNode.setData(preOrder[preIndex]);
    preIndex++;
    //System.out.println(rootNode.getData());
    if(start == end)
        return rootNode;
    int dataIndex = search(inOrder, start, end, rootNode.getData());
    if(dataIndex == -1)
        return null;
    //System.out.println("Left Bounds: "+start+" "+(dataIndex-1));
    rootNode.setLeft(buildBinaryTree(preOrder, inOrder, start, dataIndex - 1));
    //System.out.println("Right Bounds: "+(dataIndex+1)+" "+end);
    rootNode.setRight(buildBinaryTree(preOrder, inOrder, dataIndex+1, end));
    return rootNode;
}


static int search(char[] inOrder,int start,int end,char data)
{
    for(int i=start;i<=end;i++)
    {
        if(inOrder[i] == data)
            return i;
    }
    return -1;

}

}

вот математический подход для достижения вещи очень упрощенным способом:

используемый язык: Java

`
/* Алгоритм построения двоичного дерева из заданных обходов Inorder и Preorder. Ниже используется терминология:

i: представляет массив inorder, поставляемый

p: представляет массив предзаказа, поставляемый

beg1: начальный индекс массива inorder

beg2 : начиная индекс массива предзаказа

end1: конечный индекс массива inorder

end2: конечный индекс массива предзаказа

*/

публичный статический пустота constructTree(корневой узел, инт[] я, инт[] Р, инт beg1, конец1 инт, инт beg2, инт end2)

{

if(beg1==end1 && beg2 == end2)
{
    root.data = i[beg1];
}
else if(beg1<=end1 && beg2<=end2)
{
    root.data = p[beg2];
    int mid = search(i, (int) root.data);
    root.left=new Node();
    root.right=new Node();
    constructTree(root.left, i, p, beg1, mid-1, beg2+1, beg2+mid-beg1);
    System.out.println("Printing root left : " + root.left.data);
    constructTree(root.right, i, p, mid+1, end1, beg2+1+mid-beg1, end2);
    System.out.println("Printing root left : " + root.right.data);
}

}

`

вам нужно вызвать функцию следующим кодом:

int[] i ={4,8,7,9,2,5,1,6,19,3,18,10}; //Inorder
int[] p ={1,2,4,7,8,9,5,3,6,19,10,18}; //Preorder
Node root1=new Node();
constructTree(root1, i, p, 0, i.length-1, 0, p.length-1);

в случае, если вам нужно более подробное объяснение кода пожалуйста упомяните об этом в комментариях. Буду рад помочь :).