二叉树
比如我要依次插入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("前序遍历 "); if (root != null){ pre(root); } System.out.println(); } private void pre(Node node){ if (node != null) { System.out.print(node.data + " "); pre(node.left); pre(node.right); } } /** * 中序遍历 */ public void midPrint(){ System.out.print("中序遍历 "); if (root != null){ mid(root); } System.out.println(); } private void mid(Node node){ if (node != null) { mid(node.left); System.out.print(node.data + " "); mid(node.right); } } /** * 后序遍历 */ public void postPrint(){ System.out.print("后序遍历 "); 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 + " "); } } /** * 层序遍历,利用队列先进先出 */ public void tierPrint(){ if (root != null){ Queue<Node> queue = new LinkedList<>(); queue.add(root); System.out.print("层序遍历 "); while (!queue.isEmpty()){ Node temp = queue.remove(); System.out.print(temp.data + " "); 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("树高 " + 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("前序遍历 "); if (root != null){ pre(root); } System.out.println(); } private void pre(Node node){ if (node != null) { System.out.print(node.data + " "); pre(node.left); pre(node.right); } } /** * 中序遍历 */ public void midPrint(){ System.out.print("中序遍历 "); if (root != null){ mid(root); } System.out.println(); } private void mid(Node node){ if (node != null) { mid(node.left); System.out.print(node.data + " "); mid(node.right); } } /** * 后序遍历 */ public void postPrint(){ System.out.print("后序遍历 "); 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 + " "); } } /** * 层序遍历,利用队列先进先出 */ public void tierPrint(){ if (root != null){ Queue<Node> queue = new LinkedList<>(); queue.add(root); System.out.print("层序遍历 "); while (!queue.isEmpty()){ Node temp = queue.remove(); System.out.print(temp.data + " "); if (temp.left != null){ // 左节点不为空,放进队列 queue.add(temp.left); } if (temp.right != null){ // 右节点不为空,放进队列 queue.add(temp.right); } } } } }