博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[LeetCode] Delete Node in a BST 删除二叉搜索树中的节点
阅读量:5255 次
发布时间:2019-06-14

本文共 3793 字,大约阅读时间需要 12 分钟。

 

Given a root node reference of a BST and a key, delete the node with the given key in the BST. Return the root node reference (possibly updated) of the BST.

Basically, the deletion can be divided into two stages:

  1. Search for a node to remove.
  2. If the node is found, delete the node.

Note: Time complexity should be O(height of tree).

Example:

root = [5,3,6,2,4,null,7]key = 3    5   / \  3   6 / \   \2   4   7Given key to delete is 3. So we find the node with value 3 and delete it.One valid answer is [5,4,6,2,null,null,7], shown in the following BST.    5   / \  4   6 /     \2       7Another valid answer is [5,2,6,null,4,null,7].    5   / \  2   6   \   \    4   7

 

这道题让我们删除二叉搜索树中的一个节点,这道题的难点在于删除完节点并补上那个节点的位置后还应该是一棵二叉搜索树。被删除掉的节点位置,不一定是由其的左右子节点补上,比如下面这棵树:

         7

        / \
       4   8
     /   \   
    2     6
     \   /
      3 5

如果我们要删除节点4,那么应该将节点5补到4的位置,这样才能保证还是BST,那么结果是如下这棵树:

         7

        / \
       5   8
     /   \   
    2     6
     \   
      3

我们先来看一种递归的解法,首先判断根节点是否为空。由于BST的左<根<右的性质,使得我们可以快速定位到要删除的节点,我们对于当前节点值不等于key的情况,根据大小关系对其左右子节点分别调用递归函数。若当前节点就是要删除的节点,我们首先判断是否有一个子节点不存在,那么我们就将root指向另一个节点,如果左右子节点都不存在,那么root就赋值为空了,也正确。难点就在于处理左右子节点都存在的情况,我们需要在右子树找到最小值,即右子树中最左下方的节点,然后将该最小值赋值给root,然后再在右子树中调用递归函数来删除这个值最小的节点,参见代码如下:

 

解法一:

class Solution {public:    TreeNode* deleteNode(TreeNode* root, int key) {        if (!root) return NULL;        if (root->val > key) {            root->left = deleteNode(root->left, key);        } else if (root->val < key) {            root->right = deleteNode(root->right, key);        } else {            if (!root->left || !root->right) {                root = (root->left) ? root->left : root->right;            } else {                TreeNode *cur = root->right;                while (cur->left) cur = cur->left;                root->val = cur->val;                root->right = deleteNode(root->right, cur->val);            }        }        return root;    }};

 

下面我们来看迭代的写法,还是通过BST的性质来快速定位要删除的节点,如果没找到直接返回空。遍历的过程要记录上一个位置的节点pre,如果pre不存在,说明要删除的是根节点,如果要删除的节点在pre的左子树中,那么pre的左子节点连上删除后的节点,反之pre的右子节点连上删除后的节点。在删除函数中,如果左右子节点都不存在,那么返回空;如果有一个不存在,那么我们返回那个存在的;难点还是在于处理左右子节点都存在的情况,还是要找到需要删除节点的右子树中的最小值,然后把最小值赋值给要删除节点,然后就是要处理最小值可能存在的右子树的连接问题,如果要删除节点的右子节点没有左子节点了的话,那么最小值的右子树直接连到要删除节点的右子节点上即可(因为此时原本要删除的节点的值已经被最小值替换了,所以现在其实是要删掉最小值节点)。否则我们就把最小值节点的右子树连到其父节点的左子节点上。文字表述确实比较绕,请大家自行带例子一步一步观察就会很清晰明了了,参见代码如下:

 

解法二:

class Solution {public:    TreeNode* deleteNode(TreeNode* root, int key) {        TreeNode *cur = root, *pre = NULL;        while (cur) {            if (cur->val == key) break;            pre = cur;            if (cur->val > key) cur = cur->left;            else cur = cur->right;        }        if (!cur) return root;        if (!pre) return del(cur);        if (pre->left && pre->left->val == key) pre->left = del(cur);        else pre->right = del(cur);        return root;    }    TreeNode* del(TreeNode* node) {        if (!node->left && !node->right) return NULL;        if (!node->left || !node->right) {            return (node->left) ? node->left : node->right;        }        TreeNode *pre = node, *cur = node->right;        while (cur->left) {            pre = cur;            cur = cur->left;        }        node->val = cur->val;        (pre == node ? node->right : pre->left) = cur->right;        return node;    }};

 

下面来看一种对于二叉树通用的解法,适用于所有二叉树,所以并没有利用BST的性质,而是遍历了所有的节点,然后删掉和key值相同的节点,参见代码如下:

 

解法三:

class Solution {public:    TreeNode* deleteNode(TreeNode* root, int key) {        if (!root) return NULL;        if (root->val == key) {            if (!root->right) return root->left;            else {                TreeNode *cur = root->right;                while (cur->left) cur = cur->left;                swap(root->val, cur->val);            }        }        root->left = deleteNode(root->left, key);        root->right = deleteNode(root->right, key);        return root;    }};

 

参考资料:

 

转载于:https://www.cnblogs.com/grandyang/p/6228252.html

你可能感兴趣的文章
ServerSocket和Socket通信
查看>>
css & input type & search icon
查看>>
jQuery插件开发详细教程
查看>>
Crontab 在linux中的非常有用的Schedule Jobs
查看>>
ProxySQL Scheduler
查看>>
源代码的下载和编译读后感
查看>>
Kafka学习笔记
查看>>
Octotree Chrome安装与使用方法
查看>>
用CALayer实现下载进度条控件
查看>>
Windows 环境下基于 Redis 的 Celery 任务调度模块的实现
查看>>
趣谈Java变量的可见性问题
查看>>
C# 强制关闭当前程序进程(完全Kill掉不留痕迹)
查看>>
ssm框架之将数据库的数据导入导出为excel文件
查看>>
语音识别中的MFCC的提取原理和MATLAB实现
查看>>
验证组件FluentValidation的使用示例
查看>>
0320-学习进度条
查看>>
解决windows系统的oracle数据库不能启动ora-00119和ora-00130的问题
查看>>
ip相关问题解答
查看>>
MetaWeblog API Test
查看>>
反弹SHELL
查看>>