傅老师课堂:红黑树

红黑树啊,怎么这么难呢?哎,还得继续研究,目前只是完成了红黑树的添加,删除还没有完成(自己汗一个)。


package com.au.algorithm;

import java.util.ArrayList;
import java.util.List;

/**
 * 红黑树的五个性质:
 * 
 * 1)每个结点要么是红的,要么是黑的。 
 * 2)根结点是黑的。 
 * 3)每个叶结点,即空结点(NIL)是黑的。 
 * 4)如果一个结点是红的,那么它的俩个儿子都是黑的。
 * 5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。
 * 
 * 
 * @author fuyouming
 * 
 * @param <E>
 */
public class RBTree<E extends Comparable<E>> {

	private Node<E> root;

	/**
	 * 在对红黑树进行插入操作时,我们一般总是插入红色的结点,因为这样可以在插入过程中尽量避免对树的调整。
	 * 如果插入的结点是根结点,性质2会被破坏,如果插入结点的父结点是红色,则会破坏性质4。 
	 * 因此,总而言之,插入一个红色结点只会破坏性质2或性质4。
	 * 
	 * 
	 * @param e
	 */
	public void insert(E e) {
		System.out.println("====== 添加节点 " + e + "======");
		if (root == null) {
			root = new Node<E>(null, e, Color.BLACK);
		} else {
			Node<E> current = root;
			Node<E> parent = null;
			int negative = 0;
			while (current != null) {
				negative = e.compareTo(current.key);
				parent = current;
				if (negative < 0) {
					current = current.left;
				} else if (negative > 0) {
					current = current.right;
				} else {
					return;
				}
			}
			current = new Node<E>(parent, e, Color.RED);
			if (negative < 0) {
				parent.left = current;
			} else {
				parent.right = current;
			}
			insertFixup(current);
		}
	}
	
	public boolean remove(E e){
		if (root == null)
			return false;
		Node<E> current = root;
		int negative = 0;
		while (current != null) {
			negative = e.compareTo(current.key);
			if (negative < 0) {
				current = current.left;
			} else if (negative > 0) {
				current = current.right;
			} else {
				break;
			}
		}
		if(current != null){
			if (current.right != null) {
				Node<E> newCurrent = current.right;
				while (newCurrent.left != null) {
					newCurrent = newCurrent.left;
				}
				current.key = newCurrent.key;
				current = newCurrent;
			}
			System.out.println("====== 删除节点 " + e + "(" + (current == null ? ""
					: current.key) + ")======");
			Node<E> brother, parent = current.parent, rightChild = current.right;
			if (current == parent.left) {
				parent.left = rightChild;
				brother = parent.right;
			} else {
				parent.right = rightChild;
				brother = parent.left;
			}
			
			if (current.color == Color.BLACK) {
				if (rightChild != null) {
					rightChild.parent = parent;
					// 当删除的节点有一个红色的孩子
					if (rightChild.color == Color.RED) {
						rightChild.color = Color.BLACK;
					}
				} else {
					if (brother != null) {
						if (brother.color == Color.RED) {
							// 父=>红,兄=>黑
							parent.color = Color.RED;
							brother.color = Color.BLACK;
							if (brother == parent.right) {
								rotateLeft(brother);// 左旋转父节点
							} else {
								if (brother.left != null)
									rotateRight(brother.left);// 右旋转父节点
							}
						} else {
							if (brother.left != null
									&& brother.left.color == Color.RED) {
								// 侄=>父色,父=>黑
								brother.color = parent.color;
								brother.left.color = parent.color = Color.BLACK;
								if (brother == parent.right) {
									rotateLeft(brother.left);// 左旋转父节点
									rotateRight(brother);
								} else {
									rotateRight(brother.left);// 右旋转父节点
								}
							} else if (brother.right != null
									&& brother.right.color == Color.RED) {
								// 兄=>父色,父=>黑,侄=>黑,(子=>黑)
								brother.color = brother.parent.color;
								parent.color = brother.right.color = Color.BLACK;
								if (brother == parent.right) {
									rotateRight(brother.right);// 右旋转父节点
								} else {
									rotateLeft(brother.right);// 左旋转父节点
									rotateRight(brother);
								}
							} else {
								//兄=>红,子=黑,红父=>黑, 往上遍历(黑父)
								brother.color = Color.RED;
								while(parent != null && parent.color == Color.BLACK){
									parent = parent.parent;
								}
								if(parent != null && parent.color == Color.RED){
									parent.color = Color.BLACK;
								}
							}
						}
					}
				}
			}
		}
		return false;
	}
	
