• HashMap 数据结构分析


    测试代码

    public class App {
        public static void main(String[] args) {
            System.out.println("123");
            Map<Object, Object> hashMap = new HashMap<>(4);
    
            for (int i = 0; i < 64; i++) {
                hashMap.put(i, i);
            }
    
            for (int i = 0; i < 9; i++) {
                hashMap.put(new User(), i);
            }
    
    
            hashMap.get("hi");
        }
    
        private static class User {
            private int hash;
            @Override
            public int hashCode() {
                hash = 123;
                return 123;
            }
        }
    
    }
    

    数据结构分析

    HashMap{
      // 数组,若没有给定初始值,第一次 put 时才会初始化,
      /**
       	 resize() {
    	   int oldThr = threshold;
    	   ...
    	   // 给初始化容量大小
    	   else if (oldThr > 0) 
         	newCap = oldThr;
         // 不给则默认为 16 DEFAULT_INITIAL_CAPACITY = 1 << 4;
         else {          
                newCap = DEFAULT_INITIAL_CAPACITY;
                newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
         }
         ...
    		 Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
       }
       **/
      transient Node<K,V>[] table;
    	// 单向链表
      Node.next
    }
    

    逻辑分析

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                       boolean evict) {
            Node<K,V>[] tab; Node<K,V> p; int n, i;
            if ((tab = table) == null || (n = tab.length) == 0)
              // 扩容
                n = (tab = resize()).length;
            if ((p = tab[i = (n - 1) & hash]) == null)
                tab[i] = newNode(hash, key, value, null);
            else {
                Node<K,V> e; K k;
              // hash 相等 Key 相等则覆盖
                if (p.hash == hash &&
                    ((k = p.key) == key || (key != null && key.equals(k))))
                    e = p;
              // 变红黑树之后,即在 treeifyBin(tab, hash) 方法中的                TreeNode<K,V> p = replacementTreeNode(e, null); 执行之后;
                else if (p instanceof TreeNode)
                    e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
              // hash 冲突
                else {
                  // 某个键出现 hash 冲突时,会使用(Node.next属性)进行链接(链表)。当长度 >=8 ,并且数组长度大于 MIN_TREEIFY_CAPACITY = 64时,此时链表转为红黑树,即 treeifyBin 方法中的replacementTreeNode();
                    for (int binCount = 0; ; ++binCount) {
                        if ((e = p.next) == null) {
                            p.next = newNode(hash, key, value, null);
                            if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                                treeifyBin(tab, hash);
                            break;
                        }
                        if (e.hash == hash &&
                            ((k = e.key) == key || (key != null && key.equals(k))))
                            break;
                        p = e;
                    }
                }
                if (e != null) { // existing mapping for key
                    V oldValue = e.value;
                    if (!onlyIfAbsent || oldValue == null)
                        e.value = value;
                    afterNodeAccess(e);
                    return oldValue;
                }
            }
            ++modCount;
            if (++size > threshold)
                resize();
            afterNodeInsertion(evict);
            return null;
        }
    =========================函数分割线=========================
    final void treeifyBin(Node<K,V>[] tab, int hash) {
            int n, index; Node<K,V> e;
      // 
            if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
                resize();
            else if ((e = tab[index = (n - 1) & hash]) != null) {
                TreeNode<K,V> hd = null, tl = null;
                do {
                    TreeNode<K,V> p = replacementTreeNode(e, null);
                    if (tl == null)
                        hd = p;
                    else {
                        p.prev = tl;
                        tl.next = p;
                    }
                    tl = p;
                } while ((e = e.next) != null);
                if ((tab[index] = hd) != null)
                    hd.treeify(tab);
            }
        }
    

    红黑树成果图

    image-20210918081913571

    验证

    链表超过8个,但是元素不足64,不会使用红黑树

    image-20210918082318302

    只会 resize
    image-20210918082408875

    preserve order

    image-20210918082752692

    换了个位置
    image-20210918082947204

    image-20210918083217414

  • 相关阅读:
    AOJ 718.计算GPA
    AOJ 11.Rails
    AOJ 592.神奇的叶子
    AOJ 10.目标柏林
    洛谷P1030求先序排列
    vijos1514天才的记忆
    洛谷2016战略游戏
    LOJ10155数字转换
    洛谷2014选课
    洛谷2015二叉苹果树
  • 原文地址:https://www.cnblogs.com/sethxiong/p/15329882.html
Copyright © 2020-2023  润新知