二叉排序树

1.需求分析:

假设给定一个数列  [36,65,18,7,60,89,43,57,96,52,74],能够有效的完成对数据的查询和添加。

2.思路分析:

        使用数组:

                1、使用未排序数组可以直接将数组插入到数组尾端,速度快,但是查找慢

                2、使用排序好数组,查询比较快,但是插入新数据时,需要整体移动后,插入有效的位置,过程比较慢

        使用链表:

                链表特点是插入数据比较方便,但是查询数据比较慢

3.二叉排序树介绍:

二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树。是数据结构中的一类。在一般情况下,查询效率比链表结构要高。

如果有相同的值,可以将该节点放在左子节点和右子节点上。

6027f8ae2b8e4aa2b10c8ec68624dd92.png

同一集数据对应的二叉排序树不唯一。但经过中序遍历得到的关键码序列都是一个递增序列。

4.排序:

例如,假设原二叉排序树为空树,在对动态查找表 {3,5,7,2,1} 做查找以及插入操作时,可以构建出一个含有表中所有关键字的二叉排序树。

27339fa5c0dd42c6bb205b83391bc39a.png

5.删除:

其中二叉排序树是一个动态树表,其特点就是树的结构不是一次生成的,而是在查找过程中,如果关键字不在树表中,在把关键字插入到树表中。而对于删除操作,它分为三种情况

1.删除结点为叶子结点(左右子树均为NULL),所以我们可以直接删除该结点,如下图所示:

b8828aede6b74c8382d6b8e51e39a1fa.png

2.删除结点只有左子树或者右子树,此时只需要让其左子树或者右子树直接替代删除结点的位置,称为删除结点的双亲的孩子,就可以了,如下图所示:

5c12f2a78cbd45ca9c66d1b2e3408f6b.png

3.当要删除的那个结点,其左右子树都存在的情况下,则要从从左子树中找出一个最大的值那个结点来替换我们需要删除的结点,如下图所示:

0c8ac3fb592b474a8756d2c93dd96e9e.png

bedc68e4b10d45508548b7666dbf3be6.png

6.代码实现:

package binarysort;

/**
 * @author WuChenGuang
 */
public class Node {

    public int value;

    public Node left;

    public Node right;

    public Node(int value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "Node{" +
                "value=" + value +
                '}';
    }

    /**
     * 添加节点
     */
    public void add(Node node) {
        if (node == null) {
            return;
        }

        // 传入的值与当前节点关系比较
        if (node.value < this.value) {
            if (this.left == null) {
                this.left = node;
            } else {
                this.left.add(node);
            }
        } else {
            if (this.right == null) {
                this.right = node;
            } else {
                this.right.add(node);
            }
        }
    }

    /**
     * 中序遍历   关键码值递增
     */
    public void infixSelect() {
        if (this.left != null) {
            this.left.infixSelect();
        }
        System.out.println(this);
        if (this.right != null) {
            this.right.infixSelect();
        }
    }

    public Node selectByVal(int val) {
        if (this.value == val) {
            return this;
        } else if (val < this.value) {
            //查左子树
            if (this.left == null) {
                return null;
            }
            return this.left.selectByVal(val);
        } else {
            // 查询右子树
            if (this.right == null) {
                return null;
            }
            return this.right.selectByVal(val);
        }
    }

    public Node selectByParent(int val) {
        boolean left = this.left != null && this.left.value == val;
        boolean right = this.right != null && this.right.value == val;
        if (left || right) {
            return this;
        } else {
            if (val < this.value && this.left != null) {
                return this.left.selectByParent(val);
            } else if (val >= this.value && this.right != null) {
                return this.right.selectByParent(val);
            } else {
                return null;
            }
        }
    }
}

package binarysort;

/**
 * @author WuChenGuang
 */
public class BinarySortTree {

    private Node root;

    public Node getRoot() {
        return root;
    }

    /**
     * 查询
     */
    public Node selectByVal(int val) {
        if (root == null) {
            return null;
        } else {
            return root.selectByVal(val);
        }
    }

    /**
     * 查询父节点
     */
    public Node selectByParent(int val) {
        if (root == null) {
            System.out.println("root is null");
            return null;
        } else {
            return root.selectByParent(val);
        }
    }

    /**
     * 添加节点
     */
    public void add(Node node) {
        if (root == null) {
            root = node;
        } else {
            root.add(node);
        }
    }

    /**
     * 中序遍历
     */
    public void infixSelect() {
        if (root != null) {
            root.infixSelect();
        } else {
            System.out.println("空树...");
        }
    }

    /**
     * 找出右子树中最小值
     */
    public int rightTreeMin(Node node) {

        Node target = node;
        while (target.left != null) {
            target = target.left;
        }

        delNode(target.value);
        return target.value;
    }

    /*
      删除节点
      1.如果删除的节点是叶子节点,找到父节点直接删除关联
      2.如果的点带有左子树或者带有右子树,把左子树或右子树的节点交给删除该节点的父结点
      3.如果删除的节点带有双亲节点,可以从左子树中找一个最大节点替换山删除节点,也可以找右子树最小的值节点
      替换要删除的节点
     */

    /**
     * 删除的节点
     */
    public void delNode(int val) {
        if (root != null) {
            Node target = selectByVal(val);
            if (target == null) {
                return;
            }

            if (root.left == null && root.right == null) {
                root = null;
                return;
            }

            // 找到目标节点父结点
            Node parentNode = selectByParent(val);

            // 1.假设删除的是一个叶子节点
            if (target.left == null && target.right == null) {
                // 判断删除节点时父结点的左节点还是右节点
                if (parentNode.left != null && parentNode.left.value == val) {
                    // 左节点
                    parentNode.left = null;
                } else if (parentNode.right != null && parentNode.right.value == val) {
                    parentNode.right = null;
                }

            } else if (target.left != null && target.right != null) {
                target.value = rightTreeMin(target.right);
            } else {
                // 删除只有一个子树(可能右子树,可能是左子树)
                if (target.left != null) {
                    // 左子树
                    if (parentNode != null) {
                        // 确定是左子节点
                        if (parentNode.left.value == val) {
                            parentNode.left = target.left;
                        } else {
                            // 右节点
                            parentNode.right = target.left;
                        }
                    } else {
                        root = target.left;
                    }
                } else {
                    // 右节点
                    if (parentNode != null) {
                        if (parentNode.left.value == val) {
                            parentNode.left = target.right;
                        } else {
                            parentNode.right = target.right;
                        }
                    } else {
                        root = target.right;
                    }
                }
            }
        }
    }
}
package binarysort;

/**
 * @author WuChenGuang
 */
public class Test {
    public static void main(String[] args) {

        int[] array = {7, 3, 10, 12, 5, 1, 9, 2};
        BinarySortTree binarySortTree = new BinarySortTree();
        for (int j : array) {
            binarySortTree.add(new Node(j));
        }

        binarySortTree.infixSelect();
        System.out.println("====================");

        binarySortTree.delNode(3);
        binarySortTree.infixSelect();
    }
}

运行结果:

8239e5875c784b3d8f035f9478ed68bb.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ll520.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值