不是NULL指针,而是错误的访问错误消息

Not a NULL-pointer but bad access error message

本文关键字:错误 访问 消息 NULL 指针 不是      更新时间:2023-10-16

我正在编写一个BST,从7开始将数字0到15相加。

然后,当我试图从0到15删除它们时,当我尝试删除节点9时,我的getLeftChildHeight()在行if (left == NULL)上抛出EXC_BAD_ACCESS

为什么我不能检查我的指针是否为NULL,这怎么可能呢?

#include <iostream>
#include <stdio.h>
#include <queue>
#include <stack>
using namespace std;
typedef unsigned long long int KType;

struct Node {
    KType key;
    Node* left;
    Node* right;
    Node* parent;
    int level;                  // from root to node; depth(root) = 0
    int height;                 // from node to leaf; height(leaf) = 0
    int sub_tree_size;          // the size of the subtree; size(leaf) = 1
    Node(): key(0), left(NULL), right(NULL),
            parent(NULL), level(0), height(0), sub_tree_size(0) {}
    Node(const KType& _key): key(_key), left(NULL), right(NULL),
                             parent(NULL), level(0), height(0),
                             sub_tree_size(1) {}
    ~Node() { delete left; delete right;  }
    friend ostream& operator << (ostream& os, const Node* nb);

    /*
     * Returns the height of the left node
     */
    int getLeftChildHeight() {
        if (left == NULL)
            return -1;
        else
            return left -> height;
    }

    /*
     * Returns the height of the right node
     */
    int getRightChildHeight() {
        if (right == NULL)
            return -1;
        else
            return right -> height;
    }

    /*
     * Returns the height of the higher child
     */
    int getMaxLRHeight() {
        return std::max (getLeftChildHeight(), getRightChildHeight());
    }

    /*
     * Returns the height of the lower child
     */
    int getMinLRHeight() {
        return std::min (getLeftChildHeight(), getRightChildHeight());
    }

    /*
     * Returns the difference between the heights of the children
     */
    int getDeltaHeight() {
        return abs(getRightChildHeight() - getLeftChildHeight());
    }

    /*
     * Prints all the node properties
     */
    void print() {
        printf ("| (%llu) ", key);
        printf ("H: %d ", height);
        printf ("L: %d ", level);
        //printf("S: %d ", sub_tree_size);
        printf("|");
    }
};

// Standard output operator overload
ostream& operator << (ostream& os,  const Node* n) {
    cout << n -> key << " ";
    return os;
}

struct BST {
    int nNodes;
    Node* root;
    ~BST() { nNodes = 0; delete root; }

    /**
     * Adds a new node and updates all the proberties up to the root
     */
    void add(const KType& key) {
        nNodes++;
        Node* back = NULL;
        if (root == NULL)
            root = new Node(key);
        else {
                Node* v = root;
                while(v != NULL) {
                    v -> sub_tree_size++;
                    if (key <= v -> key)
                        if (v -> left != NULL)
                            v = v -> left;
                        else {
                                v -> left = new Node(key);
                                v -> left -> level = v -> level + 1;
                                v -> left -> parent = v;
                                back = v -> left;
                                v = NULL;
                        }
                    else
                        if (v -> right != NULL)
                            v = v -> right;
                        else {
                                v -> right = new Node(key);
                                v -> right -> level = v -> level + 1;
                                v -> right -> parent = v;
                                back = v -> right;
                                v = NULL;
                        }
                }
                while (back != NULL) {
                    back -> height = back -> getMaxLRHeight() + 1;
                    back = back -> parent;
                }
            }
    }

    /**
     *  Prints the tree
     */
    void printTree(bool full_info = false) {
        if (nNodes == 0) {
            cout << "The tree is empty!n";
            return;
        }
        printf("Number of nodes: %dn", nNodes);
        queue<Node*> q;
        Node* v = root;
        q.push(v);
        int level = 0;
        while (!q.empty()) {
            v = q.front();
            q.pop();
            if (v -> level > level) {
                level = v -> level;
                printf("n");
            }
            if (full_info)
                v->print();
            else
                cout << v;
            if (v -> left != NULL)
                q.push(v -> left);
            if (v -> right != NULL)
                q.push(v -> right);
        }
        cout << "n--------------------n";
    }

