数据结构与算法(Java)之二叉排序树与AVL树

二叉排序数

package com.weeks.tree.binarysorttree;

/**
 * @author 达少
 * @version 1.0
 * 二叉排序树:
 * 每个结点的左子结点的值小于当前结点的值,右子结点的大于当前结点的值
 * 如果有相同的值则放在左子结点或右子结点(下面的示例放在右子结点上)
 */
public class BinarySortTreeDemo {
    public static void main(String[] args) {
        int[] arr = {7, 3, 10, 12, 5, 1, 9, 2};
        //构建二叉排序数
        BinarySortTree binarySortTree = new BinarySortTree();
        for (int i = 0; i < arr.length; i++){
            binarySortTree.add(new Node(arr[i]));
        }
        System.out.println("中序遍历二叉排序树~~~");
        binarySortTree.infixOrder(binarySortTree.getRoot());

        //测试删除叶子结点
//        binarySortTree.delNode(2);
//        binarySortTree.delNode(5);
//        binarySortTree.delNode(9);
//        binarySortTree.delNode(12);
        binarySortTree.delNode(10);
        System.out.println("\n中序遍历删除结点后的二叉排序树~~~");
        binarySortTree.infixOrder(binarySortTree.getRoot());
    }
}

//定义二叉排序树类
class BinarySortTree{
    //根结点
    private Node root;

    public Node getRoot() {
        return root;
    }

    public void setRoot(Node root) {
        this.root = root;
    }

    //添加结点
    public void add(Node node){
        //如果根结点为空,直接将node赋值给根结点
        if(root == null){
            root = node;
        }else{
            root.add(node);
        }
    }

    //中序遍历
    public void infixOrder(Node root){
        if(root == null){
            System.out.println("空树不能遍历");
            return;
        }
        root.infixOrder();
    }

    //查找指定值的结点
    public Node search(int value){
        if(root == null){//如果是空树直接返回
            return null;
        }
        return root.search(value);
    }

    //查找指定值的父结点
    public Node searchParent(int value){
        if(root == null){
            return null;
        }
        return root.searchParent(value);
    }

    //删除结点
    public void delNode(int value){
        //判断是否是空树
        if(root == null){
            System.out.println("空树,没有结点可删除!!!");
            return;
        }
        //查找指定值的结点
        Node targetNode = root.search(value);
        //当发现没有查找到相应的结点时直接返回
        if(targetNode == null){
            return;
        }
        //当查找的二叉排序数只有一个结点,并且刚好是要查找的结点时
        if(root.getLeft() == null && root.getRight() == null && root.getData() == value){
            //直接将根结点置空
            root = null;
            return;
        }
        //查找指定值的父结点
        Node parent = root.searchParent(value);

        //第一种情况:删除的是叶子结点
        if(targetNode.getLeft() == null && targetNode.getRight() == null){
            //判断targetNode是parent的左子结点还是有右子结点
            //如果parent的左子结点不为空,并且左子结点的值等于value
            if(parent.getLeft() != null && parent.getLeft().getData() == value){
                parent.setLeft(null);//将左子结点置空
            }else if(parent.getRight() != null && parent.getRight().getData() == value){
                //如果parent的右子结点不为空,并且右子结点的值等于value
                parent.setRight(null);//将右子结点置空
            }
        }else if(targetNode.getLeft() != null && targetNode.getRight() != null){//第二种情况:删除的结点有左右子树
            //有两种方式
            //方式一:找到当前结点的右子树的最小值,替换当前当前的结点的值
//            int min = searchRightMin(targetNode.getRight());
//            targetNode.setData(min);

            //方式二:找到当前结点的左子树的最大值,替换当前当前的结点的值
            int max = searchLeftMax(targetNode.getLeft());
            targetNode.setData(max);
        }else{//第三种情况:删除的结点只有左子树或只有右子树
            if(targetNode.getLeft() != null){//删除的结点只有左子树
                //删除的结点为父节结点的左子树
                if(parent.getLeft().getData() == value){
                    parent.setLeft(targetNode.getLeft());
                }else{//删除的结点为父节结点的右子树
                    parent.setRight(targetNode.getLeft());
                }
            }else{//删除的结点只有右子树
                //删除的结点为父节结点的左子树
                if(parent.getLeft().getData() == value){
                    parent.setLeft(targetNode.getRight());
                }else{//删除的结点为父节结点的右子树
                    parent.setRight(targetNode.getRight());
                }
            }
        }
    }

    //查找以指定结点为父节的右子树的最小值
    public int searchRightMin(Node node){
        Node minTarget = node;
        //循环查找
        while(minTarget.getLeft() != null){
            minTarget = minTarget.getLeft();
        }
        //删除最小值的结点
        delNode(minTarget.getData());
        return minTarget.getData();
    }

    //查找以指定结点为父节的右子树的最小值
    public int searchLeftMax(Node node){
        Node maxTarget = node;
        //循环查找
        while(maxTarget.getRight() != null){
            maxTarget = maxTarget.getRight();
        }
        //删除最小值的结点
        delNode(maxTarget.getData());
        return maxTarget.getData();
    }
}

//定义结点类
class Node{
    private int data;
    private Node left;
    private Node right;

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

    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }

    public Node getLeft() {
        return left;
    }

    public void setLeft(Node left) {
        this.left = left;
    }

    public Node getRight() {
        return right;
    }

    public void setRight(Node right) {
        this.right = right;
    }

    //添加结点
    public void add(Node node){
        if(node == null){//如果添加的结点为空
            return;
        }
        //添加的结点值小于当前结点值
        if(node.getData() < this.getData()){
            //如果当前结点的左子结点为空
            if(this.getLeft() == null){
                //将添加的结点挂在当前结点的左子结点下
                this.setLeft(node);
            }else{//否则左递归
                this.left.add(node);
            }
        }else{//添加的结点值大于或等于当前结点值
            //如果当前结点的右子结点为空
            if(this.getRight() == null){
                //将添加的结点挂在当前结点的右子节点下
                this.setRight(node);
            }else{//否则右递归
                this.right.add(node);
            }
        }
    }

    //中序遍历
    public void infixOrder(){
        //左递归
        if(this.left != null){
            this.left.infixOrder();
        }
        //输出当前值
        System.out.print(this.data + " ");
        //右递归
        if(this.right != null){
            this.right.infixOrder();
        }
    }

    //根据指定的值查找结点
    public Node search(int value){
        //判断当前的结点的值是否等于要查找的值
        if(this.data == value){
            return this;
        }
        //判断当前的值与查找的值的大小
        if(this.data > value){
            //向左子结点递归查找
            if(this.left == null){
                return null;
            }
            return this.left.search(value);
        }else {//向右子结点递归查找
            if(this.right == null){
                return null;
            }
            return this.right.search(value);
        }
    }

    //查找指定结点的父节点
    public Node searchParent(int value){
        //如果要查找的结点是父结点,就返回父结点
        if((this.left != null && this.left.data == value) ||
                (this.right != null && this.right.data == value)){
            return this;
        }else{
            //如果查找的值小于当前结点的值,并且当前结点的左子结点不为空
            if(value < this.data && this.left != null){
                return this.left.searchParent(value);
            }else if(value >= this.data && this.right != null){
                //如果查找的值大于或等于当前结点的值,并且当前结点的右子结点不为空
                return this.right.searchParent(value);
            }else{
                return null;//没有找到父结点
            }
        }
    }
}

AVL树

package com.weeks.tree.avltree;

/**
 * @author 达少
 * @version 1.0
 *
 * 平衡二叉树:是一棵二叉排序数,并且左右子树的高度差不大于1
 *
 * 平衡二叉树的提出是因为二叉排序数存在一定的劣势,向{1,2,3,4,5,6}构建成
 * 二叉排序数时,就像单链表一样,两边的二叉树的高度差很大,造成无法体现二叉排
 * 序树的快速查找优势,所以提出平衡二叉树
 *
 */
public class AVLTreeDemo {
    public static void main(String[] args) {
//        int[] arr = {4, 3, 6, 5, 7, 8};
//        int[] arr = {10, 12, 8, 9, 7, 6};
        int[] arr = {10, 11, 7, 6, 8, 9};
        //创建AVL树
        AVLTree avlTree = new AVLTree();
        for(int i : arr){
            avlTree.add(new Node(i));
        }
        //中序遍历AVL树
        avlTree.infixOrder(avlTree.getRoot());

        //测试计算树的高度
        System.out.println("\navlTree的高度:" + avlTree.getRoot().height());
        System.out.println("左子树的高度:" + avlTree.getRoot().leftHeight());
        System.out.println("右子树的高度:" + avlTree.getRoot().rightHeight());
        System.out.println("当前的根结点:" + avlTree.getRoot().getData());
    }
}

//定义二叉排序树类
class AVLTree{
    //根结点
    private Node root;

    public Node getRoot() {
        return root;
    }

    public void setRoot(Node root) {
        this.root = root;
    }

    //添加结点
    public void add(Node node){
        //如果根结点为空,直接将node赋值给根结点
        if(root == null){
            root = node;
        }else{
            root.add(node);
        }
    }

