• 数据结构(5)树形结构——二叉搜索树(JAVA代码实现)


    5.1.概述

    二叉搜索树,也叫二叉查找树、二叉排序树,顾名思义,这种二叉树是专门用来进行数据查找的二叉树。二叉搜索树的查找其实就是二分查找。

    二叉搜索树的定义:

    • 二叉搜索树可以为空
    • 如果二叉搜索树不为空,那么每个有孩子结点的结点,其左孩子的值一定要小于它,其右孩子的值一定要大于它。

    二叉搜索树的操作集:

    既然是专门用来进行查找的二叉搜索树的操作集自然就是增删查,没有改,因为二叉搜索树中的元素都是排序好的,如果直接就地改动某个节点很可能破坏有序性,所以当发现插入的数据有误的时候先删除,再重新插入,一定要保证数据经过了插入流程,这样数据才会在对的位置,才能保证整棵的有序性。

    1. boolean find(Object target);
    2. Object findMin();
    3. Object findMax();
    4. void insert(Object data);
    5. void delete(Object data);

    5.2.操作

    5.2.1.节点

    节点实体如下:

    1. public class Node {
    2. //数据域
    3. private int data;
    4. //指针域
    5. private Node left;
    6. private Node right;
    7. //遍历标志
    8. private boolean isOrder;
    9. {
    10. isOrder=false;
    11. }
    12. public Node(){
    13. }
    14. public Node(int data){
    15. this.data=data;
    16. }
    17. public int getData() {
    18. return data;
    19. }
    20. public void setData(int data) {
    21. this.data = data;
    22. }
    23. public Node getLeft() {
    24. return left;
    25. }
    26. public void setLeft(Node left) {
    27. this.left = left;
    28. }
    29. public Node getRight() {
    30. return right;
    31. }
    32. public void setRight(Node right) {
    33. this.right = right;
    34. }
    35. public boolean isOrder() {
    36. return isOrder;
    37. }
    38. public void setOrder(boolean order) {
    39. isOrder = order;
    40. }
    41. }

    5.2.2.插入

    假设插入35,从根节点开始比较,

    35>30,属于30的右子树,30的右孩子不为空,继续向下走,

    35<41,属于41的左子树,41的左孩子不为空,继续向下走,

    35>33,属于33的右子树。33的右孩子为空,35是33的右孩子。

    代码示例:

    1. //记录根节点
    2. private static Node root=null;
    3. //用于寻路的指针
    4. private static Node flag=null;
    5. public static void insert(Node node){
    6. if(root==null){
    7. System.out.println("我插入"+node.getData()+"作为根节点");
    8. root=node;
    9. }
    10. flag=root;
    11. while (node.getData()
    12. if(flag.getLeft()==null) {
    13. System.out.println("我在"+flag.getData()+"右边插入一个"+node.getData());
    14. flag.setLeft(node);
    15. }
    16. flag = flag.getLeft();
    17. }
    18. while(node.getData()>flag.getData()){
    19. if(flag.getRight()==null) {
    20. System.out.println("我在"+flag.getData()+"右边插入一个"+node.getData());
    21. flag.setRight(node);
    22. }
    23. flag = flag.getRight();
    24. }
    25. }

     5.2.3.查找

    1.查找某个值是否存在

    二叉搜索树的查找其实就是借助数据结构实现了二分查找,如果当前节点的值大于要查找的值,说明要查找的值只可能存在于当前节点的右子树,如果当前节点的值小于要查找的值,说明要查找的值只可能存在于当前节点的左子树。不断重复以上过程,遇见两种情况终止:

    • 当前节点是要查找的值,查找成功,说明值存在。
    • 当前的值不是要查找的值,且节点没有左右子树,是叶子节点,查找失败,说明值不存在。

    代码示例:

    1. public static boolean find(int target){
    2. //从根节点开始
    3. flag=root;
    4. while(true){
    5. //当前节点值为查找值
    6. if(flag.getData()==target){
    7. return true;
    8. }
    9. //向右子树查找
    10. if(target>flag.getData()){
    11. flag=flag.getRight();
    12. }
    13. //向左子树查找
    14. if(target
    15. flag=flag.getLeft();
    16. }
    17. //当前节点是叶节点
    18. if(flag==null){
    19. return false;
    20. }
    21. }
    22. }

    2.查找最大值

    从根节点开始一直沿着右子树的右孩子进行查找,右子树的最后一个右孩子一定是最大值。

    1. public static int findMax(){
    2. flag=root;
    3. while(flag.getRight()!=null){
    4. flag=flag.getRight();
    5. }
    6. return flag.getData();
    7. }

    3.查找最小值

    从根节点开始一直沿着左子树的左孩子进行查找,左子树的最后一个左孩子一定是最小值。

    1. public static int findMin() {
    2. flag = root;
    3. while (flag.getLeft() != null) {
    4. flag = flag.getLeft();
    5. }
    6. return flag.getData();
    7. }

    5.2.4.删除

    被删除的节点有三种情况:

    • 叶子节点,直接删除即可。
    • 只有一个孩子,用孩子节点接替被删除节点即可。
    • 左右孩子双全,用左子树中最大值接替被删除节点,用右子树中最小值接替被删除节点。

    代码示例:

    二叉搜索树由于是整体有序的,每个元素的变动都会造成一定范围内需要进行整体的重新排序,且排序过程是重复的,因此这个过程用递归实现更加简洁,用循环会很冗长,此处选用递归实现。

    1. public static void delete(int target){
    2. flag=root;
    3. //由于删除节点会引起树的调整,为了以防万一根节点需要重新指向一下
    4. root=doDelete(flag,target);
    5. }
    6. private static Node doDelete(Node node,int target){
    7. //空树直接返回,或者是递归出口1:已经遍历完整棵树
    8. if(node == null) {
    9. return null;
    10. }
    11. //递归左子树
    12. if(target < node.getData()) {
    13. node.setLeft(doDelete(node.getLeft(), target));
    14. }
    15. //递归右子树
    16. if(target > node.getData()) {
    17. node.setRight(doDelete(node.getRight(), target));
    18. }
    19. //执行到此步,说明已经出递归,并且没有走递归出口1返回,说明找到了目标
    20. //情况1:被删除节点只有一个孩子节点
    21. //情况2:被删除节点为叶子节点
    22. //以上两种情况可以合并成一个逻辑处理,即指向自己的孩子节点即可
    23. if(node.getLeft() == null) {
    24. return node.getRight();
    25. }
    26. if(node.getRight() == null) {
    27. return node.getLeft();
    28. }
    29. //情况3:被删除节点左右孩子双全,找右子树中最小值接替被删除节点,右子树需递归此过程整体做调整
    30. Node minNode = findMinNode(node.getRight());
    31. node.setData(minNode.getData());
    32. node.setRight(doDelete(node.getRight(),minNode.getData()));
    33. return node;
    34. }
    35. private static Node findMinNode(Node node){
    36. while(node.getLeft() != null)
    37. node = node.getLeft();
    38. return node;
    39. }

  • 相关阅读:
    计算属性,侦听属性,方法区别及例子
    阿里云·短信发送
    【Linux】提升Linux命令行效率:光标移动和文本操作的键盘快捷键
    使用C++的CCF-CSP满分解决方案 202012-2 期末预测之最佳阈值
    6.Paddle Graph Learning (PGL)图学习之图游走类模型[系列四]
    【clickhouse专栏】单机版的安装与验证
    程序化交易行情接口有哪些特点?
    [原创]九点标定工具之机械手头部相机标定
    基于jsp+mysql+ssm协同办公系统-计算机毕业设计
    Spring SpEL表达式语言
  • 原文地址:https://blog.csdn.net/Joker_ZJN/article/details/127999678