HashMap之红黑树上(插入,查询)

红黑树

1.五大性质

  1. 每个节点要么是黑色,要么是红色
  2. 根节点为黑色
  3. 每个叶子节点(null)为黑色
  4. 每个红色的两个子节点一定是黑色
  5. 任意一节点到每个叶子节点的路径上黑节点的数目相同

红黑树并不是一个完美的平衡二叉树,根据节点五可知到子节点黑色节点数目相同。所以我们称红黑树这种平衡为黑色完美平衡

2.基本操作

  1. 左旋:以某个结点作为支点(旋转结点),其右子结点变为旋转结点的父结点,右子结点的左子结点变为旋转结点的右子结点,左子结点保持不变。
    在这里插入图片描述

在这里插入图片描述

  1. 右旋:以某个结点作为支点(旋转结点),其左子结点变为旋转结点的父结点,左子结点的右子结点变为旋转结点的左子结点,右子结点保持不变。
    在这里插入图片描述
    在这里插入图片描述

  2. 变色:结点的颜色由红变黑或由黑变红。

正文

红黑树查找

红黑树查找,与二叉搜索树相同。
在这里插入图片描述

红黑树插入

在这里插入图片描述
若插入位置父节点为黑色,则不用做任何处理。(同二分搜索树)

当插入新元素破坏了红黑树的性质
在这里插入图片描述
在这里插入图片描述

情景分析
1. 当根节点为空时。直接插入,根据性质2:根节点为黑色,变为黑色。
2. 插入节点已存在时。将新元素的值传给对应节点

在这里插入图片描述

3. 若插入位置父节点为黑色,则不用做任何处理。(同二分搜索树)。不影响黑色完美平衡。

在这里插入图片描述在这里插入图片描述

4. 插入节点父节点为红色。
4.1 叔叔节点存在并且为红色节点
>红节点的子节点为黑色----》**爷爷节点为黑色**
>1.将父节点和叔叔节点变为黑色
>2.将爷爷节点变为红色
>3.将爷爷节点变为当前节点进行后续处理。

在这里插入图片描述

4.2叔叔节点不存在或为黑色节点,并父节点是爷爷节点的左子节点。

在这里插入图片描述

  1. 插入节点为父节点的左子节点
    在这里插入图片描述

     	处理:
     >	1. 变色 ,夫系欸但为黑色,爷爷节点变为红色
     >	2. 进行右旋
    

在这里插入图片描述
2. 插入节点为父节点的右节点
3.
处理:

  1. 以p节点进行左旋
  2. 进行变色处理—》父节点变为红色
  3. 以爷爷节点进行右旋 ,若I节点有右节点则给爷爷节点的左节点

在这里插入图片描述

4.3叔叔节点不存在或为黑色节点,并父节点是爷爷节点的右子节点。

在这里插入图片描述

  1. 当插入节点为父节点的右节点时(对之前的操作相反)

变色之后进行左旋

在这里插入图片描述

在这里插入图片描述
2. 当插入节点为父节点的左节点时

先右旋,变色再以爷爷节点左旋

在这里插入图片描述

在这里插入图片描述

代码

package RBTREE;

import com.sun.prism.paint.Gradient;
import com.sun.xml.internal.bind.v2.model.core.ID;

public class RBTree<K extends Comparable<K>, V> {
	private static final boolean RED = true;  //红
	private static final boolean BLACK = false;  //黑
	
	//节点 的内部类
	static class RBNode<K extends Comparable<K>, V> {
		private RBNode parent;
		private RBNode left;
		private RBNode right;
		private boolean color;
		private K key;
		private V value;

		/**
		 * 内部类无参构造和有参构造
		 */
		public RBNode() {

		}

		public RBNode(RBNode parent, RBNode left, RBNode right, boolean color, K key, V value) {
			super();
			this.parent = parent;
			this.left = left;
			this.right = right;
			this.color = color;
			this.key = key;
			this.value = value;
		}

			
		
		public RBNode getParent() {
			return parent;
		}

		public void setParent(RBNode parent) {
			this.parent = parent;
		}

		public RBNode getLeft() {
			return left;
		}

		public void setLeft(RBNode left) {
			this.left = left;
		}

		public RBNode getRight() {
			return right;
		}

		public void setRight(RBNode right) {
			this.right = right;
		}

