题目链接:235. 二叉搜索树的最近公共祖先、701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点
文章链接:代码随想录
二叉树
1. 二叉搜索树的最近公共祖先
(待更新...)
//递归法
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == NULL) return root;
//若p和q的节点值均小于当前节点值,说明p和q都在当前节点的左子树中,往左递归
if(root -> val > p -> val && root -> val > q -> val) {
TreeNode* left = lowestCommonAncestor(root -> left, p, q);
if(left != NULL) return left;
//若p和q的节点值均大于当前节点值,说明p和q都在当前节点的右子树中,往右递归
} else if(p -> val > root -> val && q -> val > root -> val) {
TreeNode* right = lowestCommonAncestor(root -> right, p, q);
if(right != NULL) return right;
}
//以上两种条件都不符合,则当(p -> val <= root -> val && root -> val <= q -> val)
//或(q -> val <= root -> val && root -> val <= p -> val)时,root就是最近公共祖先,直接返回
return root;
}
};
//迭代法
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
while(root != NULL) {
if(root -> val > p -> val && root -> val > q -> val)
root = root -> left;
else if(root -> val < p -> val && root -> val < q -> val)
root = root -> right;
else return root;
}
return root;
}
};
2. 二叉搜索树中的插入操作
(待更新...)
//递归法
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
//终止条件:遍历到空节点,这个位置就要插入新的节点
if(root == nullptr) {
TreeNode* node = new TreeNode(val);
return node; //利用返回值完成新插入的节点与其父节点的赋值操作
}
//下一层将加入节点返回,本层用root->left或者root->right将其接住
if(root -> val > val) root -> left = insertIntoBST(root -> left, val);
else if(root -> val < val) root -> right = insertIntoBST(root -> right, val);
return root;
}
};
//迭代法
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
TreeNode* node = new TreeNode(val); //待插入的新节点
if(root == NULL) return node; //如果根节点为空,直接返回新节点
TreeNode* parent = root; //父亲节点,记录遍历的上一个节点
TreeNode* cur = root; //当前遍历的节点
//遍历
while(cur != NULL) {
parent = cur;
if(cur -> val > val) cur = cur -> left;
else if(cur -> val < val) cur = cur -> right;
}
//遍历结束后,parent指向最后一个遍历的节点(也就是待插入新节点的父亲节点),cur此时为空
//再做一次判断,完成新节点与父亲节点的赋值操作
if(parent -> val > val) parent -> left = node;
else parent -> right = node;
return root;
}
};
3. 删除二叉搜索树中的节点
(待更新...)
/*
以下面这个二叉树为例,描述二叉搜索树删除节点可能遇到的五种情况:
第一种:遍历到空节点,说明没有找到要删除的节点
第二种:要删除的节点在二叉树中左右都为空(即叶子节点),直接删除该节点(例如下图节点1)
第三种:要删除的节点在二叉树中左不为空,右为空,此时删除该节点,并将其左孩子与其父亲节点衔接(例如下图节点2)
第四种:要删除的节点在二叉树中左为空,右不为空,此时删除该节点,并将其右孩子与其父亲节点衔接(处理逻辑同上)
第五种:要删除的节点在二叉树中左右均不为空,此时有两种处理逻辑,一是将左子树衔接到右子树上,二是将右子树衔接到左子树上(例如下图节点7)
*原二叉树*
3
/ \
2 7
/ / \
1 5 9
/ \ / \
4 6 8 10
*第三种情况*
3
/ \
1 7
/ \
5 9
/ \ / \
4 6 8 10
*第五种情况* (解法一) *第五种情况* (解法二)
3 3
/ \ / \
2 9 2 5
/ / \ / / \
1 8 10 1 4 6
/ \
5 9
/ \ / \
4 6 8 10
*/
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
//终止条件:
//若根节点为空,则直接返回空
//也可以作为第一种情况的处理方法:遍历到空节点,说明没有找到要删除的节点,直接返回空
if(root == nullptr) return NULL;
//找到了要删除的节点,接下来对可能出现的四种情况进行讨论
if(root -> val == key) {
//第二种:要删除的节点在二叉树中左右都为空(即叶子节点),直接删除该节点,返回空
if(!root -> left && !root -> right) {
//释放内存
delete root;
return NULL;
//第三种:要删除的节点在二叉树中左不为空,右为空,此时删除该节点,并将其左孩子与其父亲节点衔接,处理方法是将其左孩子返回到上一层递归,注意要为删除的节点释放内存
} else if(root -> left && !root -> right) {
TreeNode* node = root -> left;
//释放内存
delete root;
return node;
//第四种:要删除的节点在二叉树中左为空,右不为空,此时删除该节点,并将其右孩子与其父亲节点衔接,处理方法是将其右孩子返回到上一层递归,注意要为删除的节点释放内存
} else if(!root -> left && root -> right) {
TreeNode* node = root -> right;
//释放内存
delete root;
return node;
//第五种:要删除的节点在二叉树中左右均不为空,此时采用第一种解法,即将左子树衔接到右子树上
//方法是找到删除节点右子树上最左边的节点,然后将删除节点的左孩子(也就是其左子树的头节点)接上去
//最后返回删除节点的右孩子作为新的根节点
} else {
TreeNode* cur = root -> right; //删除节点的右孩子
while(cur -> left != nullptr) {
cur = cur -> left; //找到删除节点右子树上最左边的节点
}
cur -> left = root -> left; //将将删除节点的左孩子(也就是其左子树的头节点)接上去
TreeNode* node = root -> right;//返回删除节点的右孩子作为新的根节点
//释放内存
delete root;
return node;
}
}
if(root -> val > key) root -> left = deleteNode(root -> left, key);
else if(root -> val < key) root -> right = deleteNode(root -> right, key);
return root;
}
};
相关题目和后续提高:
提高:
普通二叉树的删除方式
“删除二叉搜索树中的节点”迭代法