版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mottohlm/article/details/81604507
为什么说是残疾版呢,因为标准的红黑树是是三个值在一层,也就是父节点的左右分支节点都可以是红,但在此,我规定了只有左分支为红,也就是规定了最多只有两个值在一层。这样能减少很多修复平衡判断条件。在此我以实现简化版的treeMap 为例。
新增节点的第一步就是找出节点将要加入的位置,然后才修复平衡。
节点类的定义:
package hlm.com.treemap;
/**
* 节点:
* value 存值
* left 左子节点
* right 右子节点
* father 父节点(父节点为空,那表明该节点是根节点)
* color 颜色,
*/
public class Node {
private Object key ;
private Object value ;
private boolean color ;
private Node left ;
private Node right ;
private Node parent ;
public static final boolean BLANK = false ;
public static final boolean RED = true ;
public static final boolean LEFT = false ;
public static final boolean RIGHT = true ;
public Node() { }
public Node(Object key, Object value) {
this.key = key;
this.value = value;
this.color = BLANK ;
}
public Node(Object key, boolean color, Node left, Node right, Node parent) {
this.key = key;
this.color = color;
this.left = left;
this.right = right;
this.parent = parent;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public Node(Object key) {
this.key = key;
}
public Object getKey() {
return key;
}
public void setKey(Object key) {
this.key = key;
}
public boolean getColor() {
return color;
}
public void setColor(boolean color) {
this.color = color;
}
public Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
public Node getParent() {
return parent;
}
public void setParent(Node parent) {
this.parent = parent;
}
@Override
public String toString(){
return "k:"+ this.key+";v:"+this.value;
}
}
TreeMap 类的其他信息
public class MyTreeMap {
Logger log = LoggerFactory.getLogger(MyTreeMap.class) ;
/*** 根节点*/
private Node root ;
/*** 元素个数*/
private transient int size ;
}
入口 put 方法
/**
* 添加k-v方法
* @param k
* @param v
* @return
*/
public Object put(Object k ,Object v){
Node node = new Node(k , v);
//没有根那么传进来的就是根
if(root == null){
root = node ;
size ++ ;
return root.getKey();
}
return addRedBlankNode(root , node);
}
扫描二维码关注公众号,回复:
2947567 查看本文章
插入节点方法 addRedBlankNode
/**
* 按红黑树的方式添加节点
* @param root
* @param node
* @return
*/
private Object addRedBlankNode(Node root ,Node node){
//起点不存在,那么返回null
if(root == null ){
return null ;
}
//插入节点为空,那无法插入
if(node == null ){
return null ;
}
Object targetKey = node.getKey();
int tarint = hash(targetKey);
Object rootKey = root.getKey();
int rootint = hash(rootKey);
//相等,刚覆盖更新
if(tarint == rootint){
root.setValue(node.getValue());
return node.getValue();
}
//小于,左分支
if(tarint < rootint){
//存在左子节点时,递归检索进去
if(root.getLeft() != null){
return addRedBlankNode(root.getLeft() , node);
}else{
root.setLeft(node);
node.setParent(root);
}
}
//大于,右分支(由于只构建2-3树,所以添加右分支)
if(tarint > rootint){
//存在右子节点时,递归检索进去
if(root.getRight() != null){
return addRedBlankNode(root.getRight() , node);
}else{
root.setRight(node);
node.setParent(root);
}
}
//修复平衡
fixBalance(node);
size ++ ;
return node.getKey();
}
插入节点其实很简单,一路判断下去直到有位置即可
最后是修复平衡方法 fixBalance 。这个才是主角。
/**
* 调整树结构及按需重新着色
* @param node
*/
private void fixBalance(Node node){
//第一种情况,到顶了,node就是根了,那么要考虑把node的颜色变黑,
if(node.getParent() == null){
node.setColor(Node.BLANK);
}
//左支
else if(Node.LEFT == checkLR(node,node.getParent())){
//父节点为黑时,如果无左子节点或左子节点为黑,直接颜色置为红
if(Node.BLANK == node.getParent().getColor() && (
(node.getLeft() !=null && node.getLeft().getColor()==Node.BLANK)
||node.getLeft() == null)){
node.setColor(Node.RED);
}
//父节点为黑时,但其左子节点为红,由于不能连续两红
else if(Node.BLANK == node.getParent().getColor() &&
node.getLeft() !=null && node.getLeft().getColor()==Node.RED ){
node.getLeft().setColor(Node.BLANK);
turnRight(node);
fixBalance(node);
}
//父节点为红时,其祖父节点是一定存在的
//此时父节点那一层肯定是满的,只有进行变换了,看情况如何变换
else if(Node.RED == node.getParent().getColor()){
Node root = node.getParent();
root.setColor(Node.BLANK);
turnRight(root);
fixBalance(root);
}
}
//右支 (想办法变为左支)
else if(Node.RIGHT == checkLR(node,node.getParent())){
Node root = node.getParent();
if(node.getLeft()==null ||node.getLeft().getColor() == Node.BLANK){
if(root.getColor() == Node.RED){
turnLeft(node);
fixBalance(node);
}else{
turnLeft(node);
fixBalance(root);
}
}
else{
node.getLeft().setColor(Node.BLANK);
turnRight(node.getLeft());
turnLeft(node.getLeft());
fixBalance(node.getLeft());
}
}
}