	/**
	 * 红黑树的所有插入情况有以下五种: 
	 * 
	 * 情况1:插入的是根结点。 
	 * 分析:原树是空树,此情况只会违反性质2。 
	 * 
	 * 情况2:插入的结点的父结点是黑色。 
	 * 分析:此不会违反性质2和性质4,红黑树没有被破坏。 
	 * 
	 * 情况3:当前结点的父结点是红色且祖父结点的另一个子结点(叔叔结点)是红色。 
	 * 分析:此情况违反了性质4。
	 * 
	 * 情况4:当前节点的父节点是红色,叔叔节点是黑色或NIL,当前节点是其父节点的右子。
	 * 分析:此情况违反了性质4。
	 * 
	 * 情况5:当前节点的父节点是红色,叔叔节点是黑色或NIL,当前节点是其父节点的左子。
	 * 分析:此情况违反了性质4。
	 */
	private void insertFixup(Node<E> current) {
		Node<E> grandparent, parent, uncle;
		// 当有两个相连的节点都是红色的时候,违反了红黑树的性质,所以必须要调整
		while ((parent = current.parent) != null && parent.color == Color.RED
				&& current.color == Color.RED) {
			grandparent = parent.parent;
			uncle = parent == grandparent.left ? grandparent.right
					: grandparent.left;
			if (uncle != null && uncle.color == Color.RED) {
				// 父=>黑,叔=>黑,祖=>红,祖为新节点开始
				uncle.color = parent.color = Color.BLACK;
				grandparent.color = Color.RED;
				current = grandparent;
			} else {
				grandparent.color = Color.RED;// 祖=>红
				if ((parent == grandparent.left && current == parent.left)
						|| (parent == grandparent.right && current == parent.right)) {
					parent.color = Color.BLACK;// 父=>黑
					// 父=>黑,祖=>红,祖父右旋转
					rotateRight(current);
				} else {
					current.color = Color.BLACK;// 新=>黑
					// 新=>黑,祖=>红,父左旋转;祖右旋转
					rotateLeft(current);
					rotateRight(parent);
				}
				current = parent;// 以父节点为新的当前节点
			}
		}
		root.color = Color.BLACK;// 根节点永远都是黑的
	}

	/**
	 * 左旋:父节点和孩子节点交换角色
	 */
	private void rotateLeft(Node<E> current) {
		System.out.println("左旋:" + current.key);
		Node<E> parent = current.parent, grandparent = parent.parent, child = null;
		if (current == parent.right) {
			child = current.left;
			parent.right = child;
			current.left = parent;
		} else {
			child = current.right;
			parent.left = child;
			current.right = parent;
		}
		if (child != null)
			child.parent = parent;
		if (parent == grandparent.left) {
			grandparent.left = current;
		} else {
			grandparent.right = current;
		}
		current.parent = grandparent;
		parent.parent = current;
	}

	/**
	 * 右旋:祖父节点和兄弟节点交换角色
	 */
	private void rotateRight(Node<E> current) {
		System.out.println("右旋:" + current.key);
		Node<E> parent = current.parent, grandparent = parent.parent, brother = null;
		if (current == parent.left) {
			brother = parent.right;
			parent.right = grandparent;
		} else {
			brother = parent.left;
			parent.left = grandparent;
		}
		if (parent == grandparent.left)
			grandparent.left = brother;
		else
			grandparent.right = brother;
		if (brother != null)
			brother.parent = grandparent;
		if (grandparent.parent != null) {
			if (grandparent.parent.left == grandparent) {
				grandparent.parent.left = parent;
			} else {
				grandparent.parent.right = parent;
			}
		} else {
			root = parent;
		}
		parent.parent = grandparent.parent;
		grandparent.parent = parent;
	}
	
	public void print() {
		List<Node> list = new ArrayList<Node>();
		if(this.root == null) return;
		list.add(this.root);
		while (!list.isEmpty()) {
			List<Node> l = new ArrayList<Node>();
			for (Node n : list) {
				System.out.print(n.key
						//+ "("
						//+ (n.color == Color.RED ? "红" : "黑")
						//+ ")["
						+"["
						+ (n.left != null ? n.left.key + "("
								+ (n.left.color == Color.RED ? "红" : "黑") + ")"
								: "无")
						+ " "
						+ (n.right != null ? n.right.key + "("
								+ (n.right.color == Color.RED ? "红" : "黑")
								+ ")" : "无") + "] ");
				if (n.left != null) {
					l.add(n.left);
				}
				if (n.right != null) {
					l.add(n.right);
				}
			}
			System.out.print("\r");
			list = l;
		}
	}

	static enum Color {
		BLACK, RED
	}

	static class Node<E extends Comparable<E>> {
		E key;
		Node<E> left, right;
		Node<E> parent;
		Color color;

		Node(Node<E> parent, E key, Color color) {
			this.key = key;
			this.color = color;
			this.parent = parent;
			this.left = null;
			this.right = null;
		}
	}
	
	public static void main(String[] args) {
		RBTree<Integer> tree = new RBTree<Integer>();
		int[] intArr = new int[] { 12, 1, 9, 2, 0, 11, 7, 19, 4, 15, 18, 5, 14, 13, 10, 16, 6, 3, 8, 17 };// 情况3
		for (int i = 0; i < intArr.length; i++) {
			tree.insert(intArr[i]);
		}
		tree.print();
		for (int i = 0; i < intArr.length-1; i++) {
			tree.remove(intArr[i]);
			tree.print();
		}
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值