    //中序遍历
    public void infixOrder(Node root){
        if(root == null){
            System.out.println("空树不能遍历");
            return;
        }
        root.infixOrder();
    }

    //查找指定值的结点
    public Node search(int value){
        if(root == null){//如果是空树直接返回
            return null;
        }
        return root.search(value);
    }

    //查找指定值的父结点
    public Node searchParent(int value){
        if(root == null){
            return null;
        }
        return root.searchParent(value);
    }

    //删除结点
    public void delNode(int value){
        //判断是否是空树
        if(root == null){
            System.out.println("空树,没有结点可删除!!!");
            return;
        }
        //查找指定值的结点
        Node targetNode = root.search(value);
        //当发现没有查找到相应的结点时直接返回
        if(targetNode == null){
            return;
        }
        //当查找的二叉排序数只有一个结点,并且刚好是要查找的结点时
        if(root.getLeft() == null && root.getRight() == null && root.getData() == value){
            //直接将根结点置空
            root = null;
            return;
        }
        //查找指定值的父结点
        Node parent = root.searchParent(value);

        //第一种情况:删除的是叶子结点
        if(targetNode.getLeft() == null && targetNode.getRight() == null){
            //判断targetNode是parent的左子结点还是有右子结点
            //如果parent的左子结点不为空,并且左子结点的值等于value
            if(parent.getLeft() != null && parent.getLeft().getData() == value){
                parent.setLeft(null);//将左子结点置空
            }else if(parent.getRight() != null && parent.getRight().getData() == value){
                //如果parent的右子结点不为空,并且右子结点的值等于value
                parent.setRight(null);//将右子结点置空
            }
        }else if(targetNode.getLeft() != null && targetNode.getRight() != null){//第二种情况:删除的结点有左右子树
            //有两种方式
            //方式一:找到当前结点的右子树的最小值,替换当前当前的结点的值
//            int min = searchRightMin(targetNode.getRight());
//            targetNode.setData(min);

            //方式二:找到当前结点的左子树的最大值,替换当前当前的结点的值
            int max = searchLeftMax(targetNode.getLeft());
            targetNode.setData(max);
        }else{//第三种情况:删除的结点只有左子树或只有右子树
            if(parent != null){//!!!注意只有当parent不为空的条件下才能进行下面的逻辑
                if(targetNode.getLeft() != null) {//删除的结点只有左子树
                    //删除的结点为父节结点的左子树
                    if (parent.getLeft().getData() == value) {
                        parent.setLeft(targetNode.getLeft());
                    } else {//删除的结点为父节结点的右子树
                        parent.setRight(targetNode.getLeft());
                    }
                }else{//当parent为空证明删除的结点是根结点
                    root = targetNode.getLeft();
                }
            }else{//删除的结点只有右子树
                if(parent != null) {
                    //删除的结点为父节结点的左子树
                    if (parent.getLeft().getData() == value) {
                        parent.setLeft(targetNode.getRight());
                    } else {//删除的结点为父节结点的右子树
                        parent.setRight(targetNode.getRight());
                    }
                }else{
                    root = targetNode.getRight();
                }
            }
        }
    }

    //查找以指定结点为父节的右子树的最小值
    public int searchRightMin(Node node){
        Node minTarget = node;
        //循环查找
        while(minTarget.getLeft() != null){
            minTarget = minTarget.getLeft();
        }
        //删除最小值的结点
        delNode(minTarget.getData());
        return minTarget.getData();
    }

    //查找以指定结点为父节的右子树的最小值
    public int searchLeftMax(Node node){
        Node maxTarget = node;
        //循环查找
        while(maxTarget.getRight() != null){
            maxTarget = maxTarget.getRight();
        }
        //删除最小值的结点
        delNode(maxTarget.getData());
        return maxTarget.getData();
    }
}

