具有两个孩子的两个节点移除 BST 的分段错误

问题描述 投票:0回答:0

我有一个任务要实现一个 AVL 树,我首先要实现一个二叉搜索树。我正在努力弄清楚我在执行删除有两个孩子的节点时做错了什么。 remove 函数在删除叶节点或具有一个子节点的节点时起作用。

函数 removal() 是实际实现的地方。

下面是头文件

#pragma once
#include <iostream>
#include <vector>

using std::cout;
using std::endl;
using std::vector;

// AVL Node Class
template <class T>
class AVLTreeNode {
public:
    // Node attributes
    AVLTreeNode* parent;
    AVLTreeNode* left;
    AVLTreeNode* right;
    T data;
    unsigned int height;

    // Default constructor
    AVLTreeNode(T val) {

        data = val;
        parent = nullptr;
        left = nullptr;
        right = nullptr;
        height = 0;
    }
};

// AVL Tree class
template <class T>
class AVLTree {
private:
    // pointer to root of the tree
    AVLTreeNode<T>* root;

    // variable to record the the current number of values in the tree
    int currentSize;

    // Private helper methods

    // POST: deallocates dynamic memory of the tree
    void deleteTree(AVLTreeNode<T>* node);

    // PARAM: node - starting node to search from
    //        target - value to search for 
    // POST: Return true if target is in tree, otherwise return false
    bool BSTSearch(AVLTreeNode<T>* node, T target) const;

    // PARAM: node - starting node to traverse
    //        value - value to be inserted into tree
    // POST: recurse through the tree and find place to insert value, returns node
    AVLTreeNode<T>* insertion(AVLTreeNode<T>* node, T value);

    // PARAM: node - starting node to traverse
    //        value - value to be removed from tree
    // POST: recurse through the tree and find value to remove, returns node
    AVLTreeNode<T>* removal(AVLTreeNode<T>* node, T value);

    // PARAM: node - starting node to traverse
    // POST: find and return the successor of the node param
    AVLTreeNode<T>* findSuccessor(AVLTreeNode<T>* node);

    // PARAM: node - starting node to grab values from
    // POST: insert values into vector by inorder traversal
    void inOrderVector(AVLTreeNode<T>* node, vector<T> &vector) const;

public:
    // Default constructor
    AVLTree();

    // Destructor
    ~AVLTree();

    // Mutators

    // PARAM: value - template value to be added into tree
    // POST: if val isn't in the tree, insert the value into the tree and return true
    //       otherwise, don't insert val and return false
    bool insert(T value);

    // PARAM: value - template value to be added into tree
    // POST: removes param value and returns true, return false if value is not within tree
    bool remove(T value);

    // Accessors

    // PARAM: target - template value to be searched within tree
    // POST: returns true if target is found, return false otherwise
    bool search(T target) const;

    // POST: returns a vector with all the values of the tree, in ascending order
    vector<T> values() const;

    // POST: return the number of values in the tree
    int size() const;

};

// AVL Tree Method Implementations

// Default constructor
template <class T>
AVLTree<T>::AVLTree() {

    root = nullptr;
    currentSize = 0;
}

// Destructor
template <class T>
AVLTree<T>::~AVLTree() {

    deleteTree(root);
}

// Mutators

// PARAM: value - template value to be added into tree
// POST: if val isn't in the tree, insert the value into the tree and return true
//       otherwise, don't insert param and return false
template <class T>
bool AVLTree<T>::insert(T value) {

    // search tree for param
    bool exists = BSTSearch(root, value);

    // if param is not in tree, insert it and return true
    if (exists == false) {

        // start from root
        root = insertion(root, value);

        // increment size
        currentSize++;

        return true;

    // otherwise, return false
    } else {
        return false;
    }
}

// PARAM: value - template value to be added into tree
// POST: removes param value and returns true, return false if value is not within tree
template <class T>
bool AVLTree<T>::remove(T value) {

    // search tree for param
    bool exists = BSTSearch(root, value);

    // if param is not in tree, return false
    if (exists == false) {
        
        return false;
    }

    root = removal(root, value);

    currentSize--;

    return true;
}

// Accessors

// PARAM: target - value to be searched within tree
// POST: returns true if target is found, return false otherwise
template <class T>
bool AVLTree<T>::search(T target) const {

    return BSTSearch(root, target);
}

// POST: returns a vector with all the values of the tree, in ascending order
template <class T>
vector<T> AVLTree<T>::values() const {

    // create vector for values
    vector<T> values;

    inOrderVector(root, values);

    // return vector
    return values;  
}

// POST: return the number of values in the tree
template <class T>
int AVLTree<T>::size() const {

    return this->currentSize;
}

// Private Helper Methods

// POST: deallocates dynamic memory of the tree
template <class T>
void AVLTree<T>::deleteTree(AVLTreeNode<T>* node) {

    // recursively goes through tree until both children are null
    if (node != nullptr) {

        // move to left child
        deleteTree(node->left);

        // move to right child
        deleteTree(node->right);

        // delete node
        delete node;
    }
}

// PARAM: node - starting node to search from
//        target - value to search for 
// POST: Return true if target is in tree, otherwise return false
template <class T>
bool AVLTree<T>::BSTSearch(AVLTreeNode<T>* node, T target) const {
    
    // reached end of path
    if (node == nullptr) {
        return false;

    // if target is found
    } else if (target == node->data) {
        return true;

    // target is less than current node, go down to left
    } else if (target < node->data) {
        return BSTSearch(node->left, target);

    // target is greater than current node, go down to right
    } else {
        return BSTSearch(node->right, target);
    }
}

