面試題: Java中各個集合類的擴容機制


個人博客網:https://wushaopei.github.io/    (你想要這里多有)

Java 中提供了很多的集合類,包括,collection的子接口list、set,以及map等。由於它們的底層構成不同,以及數據的構造為單列、多列、可重復、不可重復,導致其擴容機制也不盡相同。

一、List

獲取ArrayList 容量大小的方法:

    public static int getArrayListCapacity(ArrayList<?> arrayList) { Class<ArrayList> arrayListClass = ArrayList.class; try { Field field = arrayListClass.getDeclaredField("elementData"); field.setAccessible(true); Object[] objects = (Object[])field.get(arrayList); return objects.length; } catch (NoSuchFieldException e) { e.printStackTrace(); return -1; } catch (IllegalAccessException e) { e.printStackTrace(); return -1; } }

1、ArrayList

ArrayList以數組的形式存儲。ArrayList中與容量有關的構造器有兩個,代碼如下:

    public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } /** * Constructs an empty list with an initial capacity of ten. */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }

由以上代碼可知,ArrayList 的容量擴容包含有 ArrayList(int initialCapacity) ,另一個則是 ArrayList() ;

第一個構造器在初始創建時以形參將容量大小進行定義,由外部自定義;第二個構造器沒有傳入參數,使用默認初始化的容量大小;詳細解析如下:

第一個有參構造器:自定長度在后面,這里先看無參有默認容量長度的構造器怎么實現的擴容?

第二個無參構造器:

    /** * Constructs an empty list with an initial capacity of ten. */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }

代碼測試:

@Test public void catapicity(){ ArrayList<Object> objects = new ArrayList<>(); objects.add("a"); objects.add("b"); objects.add("c"); System.out.println(objects.size() + " " + getArrayListCapacity(objects)); // 增加一個值 for (int i = 0 ; i < 9 ; i ++ ){ objects.add(i); } System.out.println(objects.size() + " " + getArrayListCapacity(objects)); // 增加一個值 for (int i = 10 ; i <15 ; i ++ ){ objects.add(i); } System.out.println(objects.size() + " " + getArrayListCapacity(objects)); // 增加一個值 for (int i = 15 ; i < 20 ; i ++ ){ objects.add(i); } System.out.println(objects.size() + " " + getArrayListCapacity(objects)); objects.add(20); System.out.println(objects.size() + " " + getArrayListCapacity(objects)); }

在上述單元測試中,創建了一個無參構造的ArrayList 集合,並對其進行元素的添加,以滿足對元素添加過程中容量大小的擴張規則。

長度:  3 容量: 10
長度:  12 容量: 15
長度:  17 容量: 22
長度:  22 容量: 22
2020-01-29 11:42:35.260  INFO 28488 --- [       Thread-2] o.s.w.c.s

上述是單元測試結果,在這里做一番分析:

在以上的代碼中,默認使用ArrayList的初始化容量長度,在ArrayList中,默認初始化容量是 10 ,

 /** * Default initial capacity. */ private static final int DEFAULT_CAPACITY = 10; 

從測試結果可以看到,當元素的長度為3時,其容量為默認的值 10 ; 當添加的元素超過初始容量后,即 12 > 10  時,集合進行了自動擴容,添加每一個元素都會調用  ensureCapacityInternal(int minCapacity)  方法,在該方法中比較長度是否達到當前容量的邊緣,將比較的結果 覆蓋原來的 minCapacity 參數,該值用於保存當前的容器元素長度;如單元測試中,當元素個數超過默認的 值 10 時,會調用

minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);

方法,並接着調用  ensureExplicitCapacity(minCapacity);方法,該方法會對當前集合長度與最大容量值進行比較,並調用 grow(minCapacity) 方法進行位移擴容:

private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); }

實現ArrayList 集合擴容的代碼如下:

   /** * Increases the capacity to ensure that it can hold at least the * number of elements specified by the minimum capacity argument. * * @param minCapacity the desired minimum capacity */ private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); }

在集合長度超過初始值或當前最大值時,在   grow(int minCapacity) 方法中,進行了擴容,該擴容如代碼所示, 聲明當前集合的最大容量為 oldCapacity , 新增的長度為 oldCapacity 右位移一位數,當容量為 10 時,二進制為  “8020” >> 1 右移后為 “0401” ,十進制值為 5 ,此時將 oldCapacity + 位移后的值 即   10 + 5 = 15 。 

