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

Posted 达少Rising

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法(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){以上是关于数据结构与算法(Java)之二叉排序树与AVL树的主要内容,如果未能解决你的问题,请参考以下文章

红黑树与AVL树

数据结构之二叉堆堆排序

python常用算法——树,二叉树与AVL树

数据结构之二叉搜索树AVL自平衡树

数据结构与算法:树 AVL平衡二叉排序树

数据结构与算法:树 AVL平衡二叉排序树