// PARAM: node - starting node to traverse
//        data - value to be inserted into tree
// POST: recurse through the tree and find place to insert value, return node that was inserted
template <class T>
AVLTreeNode<T>* AVLTree<T>::insertion(AVLTreeNode<T>* node, T value) {

    // base case
    if (node == nullptr) {
        
        // create new node with value and return it
        AVLTreeNode<T>* temp = new AVLTreeNode(value);
        return temp;
    }

    // traverse through tree and find position for new node
    if (value < node->data) {

        // go down to left child 
        AVLTreeNode<T>* leftChild = insertion(node->left, value);
        node->left = leftChild; // set the current node's left* 
        leftChild->parent = node; // set the parent node of left to be current node
    } else {

        // go down to right child
        AVLTreeNode<T>* rightChild = insertion(node->right, value);
        node->right = rightChild; // set the current node's right*
        rightChild->parent = node; // set the parent node of right to be current node
    }

    return node;
}

// PARAM: node - starting node to traverse
// POST: find and return the successor of the node param
template <class T>
AVLTreeNode<T>* AVLTree<T>::findSuccessor(AVLTreeNode<T>* node) {

    // create pointer to right child
    AVLTreeNode<T>* successor = node;

    // loop down to find left most node
    while (successor != nullptr && successor->left != nullptr) {

        successor = successor->left;
    }

    // return the successor
    return successor;
}

// PARAM: node - starting node to traverse
//        value - value to be removed from tree
// POST: recurse through the tree and find value to remove, returns node
template <class T>
AVLTreeNode<T>* AVLTree<T>::removal(AVLTreeNode<T>* node, T value) {

    // base case
    if (node == nullptr) {

        return node;
    }

    // if value is less than current node, go to left
    if (value < node->data) {
        node->left = removal(node->left, value);

    // if value is greater than current node, go to right
    } else if (value > node->data) {
        node->right = removal(node->right, value);

    // if value is equal to current node, remove it
    } else {
        
        // if node has no children
        if (node->left == nullptr && node->right == nullptr) {

            // delete node and return
            delete node;
            return nullptr;

        // if node has only one child (right)
        } else if (node->left == nullptr) {

            // check if the node being removed is the left or right child of the parent
            // then replace the node with it's subtree
            if (node->parent->left == node) {
                node->parent->left = node->right;

            } else {
                node->parent->right = node->right;
            }
            
            // delete the node and return the new subtree
            delete node;
            return node->right;

        // if node has only one child (left)
        } else if (node->right == nullptr) {

            // check if the node being removed is the left or right child of the parent
            // then replace the node with it's subtree
            if (node->parent->left == node) {
                node->parent->left = node->left;

            } else {
                node->parent->right = node->left;
            }

            // delete node
            delete node;
            return node->left;
        }

        // if node has two children
        // find successor first
        AVLTreeNode<T>* successor = findSuccessor(node->right);

        // detach successor
        if (successor->parent->left == successor) {

            successor->parent->left = nullptr;
        } else {

            successor->parent->right = nullptr;
        }

        // make the successor's children the node's children
        successor->right = node->right;
        successor->left = node->left;
        
        // make the successor the child of the node's parent
        if (node->parent->left == node) {

            node->parent->left = successor;
        } else {

            node->parent->right = successor;
        }

        // delete the node
        delete node;
    }

    return node;
}

// PARAM: node - starting node to grab values from
// POST: insert values into vector by inorder traversal
template <class T>
void AVLTree<T>::inOrderVector(AVLTreeNode<T>* node, vector<T> &vector) const {

    // if tree is empty, return empty vector
    if (node == nullptr) {
        return;
    }

    // go to left node
    inOrderVector(node->left, vector);

    // push data into vector
    vector.push_back(node->data);

    // go to right node
    inOrderVector(node->right, vector);
} 

这就是我用来测试功能的东西。

#include "AVLFunctions.h"

int main()
{
    AVLTree<int> tree;

    cout << "inserting 47: " << tree.insert(47) << endl;
    cout << "inserting 32: " << tree.insert(32) << endl;
    cout << "inserting 19: " << tree.insert(19) << endl;
    cout << "inserting 41: " << tree.insert(41) << endl;
    cout << "inserting 37: " << tree.insert(37) << endl;
    cout << "inserting 44: " << tree.insert(44) << endl;
    cout << "inserting 63: " << tree.insert(63) << endl;
    cout << "inserting 96: " << tree.insert(96) << endl;
    cout << "inserting 14: " << tree.insert(14) << endl;

    cout << "removing: " << tree.remove(41) << endl;

    cout << "search removed node: " << tree.search(41) << endl;

    vector<int> v = tree.values();
    
    cout << "tree values: {";

    for (int i = 0; i < v.size(); i++) {
        cout << " " << v.at(i);
    }
    cout << " }" << endl;
}

这是我运行代码时得到的结果:

inserting 47: 1
inserting 32: 1
inserting 19: 1
inserting 41: 1
inserting 37: 1
inserting 44: 1
inserting 63: 1
inserting 96: 1
inserting 14: 1
removing: 1
search removed node: 1
Segmentation fault
c++ pointers binary-search-tree
© www.soinside.com 2019 - 2024. All rights reserved.