简体   繁体   中英

how to make Binary Tree from inorder and preorder traversals

Here is the full question:

Write a function that gets two arrays of length n. The first array is the PreOrder some binary tree and the second array is the InOrder of the binary tree. The functions outputs the binary tree.

// the function recovers the tree from its inorder and preorder
BTnode_t* reconstruct_tree( int * preorder, int * inorder, int n)

given struct and functions:

struct BTnode {
   int value;
   struct BTnode* left;
   struct BTnode* right;
   struct BTnode* parent;
};
typedef struct BTnode BTnode_t;

BTnode_t* create_node(int val) {
    BTnode_t* newNode = (BTnode_t*) malloc(sizeof(BTnode_t));
    newNode->value = val;
    newNode->left = NULL;
    newNode->right = NULL;
    newNode->parent = NULL;

    return newNode;
}

My implementation of how to solve this problem, It is currently not working and I think my error is in how I send the indices in my recursive step.

#include <stdio.h>
#include <stdlib.h>


#include "assignment4.h"

int search(int arr[], int strt, int end, int value);

int search(int arr[], int strt, int end, int value) 
{ 
    int i; 
    for (i = strt; i <= end; i++) { 
        if (arr[i] == value) 
            return i; 
    } 
} 

// the function recovers the tree from its inorder and preorder
BTnode_t* reconstruct_tree(int* preorder, int* inorder, int n) {
  // implement me
    int preIndex = 0;

  BTnode_t* newnode = create_node(preorder[preIndex]);

  preIndex++;


  if( sizeof(inorder) > n-1)
    return NULL;

  if( sizeof(inorder) == n-1)
    return newnode;

  int inIndex = search( inorder, 0, n - 1, newnode->value);

  newnode->left = reconstruct_tree(preorder, inorder, inIndex -1);
  newnode->right = reconstruct_tree(preorder, inorder + inIndex +1, n-1 );

  return newnode;

}

The code used to test this part of the assignment:

#include <stdio.h>
#include <stdbool.h>
#include <string.h>

#include "assignment4.h"



bool BT_equal(BTnode_t* t1, BTnode_t* t2) {
  if (t1 == t2)
    return true;
  if ((t1 && !t2) || (!t1 && t2))
    return false;
  return (t1->value == t2->value) && BT_equal(t1->left, t2->left) && BT_equal(t1->right, t2->right);
}

BTnode_t* create_my_tree() {
  BTnode_t* n1 = create_node(1);
  BTnode_t* n2 = create_node(2);
  BTnode_t* n3 = create_node(3);
  BTnode_t* n4 = create_node(4);
  BTnode_t* n5 = create_node(5);
  BTnode_t* n6 = create_node(6);
  BTnode_t* n7 = create_node(7);

  n1->parent = NULL;

  n1->left = n2;
  n2->parent = n1;

  n1->right = n3;
  n3->parent = n1;

  n2->left = n4;
  n4->parent = n2;
  n4->left = NULL;
  n4->right = NULL;

  n2->right = n5;
  n5->parent = n2;
  n5->left = NULL;
  n5->right = NULL;

  n3->left = n6;
  n6->parent = n3;
  n6->left = NULL;
  n6->right = NULL;

  n3->right = n7;
  n7->parent = n3;
  n7->left = NULL;
  n7->right = NULL;

  return n1;
}



bool test_q1() {
  BTnode_t* n1 = create_my_tree();

  int preorder[] = {1,2,4,5,3,6,7};
  int inorder[] = {4,2,5,1,6,3,7};
  BTnode_t* tree = reconstruct_tree(preorder, inorder, 7);

  if (BT_equal(tree, n1))  {
    printf("Q1 - ok\n");
    return true;
  }
  else {
    printf("Q1 - error\n");
    return true;
  }
}

I understand the algorithm visually.I have thought long and hard about it, and I think I am sending my indices correctly.

My question: Am I making the recursive call incorrectly? I think sizeof() is returning me the what sizeof(int) would return for example, how should i do this correctly? Could anyone please point me in the right direction? Or point out any glaring issues?