    /*
     * Reads the tree from the standard input
     */
    void getTree() {
        int n = 0;
        KType k;
        scanf("%d", &n);
        for(int i = 0; i < n; i++) {
            scanf("%llu", &k);
            add(k);
        }
    }

    /*
     * Returns the pointer to the node if the tree contains the key
     */
    Node* find(const KType& k) {
        if (root == NULL) return NULL;
        Node* v = root;
        while (v != NULL) {
            if (v -> key == k) return v;
            if (k < v -> key)
                v = v -> left;
            else
                v = v -> right;
        }
        return v;
    }

    /*
     * Returns true if the tree contains the key
     */
    bool contains(const KType& k) {
        return find(k) != NULL;
    }

    /* 
     * Returns the pointer to the minimum for the subtree with the local_root,
     * which is the leftmost node in the subtree
     */
    Node* min(Node* local_root) {
        Node* v = local_root;
        while (v -> left != NULL)
            v = v -> left;
        return v;
    }

    /*
     * Returns the minimum key for the subtree with the local_root,
     * which is the leftmost key in the subtree
     */
    KType minKey(Node* local_root) {
        return min(local_root) -> key;
    }

    /*
     * Returns the minimum key for the subtree with the k as its root,
     * which is the leftmost key in the subtree
     */
    KType minKey(const KType& k) {
        Node *v = find(k);
        return min(v) -> key;
    }

    /*
     * Returns the pointer to the maximum for the subtree with the local_root,
     * which is the rightmost node in the subtree
     */
    Node* max(Node* local_root) {
        Node* v = local_root;
        while (v -> right != NULL)
            v = v -> right;
        return v;
    }

    /*
     * Returns the maximum key for the subtree with the local_root
     * which is the rightmost key in the subtree
     */
    KType maxKey(Node* local_root) {
        return max(local_root) -> key;
    }

    /*
     * Returns the maximum key for the subtree with the k as its root
     * which is the rightmost key in the tree
     */
    KType maxKey(const KType& k) {
        Node *v = find(k);
        return max(v) -> key;
    }

    /*
     * Returns the pointer to the predecessor of the node
     */
    Node* predecessor(Node* node) {
        if (node -> left == NULL) {
            Node* start = node;
            while (node -> key >= start -> key && node != root)
                node = node -> parent;
            if (node == root && node -> key > start -> key)
                return start;
            else
                return node;
        }
        else
            return max(node -> left);
    }

    /*
     * Returns the pointer to the predecessor of the key k
     */
    Node* predecessor(const KType& k) {
        Node* node = find(k);
        return predecessor(node);
    }

    /*
     * Returns the pointer to the predecessor of the key k
     */
    KType predecessorKey(const KType& k) {
        Node* node = find(k);
        return predecessor(node) -> key;
    }

    /*
     * Returns the pointer to the successor of the node
     */
    Node* successor(Node* node) {
        if (node -> right == NULL) {
            Node* start = node;
            while (node -> key <= start -> key && node != root)
                node = node -> parent;
            if (node == root && node -> key < start -> key)
                return start;
            else
                return node;
        }
        else
            return min(node -> right);
    }

    /*
     * Returns the pointer to the successor of the key k
     */
    Node* successor(const KType& k) {
        Node* node = find(k);
        return successor(node);
    }

    /*
     * Returns the pointer to the successor of key
     */
    KType successorKey(const KType& k) {
        Node* node = find(k);
        return successor(node) -> key;
    }

    /*
     *  Returns the pointer to the right child if the node is
     *  the left child of its parent and vice versa
     */
    Node* otherChild(Node* node) {
        if (node == root) return NULL;
        if (node -> parent -> left == NULL ||
            node -> parent -> right == NULL)
            return NULL;
        if (node == node -> parent -> left)
            return node -> parent -> right;
        else
            return node -> parent -> left;
    }

    /*
     *  Returns the key of the right child if the node is
     *  the left child of its parent and vice versa
     */
    long long int otherChildKey(Node* node) {
        Node *v = otherChild(node);
        if (v == NULL)
            return -1;
        else
            return v -> key;
    }

    /*
     *  Returns the key of the right child if the node is
     *  the left child of its parent and vice versa
     */
    long long int otherChildKey(const KType& k) {
        Node *v = otherChild(find(k));
        if (v == NULL)
            return -1;
        else
            return v -> key;
    }

    /*
     * Returns the height of the other child
     */
    int otherChildHeight(Node* node) {
        Node *v = otherChild(node);
        if (v == NULL)
            return -1;
        else
            return v -> height;
    }

    /**
     * Returns true if child is the left child of its parent
     * and false otherwise
     */
    bool isLeftChild(Node *child) {
        if (child -> parent -> left != NULL &&
            child -> parent -> left == child)
            return true;
        return false;
    }

    /**
     * Returns true if the key k is the left child of its parent
     * and false otherwise
     */
    bool isLeftChild(const KType &k) {
        Node* child = find(k);
        if (child -> parent -> left != NULL &&
            child -> parent -> left == child)
            return true;
        return false;
    }

    /**
     * Returns true if child is the right child of its parents
     * and false otherwise
     */
    bool isRightChild(Node *child) {
        if (child -> parent -> right != NULL &&
            child -> parent -> right == child)
            return true;
        return false;
    }

    /**
     * Returns true if the key k is the right child of its parent
     * and false otherwise
     */
    bool isRightChild(const KType &k) {
        Node* child = find(k);
        if (child -> parent -> right != NULL &&
            child -> parent -> right == child)
            return true;
        return false;
    }

    /*
     * Returns true if the node has only the right child
     * and false otherwise
     */
    bool hasOnlyRightChild (Node* node) {
        return (node -> left == NULL && node -> right != NULL);
    }

    /*
     * Returns true if the node has only the left childe
     * and false otherwise
     */
    bool hasOnlyLeftChild (Node* node) {
        return (node -> right == NULL && node -> left != NULL);
    }

    /*
     * Returns true if the node with the key k has only the right child
     * and false otherwise
     */
    bool hasOnlyRightChild (const KType& k) {
        Node* node = find(k);
        return (node -> left == NULL && node -> right != NULL);
    }

    /*
     * Returns true if the node with the key k has only the left child
     * and false otherwise
     */
    bool hasOnlyLeftChild (const KType& k) {
        Node* node = find(k);
        return (node -> right == NULL && node -> left != NULL);
    }

    /*
     * Deletes the leaf of the tree
     */
    void deleteLeaf(Node * leaf) {
        if (leaf -> left != NULL ||  leaf -> right != NULL) {
            cout << "Not a leaf!!n";
            return;
        }
        nNodes--;
        if (leaf == root) {
            root = NULL;
            delete root;
            return;
        };
        // Deleting the node
        Node* v = leaf -> parent;
        if (isLeftChild(leaf)) {
            leaf -> parent = NULL;
            //delete leaf;
            //v -> left -> parent = NULL;
            //delete v -> left;
            v -> left = NULL;
            delete v -> left;

        }
        else {
                leaf -> parent = NULL;
                //delete leaf;
                //v -> right -> parent = NULL;
                //delete v -> right;
                v -> right = NULL;
                delete v -> left;
        }
        // Updating the parameters
        while (v != NULL) {
            v -> height = v -> getMaxLRHeight() + 1;
            v -> sub_tree_size--;
            v = v -> parent;
        }
    }

    /*
     * Deletes the leaf of the tree with the key k
     */
    void deleteLeafKey(const KType& k) {
        Node* leaf = find(k);
        if (leaf == NULL) return;
        if (leaf -> left != NULL ||  leaf -> right != NULL) {
            cout << "Not a leaf!!n";
            return;
        }
        deleteLeaf(leaf);
    }

    /*
     *  Increments the level of all the nodes that are lifted up after the deletion
     */
    void updLevelDown(Node* node) {
        stack <Node*> s;
        s.push(node);
        while(!s.empty()) {
            Node* v = s.top();
            s.pop();
            v -> level--;
            if (v -> left != NULL)
                s.push(v -> left);
            if (v -> right != NULL)
                s.push(v -> right);
        }
    }

    /*
     * Kills the node
     */
    void killNode(Node* node) {
        node -> left = NULL;
        node -> right = NULL;
        node -> parent = NULL;
        delete node;
    }

