平衡树

百科定义

平衡二叉树(Balanced Binary Tree)具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

平衡因子
二叉树上节点的左子树深度减去右子树深度的值称为平衡因子BF(Balance Factor)

平衡二叉树的实现

调整平衡的基本思想:
当在二叉排序树中插入一个节点时,首先检查是否因插入而破坏了平衡,若破坏,则找出其中的最小不平衡二叉树,在保持二叉排序树特性的情况下,调整最小不平衡子树中节点之间的关系,以达到新的平衡。
所谓最小不平衡子树,指离插入节点最近且以平衡因子的绝对值大于1的节点作为根的子树。

实现平衡的方法:

. 左旋

image.png

上图中,最小不平衡子树为结点3下面的树,结点3 的平衡因子BF为-2。
平衡方法为:以结点3进行左旋,旋转结果为图8。旋转后变为平衡二叉树


旋转方法


左旋.png

如上图,我们对X进行左旋,为了方便表达,做如下初始定义,保存左旋前节点的数据:

  • X为node
  • X的父结点为nodeP
  • X的左结点为nodeL
  • X的右节点为NodeR
  • X的右子树的左节点为nodeRL
  • X的右子树的右节点位nodeRR

变换步骤:

    1. node的右节点改为nodeRL,nodeRL的父结点改为node
    1. 判断node属于nodeP的左孩子还是右孩子,nodeP指向nodeR,nodeR的父亲结点改为nodeP
    1. nodeR指向node,node的父结点变为nodeR
public void left_rotate(Node x) {
        if (x != null) {
            Node y = x.right;
            // step 1
            x.right = y.left;
            if (y.left != null) {
                y.left.parent = x;
            }
             // step2
            y.parent = x.parent;
             if (x.parent == null) {
                root = y;
             } else {
                 if (x.parent.left == x) {
                     x.parent.left = y;
                    
                } else if(x.parent.right == x){
                    x.parent.right = y;
                }
             }
            //step 3
             y.left = x;
             x.parent = y;
        }
    }

. 右旋

image.png

上图中,节点3的平衡因子为2,左边的多于右边,需要进行右旋,把内容分配到右边一部分。

右旋.jpg

同左旋,定义保存右旋前一些使用到节点的数据

  • Y 保存为node
  • Y的父结点保存为nodeP
  • Y的左节点保存为nodeL
  • Y的右节点保存为nodeR
  • Y的左节点的右孩子保存为nodeLR
  • Y的左节点的左孩子保存为nodeLL

步骤:

    1. node的右孩子变为nodeLR,nodeLR父结点变为node
    1. 判断node属于nodeP的左孩子还是右孩子,nodeP指向nodeL,nodeL的父结点改为nodeP
    1. nodeL的右孩子变为node,node的父结点变为nodeL

public void right_rotate(Node y) {
        if (y != null) {
            Node yl = y.left;
            
            //step1
            y.left= yl.right;
            if (yl.right != null) {
                yl.right.parent = y;
            }
            
            // step2
            yl.parent = y.parent;
            if (y.parent == null) {
                root = yl;
            } else {
                if (y.parent.left == y) {
                    y.parent.left = yl;
                } else if (y.parent.right == y) {
                    y.parent.right = yl;
                }
            }
            // step3
            yl.right = y;
            y.parent = yl;
        }
    }
    

插入结点时候,导致平衡树失衡的情况分析,处理步骤

结点t的不平衡是因为左子树过深

