GSON源碼LinkedTreeMap學習


  在學習GSON的過程中,發現了GSON的基礎數據類型LinkedTreeMap,因此展開學習。

 private final LinkedTreeMap<String, JsonElement> members =
      new LinkedTreeMap<String, JsonElement>();

  LinkedTreeMap,一切如此的熟悉,在jdk中有LinkedMap有TreeMap有TreeMap,這個LinkedTreeMap是個什么,顧名思義,這應該是一個連續的且有序的集合。

package com.google.gson.internal;

  一看包名,這是google自己實現的map。

    Node<K, V> parent;
    Node<K, V> left;
    Node<K, V> right;
    Node<K, V> next;
    Node<K, V> prev;
    final K key;
    V value;
    int height;

  咋一看,這是啥啊。一個結點包含了父節點,左右結點和前后結點,但是不要慌我們接着往下看。

  接着回到LinkedTreeMap,在類的最開時定義了一個比較器NATURAL_ORDER

  private static final Comparator<Comparable> NATURAL_ORDER = new Comparator<Comparable>() {
    public int compare(Comparable a, Comparable b) {
      return a.compareTo(b);
    }
  };

  這個比較器在構造LinkHashMap時傳入,如果傳入的比較器是空(該類沒有實現Comparator)則使用NATURAL_ORDER 比較器進行比較,此處略微介紹Comparator和Comparable的區別,實現Comparable 接口的類即支持排序(因為實現了CompareTo)方法,而如果一個類不支持排序(沒有實現Compareable接口)則可以使用Comparator比較器來實現比較方法。

  為什么要先介紹這個比較器呢,因為在LinkTreeMap進行新增結點和查找結點都需要使用到這個比較器,在find()方法里,首先判斷根節點是否為空。

Node<K, V> find(K key, boolean create) {
    Node<K, V> nearest = root;
    if (nearest != null) {
          Comparable<Object> comparableKey = (comparator == NATURAL_ORDER)
          ? (Comparable<Object>) key
          : null;

  當根節點不為空時,判斷比較器是否為LinkTreeMap自定義的比較器,如果是則使用K類的比較器,否則傳null。此處的null主要是標志作用,決定之后使用Compare方法還是使用compareTo方法。

   while (true) {
        comparison = (comparableKey != null)
            ? comparableKey.compareTo(nearest.key)
            : comparator.compare(key, nearest.key);

        // We found the requested key.
        if (comparison == 0) {
          return nearest;
        }

        // If it exists, the key is in a subtree. Go deeper.
        Node<K, V> child = (comparison < 0) ? nearest.left : nearest.right;
        if (child == null) {
          break;
        }

        nearest = child;
      }

  在這循環中根據返回值判斷要尋找的結點可能存在的位置,當值比比較的結點小時在他的左子樹上繼續查找,反之查詢右子樹直到找到或者當前對象為空。

  緊接着,如果create為false則結束find方法,此時nearest就是要查找的值或者根節點。

  如果create為true則創建結點,且nearest為null,nearest為null只有一種情況:當前樹是一個空樹

     created = new Node<K, V>(nearest, key, header, header.prev);
     root = created;

  new Node干的事

    /** Create a regular entry */
    Node(Node<K, V> parent, K key, Node<K, V> next, Node<K, V> prev) {
      this.parent = parent;
      this.key = key;
      this.height = 1;
      this.next = next;
      this.prev = prev;
      prev.next = this;
      next.prev = this;
    }

  當樹不是空樹時則根據最后一次比較的結果進行插入。

else {
      created = new Node<K, V>(nearest, key, header, header.prev);
      if (comparison < 0) { // nearest.key is higher
        nearest.left = created;
      } else { // comparison > 0, nearest.key is lower
        nearest.right = created;
      }
      rebalance(nearest, true);
 }

  進行調整。

  private void rebalance(Node<K, V> unbalanced, boolean insert) {
    for (Node<K, V> node = unbalanced; node != null; node = node.parent) {

  進入方法后就開始遍歷結點,遍歷規則是當結點父節點不為空時,無限循環。

      Node<K, V> left = node.left;
      Node<K, V> right = node.right;
      int leftHeight = left != null ? left.height : 0;
      int rightHeight = right != null ? right.height : 0;

      int delta = leftHeight - rightHeight;

  保存結點的左右結點以及高度,並計算高度差。

if (delta == -2) {
        Node<K, V> rightLeft = right.left;
        Node<K, V> rightRight = right.right;
        int rightRightHeight = rightRight != null ? rightRight.height : 0;
        int rightLeftHeight = rightLeft != null ? rightLeft.height : 0;

        int rightDelta = rightLeftHeight - rightRightHeight;
        if (rightDelta == -1 || (rightDelta == 0 && !insert)) {
          rotateLeft(node); // AVL right right
        } else {
          assert (rightDelta == 1);
          rotateRight(right); // AVL right left
          rotateLeft(node);
        }
        if (insert) {
          break; // no further rotations will be necessary
        }

}

  當左節點比右結點低2時,保存右左結點,右右結點,右左結點高度,右右結點高度,並計算高度差。當高度等於1或等於0時進行左旋。當高度差為1是進行右結點右旋,根節點左旋。

  當右節點比左結點低2時,反之。

  當高度差為0時,修改節點高度。

else if (delta == 0) {
        node.height = leftHeight + 1; // leftHeight == rightHeight
        if (insert) {
          break; // the insert caused balance, so rebalancing is done!
        }
}

  當左右節點差為1時,設置高度為左右結點高度更高者加一。以高度差作為約束,約束左右結點高度差不高於2,當等於2時根據左右高度差進行旋轉,最終的存儲結構是一個有插入順序的鏈表和排序二叉樹

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM