手写Java红黑树

本文详细介绍了红黑树的基本特征、颜色变换规则和旋转操作,包括左旋和变色的实例。通过纯手写代码展示了红黑树的插入节点及平衡修复过程,并探讨了红黑树在查询最大值时的高效性,强调了其在大数据查找中的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

红黑树

1.红黑树基本的特征介绍

基本特征:

  1. 每个节点不是红色就是黑色
  2. 不允许两红相连
  3. 根节点都是黑色
  4. 每个红色节点的两个子节点都是黑色
  5. 默认情况下添加的节点为红色节点
    备注:如果产生了红色相连如何解决:变色或者旋转。

红黑树平衡规则:
1.改变节点颜色
2.左旋转
3.右旋转

2.红黑树变换颜色的规则要求

变色或者旋转都是插入节点后修复平衡的实现。

变色:当前节点父亲是红色,叔叔节点(祖父节点的另一个子节点)也是红色:
1.将父亲节点设置为黑色
2.将叔叔节点设为黑色
3.将祖父也就是父亲的父亲设为红色
4.把指针定义到祖父节点设为当前操作

左旋转:当父亲节点为红色情况,叔叔的节点为黑色的情况,且当前的节点是右子树,左旋转以父节点作为左旋;

左旋后祖父节点变为红色,父亲节点变成黑色

右旋转:当父亲节点为红色情况,叔叔的节点为黑色的情况,且当前的节点是左子树,右旋转以

  1. 父节点作为右旋;
  2. 将父节点变为黑色
  3. 将祖父节点变为红色(爷爷)
  4. 以祖父节点开始旋转

3.红黑树左右旋转基本的规则

image-20211211152541846

image-20211213161810774

4.纯手写红黑树左旋转和变色

/**
 * 
 */
package com.chenyun.tree;


/**
 * @author: 陈云
 * @date: 2021年12月13日
 * @description: 
 */
public class RedBlackTree {
	class Node {
		/**
		 * 节点内容值
		 */
		private int value;

		/**
		 * 节点颜色
		 */
		private String color;

		/**
		 * 左子树
		 */
		private Node left;

		/**
		 * 右子树
		 */
		private Node right;

		/**
		 * 记录当前节点父节点
		 */
		private Node parent;

		public Node(int value, String color, Node left, Node right, Node parent) {
			super();
			this.value = value;
			this.color = color;
			this.left = left;
			this.right = right;
			this.parent = parent;
		}

		public Node() {
			super();
		}

		@Override
		public String toString() {
			return "Node [value=" + value + ", color=" + color + ", left=" + left + ", right=" + right + ", parent="
					+ parent + "]";
		}	
	}
	
	//记录根节点
	private Node root;
	
	/**
	 * 添加节点
	 * @param value
	 * @return
	 */
	public Node add(int value) {
		//当根节点为null时,新插入的节点就是跟节点
		if(root == null) {
			Node node = new Node(value, "black", null, null, null);
			root = node;
			return node;
		}else {
			//当根节点不为空时,从根节点开始,搜索二叉树,得到新节点要插入的位置,并插入新节点
			Node node = getPosition(root, value);
			//红黑树修复
			repairTree(node);
			return node;
		}
	}
	
	/**
	 * 红黑树修复
	 * @param node
	 */
	private void repairTree(Node node) {
		//如果父节点为红色,当前节点默认红色,两红相连,变色或者旋转
		if(node.parent.color.equals("red") && node.color.equals("red")) {
			//父节点
			Node p = node.parent;
			Node g = node.parent.parent;
			//如果叔叔节点和父亲节点都为红,变色操作:将父亲节点+叔叔节点改为黑,祖父节点改为红
			//假设当前为右子树,叔叔在左边
			if(g.left != null && g.left.color.equals("red")) {
				p.color = "black";
				g.left.color = "black";
				//如果祖父节点为根节点
				if(g == root) {
					g.color ="black";
				}else {
					g.color = "red";
				}
				return;
			}
			
			//否则旋转
			leftRotate(g);
			 //左旋后祖父节点变为红色,父亲节点变成黑色
            g.color = "red";
            p.color = "black";
		}	
	}
	
	/**
	 * 左旋
	 * @param x
	 */
	private void leftRotate(Node x) {
		//通过待翻下的x,获取待翻上的y
		Node y = x.right;
		//改变x和y.left的执行
		x.right = y.left;
		if(y.left != null) {
			y.left.parent = x;
		}
		//改变父节点指向
		y.parent = x.parent;
		if(x.parent == null) {
			// x为根节点,x翻下y翻上,y变为新根节点
	        root = y;
		}else {
			// 否则,判断x为左子树或者右子树,分别做不同的处理
	    	if (x.parent.left == x) {
	            // x为左子树,父节点的左子树变为y
	            x.parent.left = y;
	        } else {
	            x.parent.right = y;
	        }
		}
		
		// 更改x和y之间的指向关系
	    y.left = x;
	    x.parent = y;
	}
	
	
	/**
	 * 遍历二叉树,把新节点添加到二叉树的末尾
	 * @param node
	 * @param value
	 * @return
	 */
	private Node getPosition(Node node,int value) {
		if(value > node.value) {
			//插入右子树
			if(node.right == null) {
				Node newNode = new Node(value, "red", null, null, node);
				node.right = newNode;
				return newNode;
			}else {
				return getPosition(node.right, value);
			}
		}else {
			//插入左子树
			if(node.left == null) {
				Node newNode = new Node(value, "red", null, null, node);
				node.left = newNode;
				return newNode;
			}else {
				return getPosition(node.left, value);
			}
		}
	}
	
}

5.红黑树查询最大值

	
	/**
	 * 查询最大值
	 * @return
	 */
	public int getMax() {
		int maxValue = getMaxValue(root);
		return maxValue;
	}
	
	/**
	 * 递归查询最大值
	 * @param node
	 * @return
	 */
	private int getMaxValue(Node node) {
	    if (node != null) {
	        if (node.right != null) {
	            return getMaxValue(node.right);
	        } else {
	            return node.value;
	        }
	    }
	    return 0;
	}

红黑树查询时间复杂度o(log n)

如果当前有10亿数字,如何最快的查找到最大/小值?
使用红黑树/平衡二叉树,30次左右,2^30=10亿+

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值