【数据结构】二叉搜索树(BST)

简介

二叉搜索树(BST)又称二叉查找树、二叉排序树,它或为一棵空树,或满足以下定义:

❶ 若左子树非空,则左子树上的所有结点的值都小于根结点的值

❷ 若右子树非空,则右子树上的所有结点的值都大于根结点的值

❸ 左、右子树也分别是一棵二叉搜索树

❹ 中序遍历的结果是一个递增的有序序列(重要性质)

 
二叉搜索树实现的功能有:

① 节点定义

② 插入结点

③ 构建二叉树

④ 中序遍历

⑤ 查找

⑥ 返回整棵树的最大最小值

⑦ 返回某个结点的直接前驱/直接后继

⑧ 删除结点(难点)

 
 
 

节点定义

二叉树都这么写 >_<

class TreeNode {

    public int val;
    public TreeNode left;
    public TreeNode right;

    public TreeNode(){}

    public TreeNode(int val) {
        this.val = val;
    }

    public TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }

}

 

插入结点

非常优美的递归写法!如果比根结点小则插入到左子树,如果比根结点大则插入到右子树。

private void insert(TreeNode root, int val) {
	if (root == null) {
		root = new TreeNode(val);
	}
	if (val < root.val) {
		insert(root.left, val);
	} else {
		insert(root.right, val);
	}
}

 

构建二叉树

调用上面的插入结点操作即可!

private void build(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            insert(root, arr[i]);
        }
}

 

中序遍历

中序遍历的结果是一个递增的有序序列!

private void inOrder(TreeNode root) {
        if (root != null) {
            inOrder(root.left);
            System.out.println(root.val);
            inOrder(root.right);
        }
}

 

查找

将二叉搜索树的结构性质体现的淋漓尽致!如果比根结点小则查左子树,如果比根结点大则查右子树,并递归进行。

private boolean search(TreeNode root, int target) {
        if (root == null) {
            return false;
        }
        if (root.val == target) {
            return true;
        }
        if (target < root.val) {
            return search(root.left, target);
        } else {
            return search(root.right, target);
        }
}

private TreeNode searchNode(TreeNode root, int target) {
        if (root == null) {
            return null;
        }
        if (root.val == target) {
            return root;
        }
        if (target < root.val) {
            return searchNode(root.left, target);
        } else {
            return searchNode(root.right, target);
        }
}

 

返回整棵树的最大最小值

查最小值,就是一直走左孩子直到尽头;查最大值,就是一直走右孩子直到尽头。

private TreeNode getMin(TreeNode root) {
        if (root == null) {
            return null;
        }
        if (root.left == null) {
            return root;
        } else {
            return getMin(root.left);
        }

}

private TreeNode getMax(TreeNode root) {
        if (root == null) {
            return null;
        }
        if (root.right == null) {
            return root;
        } else {
            return getMax(root.right);
        }
}

 

返回某个结点的直接前驱/直接后继

在这里插入图片描述

private TreeNode getPrecursor(TreeNode root, TreeNode node) {
        if (node == null) {
            return null;
        }
        if (root.left != null) {
            // 如果左子树不为空,则直接前驱为左子树的最大值
            return getMax(root.left);
        } else {
            // 如果左子树为空,则直接前驱为祖先,一直向上找直到祖先出现在左上
            TreeNode precursor = getParentNode(root, node);
            while (precursor != null && precursor.left == node) {
                node = precursor;
                precursor  = getParentNode(root, node);
            }
            return precursor;
        }
}

private TreeNode getSuccessor(TreeNode root, TreeNode node) {
        if (node == null) {
            return null;
        }
        if (root.right != null) {
            // 如果右子树不为空,则直接后继为右子树的最小值
            return getMin(root.right);
        } else {
            // 如果右子树为空,则直接后继为祖先,一直向上找直到祖先出现在右上
            TreeNode successor = getParentNode(root, node);
            while (successor != null && successor.right == node) {
                node = successor;
                successor = getParentNode(root, node);
            }
            return successor;
        }
}

 

删除结点(难点)

在这里插入图片描述

private void delete(TreeNode root, int target) {
        TreeNode deleteNode = searchNode(root, target);
        TreeNode parentNode = getParentNode(root, deleteNode);
        if (deleteNode.left == null && deleteNode.right == null) {
            // 如果被删除结点是叶子结点,则直接删除
            if (parentNode.left == deleteNode) {
                parentNode.left = null;
            } else {
                parentNode.right = null;
            }
        } else if (deleteNode.left != null && deleteNode.right == null) {
            // 如果被删除结点只有左子树,则让左子树直接替代被删除结点,即子承父业
            if (parentNode.left == deleteNode) {
                parentNode.left = deleteNode.left;
            } else {
                parentNode.right = deleteNode.left;
            }
        } else if (deleteNode.left == null && deleteNode.right != null) {
            // 如果被删除结点只有右子树,则让右子树直接替代被删除结点,即子承父业
            if (parentNode.left == deleteNode) {
                parentNode.left = deleteNode.right;
            } else {
                parentNode.right = deleteNode.right;
            }
        } else {
            // 如果被删除结点有左右两棵子树,则被删除结点的值被其直接后继(直接前驱)结点的值取代,并转换为对直接后继(直接前驱)结点的删除
            TreeNode successor = getSuccessor(root, deleteNode);
            delete(root, deleteNode.val);
            deleteNode.val = successor.val;
        }
}

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

☘️

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值