首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
01|动态数组:按需分配的vector为什么要二倍扩容?
02|双向链表:list如何实现高效地插入与删除?
03|双端队列:并行计算中的工作窃取算法如何实现?
04|栈:函数调用的秘密究竟是什么?
05|HashMap:一个优秀的散列表是怎么来的?
06|TreeMap:红黑树真的有那么难吗?
07|堆:如何实现一个高效的优先队列?
08|外部排序:如何为TB级数据排序?
09|二分:如何高效查询Kafka中的消息?
10|搜索算法: 一起来写一个简单的爬虫?
11|字符串匹配:如何实现最快的grep工具
12|拓扑排序:Webpack是如何确定构建顺序的?
13|哈夫曼树:HTTP2.0是如何更快传输协议头的?
14|调度算法:操作系统中的进程是如何调度的?
15|LRU:在虚拟内存中页面是如何置换的?
16|日志型文件系统:写入文件的时候断电了会发生什么?
17|选路算法:Dijkstra是如何解决最短路问题的?
18|选路算法:链路状态算法是如何分发全局信息的
19|选路算法:距离矢量算法为什么会产生无穷计算问题?
20|滑动窗口:TCP是如何进行流量控制和拥塞控制的?
21|分而治之:MapReduce如何解决大规模分布式计算问题
22|PageRank:谷歌是如何计算网页排名的
23|Raft:分布式系统间如何达成共识?
24|UUID:如何高效生成全局的唯一ID?
25|一致性哈希:如何在集群上合理分配流量?
26|B+ Tree:PostgreSQL 的索引是如何建立的?
27|LSM Tree:LevelDB的索引是如何建立的?
28|MVCC:如何突破数据库并发读写性能瓶颈?
29|位图:如何用更少空间对大量数据进行去重和排序?
30|布隆过滤器:如何解决Redis缓存穿透问题?
31|跳表:Redis是如何存储有序集合的?
32|时间轮:Kafka是如何实现定时任务的?
33|限流算法:如何防止系统过载?
34|前缀树:Web框架中如何实现路由匹配?
当前位置:
首页>>
技术小册>>
业务开发实用算法精讲
小册名称:业务开发实用算法精讲
### 01|动态数组:按需分配的vector为什么要二倍扩容? 在深入探讨编程中的数据结构时,动态数组(如C++标准模板库中的`std::vector`)无疑是一个极其重要的基础。动态数组之所以如此受欢迎,是因为它们能够在运行时自动调整大小以存储更多的元素,无需程序员手动管理内存分配和释放,从而大大简化了数组使用的复杂性。然而,动态数组的这种灵活性并非没有代价,其中最关键的一环便是其扩容策略。在众多扩容策略中,二倍扩容因其效率和实用性而成为了众多实现(包括`std::vector`)的首选。本章节将详细探讨为何动态数组采用二倍扩容策略,以及这一策略背后的逻辑与优势。 #### 一、动态数组的基本概念 动态数组,又称可变数组或向量(Vector),是一种可以动态调整其大小的数组结构。与静态数组不同,动态数组在初始化时不需要指定最大容量,它们能够根据元素的实际存储需求自动增加容量。这种特性使得动态数组非常适合于那些大小未知或会随时间变化的场景。 #### 二、扩容的必然性 由于动态数组的大小不是固定的,因此当向其中添加新元素而当前容量不足以容纳时,就必须进行扩容操作。扩容意味着在内存中分配一个更大的连续空间,并将原数组的元素复制到新空间中,然后在这个新空间中继续存储新元素。这个过程涉及内存分配、数据复制和旧内存的释放(虽然在很多情况下,旧内存的释放可能由垃圾回收机制或智能指针等自动管理),因此存在一定的性能开销。 #### 三、扩容策略的选择 动态数组的扩容策略直接影响到其性能。理想的扩容策略应该能够平衡扩容操作的频率与每次扩容的成本,以减少整体的性能损耗。常见的扩容策略包括: 1. **固定增量扩容**:每次扩容时,容量固定增加某个常数值(如10)。这种策略简单直观,但可能导致频繁扩容,特别是在数据量增长迅速时。 2. **按比例扩容**:每次扩容时,容量按照一定比例增加(如1.5倍或2倍)。这种策略可以减缓扩容的频率,但每次扩容的成本相对较高。 3. **几何增长扩容**:一种特殊的比例扩容,其中扩容比例是指数级增长的(如2的幂次方倍)。这种策略结合了前两者的优点,既能减少扩容频率,又能控制每次扩容的成本增长。 #### 四、二倍扩容的优势 在众多扩容策略中,二倍扩容因其独特的优势而被广泛采用。以下是二倍扩容的几个主要优点: 1. **减少扩容次数**:二倍扩容意味着每次扩容后,动态数组能够容纳的元素数量都会翻倍。这显著降低了扩容操作的频率,特别是在数据量较大且增长迅速时。例如,如果一个动态数组初始容量为1,采用二倍扩容策略,则在添加第n个元素时(n为2的幂),才需要进行log2(n)次扩容操作,这比固定增量扩容的频率要低得多。 2. **平衡扩容成本**:虽然二倍扩容每次增加的容量较大,但由于扩容次数减少,整体上看,它能在一定程度上平衡扩容的成本。特别是当内存分配采用“延迟分配”(如虚拟内存管理)时,这种策略能够更有效地利用物理内存和减少页面交换(Paging)的次数。 3. **简化内存管理**:二倍扩容策略在内存管理方面也有其独到之处。由于扩容后的容量总是前一次的两倍,这有助于减少内存碎片。同时,许多操作系统和内存管理库都针对这种幂次扩容进行了优化,使得内存分配和释放更加高效。 4. **兼容性与通用性**:二倍扩容已成为动态数组扩容策略的一种事实标准,被广泛应用于各种编程语言和库中。这种一致性使得开发者能够更容易地理解和使用不同语言或库中的动态数组,降低了学习和迁移的成本。 #### 五、二倍扩容的潜在问题 尽管二倍扩容策略具有诸多优势,但也存在一些潜在的问题和挑战: 1. **空间浪费**:在极端情况下,如果动态数组的使用量远小于其当前容量,可能会导致大量的空间浪费。例如,在添加少量元素后就进行了多次二倍扩容,那么最终可能只有一小部分空间被有效利用。然而,这种情况在实际应用中并不常见,因为动态数组通常用于存储大量数据,且数据量的增长往往是连续的。 2. **扩容成本累积**:虽然每次扩容的成本相对于数据量来说是可控的,但在数据量极大时,累积的扩容成本也可能变得显著。这主要影响的是大规模数据处理和实时性要求较高的应用场景。然而,对于大多数常规应用而言,这种成本仍然是可以接受的。 #### 六、结论 综上所述,二倍扩容策略因其能够减少扩容次数、平衡扩容成本、简化内存管理以及广泛的兼容性和通用性而成为动态数组扩容的首选策略。尽管它也存在一些潜在的问题和挑战,但在实际应用中,这些问题通常不会对性能产生显著影响。因此,在设计和实现动态数组时,合理采用二倍扩容策略是一种既高效又实用的选择。 在本书后续章节中,我们将继续探讨动态数组的其他特性和应用场景,包括其性能优化、与静态数组的比较、以及在特定场景下的特殊实现等。通过深入理解动态数组的工作原理和最佳实践,读者将能够更加灵活地运用这一数据结构来解决实际问题。
下一篇:
02|双向链表:list如何实现高效地插入与删除?
该分类下的相关小册推荐:
数据结构与算法(中)
编程之道-算法面试(上)
算法面试通关 50 讲
编程之道-算法面试(下)
数据结构与算法(上)
数据结构与算法之美
数据结构与算法(下)