从我的二叉搜索树中删除节点时遇到困难

时间:2015-05-10 10:56:43

标签: c++ recursion binary-search-tree

我正在创建一个二进制搜索树,它需要能够删除节点,如果节点被正确删除则返回true,如果树中不存在该值,则返回false。我这样做是因为我需要删除多个数字,并且我想创建一个while循环来删除所有它而它是真的。例如,一棵树具有以下内容:{79,83,147,71,95,49,15,191}。另一棵树具有以下整数{26,79,144,88,147,200,90}。我的任务是找到树2中树2中的任何元素,并从树1中删除它们(在本例中为79和147)。我想创建一个循环,遍历树2中的所有数字,并从第一个树中搜索和删除。这是我到目前为止删除节点功能(假设树已经构建并填充):

Node.h:

template<class ItemType>
class Node {
public:
    ItemType data;
    Node * left;
    Node * right;

    //Constructors / Destructors
    Node ();
    Node ( ItemType inData );
    ~Node ();
};

//--------------------------------------------------------------//
//--                Constructor / Destructor                  --//
//--------------------------------------------------------------//
/** Standard Constructor */
template<class ItemType>
Node<ItemType>::Node () {
    left = right = NULL;
}

/** Overload Constructor */
template<class ItemType>
Node<ItemType>::Node ( ItemType inData ) {
    data = inData;
    left = right = NULL;
}

/** Standard Destructor */
template<class ItemType>
Node<ItemType>::~Node () {
    right = left = NULL;
}

来自Source.cpp:

Tree2.postorder_print ();

int ridOf = 79;

if (Tree2.remove ( ridOf )) {
        Tree2.postorder_print ();
        cout << endl << "Number of Nodes: " << Tree2.get_num_of_nodes () << endl;
        cout << "Height:          " << Tree2.get_tree_height () << endl << endl;
    }

来自Tree.h:

template<class ItemType>
void BTree<ItemType>::postorder_print_helper ( Node<ItemType> * inRoot, int & count ) {
    if (inRoot != NULL) {
        postorder_print_helper ( inRoot->left, count );
        postorder_print_helper ( inRoot->right, count );
        count++;
        std::cout << setw ( 4 ) << inRoot->data << " ";
        if (count % 5 == 0) { std::cout << endl; }
    }
} // end of void BTree<ItemType>::postorder_print_helper ( Node<ItemType> * inRoot )  




template<class ItemType>
void BTree<ItemType>::postorder_print_helper ( Node<ItemType> * inRoot, int & count ) {
    if (inRoot != NULL) {
        postorder_print_helper ( inRoot->left, count );
        postorder_print_helper ( inRoot->right, count );
        count++;
        std::cout << setw ( 4 ) << inRoot->data << " ";
        if (count % 5 == 0) { std::cout << endl; }
    }
} // end of void BTree<ItemType>::postorder_print_helper ( Node<ItemType> * inRoot ) 




template<class ItemType>
bool BTree<ItemType>::remove_helper (Node<ItemType> * inRoot, ItemType toRemove) {
    //if this is the node with the data
    if (inRoot->data == toRemove) {
        //Create Null Node that points to NUll
        Node<ItemType> * nullNode = new Node < ItemType > ;
        //if inRoot has No Children
        if (inRoot->left == NULL && inRoot->right == NULL ) {
            inRoot = nullNode;
            return true;
        }
        //if inRoot has 2 Children
        else if (inRoot->left != NULL && inRoot->right != NULL) {
            Node<ItemType> * temp = new Node < ItemType >;
            temp = return_max_value ( inRoot->left );
            Node<ItemType> * tempRight = new Node < ItemType >;
            tempRight = inRoot->right;
            Node<ItemType> * tempLeft = new Node < ItemType >;
            tempLeft = inRoot->left;
            inRoot = nullNode;
            inRoot = temp;
            temp->left = tempLeft;
            temp->right = tempRight;

            return true;
        }
        //if inRoot has 1 child
        else {
            //if inRoot has left child
            if (inRoot->right == NULL) {
                Node<ItemType> * temp = new Node < ItemType >;
                temp = inRoot->left;
                inRoot = nullNode;
                inRoot = temp;
                return true;
            }
            //if inRoot has right child
            else {
                Node<ItemType> * temp = new Node < ItemType >;
                temp = inRoot->right;
                inRoot = nullNode;
                inRoot = temp;
                return true;
            }
        }
    }
    //If not the node with the data See if toRemove is less than inRoot and perform recursive action
    else if ( toRemove < inRoot->data ) {
        remove_helper ( inRoot->left, toRemove );
    } //end if (toRemove < inRoot->data) 
    //See if toRemove is greater than inRoot and perform recursive action
    else if ( toRemove > inRoot->data)  {
        remove_helper ( inRoot->right, toRemove );
    }// end of else 

    //return false if data cannot be found
    else return false;
}

