二叉搜索树(BST)删除函数实现正确性咨询
二叉搜索树(BST)删除函数实现疑问
我正在实现一个基础的二叉搜索树(BST),希望获得删除函数的相关帮助。以下是我对节点删除逻辑的理解:
- 删除叶子节点:直接移除该节点(修改其父节点的指针)并返回其数据
- 删除仅含左子节点的节点:移除该节点,将其父节点的对应子节点设为该节点的左子节点
- 删除内部节点:需用右子树中最小的节点替代当前节点,若替代节点有右子节点,则让其占据替代节点原位置
请问以下代码是否正确实现了上述逻辑?
// main function to remove node with "data" template <typename T> T BSTree<T>::delete(T& data){ // BSTree is empty if (root == NULL){ return root; } return delete(root, data); } // recursive function to locate the node to be removed and alter the respective pointers template <typename T> T BSTree<T>::delete(BTNode<T>* node, T& data){ // "data" is to the left of sub-tree if (node->getData() > data){ return delete(node->getLeft(), data); } // "data" is to the right of sub-tree else if (node->getData() < data){ return delete(node->getRight(), data); } // now, node points to the node with "data" // if node is leaf; delete the node and any pointers to it if (node->getLeft() == NULL and node->getRight() == NULL){ // if node is the left child; parents left child will be null if (node->getParent()->getData() > data){ node->getParent()->setLeft(NULL); } // node is the right child; parents right child will be null else{ node->getParent()->setRight(NULL); } } else{ // node to be deleted has only the left child if (node->getRight() == NULL){ node->getLeft()->setParent(node->getParent); // if node is the left child; parents left child will be nodes left child if (node->getParent()->getData() > data){ node->getParent()->setLeft(node->getLeft()); } // node is the right child; parents right child will be nodes left child else{ node->getParent()->setRight(node->getLeft()); } } // node to be deleted has both children else{ BTNode<T>* deleteNode = node; // iterate to the smallest from the right sub-tree node = node->getRight(); while(node->getLeft()){ node = node->getLeft(); } // if the substitute has a right child; put it in the substitutes place if (node->getRight()){ node->getParent()->setLeft(node->getRight()); node->getLeft()->setParent(node->getParent()); } // replace deleteNode and node (ie substitute node) node->setParent(deleteNode->getParent()); // if deleteNode is the left child; parents left child will be node if (deleteNode->getParent()->getData() > data){ deleteNode->getParent()->setLeft(node); } // deleteNOde is the right child; parents right child will be node else{ deleteNode->getParent()->setRight(node); } node = deleteNode; } } delete node; return data; }
代码问题分析
你的思路方向符合BST删除的基本逻辑,但代码存在多个编译错误和逻辑漏洞,无法正确运行:
关键字冲突:
delete是C++的关键字,不能用作函数名,编译会直接报错,建议改为remove或deleteNode。返回值类型不匹配:
- 主函数返回类型是
T,但树为空时返回root(指针类型),类型完全不兼容; - 递归函数同样返回
T,但递归调用逻辑需要返回修改后的子树根节点指针,而非被删除的数据,否则无法更新父节点的指针,树结构不会变化。
- 主函数返回类型是
根节点处理缺失:当待删除节点是根节点时,
node->getParent()为空指针,访问其成员会触发空指针异常,代码完全未覆盖这种场景。递归逻辑错误:递归查找待删除节点时,直接返回子函数结果但未更新当前节点的左/右指针,导致父节点的指针永远不会被修改,删除操作无法生效。
语法错误:仅左子节点分支中,
node->getLeft()->setParent(node->getParent);少了函数调用括号,应为node->getParent(),否则会传递函数地址而非父节点指针,编译失败。内部节点替换逻辑漏洞:
- 替代节点(右子树最小节点)的左子节点必然为空,代码中
node->getLeft()->setParent(...)会触发空指针访问,正确操作应为给替代节点的右子节点设置父节点; - 未将被删除节点的左子树挂载到替代节点上,会丢失左子树数据;
- 当替代节点是被删除节点的直接右子节点时,
node->getParent()指向被删除节点本身,此时设置父节点指针会出现逻辑错误。
- 替代节点(右子树最小节点)的左子节点必然为空,代码中
修正后的核心逻辑参考
递归删除函数应设计为返回BTNode<T>*类型,通过返回修改后的子节点自动更新父节点指针,同时简化根节点和内部节点的处理:
template <typename T> BTNode<T>* BSTree<T>::remove(BTNode<T>* node, T& data) { if (node == nullptr) return nullptr; if (data < node->getData()) { node->setLeft(remove(node->getLeft(), data)); if (node->getLeft() != nullptr) { node->getLeft()->setParent(node); } } else if (data > node->getData()) { node->setRight(remove(node->getRight(), data)); if (node->getRight() != nullptr) { node->getRight()->setParent(node); } } else { // 处理叶子节点/单子节点情况 if (node->getLeft() == nullptr) { BTNode<T>* temp = node->getRight(); delete node; return temp; } if (node->getRight() == nullptr) { BTNode<T>* temp = node->getLeft(); delete node; return temp; } // 找右子树最小节点 BTNode<T>* temp = node->getRight(); while (temp->getLeft() != nullptr) { temp = temp->getLeft(); } // 替换数据而非移动节点 node->setData(temp->getData()); // 删除替代节点 node->setRight(remove(node->getRight(), temp->getData())); if (node->getRight() != nullptr) { node->getRight()->setParent(node); } } return node; }
这种实现通过数据替换简化了内部节点的删除逻辑,同时自动处理了父节点指针更新和根节点场景,避免了空指针风险。
内容的提问来源于stack exchange,提问作者Avishek Sapkota Sharma
相关产品推荐
相关产品推荐

