0

I'm learning about Binary search tree. I'm writing a search function where it recursively returns 1 if it finds the number, otherwise 0. The problem is I have put an assertion where it is activated if it can not find the correct number. What is it that I am doing wrong?

BSTree tree = emptyTree();
    assert(isEmpty(tree));

    // Insert 7 elements into the tree
    int arr[7] = { 5,10,1,3,7,18,20 }, i;
    for (i = 0; i < 7; i++)
    {
        insertSorted(&tree, arr[i]);
    }

    for (i = 0; i < 7; i++)
    {
        // Verify that all elements are in the tree
        assert(find(tree, arr[i]));
    }
    assert(!find(tree, 18)); //Here the assert is activated
    assert(!find(tree, 5));

Here is my code for the search function

int find(const BSTree tree, int data)
{
    if (data == tree->data)
        return 1;
    if (data < tree->data)
        return find(tree->left, data);
    if (data > tree->data)
        return find(tree->right, data);
    else
        return 0;
}

void insertSorted(BSTree *tree, int data)
{
    if (*tree == NULL)
    {
        *tree = createNode(data);
    }
    else if (data < (*tree)->data)
    {
        insertSorted(&(*tree)->left, data);
    }
    else
    {
        insertSorted(&(*tree)->right, data);
    }
}

