https://leetcode.com/problems/delete-node-in-a-bst/#/description
題目大意是實現在一個二叉樹中刪除一個節點的算法
要刪除二叉搜索樹中的某個節點p需要考慮三種情況:
1)p有兩顆非空子樹
2)p是樹葉
3)p是只有一顆非空子樹
刪除p節點的思路
1)要刪除的節點p具有兩顆非空子樹。先將該節點的元素替換為它的左子樹的最大元素或右子樹的最小元素。
2)要刪除的節點是葉子節點 。處理的方法是釋放該節點空間,若是根節點,則令根為NULL。
3 ) 要刪除的節點p只有一顆子樹。如果p沒有節點(即p是根節點),則p的唯一子樹的根節點成為新的搜索樹的根節點。如果p有父節點pp,則修改pp的指針域,使得它指向p的唯一孩子,然后釋放節點p。
以下是我實現的代碼
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
root = deleteNodeitem(root, key);
return root;
}
TreeNode* deleteNodeitem(TreeNode* root, int key){
TreeNode* p = root;//the keynode to delete
TreeNode* pp = root;//parentNode of the keynode
TreeNode* s;//the node to replace the keynode
TreeNode* ps;//parent node of replacenode
//findout the keynode p and its parant node pp
while((p != NULL)&&(p->val != key)){
pp = p;
if(key > p->val){
p = p->right;
}else if(key < p->val){
p = p->left;
}
}
if(p == NULL){
return root;
}
//state1 node p have 2 nonull childnode
if((p->left!=NULL)&&(p->right!=NULL)){
//find the biggest node in the right tree
s = p->right;
ps = p;
while(s->left != NULL){
ps = s;
s = s->left;
}
TreeNode q = {s->val}; q.left = p->left; q.right = p->right;
if(pp->left == p){
pp->left = &q;
}else if(pp->right == p){
pp->right = &q;
}else if(p == root){//要刪除的節點就是根節點
pp->val = q.val;
cout<< "要刪除的節點就是根節點" <<endl;
}
//make the s node to delete 找出節點s所對應的父節點
if(ps != p){
pp = ps;
}else if((p == ps)&&(p!=root)){//當s的父節點即為p節點時
pp = &q;
cout<< "當s的父節點即為p節點時" <<endl;
}
p = s;//it must one left child of p if p has child
}
//statue2 node p have at most one nonull childnode
TreeNode* pc = p;//the child of p , if it has.
if(p->left != NULL){
pc = p->left;
}else if(p->right != NULL){
pc = p->right;
}else{
pc = NULL;//p has no child
}
if(pp->left == p){
pp->left = pc;
}else if(pp->right == p){
pp->right = pc;
}else{
root = pc;//根節點就是需要刪除的節點
}
// delete p;
return root;
}
};
可見代碼還是相對繁瑣的,下面是其他網友提供的更簡潔的算法,大體思路是一樣的但利用遞歸代碼量大大的減少
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if (!root) return nullptr;
if (root->val == key) {
if (!root->right) {
TreeNode* left = root->left;
delete root;
return left;
}
else {
TreeNode* right = root->right;
while (right->left)
right = right->left;
swap(root->val, right->val);
}
}
//利用遞歸找出左右子樹中要刪除的節點,并利用該節點的右子樹中的左子樹的最小節點替換掉要被刪除的節點
root->left = deleteNode(root->left, key);
root->right = deleteNode(root->right, key);
return root;
}
};