简体   繁体   中英

Binary search tree Pointers issue

I am trying to implement a function that should add a value in leaf , here my codes

Node structure: the node contain two the shild the left one and the right one and his dadi (predecessor ) and the value .

struct arbre {
int val ;
struct arbre * D;
struct arbre * G ;
struct arbre * pere ;
};

Here is the function : the function always add the value on the leafs

void ajout_feuille( struct arbre** arbre , int value )
{
    struct arbre* q ,*p ;
    if ( *arbre == NULL)
    {
        q=malloc(sizeof(struct arbre ));
        q->D=NULL ;
        q->G=NULL;
        q->pere=NULL;
        q->val=value;
        *arbre=q ;
    }
    else
    {
    p=*arbre;
    while(p!=NULL)
    {
        if (p->val<value) //if the value is > we go on the right shild;
        {
            if (p->D==NULL) // if we are on the leaf 
            {
                q=malloc(sizeof(struct arbre ));
                q->val=value;
                q->D=NULL;
                q->G=NULL;
                q->pere=p;
                p->D=q;
            }else
            {
                p=p->D;
            }

        }else
        {
            if (p->val>value)
            {
                if(p->G==NULL)
                {
                     q=malloc(sizeof(struct arbre ));
                     q->val=value;
                     q->D=NULL;
                     q->G=NULL;
                     q->pere=p;
                     p->G=q;
                }
            }else { p=p->G; }
        }
    }
    }

}

Here is the Display method : this is prefix display method

void affichage (struct arbre * arbre )
{
    if (arbre != NULL){
printf("%d\n",arbre->val);
    affichage(arbre->G);
    affichage(arbre->D);

}
}

Here is the main method :

int main()
{
    struct arbre * A=NULL ;

    ajout_feuille(&A,5);
    ajout_feuille(&A,4);
    affichage(A);


    return 0;
}

The probleme is : nothing is shown by the display methode i think there is probleme in the pointers .

More pointers and variables therein does not make the code easier to read. The reason nothing prints is because your enumeration loop never terminates.

Your code has two code infinite loop problems. Remember, you have no break statements in this code, so the only thing that unleashes that while-loop is when p becomes NULL.

  • A left-side ending traversal will never exit the loop
  • Duplicate entries will never exit the loop

Regarding the first of these, Chasing a left-side traversal will never set p to NULL because of the following. Consider the difference between your right-side traversal and your left-side traversal.

A right side traversal does this:

        if (p->val<value) //if the value is >, we go on the right child;
        {
            if (p->D==NULL) // if we are on the leaf
            {
                q=malloc(sizeof(struct arbre ));
                q->val=value;
                q->D=NULL;
                q->G=NULL;
                q->pere=p;
                p->D=q;
            }
            else
            {
                p=p->D;
            }
        }