//定义结点类
class Node{
    private int data;
    private Node left;
    private Node right;

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

    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }

    public Node getLeft() {
        return left;
    }

    public void setLeft(Node left) {
        this.left = left;
    }

    public Node getRight() {
        return right;
    }

    public void setRight(Node right) {
        this.right = right;
    }

    //添加结点
    public void add(Node node){
        if(node == null){//如果添加的结点为空
            return;
        }
        //添加的结点值小于当前结点值
        if(node.getData() < this.getData()){
            //如果当前结点的左子结点为空
            if(this.getLeft() == null){
                //将添加的结点挂在当前结点的左子结点下
                this.setLeft(node);
            }else{//否则左递归
                this.left.add(node);
            }
        }else{//添加的结点值大于或等于当前结点值
            //如果当前结点的右子结点为空
            if(this.getRight() == null){
                //将添加的结点挂在当前结点的右子节点下
                this.setRight(node);
            }else{//否则右递归
                this.right.add(node);
            }
        }
        //添加完结点后,当 右子树的高度-左子树的高度>1 时,应该发生左旋转
        if(this.rightHeight() - this.leftHeight() > 1){
            //当满足左旋转的条件下,同时满足 当前结点的右子树的左子树的高度 大于 当前结点的右子树的右子树高度
            //需要先进行有旋转再左旋转,也就是双旋转
            if(this.left != null && this.right.leftHeight() > this.right.rightHeight()){
                this.right.rightRotate();//先右旋转
                leftRotate();//再左旋转
            }else{//如果不满足第二个条件,直接左旋转
                leftRotate();
            }
            return;//旋转完后已经是平衡二叉树了,可以直接结束
        }

        //添加完结点后,当 左子树的高度 - 右子树的高度 > 1 时,应当进行右旋转
        if(this.leftHeight() - this.rightHeight() > 1){
            //当满足右旋转的条件下,同时满足 当前结点的左子树的右子树的高度 大于 当前结点的左子树的左子树高度
            //需要先进行左旋转再右旋转,也就是双旋转
            if(this.left != null && this.left.rightHeight() > this.left.leftHeight()){
                this.left.leftRotate();//先左旋转
                rightRotate();//再右旋转
            }else{//如果不满足第二个条件,直接右旋转
                rightRotate();
            }
        }
    }

    //中序遍历
    public void infixOrder(){
        //左递归
        if(this.left != null){
            this.left.infixOrder();
        }
        //输出当前值
        System.out.print(this.data + " ");
        //右递归
        if(this.right != null){
            this.right.infixOrder();
        }
    }

    //根据指定的值查找结点
    public Node search(int value){
        //判断当前的结点的值是否等于要查找的值
        if(this.data == value){
            return this;
        }
        //判断当前的值与查找的值的大小
        if(this.data > value){
            //向左子结点递归查找
            if(this.left == null){
                return null;
            }
            return this.left.search(value);
        }else {//向右子结点递归查找
            if(this.right == null){
                return null;
            }
            return this.right.search(value);
        }
    }

    //查找指定结点的父节点
    public Node searchParent(int value){
        //如果要查找的结点是父结点,就返回父结点
        if((this.left != null && this.left.data == value) ||
                (this.right != null && this.right.data == value)){
            return this;
        }else{
            //如果查找的值小于当前结点的值,并且当前结点的左子结点不为空
            if(value < this.data && this.left != null){
                return this.left.searchParent(value);
            }else if(value >= this.data && this.right != null){
                //如果查找的值大于或等于当前结点的值,并且当前结点的右子结点不为空
                return this.right.searchParent(value);
            }else{
                return null;//没有找到父结点
            }
        }
    }

    //计算左子树的高度
    public int leftHeight(){
        if(this.left == null){
            return 0;
        }
        return this.left.height();
    }

    //计算右子树的高度
    public int rightHeight(){
        if(this.right == null){
            return 0;
        }
        return this.right.height();
    }

    //计算以当前结点为根结点树的高度
    public int height(){
        return (Math.max(this.left == null ? 0 : this.left.height(), this.right == null ? 0 : this.right.height()) + 1);
    }

    //左旋转,当 右子树的高度-左子树的高度>1 时,应该发生左旋转
    public void leftRotate(){
        //1.创建一个新的结点,并将当前结点的值赋给新的结点
        Node newNode = new Node(this.data);
        //2.新创建的结点的左指针域指向当前结点的左子树
        newNode.left = this.left;
        //3.新创建的结点的右指针域指向当前结点的右子树的左子树
        newNode.right = this.right.left;
        //4.使用当前结点的右子结点的值替换当前结点的值
        this.data = this.right.data;
        //5.将当前结点的左指针域指向新创建的结点
        this.left = newNode;
        //6.将当前结点的右指针域指向右子结点的右子树
        this.right = this.right.right;
    }

    //右旋转,当 左子树的高度 - 右子树的高度 > 1 时,应当进行右旋转
    public void rightRotate(){
        //1.创建一个新的结点,并将当前结点的值赋给新的结点
        Node newNode = new Node(this.data);
        //2.新创建结点的右指针域指向当前结点的右子树
        newNode.right = this.right;
        //3.新创建结点的左指针域向当前结点的左子结点的右子树
        newNode.left = this.left.right;
        //4.使用当前结点的左子结点的值替换当前结点的值
        this.data = this.left.data;
        //5.将当前结点的右指针域指向新创建的结点
        this.right = newNode;
        //6.将当前结点的左指针域指向左子结点的左子树
        this.left = this.left.left;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值