删除二叉树

删除一个二叉树很简单,但是通常我们是用递归的方式,若用迭代的方式则需要额外的空间来保存信息。

如何在O(N)的时间内使用O(1)的空间来完成二叉树空间的释放呢?这是我在面试中遇到的一个问题.


Morris中序遍历

利用Morris中序遍历可以在O(1)的空间O(N)的时间复杂度内遍历完成二叉树,因此可以在遍历的过程中完成树的空间的释放。我之前转载过Morris遍历二叉树的一篇文章,详细看这里:
Morris方法遍历二叉树

不断改变树的结构

如果不用Morris遍历方法,我们就不可能在O(N)时间O(1)空间内完成中序遍历,因此中序遍历这条路就走不通了。

我们考虑当要删除一个节点的时候,必须要记录下其左右子树的指针才能进行下一步的删除,这样不断删除下去,势必会需要O(N)的空间来进行存储。于是我们可以考虑改变二叉树的结构,当删除一个节点的时候,我们将其一个子树移动到另外一个位置,这样相当于只需要一个cur指针来不断的移动到要删除的节点。具体思路如下:

  • 当前cur指针指向root节点,找到leftMost节点(二叉树中最左边的叶子节点)
  • 若cur节点的右子树不为空,将其右子树设为leftMost节点的左子树,并重新定位leftMost节点,删除当前节点并将cur指向当前节点的左孩子节点
  • 若cur右子树为空,直接删除当前节点并将cur指向当前节点的左孩子节点
  • 重复上述过程,知道cur为空 也就是将二叉树全部节点删除

举一个例子更好理解,如下图:

  1. 当前节点指向root节点1, leftMost节点为5
    这里写图片描述
  2. 1节点有右子树所以其右子树要设为节点5的左子树,并更新leftMost节点,如下图:
    这里写图片描述

  3. 2节点有右子树,因此需要继续把右子树设为leftMost节点3的左子树,并调整leftMost节点为 节点6,删除节点2并设置cur节点为5
    这里写图片描述

  4. 节点5没有右子树,直接删除节点5,并设置cur节点为3
    这里写图片描述

  5. 同理这一步将3节点的右子树设置为6节点的左子树,leftMost节点设为4,删除节点3,并将cur节点为6
    这里写图片描述

  6. 这一步很简单只需要删除节点6,将cur节点设为4
    这里写图片描述

最后删除节点4,整个过程时间复杂度为O(N),空间复杂度为O(1)!

有人可能会疑惑求leftMost节点的过程时间复杂度会达到O(NlgN),但实际上是不会的,如上述几个图,求leftMost节点需要的总步数为:
2+1+1+1 =5 也就是O(N)的时间复杂度。

因此整个算法的时间复杂度仍然是O(N)。

代码实现

最终的实现代码如下:

struct TreeNode {
      int val;
      TreeNode *left;
      TreeNode *right;
      TreeNode(int x) : val(x), left(NULL), right(NULL) {}
  };
//获取最左边的叶节点
TreeNode* getLeftMost(TreeNode* root)
{
   if(NULL == root) return root;
   while(NULL != root->left)
   {
     root = root->left;
   }
   return root;
}

void deletTree(TreeNode* root)
{
   TreeNode* cur = root;
   TreeNode* pre =NULL;
   TreeNode* leftMostNode = getLeftMost(root);
   while(cur)
   {
      pre = cur;
      if(cur->right)
      {
         leftMostNode->left = cur->right;
         leftMostNode = getLeftMost(leftMostNode);//重新设置最左节点 总时间复杂度为O(N)
      }
      cur = cur->left; //当前节点指向当前节点的左孩子
      delete pre;//释放节点空间
   }
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值