Thank you in advance!

important edit

I got it working - here is the correct code

BTnode_t* reconstruct_tree(int* preorder, int* inorder, int n) {
  // implement me
    static int preIndex = 0;

  BTnode_t* newnode = create_node(preorder[preIndex]);

  preIndex++;


  if (n<=1){
    return newnode;
  }

  int inIndex = search( inorder, 0, n - 1, newnode->value);

  newnode->left = reconstruct_tree(preorder, inorder, inIndex);
  newnode->right = reconstruct_tree(preorder, inorder + inIndex +1, n - inIndex -1 );

  return newnode;

}

But I still do not understand why the recursive call works, can someone please explain how the recursion is happening

Well, the first thing to say is that there's a simple remap on the sequences given that allows you to construct the tree from the inorder sequence, based only on the fact that the remapping only complicates things, without adding anything helpful to the problem. So I'll do the following simplification to the problem description:

  • the preorder list is the sequence of the numbers 0... N-1 in ascending order.
  • as the preorder sequence visits each node once and only once, there's a biyective mapping between the numbers of the preorder sequence and the sequence 0...N-1.
  • as the mapping is biyective, there's an inverse mapping that allows to get a new inorder sequence as a result of applying the inverse mapping to the numbers of the inorder sequence. This results in a new inorder sequence that maps to the same tree, as both sequences are equivalent now.
  • this allows to forget the preorder sequence and, instead of searching for a number, to search for the minimum of the set.
  • This solves a more general problem, but equivalent when the set of sequences of inorder nodes is compatible with a valid preordering of the preorder sequence.

The set of preorder sequences is not always compatible with the given inorder sequence.

Proof: Lets asume the building process of a tree from an inorder sequence (assuming the preorder sequence is the ordered set of numbers 0..N-1) in that case, for each node that is a root of some subtree, the minimum of the ids of that tree should be the root at the subtree... and the minimum+1 should be the subtree of its left node, except in the case of an empty left subtree. Let's represent this fact with the following notation:

                  (n)
                 /   \
[lllllll(n+1)llll]   [rrrrrrrr]

and (n+1) will only be at the right partition in case the left partition is empty:

  (n)
 /   \
*    [rrrrrrrr(n+1)rrrrrrrrrrr]

So, in case the inorder sequence has a nonempty left subtree, and the (n+1) element in preorder is after (n) in the sequence, it will be impossible to build a tree in which the preorder sequence is valid. This manifests in your code with the fact that the searched item is not present in the left subtree, being it non-empty. My solution, as it finds the minimum, just always gives a solution with a tree that is not valid preorder, but in which all the nodes have been inserted in ascending order, attaching them into an already present node. When that order is a valid preorder, then both algorithms give the same result.

I'll give you a solution that explores the array of inorder nodes, dividing it at the point it encounters the minimum id value (which should be the root of the subtree) and applies the algorithm again to the arrays representing the left subtree and the right subtree. The algorithm attaches the created node to the passed parent node, and returns the root of the matching tree:

build.c

#include <assert.h>
#include <stdlib.h>

#include "node.h"

struct node *build(const unsigned *l, int sz, struct node *parent)
{
    if (sz == 0) return NULL;

    struct node *res = malloc(sizeof *res);
    assert(res != NULL);

    int i, im = -1;
    unsigned m = ~0;
    for (i = 0; i < sz; i++) {
        const unsigned c = l[i];
        if (c < m) {
            m = c;
            im = i;
        }
    }
    assert (im >= 0 && im < sz);

    res->id     = m;
    res->parent = parent;
    res->left   = build(l, im, res);
    res->right  = build(l + im + 1, sz - im - 1, res);

    return res;
}

A whole solution or this algorithm, which prints the tree (renumbered in order to produce the valid inorder sequence that matches a valid canonical preorder one, for the same tree ---which allows to produce valid sequences of inorder/preorder datasets) is given in github .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM