数据结构之平衡二叉树

1.背景

面试中经常问到关于二叉平衡树的知识点

2.左旋

 

 

 /**
     * 左旋
     * 右边高就左旋
     */
    public void leftRotate() {
        // 定义一个新的当前节点
        Node nodeNew = new Node(value);
        // 新节点的左节点为:当前节点的左节点
        nodeNew.leftNode = leftNode;
        // 新节点的右节点:当前节点的右节点的左节点
        nodeNew.rightNode = rightNode.leftNode;
        // 值替换:当前节点的值替换为当前节点右节点的值
        value = rightNode.value;
        // 当前节点的左节点为: 新的节点
        leftNode = nodeNew;
        // 当前节点的右节点为: 当前节点的右节点的右节点
        rightNode = rightNode.rightNode;
    }

 

3.右旋

 

 

 /**
     * 右旋
     * 左边边高就右旋
     */
    public void rightRotate() {
        // 步骤1:定义新节点10,newNode
        Node newNode = new Node(value);
        // 步骤2:新节点的左节点为9
        newNode.leftNode = leftNode.rightNode;
        // 步骤3:新节点的右节点为12
        newNode.rightNode = rightNode;
        // 步骤4:8替换10的值
        value = leftNode.value;
        // 步骤5:8节点的左节点为7
        leftNode = leftNode.leftNode;
        // 步骤6:8节点的右节点为新的节点10
        rightNode = newNode;
    }

 

4.双旋

 

 

 /**
     * 添加一个节点
     *
     * @param node
     */
    public void add(Node node) {
        if (node.value < this.value) { // 放在左边
            if (this.leftNode == null) {
                this.leftNode = node;
            } else {
                this.leftNode.add(node);
            }
        } else {// 放在右边
            if (this.rightNode == null) {
                this.rightNode = node;
            } else {
                this.rightNode.add(node);
            }
        }
        // 当添加完节点后,如果(右子树的高度-左子树的高度>1),左旋
        if (rightHeight() - leftHeight() > 1) {
            // 如果(它的右子树的左子树高度-它的右子树的右子树高度>0)
            if (rightNode != null && rightNode.leftHeight() - rightNode.rightHeight() > 0) {
                // 先对右子节点进行右旋
                rightNode.rightRotate();
                // 然后在对当前节点进行左旋
                leftRotate();
            } else {
                // 直接左旋
                leftRotate();
            }
            // 当前情况处理完成后返回,避免继续往下面执行
            return;
        }
        // 当添加完成一个节点后,如果(左子树的高度-右子树的高度>1),右旋
        if (leftHeight() - rightHeight() > 1) {
            // 如果它的左子树的右子树高度大于它的左子树的左子树的高度
            if (leftNode != null && leftNode.rightHeight() - leftNode.leftHeight() > 0) {
                // 它的左子树左旋
                leftNode.leftRotate();
                // 当前节点右旋
                rightRotate();
            } else {
                // 当前节点右旋
                rightRotate();
            }
            return;
        }
    }

 

 

5.代码

package com.ldp.structure.demo08AVLTree;

import org.junit.Test;

/**
 * @create 05/03 11:18
 * @description <p>
 * 二叉平衡树
 * </p>
 */
public class Test01 {
    /**
     * 二叉排序树,添加测试
     */
    @Test
    public void test01() {
        int[] array = {100, 110, 70, 80, 60, 90};
        BstTree bstTree = new BstTree();
        // 添加到二叉树
        for (int i : array) {
            bstTree.add(new Node(i));
        }
        // 中序遍历
        bstTree.middleList();
    }
}

class BstTree {
    Node root;

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

    /**
     * 删除节点
     *
     * @param value
     */
    public void delete(Integer value) {
        Node targetNode = getTargetNode(value);
        if (targetNode == null) {
            System.out.println("该节点不存在:value=" + value);
            return;
        }
        Node targetNodeParent = getTargetNodeParent(value);
        // 1.待删除的节点有零个叶子节点(本身是叶子节点)
        if (targetNode.leftNode == null && targetNode.rightNode == null) {
            deleteZero(targetNodeParent, value);
            System.out.println("节点删除成功:value=" + value);
        } else if (targetNode.leftNode != null && targetNode.rightNode != null) {
            // 3.待删除的节点有两个叶子节点
            deleteTwo(targetNode);
            System.out.println("节点删除成功:value=" + value);
        } else {
            // 2.待删除的节点有一个叶子节点
            deleteOne(targetNodeParent, targetNode, value);
            System.out.println("节点删除成功:value=" + value);
        }
    }