此時完成擴容,newCapacity  = 15 就是 ArrayList 擴容后的最新容量大小。

根據擴容規則可知,容量的遞增可預計為  0 、10、15、22、33、49,以此類推。

注意: 這里對新的容量 newCapacity 和 當前元素長度進行比較,如果元素添加的比較多,超過當次位移擴容的容量大小,則會 直接使用  hugeCapacity 方法進行擴容,

  private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }

第一個有參構造器:

單元測試:

① 當聲明的容量小於默認初始值10 時,會在超過初始容量10 后進行擴容,

@Test public void catapicity(){ ArrayList<Object> objects = new ArrayList<>(5); objects.add("a"); objects.add("b"); objects.add("c"); System.out.println("長度: "+objects.size() + " 容量: " + getArrayListCapacity(objects)); // 增加一個值 for (int i = 0 ; i < 2 ; i ++ ){ objects.add(i); } System.out.println("長度: "+objects.size() + " 容量: " + getArrayListCapacity(objects)); // 增加一個值 for (int i =3; i <5 ; i ++ ){ objects.add(i); } System.out.println("長度: "+objects.size() + " 容量: " + getArrayListCapacity(objects)); // 增加一個值 for (int i = 6 ; i < 10 ; i ++ ){ objects.add(i); } System.out.println("長度: "+objects.size() + " 容量: " + getArrayListCapacity(objects)); for (int i = 11 ; i < 15 ; i ++ ){ objects.add(i); } System.out.println("長度: "+objects.size() + " 容量: " + getArrayListCapacity(objects)); for (int i = 11 ; i < 15 ; i ++ ){ objects.add(i); } System.out.println("長度: "+objects.size() + " 容量: " + getArrayListCapacity(objects)); } 

測試結果:

長度:  3 容量: 5
長度:  5 容量: 5
長度:  7 容量: 7
長度:  11 容量: 15
長度:  15 容量: 15
長度:  19 容量: 22

②超過初始化容量的元素增加:

@Test public void catapicity(){ ArrayList<Object> objects = new ArrayList<>(13); // objects.add("a"); // objects.add("b"); // objects.add("c"); // System.out.println("長度: "+objects.size() + " 容量: " + getArrayListCapacity(objects)); // 增加一個值 for (int i = 0 ; i < 15 ; i ++ ){ objects.add(i); } System.out.println("長度: "+objects.size() + " 容量: " + getArrayListCapacity(objects)); // 增加一個值 for (int i =3; i <5 ; i ++ ){ objects.add(i); } System.out.println("長度: "+objects.size() + " 容量: " + getArrayListCapacity(objects)); // 增加一個值 for (int i = 6 ; i < 10 ; i ++ ){ objects.add(i); } System.out.println("長度: "+objects.size() + " 容量: " + getArrayListCapacity(objects)); for (int i = 11 ; i < 15 ; i ++ ){ objects.add(i); } System.out.println("長度: "+objects.size() + " 容量: " + getArrayListCapacity(objects)); for (int i = 11 ; i < 15 ; i ++ ){ objects.add(i); } System.out.println("長度: "+objects.size() + " 容量: " + getArrayListCapacity(objects)); }
長度:  15 容量: 19
長度:  17 容量: 19
長度:  21 容量: 28
長度:  25 容量: 28
長度:  29 容量: 42

超過初試容量后,第一次擴容會直接使用當前集合長度作為 oldCapacity 進行擴容

2、LinkedList

鏈表結構,且是是雙向鏈表, 不涉及擴容的問題。

3、Vector

Vector與ArrayList一樣,是存儲在數組結構中。  與擴容機制相關的構造器有三個,分別是

  1. Vector(int initialCapacity, int capacityIncrement),
  2. Vector(int initialCapacity)
  3. Vector()

  其實這后兩個最終都是調用了第一個構造器,不過是使用了不同的默認參數,initialCapacity是初始容量,默認是10,capacityIncrement 是每次擴容時候的遞增數量,如果該數值不等於0則每次擴容的時候是原來的二倍,如果該數值大於0,則每次增長的數量等於該數值

int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); )。

