二叉樹 & 平衡二叉樹 算法(Java實現)

二叉樹

比如我要依次插入10、3、1、8、23、15、28。先插入10作爲根節點:

 然後插入3,比10小,放在左邊:

再插入1,比10和3小,放在3左邊:

再插入8,比10小,比3大,放在3右邊:

 再插入23,比10大,放在10右邊:

 再插入15,比10大,比23小,放在23左邊:

 最後插入28,比10和23大,放在23右邊:

 代碼實現:

package com.demo.tree;

import java.util.LinkedList;
import java.util.Queue;


public class BinaryTree {

    public static void main(String[] args){
        BinaryTree tree = new BinaryTree();
        tree.batchInsert(new int[]{10,3,1,8,23,15,28});
        tree.prePrint();
        tree.midPrint();
        tree.postPrint();
        tree.tierPrint();
        tree.printDepth();
    }

    private Node root;

    /**
     * 節點
     */
    private class Node{
        int data;   // 數據
        Node left;  // 左指針
        Node right; // 右指針

        private Node(int data) {
            this.data = data;
            this.left = null;
            this.right = null;
        }
    }

    /**
     * 插入
     * @param data
     */
    public void insert(int data){
        Node newData = new Node(data);
        if (root == null){
            root = newData;
        }else{
            Node parent = root;
            while (true){
                if (data < parent.data){
                    // 如果左邊爲空,那新數據就直接放在這
                    if (parent.left == null){
                        parent.left = newData;
                        break;
                    }
                    // 進入左節點
                    parent = parent.left;
                }else{
                    // 如果右邊爲空,那新數據就直接放在這
                    if (parent.right == null){
                        parent.right = newData;
                        break;
                    }
                    // 進入右節點
                    parent = parent.right;
                }
            }
        }
    }

    /**
     * 批量插入
     * @param arr
     */
    public void batchInsert(int[] arr){
        for (int data : arr){
            insert(data);
        }
    }

    /**
     * 前序遍歷
     */
    public void prePrint(){
        System.out.print("前序遍歷\t");
        if (root != null){
            pre(root);
        }
        System.out.println();
    }

    private void pre(Node node){
        if (node != null) {
            System.out.print(node.data + "\t");
            pre(node.left);
            pre(node.right);
        }
    }

    /**
     * 中序遍歷
     */
    public void midPrint(){
        System.out.print("中序遍歷\t");
        if (root != null){
            mid(root);
        }
        System.out.println();
    }

    private void mid(Node node){
        if (node != null) {
            mid(node.left);
            System.out.print(node.data + "\t");
            mid(node.right);
        }
    }

    /**
     * 後序遍歷
     */
    public void postPrint(){
        System.out.print("後序遍歷\t");
        if (root != null){
            post(root);
        }
        System.out.println();
    }

    private void post(Node node){
        if (node != null) {
            post(node.left);
            post(node.right);
            System.out.print(node.data + "\t");
        }
    }

    /**
     * 層序遍歷,利用隊列先進先出
     */
    public void tierPrint(){
        if (root != null){
            Queue<Node> queue = new LinkedList<>();
            queue.add(root);
            System.out.print("層序遍歷\t");
            while (!queue.isEmpty()){
                Node temp = queue.remove();
                System.out.print(temp.data + "\t");
                if (temp.left != null){
                    // 左節點不爲空,放進隊列
                    queue.add(temp.left);
                }
                if (temp.right != null){
                    // 右節點不爲空,放進隊列
                    queue.add(temp.right);
                }
            }
        }
        System.out.println();
    }

    /**
     * 求樹高
     */
    public void printDepth(){
        if (root == null){
            System.out.println(0);
        }else{
            System.out.println("樹高\t" + getDepth(root));
        }
    }

    private int getDepth(Node node){
        if (node == null){
            return 0;
        }
        return Math.max(getDepth(node.left), getDepth(node.right))+1;
    }

}

測試:

 平衡二叉樹

前面的二叉樹有個問題,如果我們按照順序插入,那麼這個樹就會退化成一個線性鏈表,這個時候引入平衡二叉樹來解決。

平衡二叉樹要維持平衡需要旋轉操作

LL型(在A的左孩子(L)的左子樹(L)上插入新結點)

過程:

1. 將A的左孩子B提升爲根節點

2. 將A降級爲B的右孩子

3. 將B的右孩子調整爲A的左孩子

RR型(在A的右孩子(R)的右子樹(R)上插入新結點)

過程:

1. 將A的右孩子B提升爲根節點

2. 將A降級爲B的左孩子

3. 將B的左孩子調整爲A的右孩子

LR型(在A的左孩子(L)的右子樹(R)上插入新結點)【插入在C任意一顆子樹都可以】

過程:

1. B、C節點左旋。

2. A、C節點右旋。

RL型(在A的右孩子(R)的左子樹(L)上插入新結點)【插入在C任意一顆子樹都可以】

過程:

1. B、C節點右旋。

2. A、C節點左旋。

插入步驟圖解

平衡二叉樹的插入,例如依次插入:8,6,3,4,5,20,15,23,28,1,2

