2020-10-08目前代码只记录了插入过程和插入之后的恢复过程代码,删除过程代码还在整理.
package com.lsx.tree; public class RedBlackTree { //红色,默认用红色 private final int R = 0; //黑色 private final int B = 1; private Node root = null; // 红黑树的根节点 class Node { //存储数据 int data; //颜色 int color = R; //左 Node left; //右 Node right; //父节点 Node parent; public Node(int data) { this.data = data; } } /** * 插入数据 * * @param newNode */ public void inset(Node newNode) { Node r = this.root; //新节点的父节点 Node py = null; //定位新节点要插入到那个位置 while (r != null) { //存储找到了位置的父节点信息 py = r; if (r.data < newNode.data) { r = r.right; } else if (r.data > newNode.data) { r = r.left; } else { //节点值相等,替新出的节点替换掉老的节点,为啥:如果节点值是一个对象, // 如果使用ID来判断对象是否是同一个的时候,可能对象某个数据发生了变化。 if (r.parent == null) { this.root = newNode; } else { if (r.parent.left == r) { r.parent.left = newNode; } else { r.parent.right = newNode; } r = null; newNode.parent = r.parent; } return; } } newNode.parent = py; if (py != null) { if (py.data < newNode.data) { py.right = newNode; } else { py.left = newNode; } } //插入的新节点默认是红色。 //修正为一颗二叉查找树 insertFixUp(newNode); } /** * 修正为一颗红黑树,节点插入正确位置之后,需要把树进行整理 * 1.变色 * 2.看看要怎么旋转 * * @param newNode */ private void insertFixUp(Node newNode) { Node parent, gparent; //诺父节点存在,并且父节点的颜色都是红色. //如果父节点是黑色,则不用修正 while ((parent = newNode.parent) != null && isRed(parent)) { //获取祖父结点 gparent = parent.parent; //检查父节点是左子树还是右子树 if (gparent.left == parent) { //父节点是左子树 // Case 1条件:叔叔节点是红色 // 黑 // 红(p) 红(u) //红 Node uncle = gparent.right; //case 1 if (uncle != null && isRed(uncle)) { setBlack(uncle); setBlack(parent); setRead(gparent); newNode = gparent; continue; } //case 2 // 此时uncle是null或者颜色是黑色(null也是黑色),且当前插入节点是右孩子, //旋转成插入节点在父节点的左边,形成pg ->p->newnode都是在左边 if (parent.right == newNode) { leftRotate2(parent); Node tmp; //旋转完成之后,把newNode的引用改成parent tmp = parent; parent = newNode; newNode = tmp; } //case 2.1 //叔叔全是黑色,当前节点是左孩子,进行一下右旋 setRead(gparent); setBlack(parent); rightRotate2(gparent); //处理完这个之后,while会在isRed(parent)不成立而结束循环 } else { //右子树 // Case 1条件:叔叔节点是红色 // 黑 // 红(u) 红(p) //红 Node uncle = gparent.left; //caes 1 if (uncle != null && isRed(uncle)) { //变色 setBlack(uncle); setBlack(parent); setRead(gparent); newNode = gparent; continue; } //case 2 //此时uncle是null或者颜色是黑色(null也是黑色) //线程pg -p->newNode都是在右边 if (parent.left == newNode) { //旋转成插入节点在父节点的左边 rightRotate2(parent); Node tmp; //旋转完成之后,把newNode的引用改成parent tmp = parent; parent = newNode; newNode = tmp; } //case 2.1 setRead(gparent); setBlack(parent); rightRotate2(gparent); //处理完这个之后,while会在isRed(parent)不成立而结束循环 } } //这行代码处理的是树为空的时候,插入的第一个节点 setBlack(this.root); } /** * 单独写出来是方便后期如果01表示的含义不是红黑,好方便修改 * * @param node * @return */ private boolean isRed(Node node) { return node.color == R; } private void setRead(Node node) { node.color = R; } private void setBlack(Node node) { node.color = B; } /* * 对红黑树的节点(x)进行左旋转 * * 左旋示意图(对节点x进行左旋): * px px * / / * x y * / \ --(左旋)-. / \ # * lx y x ry * / \ / \ * ly ry lx ly * * */ public void leftRotate2(Node node) { //获取它的右边节点 Node y = node.right; //新数据,把y的左节点处理 node.right = y.left; if (y.left != null) { y.left.parent = node; } //处理node节点的父节点 if (node.parent.left == node) { //当前node节点是左边的 node.parent.left = y; } else if (node.parent.right == node) { //右边的 node.parent.right = y; } else { //如果父节点是空,就把新的根节点设置为树的根节点 root = y; } //处理y节点 y.left = node; node.parent = y; } /* * 对红黑树的节点(y)进行右旋转 * * 右旋示意图(对节点y进行左旋): * py py * / / * y x * / \ --(右旋)-. / \ * x ry lx y * / \ / \ * lx rx rx ry * */ public void rightRotate2(Node node) { Node x = node.left; node.left = x.right; if (x.right != null) { node.left.parent = node; } if (node.parent.left != null) { node.parent.left = x; } else if (node.parent.right != null) { node.parent.right = x; } else { root = x; } x.right = node; node.parent = x; } }
