/smoothie-fruit-beverage-drink-161600.jpeg)
插入元素
插入元素,如果元素在树中存在,则替换value;如果元素不存在,则插入到对应的位置,再平衡树。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
   | public V put(K key, V value) {     Entry<K,V> t = root;     if (t == null) {                  compare(key, key);          root = new Entry<>(key, value, null);         size = 1;         modCount++;         return null;     }          int cmp;          Entry<K,V> parent;          Comparator<? super K> cpr = comparator;     if (cpr != null) {                           do {             parent = t;             cmp = cpr.compare(key, t.key);             if (cmp < 0)                                  t = t.left;             else if (cmp > 0)                                  t = t.right;             else                                  return t.setValue(value);         } while (t != null);     }     else {                  if (key == null)             throw new NullPointerException();         @SuppressWarnings("unchecked")         Comparable<? super K> k = (Comparable<? super K>) 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);     }          Entry<K,V> e = new Entry<>(key, value, parent);     if (cmp < 0)                  parent.left = e;     else                  parent.right = e;
           fixAfterInsertion(e);          size++;          modCount++;          return null; }
  | 
 
插入再平衡
插入的元素默认都是红色,因为插入红色元素只违背了第4条特性,那么我们只要根据这个特性来平衡就容易多了。
根据不同的情况有以下几种处理方式:
插入的元素如果是根节点,则直接涂成黑色即可,不用平衡;
 
插入的元素的父节点如果为黑色,不需要平衡;
 
插入的元素的父节点如果为红色,则违背了特性4,需要平衡,平衡时又分成下面三种情况:
 
(如果父节点是祖父节点的左节点)
| 情况 | 
策略 | 
| 1)父节点为红色,叔叔节点也为红色 | 
(1)将父节点设为黑色; (2)将叔叔节点设为黑色; (3)将祖父节点设为红色; (4)将祖父节点设为新的当前节点,进入下一次循环判断; | 
| 2)父节点为红色,叔叔节点为黑色,且当前节点是其父节点的右节点 | 
(1)将父节点作为新的当前节点; (2)以新当节点为支点进行左旋,进入情况3); | 
| 3)父节点为红色,叔叔节点为黑色,且当前节点是其父节点的左节点 | 
(1)将父节点设为黑色; (2)将祖父节点设为红色; (3)以祖父节点为支点进行右旋,进入下一次循环判断; | 
(如果父节点是祖父节点的右节点,则正好与上面反过来)
| 情况 | 
策略 | 
| 1)父节点为红色,叔叔节点也为红色 | 
(1)将父节点设为黑色; (2)将叔叔节点设为黑色; (3)将祖父节点设为红色; (4)将祖父节点设为新的当前节点,进入下一次循环判断; | 
| 2)父节点为红色,叔叔节点为黑色,且当前节点是其父节点的左节点 | 
(1)将父节点作为新的当前节点; (2)以新当节点为支点进行右旋; | 
| 3)父节点为红色,叔叔节点为黑色,且当前节点是其父节点的右节点 | 
(1)将父节点设为黑色; (2)将祖父节点设为红色; (3)以祖父节点为支点进行左旋,进入下一次循环判断; | 
让我们来看看TreeMap中的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
   | 
 
 
 
 
 
 
  private void fixAfterInsertion(Entry<K,V> x) {          x.color = RED;
           while (x != null && x != root && x.parent.color == RED) {         if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {                                       Entry<K,V> y = rightOf(parentOf(parentOf(x)));             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 = parentOf(x);                                          rotateLeft(x);                 }                                                   setColor(parentOf(x), BLACK);                                  setColor(parentOf(parentOf(x)), RED);                                  rotateRight(parentOf(parentOf(x)));             }         } else {                                       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 = parentOf(parentOf(x));             } else {                                                   if (x == leftOf(parentOf(x))) {                                          x = parentOf(x);                                          rotateRight(x);                 }                                                   setColor(parentOf(x), BLACK);                                  setColor(parentOf(parentOf(x)), RED);                                  rotateLeft(parentOf(parentOf(x)));             }         }     }          root.color = BLACK; }
 
  | 
 
插入元素举例
我们依次向红黑树中插入 4、2、3 三个元素,来一起看看整个红黑树平衡的过程。
三个元素都插入完成后,符合父节点是祖父节点的左节点,叔叔节点为黑色,且当前节点是其父节点的右节点,即情况2)。
/treemap1.png)
情况2)需要做以下两步处理:
- 将父节点作为新的当前节点;
 
- 以新当节点为支点进行左旋,进入情况3);
 
/treemap2.png)
情况3)需要做以下三步处理:
- 将父节点设为黑色;
 
- 将祖父节点设为红色;
 
- 以祖父节点为支点进行右旋,进入下一次循环判断;
 
/treemap3.png)
下一次循环不符合父节点为红色了,退出循环,插入再平衡完成。