		public boolean isColor() {
			return color;
		}

		public void setColor(boolean color) {
			this.color = color;
		}

		public K getKey() {
			return key;
		}

		public void setKey(K key) {
			this.key = key;
		}

		public V getValue() {
			return value;
		}

		public void setValue(V value) {
			this.value = value;
		}

		@Override
		public String toString() {
			return value.toString();
		}
	}

	private RBNode root;
	private int size;

	/**
	 * 初始化红黑树
	 * 
	 * @param root
	 * @param size
	 */
	public RBTree() {
		this.root = null;
		this.size = 0;
	}
	
	
	//辅助方法
	/**
	 * 返回节点的父节点
	 * 
	 * @param node
	 * @return
	 */
	private RBNode parentof(RBNode node) {
		if (node != null && node != root) {
			return node.parent;
		}
		return null;
	}

	/**
	 * 判断节点是否为红色
	 * 
	 * @param node
	 * @return
	 */
	private boolean isRed(RBNode node) {
		if (node != null) {
			return node.color == RED;
		}
		return false;
	}

	/**
	 * 判断节点是否为黑色
	 * 
	 * @param node
	 * @return
	 */
	private boolean isBlack(RBNode node) {
		if (node != null) {
			return node.color == BLACK;
		}
		return false;
	}

	/**
	 * 设置节点为红色
	 * 
	 * @param node
	 */
	private void setRed(RBNode node) {
		if (node != null) {
			node.color = RED;
		}
	}

	/**
	 * 设置节点为黑色
	 * 
	 * @param node
	 */
	private void setBlack(RBNode node) {
		if (node != null) {
			node.color = BLACK;
		}
	}

	/**
	 * 左旋
	 */
	private void leftRotate(RBNode x) {
		RBNode y = x.right;

		x.right = y.left;
		if (y.left != null) {
			y.left.parent = x;
		}

		if (x.parent != null) {
			y.parent = x.parent;

			if (x == x.parent.left) {
				x.parent.left = y;
			} else {
				x.parent.right = y;
			}
		}else {
			this.root = y;
			this.root.parent =null;
		}

		x.parent = y;
		y.left = x;
	}

	/**
	 * 右旋
	 * @param y
	 */
	private void rightRotate(RBNode y){
		RBNode x =y.left;
		y.left =x.right;
		
		if (x.right !=null) {
			x.right.parent =y;
		}
		
		if (y.parent !=null) {
			x.parent =y.parent;
			
			if (y==y.parent.left) {
				y.parent.left =x;
			}else{
				y.parent.right = x;
			}
		}else {
			this.root=x;
			this.root.parent =null;
		}
		
		y.parent =x;
		x.right=y;
	}
	
	
	/**
	 * 中序遍历
	 */
	public void inOrderprint() {
		inOrderprint(this.root);
	}

	private void inOrderprint(RBNode node) {
		if (node != null) {
			inOrderprint(node.left);
			System.out.println("Key:" + node.key + "......value:" + node.value + "...color:" + node.color);
			inOrderprint(node.right);
		}
	}
	
	
	/**
	 * 插入
	 */
	public void insert(K key,V value){
		RBNode node =new RBNode();
		node.setKey(key);
		node.setValue(value);
		node.setColor(true);
		insert(node);
	}
	
	private void insert(RBNode node){
		RBNode partent =null;
		RBNode x=this.root;
		
		while(x != null){
			partent = x;
			int cmp =node.key.compareTo(x.key);
			if (cmp>0) {
				x=x.right;
			}else if (cmp < 0) {
				x=x.left;
			}else {
				x.setValue(node.getValue());
				return;
			}
		}
		node.parent=partent;
		
		
		if (partent != null) {
			int cmp=node.key.compareTo(partent.key);
			if (cmp>0) {
				partent.right=node;
			}else{
				partent.left=node;
			}
		}else {
			this.root=node;
		}
		 
		size++;
		//修复红黑树平衡的方法
		insertFixUp(node);
	}
	