/**
     * 左平衡操作,即结点t的不平衡是因为左子树过深
     * 
     * 1、如果新的结点插入到t的左孩子的左子树中,则直接进行右旋操作即可
     *              t                                      tl
     *             /  \         右旋操作                /      \
     *            tl   tr       ------------->       tll         t
     *           /  \                                /  \       /   \
     *          tll  tlr                           lcll  lclr  tlr   tr 
     *          /  \
     *       lcll  lclr
     *         
     * 2、如果新的结点插入到t的左孩子的右子树中,则需要进行分情况讨论
     * 
     *  情况a:当t的左孩子的右子树根节点的balance = RIGHT_HIGH
     *          t                           t                           tlr
     *         /  \                        /  \                        /  \
     *        tl    6        左旋        tlr    6       右旋          tl    t
     *       /  \       ------->        /  \        -------->        /    /  \
     *      3  tlr                     tl    5                      3    5    6
     *            \                   /
     *             5                 3
     *  情况b:当p的左孩子的右子树根节点的balance = LEFT_HIGH
     * 
     *          t                              t                           tlr
     *         /  \                           /  \                         /  \
     *       tl    6            左旋        tlr    6          右旋        tl    t
     *      /  \        ------->            /          -------->         / \    \
     *     3  tlr                         tl                            3   5    6
     *          /                        / \
     *         5                        3   5
     * 
     *  情况c:当p的左孩子的右子树根节点的balance = EQUAL_HIGH
     * 
     *          t                               t                               tlr
     *         /  \                           /  \                             /   \
     *        tl    7         左旋           tlr    7          右旋           tl    t
     *        /  \          ------->        / \         -------->            / \   / \
     *       3  tlr                       tl   6                            3  5  6   7
     *           / \                     / \
     *          5   6                   3   5
     * */

结点t的不平衡是因为左子树过深调整代码

    private static final int LH = 1;
    private static final int RH = -1;
    private static final int EH = 0;
private void leftBalance(AVL.Node t) {
        Node tl = t.left;
        switch (tl.balance) {
        case LH: // t 的左子树的左边有问题,直接右旋
            right_rotate(t);
            tl.balance = EH;
            t.balance = EH;
            break;
        case RH:
            Node tlr = tl.right;
            switch (tlr.balance) {
            case RH:
                t.balance = EH;
                tlr.balance = EH;
                tl.balance = LH;
                break;
            case LH:
                t.balance = RH;
                tl.balance =EH;
                tlr.balance = EH;
                break;
            case EH:
                t.balance = EH;
                tl.balance = EH;
                tlr.balance =EH;
                break;
                //统一旋转
            default:
                break;
            }
            left_rotate(t.left);
            right_rotate(t);
            break;
        default:
            break;
        }
        
    }

结点t的不平衡是因为右子树过深

/**
     * 右平衡操作,即结点t的不平衡是因为右子树过深
     * 
     * 1、如果新的结点插入到t的右孩子的右子树中,则直接进行左旋操作即可
     *       
     *          t                                            tr
     *        /   \                                        /     \
     *       l     tr              左旋操作               t       rr
     *           /   \          ----------->             / \     /   \
     *          rl    rr                                l  rl  rrl   rrr
     *              /   \
     *           rrl    rrr
     
     * 2、如果新的结点插入到p的右孩子的左子树中,则需要进行分情况讨论 
     *  情况a:当p的右孩子的左子树根节点的balance = LEFT_HIGH
     * 
     *          t                       t                           trl
     *         /  \                    /  \                        /   \
     *        2   tr        右旋      2    trl        左旋        t     tr
     *            /  \     ------->  /     \        ------->     /  \    \
     *          trl   5             6      tr                   2   6     5 
     *          /                            \
     *         6                              5 
     * 情况b:当p的右孩子的左子树根节点的balance = RIGHT_HIGH
     * 
     *          t                       t                           trl
     *         /  \                    /  \                        /   \
     *        2   tr          右旋      2   trl           左旋     t    tr
     *            /  \     ------->          \      ------->     /    /  \
     *          trl   5                      tr                 2    6    5 
     *            \                          /  \
     *             6                        6    5
     
     * 情况C:当p的右孩子的左子树根节点的balance = EQUAL_HIGH
     *          t                       t                            trl
     *         /  \                    /  \                         /    \
     *        2   tr          右旋      2   trl       左旋         t      tr
     *            /  \     ------->       /  \      ------->      / \     / \
     *         trl    5                  6   tr                  2   6   7   5  
     *          / \                          /  \
     *         6   7                        7    5
     * */

结点t的不平衡是因为右子树过深调整代码

    private static final int LH = 1;
    private static final int RH = -1;
    private static final int EH = 0;
private void rightBalance(AVL.Node t) {
        Node tr = t.right;
        switch (tr.balance) {
        case RH:
            left_rotate(t);
            t.balance = EH;
            tr.balance = EH;
            break;
        case LH:
            Node trl = tr.left;
            switch (trl.balance) {
            case LH:
                t.balance = EH;
                tr.balance = RH;
                break;
            case RH:
                t.balance = LH;
                tr.balance = EH;
                break;
            case EH:
                t.balance = EH;
                tr.balance = EH;
                break;
    
            }
            trl.balance = EH;
            right_rotate(t.right);
            left_rotate(t);
            break;
            
        default:
            break;
        }
        
    }

