删除结点的话,假设找到的结点为X;需要处理X和父节点之间的关系,我之前直接删除叶子结点就是这里错了,直接删除造成内存泄露。
用递归去做的话,这个结点本身是叶子结点或单边结点,那么在递归的返回值可以解决这个问题,直接返回null或另一边地址即可。
但如果是左右结点都在,有两种操作方式,(我们这里都去找该结点的后继结点Y,也就是该结点的右孩子的最左孩子)
第一种,让X的左结点挂到原来Y的左结点上,同时返回X的右节点即可;这种操作会使树的高度j加倍,如果不是AVL树的话无所谓。而实际上AVL树采用的是下面第二种方式。
第二种,用Y的值去替代X的值,同时将问题转化为删除Y。
递归去做
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key)
{
if(root==nullptr)
return nullptr;
if(root->val==key)
{
if(root->left&&root->right)
{
TreeNode *pre=root;
TreeNode *pmove=root->right;
while(pmove->left)
{pre=pmove;
pmove=pmove->left;}
root->val=pmove->val;
/*下面我就是没有考虑到父结点的情况下删除叶子结点造成泄漏
if(pmove->right)
{
TreeNode *temp=pmove;
pmove=pmove->right;
temp->val=pmove->val;
temp->left=pmove->left;
temp->right=pmove->right;
}
delete pmove;
pmove=NULL;
*/
if(pre->right==pmove)
root->right=pmove->right;
else
pre->left=pmove->right;
delete pmove;
pmove=NULL;
/*上面五行也可以用下面的一句递归调用来解决,也不用pre变量,能大大减少代码长度
root->right=deleteNode(root->right,pmove->val);
*/
return root;
}
else if(root->left)
return root->left;
else
return root->right;
}
if(root->val>key) root->left=deleteNode(root->left,key);
if(root->val<key) root->right=deleteNode(root->right,key);
return root;
}
};
迭代来做
class Solution {
public:
void ifroot(TreeNode* pmove,TreeNode* pre)
{
if(pmove->right&&pmove->left)
{
TreeNode* prl=pmove->right;
pre=pmove;
while(prl->left)
{pre=prl;
prl=prl->left;}
pmove->val=prl->val;
if(pre->right==prl)
pre->right=prl->right;
else
pre->left=prl->right;
delete prl;
pre==NULL;
}
else if(pmove->left)
{
if(pmove==pre->left)
pre->left=pmove->left;
else
pre->right=pmove->left;
pmove=NULL;
}
else
{
if(pmove==pre->left)
pre->left=pmove->right;
else
pre->right=pmove->right;
pmove=NULL;
}
}
TreeNode* deleteNode(TreeNode* root, int key) {
TreeNode *pmove=root;
TreeNode *pre=new TreeNode(0,root,NULL);
while(pmove&&pmove->val!=key)
{pre=pmove;
pmove=pmove->val>key?pmove->left:pmove->right;}
if(!pmove) return root;
ifroot(pmove,pre);
if(root==pmove)
root=pre->left;
return root;
}
};