TreeMap源码分析

TreeMap

属性

//比较器,用于比较判断存放数据与已存在节点的大小比较
private final Comparator<? super K> comparator;
//根节点(将存入的k-v对封装成Entry节点)
private transient Entry<K,V> root;
//已存入节点的数量
private transient int size = 0;
//操作的次数,将每次对节点的操作会进行自增,用于failfast(快速失败)的机制
private transient int modCount = 0;
//红色
private static final boolean RED   = false;
//黑色
private static final boolean BLACK = true;

构造方法

//无参构造  将其中的构造器置为null
    public TreeMap() {
        comparator = null;
    }
    //将自己的比较器设置给TreeMap
    public TreeMap(Comparator<? super K> comparator) {
        this.comparator = comparator;
    }

Put方法

 public V put(K key, V value) {
 	//将根节点赋值给局部变量t
     Entry<K,V> t = root;
    //当第一次存储时根节点root为null
      if (t == null) {
      //比较存储的key是否为null,如果为null底层会报NPE异常
          compare(key, key); // type (and possibly null) check
		//将传入的K-V对封装成一个Entry节点并赋值给root属性
          root = new Entry<>(key, value, null);
          //因为是只有第一次存储数据会进入所以size直接设置成了1
          size = 1;
          //修改次数直接进行自增
          modCount++;
          return null;
      }
      //用于存储比较器比较后返回的int值
      int cmp;
      //申明父节点的零时变量
      Entry<K,V> parent;
      // split comparator and comparable paths
      Comparator<? super K> cpr = comparator;
      //当比较器不为空时
      if (cpr != null) {
      	//下面的循环是为了循环查找到传入的K-V对因该处于树的什么位置
          do {
          	//第一次进入循环时,t为上面的根节点
              parent = t;
              //将根节点和传入的key进行比较
              cmp = cpr.compare(key, t.key);
              //如果传入的key比根节点小,则将根节点的左子节点赋值给零时变量t
              if (cmp < 0)
                  t = t.left;
                  //相反如果传入的key比t节点要大则将t的右子节点赋值给t变量
              else if (cmp > 0)
                  t = t.right;
              else
              //如果传入的key和t变量相等那么直接进行value值的替换就可以了
                  return t.setValue(value);
          } while (t != null);
      }
      else {//代表比较器为null
          if (key == null)
              throw new NullPointerException();
          @SuppressWarnings("unchecked")
          //会使用出入的key的比较器
              Comparable<? super K> k = (Comparable<? super K>) key;
              //下面的循环和上面的循环一样也是为了找到传入的key在树中的位置
          do {
              parent = t;
              cmp = k.compareTo(t.key);
              if (cmp < 0)
                  t = t.left;
              else if (cmp > 0)
                  t = t.right;
              else
                  return t.setValue(value);
          } while (t != null);
      }
      //将传入的key-value和上面个的parent父节点封装成一个Entry节点
      Entry<K,V> e = new Entry<>(key, value, parent);
      //如果比较的结果小于0则新的Entry对象会存放在父节点的左子节点
      if (cmp < 0)
          parent.left = e;
      else
      //如果比较的结果大于0则新的Entry对象会存放在父节点的右子节点
          parent.right = e;
      //将以存储的数据进行颜色的变更和旋转来达到红黑树的自平衡效果
      fixAfterInsertion(e);
      //树中的元素个数会进行自增
      size++;
      //变动次数会进行新增
      modCount++;
      return null;
    }

红黑树新增节点的几种情况:

  1. 当root节点不存在时,直接新增并且将root节点设置为黑色
  2. 插入节点的父节点为黑色时,则直接插入并将自身设置为红色节点
  3. 插入节点的父节点为红色时:
    3.1 叔叔节点存在且为红色时,那么将父节点和叔叔节点变成黑色节点,然后将祖父节点变成红色,然后将祖父节点赋值给插入节点,递归此步骤进行颜色的变更。
    3.2叔叔节点不存在或者为黑色时:
      3.2.1 父节点时祖父节点的左节点时:
        3.2.1.1 插入节点是父节点的左子节点,将父节点设置为黑色,将祖父节点设置为红色。
        3.2.1.2插入节点是父节点的右子节点,将父节点进行左旋,然后将父节点设置为插入节点执行3.2.1.1的操作。
      3.2.2 父节点是祖父节点的右子节点:
        3.2.2.1插入节点为父节点的右子节点。则将父节点设置为黑色将祖父节点设置为红色,对祖父节点进行左旋
        3.2.2.2插入节点为父节点的左子节点,则将父节点进行右旋,将父节点设置为插入节点然后执行3.2.2.1的操作

fixAfterInsertion方法

 private void fixAfterInsertion(Entry<K,V> x) {
 	//将新增的节点设置为红色节点
     x.color = RED;
 	//当新增节点不为空并且新增节点不是root节点并且新增节点的父节点是红色节点时
     while (x != null && x != root && x.parent.color == RED) {
     //如果新增节点的父节点是祖父节点的左子节点
         if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
         //将祖父节点的右子节点即为叔叔节点赋值给局部变量y
             Entry<K,V> y = rightOf(parentOf(parentOf(x)));
             //如果叔叔节点为红色,则满足3.1的插入规则
             if (colorOf(y) == RED) {
             //设置父节点为黑色
                 setColor(parentOf(x), BLACK);
                 //设置叔叔节点为黑色
                 setColor(y, BLACK);
                 //设置祖父节点为红色
                 setColor(parentOf(parentOf(x)), RED);
                 //将祖父节点设置给插入节点然后进行迭代操作
                 x = parentOf(parentOf(x));
             } else {
             //插入节点的父节点的右子节点是否存在
                 if (x == rightOf(parentOf(x))) {
                 //将父节点赋值给x变量
                     x = parentOf(x);
                     //进行左旋
                     rotateLeft(x);
                 }
                 //将父节点设置为黑色
                 setColor(parentOf(x), BLACK);
                 //将祖父节点设置为红色
                 setColor(parentOf(parentOf(x)), RED);
                 //将祖父节点进行右旋
                 rotateRight(parentOf(parentOf(x)));
             }
         } else {
         //将祖父节点赋值给变量y
             Entry<K,V> y = leftOf(parentOf(parentOf(x)));
             //祖父节点为红色
             if (colorOf(y) == RED) {
             //将父节点设置为黑色
                 setColor(parentOf(x), BLACK);
                 //将祖父节点设置为黑色
                 setColor(y, BLACK);
                 //将祖父节点设置为红色
                 setColor(parentOf(parentOf(x)), RED);
                 //将祖父节点赋值给变量x
                 x = parentOf(parentOf(x));
             } else {
             //判断父节点的左节点是否存在
                 if (x == leftOf(parentOf(x))) {
                 //父节点赋值给x变量
                     x = parentOf(x);
                     //父节点进行右旋
                     rotateRight(x);
                 }
                 //将父节点设置为黑色
                 setColor(parentOf(x), BLACK);
                 //将祖父节点设置为红色
                 setColor(parentOf(parentOf(x)), RED);
                 //将祖父节点进行左旋
                 rotateLeft(parentOf(parentOf(x)));
             }
         }
     }
     root.color = BLACK;
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值