插入操作

public boolean inserElement(E element) {
        Node t = root;
        if (t == null) {
            root = new Node(element, null);
            size = 1;
            root.balance = 0;
            return true;
        } else {
            int cmp = 0;
            Node parent;
            Comparable e = (Comparable)element;
            do {
                parent = t;
                cmp = e.compareTo(t.element);
                if (cmp < 0) {
                    t= t.left;
                } else if (cmp > 0) {
                    t= t.right;
                } else {
                    return false;
                }
            } while (t != null);
            Node child = new Node(element, parent);
            if (cmp < 0) {
                parent.left = child;
            } else {
                parent.right = child;
            }
            //节点已经插入,
            // 检查平衡,回溯查找
            while (parent != null) {
                cmp = e.compareTo(parent.element);
                //元素在左边插入
                if (cmp < 0) {
                    parent.balance++;
                } else{ //元素在右边插入
                    parent.balance --;
                }
                
                if (parent.balance == 0) {
                    break;
                }
                if (Math.abs(parent.balance) == 2) {
                    //出现平衡问题
                    fixAfterInsertion(parent);
                    break;
                } else {
                    parent = parent.parent;
                }
            }
            size++;
            return true;
        }
    }

private void fixAfterInsertion(AVL.Node parent) {
        if (parent.balance == 2) {
            leftBalance(parent);
        } 
        if (parent.balance == -2) {
            rightBalance(parent);
        }
        
    }

全部代码


import java.util.LinkedList;

public class AVL> {

    private Node root;
    private int size = 0;
    private static final int LH = 1;
    private static final int RH = -1;
    private static final int EH = 0;
    
    public void midOrderDisplay(Node root) {
        if (root == null) {
            return;
        } else {
            midOrderDisplay(root.left);
            System.out.println("midOrder: " + root.element);
            midOrderDisplay(root.right);
        }
    }
    /**
     * node insert,check balance and keep balance
     * @author LK
     *
     * @param 
     */
    public boolean inserElement(E element) {
        Node t = root;
        if (t == null) {
            root = new Node(element, null);
            size = 1;
            root.balance = 0;
            return true;
        } else {
            int cmp = 0;
            Node parent;
            Comparable e = (Comparable)element;
            do {
                parent = t;
                cmp = e.compareTo(t.element);
                if (cmp < 0) {
                    t= t.left;
                } else if (cmp > 0) {
                    t= t.right;
                } else {
                    return false;
                }
            } while (t != null);
            Node child = new Node(element, parent);
            if (cmp < 0) {
                parent.left = child;
            } else {
                parent.right = child;
            }
            //节点已经插入,
            // 检查平衡,回溯查找
            while (parent != null) {
                cmp = e.compareTo(parent.element);
                //元素在左边插入
                if (cmp < 0) {
                    parent.balance++;
                } else{ //元素在右边插入
                    parent.balance --;
                }
                
                if (parent.balance == 0) {
                    break;
                }
                if (Math.abs(parent.balance) == 2) {
                    //出现平衡问题
                    fixAfterInsertion(parent);
                    break;
                } else {
                    parent = parent.parent;
                }
            }
            size++;
            return true;
        }
    }
    
    private void fixAfterInsertion(AVL.Node parent) {
        if (parent.balance == 2) {
            leftBalance(parent);
        } 
        if (parent.balance == -2) {
            rightBalance(parent);
        }
        
    }

    private void rightBalance(AVL.Node t) {
        Node tr = t.right;
        switch (tr.balance) {
        case RH:
            left_rotate(t);
            t.balance = EH;
            tr.balance = EH;
            break;
        case LH:
            Node trl = tr.left;
            switch (trl.balance) {
            case LH:
                t.balance = EH;
                tr.balance = RH;
                break;
            case RH:
                t.balance = LH;
                tr.balance = EH;
                break;
            case EH:
                t.balance = EH;
                tr.balance = EH;
                break;
    
            }
            trl.balance = EH;
            right_rotate(t.right);
            left_rotate(t);
            break;
            
        default:
            break;
        }
        
    }