比如:

       Vector<String> v = new Vector<String>(); // 10 20 ,40 80 ,160,320 的速度遞增

      Vector<String> v2 = new Vector<>(5,3);// 5 8 11 14 17 ,20,23 的速度遞增。

   他的加載因子也是10

4、Stack

  繼承於Vector,所以他的擴容機制等同於Vector的默認情況,也就是2倍速度擴容,加載因子為1

二、Map

獲取Map集合容量大小的方法:

思路:利用反射獲取hashmap里的threshold(擴容上限)除以 負載因子 就得到容器大小了。

public static int getHashMapCapacity(HashMap<?,?> hashMap) { Class<HashMap> hashMapClass = HashMap.class; try { // threshold是hashmap對象里的一個私有變量,若hashmap的size超過該數值,則擴容。這是通過反射獲取該值 Field field = hashMapClass.getDeclaredField("threshold"); //setAccessible設置為true可以開啟對似有變量的訪問 field.setAccessible(true); int threshold = 0; if ((int) field.get(hashMap) != threshold) { threshold = (int) field.get(hashMap); // 默認的負載因子是0.75,也就是說實際容量是/0.75 double v = (int) field.get(hashMap) / 0.75; // System.out.println((int) field.get(hashMap) / 0.75); System.out.println("擴張容量: " + threshold + " 實際容量: "+ (int)v); } return threshold; } catch (NoSuchFieldException e) { e.printStackTrace(); return -1; } catch (IllegalAccessException e) { e.printStackTrace(); return -1; } }

1、HashMap 的擴容機制:

在HashMap 中,與容量有關的構造器有三個:

  1. public HashMap(int initialCapacity, float loadFactor) 
  2. public HashMap(int initialCapacity)     
    
  3. public HashMap() 
       
    

1.1 這里先對  public HashMap( )做單元測試,並進行分析

	@Test public void mapCapacity(){ HashMap<Object, Object> map = new HashMap<>(); getHashMapCapacity(map); System.out.println( " 已占用容量" + map.size()); // 這里添加是個元素 for (int i= 0; i < 10; i++){ map.put(String.valueOf(i),i); } getHashMapCapacity(map); System.out.println( " 已占用容量" + map.size()); // 這里添加2個元素 for (int i= 11; i < 13; i++){ map.put(String.valueOf(i),i); } getHashMapCapacity(map); System.out.println( " 已占用容量" + map.size()); // 這里添加30個元素 for (int i= 31; i < 60; i++){ map.put(String.valueOf(i),i); } getHashMapCapacity(map); System.out.println( " 已占用容量" + map.size()); }

單元測試結果:

DemoApplicationTests      : Started DemoApplicationTests in 3.717 seconds (JVM running for 4.477) 已占用容量0 擴張容量: 12 實際容量: 16 已占用容量11 擴張容量: 24 實際容量: 32 已占用容量13 擴張容量: 48 實際容量: 64 已占用容量42 2020-01-29 13:08:05.433 INFO 29660 --- [ Thread-2] o.s.w.c.s.GenericWebApplicationContext : Closing org.springframework.web.context.support.GenericWebApplicationContext@ffaa6af: startup date [Wed Jan 29 13:08:02 CST 2020]; root of context hierarchy

在這里先對單元測試結果進行分析:

首先我們先看一下,單元測試中,創建了一個默認無參的HashMap,此時第一次打印 集合實例的 容量值,得到的結果是 "已占用容量 0",這里對代碼進行分析:

                        if ((int) field.get(hashMap) != threshold) { threshold = (int) field.get(hashMap); // 默認的負載因子是0.75,也就是說實際容量是/0.75 double v = (int) field.get(hashMap) / 0.75; // System.out.println((int) field.get(hashMap) / 0.75); System.out.println("擴張容量: " + threshold + " 實際容量: "+ (int)v); }

這里是通過反射獲取 HashMap 字節碼對象從而得到運行時的構造器或方法實例及相應的屬性的值,

		Field field = hashMapClass.getDeclaredField("threshold");

以上的一條代碼便是獲取 “threshold ” 私有屬性的方法,這里看一看該變量在 HashMap   中的含義:

  /** * The next size value at which to resize (capacity * load factor). * * @serial */ // (The javadoc description is true upon serialization. (序列化時,javadoc描述為真。 // Additionally, if the table array has not been allocated, this 此外,如果還沒有分配表數組,則執行此操作 // field holds the initial array capacity, or zero signifying 字段持有初始數組容量,或表示為零 // DEFAULT_INITIAL_CAPACITY.) DEFAULT_INITIAL_CAPACITY)。 int threshold; 

由注釋我們可以知道,當前字段在 HashMap 用於存儲 key 字段元素的長度,當初始化一個無參構造時,在沒有對其進行分配元素的情況下,該字段是不會被分配值的,默認值表示值為 0 或 為初始化長度   DEFAULT_INITIAL_CAPACITY 。

    /** * The default initial capacity - MUST be a power of two. */ static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

以上是HashMap中的源碼部分對 默認初始容量的定義: 默認長度為 16 。

以上是為了說明一個問題,在默認定義HashMap 集合容量且沒有添加元素到容器中的情況下, 其容量值 可能是0 ,也可能是初始容量16.

第一條打印結果分析完畢。

以下對HashMap 的 擴容機制進行一番分析,這里會基於單元測試后面的三條打印結果進行分析:

擴張容量: 12 實際容量: 16    已占用容量11
擴張容量: 24 實際容量: 32    已占用容量13
擴張容量: 48 實際容量: 64    已占用容量42

從打印的結果,我們可以看到,第一次打印結果中,集合的實際容量為  16 ,而根據 HashMap 的加載因子來計算,當添加的元素達到長度 0.75 時會進行一次擴容。這里從源碼方面進行分析:

1.2 此處要搞清楚為什么加載因子是0.75?

    /** * Constructs an empty <tt>HashMap</tt> with the default initial capacity * (16) and the default load factor (0.75). */ public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted } 

在以上源碼中,空參構造中,不會對容量大小進行自定義聲明,而是使用默認值 16 ,方法中的成員變量 this.loadFactor 代表當前集合的加載因子,即滿足一定條件進行容量擴張。其中的

DEFAULT_LOAD_FACTOR 在源碼中的位置:
    /** * The load factor used when none specified in constructor. */ static final float DEFAULT_LOAD_FACTOR = 0.75f; 

這里解決了加載因子為什么是 0.75 的問題,不過,在HashMap提供的構造器中,加載因子也是可以自定義的,就在這里給分析一下:

   /** * Constructs an empty <tt>HashMap</tt> with the specified initial * capacity and load factor. * * @param initialCapacity the initial capacity * @param loadFactor the load factor * @throws IllegalArgumentException if the initial capacity is negative * or the load factor is nonpositive */ public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); this.loadFactor = loadFactor; this.threshold = tableSizeFor(initialCapacity); } 

有上述源碼可以知道, map的容量與加載因子可以同時被自定義聲明,在構造函數中會對容量合法性進行校驗:

1.3 在這里我們提出一個問題:HashMap中容量的最大值是什么?

我們看看源碼中的這一句,

            if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY;

當容量大於HashMap 定義的私有變量 MAXIMUM_CAPACITY 時,

將  MAXIMUM_CAPACITY  賦值給  initialCapacity 

在HashMap 中對 MAXIMUM_CAPACITY 的值定義的大小是:

    /** * The maximum capacity, used if a higher value is implicitly specified * by either of the constructors with arguments. * MUST be a power of two <= 1<<30. */ static final int MAXIMUM_CAPACITY = 1 << 30; 

從這里可以知道,hashmap的最大容量是 2的30次方。

1.4 Hashmap 的 擴容機制

在 HashMap 在擴容的過程中有幾個問題要注意:

  1. key 值不可重復與 value 值不可重復的問題?
  2. 容量長度的擴容機制?

在這里就不對第一個問題進行過多贅述,可以參考 筆者的另一篇博文,

從源碼看: hashset如何保證值不會被重復的  在該博文中對key值value值不可重復做了詳盡的分析。

添加元素HashMap 集合中,

                // 這里添加是個元素 for (int i= 0; i < 10; i++){ map.put(String.valueOf(i),i); }

進入 put ()方法中,進行新元素的添加:

    /** * Associates the specified value with the specified key in this map. * If the map previously contained a mapping for the key, the old * value is replaced. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with <tt>key</tt>, or * <tt>null</tt> if there was no mapping for <tt>key</tt>. * (A <tt>null</tt> return can also indicate that the map * previously associated <tt>null</tt> with <tt>key</tt>.) */ public V put(K key, V value) { return putVal(hash(key), key, value, false, true); }

在上述源碼中,會對傳入的key 進行值重復的校驗,具體使用 key 進行hash運算獲取在 當前 集合中的 hash 值,如下:

  static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }

在 put  方法中,對元素 key-value 添加到集合容器的操作是在 putVal() 方法中實現的,並且在該方法中調用 resize () 方法對集合容量長度進行擴容。

  /** * Implements Map.put and related methods * * @param hash hash for key * @param key the key * @param value the value to put * @param onlyIfAbsent if true, don't change existing value * @param evict if false, the table is in creation mode. * @return previous value, or null if none */ 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; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); else { 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; }

使用DEBUG分析查看 putVal方法中的 參數,當前 map 集合的長度為 8 ,有八個key ,每個 key 對應一個value

根據源碼我們可以知道,hashmap的底層是由數組和鏈表構成的,如上圖中, Node<K,V> [ ] tab 代表當前map集合的底層結構,該結構由一個Node (鏈表)類型的數組構成。每個新添加的 key-value 會以一個  Node<K,V> 的鏈表節點的形式被添加到 集合 tab 中 。

在添加元素的時候會調用 resize()方法,並在resize() 方法中將新的集合數據存儲到 table 私有變量中:

    /** * The table, initialized on first use, and resized as * necessary. When allocated, length is always a power of two. * (We also tolerate length zero in some operations to allow * bootstrapping mechanics that are currently not needed.) */ transient Node<K,V>[] table; 

以下是resize() 的代碼:

  /** * Initializes or doubles table size. If null, allocates in * accord with initial capacity target held in field threshold. * Otherwise, because we are using power-of-two expansion, the * elements from each bin must either stay at same index, or move * with a power of two offset in the new table. * * @return the table */ final Node<K,V>[] resize() { Node<K,V>[] oldTab = table; int oldCap = (oldTab == null) ? 0 : oldTab.length; int oldThr = threshold; int newCap, newThr = 0; if (oldCap > 0) { if (oldCap >= MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return oldTab; } else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) newThr = oldThr << 1; // double threshold } else if (oldThr > 0) // initial capacity was placed in threshold newCap = oldThr; else { // zero initial threshold signifies using defaults newCap = DEFAULT_INITIAL_CAPACITY; newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); } if (newThr == 0) { float ft = (float)newCap * loadFactor; newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? (int)ft : Integer.MAX_VALUE); } threshold = newThr; @SuppressWarnings({"rawtypes","unchecked"}) Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]; table = newTab; if (oldTab != null) { for (int j = 0; j < oldCap; ++j) { Node<K,V> e; if ((e = oldTab[j]) != null) { oldTab[j] = null; if (e.next == null) newTab[e.hash & (newCap - 1)] = e; else if (e instanceof TreeNode) ((TreeNode<K,V>)e).split(this, newTab, j, oldCap); else { // preserve order Node<K,V> loHead = null, loTail = null; Node<K,V> hiHead = null, hiTail = null; Node<K,V> next; do { next = e.next; if ((e.hash & oldCap) == 0) { if (loTail == null) loHead = e; else loTail.next = e; loTail = e; } else { if (hiTail == null) hiHead = e; else hiTail.next = e; hiTail = e; } } while ((e = next) != null); if (loTail != null) { loTail.next = null; newTab[j] = loHead; } if (hiTail != null) { hiTail.next = null; newTab[j + oldCap] = hiHead; } } } } } return newTab; }

在以上源碼中,關於擴容部分的代碼是:

  else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) newThr = oldThr << 1; // double threshold

HashMap 中對當前的容量值使用左位移的方式, oldCap << 1 ,將集合容量擴張為當前的2N次冪。此時,我們可以知道HashMap 的擴容是新容量為當前的  2的N次方;

1.5 HashMap 集合進行擴容的時機是?

        if (newThr == 0) { float ft = (float)newCap * loadFactor; newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? (int)ft : Integer.MAX_VALUE); }

前提: 當前集合集合的鏈表數組中必須有值的情況下,才會觸發擴容機制。

當前的集合元素長度達到了 當前給定集合的容量的0.75倍時,該鏈表數組進行自增左位移,默認為2的N次冪。


免責聲明!

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



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