插入8先作爲根節點,插入6依然平衡,插入3不平衡,進行一次右旋(LL)

插入4依然平衡,插入5不平衡,進行左旋(RR)

插入20依然平衡,插入15不平衡,先右旋再左旋(RL)

插入23依然平衡,插入28不平衡,進行一次左旋(RR)

插入1依然平衡,插入2不平衡,先左旋再右旋(LR)

代碼

package com.demo.tree;

import java.util.LinkedList;
import java.util.Queue;


public class BalancedBinaryTree {

    public static void main(String[] args){
        BalancedBinaryTree tree = new BalancedBinaryTree();
        tree.batchInsert(new int[]{8,6,3,4,5,20,15,23,28,1,2});
        tree.tierPrint();
    }

    private Node root;

    /**
     * 節點
     */
    private class Node{
        int data;   // 數據
        Node left;  // 左指針
        Node right; // 右指針

        private Node(int data) {
            this.data = data;
            this.left = null;
            this.right = null;
        }
    }

    /**
     * 右旋操作(左孩子的左子樹插入節點)
     * @param p
     */
    private Node rightRotate(Node p){
        Node temp = p.left;    // temp指向p的左子樹
        p.left = temp.right;   // p的左子樹指向temp的右子樹
        temp.right = p;
        return temp;
    }

    /**
     * 左旋操作(右孩子的右子樹插入節點)
     * @param p
     */
    private Node leftRotate(Node p){
        Node temp = p.right;    // temp指向p的右子樹
        p.right = temp.left;   // p的右子樹指向temp的左子樹
        temp.left = p;
        return temp;
    }

    /**
     * 先左旋再右旋(左孩子的右子樹插入節點)
     * @param p
     */
    private Node leftRightRotate(Node p){
        p.left = leftRotate(p.left);
        return rightRotate(p);
    }

    /**
     * 先右旋再左旋(右孩子的左子樹插入節點)
     * @param p
     */
    private Node rightLeftRotate(Node p){
        p.right = rightRotate(p.right);
        return leftRotate(p);
    }

    /**
     * 樹高
     * @param node
     * @return
     */
    private int getDepth(Node node){
        if (node == null){
            return 0;
        }
        return Math.max(getDepth(node.left), getDepth(node.right))+1;
    }

    /**
     * 平衡因子(左高:>1 等高:0 右高:<-1)
     * @return
     */
    public int balanceFactor(Node node){
        if (node == null){
            return 0;
        }
        return getDepth(node.left) - getDepth(node.right);
    }

    /**
     * 插入
     * @param node
     * @param data
     */
    public Node insert(Node node, int data){
        Node newData = new Node(data);
        if (node == null){
            return newData;
        }
        if (data < node.data){
            node.left = insert(node.left, data);
        }else if (data > node.data){
            node.right = insert(node.right, data);
        }else{
            return node;
        }
        int bf = balanceFactor(node);

        if (bf > 1 && data < node.left.data){
            // LL
            System.out.println("LL" + data);
            return rightRotate(node);
        }else if (bf < -1 && data > node.right.data){
            // RR
            System.out.println("RR" + data);
            return leftRotate(node);
        }else if (bf > 1 && data > node.left.data){
            // LR
            System.out.println("LR" + data);
            return leftRightRotate(node);
        }else if (bf < -1 && data < node.right.data){
            // RL
            System.out.println("RL" + data);
            return rightLeftRotate(node);
        }
        return node;
    }

    /**
     * 批量插入
     * @param arr
     */
    public void batchInsert(int[] arr){
        for (int data : arr){
            root = insert(root, data);
        }
    }

    /**
     * 前序遍歷
     */
    public void prePrint(){
        System.out.print("前序遍歷\t");
        if (root != null){
            pre(root);
        }
        System.out.println();
    }

    private void pre(Node node){
        if (node != null) {
            System.out.print(node.data + "\t");
            pre(node.left);
            pre(node.right);
        }
    }

    /**
     * 中序遍歷
     */
    public void midPrint(){
        System.out.print("中序遍歷\t");
        if (root != null){
            mid(root);
        }
        System.out.println();
    }

    private void mid(Node node){
        if (node != null) {
            mid(node.left);
            System.out.print(node.data + "\t");
            mid(node.right);
        }
    }

    /**
     * 後序遍歷
     */
    public void postPrint(){
        System.out.print("後序遍歷\t");
        if (root != null){
            post(root);
        }
        System.out.println();
    }

    private void post(Node node){
        if (node != null) {
            post(node.left);
            post(node.right);
            System.out.print(node.data + "\t");
        }
    }

    /**
     * 層序遍歷,利用隊列先進先出
     */
    public void tierPrint(){
        if (root != null){
            Queue<Node> queue = new LinkedList<>();
            queue.add(root);
            System.out.print("層序遍歷\t");
            while (!queue.isEmpty()){
                Node temp = queue.remove();
                System.out.print(temp.data + "\t");
                if (temp.left != null){
                    // 左節點不爲空,放進隊列
                    queue.add(temp.left);
                }
                if (temp.right != null){
                    // 右節點不爲空,放進隊列
                    queue.add(temp.right);
                }
            }
        }
    }

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章