简体   繁体   中英

Strcmp Error in Binary Search Tree Insertion (Recursion)?

i'm trying to implement some functions that allow me to add "Books" to a binary search tree for the "Student" class, but I'm getting a strange error:

msvcr100d.dll!strcmp(unsigned char * str1, unsigned char * str2) Line 83 Asm

The program is entirely in C/C++, so I'm not sure why its returning an assembly language error? My first thought is something is wrong with my use of strcmp, and the Call Stack shows Line 188 as the last executed statement (before the above error), which means I'm probably messing up my recursion somewhere. I am calling the insertBook() function of "Student", so here is my "Student" class. Any help? Thanks.

class Student : public Personnel { //inherit from Personnel
public:
    Book *bookTree;

    Book* searchBookTree(Book *bookNode, char *title) {
        if ((strcmp(title, bookNode->title)) < 0) //***LINE 188
            return searchBookTree(bookNode->left, title); 

        else if ((strcmp(title, bookNode->title)) > 0)
            return searchBookTree(bookNode->right, title);

        else
            return bookNode;
    }

    void insertBook(Book *node) {
        Book *newBook, *parent;
        newBook = node;

        newBook->left = NULL;
        newBook->right = NULL;

        if (bookTree == NULL) { //if bookTree is empty
            bookTree = newBook; 
        }
        else {          
            parent = searchBookTree(bookTree, newBook->title);
            newBook->left = parent->left;
            newBook->right = parent->right;
        }   
    }

    void printBooks(Book *top) {
        Book *root = top;
        if (root != NULL) {
            printBooks(root->left);
            cout << "BOOK LIST" << endl;
            cout << "Title:\t\t" << root->title << endl;
            cout << "URL:\t\t" << root->url << endl;
            printBooks(root->right);
        }
    } 

    void display() {
            Personnel::display();
            cout << "STUDENT" << endl;  
            cout << "Level:\t\t" << getLevel() << endl;
            printBooks(bookTree); cout << endl;
    }

    Student(char *cName, char *cBirthday, char *cAddress, char *cPhone, char *cEmail, level gradeLevel) 
        : Personnel(cName, cBirthday, cAddress, cPhone, cEmail) 
    {
        bookTree = NULL;
        setLevel(gradeLevel);
    }

};

Your recursive search an important termination test missing! At some point, you hit the bottom of the tree without finding the item. And so your search function is called with a null pointer for the tree node! The problem is not in strcmp , but in the null pointer in one of the argument expressions.

You have only considered the case when the item exists in the tree and is eventually found, neglecting the not-found case.

Programmers are not to be measured by their ingenuity and their logic but by the completeness of their case analysis.

  • Alan J. Perlis, Epigram #32
Book* searchBookTree(Book *bookNode, char *title) {
        if ((strcmp(title, bookNode->title)) < 0) //***LINE 188
            // What happens if bookNode->left == NULL ???
            return searchBookTree(bookNode->left, title); 

        else if ((strcmp(title, bookNode->title)) > 0)
            // What happens if bookNode->right== NULL ???
            return searchBookTree(bookNode->right, title);

        else
            return bookNode;
    }

you'll need a termination point in your search function. At the top, I'd first check if bookNode == NULL.

Your insert routine has problems. I suggest you make your searchBookTree just return a null pointer when it doesn't find anything. Do not use that routine in the implementation of insertBook . Rather, you can write insertBook recursively also:

private:
    // Inserts bookNode into tree, returning new tree:

    Book *insertBookHelper(Book *tree, Book *bookNode) {
        if (tree == NULL)
            return bookNode; // bookNode becomes new tree

        // no need to call strcmp twice!!!
        int cmp = strcmp(title, bookNode->title);

        if (cmp < 0) {
            tree->left = insertBookHelper(tree->left, bookNode->title); 
        else if (cmp > 0)
            tree->right = insertBookHelper(tree->right, bookNode->title);
        else {
            // Uh oh! Tree already contains that title, what to do?
            // Answer: update!
            // I don't know how to write this because I don't know
            // how your Book class handles the memory for the strings,
            // and what other members it has besides the title.
            // this could be a possibility:
            // bookNode->left = tree->left;    // install same child pointers
            // bookNode->right = tree->right;  // into bookNode.
            // *tree = *bookNode; // if Book has a sane copy constructor!!!
        }
        return tree;
    }

 public:
    void insertBook(Book *node) {
        tree = insertBookHelper(tree, node);
    }

Do you see how the recursion works? It's a little different from the pure search. Each recursive level handles the insertion into the subtree and returns the new subtree. Often, the returned tree is exactly the same as the tree that went in! But when inserting into an empty tree, the returned tree is not the same: the tree that went in is a null pointer, but a non-null pointer comes out. This trick of pretending that we are making a new tree and returning it as a replacement for the old tree makes for smooth code.

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