常见的扩容机制

          StringBuilder stringBuilder=new StringBuilder();

扩容机制通常指的是在计算机科学和软件开发中用户动态调整数据结构大小的一种策略,这通常涉及到动态分配额外的内存空间,以便在数据量增加时能够容纳更多的元素。以下是常见的扩容机制;

1.动态数组的扩容

在许多编程语言中,动态数组(例如 Java 中的 ArrayList,C++ 中的 std::vector)通常使用动态扩容机制。当数组达到其当前容量时,会创建一个新的更大的数组,将原始数据复制到新数组中,然后释放原始数组。通常,新数组的大小是原数组的两倍。

1.1arraylist的扩容机制

      1.初始化容量:

      初始容量:

     当你创建一个新的 ArrayList 时,它会有一个初始的容量。这个容量通常是一个较小的值,例       如10。

        List list=new ArrayList();

     添加元素的时候检查:

     当你使用add方法向arraylist中添加元素的时候,会检查当前元素数量是否达到了数组的容量:

  list.add("ssss");

       arraylist的add源码如下:jdk11

           

private void add(E e, Object[] elementData, int s) {
//检查当前数组是否已满
        if (s == elementData.length)
           //扩容
            elementData = grow();
        elementData[s] = e;
        size = s + 1;
    }

         3.扩容操作:

         如果当前元素数量等于数组容量,ArrayList 将会触发扩容操作。它会创建一个新的数组,通常是原始容量的两倍,然后将所有的元素从旧数组复制到新数组中。

 return elementData = Arrays.copyOf(elementData,
                                           newCapacity(minCapacity));
 private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity <= 0) {
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                return Math.max(DEFAULT_CAPACITY, minCapacity);
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            return minCapacity;
        }
        return (newCapacity - MAX_ARRAY_SIZE <= 0)
            ? newCapacity
            : hugeCapacity(minCapacity);
    }

    4.赋值

2.哈希表的扩容

在哈希表中,为了保持较低的冲突率,当元素数量达到一定阈值时,哈希表会进行扩容。扩容过程通常包括创建一个更大的哈希表,将所有的键值对重新散列到新表中。这有助于减少冲突,并保持较好的性能。

hash表的链接:HashMap深入介绍-CSDN博客

3.堆的动态扩容:

在堆内存管理中,动态分配的内存块可能会被动态扩容。当内存块不足以满足分配请求时,系统可能会分配一个更大的内存块,将原始数据复制到新的内存块中,然后释放原始内存块。

4.字符串的动态扩容

对于动态字符串(例如 Java 中的 StringBuilder,C++ 中的 std::string),通常在字符串追加时会进行动态扩容。这涉及到创建一个更大的字符数组,将原始字符复制到新数组中。

扩容机制的设计旨在平衡内存使用和性能。频繁的扩容可能导致内存碎片和性能开销,因此在设计中需要权衡扩容的频率和扩容的大小。很多情况下,选择一个合适的扩容因子(如动态数组的两倍大小)可以在保证性能的同时减少扩容次数。

StringBuilder的扩容:默认容量16

        StringBuilder stringBuilder=new StringBuilder();
public AbstractStringBuilder append(String str) {
        if (str == null) {
            return appendNull();
        }
        int len = str.length();
        //count+len 是原有的字符串长度+新追加的字符串长度
        ensureCapacityInternal(count + len);
        putStringAt(count, str);
        count += len;
        return this;
    }

ensureCapacityInternal 这个方法我们去源码看一下

 // overflow-conscious code
/*我们首先看到了一个二进制位的右移运算。value.length是字符数组的长度,结合coder参数进行右移运算,得到字符串的原有容量。这里的coder参数是一种编码方式,如果字符串中没有中文,默认是采用Latin1编码,如果有中文则会采用UTF-16编码。因为UTF-16编码中文时需要两个字节,也就是说,只要字符串中含有中文,value字节数组中是每两位对应一个字符。*/
        int oldCapacity = value.length >> coder;
        if (minimumCapacity - oldCapacity > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity) << coder);
        }
private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = value.length >> coder;
        int newCapacity = (oldCapacity << 1) + 2;
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }
        int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
        return (newCapacity <= 0 || SAFE_BOUND - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }

从上面可以看书,arrayList的扩容和stringbuilder的扩容思路一只,都是复制数组到扩容新的数组

你可能感兴趣的:(数据结构)