    private void left_rotate(AVL.Node t) {
        if (t != null) {
            Node tr = t.right;
            t.right = tr.left;
            if (tr.left != null) {
                tr.left.parent = t;
            }
            
            tr.parent = t.parent;
            if (t.parent == null) {
                root = tr;
            } else {
                if (t.parent.left == t) {
                    t.parent.left = tr;
                } else if (t.parent.right == t) {
                    t.parent.right = tr;
                }
            }
            tr.left = t;
            t.parent = tr;
        }
    }

    private void right_rotate(AVL.Node t) {
        if (t != null) {
            Node tl = t.left;
            t.left =tl.right;
            if (tl.right != null) {
                tl.right.parent = t;
            }
            
            tl.parent = t.parent;
            if (t.parent == null) {
                root = tl;
            } else {
                if (t.parent.left == t) {
                    t.parent.left = tl;
                } else if (t.parent.right == t) {
                    t.parent.right = tl;
                }
            }
            
            tl.right = t;
            t.parent = tl;
        }
    }

    public Node searchNode(E element) {
        if (root == null) {
            return null;
        } else {
            Node cur = root;
            while(cur != null) {
                if (element.compareTo(cur.element) > 0) {
                    cur = cur.right;
                } else if (element.compareTo(cur.element) < 0) {
                    cur = cur.left;
                } else {
                    return cur;
                }
            }
        }
        return null;
    }
    
    
    private void leftBalance(AVL.Node t) {
        Node tl = t.left;
        switch (tl.balance) {
        case LH: // t 的左子树的左边有问题,直接右旋
            right_rotate(t);
            tl.balance = EH;
            t.balance = EH;
            break;
        case RH:
            Node tlr = tl.right;
            switch (tlr.balance) {
            case RH:
                t.balance = EH;
                tlr.balance = EH;
                tl.balance = LH;
                break;
            case LH:
                t.balance = RH;
                tl.balance =EH;
                tlr.balance = EH;
                break;
            case EH:
                t.balance = EH;
                tl.balance = EH;
                tlr.balance =EH;
                break;
                //统一旋转
            default:
                break;
            }
            left_rotate(t.left);
            right_rotate(t);
            break;
        default:
            break;
        }
        
    }
    
    class NodeBF {

        int level;
        Node node;
        public NodeBF(Node node, int lev) {
            this.node = node;
            level = lev;
        }
        
    }

    class Node>{
        E element; // data 
        int balance = 0; // balance value
        Node left;
        Node right;
        Node parent;
        public Node(E element, Node parent) {
            this.element = element;
            this.parent = parent;
        }
        
        @Override
        public String toString() {
            // TODO Auto-generated method stub
            return element + "BF: " + balance;
        }

        public E getElement() {
            return element;
        }

        public void setElement(E element) {
            this.element = element;
        }

        public int getBalance() {
            return balance;
        }

        public void setBalance(int balance) {
            this.balance = balance;
        }

        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 Node getParent() {
            return parent;
        }

        public void setParent(Node parent) {
            this.parent = parent;
        }


        
        
    }
    
    public Node getRoot() {
        return root;
    }
    
    public void levelDisplay(Node root) {
        LinkedList list = new LinkedList<>();
        NodeBF nodeBF = new NodeBF(root, 0);
        list.offer(nodeBF);
        while (!list.isEmpty()) {
            NodeBF node = list.pop();
            System.out.println(node.node.element + " level: " + node.level);
            if (node.node.left != null) {
                NodeBF nodel = new NodeBF(node.node.left, node.level + 1);
                list.offer(nodel);
            }
            if (node.node.right != null) {
                NodeBF noder = new NodeBF(node.node.right, node.level + 1);
                list.offer(noder);
            }
        }
    }
    public static void main(String[] args) {
//      Integer[] nums = {5, 8, 2, 0, 1, -2, -9, 100};
        Integer[] nums = {5, 8, 2, 0, 1, -2};
        AVL vAvlTree = new AVL();
        for (int i = 0; i < nums.length; i++) {
            vAvlTree.inserElement(nums[i]);
        }
//      vAvlTree.midOrderDisplay(vAvlTree.root);
        vAvlTree.levelDisplay(vAvlTree.root);
        System.out.println(vAvlTree.root.element);
    }
}

你可能感兴趣的:(平衡树)