1. 程式人生 > >二叉搜尋樹的刪除操作(附例題)

二叉搜尋樹的刪除操作(附例題)

。。。這一部分真心讓我懵逼,可能是我太笨的緣故吧。。。。

二叉搜尋樹的刪除操作。。。具體方法要分情況,

1. 若刪除的節點沒有孩子的時候,直接刪除此節點,然後將父節點NULL;

2.若刪除的節點有一個孩子的時候,直接將父節點連線到其孩子節點,然後刪除此節點。

3.若有兩個節點的時候,這時候就要找個節點代替它了,因為二叉搜尋樹具有左子樹比此節點的值都小,右子樹比此節點的值大,所以(1)可以找左子樹中節點最大的元素,也就是左子樹中最右端的元素,(2)也可以找右子樹中節點最小的元素,也就是右子樹中最左端的節點。讓此節點的值等於子樹中選出的值,然後刪除子樹中的節點,因為被刪除的節點不是在最右端就是在最左端,所以可知此節點只有一個孩子。。。。然後轉到第二種情況。。。

可以看出,這三種情況都需要記住父節點的地址。。。。

然後看浙大資料結構視訊這一節視訊給出的程式碼讓我好懵逼,好不容易才理解。。。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef struct tree
{
    int data;
    struct tree *left,*right;
}tree,*Tree;
//建立二叉搜尋樹;
Tree Create(Tree t,int data)
{
    if(t)
    {
        if(t->data>=data)
            t->left=Create (t->left,data);
        else
            t->right=Create (t->right,data);
    }
    else
    {
        t=(Tree)malloc(sizeof(tree));
        t->data=data;
        t->left=t->right=NULL;
    }
    return t;
}
//先序遍歷二叉搜尋樹;
void Traverse (Tree t)
{
    if(t)
    {
        printf("%d ",t->data);
        Traverse (t->left);
        Traverse (t->right);
    }
}
//找到子樹中最小的節點的地址;
Tree FindMin(Tree t)
{
    if(t)
    while (t->left)
    {
        if(t->left)
            t=t->left;
    }
    return t;
}
Tree Delete (Tree t,int data)
{
    //要被刪除的節點
    Tree temp=NULL;
    if(!t)
        printf("好像沒有此元素呢\n");
    else if(t->data>data)
        t->left=Delete (t->left,data);
    else if(t->data<data)
        t->right=Delete (t->right,data);
    else
    {
        //有兩個子節點時
        if(t->left&&t->right)
        {
            temp=FindMin(t->right);
            t->data=temp->data;
            //下面一定是t->data;因為要找到最小元素並刪除它...
            t->right=Delete (t->right,t->data);
        }
        else
        {
            //這裡挺讓人懵逼的,多想想就好了...
            temp=t;
            if(!t->left)
                t=t->right;
            else if(!t->right)
                t=t->left;
            free(temp);
        }
    }
    return t;
}
int main()
{
    Tree t=NULL;
    int n,temp;
    scanf("%d",&n);
    for (int i=0;i<n;i++)
    {
        scanf("%d",&temp);
        t=Create(t,temp);
    }

    scanf("%d",&temp);
    t=Delete (t,temp);
    Traverse (t);
    return 0;
}

例題為Leetcode的 Delete Node in a BST

給定一個二叉搜尋樹的根節點 root 和一個值 key,刪除二叉搜尋樹中的 key 對應的節點,並保證二叉搜尋樹的性質不變。返回二叉搜尋樹(有可能被更新)的根節點的引用。

一般來說,刪除節點可分為兩個步驟:

  1. 首先找到需要刪除的節點;
  2. 如果找到了,刪除它。

說明: 要求演算法時間複雜度為 O(h),h 為樹的高度。

示例:

root = [5,3,6,2,4,null,7]
key = 3

    5
   / \
  3   6
 / \   \
2   4   7

給定需要刪除的節點值是 3,所以我們首先找到 3 這個節點,然後刪除它。

一個正確的答案是 [5,4,6,2,null,null,7], 如下圖所示。

    5
   / \
  4   6
 /     \
2       7

另一個正確答案是 [5,2,6,null,4,null,7]。

    5
   / \
  2   6
   \   \
    4   7

 這裡用的是遞迴

Java程式碼:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
         if(root==null)
             return root;
        if(root.val<key)
            root.right=deleteNode (root.right,key);
        else if(root.val>key)
            root.left=deleteNode (root.left,key);
        else 
        {
            if(root.left==null||root.right==null)
            {
                if(root.left==null)
                    return root.right;
                else 
                    return root.left;
            }
            else 
            {
                TreeNode t=root.left;
                while (t.right!=null)
                    t=t.right;
                root.val=t.val;
                root.left=deleteNode (root.left,t.val);
            }
        }
        return root;
    }
}