本文主要回顾二叉树、二叉搜索树、平衡二叉搜索树、AVL树、B树、红黑树。包含具体的实现代码、部分方法的注释。
树间的继承关系:
- BinaryTree实现BinaryTreeInfo接口
- BinarySearchTree继承BinaryTree
- BalanceBinarySearchTree继承BinarySearchTree
- AVLTree和RBTree继承BalanceBinarySearchTree
二叉树
◼ 二叉树的特点
每个节点的度最大为 2(最多拥有 2 棵子树)
左子树和右子树是有顺序的
即使某节点只有一棵子树,也要区分左右子树
代码
BinaryTreeInfo.java //BianryTree实现的接口
package com.mj.printer;
public interface BinaryTreeInfo {
/**
* who is the root node
*/
Object root();
/**
* how to get the left child of the node
*/
Object left(Object node);
/**
* how to get the right child of the node
*/
Object right(Object node);
/**
* how to print the node
*/
Object string(Object node);
}
package _08_红黑树.tree;
import java.util.LinkedList;
import java.util.Queue;
import com.mj.printer.BinaryTreeInfo;
@SuppressWarnings("all")
public class BinaryTree2<E> implements BinaryTreeInfo {
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 preorder(Visitor<E> visitor){
if (visitor == null) return ;
preorder(root, visitor);
}
public void preorder(Node<E> node, Visitor<E> visitor){
if (node == null || visitor.stop) return;
visitor.stop = visitor.visit(node.element);
preorder(node.left, visitor);
preorder(node.right, visitor);
}
public void inorder(Visitor<E> visitor){
if (visitor == null) return;
inorder(root, visitor);
}
public void inorder(Node<E> node, Visitor visitor){
if (node == null || visitor.stop) return;
inorder(node.left, visitor);
if (visitor.stop) return;
visitor.stop = visitor.visit(node.element);
inorder(node.right, visitor);
}
public void postorder(Visitor<E> visitor){
if (visitor == null) return;
postorder(root, visitor);
}
public void postorder(Node<E> node, Visitor<E> visitor){
if (node == null || visitor.stop) return;
postorder(node.left, visitor);
postorder(node.right, visitor);
if (visitor.stop) return;
visitor.stop = visitor.visit(node.element);
}
public void levelOrder(Visitor<E> visitor){
if (root == null || visitor.stop) return;
Queue<Node<E>> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
Node<E> node = queue.poll();
if (visitor.stop)return;
visitor.stop = visitor.visit(node.element);
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
}
/**
* 判断该树是否是一颗完全二叉树
* @return
*/
public boolean isComplete(){
if (root == null) return true;
Queue<Node<E>> queue = new LinkedList<>();
queue.offer(root);
boolean leaf = false;
while( !queue.isEmpty()){
Node<E> node = queue.poll();
if (leaf && !node.isLeaf()) return false;
if (node.left != null){
queue.offer(node.left);
} else if (node.right != null){
return false;
}
if (node.right != null){
queue.offer(node.right);
} else{ //后面遍历的节点必须是叶子节点
leaf = true;
}
}
return true;
}
public int height(){
if (root == null) return 0;
//树的高度
int height = 0;
//存储着每一层元素的数量
int levelSize = 1;
Queue<Node<E>> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()){
levelSize--;
Node<E> node = queue.poll();
if (node.left != null){
queue.offer(node.left);
}
if (node.right != null){
queue.offer(node.right);
}
if (levelSize == 0){ //意味着即将要访问下一层
height++;
levelSize = queue.size();
}
}
return height;
}
public int height2(){
return height(root);
}
public int height(Node<E> node){
if (node == null) return 0;
return Math.max(height(node.left), height(node.right)) + 1;
}
/*
*
* 创建一个节点
*/
protected Node<E> createNode(E element, Node<E> parent){
return new Node<E>(element, parent);
}
protected Node<E> predecessor(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.parent.left == node){
node = node.parent;
}
//node.parent == null
// node.parent.right == node
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 != null){
p = p.left;
}
return p;
}
//从父节点中找
while (node.parent != null && node == node.parent.right){
node = node.parent;
}
return node.parent;
}
protected 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;
}
public boolean isLeaf(){
return left == null && right == null;
}
public boolean hasTwoChildren(){
return left != null && right != null;
}
public boolean isLeftChild(){
return parent != null && this == parent.left;
}
public boolean isRightChild(){
return parent != null && this == parent.right;
}
public Node<E> sibling(){
if (isLeftChild()){
return parent.right;
}
if (isRightChild()){
return parent.left;
}
return null;
}
}
@Override
public Object root() {
return root;
}
@Override
public Object left(Object node) {
return ((Node<E>)node).left;
}
@Override
public Object right(Object node) {
return ((Node<E>)node).right;
}
@Override
public Object string(Object node) {
return node;
}
public static abstract class Visitor<E>{
boolean stop;
/**
*
* @param element
* @return 如果返回true,就代表遍历停止。
*/
abstract boolean visit(E element);
}
}
二叉搜索树
◼ 二叉搜索树是二叉树的一种,是应用非常广泛的一种二叉树,英文简称为 BST
又被称为:二叉查找树、二叉排序树
任意一个节点的值都大于其左子树所有节点的值
任意一个节点的值都小于其右子树所有节点的值
它的左右子树也是一棵二叉搜索树
代码
package _08_红黑树.tree;
import java.util.Comparator;
@SuppressWarnings("unchecked")
public class BST2<E> extends BinaryTree2<E> {
private Comparator<E> comparator;
public BST2(){
this(null);
}
public BST2(Comparator<E> comparator){
this.comparator = comparator;
}
public void add(E element){
elementNotNullCheck(element);
//添加第一个节点
if (root == null){
root = createNode(element, null);
size++;
//新添加节点之后的处理
afterAdd(root);
return;
}
//添加的不是第一个节点 找到父节点
Node<E> parent = root;
Node<E> node = root;
int cmp = 0;
do {
cmp = compare(element, node.element);
parent = node;
if(cmp > 0){
node = node.right;
} else if (cmp < 0){
node = node.left;
}else{
node.element = element;
return;
}
}while (node != null);
//看看插入到父节点哪个位置
Node<E> newNode = createNode(element, parent);
if (cmp > 0){
parent.right = newNode;
}else{
parent.left = newNode;
}
size++;
//新添加结点之后的处理
afterAdd(newNode);
}
/**
* 添加节点之后的处理
* @param node
*/
protected void afterAdd(Node<E> node){
}
protected void afterRemove(Node<E> node){
}
public void remove(E element){
remove(node(element));
}
public boolean contains(E element){
return node(element) != null;
}
public void remove(Node<E> node){
if ( node == null) return;
size--;
if (node.hasTwoChildren()){ //度为2的节点
//找到后继节点
Node<E> s = successor(node);
//用后继节点的值覆盖当前节点
node.element = s.element;
//删除后继节点
node = s;
}
//删除node节点 node必定为度为1或0的节点
Node<E> replacement = node.left != null ? node.left : node.right;
if (replacement != null){ //node是度为1的结点
//更改parent
replacement.parent = node.parent;
//更改parent的left right指向
if (node.parent == null){ //node是度为1的节点并且是根节点
root = replacement;
} else if (node.parent.left == node){//node在父节点左边
node.parent.left = replacement;
}else{
node.parent.right = replacement;
}
//删除节点之后的处理
afterRemove(replacement);
}else if (node.parent == null){ //node是度为0的节点(叶子节点)并且是根节点
root = null;
afterRemove(node);
} else{ //node是叶子节点, 但不是根节点
if (node == node.parent.left){
node.parent.left = null;
}else{
node.parent.right = null;
}
//删除节点之后的处理
afterRemove(node);
}
}
/**
* 按值查找节点
* @param element
* @return 目标节点
*/
private Node<E> node(E element){
Node<E> node = 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 e1
* @param e2
* @return
*/
private int compare(E e1, E e2){
if (comparator != null){
return comparator.compare(e1, e2);
}
//没有比较器就必须实现Comparable<E>接口 否则下面这句就报错
return ((Comparable<E>)e1).compareTo(e2);
}
private void elementNotNullCheck(E element){
if (element == null ){
throw new IllegalArgumentException("element must not be null!");
}
}
}
平衡二叉搜索树
◼ 英文简称为:BBST
◼ 经典常见的平衡二叉搜索树有
AVL树
✓ Windows NT 内核中广泛使用
红黑树
✓ C++ STL(比如 map、set )
✓ Java 的 TreeMap、TreeSet、HashMap、HashSet
✓ Linux 的进程调度
✓ Ngix 的 timer 管理
一般也称它们为:自平衡的二叉搜索树(Self-balancing Binary Search Tree)
package _08_红黑树.tree;
import java.util.Comparator;
public class BBST2<E> extends BST2<E> {
public BBST2(){
this(null);//调用他自己的构造方法
}
public BBST2(Comparator<E> comparator){
super(comparator); //将comparator传入父类的构造方法中
}
/**
* 左旋
* @param grand
*/
protected void rotateLeft(Node<E> grand){
Node<E> parent = grand.right;
Node<E> child = parent.left;
grand.right = child;
parent.left = grand; //让parent称为根节点
afterRotate(grand, parent, child);
}
/**
* 右旋
* @param grand
*/
protected void rotateRight(Node<E> grand){
Node<E> parent = grand.left;
Node<E> child = parent.right;
grand.left = child;
parent.right = grand; //让parent成为根节点
afterRotate(grand, parent, child);
}
protected void afterRotate(Node<E> grand, Node<E> parent, Node<E> child){
// 让parent成为子树的根节点 需要的一系列操作
parent.parent = grand.parent;
if (grand.isLeftChild()){
grand.parent.left = parent;
} else if(grand.isRightChild()){
grand.parent.right = parent;
} else{ //grand是root节点
root = parent;
}
//更新child的parent
if ( child != null){
child.parent = grand;
}
//更新grand的parent
grand.parent = parent;
}
/**
* 统一旋转操作
*
*/
protected void rotate(
Node<E> r, //子树的根节点
Node<E> b, Node<E> c,
Node<E> d,
Node<E> e, Node<E> f){
//让d 成为这颗子树的根节点
d.parent = r.parent;
if (r.isLeftChild()){
r.parent.left = d;
} else if (r.isRightChild()){
r.parent.right = d;
} else{
root = d;
}
//b-c
b.right = c;
if (c != null){
c.parent = b;
}
//e-f
f.left = e;
if (e != null){
e.parent = f;
}
//b-d-f
d.left = b;
d.right = f;
b.parent = d;
f.parent = d;
}
}
AVL树
◼ 平衡因子(Balance Factor):某结点的左右子树的高度差
◼ AVL树的特点
每个节点的平衡因子只可能是 1、0、-1(绝对值 ≤ 1,如果超过 1,称之为“失衡”)
每个节点的左右子树高度差不超过 1
搜索、添加、删除的时间复杂度是 O(logn)
代码
package _08_红黑树.tree;
import java.util.Comparator;
@SuppressWarnings("all")
public class AVLTree2<E> extends BBST2<E> {
public AVLTree2(){
this(null);
}
public AVLTree2(Comparator<E> comparator){
super(comparator);
}
//添加元素 一定是加到叶子结点上, 可能会导致所有祖先节点都失衡 所以一直循环往上找
protected void afterAdd(Node<E> node){
while((node = node.parent ) != null){
if (isBalanced(node)){
//更新高度
updateHeight(node);
}else{
//恢复平衡
rebalance(node);
//整棵树恢复平衡
break;
}
}
}
/**
* 删除 : 可能会导致父节点或祖先节点失衡(只有1个节点会失衡),其他节点,都不可能失衡
* * 更高层的祖先节点可能也会失衡,需要再次恢复平衡,然后又可能导致更高层的祖先节点失衡...
* * 极端情况下,所有祖先节点都需要进行恢复平衡的操作,共 O(logn) 次调整
* @param node 被删除的节点 或者 用以取代被删除节点的子节点(当被删除节点的度为1)
*/
protected void afterRemove(Node<E> node){
while ((node = node.parent) != null){
if (isBalanced(node)){
//更新高度
updateHeight(node);
} else{
//恢复平衡
rebalance(node);
}
}
}
protected Node<E> createNode(E element, Node<E> parent){
return new AVLNode<>(element, parent);
}
/**
* 恢复平衡
* @param grand 高度最低的那个不平衡点
*/
private void reBalance2(Node<E> grand){
Node<E> parent = ((AVLNode<E>)grand).tallerChild();
Node<E> node = ((AVLNode<E>)parent).tallerChild();
if (parent.isLeftChild()){ //L
if (node.isLeftChild()){ //LL
rotateRight(grand);
} else{ //LR
rotateLeft(parent);
rotateRight(grand);
}
} else{ //R
if (node.isLeftChild()) { //RL
rotateRight(parent);
rotateLeft(grand);
}else{ //RR
rotateLeft(grand);
}
}
}
@Override
protected void afterRotate(Node<E> grand, Node<E> parent, Node<E> child) {
super.afterRotate(grand, parent, child);
// 更新高度
updateHeight(grand);
updateHeight(parent);
}
/**
* 统一旋转 调用父类的rotate函数
* @param r 根节点
* @param b
* @param c
* @param d
* @param e
* @param f
*/
@Override
protected void rotate(Node<E> r, Node<E> b, Node<E> c, Node<E> d, Node<E> e, Node<E> f) {
super.rotate(r, b, c, d, e, f);
// 更新高度
updateHeight(b);
updateHeight(f);
updateHeight(d);
}
/**
* 恢复平衡 添加和删除节点都有可能导致失去平衡
* 添加 : 最坏情况:可能会导致所有祖先节点都失衡
* 删除 : 可能会导致父节点或祖先节点失衡(只有1个节点会失衡),其他节点,都不可能失衡
* 更高层的祖先节点可能也会失衡,需要再次恢复平衡,然后又可能导致更高层的祖先节点失衡...
* 极端情况下,所有祖先节点都需要进行恢复平衡的操作,共 O(logn) 次调整
* @param grand 高度最低的那个不平衡节点
*/
private void rebalance(Node<E> grand) {
Node<E> parent = ((AVLNode<E>)grand).tallerChild();
Node<E> node = ((AVLNode<E>)parent).tallerChild();
if (parent.isLeftChild()) { // L
if (node.isLeftChild()) { // LL
rotate(grand, node, node.right, parent, parent.right, grand);
} else { // LR
rotate(grand, parent, node.left, node, node.right, grand);
}
} else { // R
if (node.isLeftChild()) { // RL
rotate(grand, grand, node.left, node, node.right, parent);
} else { // RR
rotate(grand, grand, parent.left, parent, node.left, node);
}
}
}
/**
* 看这个结点是否平衡 即看这个节点的平衡因子绝对值是否小于等于1
* @param node
* @return
*/
private boolean isBalanced(Node<E> node){
return Math.abs(((AVLNode<E>)node).balanceFactor()) <= 1;
}
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; //左右两边相等的情况
}
public String toString() {
String parentString = "null";
if (parent != null){
parentString = parent.element.toString();
}
return element + "_p(" + parentString + ")_h(" + height + ")";
}
}
}
红黑树
◼ 红黑树也是一种自平衡的二叉搜索树
以前也叫做平衡二叉B树(Symmetric Binary B-tree)
◼ 红黑树必须满足以下 5 条性质
- 节点是 RED 或者 BLACK
- 根节点是 BLACK
- 叶子节点(外部节点,空节点)都是 BLACK
- RED 节点的子节点都是 BLACK
✓ RED 节点的 parent 都是 BLACK
✓ 从根节点到叶子节点的所有路径上不能有 2 个连续的 RED 节点 - 从任一节点到叶子节点的所有路径都包含相同数目的 BLACK 节点
代码
package _08_红黑树.tree;
import java.util.Comparator;
public class RBTree2<E> extends BBST2<E> {
private static final boolean RED = false;
private static final boolean BLACK = true;
public RBTree2() {
this(null);
}
public RBTree2(Comparator<E> comparator) {
super(comparator);
}
/**
* 红黑数等姐于4阶B树 添加时只能在叶子节点上加,共12种情况 可能会导致树失衡
* 对12种情况进行处理
* @param node
*/
protected void afterAdd(Node<E> node) {
Node<E> parent = node.parent;
// 添加的是根节点 或者
// 上溢到达了根节点(根节点中间的值自己上去成为新的根节点 没有parent)
if (parent == null) {
black(node);
return;
}
// 如果父节点是黑色,直接返回
if (isBlack(parent)) return;
// 叔父节点
Node<E> uncle = parent.sibling();
// 祖父节点 //添加时不合规的那八种情况,修复的时候grand都是要染成红色的
Node<E> grand = red(parent.parent);
if (isRed(uncle)) { // 叔父节点是红色【B树节点上溢】
black(parent);
black(uncle);
// 把祖父节点当做是新添加的节点 向上合并
afterAdd(grand);
return;
}
// 叔父节点不是红色
if (parent.isLeftChild()) { // L
if (node.isLeftChild()) { // LL
black(parent);
} else { // LR
black(node);
rotateLeft(parent);
}
rotateRight(grand);
} else { // R
if (node.isLeftChild()) { // RL
black(node);
rotateRight(parent);
} else { // RR
black(parent);
}
rotateLeft(grand);
}
}
/**
* B树中,最后真正被删除的元素都在叶子节点中
* 删除红色节点不需要处理
* 删除黑色节点
* ◼ 有 3 种情况 可能会导致红黑树失衡
* 拥有 2 个 RED 子节点的 BLACK 节点
* ✓ 不可能被直接删除,因为会找它的子节点替代删除
* ✓ 因此不用考虑这种情况
* 拥有 1 个 RED 子节点的 BLACK 节点
* BLACK 叶子节点
* @param node
*/
@Override
protected void afterRemove(Node<E> node) {
// 如果删除的节点是红色
// 或者 用以取代删除节点的子节点是红色
if (isRed(node)) {
black(node);
return;
}
Node<E> parent = node.parent;
// 删除的是根节点
if (parent == null) return;
// 删除的是黑色叶子节点【下溢】
// 判断被删除的node是左还是右
boolean left = parent.left == null || node.isLeftChild();
Node<E> sibling = left ? parent.right : parent.left;
if (left) { // 被删除的节点在左边,兄弟节点在右边
if (isRed(sibling)) { // 兄弟节点是红色
black(sibling);
red(parent);
rotateLeft(parent);
// 更换兄弟
sibling = parent.right;
}
// 兄弟节点必然是黑色
if (isBlack(sibling.left) && isBlack(sibling.right)) {
// 兄弟节点没有1个红色子节点,父节点要向下跟兄弟节点合并
boolean parentBlack = isBlack(parent);
black(parent);
red(sibling);
if (parentBlack) {
afterRemove(parent);
}
} else { // 兄弟节点至少有1个红色子节点,向兄弟节点借元素
// 兄弟节点的左边是黑色,兄弟要先旋转
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)) {
// 兄弟节点没有1个红色子节点,父节点要向下跟兄弟节点合并
boolean parentBlack = isBlack(parent);
black(parent);
red(sibling);
if (parentBlack) {
afterRemove(parent);
}
} else { // 兄弟节点至少有1个红色子节点,向兄弟节点借元素
// 兄弟节点的左边是黑色,兄弟要先旋转
if (isBlack(sibling.left)) {
rotateLeft(sibling);
sibling = parent.left;
}
color(sibling, colorOf(parent));
black(sibling.left);
black(parent);
rotateRight(parent);
}
}
}
private Node<E> color(Node<E> node, boolean color) {
if (node == null) return node;
((RBNode2<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 : ((RBNode2<E>)node).color;
}
private boolean isBlack(Node<E> node) {
return colorOf(node) == BLACK;
}
private boolean isRed(Node<E> node) {
return colorOf(node) == RED;
}
@Override //重写父类的创建结点方法
protected Node<E> createNode(E element, Node<E> parent) {
return new RBNode2<E>(element, parent);
}
private static class RBNode2<E> extends Node<E> {
boolean color = RED;
public RBNode2(E element, Node<E> parent) {
super(element, parent);
}
@Override
public String toString() {
String str = "";
if (color == RED) {
str = "R_";
}
return str + element.toString();
}
}
}
有问题欢迎评论、私信。
如果觉得本文对你的学习有帮助,还请一键三连!