    /**
     * 待删除的节点有零个叶子节点(本身是叶子节点)
     * 1.找到待删除的节点 targetNode;
     * 2.找到targetNode的父节点 parentNode;
     * 3.判定targetNode是parentNode的左节点还是右节点
     * 如果targetNode是parentNode的左节点:parentNode.leftNode=null;
     * 如果targetNode是parentNode的右节点:parentNode.rightNode=null;
     */
    private void deleteZero(Node nodeParent, Integer value) {
        if (nodeParent == null) {
            root = null;
            return;
        }
        if (nodeParent.leftNode.value == value) {
            nodeParent.leftNode = null;
        } else {
            nodeParent.rightNode = null;
        }
    }

    /**
     * 待删除的节点有一个叶子节点
     * 1.找到待删除的节点 targetNode;
     * 2.找到targetNode的父节点 parentNode;
     * 3.判定targetNode是parentNode的左节点还是右节点
     * 如果targetNode是parentNode的左节点:
     * 且targetNode的叶子节点是左节点:parentNode.leftNode=targetNode.leftNode
     * 且targetNode的叶子节点是右节点:parentNode.leftNode=targetNode.rightNode
     * 如果targetNode是parentNode的右节点:
     * 且targetNode的叶子节点是左节点:parentNode.rightNode=targetNode.leftNode
     * 且targetNode的叶子节点是右节点:parentNode.rightNode=targetNode.rightNode
     */
    private void deleteOne(Node nodeParent, Node targetNode, Integer value) {
        Node tempNode;
        if (targetNode.leftNode != null) {// targetNode的叶子节点是左节点
            tempNode = targetNode.leftNode;
        } else {
            tempNode = targetNode.rightNode;
        }
        // 如果父节点为空
        if (nodeParent == null) {
            root = tempNode;
            return;
        }
        if (nodeParent.leftNode != null && nodeParent.leftNode.value == value) {// 如果targetNode是parentNode的左节点
            nodeParent.leftNode = tempNode;
        } else {
            nodeParent.rightNode = tempNode;
        }
    }

    /**
     * 待删除的节点有两个叶子节点
     * 1.找到待删除的节点 targetNode;
     * 2.targetNode的右节点开始找,找到最小节点
     * 3.用一个临时节点minNode保存
     * 4.删除最小节点
     * 5.targetNode.value=minNode.value
     *
     * @param targetNode
     */
    private void deleteTwo(Node targetNode) {
        Node minNodeParent = targetNode;
        Node minNode = targetNode.rightNode;
        if (targetNode.rightNode.leftNode == null) { // 如果股目标节点的右节点没有左子节点,则右节点是最小节点
            minNodeParent.rightNode = null;
            targetNode.value = minNode.value;
        } else {// 如果股目标节点的右节点有左子节点,则一直往最左边找,最后一个左节点是最小节点
            while (true) {
                if (minNode.leftNode != null) {
                    minNodeParent = minNode;
                    minNode = minNode.leftNode;
                } else {
                    break;
                }
            }
            minNodeParent.leftNode = null;
            targetNode.value = minNode.value;
        }
    }


    /**
     * 根据value找到目标节点
     *
     * @param value
     * @return
     */
    public Node getTargetNode(Integer value) {
        Node tempNode = root;
        while (tempNode != null) {
            if (tempNode.value.equals(value)) {// 已找到
                break;
            } else if (value < tempNode.value) {
                tempNode = tempNode.leftNode;
            } else {
                tempNode = tempNode.rightNode;
            }
        }
        return tempNode;
    }