void displayTree( BSTree * tree )
{
    if ( *tree != NULL )
    {
        displayTree( &( *tree )->left );
        printf( "%d ", ( *tree )->data );
        displayTree( &( *tree )->right );
    }
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 1
    Did you try to step through it with a debugger and check the values? – litelite Aug 01 '17 at 16:27
  • 5
    Also, as it is, your code can never return 0 and will crash on any number not in the tree – litelite Aug 01 '17 at 16:29
  • 1
    You don't show the `insertSorted()` code; you don't show the code you've used to print your tree so you know it is safe/complete. Your `find()` function doesn't handle null pointers (from `tree->left` or `tree->right` being null), and doesn't return 0 ever. – Jonathan Leffler Aug 01 '17 at 16:31
  • There is nothing wrong with the insert code and i have test it completely working –  Aug 01 '17 at 16:33
  • If I had a dollar for every time I got told that, I'd probably not be paying attention to SO any more... You may be satisfied, but you've not shown us that we can trust your code. However, @litelite pointed out a major part of the problem; my comment points out some issues (as well as sniping about you not providing an MCVE — [MCVE]). – Jonathan Leffler Aug 01 '17 at 16:34
  • 1
    `assert(!find(tree, 18));` --> `assert(!find(tree, 8));` – BLUEPIXY Aug 01 '17 at 16:34
  • i have put the insertSorted() and the display function as you asked I really appreciate your help –  Aug 01 '17 at 16:44
  • I suspect the problem is that you're missing the test `if(tree == NULL) return 0;` at the top of `find()`. – Steve Summit Aug 01 '17 at 17:14
  • @litelite Corner case: If `tree->data` was a FP with a non-a-number "value", `find()` may return 0. – chux - Reinstate Monica Aug 01 '17 at 18:41

2 Answers2

1

It looks like in this line:

assert(!find(tree, 18));

You are asserting that 18 is not in the tree, but you have 18 in the array to be inserted into the tree. I think if you want it to be correct, it should be:

assert(find(tree, 18));

Please let me know if I read your question wrong.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
Devin L.
  • 437
  • 2
  • 12
  • my assert is telling that it should be activated if it not finding the number it should be with the ! –  Aug 01 '17 at 17:01
  • This answer is correct — in part. If the assertions in the loop don't fire, these assertions after the loop should fire. The loop assertion checks that 5 (`arr[0]`) and 18 (`arr[5]`) are present; the post-loop assertions check that they are absent. One or the other assertion will fire. – Jonathan Leffler Aug 01 '17 at 17:47
1

The find() function should probably be:

int find(const BSTree tree, int data)
{
    if (tree == 0)  // or NULL
        return 0;
    else if (data == tree->data)
        return 1;
    else if (data < tree->data)
        return find(tree->left, data);
    else // if (data > tree->data)
        return find(tree->right, data);
}

It's notable that you must have code equivalent to typedef struct SomeTag { … } *BSTree somewhere in your system. On the whole, the answer to Is it a good idea to typedef pointers is "No".

Your displayTree() function is unexpectedly complex because you define it to take a BSTree * instead of just a BSTree. It should be:

void displayTree(const BSTree tree)
{
    if (tree != NULL)  // or 0
    {
        displayTree(tree->left);
        printf("%d ", tree->data);
        displayTree(tree->right);
    }
}

The pointer-to-pointer is necessary in the insertSorted() code, or you revise the prototype to:

BSTree *insertSorted(BSTree tree, int data).

and call it with:

tree = insertSorted(tree, data);

Both designs are feasible — there are some advantages each way.


MCVE

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

typedef struct BSTree *BSTree;
struct BSTree
{
    int    data;
    BSTree left;
    BSTree right;
};

void displayTree(BSTree tree);
void insertSorted(BSTree *tree, int data);
int find(const BSTree tree, int data);

static int isEmpty(const BSTree tree)
{
    return (tree == 0);
}

static BSTree emptyTree(void)
{
    return 0;
}

static BSTree createNode(int data)
{
    BSTree root = malloc(sizeof(*root));
    if (root != 0)
    {
        root->data = data;
        root->left = 0;
        root->right = 0;
    }
    return root;
}

int main(void)
{
    BSTree tree = emptyTree();
    assert(isEmpty(tree));

    // Insert 7 elements into the tree
    int arr[7] = { 5, 10, 1, 3, 7, 18, 20 };
    for (int i = 0; i < 7; i++)
    {
        insertSorted(&tree, arr[i]);
    }
    displayTree(tree);
    putchar('\n');

    for (int i = 0; i < 7; i++)
    {
        assert(find(tree, arr[i]));
    }
    assert(!find(tree, 19));
    assert(!find(tree, 6));
    return 0;
}

int find(const BSTree tree, int data)
{
    if (tree == 0)
        return 0;
    else if (data == tree->data)
        return 1;
    else if (data < tree->data)
        return find(tree->left, data);
    else // if (data > tree->data)
        return find(tree->right, data);
}

void insertSorted(BSTree *tree, int data)
{
    if (*tree == NULL)
    {
        *tree = createNode(data);
    }
    else if (data < (*tree)->data)
    {
        insertSorted(&(*tree)->left, data);
    }
    else
    {
        insertSorted(&(*tree)->right, data);
    }
}

void displayTree(BSTree tree)
{
    if (tree != NULL)
    {
        displayTree(tree->left);
        printf("%d ", tree->data);
        displayTree(tree->right);
    }
}

Output

1 3 5 7 10 18 20 

Assertions firing in the question's code

Note that in the question, there are two trailing assertions:

assert(!find(tree, 18)); //Here the assert is activated
assert(!find(tree, 5));

As Devin Liu pointed out in the answer, these assertions should fire — you just ran a loop that checked whether the elements of the array were present with assert(find(tree, arr[i]));, and both 5 and 18 are in the array (arr[0] and arr[5]), so the contrary assertion after the checking loop should fire.

Change 18 to 19, and 5 to 6 (say; many other changes are OK too) and the code works, as shown above.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Thank you for your response, the assert is still activated but I've made the changes you gave –  Aug 01 '17 at 17:37
  • The two trailing assertions are wrong. You inserted a value 18 into the tree; the loop checked that it was present. You didn't remove it; the standalone test fails to find it absent. Change the 18 to 19, for example, and the following 5 to 6, say, and you'll be OK. – Jonathan Leffler Aug 01 '17 at 17:40