	private void insertFixUp(RBNode node){
		this.root.setColor(BLACK);
		
		RBNode parent =parentof(node);
		RBNode gparent=parentof(parent);
		
		//插入结点的父节点为红色
		if (parent != null && isRed(parent)) {
			//如果父节点时红色  那么一定存在爷爷节点。
			//定义一个叔叔节点
			RBNode uncle = null;
			
			//父节点是爷爷节点的左孩子
			if (parent == gparent.left) {
				uncle = gparent.right;
				
//				叔叔节点存在,并且为红色(叔-父双红)
				if(uncle !=null  && isRed(uncle)){
					setBlack(parent);
					setBlack(uncle);
					setRed(gparent);
					insertFixUp(gparent);
					return;
				}
				
//				叔叔节点不存在或为黑色
				if (uncle == null || isBlack(uncle)) {
//					LL双红   父节点变黑   爷爷节点变红   以爷爷节点右旋
					if(node == parent.left){
						setBlack(parent);
						setRed(gparent);
						rightRotate(gparent);
						return;
					}
					
					//插入节点是左孩子  则先父节点左旋变为 LL双红   再以父节点进行处理
					if (node == parent.right) {
						leftRotate(parent);
						insertFixUp(parent);
						return;
					}
				}
				
			}else {
//				父节点是爷爷节点的右孩子
				uncle =gparent.left;
				
//				护树节点存在,并且为红色、
				if (uncle != null && isRed(uncle)) {
//					父节点和叔叔节点变黑  爷爷节点变红  再处理
					setBlack(uncle);
					setBlack(parent);
					setRed(gparent);
					insertFixUp(gparent);
					return;
				}
				
//				叔叔节点不存在或者为黑色
				if (uncle == null || isBlack(uncle)) {
					//插入节点是父节点的右孩子  父节点变黑 爷节点变红 左旋
					if (node == parent.right) {
						setBlack(parent);
						setRed(gparent);
						leftRotate(gparent);
						return;
					}
					
					//插入节点是父节点的左孩子
					//先右旋  得到RR双红    父节点做处理
					if (node == parent.left) {
						rightRotate(parent);
						insertFixUp(parent);
						return;
					}			
				}				
			}
			
		}
	}
	
	
	/**
	 * (递归实现)查找"红黑树x"中键值为key的节点
	 */
	public RBNode search(K key) {
		return search(root, key);
	}
	
	private RBNode search(RBNode x, K key) {
		if (x == null) {
			return x;
		}

		int cmp = x.key.compareTo(key);
		if (cmp < 0) {
			return search(x.left, key);
		} else if (cmp > 0) {
			return search(x.right, key);
		} else {
			return x;
		}
	}


}

package RBTREE;
public class test {
	private static final int[] a = {10, 40, 30, 60, 90, 70, 20, 50, 80, 75,88,87,98,23,44,55,66,77,1,2,3,4,35,36,33,32,31,89,81,82,83,84,85,86,79};
	private static final boolean mDebugInsert = false;    // "插入"动作的检测开关(false,关闭;true,打开)
	private static final boolean mDebugDelete = false;    // "删除"动作的检测开关(false,关闭;true,打开)

	public static void main(String[] args) {
		int i, ilen = a.length;
		RBTree<Integer,Integer> tree = new RBTree<>();

		System.out.printf("== 原始数据: ");
		for (i = 0; i < ilen; i++) {
			System.out.printf("%d ", a[i]);
		}
		System.out.printf("\n");

		for (i = 0; i < ilen; i++) {
			tree.insert(a[i], i+1);
			// 设置mDebugInsert=true,测试"添加函数"
			if (mDebugInsert) {
				System.out.printf("== 添加节点: %d\n", a[i]);
				System.out.printf("== 树的详细信息: \n");
//				S
				System.out.printf("\n");
			}
		}
		
		System.out.printf("\n== 中序遍历: ");
		tree.inOrderprint();

		

	
	}
}

问题

  1. 为什么再hashmap中要用红黑树,而不是二分搜索树或咋是AVL平衡树
    时间复杂度:

二分搜索树 : logn 当插入序列有序时 时间复杂度为n
AVL平衡树 :long 但是没插入一个树都会改变树形结构 频繁改变会对系统 资源造成浪费
红黑树:由性质:红节点的子节点必须为黑节点 与性质:任意节点的值到叶子节点的黑节点数相等
可知不看红节点,红黑树是一颗完美AVL平衡树。时间复杂度为logn。
而高度差最大相差1倍 故而红黑树的时间复杂度为2logn。(logn)
红黑树容差率更大,更加节省系统资源,故而使用的是红黑树,而不是二分搜索树或AVL平衡树

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值