小白白跑去鹅厂面试,面试官提出了一个问题: 容器空间爆满怎么去扩容,说一说内部是如何处理的?我们的小白白不假思索的回答道:容器满了就要倒出来!啊?容器是装水的瓶子?(更多内容关注微信公众号: 白白家族)
一:容器为什么要扩容
在处理新增元素时,如果容器已满,就要先分配一块更大的内存空间,其次将容器的数据复制进来,再释放之前的内存,最后插入新增的元素。
二:那些容器要扩容
底层实现包含数组类的需要扩容:如ArrayList,HashMap
底层实现包含链表类的则不需要扩容:如LinkedList
三:各容器扩容汇总
容器 | 初始空间 | 扩容倍数 | 加载因子 |
ArrayList | 10 | 1.5 | 无 |
Vector | 10 | 2 | 无 |
HashSet | 16 | 2 | 0.75 |
HashMap | 16 | 2 | 0.75 |
PriorityQueue | 11 | 1.5 | 无 |
四:为何选用倍数扩容,而不采用增加固定大小值扩容
1,以成倍方式增长
假定有 n 个元素,倍增因子为 m;那么,第 i 次重新分配将会导致迁移m^(i) (也就是当前的容器大小)个旧空间中元素;因此,n 次迁移操作所花费的时间复制度为O(n);均摊下来每次push_back 操作的时间复杂度为常数级别;
2,一次增加固定值大小
假定有 n 个元素,每次增加k个;n 次 push_back 操作所花费的时间复杂度为O(n^2);均摊下来每次push_back 操作的时间复杂度为O(n);
总结:对比可以发现采用采用成倍方式扩容,可以保证常数的时间复杂度,而增加固定值容量的只能达到O(n)的时间复杂度;
以上分析的太复杂,这里给出形象解释:容器扩容为原来的2倍(假设N足够大),采用成倍增长,一次扩容即可(包括数据迁移到新空间),而固定值K增长扩容方案,因为N远远大于增长量K时,就会发生N/k次扩容,这里会产生多次就数据迁移过程,因此,可见使用成倍的方式扩容的好处。
五,为何不选用更大倍数扩容
主要是考虑空间浪费问题,根据预判i经验,成倍增长倍数不能太大,倍数设置最好为(1,2)之间,目前较为广泛使用的扩容数有两种,以2倍或1.5倍。
六,综述
总结一下,容器扩容时候会迁移元素,所以频繁的扩容是对性能有消耗的,所以设置合理的容量的出事大小可以在很大程度上提高性能。
(更多内容关注微信公众号: 白白家族)
扫描二维码: