title: Day30-数据结构与算法-树
date: 2020-10-21 19:08:27
author: 子陌
常用的经典数据结构
树(Tree)
使用树形结构可以大大提高效率
树的概念
- 节点、根节点、父节点、子节点、兄弟节点
- 一棵树可以没有任何节点,称为空树
- 一棵树可以只有一个节点,也就是只有根节点
- 子树、左子树、右子树
- 节点的度:子树的个数
- 树的度:所有节点度中的最大值
- 叶子节点:度为0的节点
- 非叶子节点:度不为0的节点
- 层数:根节点在第一层,根节点的子节点在第二层,以此类推
- 节点的深度:从根节点到当前节点的唯一路径上的节点总数
- 节点的高度:从当前节点到最远叶子节点的路径上的节点总数
- 树的深度:所有节点深度中的最大值
- 树的高度:所有节点高度中的最大值
- 树的深度等于树的高度
- 有序树
- 树中任意节点的字节的之间有顺序关系
- 无序树
- 树中任意节点的子节点之间没有顺序关系
- 也称为“自由树”
- 森林
- 由m(m ≥ 0)棵互不相交的树组成的集合
二叉树(Binary Tree)
特点
每个节点的度最大为2(最多拥有2棵子树)
左子树和右子树是有顺序的
即使某节点只有一棵子树,也要区分左右子树
二叉树的性质
非空二叉树的第i层,最多有2i - 1个节点(i ≥ 1)
在高度为n的二叉树上最多有2n - 1个节点(n ≥ 1)
对于任何一棵非空二叉树,如果叶子节点个数为n0,度为2的节点个数为n2,则有:n0 = n2 + 1
假设度为1的节点个数为n1,那么二叉树的节点总数n = n0 + n1 + n2
二叉树的边数T = n1 + 2 * n2 = n - 1 = n0 + n1 + n2 - 1
-
真二叉树:所有节点的度都要么为0,要么为2
-
满二叉树:所有节点的度都要么为0,要么为2。且所有的叶子节点都在最后一层
-
在同样高度的二叉树中,满二叉树的叶子节点数量最多、总节点数量最多
-
满二叉树一定是真二叉树,真二叉树不一定是满二叉树
-
假设满二叉树的高度为h(h ≥ 1),那么:
-
第i层的节点数量:2i - 1
-
叶子节点数量:2h - 1
-
总节点数量n
✔ n =2h - 1 = 20 + 21 + 22 + … + 2h - 1
✔ h = log2(n + 1)
-
-
-
完全二叉树:叶子节点只会出现最后2层,且最后1层的叶子节点都靠左对齐
-
完全二叉树从根节点至倒数第二层是一棵满二叉树
-
满二叉树一定是完全二叉树,完全二叉树不一定是满二叉树
-
性质:
-
度为1的节点只有左子树
-
度为1的节点要么是1个,要么是0个
-
同样节点数量的二叉树,完全二叉树的高度最小
-
假设完全二叉树的高度为h(h ≥ 1),那么
-
至少有2h - 1个节点(20 + 21 + 22 + … + 2h - 2 + 1)
-
最多有2h - 1个节点(20 + 21 + 22 + … + 2h - 1,满二叉树)
-
总节点数量为n
✔ 2h - 1 ≤ n ≤ 2h
✔ h - 1 ≤ log2n < h(h = floor(log2n)向下取整 + 1)
-
-
-
二叉树的遍历
- 遍历是数据结构中的常见操作
- 把所有元素都访问一遍
- 线性数据结构的遍历比较简单
- 正序遍历
- 逆序遍历
- 根据节点访问顺序的不同,二叉树的常见遍历方式有4种
- 前序遍历:根节点、前序遍历左子树、前序遍历右子树
- 树状结构展示(注意左右子树的顺序)
- 中序遍历:中序遍历左子树、根节点、中序遍历右子树
- 二叉搜索树的遍历结果是升序或者降序
- 后序遍历:后序遍历左子树、后序遍历右子树、根节点
- 适用于先子后父的操作
- 层序遍历:从上到下、从左到右依次访问每个节点
- 计算二叉树的高度
- 判断一棵树是否为完全二叉树
- 前序遍历:根节点、前序遍历左子树、前序遍历右子树
根据遍历结果重构二叉树
- 前序遍历 + 中序遍历
- 后序遍历 + 中序遍历
- 后序遍历 + 后序遍历
- 如果它是一棵真二叉树,结果唯一
- 不然结果不唯一
前驱节点
- 前驱节点:中序遍历的前一个节点
- 如果是二叉搜索树,前驱节点就是前一个比它小的节点
- node.left != null
- predecessor = node.left.right.right…
- 终止条件:right == null
- node.left == null && node.parent != null
- predecessor = node.parent.parent…
- 终止条件:node在parent的右子树中
- node.left == null && node.parent == null
- 没有前驱节点
后继节点
- 后继节点:中序遍历的后一个节点
- 如果是二叉搜索树,前驱节点就是后一个比它大的节点
- node.right != null
- successor = node.right.left.left.left…
- 终止条件:left == null
- node.right == null && node.parent != null
- successor = node.parent.parent.parent…
- 终止条件:node在parent的左子树中
- node.right == null && node.parent == null
- 没有后继节点
二叉搜索树(Binary Search Tree)
- 二叉搜索树是二叉树的一种,是应用非常广泛的一种二叉树,英文简称为BST
- 又被称为:二叉查找树,二叉排序树、
- 任意一个节点的值都大于其左子树所有节点的值
- 任意一个节点的值都小于其右子树所有节点的值
- 它的左右子树也是一棵二叉搜索树
- 二叉搜索树可以大大提高搜索数据的效率
- 二叉搜索树存储的元素必须具备可比较性
- 比如int、double等
- 如果是自定义类型,需要指定比较方式
- 不允许为null
接口设计
int size() 元素的数量
boolean isEmpty() 是否为空
void clear() 清空所有元素
void add(E element) 添加元素
void remove(E element) 删除元素
boolean contains(E element) 是否包含某个元素
需要注意的是,对于二叉树来说,没有索引的概念
- 删除节点:
- 度为0:叶子节点直接删除 parent.child = null 或 root = null
- 度为1:用删除的子节点替代 parent.child = child.child 或 root = child.child
- 度为2:先用前驱或者后继节点的值覆盖原节点的值,然后删除相应的前驱或者后继节点
- 如果一个节点的度为2,那么它的前驱、后继节点的度只可能是1和0
package com.zimo.树;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Queue;
/**
* 树 - 二叉树 - 二叉搜索树实现
*
* @author Liu_zimo
* @version v0.1 by 2020/10/23 15:08:30
*/
// public class BinarySearchTree<E extends Comparable<E>> { 声明时,不强制实现比较接口,如果别人想自定义比较器则会出错
public class BinarySearchTree<E> {
public static void main(String[] args) {
BinarySearchTree<Integer> b1 = new BinarySearchTree<>();
// 匿名类方式,也可以自定义类实现比较器
BinarySearchTree<Object> b2 = new BinarySearchTree<>(new Comparator<Object>() {
@Override
public int compare(Object o, Object t1) {
// 比较逻辑
return 0;
}
});
Integer[] integers = {
7, 4, 9, 2, 5, 8, 11, 1, 3, 10, 12};
for (Integer integer : integers) {
b1.add(integer);
}
b1.preorderTraversal(new Visitor<Integer>() {
@Override
public boolean visitor(Integer element) {
System.out.print("_" + element + "_ ");
return element == 9 ? true : false; // 遇到9后续不打印
}
});
System.out.println("\n树高为:" + b1.height() + b1.height1());
System.out.println("是否为完全二叉树" + b1.isComplete());
System.out.println(b1.predesessor(b1.root).element);
System.out.println(b1.successor(b1.root).element);
b1.remove(11);
b1.remove(7);
b1.preorderTraversal(new Visitor<Integer>() {
@Override
public boolean visitor(Integer element) {
System.out.print("_" + element + "_ ");
return false;
}
});
}
private int size;
private Node<E> root;
private Comparator<E> comparator;
public BinarySearchTree() {
this(null);
}
public BinarySearchTree(Comparator<E> comparator) {
this.comparator = comparator;
}
/**
* 获取元素的数量
* @return 元素的数量
*/
public int size(){
return size;
}
/**
* 是否为空
* @return 是否为空
*/
public boolean isEmpty(){
return size == 0;
}
/**
* 清空所有元素
*/
public void clear(){
root = null;
size = 0;
}
/**
* 添加元素
* @param element 要添加的元素
*/
public void add(E element){
elementNotNullCheck(element);
if (root == null){
// 添加第一个节点
root = new Node<>(element, null);
size++;
return;
}else {
// 添加不是第一个节点
Node<E> node = this.root;
Node<E> parent = null;
int compare = 0;
// 1.找到父节点parent
while (node != null){
compare = compare(element, node.element);
parent = node;
if (compare > 0){
node = node.right;
}else if (compare < 0){
node = node.left;
}else {
// 相等
node.element = element;
return;
}
}
// 2.创建新节点node
Node<E> newNode = new Node<>(element, parent);
// 3.parent.left = node || parnet.right = node
if (compare > 0){
parent.right = newNode;
}else {
parent.left = newNode;
}
size++;
}
}
/**
* 删除元素(提供外界删除元素,外面没有节点概念)
* @param element 要删除的元素
*/
public void remove(E element){
remove(node(element));
}
/**
* 删除一个节点(删除内部节点)
* @param node 要删除的节点
*/
private void remove(Node<E> node){
if (node == null) return;
size--;
if (node.hasTwoChildren()){
// 删除度为2的节点 - rmNode的前驱或者后继节点覆盖rmNode,然后删除相应的前驱或者后继节点
Node<E> successor = successor(node);
// 用后继节点值覆盖度为2的节点值
node.element = successor.element;
// 删除后继节点
node = successor;
}
// 删除node节点(node 度必然是1 或者 0)
Node<E> replacement = node.left != null ? node.left : node.right;
if (replacement != null){
// 删除度为1的节点 - 用删除的子节点替代 parent.child = rmNode.left/right || root = rmNode.left/right
replacement.parent = node.parent; // 更改parent
// 更改parent的left/right的指向
if (node.parent == null){
// 度为1的根节点
root = replacement;
}else if(node == node.parent.left){
node.parent.left = replacement;
}else {
node.parent.right = replacement;
}
}else if (node.parent == null){
// 删除根节点:root = null
root = null;
}else{
// 删除叶子节点 - 直接删除 left/right = null
if (node == node.parent.left){
node.parent.left = null;
}else {
node.parent.right = null;
}
}
}
/**
* 根据元素查找对应的节点
* @param element
* @return
*/
private Node<E> node(E element) {
Node<E> node = this.root;
while (node != null){
int cmp = compare(element, node.element);
if (cmp == 0) return node;
if (cmp > 0) node = node.right;
else node = node.left;
}
return null;
}
/**
* 是否包含某个元素
* @param element 要查找的元素
* @return 是否包含查找的元素
*/
public boolean contains(E element){
return node(element) != null;
}
/**
* 比较元素大小
* @param e1
* @param e2
* @return 0:e1 == e2 >0: e1 > e2 <0: e1 < e2
*/
private int compare(E e1, E e2){
// return e1.compareTo(e2);
if (comparator != null) {
return comparator.compare(e1, e2);
}
return ((Comparable<E>)e1).compareTo(e2); // 如果没实现比较器,默认为强制实现比较接口
}
/**
* 前序遍历
*/
public void preorderTraversal(Visitor<E> visitor){
if (visitor == null) return;
preorderTraversal(root, visitor);
}
private void preorderTraversal(Node<E> node, Visitor<E> visitor){
if (node == null || visitor.stop) return;
// System.out.println(node.element);
//if (visitor.stop) return;
visitor.stop = visitor.visitor(node.element);
preorderTraversal(node.left, visitor);
preorderTraversal(node.right, visitor);
}
/**
* 中序遍历
* @param visitor
*/
public void inorderTraversal(Visitor<E> visitor){
if (visitor == null) return;
inorderTraversal(root ,visitor);
}
private void inorderTraversal(Node<E> node, Visitor<E> visitor){
if (node == null || visitor.stop) return;
inorderTraversal(node.left,visitor);
// System.out.println(node.element);
if (visitor.stop) return;
visitor.stop = visitor.visitor(node.element);
inorderTraversal(node.right,visitor);
}
/**
* 后序遍历
*/
public void postorderTraversal(Visitor<E> visitor){
if (visitor == null) return;
postorderTraversal(root, visitor);
}
private void postorderTraversal(Node<E> node, Visitor<E> visitor){
if (node == null || visitor.stop) return;
postorderTraversal(node.left,visitor);
postorderTraversal(node.right,visitor); // visitor.stop == true
// System.out.println(node.element);
if (visitor.stop) return;
visitor.stop = visitor.visitor(node.element);
}
/**
* 层序遍历:实现思路(队列)
* 1.根节点入队
* 2.循环执行一下操作,直到队列为空
* A节点访问,A的左子树入队,A的右子树入队
*/
public void levelOrderTraversal(Visitor<E> visitor){
if (root == null || visitor == null) return;
Queue<Node<E>> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()){
Node<E> poll = queue.poll();
// System.out.println(poll.element);
if (visitor.visitor(poll.element)) {
return;
}
if (poll.left != null){
queue.offer(poll.left);
}
if (poll.right != null){
queue.offer(poll.right);
}
}
}
/**
* 计算二叉树的高度(递归)
* @return 二叉树的高度
*/
public int height(){
return height(root);
}
private int height(Node<E> node){
if (node == null) return 0;
return 1 + Math.max(height(node.left), height(node.right));
}
/**
* 计算二叉树高度(非递归:层序遍历)
* @return
*/
public int height1(){
if(root == null) return 0;
int height = 0; // 树高度
int levelSize = 1; // 每层的元素的数量
Queue<Node<E>> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()){
Node<E> poll = queue.poll();
levelSize--;
if (poll.left != null){
queue.offer(poll.left);
}
if (poll.right != null){
queue.offer(poll.right);
}
if (levelSize == 0){
levelSize = queue.size();
height++;
}
}
return height;
}
/**
* 是否为完全二叉树
* @return 返回是否为完全二叉树的结果
*/
public boolean isComplete(){
if (root == null) return false;
Queue<Node<E>> queue = new LinkedList<>();
queue.offer(root);
boolean leaf = false;
while (!queue.isEmpty()){
Node<E> poll = queue.poll();
if (leaf && !poll.isLeaf()) return false;
if (poll.left != null){
queue.offer(poll.left);
}else if (poll.right != null){
return false; // left == null && right != null
}
if (poll.right != null){
queue.offer(poll.right);
}else {
// left == null && right == null 或者 left != null && right == null
leaf = true;
}
}
return true;
}
public boolean isComplete1(){
if (root == null) return false;
Queue<Node<E>> queue = new LinkedList<>();
queue.offer(root);
boolean leaf = false;
while (!queue.isEmpty()){
Node<E> poll = queue.poll();
if (leaf && poll.isLeaf()) return false;
if (poll.hasTwoChildren()){
queue.offer(poll.left);
queue.offer(poll.right);
}else if (poll.left == null && poll.right != null){
return false;
}else {
// 后面遍历的节点必须是叶子节点
leaf = true;
if (poll.left != null){
queue.offer(poll.left);
}
}
}
return true;
}
/**
* 获取node节点的前驱节点:中序遍历的前一个
* @param node 要找的节点
* @return 查找结果
*/
private Node<E> predesessor(Node<E> node){
if (node == null) return null;
// 前驱节点在左子树中
Node<E> p = node.left;
if (p != null){
while (p.right != null) p = p.right;
return p;
}
// 从父节点、祖父节点中寻找前驱
while (node.parent != null && node == node.parent.left){
node = node.parent;
}
// node.parent
return node.parent;
}
/**
* 获取node节点的后继节点:中序遍历的后一个
* @param node
* @return
*/
private Node<E> successor(Node<E> node){
if (node == null) return null;
// 前驱节点在左子树中
Node<E> p = node.right;
if (p != null){
while (p.left != null) p = p.left;
return p;
}
// 从父节点、祖父节点中寻找前驱
while (node.parent != null && node == node.parent.right){
node = node.parent;
}
// node.parent
return node.parent;
}
private void elementNotNullCheck(E element){
if(element == null)
throw new IllegalArgumentException("element元素不能为空");
}
// 如果想要操作遍历元素
public static abstract class Visitor<E>{
boolean stop;
/**
* 返回true时停止遍历
* @param element
* @return
*/
abstract boolean visitor(E element);
}
private static class Node<E>{
E element;
Node<E> left;
Node<E> right;
Node<E> parent;
public Node(E element, Node<E> parent) {
this.element = element;
this.parent = parent;
}
/**
* 判断是否为叶子节点
* @return
*/
public boolean isLeaf() {
return left == null && right == null;
}
/**
* 是否有两个子节点
* @return
*/
public boolean hasTwoChildren(){
return left != null && right != null;
}
}
}
翻转二叉树
package com.zimo.树;
import java.util.LinkedList;
import java.util.Queue;
/**
* 翻转二叉树 : https://leetcode-cn.com/problems/invert-binary-tree/
*
* @author Liu_zimo
* @version v0.1 by 2020/10/24 14:50:40
*/
public class InvertBinaryTree {
// 前序遍历
public TreeNode preInvertTree(TreeNode root){
if (root == null) return null;
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
preInvertTree(root.left);
preInvertTree(root.right);
return root;
}
// 后序遍历
public TreeNode postInvertTree(TreeNode root){
if (root == null) return null;
preInvertTree(root.left);
preInvertTree(root.right);
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
return root;
}
// 中序遍历
public TreeNode inInvertTree(TreeNode root){
if (root == null) return root;
preInvertTree(root.left);
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
preInvertTree(root.left); // 注意:中序和前后序遍历不一样,交换后还是left而不是right
return root;
}
// 层序遍历
public TreeNode levelInvertTree(TreeNode root){
if (root == null) return null;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()){
TreeNode node = queue.poll();
TreeNode tmp = node.left;
node.left = node.right;
node.right = tmp;
if (node.left != null){
queue.offer(node.left);
}
if (node.right != null){
queue.offer(node.right);
}
}
return root;
}
}
class TreeNode{
int val;
TreeNode left;
TreeNode right;
TreeNode(int x){
val = x;
}
}
重构二叉搜索树
-
抽取二叉树公共方法
package com.zimo.树; import java.util.LinkedList; import java.util.Queue; /** * 二叉树 - 基类 * * @author Liu_zimo * @version v0.1 by 2020/10/26 10:41 */ public class BinaryTree<E> { protected int size; protected Node<E> root; public int size() { return size; } public boolean isEmpty() { return size == 0; } public void clear() { root = null; size = 0; } public void preorderTraversal(Visitor<E> visitor) { if (visitor == null) return; preorderTraversal(root, visitor); } private void preorderTraversal(Node<E> node, Visitor<E> visitor) { if (node == null || visitor.stop) return; visitor.stop = visitor.visitor(node.element); preorderTraversal(node.left, visitor); preorderTraversal(node.right, visitor); } public void inorderTraversal(Visitor<E> visitor) { if (visitor == null) return; inorderTraversal(root, visitor); } private void inorderTraversal(Node<E> node, Visitor<E> visitor) { if (node == null || visitor.stop) return; inorderTraversal(node.left, visitor); if (visitor.stop) return; visitor.stop = visitor.visitor(node.element); inorderTraversal(node.right, visitor); } public void postorderTraversal(Visitor<E> visitor) { if (visitor == null) return; postorderTraversal(root, visitor); } private void postorderTraversal(Node<E> node, Visitor<E> visitor) { if (node == null || visitor.stop) return; postorderTraversal(node.left, visitor); postorderTraversal(node.right, visitor); if (visitor.stop) return; visitor.stop = visitor.visitor(node.element); } public void levelOrderTraversal(Visitor<E> visitor) { if (root == null || visitor == null) return; Queue<Node<E>> queue = new LinkedList<>(); queue.offer(root); while (!queue.isEmpty()) { Node<E> poll = queue.poll(); if (visitor.visitor(poll.element)) { return; } if (poll.left != null) { queue.offer(poll.left); } if (poll.right != null) { queue.offer(poll.right); } } } protected Node<E> predesessor(Node<E> node) { if (node == null) return null; Node<E> p = node.left; if (p != null) { while (p.right != null) p = p.right; return p; } while (node.parent != null && node == node.parent.left) { node = node.parent; } // node.parent return node.parent; } protected Node<E> successor(Node<E> node) { if (node == null) return null; Node<E> p = node.right; if (p != null) { while (p.left != null) p = p.left; return p; } while (node.parent != null && node == node.parent.right) { node = node.parent; } return node.parent; } public int height() { return height(root); } private int height(Node<E> node) { if (node == null) return 0; return 1 + Math.max(height(node.left), height(node.right)); } public int height1() { if (root == null) return 0; int height = 0; // 树高度 int levelSize = 1; // 每层的元素的数量 Queue<Node<E>> queue = new LinkedList<>(); queue.offer(root); while (!queue.isEmpty()) { Node<E> poll = queue.poll(); levelSize--; if (poll.left != null) { queue.offer(poll.left); } if (poll.right != null) { queue.offer(poll.right); } if (levelSize == 0) { levelSize = queue.size(); height++; } } return height; } public boolean isComplete() { if (root == null) return false; Queue<Node<E>> queue = new LinkedList<>(); queue.offer(root); boolean leaf = false; while (!queue.isEmpty()) { Node<E> poll = queue.poll(); if (leaf && !poll.isLeaf()) return false; if (poll.left != null) { queue.offer(poll.left); } else if (poll.right != null) { return false; } if (poll.right != null) { queue.offer(poll.right); } else { leaf = true; } } return true; } public boolean isComplete1() { if (root == null) return false; Queue<Node<E>> queue = new LinkedList<>(); queue.offer(root); boolean leaf = false; while (!queue.isEmpty()) { Node<E> poll = queue.poll(); if (leaf && poll.isLeaf()) return false; if (poll.hasTwoChildren()) { queue.offer(poll.left); queue.offer(poll.right); } else if (poll.left == null && poll.right != null) { return false; } else { leaf = true; if (poll.left != null) { queue.offer(poll.left); } } } return true; } protected static class Node<E> { public E element; public Node<E> left; public Node<E> right; public Node<E> parent; public Node(E element, Node<E> parent) { this.element = element; this.parent = parent; } public boolean isLeaf() { return left == null && right == null; } public boolean hasTwoChildren() { return left != null && right != null; } } public static abstract class Visitor<E> { boolean stop; public abstract boolean visitor(E element); } }
-
二叉搜索树实现
package com.zimo.树.二叉搜索树; import com.zimo.树.BinaryTree; import java.util.Comparator; /** * 树 - 二叉树 - 重构二叉搜索树 * * @author Liu_zimo * @version v0.1 by 2020/10/26 10:34:00 */ public class ReconsitutionBinarySearchTree<E> extends BinaryTree<E> { public static void main(String[] args) { ReconsitutionBinarySearchTree<Integer> b1 = new ReconsitutionBinarySearchTree<>(); Integer[] integers = { 7, 4, 9, 2, 5, 8, 11, 1, 3, 10, 12}; for (Integer integer : integers) { b1.add(integer); } b1.preorderTraversal(new Visitor<Integer>() { @Override public boolean visitor(Integer element) { System.out.print("_" + element + "_ "); return element == 9 ? true : false; // 遇到9后续不打印 } }); System.out.println("\n树高为:" + b1.height() + b1.height1()); System.out.println("是否为完全二叉树" + b1.isComplete()); System.out.println(b1.predesessor(b1.root).element); System.out.println(b1.successor(b1.root).element); b1.remove(11); b1.remove(7); b1.preorderTraversal(new Visitor<Integer>() { @Override public boolean visitor(Integer element) { System.out.print("_" + element + "_ "); return false; } }); } private Comparator<E> comparator; public ReconsitutionBinarySearchTree() { this(null); } public ReconsitutionBinarySearchTree(Comparator<E> comparator) { this.comparator = comparator; } public void add(E element) { elementNotNullCheck(element); if (root == null) { root = new Node<>(element, null); size++; return; } else { Node<E> node = this.root; Node<E> parent = null; int compare = 0; while (node != null) { compare = compare(element, node.element); parent = node; if (compare > 0) { node = node.right; } else if (compare < 0) { node = node.left; } else { // 相等 node.element = element; return; } } Node<E> newNode = new Node<>(element, parent); if (compare > 0) { parent.right = newNode; } else { parent.left = newNode; } size++; } } public void remove(E element) { remove(node(element)); } private void remove(Node<E> node) { if (node == null) return; size--; if (node.hasTwoChildren()) { Node<E> successor = successor(node); node.element = successor.element; node = successor; } Node<E> replacement = node.left != null ? node.left : node.right; if (replacement != null) { replacement.parent = node.parent; // 更改parent if (node.parent == null) { // 度为1的根节点 root = replacement; } else if (node == node.parent.left) { node.parent.left = replacement; } else { node.parent.right = replacement; } } else if (node.parent == null) { root = null; } else { if (node == node.parent.left) { node.parent.left = null; } else { node.parent.right = null; } } } private Node<E> node(E element) { Node<E> node = this.root; while (node != null) { int cmp = compare(element, node.element); if (cmp == 0) return node; if (cmp > 0) node = node.right; else node = node.left; } return null; } public boolean contains(E element) { return node(element) != null; } private int compare(E e1, E e2) { // return e1.compareTo(e2); if (comparator != null) { return comparator.compare(e1, e2); } return ((Comparable<E>) e1).compareTo(e2); // 如果没实现比较器,默认为强制实现比较接口 } private void elementNotNullCheck(E element) { if (element == null) throw new IllegalArgumentException("element元素不能为空"); } }
如果从小到大添加元素,二叉搜索树退化成链表,则复杂度为n,如果是平衡二叉树,则是log2n两者性能差异较大
- 添加、删除节点时,都可能会导致二叉搜索树退化成链表
平衡二叉搜索树(Balanced Binary Search Tree)
英文简称:BBST
- 平衡:当节点数量固定时,左右子树的高度越接近,这棵二叉树就越平衡(高度越低)
- 理想平衡:最理想的平衡,就是像完全二叉树、满二叉树那样,高度最小
二叉搜索树改进:
经典常见的平衡二叉搜索树有:
-
AVL树
✓ Windows NT 内核中广泛使用
-
红黑树
✓ C++ STL(比如map、set)
✓ Java的TreeMap、TreeSet、HashMap、HashSet
✓ Linux的进程调度
✓ Ngix的timer管理
-
一般也称他们为:自平衡的二叉搜索树(Self-balancing Binary Search Tree)
AVL树
- AVL树是最早发明的自平衡二叉搜索树之一
- AVL取名于两位发明者的名字(G.M.Adeloson-Velsky和E.M.Landis)来自苏联的科学家
- 网络上有些人把AVL树念作“艾薇儿树”
- 平衡因子(Balance Factor):某节点的左右子树的高度差
- AVL树的特点
- 每个节点的平衡因子只可能是1,0,-1(绝对值 ≤ 1,如果超过1,称之为“失衡”)
- 每个节点的左右子树高度差不超过1
- 搜索、添加、删除的时间复杂度是O(log2n)
- 添加导致失衡
- 最坏情况:可能会导致所有祖先节点都失衡
- 父节点、非祖先节点,都不可能失衡
- 只要让高度最低的失衡节点恢复平衡,整棵树就恢复平衡【仅需O(1)次调整】
- LL - 右旋转(单旋)、RR - 左旋转(单旋)、LR - RR左旋转、LL右旋转(双旋)、RL - LL右旋转、RR左旋转(双旋)
- 删除导致的失衡
- 可能会导致父节点或者祖先节点失衡(只有一个节点会失衡),其他节点,都不可能失衡
- 除父节点外的其他节点,都不可能失衡
- 让父节点恢复平衡后,可能会导致更高层的祖先节点失衡【最多需要O(log2n)次调整】
- BinaryTree修改
// 二叉树 - 基类 修改的地方如下
public class BinaryTree<E> {
+ protected Node<E> createNode(E element, Node<E> parent){
return new Node<>(element, parent);
}
protected static class Node<E> {
public E element;
public Node<E> left;
public Node<E> right;
public Node<E> parent;
public Node(E element, Node<E> parent) {
this.element = element;
this.parent = parent;
}
public boolean isLeaf() {
return left == null && right == null;
}
public boolean hasTwoChildren() {
return left != null && right != null; }
+ public boolean isLeftChild() {
return parent != null && parent.left == this; }
+ public boolean isRightChild() {
return parent != null && parent.right == this; }
}
}
- ReconsitutionBinarySearchTree修改
// 树 - 二叉树 - 重构二叉搜索树 修改的地方如下
public class ReconsitutionBinarySearchTree<E> extends BinaryTree<E> {
public void add(E element) {
elementNotNullCheck(element);
if (root == null) {
root = createNode(element, null);
size++;
+ afterAdd(root);
return;
} else {
Node<E> node = this.root;
Node<E> parent = null;
int compare = 0;
while (node != null) {
compare = compare(element, node.element);
parent = node;
if (compare > 0) {
node = node.right;
} else if (compare < 0) {
node = node.left;
} else {
// 相等
node.element = element;
return;
}
}
Node<E> newNode = createNode(element, parent);
if (compare > 0) {
parent.right = newNode;
} else {
parent.left = newNode;
}
size++;
+ afterAdd(newNode);
}
}
private void remove(Node<E> node) {
if (node == null) return;
size--;
if (node.hasTwoChildren()) {
Node<E> successor = successor(node);
node.element = successor.element;
node = successor;
}
Node<E> replacement = node.left != null ? node.left : node.right;
if (replacement != null) {
replacement.parent = node.parent; // 更改parent
if (node.parent == null) {
// 度为1的根节点
root = replacement;
} else if (node == node.parent.left) {
node.parent.left = replacement;
} else {
node.parent.right = replacement;
}
+ afterRemove(node); // 为了兼容红黑树和其他数据结构,不建议提取到外面去
} else if (node.parent == null) {
root = null;
+ afterRemove(node);
} else {
if (node == node.parent.left) {
node.parent.left = null;
} else {
node.parent.right = null;
}
+ afterRemove(node);
}
}
/**
* 添加node之后的调整
* @param node 新添加的节点
*/
+ protected void afterAdd(Node<E> node){
}
/**
* 删除node之后的调整
* @param node 被删除的节点
*/
+ protected void afterRemove(Node<E> node){
}
- 新增AVL树类
package com.zimo.树.二叉搜索树;
import com.zimo.树.BinaryTree;
import java.util.Comparator;
/**
* 树 - 二叉树 - 二叉搜索树 - AVL树
*
* @author Liu_zimo
* @version v0.1 by 2020/10/26 15:01:54
*/
public class AVLTree<E> extends ReconsitutionBinarySearchTree<E>{
public AVLTree() {
this(null);
}
public AVLTree(Comparator comparator) {
super(comparator);
}
@Override
protected Node<E> createNode(E element, Node<E> parent) {
return new AVLNode<>(element, parent);
}
@Override
protected void afterAdd(Node<E> node) {
while ((node = node.parent) != null){
if (isBalanced(node)){
// 更新高度
updateHeight(node);
}else {
// 恢复平衡
rebalance(node);
break;
}
}
}
@Override
protected void afterRemove(Node<E> node) {
while ((node = node.parent) != null){
if (isBalanced(node)){
// 更新高度
updateHeight(node);
}else {
// 恢复平衡
rebalance(node);
}
}
}
private boolean isBalanced(Node<E> node){
return Math.abs(((AVLNode<E>)node).balanceFactor()) <= 1;
}
/**
* 恢复平衡
* @param node 高度最底的不平衡节点
*/
private void rebalance(Node<E> node){
Node<E> parent = ((AVLNode<E>)node).tallerChild();
Node<E> child = ((AVLNode<E>)parent).tallerChild();
if (parent.isLeftChild()){
// L
if (child.isLeftChild()){
// LL
rotateRight(node);
// unifyRebalance(node,child.left,child,child.right,parent,parent.right,node,node.right);
}else {
//LR
rotateLeft(parent);
rotateRight(node);
// unifyRebalance(node, parent.left, parent, child.left, child, child.right, node, node.right);
}
}else {
// R
if (child.isLeftChild()){
// RL
rotateRight(parent);
rotateLeft(node);
// unifyRebalance(node, node.left, node, child.left, child, child.right, parent, parent.right);
}else {
// RR
rotateLeft(node);
// unifyRebalance(node, node.left, node, parent.left, parent, child.left, child, child.right);
}
}
}
// 左旋
private void rotateLeft(Node<E> node){
Node<E> parent = node.right;
Node<E> child = parent.left;
node.right = child;
parent.left = node;
afterRotate(node, parent, child);
}
// 右旋
private void rotateRight(Node<E> node){
Node<E> parent = node.left;
Node<E> child = parent.right;
node.left = child;
parent.right = node;
afterRotate(node, parent, child);
}
/**
* 统一处理恢复平衡(不分情况左右旋转)
* @param node
*/
private void unifyRebalance(Node<E> oldRoot,
Node<E> nodeA, Node<E> nodeB, Node<E> nodeC,
Node<E> nodeD,
Node<E> nodeE, Node<E> nodeF, Node<E> nodeG,){
// d成为子树的根节点
nodeD.parent = oldRoot.parent;
if (oldRoot.isLeftChild()){
oldRoot.parent.left = nodeD;
}else if (oldRoot.isRightChild()){
oldRoot.parent.right = nodeD;
}else {
root = nodeD;
}
// a - b - c
nodeB.left = nodeA;
if (nodeA != null) nodeA.parent = nodeB;
nodeB.right = nodeC;
if (nodeC != null) nodeC.parent = nodeB;
updateHeight(nodeB);
// e - f - g
nodeF.left = nodeE;
if (nodeE != null) nodeE.parent = nodeF;
nodeF.right = nodeG;
if (nodeG != null) nodeG.parent = nodeF;
updateHeight(nodeF);
// b - d - f
nodeD.left = nodeB;
nodeD.right= nodeF;
nodeB.parent = nodeD;
nodeF.parent = nodeD;
updateHeight(nodeD);
}
private void rotate
private void afterRotate(Node<E> node, Node<E> parent, Node<E> child) {
parent.parent = node.parent;
if (node.isLeftChild()) {
node.parent.left = parent;
} else if (node.isRightChild()) {
node.parent.right = parent;
} else {
root = parent;
}
if (child != null) child.parent = node;
node.parent = parent;
updateHeight(node);
updateHeight(parent);
}
private void updateHeight(Node<E> node){
((AVLNode<E>)node).updateHeight();
}
private static class AVLNode<E> extends Node<E>{
int height = 1;
public AVLNode(E element, Node<E> parent) {
super(element, parent);
}
public int balanceFactor(){
int leftHeight = left == null ? 0 : ((AVLNode<E>)left).height;
int rightHeight = right == null ? 0 : ((AVLNode<E>)right).height;
return leftHeight - rightHeight;
}
public void updateHeight(){
int leftHeight = left == null ? 0 : ((AVLNode<E>)left).height;
int rightHeight = right == null ? 0 : ((AVLNode<E>)right).height;
height = 1 + Math.max(leftHeight, rightHeight);
}
public Node<E> tallerChild() {
int leftHeight = left == null ? 0 : ((AVLNode<E>)left).height;
int rightHeight = right == null ? 0 : ((AVLNode<E>)right).height;
if (leftHeight > rightHeight) return left;
if (leftHeight < rightHeight) return right;
return isLeftChild() ? left : right;
}
}
}
- 平均时间
- 搜索:O(log2n)
- 添加:O(log2n),仅需O(1)次的旋转操作
- 删除:O(log2n),最多需要O(log2n)次的旋转操作
B树(B-tree、B-树)
B树是一种平衡的多路搜索树,多用于文件系统、数据库的实现
-
特点:
- 1个节点可以存储超过2个元素、可以拥有超过2个子节点
- 拥有二叉搜索树的一些性质
- 平衡,每个节点的所有子树的高度一致
- 比较矮
-
m阶B树的性质(m ≥ 2)
假设一个节点存储的元素个数为x
-
根节点:1 ≤ x ≤ m - 1
-
根节点:ceil(m/2) - 1 ≤ x ≤ m - 1
-
如果有子节点,子节点个数 y = x + 1
-
根节点:2 ≤ y ≤ m
-
非根节点:ceil(m/2) ≤ y ≤ m
比如m = 3, 2 ≤ y ≤ 3,因此可以称为(2,3)树、2 - 3树
比如m = 4, 2 ≤ y ≤ 4,因此可以称为(2,4)树、2 - 3 - 4树
比如m = 5, 3 ≤ y ≤ 5,因此可以称为(3,5)树、3 - 4 - 5树
比如m = 6, 3 ≤ y ≤ 6,因此可以称为(3,6)树
若m = 2,那么b树就是二叉搜索树,数据库中实现一般用200 ~ 300阶B树
-
-
B树 VS 二叉搜索树
- B树和二叉搜索树,在逻辑上是等价的
- 多代节点合并,可以获得一个超级节点
- 2代合并的超级节点,最多拥有4个子节点(至少是4阶B树)
- 3代合并的超级节点,最多拥有8个子节点(至少是8阶B树)
- n代合并的超级节点,最多拥有2n个子节点(至少是2n阶B树)
- m阶B树,最多需要log2m代合并
搜索
添加
添加上溢问题解决
删除
B树中,最后真正被删除的元素都在叶子节点中
删除下溢问题解决
4阶B树
学习4阶B树(2-3-4树),将能更好理解红黑树
- 性质:
- 所有节点能存储的元素个数x:1 ≤ x ≤ 3
- 所有非叶子节点的子节点个数y:2 ≤ y ≤ 4
红黑树(Red Black Tree)
- 红黑树也是一种自平衡的二叉搜索树,以前也叫做平衡二叉B树(Symmetric Binary B-tree)
- 红黑树必须满足以下5条性质
- 节点是RED或者BLACK
- 根节点是BLACK
- 叶子节点(外部节点,空节点)都是BLACK,空节点是假象出来,为了保证以前的节点度为2
- RED节点的子节点都是BLACK
- RED节点的父节点都是BLACK
- 从根节点到叶子节点的所有路径上不能有2个连续的RED节点
- 从任一节点到叶子节点的所有路径都包含相同数目的BLACK节点
红黑树的等价变换
添加
- 添加操作的所有情况
- 添加:修复性质4 不能有连续红色节点
删除
红黑树实现
继承结构修改:BinaryTree <- ReconsitutionBinarySearchTree <- BalanceBinarySearchTree <-(AVL/红黑树)
- BinaryTree修改
protected static class Node<E> {
public E element;
public Node<E> left;
public Node<E> right;
public Node<E> parent;
public Node(E element, Node<E> parent) {
this.element = element;
this.parent = parent;
}
public boolean isLeaf() {
return left == null && right == null; }
public boolean hasTwoChildren() {
return left != null && right != null; }
public boolean isLeftChild() {
return parent != null && parent.left == this; }
public boolean isRightChild() {
return parent != null && parent.right == this; }
+ public Node<E> sibling(){
+ if (isLeftChild()) return parent.right;
+ if (isRightChild()) return parent.left;
+ return null;
+ }
}
- ReconsitutionBinarySearchTree 修改
* protected void afterRemove(Node<E> node, Node<E> replacement){
}
private void remove(Node<E> node) {
if (node == null) return;
size--;
if (node.hasTwoChildren()) {
Node<E> successor = successor(node);
node.element = successor.element;
node = successor;
}
Node<E> replacement = node.left != null ? node.left : node.right;
if (replacement != null) {
replacement.parent = node.parent; // 更改parent
if (node.parent == null) {
// 度为1的根节点
root = replacement;
} else if (node == node.parent.left) {
node.parent.left = replacement;
} else {
node.parent.right = replacement;
}
* afterRemove(node, replacement);
} else if (node.parent == null) {
root = null;
* afterRemove(node, null);
} else {
if (node == node.parent.left) {
node.parent.left = null;
} else {
node.parent.right = null;
}
* afterRemove(node, null);
}
}
- 新增BalanceBinarySearchTree
package com.zimo.树.二叉搜索树;
import java.util.Comparator;
/**
* 平衡二叉搜索树
*
* @author Liu_zimo
* @version v0.1 by 2020/10/29 17:02:40
*/
public class BalanceBinarySearchTree<E> extends ReconsitutionBinarySearchTree<E> {
public BalanceBinarySearchTree() {
this(null);
}
public BalanceBinarySearchTree(Comparator<E> comparator) {
super(comparator);
}
// 左旋
protected void rotateLeft(Node<E> node){
Node<E> parent = node.right;
Node<E> child = parent.left;
node.right = child;
parent.left = node;
afterRotate(node, parent, child);
}
// 右旋
protected void rotateRight(Node<E> node){
Node<E> parent = node.left;
Node<E> child = parent.right;
node.left = child;
parent.right = node;
afterRotate(node, parent, child);
}
protected void afterRotate(Node<E> node, Node<E> parent, Node<E> child) {
parent.parent = node.parent;
if (node.isLeftChild()) {
node.parent.left = parent;
} else if (node.isRightChild()) {
node.parent.right = parent;
} else {
root = parent;
}
if (child != null) child.parent = node;
node.parent = parent;
}
/**
* 统一处理恢复平衡(不分情况左右旋转)
* @param node
*/
protected void unifyRebalance(Node<E> oldRoot,
Node<E> nodeA, Node<E> nodeB, Node<E> nodeC,
Node<E> nodeD,
Node<E> nodeE, Node<E> nodeF, Node<E> nodeG){
// d成为子树的根节点
nodeD.parent = oldRoot.parent;
if (oldRoot.isLeftChild()){
oldRoot.parent.left = nodeD;
}else if (oldRoot.isRightChild()){
oldRoot.parent.right = nodeD;
}else {
root = nodeD;
}
// a - b - c
nodeB.left = nodeA;
if (nodeA != null) nodeA.parent = nodeB;
nodeB.right = nodeC;
if (nodeC != null) nodeC.parent = nodeB;
// e - f - g
nodeF.left = nodeE;
if (nodeE != null) nodeE.parent = nodeF;
nodeF.right = nodeG;
if (nodeG != null) nodeG.parent = nodeF;
// b - d - f
nodeD.left = nodeB;
nodeD.right= nodeF;
nodeB.parent = nodeD;
nodeF.parent = nodeD;
}
}
- AVL树优化
* public class AVLTree<E> extends BalanceBinarySearchTree<E>{
@Override
* protected void afterRemove(Node<E> node, Node<E> replacement) {
while ((node = node.parent) != null){
if (isBalanced(node)){
// 更新高度
updateHeight(node);
}else {
// 恢复平衡
rebalance(node);
}
}
}
}
- 红黑树实现
package com.zimo.树.二叉搜索树;
import java.util.Comparator;
/**
* 树 - 红黑树
*
* @author Liu_zimo
* @version v0.1 by 2020/10/29 14:00:00
*/
public class RedBlackTree<E> extends BalanceBinarySearchTree<E> {
private static final boolean RED = false;
private static final boolean BLACK = true;
public RedBlackTree() {
this(null);
}
public RedBlackTree(Comparator comparator) {
super(comparator);
}
@Override
protected void afterAdd(Node<E> node) {
Node<E> parent = node.parent;
// 如果是根节点或者上溢到达根节点,直接染成黑色(一定要在isBlack之前处理根节点,否则null节点默认也是黑色)
if (parent == null){
black(node);
return;
}
// 如果父节点是黑色,直接返回
if (isBlack(parent)){
return; }
// 父节点黑色处理完毕
// 祖父节点 // 优化1:无论啥情况,祖父节点都染成红色
Node<E> grand = red(parent.parent);
// uncle节点
Node<E> uncle = parent.sibling();
if (isRed(uncle)){
// 叔父节点是红色[B树节点上溢]
// 父亲、叔父染黑色
black(parent);
black(uncle);
// 祖父节点染红色,当作新添加元素重新插入
// afterAdd(red(grand)); 优化1
afterAdd(grand);
return;
}
// 叔父节点不是红色
if (parent.isLeftChild()){
// L
// red(grand); 优化1
if (node.isLeftChild()){
// LL
black(parent);
}else {
// LR
black(node);
rotateLeft(parent);
}
rotateRight(grand);
}else {
// R
// red(grand); 优化1
if (node.isLeftChild()){
// RL
black(node);
rotateRight(parent);
}else {
// RR
black(parent);
}
rotateLeft(grand);
}
}
@Override
protected void afterRemove(Node<E> node, Node<E> replacement) {
// 如果删除红色节点,不做任何处理
if (isRed(node)) return;
// 用于取代node的节点是红色
if (isRed(replacement)){
black(replacement); // 将替代的子节点直接染成黑色
return;
}
Node<E> parent = node.parent;
// 删除的是根节点
if (parent == null) return;
// 删除的是黑色的叶子节点【下溢】
boolean isleft = parent.left == null || node.isLeftChild(); // node.isLeftChild()为了包含下面父节点删除情况
Node<E> sibling = isleft ? parent.right : parent.left;
// 1.兄弟是黑是红 无法使用node.sibling(),因为再执行afterRemove,node跟父节点切断了
if (isleft){
// 被删除的节点在左边,兄弟在右边
if (isRed(sibling)) {
// 如果是红色转成黑色
black(sibling);
red(parent);
rotateLeft(parent);
// 更换兄弟
sibling = parent.right;
}
// 2.兄弟节点是黑色,看左右是否有红色子节点借给我
if (isBlack(sibling.left) && isBlack(sibling.right)){
// 兄弟没有红色子节点,父节点向下跟兄弟节点合并
boolean pIsBlack = isBlack(parent);
black(parent);
red(sibling);
if (pIsBlack) {
afterRemove(parent,null);
}
}else{
// 兄弟节点至少有一个红色子节点,向兄弟节点借元素
if (isBlack(sibling.right)){
// 兄弟节点的左边是黑色,兄弟要先右旋转
rotateRight(sibling);
sibling = parent.right;
}
color(sibling, colorOf(parent));
black(sibling.right);
black(parent);
rotateLeft(parent);
}
}else {
// 被删除的节点在右边,兄弟在左边
if (isRed(sibling)) {
// 如果是红色转成黑色
black(sibling);
red(parent);
rotateRight(parent);
// 更换兄弟
sibling = parent.left;
}
// 2.兄弟节点是黑色,看左右是否有红色子节点借给我
if (isBlack(sibling.left) && isBlack(sibling.right)){
// 兄弟没有红色子节点,父节点向下跟兄弟节点合并
boolean pIsBlack = isBlack(parent);
black(parent);
red(sibling);
if (pIsBlack) {
afterRemove(parent,null);
}
}else{
// 兄弟节点至少有一个红色子节点,向兄弟节点借元素
if (isBlack(sibling.left)){
// 兄弟节点的左边是黑色,兄弟要先左旋转
rotateLeft(sibling);
sibling = parent.left;
}
color(sibling, colorOf(parent));
black(sibling.left);
black(parent);
rotateRight(parent);
}
}
}
/**
* 对节点进行染色
* @param node 要染色的节点
* @param color 要染的颜色
* @return 返回染色的节点
*/
private Node<E> color(Node<E> node, boolean color){
if (node == null) return node;
((RBNode<E>) node).color = color;
return node;
}
private Node<E> red(Node<E> node){
return color(node, RED); }
private Node<E> black(Node<E> node){
return color(node, BLACK); }
private boolean colorOf(Node<E> node){
return node == null ? BLACK : ((RBNode<E>) node).color; }
private boolean isRed(Node<E> node){
return colorOf(node) == RED; }
private boolean isBlack(Node<E> node){
return colorOf(node) == BLACK; }
@Override
protected Node<E> createNode(E element, Node<E> parent) {
return new RBNode(element, parent);
}
private static class RBNode<E> extends Node<E>{
boolean color = RED; // 默认染成红色,这样能够让红黑树的性质尽快满足
public RBNode(E element, Node<E> parent) {
super(element, parent);
}
}
}
红黑树优化
- ReconsitutionBinarySearchTree 修改
* protected void afterRemove(Node<E> node){
}
private void remove(Node<E> node) {
if (node == null) return;
size--;
if (node.hasTwoChildren()) {
Node<E> successor = successor(node);
node.element = successor.element;
node = successor;
}
Node<E> replacement = node.left != null ? node.left : node.right;
if (replacement != null) {
replacement.parent = node.parent; // 更改parent
if (node.parent == null) {
// 度为1的根节点
root = replacement;
} else if (node == node.parent.left) {
node.parent.left = replacement;
} else {
node.parent.right = replacement;
}
* afterRemove(replacement); // 对于AVL树毫无影响
} else if (node.parent == null) {
root = null;
* afterRemove(node);
} else {
if (node == node.parent.left) {
node.parent.left = null;
} else {
node.parent.right = null;
}
* afterRemove(node);
}
}
- 红黑树修改优化
public class RedBlackTree<E> extends BalanceBinarySearchTree<E> {
@Override
protected void afterRemove(Node<E> node) {
// node可能是 被删除node或者被替换的replacementNode(度为1)
- // 如果删除红色节点,不做任何处理
- // if (isRed(node)) return;
// 用于取代node的节点是红色
* if (isRed(node)){
* black(node); // 将替代的子节点直接染成黑色
return;
}
Node<E> parent = node.parent;
if (parent == null) return;
boolean isleft = parent.left == null || node.isLeftChild();
Node<E> sibling = isleft ? parent.right : parent.left;
if (isleft){
if (isRed(sibling)) {
black(sibling);
red(parent);
rotateLeft(parent);
sibling = parent.right;
}
if (isBlack(sibling.left) && isBlack(sibling.right)){
boolean pIsBlack = isBlack(parent);
black(parent);
red(sibling);
if (pIsBlack) {
* afterRemove(parent);
}
}else{
if (isBlack(sibling.right)){
rotateRight(sibling);
sibling = parent.right;
}
color(sibling, colorOf(parent));
black(sibling.right);
black(parent);
rotateLeft(parent);
}
}else {
if (isRed(sibling)) {
black(sibling);
red(parent);
rotateRight(parent);
sibling = parent.left;
}
if (isBlack(sibling.left) && isBlack(sibling.right)){
boolean pIsBlack = isBlack(parent);
black(parent);
red(sibling);
if (pIsBlack) {
* afterRemove(parent);
}
}else{
if (isBlack(sibling.left)){
rotateLeft(sibling);
sibling = parent.left;
}
color(sibling, colorOf(parent));
black(sibling.left);
black(parent);
rotateRight(parent);
}
}
}
}
红黑树的平衡
- 五条性质,可以保证 红黑树 等价于 4阶B树
- 相比于AVL树,红黑树的平衡标准比较宽松:没有一条路径会大于其他路径的2倍
- 是一种弱平衡、黑高度平衡
- 红黑树的最大高度是2 * log2(n + 1),依然是O(logn)级别
- 平均时间复杂度:
- 搜索:O(logn)
- 添加:O(logn),O(1)次旋转操作
- 删除:O(logn),O(1)次旋转操作
AVL树VS红黑树
- AVL树
平衡标准比较严格:每个左右子树的高度差不超过1
最大高度是1.44 * log2(n + 2) - 1.328(100w个节点,AVL树最大树高28)
搜索、添加、删除都是O(logn)复杂度,其中添加仅需O(1)次旋转调整、删除最多需要O(logn)次旋转调整
- 红黑树
红黑树的平衡标准比较宽松:没有一条路径会大于其他路径的2倍
红黑树的最大高度是2 * log2(n + 1)(100w个节点,红黑树最大树高40)
搜索、添加、删除都是O(logn)复杂度,其中添加、删除仅需O(1)次旋转调整
- 搜索的次数远远大于插入和删除,选择AVL树;搜索、插入、删除次数几乎差不多,选择红黑树
- 相对于AVL树来说,红黑树牺牲了部分平衡性以换取插入/删除操作时少量的旋转操作,整体来说性能要优于AVL树
- 红黑树的平均统计性能优于AVL树,实际应用中更多选择使用红黑树