码迷,mamicode.com
首页 > 其他好文 > 详细

GSON源码LinkedTreeMap学习

时间:2019-07-24 00:12:05      阅读:104      评论:0      收藏:0      [点我收藏+]

标签:需要   str   new   包含   实现   value   sub   regular   while   

  在学习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时,设置高度为左右结点高度更高者加一。

GSON源码LinkedTreeMap学习

标签:需要   str   new   包含   实现   value   sub   regular   while   

原文地址:https://www.cnblogs.com/yi-zeng/p/11217600.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!