Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I made this program but need help in optimizing this algo. It was actually asked in an interview as now I have made it in the best possible way I could I would like to optimize it if there is any chance of doing it.

The input is:

a(b(cd)e(fg)) 

The output should be:

                            a
                           / \
                          b   e
                         / \ / \
                        c  d f  g

My current code is:

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

struct node
{
    char x;
    struct node *left;
    struct node *right;
}*root;

char a[30];
int i=0,n;

void tre(struct node * p) //function that I am using to convert the string to a tree
{
        if(a[i]=='(')
        {
            i++;
            struct node *temp=malloc(sizeof(struct node));
            temp->x=a[i];
            temp->left=temp->right=NULL;
            i++;
            if(p->left==NULL)
            {
                p->left=temp;
                tre(p->left);
            }
            if(a[i]!='('&&a[i]!=')')
            {
                struct node *tempp=malloc(sizeof(struct node));
                tempp->x=a[i];
                i++;
                p->right=tempp;
                tre(p->right);
            }
        }
        else
        if(a[i]==')')
        {
            i++;
        }

}    

void inorder(struct node *p)//inorder traversal of the tree made
{    
    if(p!=NULL)
    {
        inorder(p->left);
        printf("%c ",p->x);
        inorder(p->right);
    }
}

main()
{
    printf("Enter the string : ");
    scanf("%s",a);
    struct node *temp=malloc(sizeof(struct node));
    temp->x=a[i];
    temp->left=temp->right=NULL;
    i++;
    root=temp;
    tre(root);
    inorder(root);
}           
share|improve this question
1  
Optimize for what? With recursion your program will crash (stack overflow) if a very large tree is provided. – Mark Byers Dec 10 '11 at 22:25
@MarkByers : I thought of that but couldn't think of any solution. Is there any other way to handle the problem if large tree is given? – Pankaj Anand Dec 10 '11 at 22:29
You could use an iterative algorithm. – Mark Byers Dec 10 '11 at 22:37
1  
This is not tail recursion so there is no easy way to convert to iteration. Why assume a very large input unless the question is all about large inputs? To convert to iteration, you will need to maintain one or two stack data structures. So then you will eventually run out of heap space anyway, instead of stack space. Recursive structures can be cleaner on an interview answer for reasonable size inputs. – ThomasMcLeod Dec 10 '11 at 23:05
1  
We you asked to do this specifically i C? Possibly the biggest thing you can do to help this code is to do it in C++. – ThomasMcLeod Dec 10 '11 at 23:13
show 9 more comments

migrated from stackoverflow.com Dec 10 '11 at 22:41

2 Answers

up vote 2 down vote accepted

If this was asked at an interview then as the person asking the question I would have expected you to ask a couple of more questions about the input format. What we have here is relatively clear for the simple example but there are some subtitles that come out form this that we need to tease out from the input format.

  • How are NULL branches represented?
  • How are nodes with the value ')' or '(' represented.
  • If we open '(' will there always be two nodes before the ')'

My first problem would be these global variables:

char a[30];
int i=0,n;

Global variables make the code harder to modify and maintain in the long run and should be avoided in most situations. Pass them as parameters and things become much more flexible.

Second point is to declare each variable on its own line (it is much more readable). And try and make the names more meaningful a,i,n hold no meaning so I have no idea what you are going to use them for.

In C I find it usefull to typedef structures to make sure I can use the short version of the name (I have not use C in anger recently so I am not sure if this best practice anymore but I think it makes the code more readable).

typedef struct node
{
    char x;
    struct node *left;
    struct node *right;
} Node;

void tre(struct node * p) //function that I am using to convert the string to a tree

If we are building a tree I would normal expect the return value to be the tree we are building. Not a way of filling out the tree. So I would expect the function signature to look like this:

Node* tre(char const* input)  // potentially more parameters to deal with position.

I find the logic in you main function very hard to follow. You only seem to make nodes if there is an open brace '(' that does not seem correct. You do nothing when there is a close brace? You test if the left on the current node is null but not the right on the current node. I would expect the code to be inherently more symmetrical. The fact that it is not makes it harder to follow.

As an interviewer the things I would have looked for:

  • Error checking:
  • Binary tree code is inherently symmetrical. Notice that below.
    Doing the left and right branches should look the same.
  • the function that parses the input should work on one node:
    You seem to work on one node and part of the next.

I wrote the code and min looks like this:
(Now that I have written it looks identical to Winston)

Node* parseTree(char const* data, size_t* pos)
{
    if (data[(*pos)] == '\0')
    {   // Appropriate error msg
        exit(1);
    }

    // Allocate the tree here. (initialize all members)
    Node*   result  = malloc(sizeof(Node));
    result->value   = data[(*pos)++];
    result->left    = NULL;
    result->right   = NULL;

    // Now check for sub branches.
    if (data[(*pos)] == '(')
    {
        // Move past the '('
        (*pos)++;

        result->left    = parseTree(data, pos);
        result->right   = parseTree(data, pos);

        if ((*pos) != ')')
        {   // Appropriate error msg
            exit(1);
        }
        // Move past the ')'
        (*pos)++;
    }
    // Done.
    return result;
}
Node* buildTree(char const* data)
{
    if (data == NULL)
    {   // Appropriate error msg
        exit(1);
    }
    size_t  pos = 0;
    return parseTree(data, &pos);
}

Perfect in-order traversal of the tree.

But it does not print out what the output should be:

                        a
                       / \
                      b   e
                     / \ / \
                    c  d f  g

To print this you need a couple of things:

  • The depth of the tree.
  • The max width (related to max depth)
  • A breadth first way of printing the tree.

Note: If I was doing the interview I would ask this to make sure you could do a breadth first traversal of the tree. Which involves using a loop rather than recursion.

share|improve this answer
Thanks for the answering, leant some impotant things. – Pankaj Anand Dec 12 '11 at 0:07
a : array where the string is stored. i : is the position tracker on a particular node while parsing it. – Pankaj Anand Dec 12 '11 at 0:08
Yes: a and i may have meaning to you. But think about the person that needs to read the code in 10 years time. a and i have no meaning. Identifier names should be self explanatory (even more so if they are global). – Loki Astari Dec 12 '11 at 2:09
void tre(struct node * p) //function that I am using to convert the string to a tree
{
        if(a[i]=='(')
        {

I recommend not using such short variable names

            i++;
            struct node *temp=malloc(sizeof(struct node));
            temp->x=a[i];
            temp->left=temp->right=NULL;

You basically repeat these three lines three times. If you instead do this at the beginning of tre you can avoid the duplication.

            i++;
            if(p->left==NULL)

Given the way your code is structured, won't p->left always be null? The value passed to tre is always a freshly created node

            {
                p->left=temp;
                tre(p->left);
            }
            if(a[i]!='('&&a[i]!=')')

Why do you need to check for this? Wouldn't this indicate an invalid input? If so, perhaps you should report the error somehow.

            {
                struct node *tempp=malloc(sizeof(struct node));
                tempp->x=a[i];
                i++;
                p->right=tempp;
                tre(p->right);
            }

        }
        else
        if(a[i]==')')
        {
            i++;
        }

Again, in what situation will this be called?

}    

How I'd approach that function

stuct node * tre()
{ 
     struct node * node = malloc(sizeof(struct node));
     node->x = a[i++];
     if(a[i] == '(')
     {
          node->left = tre();
          node->right = tre();
          assert(a[i++] == ')');
     }
     else
     {
          node->left = node->right = NULL;
     }
     return node;
}

Unless I'm missing something, your example output and code do not match. So I'm not going to comment on that.

share|improve this answer
Thanks for the answer learnt some things from ur answer but I need to point out that whenever ')' occurs is not the error its just says that the function on this node is finished, we will have to go one level up in tree to check for the next child. – Pankaj Anand Dec 12 '11 at 0:06

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.