【问题标题】:Delete node method not actually deleting node in binary search tree. C++删除节点方法实际上并不删除二叉搜索树中的节点。 C++
【发布时间】:2019-11-19 11:20:17
【问题描述】:

当我调用我的 removeNode 方法时,它显示要在本地删除节点并在调试器中将其设置为 null,但是当我在调试器中查看树时,应该删除的节点仍然存在。当我打印树时,应该被删除的节点会打印出来,但是分配给结构的 int 和字符串却指向打印出乱码。

我尝试过使用 free() 和 delete,但都没有真正删除节点。

bool BinTree::addNode(int id, string info, DataNode *add_node) {
    auto *temp_node = new DataNode;
    temp_node->data.id = id;
    temp_node->data.information = info;
    temp_node->left = temp_node->right = nullptr;

    if(id < add_node->data.id){
        if(!add_node->left){
            add_node->left = new DataNode;
            add_node->left = temp_node;
            count++;
        }else{
            addNode(id, info, add_node->left);
        }
    }else{
        if(!add_node->right){
            add_node->right = new DataNode;
            add_node->right = temp_node;
            count++;
        }else{
            addNode(id, info, add_node->right);
        }
    }
}

bool BinTree::removeNode(int id, DataNode *temp_root) {
    cout << "Searching to remove: " << id << endl;
    if(temp_root == nullptr){
        return false;
    }
    else if(id < temp_root->data.id) {
        removeNode(id, (temp_root->left);
    }
    else if(id > temp_root->data.id){
        removeNode(id, temp_root->right);
    }
    else{
        //no child
        if(temp_root->left == nullptr && temp_root->right == nullptr){
            cout << "Deleting no children node" << endl;            //DEBUG ONLY
            cout << "Temp root address:" << temp_root << endl;      //DEBUG ONLY
            delete temp_root;
            temp_root->data.id = 123456;                            //DEBUG ONLY
            cout << "no child deleted" << endl;                     //DEBUG ONLY
            count--;
        }
        //one child
        else if(temp_root->left == nullptr){
            cout << "Deleting 1 child node" << endl;
            DataNode *temp_node = temp_root;
            temp_root = temp_root->right;
            delete temp_node;
            temp_node = nullptr;
            count--;
        }
        else if(temp_root->right == nullptr){
            cout << "Deleting 1 child node" << endl;
            DataNode *temp_node = temp_root;
            temp_root = temp_root->left;
            free(temp_node);
            temp_node = nullptr;
            count--;
        }
        //two children
        else if(temp_root->left && temp_root->right){
            cout << "Deleting 2 child node" << endl;
            DataNode temp_node = minValueNode(temp_root->right);
            temp_root->data = temp_node.data;
            removeNode(temp_node.data.id, temp_root->right);
        }
        return true;
    }
}

DataNode BinTree::minValueNode(DataNode *temp_node) {
    while(temp_node->left){
        temp_node = temp_node->left;
    }
    return *temp_node;
}

我在方法中有一些调试输出,以验证它正在删除的 temp_root 地址是否与给定节点的树具有相同的地址,这是正确的。它只是没有从实际的树中删除它。

【问题讨论】:

  • delete temp_root; temp_root-&gt;data.id = 123456; 是未定义的行为。删除后不能使用指针,除非将其重新分配给另一个有效地址。
  • 我这样做是为了检查代码的输出,而不是乱码,它会在整数中显示 123456。只是用来验证它实际上没有被删除。
  • 变量temp_nodetemp_root 是函数的局部变量。您没有更改实际树中的任何节点,只是更改了局部变量。
  • 只是用来验证它实际上没有被删除。 这不是一个有效的测试。取消引用已删除的指针是未定义的行为。
  • 如何将 root 的实际值传递给 temp_root?我的印象是通过这种方式可以让我直接修改树。

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


【解决方案1】:

我个人会编写 remove 以返回链接的新值。

void removeNode(int id) {
    root = removeNode(id, root);
}
Node* removeNode(int id, Node* n) {
    if (n == nullptr) {
        return nullptr;
    }

    if (id < n->id) {
        n->left = removeNode(id, n->left);
        return n;
    }
    else if (n->id < id) {
        n->right = removeNode(id, n->right);
        return n;
    }
    else if (n->left == null) {
         Node* result = n->right;
         delete n;
         return result;
    }
    else if (n->right == null) {
         Node* result = n->left;
         delete n;
         return result;
    }
    else {
         int v = findSmallestValue(n->right);
         n->right = removeNode(v, n->right);
         n->id = v;
         return n;
    }
}

【讨论】:

  • 我没有看到这说明了一个没有子节点的原因,但我可能读错了。
  • @justenc94 你不需要那个。如果一个节点没有子节点,那么 left 和 right 都为空。因此它将被else if (n-&gt;left == null) { 捕获,它会删除当前节点并返回正确的节点作为该位置的新节点。正确的节点已经为空,所以我们得到了正确的行为。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多