    /**
     * 根据value找到目标节点的父节点
     *
     * @param value
     * @return
     */
    public Node getTargetNodeParent(Integer value) {
        if (this.root.value.equals(value)) {
            System.out.println("该节点没有父节点.....");
            return null;
        }
        Node parentNode = null;
        Node tempNode = root;
        while (tempNode != null) {
            if (tempNode.value.equals(value)) {// 已找到
                break;
            } else if (value < tempNode.value) {
                parentNode = tempNode;
                tempNode = tempNode.leftNode;
            } else {
                parentNode = tempNode;
                tempNode = tempNode.rightNode;
            }
        }
        if (tempNode == null) {
            return null;
        }
        return parentNode;
    }

    public void middleList() {
        if (root == null) {
            System.out.println("节点为空...");
        } else {
            root.middleList();
        }
    }
}

class Node {
    Integer value;
    Node leftNode;
    Node rightNode;

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

    /**
     * 添加一个节点
     *
     * @param node
     */
    public void add(Node node) {
        if (node.value < this.value) { // 放在左边
            if (this.leftNode == null) {
                this.leftNode = node;
            } else {
                this.leftNode.add(node);
            }
        } else {// 放在右边
            if (this.rightNode == null) {
                this.rightNode = node;
            } else {
                this.rightNode.add(node);
            }
        }
        // 当添加完节点后,如果(右子树的高度-左子树的高度>1),左旋
        if (rightHeight() - leftHeight() > 1) {
            // 如果(它的右子树的左子树高度-它的右子树的右子树高度>0)
            if (rightNode != null && rightNode.leftHeight() - rightNode.rightHeight() > 0) {
                // 先对右子节点进行右旋
                rightNode.rightRotate();
                // 然后在对当前节点进行左旋
                leftRotate();
            } else {
                // 直接左旋
                leftRotate();
            }
            // 当前情况处理完成后返回,避免继续往下面执行
            return;
        }
        // 当添加完成一个节点后,如果(左子树的高度-右子树的高度>1),右旋
        if (leftHeight() - rightHeight() > 1) {
            // 如果它的左子树的右子树高度大于它的左子树的左子树的高度
            if (leftNode != null && leftNode.rightHeight() - leftNode.leftHeight() > 0) {
                // 它的左子树左旋
                leftNode.leftRotate();
                // 当前节点右旋
                rightRotate();
            } else {
                // 当前节点右旋
                rightRotate();
            }
            return;
        }
    }

    /**
     * 中序遍历
     */
    public void middleList() {
        if (this.leftNode != null) {
            this.leftNode.middleList();
        }
        System.out.println(this);
        if (this.rightNode != null) {
            this.rightNode.middleList();
        }
    }

    public int leftHeight() {
        if (leftNode == null) {
            return 0;
        }
        return leftNode.height();
    }

    public int rightHeight() {
        if (rightNode == null) {
            return 0;
        }
        return rightNode.height();
    }

    /**
     * 计算树的高度
     *
     * @return
     */
    public Integer height() {
        return Math.max(leftNode == null ? 0 : leftNode.leftHeight(), rightNode == null ? 0 : rightNode.rightHeight()) + 1;
    }

    /**
     * 左旋
     * 右边高就左旋
     */
    public void leftRotate() {
        // 定义一个新的当前节点
        Node nodeNew = new Node(value);
        // 新节点的左节点为:当前节点的左节点
        nodeNew.leftNode = leftNode;
        // 新节点的右节点:当前节点的右节点的左节点
        nodeNew.rightNode = rightNode.leftNode;
        // 值替换:当前节点的值替换为当前节点右节点的值
        value = rightNode.value;
        // 当前节点的左节点为: 新的节点
        leftNode = nodeNew;
        // 当前节点的右节点为: 当前节点的右节点的右节点
        rightNode = rightNode.rightNode;
    }

    /**
     * 右旋
     * 左边边高就右旋
     */
    public void rightRotate() {
        // 步骤1:定义新节点10,newNode
        Node newNode = new Node(value);
        // 步骤2:新节点的左节点为9
        newNode.leftNode = leftNode.rightNode;
        // 步骤3:新节点的右节点为12
        newNode.rightNode = rightNode;
        // 步骤4:8替换10的值
        value = leftNode.value;
        // 步骤5:8节点的左节点为7
        leftNode = leftNode.leftNode;
        // 步骤6:8节点的右节点为新的节点10
        rightNode = newNode;
    }

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

 

完美!

posted @ 2022-05-14 22:34  不停学  阅读(42)  评论(0)    收藏  举报