Note specifically what the else-reaction p=p->D is hinged to. Now look at your left-side logic, which should be similar, but chasing a different pointer using reversed logic (which is a mistake that eventually leads to your infinite loop problem in the duplicate-insertion case, but we'll get to that in a moment):

        if (p->val>value) // ok so far
        {
            if(p->G==NULL)
            {
                q=malloc(sizeof(struct arbre ));
                q->val=value;
                q->D=NULL;
                q->G=NULL;
                q->pere=p;
                p->G=q;
            }
        }
        else
        {
            p=p->G;
        }

Notice where the else-condition hangs now. First, it's wrong, second, that if and else really shouldn't be there in the first place unless you're specifically trying to build a set (ie no duplicate keys), and if that is the case, you still need an exit clause to break the otherwise-endless while(p!=NULL) state.

Fully functional versions of your code that (a) don't allow duplicates, which you appear to be targeting, and (b) allows duplicates, are below. Then an alternative is proffered that I strongly advise you review.

Fix #1 - No Duplicates

void ajout_feuille0( struct arbre** arbre , int value )
{
    struct arbre* q ,*p ;
    if ( *arbre == NULL)
    {
        q=malloc(sizeof(struct arbre ));
        q->D=NULL ;
        q->G=NULL;
        q->pere=NULL;
        q->val=value;
        *arbre=q ;
    }
    else
    {
        p = *arbre;
        while (p!=NULL)
        {
            if (p->val<value) //if the value is > we go on the right shild;
            {
                if (p->D==NULL) // if we are on the leaf
                {
                    q=malloc(sizeof(struct arbre ));
                    q->val=value;
                    q->D=NULL;
                    q->G=NULL;
                    q->pere=p;
                    p->D=q;
                }
                else
                {
                    p=p->D;
                }
            }
            else if (value < p->val) // else if less we go down the left side.
            {
                if(p->G==NULL)
                {
                    q=malloc(sizeof(struct arbre ));
                    q->val=value;
                    q->D=NULL;
                    q->G=NULL;
                    q->pere=p;
                    p->G=q;
                }
                else
                {
                    p=p->G;
                }
            }
            else // else the value is already in the tree.
            {
                break;
            }
        }
    }
}

Fix #2 - Duplicates Allowed

void ajout_feuille0( struct arbre** arbre , int value )
{
    struct arbre* q ,*p ;
    if ( *arbre == NULL)
    {
        q=malloc(sizeof(struct arbre ));
        q->D=NULL ;
        q->G=NULL;
        q->pere=NULL;
        q->val=value;
        *arbre=q ;
    }
    else
    {
        p = *arbre;
        while (p!=NULL)
        {
            if (p->val<value) //if the value is > we go on the right shild;
            {
                if (p->D==NULL) // if we are on the leaf
                {
                    q=malloc(sizeof(struct arbre ));
                    q->val=value;
                    q->D=NULL;
                    q->G=NULL;
                    q->pere=p;
                    p->D=q;
                }
                else
                {
                    p=p->D;
                }
            }
            else
            {
                if(p->G==NULL)
                {
                    q=malloc(sizeof(struct arbre ));
                    q->val=value;
                    q->D=NULL;
                    q->G=NULL;
                    q->pere=p;
                    p->G=q;
                }
                else
                {
                    p=p->G;
                }
            }
        }
    }
}

Alternative

The truth is, you don't need p and q . You need only two things:

  1. The pointer-to-pointer you were given. We can use that to traverse the tree by directly addressing each pointer during the descent.
  2. a one-back "parent" pointer, initially set to NULL, and set to the current node pointer before we descend down a next child.

Using those, you can implement both algorithms (no-duplicates and allow-duplicates) much more concisely:

No Duplicates

void ajout_feuille( struct arbre** tree , int value )
{
    struct arbre *pere = NULL;
    while (*tree)
    {
        pere = *tree;

        // left side ?
        if (value < (*tree)->val)
            tree = &(*tree)->G;

        // right side ?
        else if ((*tree)->val < value)
            tree = &(*tree)->D;

        else // duplicate found
            break;
    }

    if (!*tree) // null means we have a place to hang a node.
    {
        *tree = malloc(sizeof **tree);
        if (!*tree)
        {
            perror("Failed to allocate new tree node");
            exit(EXIT_FAILURE);
        }

        (*tree)->val = value;
        (*tree)->pere = pere;
        (*tree)->G = NULL;
        (*tree)->D = NULL;
    }
}

Allow Duplicates

void ajout_feuille( struct arbre** tree , int value )
{
    struct arbre *pere = NULL;
    while (*tree)
    {
        pere = *tree;

        // left side ?
        if (value < (*tree)->val)
            tree = &(*tree)->G;

        // els ejust move to right
        else tree = &(*tree)->D;
    }

    if (!*tree) // null means we have a place to hang a node.
    {
        *tree = malloc(sizeof **tree);
        if (!*tree)
        {
            perror("Failed to allocate new tree node");
            exit(EXIT_FAILURE);
        }

        (*tree)->val = value;
        (*tree)->pere = pere;
        (*tree)->G = NULL;
        (*tree)->D = NULL;
    }
}

In both cases, the code is much cleaner, and avoids the extra loop through the outer while.

Hope it helps.

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