carrayssortingbinary-treebsp-tree

Difficulty Constructing Binary Tree from Array


I am trying to build a binary tree from an unsorted float array for an assignment, but I cannot quite figure it out. My goal is to send the unsorted array xdata of size ndata to the function build_tree(), which creates a new node using the function create_node(). In the case that the array size is greater than 1, it will call the function paritition_data() (which works fine, but I've placed it at the bottom of the question for reference), which will swap the order of array values so that all values less than mid fall on its left, and greater values to its right. The function returns nleft, the number of values on the left of mid. I then want to recursively call partition_data() to create new left and right child nodes. I think it is at this step that my program seems to fail, and despite it compiling, the program seems to recursively call partition_data() infinitely, and I'm not sure why. I appreciate any help.

typedef struct treenode_struct {
  int n;
  float data;
  struct treenode_struct *left, *right;
} treenode;

treenode *create_node( ) {
  treenode *node;

  node = malloc(sizeof(treenode));
  if (node == NULL) {
    printf("Allocate Failed");
    exit(-1);
  }
  node->n = 0;
  node->right = NULL;
  node->left = NULL;

  tree_nodes++;

  return node;
}

treenode *build_tree( float xdata[], int ndata, float xmin, float xmax ) {
  treenode *node;
  int nleft;
  float mid = (xmin+xmax)/2.;

  node = create_node();
  node->n = ndata;
  if (ndata == 1) {  // Add code for this case
    node->data = xdata[0]; 
    node->left = NULL;
    node->right = NULL;
    return node;
  }
  if (ndata == 0){
    printf("Allocate failed\n");
    exit(-1);
  }
 // More than one data point: use partition function
  if (ndata > 1) {
    nleft = partition_data(xdata,ndata,mid);
    int nright = ndata-nleft;

    // Add code to make a left child
    if(nleft != 0){
      node->left=build_tree(xdata,nleft,xmin,xdata[nleft-1]);
    }
    else{
      node->left = NULL;
    }

    // Add code to make a right child
    if(nright != 0){
      node->right=build_tree(xdata,nright,xdata[nleft],xmax);
    }
    else{
      node->right = NULL;
    }
    return node;
  }
}

int tree_nodes;

int main() {
  const int ndata = 16;
  float xdata[] = { 0.963,  0.003, 0.0251, 0.353, 0.667, 0.838, 0.335, 0.915,
            0.796, 0.833, 0.345, 0.871, 0.089, 0.888, 0.701, 0.735 };
  int i;
  float xmiddle = 0.5;
  printf("Input data:\n");
  for (i=0;i<ndata;i++) printf("%f ",xdata[i]);
  printf("\n");

 treenode *tree_root;
  float tree_xmin, tree_xmax;
  tree_nodes = 0;

  tree_xmin = 0;
  tree_xmax = 1;
  tree_root = build_tree( xdata, ndata, tree_xmin, tree_xmax );
  printf("Tree Built: nodes %d\n",tree_nodes);

  printf("Tree Ordered data:\n");
  for (i=0;i<ndata;i++) printf("%f ",xdata[i]);
  printf("\n\n");
}

Here is partition_data():

int partition_data( float xdata[], int ndata, float xmiddle ) {

  // Your code goes here
  int left = 0;
  int right = ndata-1;
  float temp;
  while(left < ndata){  //left loop
    if(xdata[left] < xmiddle){
      if(left == right){
    return left+1;
    break;
      }//DONE
      left = left + 1;
    }
    else{
      while(right<ndata){ //right loop, search for swappable Xright
    if(xdata[right] >= xmiddle){//X[right] is greater than/equal to xmiddle
      if(left == right){
        return left;
        break;
      }
      right=right-1;
    }
    else{ //found X[right] to swap
      temp = xdata[left];
      xdata[left] = xdata[right];//swap
      xdata[right]=temp;
      right = right-1;
      if(left == right) {
        return left+1;
        break;
      }
      left=left+1;
      break;
    }
    break;
      }
    }
  }

Solution

  • Your recursion problem is caused by the creation of your right node.
    You create the right node with this code:

    // Add code to make a right child
    if(nright != 0){
      node->right=build_tree(xdata,nright,xdata[nleft],xmax);
    }
    else{
      node->right = NULL;
    }
    

    Now if you look at your build_tree function what you have is:

    treenode *build_tree( float xdata[], int ndata, float xmin, float xmax )
    

    Let's interprete it as:

    create a tree from the array xdata[] where all elements are greater than xmin and less than xmax

    Now don't see xdata[] as array xdata[] but see xdata as the pointer to the first element I have to process. This will (hopefully) help you understand it a little bit (and is actually what it is, it is just a pointer). In your code to create the right node you use:

     node->right=build_tree(xdata,nright,xdata[nleft],xmax);
    

    but there you actually insert as right node the root of the tree that will be created by processing the data starting at the first element of your array. That's not the slice of the array you want. The slice you want to have in your right node is the right part of the array so the part that starts at index ndata-nright. So if you want to change the begin of an array, you just add the index to the pointer of the array. So in your case xdata + (ndata-nright) will represent an array that starts at element ndata-nright (or pointer to that element). So you should have:

      node->right=build_tree(xdata + (ndata-nright),mid,xdata[nleft],xmax);
    

    to create your right node!