我的一些结果不同而且都错了。一个结果是无限循环,一直打印树。另一个结果是它预先形成删除并且看起来是成功的但是如果你看两个打印输出,它们是相同的并且节点没有被删除(如果返回false,它不应该再打印出来但它确实如此)。然后第三个结果发生在第二个print_preorder期间。它断开并在空节点上停止,但左右数据都表示“无法读取内存”。我做错了什么?我无法弄清楚。我尝试删除节点之前的所有其他树函数(包括预订打印)。

为了澄清一点,我的remove_helper函数存在问题。所以我可以从Tree1中删除Tree2中存在的节点。

3 个答案:

答案 0 :(得分:2)

remove_helper正在尝试更改inRoot参数的值。但是inRoot是按值传递的,因此函数中所做的任何更改都不会反映在调用函数中。

更改remove_helper函数以引用inRoot,然后它将能够修改调用函数中使用的参数的值:

template<class ItemType>
bool BTree<ItemType>::remove_helper (Node<ItemType> * &inRoot, ItemType toRemove) {

此代码似乎也不正确:

    //Create Null Node that points to NUll
    Node<ItemType> * nullNode = new Node < ItemType > ;

该节点未指向NULL,它指向空节点。在代码的下方,您正在检查inRoot->left == NULL,因此您应该将指针设置为NULL,而不是指向空节点。

你也有很多内存泄漏,请记住 - 如果你使用new创建内容,那么在某处也应该有相应的delete

编辑:还有一件事 - 你永远不想这样做:

 Node<ItemType> * tempRight = new Node < ItemType >;
 tempRight = inRoot->right;

您正在分配一些内存并在tempRight中指向它,然后立即将tempRight设置为其他内容。这是泄漏内存并且是不必要的 - 您不需要为每个指针分配内存。 将其更改为:

 Node<ItemType> * tempRight = inRoot->right;

答案 1 :(得分:0)

你要做的是两棵树之间的倒置交叉。您可以通过创建具有两个参数的函数来完成此操作。一个参数是要从(tree1)中删除内容的树,另一个是要检查的树(tree2)。

在函数中,然后使用递归检查tree2。对于您取出的每个元素,您使用该元素来搜索它是否存在于tree1中(在这种情况下也会删除它)。然后你继续在tree2中为tree2中的每个节点搜索tree1,直到你遍历了tree2中的每个元素。

答案 2 :(得分:0)

好的,在@TheDark的帮助下,这是我的remove_helper函数:

template<class ItemType>
bool BTree<ItemType>::remove_helper (Node<ItemType> * &inRoot, ItemType toRemove) {
    //if this is the node with the data
    if (inRoot->data == toRemove) {
        //if inRoot has No Children
        if (inRoot->left == NULL && inRoot->right == NULL ) {
            inRoot = NULL;
            std::cout << "one" << std::endl;
            return true;
        }
        //if inRoot has 2 Children
        else if (inRoot->left != NULL && inRoot->right != NULL) {
            inRoot->data = return_max_value ( inRoot->left )->data;
            remove_helper (inRoot->left,inRoot->data);
            std::cout << "two" << std::endl;
            return true;
        }
        //if inRoot has 1 child
        else {
            std::cout << "zero" << std::endl;
            //if inRoot has left child
            if (inRoot->right == NULL) {
                Node<ItemType> * temp = new Node < ItemType >;
                temp = inRoot->left;
                inRoot = NULL;
                inRoot = temp;
                return true;
            }
            //if inRoot has right child
            else {
                Node<ItemType> * temp = new Node < ItemType >;
                temp = inRoot->right;
                inRoot = NULL;
                inRoot = temp;
                return true;
            }
        }
    }
    //If not the node with the data See if toRemove is less than inRoot and perform recursive action
    else if ( toRemove < inRoot->data ) {
        remove_helper ( inRoot->left, toRemove );
    } //end if (toRemove < inRoot->data) 
    //See if toRemove is greater than inRoot and perform recursive action
    else if ( toRemove > inRoot->data)  {
        remove_helper ( inRoot->right, toRemove );
    }// end of else 

    //return false if data cannot be found
    else return false;
}

在通过引用传递参数之后,我修复了具有2个子节点的节点的删除。我只是从左边的最大值复制数据,然后删除它来自递归的节点。现在这已经完成,我可以继续我的下一步!谢谢大家。