    /*
     * Deletes a node that has only one child
     */
    void deleteOneChildNode(Node *node) {
        Node* upd;
        Node* upd2;
        nNodes--;
        if (node == root) {
            upd = root;
            if (root -> right != NULL)
                root = root -> right;
            else
                root = root -> left;
            updLevelDown(upd);
            killNode(upd);
            return;
        }
        // Deleting the node
        if (isLeftChild(node)) {
            if (hasOnlyLeftChild(node)) {
                upd = node -> left;
                node -> parent -> left = node -> left;
                node -> left -> parent = node -> parent;
                killNode(node);
            }
            else {
                    upd = node -> right;
                    node -> parent -> left = node -> right;
                    node -> right -> parent = node -> parent;
                    killNode(node);
            }
        }
        else {
            if (hasOnlyLeftChild(node)) {
                upd = node -> left;
                node -> parent -> right = node -> left;
                node -> left -> parent = node -> parent;
                killNode(node);
            }
            else {
                    upd = node -> right;
                    node -> parent -> right = node -> right;
                    node -> right -> parent = node -> parent;
                    killNode(node);
            }
        }

        // Updating the parameters
        upd2 = upd;
        updLevelDown(upd2);
        while (upd2 != NULL) {
            upd -> height = upd -> getMaxLRHeight() + 1;
            upd -> sub_tree_size--;
            upd = upd -> parent;
        }
    }

    /*
     * Deletes a node that has both children
     */
    void deleteOneChildNodeKey(const KType& k) {
        Node* node = find(k);
        deleteOneChildNode(node);
    }

    /*
     * Returns true if the node is a leaf and false otherwise
     */
    bool isLeaf(Node* node) {
        return (node -> left == NULL &&  node -> right == NULL);
    }

    /*
     * Returns true if the node has both children
     */
    bool hasBothChildren(Node* node) {
        return (node -> left != NULL && node ->right != NULL);
    }

    /*
     * Returns true if the node has both children
     */
    bool hasBothChildrenKey(const KType& k) {
        Node* node = find(k);
        return (node -> left != NULL && node ->right != NULL);
    }

    /*
     * Swaps two keys
     */
    void swapKeys(Node* nodeA, Node* nodeB) {
        KType c = nodeA -> key;
        nodeA -> key = nodeB -> key;
        nodeB -> key = c;
    }

    // Deletes a node with two children
    void deleteTwoChildrenNode(Node* node) {
        Node* s = successor(node);
        swapKeys(node, s);
        if (isLeaf(s))
            deleteLeaf(s);
        else
            deleteOneChildNode(s);
    }

    // Deletes a key with two children
    void deleteTwoChildrenNodeKey(const KType& k) {
        Node* node = find(k);
        deleteTwoChildrenNode(node);
    }

    /*
     * Deletes any node from the tree
     */
    void deleteNode(Node* node) {
        if (isLeaf(node))
            deleteLeaf(node);
        else
            if (hasBothChildren(node))
                deleteTwoChildrenNode(node);
            else deleteOneChildNode(node);
    }

    /*
     * Deletes any key from the tree
     */
    void deleteNodeKey(const KType& k) {
        Node* node = find(k);
        if (node != NULL) deleteNode(node);
    }

};

int main(int argc, const char * argv[]) {
    string path = "/Users/alekscooper/Dropbox/Binary Search Tree/Input/";
    path+= "input4.txt";
    freopen (path.c_str(), "r", stdin);
    BST t;

    t.getTree();
    t.printTree(1);
    for(int i = 0; i < 17; i++)
        t.deleteNodeKey(i);
    t.printTree(1);

    return 0;
}

这是input4.txt文件:

16
7
3
12
1
6
9
13
0
2
4
8
11
15
5
10
14

两个错误:

1:

    // Updating the parameters
    upd2 = upd;
    updLevelDown(upd2);
    while (upd2 != NULL) {
        upd -> height = upd -> getMaxLRHeight() + 1;
        upd -> sub_tree_size--;
        upd = upd -> parent;
    }
}

您正在检查upd2,但正在更改upd。所以你一直运行到updNULL,然后你在上面调用getMaxLRHeight

2:

struct BST {
    int nNodes;
    Node* root;
    ~BST() { nNodes = 0; delete root; }
    ....

您没有UPD的构造函数。因此,它从不可预测的价值观开始。添加:

BST() { nNodes = 0; root = NULL; }