展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > deque底层实现原理详解:块状数组优缺点分析

deque底层实现原理详解:块状数组优缺点分析

deque的内部实现采用分块数组结构,由多个固定大小的数据块通过指针数组(map)连接,形成逻辑连续的序列。1.数据块是固定大小的数组,用于存储元素;2.map数组存储指向数据块的指针;3.头尾指针标识当前逻辑起始和结束位置;4.插入操作在头尾时分配新块并更新map,无需移动旧数据;5.随机访问需两次指针解引用,时间复杂度为O(1)。相比vector,deque避免了频繁内存重分配,支持高效两端操作;相比list,具有更好的缓存局部性和随机访问性能。适用场景包括双端队列、滑动窗口等需要两端高效扩展的场合。

本文目录

    deque的内部实现采用分块数组结构,由多个固定大小的数据块通过指针数组(map)连接,形成逻辑连续的序列。1. 数据块是固定大小的数组,用于存储元素;2. map数组存储指向数据块的指针;3. 头尾指针标识当前逻辑起始和结束位置;4. 插入操作在头尾时分配新块并更新map,无需移动旧数据;5. 随机访问需两次指针解引用,时间复杂度为O(1)。相比vector,deque避免了频繁内存重分配,支持高效两端操作;相比list,具有更好的缓存局部性和随机访问性能。适用场景包括双端队列、滑动窗口等需要两端高效扩展的场合。迭代器失效规则介于vector和list之间:两端插入不轻易失效,但中间操作或map扩容可能导致部分或全部迭代器失效。

    deque内部实现原理是怎样的 块状数组结构优缺点解析

    deque(双端队列)的内部实现,通常采用的是一种“分块数组”或“多段数组”的结构。它不像vector那样在内存中连续分配一大块空间,而是由多个大小相对固定的小型动态数组(块)组成,这些小块通过一个指针数组(通常称为“map”或“control array”)来管理和连接,形成一个逻辑上连续的序列。这种设计巧妙地融合了数组的随机访问能力和链表的动态扩展灵活性,尤其擅长在两端进行高效的插入和删除操作。

    deque内部实现原理是怎样的 块状数组结构优缺点解析

    解决方案

    deque的核心思想在于,它将数据分散存储在多个独立的内存块中。想象一下,你有一本厚厚的书,但不是一整页一整页地写,而是每写完一章就单独装订成一个小册子,然后把这些小册子按照顺序放在一个大盒子里。这个大盒子就是deque的“map”数组,里面装着指向各个小册子(数据块)的指针。

    deque内部实现原理是怎样的 块状数组结构优缺点解析

    具体来说,deque的结构大致是这样的:

    1. 数据块(Chunks/Blocks): 每个数据块都是一个固定大小的数组,比如std::deque通常会使用一个2的幂次大小的块,比如512字节或4KB,以优化内存对齐和缓存利用率。当deque需要存储元素时,它会从这些块中分配空间。
    2. 映射数组(Map Array): 这是一个动态数组,它不存储实际的数据,而是存储指向各个数据块的指针。例如,map_array[i]会指向第i个数据块。
    3. 头尾指针(Pointers/Indices): deque内部会维护一些指针或索引,指示当前deque的逻辑起始位置(比如start_block_index, start_element_index_in_block)和逻辑结束位置(比如end_block_index, end_element_index_in_block)。

    当你在deque的尾部push_back一个元素时,它会尝试将其放入当前最后一个数据块。如果该块已满,deque会分配一个新的数据块,并将其指针添加到映射数组的末尾,然后将新元素放入新块。类似地,push_front时,如果第一个数据块已满,它会分配一个新的数据块,并将其指针添加到映射数组的头部(这可能涉及到映射数组本身的扩展和元素移动),然后将新元素放入新块。

    deque内部实现原理是怎样的 块状数组结构优缺点解析

    随机访问元素,例如deque[i],涉及到两次指针解引用:首先通过索引i计算出对应的块在映射数组中的位置,然后通过该块指针和元素在块内的偏移量,找到实际的元素。这个过程虽然比vector多了一次指针跳转,但依然是O(1)时间复杂度。

    这种分块设计的好处在于,当deque在两端扩展时,它不需要像vector那样进行大规模的内存重新分配和元素拷贝。它只需要分配一个新的小块,并更新映射数组即可。这使得push_front和push_back操作的平均时间复杂度都达到了O(1)。

    deque与vector、list相比,其性能特点和适用场景有何不同?

    谈到容器,我们总会不自觉地把deque和vector、list放在一起比较,它们各有千秋,但deque的存在感似乎总是在两者之间摇摆。

    从性能特点来看:

    • vector: 内存连续,这是它最大的优势。这意味着极佳的缓存局部性,访问元素时CPU能高效预取数据,所以随机访问([]操作)和尾部添加(push_back,均摊O(1))速度飞快。但它的缺点也很明显:在中间插入或删除元素(O(N)),以及在头部插入元素(O(N)),都需要大量的数据移动。更要命的是,当容量不足时,它需要重新分配更大的内存空间,然后将所有旧元素拷贝过去,这个过程成本很高。
    • list: 双向链表,内存不连续,每个元素独立分配,并带有前后指针。它的优点是插入和删除元素(无论在何处)都非常快,是O(1)操作,因为它只需要修改几个指针。但缺点也同样突出:随机访问元素是O(N),你需要从头或尾遍历才能找到目标;缓存局部性差,因为元素可能分散在内存各处,导致CPU缓存命中率低。
    • deque: 介于两者之间,它试图取长补短。它的随机访问是O(1),但由于需要两次指针解引用(先到块指针,再到元素),通常会比vector略慢一点点,但比list快得多。两端插入和删除(push_front/push_back/pop_front/pop_back)都是均摊O(1)的,这是它最突出的优势。它避免了vector频繁的内存重分配,同时比list有更好的缓存局部性(因为块内部是连续的)。不过,在中间插入或删除元素,依然是O(N),因为它可能需要移动半个deque的数据块。

    至于适用场景:

    • vector: 你的首选容器,如果你的主要操作是尾部添加、遍历和随机访问,并且对中间插入/删除不敏感,或者数据量相对固定。它就是那个万金油。
    • list: 当你频繁需要在容器的任意位置进行插入和删除操作,并且对随机访问性能要求不高时,list就是最佳选择。比如实现一些复杂的图算法中的邻接表,或者需要高效管理大量动态对象的场景。
    • deque: 什么时候考虑deque呢?当你需要一个既能快速在两端扩展(像队列或栈那样),又需要保持相对快速的随机访问能力时。比如,实现一个双端队列、一个滑动窗口,或者作为其他数据结构(如某些树或图的遍历算法)的底层存储。我个人觉得,在处理日志流、任务队列,或者任何需要从两端高效处理数据的场景,deque都表现出色。

    deque在内存管理上是如何避免vector频繁重新分配的痛点?

    vector的内存管理方式,对于我这种追求效率的人来说,有时候确实是个“痛点”。它为了保证元素的连续存储和O(1)的随机访问,一旦当前容量不足,就得申请一块更大的新内存,然后把所有旧元素一股脑儿地复制过去,最后再释放旧内存。这个过程,尤其是当vector存储的是大对象或者元素数量庞大时,性能开销是相当可观的。

    deque则聪明地避开了这个坑。它的核心策略是“分而治之”。它不追求所有元素都在一块连续的内存上,而是把数据分散到多个固定大小的“块”里。当deque需要在两端扩展时(比如push_back或push_front),它并不会去寻找一块能容纳所有现有元素和新元素的更大内存区域,然后进行复制。

    相反,它会:

    1. 分配新的小块内存: 如果当前最末端或最前端的块已满,deque会直接分配一个新的数据块(通常是预设的固定大小,比如512字节或4KB),而不是一个翻倍大小的新deque总内存。
    2. 更新映射数组: 这个新分配的块的指针会被添加到deque内部的“映射数组”(一个存储块指针的数组)的相应位置(头部或尾部)。
    3. 放置新元素: 新元素直接放入这个新分配的块中。

    这个过程的关键在于,旧的数据块和其中的元素根本不需要移动。它们仍然留在原来的内存位置。只有映射数组本身可能会因为需要存储更多块指针而进行扩展,但这个映射数组通常比实际数据小得多,其重新分配的开销也远小于vector的数据区重新分配。

    所以,deque的这种“按需分配小块,并通过指针数组管理”的策略,从根本上避免了vector那种“全员大迁徙”式的内存重分配,从而保证了其两端操作的高效性,即使在处理大量数据时也能保持稳定的性能表现。这对我来说,是它在某些特定场景下比vector更有吸引力的原因。

    为什么说deque的迭代器失效规则比vector复杂,但比list简单?

    迭代器失效规则,这东西在C++容器里,有时候确实让人头疼,尤其是当你写一些复杂算法,涉及到迭代器操作时,搞不清楚就容易出bug。deque的迭代器失效规则,我觉得用“微妙”来形容可能更贴切,因为它确实介于vector的“粗暴”和list的“佛系”之间。

    首先,让我们回顾一下:

    • vector的迭代器失效:它的规则最简单也最“残酷”。任何可能导致vector内部内存重新分配的操作(比如push_back导致容量不足、insert、erase),都会导致所有指向该vector元素的迭代器、指针和引用全部失效。因为元素可能已经被移动到新的内存地址了。简单粗暴,但很明确。
    • list的迭代器失效:这是最“佛系”的。由于list的每个元素都是独立分配的,并由指针连接,所以除了指向被删除元素本身的迭代器会失效外,其他任何插入或删除操作都不会影响到现有元素的内存位置,因此它们的迭代器、指针和引用都不会失效。非常稳定。

    那么deque呢?它有点像个“中间派”:

    比vector更稳定(更简单): deque在两端进行push_front或push_back操作时,通常不会导致所有迭代器失效。这是因为这些操作主要涉及分配新的数据块并更新映射数组,而不会移动已存在的数据块。所以,只要没有涉及到映射数组本身的重新分配(这种情况非常罕见,通常只发生在deque变得非常非常大,以至于映射数组也需要扩容时),或者没有在中间进行插入/删除,指向现有元素的迭代器是保持有效的。这一点比vector好太多了,你不用担心在push_back后,之前获取的迭代器就不能用了。

    比list更复杂(不那么简单): deque的迭代器并非完全免疫失效。

    1. 中间插入/删除:如果在deque的中间进行insert或erase操作,那么从插入/删除点开始,到deque末尾的所有迭代器都可能失效。这是因为deque为了保持其逻辑上的连续性,需要移动数据块内的元素,或者甚至移动整个数据块以腾出空间或填补空缺。
    2. 映射数组重分配:虽然罕见,但如果deque的元素数量庞大到需要扩展其内部的“映射数组”本身时,所有迭代器都会失效。这类似于vector的整体重分配,但发生的频率要低得多。

    所以,我的理解是,deque的迭代器失效规则是vector和list之间的一个折衷。它在两端操作时提供了比vector更好的迭代器稳定性,但在中间操作时,它仍然需要你小心处理迭代器,不如list那样“无忧无虑”。在使用deque时,我通常会尽量避免在循环中对中间部分进行插入或删除,或者在操作后重新获取迭代器,以避免潜在的问题。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发
    相关文章 更多
    精品专题 更多
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    IOS软件

    正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

    AI

    正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

    Mac软件 更多
    Postman macOS版
    Postman macOS版

    Postman是一套面向API全生命周期的开发与测试平台,可在Mac上发送和调试多种协议请求,管理集合、环境及认证信息,并完成脚本测试、模拟服务、监控、文档发布和团队协作。它适合开发、测试及运维人员使用,提供个人免费方案。

    Docker Desktop macOS版
    Docker Desktop macOS版

    Docker Desktop 是 Docker 官方为 Mac 提供的容器开发环境,集成 Docker Engine、命令行工具、Compose、Build、Kubernetes 与图形化管理界面。

    Android Studio macOS版
    Android Studio macOS版

    Android Studio 是 Google 面向安卓应用开发提供的官方集成开发环境,基于 IntelliJ IDEA 构建。它整合智能代码编辑、Gradle 构建、界面预览、设备模拟、性能分析、调试测试及 APK 分析等工具。

    Xcode macOS版
    Xcode macOS版

    Xcode 是苹果面向 Mac 提供的官方集成开发环境,将代码编辑、项目构建、SwiftUI 实时预览、设备模拟、自动化测试、断点调试、性能分析和应用分发整合在同一套工作流中,适合开发与维护 iPhone、iPad、Mac、Apple Wa

    JetBrains WebStorm macOS版
    JetBrains WebStorm macOS版

    JetBrains WebStorm 是面向 JavaScript、TypeScript 和现代 Web 技术的专业集成开发环境,可智能理解项目结构,提供代码补全、重构、错误检查、运行调试、测试及 Git 工具。

    PhpStorm macOS版
    PhpStorm macOS版

    PhpStorm 是 JetBrains 推出的专业 PHP 集成开发环境,可在 Mac 上完成代码编写、智能检查、重构、调试、测试和数据库管理。它支持主流 PHP 框架、Composer、Git、Docker 与远程解释器。

    JetBrains PyCharm macOS版
    JetBrains PyCharm macOS版

    JetBrains PyCharm 是面向 Python 开发者的集成开发环境,提供智能补全、代码检查、重构、调试、测试、版本控制及虚拟环境管理功能。Mac 版兼容 Intel 与 Apple 芯片,核心功能可免费使用。

    JetBrains IntelliJ IDEA macOS版
    JetBrains IntelliJ IDEA macOS版

    IntelliJ IDEA 是 JetBrains 推出的专业集成开发环境,重点服务于 Java、Kotlin 与 JVM 项目开发。软件集成代码补全、静态检查、重构、调试、测试、版本控制及构建工具,并可借助插件扩展语言和框架支持。

    Visual Studio Code macOS版
    Visual Studio Code macOS版

    Visual Studio Code 是微软提供的免费代码编辑器,支持 macOS,并为 Intel 与 Apple 芯片 Mac 提供适配版本。软件集代码编辑、调试、Git 源代码管理、集成终端和扩展市场于一体。

    REAPER macOS版
    REAPER macOS版

    REAPER是Cockos开发的数字音频工作站,提供多轨音频与MIDI录制、剪辑、处理、混音和母带制作工具。Mac版兼容Intel与Apple芯片,支持AU、VST、VST3、CLAP等插件格式,并提供高度可定制的工作流程。

    Adobe Audition macOS版
    Adobe Audition macOS版

    Adobe Audition 是面向播客、影视后期、音乐制作及内容创作者的专业音频工作站,提供波形精修、多轨录制与混音、频谱编辑、降噪修复、响度匹配和效果处理工具,并可与 Adobe Premiere 协同完成视频声音制作。

    Pro Tools macOS版
    Pro Tools macOS版

    Pro Tools 是 Avid 推出的专业数字音频工作站,覆盖多轨录音、无损剪辑、MIDI 编曲、插件处理、自动化混音及声音与画面同步等工作。它拥有 Intro、Artist、Studio 和 Ultimate 等方案。

    WINDOWS 更多
    PixPix 网页版
    PixPix 网页版

    PixPix 是面向品牌、卖家和内容团队的在线 AI 图片视频创作平台,提供图视频 Agent、无限画布、图片生成、视频生成、自然语言编辑及商品套图、产品精修和带货视频等电商工具。

    Postman Windows版
    Postman Windows版

    Postman 是面向 API 全生命周期的开发与协作平台。Windows 桌面版可用于构建和发送 HTTP、GraphQL、gRPC、WebSocket、MQTT 等请求,并提供环境变量、集合、脚本测试、模拟服务、监控、文档及团队工作区等

    Docker Desktop Windows版
    Docker Desktop Windows版

    Docker Desktop 为 Windows 开发者提供集成式容器环境,内置 Docker Engine、命令行工具、Compose、Build 与 Kubernetes 等组件,可在本机完成镜像构建、容器运行、日志查看和资源管理。

    Android Studio Windows版
    Android Studio Windows版

    Android Studio 是 Google 面向 Android 应用开发提供的官方集成开发环境,以 IntelliJ IDEA 为基础,集成智能代码编辑、Gradle 构建、设备模拟、界面预览、调试测试及性能分析工具,

    JetBrains WebStorm Windows版
    JetBrains WebStorm Windows版

    WebStorm 是 JetBrains 面向 JavaScript、TypeScript 和现代 Web 技术打造的集成开发环境。它提供项目级代码分析、智能补全、安全重构、导航搜索,并集成调试、测试、终端、Git 与常用前端工具,

    JetBrains PhpStorm Windows版
    JetBrains PhpStorm Windows版

    PhpStorm 是 JetBrains 面向 PHP 与现代 Web 开发打造的专业集成开发环境,提供代码补全、静态检查、重构、调试、测试、数据库、版本控制及前端语言支持。Windows 用户可直接下载安装程序,

    JetBrains PyCharm Windows版
    JetBrains PyCharm Windows版

    PyCharm 是 JetBrains 推出的 Python 集成开发环境,提供智能代码补全、错误检查、重构、调试、测试、Git、终端及 Jupyter Notebook 支持。统一版安装后可体验 30 天 Pro 功能,

    JetBrains IntelliJ IDEA Windows版
    JetBrains IntelliJ IDEA Windows版

    JetBrains IntelliJ IDEA 是以 Java、Kotlin 和 JVM 项目为核心的专业集成开发环境,提供智能补全、代码检查、安全重构、调试、测试、版本控制及构建工具集成。统一发行版的核心功能可免费用于商业和非商业项目,

    Visual Studio Code Windows版
    Visual Studio Code Windows版

    Visual Studio Code 是微软推出的免费代码编辑器,Windows 版集成智能补全、代码导航、调试、终端和版本控制,并可通过扩展添加语言、格式化及远程开发能力。它启动较快、配置灵活,

    REAPER Windows版
    REAPER Windows版

    REAPER 是 Cockos 推出的数字音频工作站,适用于录音、MIDI 编曲、音频编辑、混音、母带制作及声音设计。软件安装包小巧,支持多轨录制、灵活路由、自动化、第三方插件和脚本扩展,并提供完整功能的 60 天免费评估期。

    Adobe Audition Windows版
    Adobe Audition Windows版

    Adobe Audition 是面向播客、影视后期、广播与音乐制作的专业音频工作站,提供波形编辑、多轨混音、频谱分析、录音、降噪修复和效果处理等功能。Windows 版通过 Adobe Creative Cloud 安装和管理,

    Pro Tools Windows版
    Pro Tools Windows版

    Pro Tools 是 Avid 推出的专业数字音频工作站,提供多轨录音、音频剪辑、MIDI编曲、插件处理、自动化混音及影视声音制作能力。它适合音乐人、录音师、制作人和音频后期团队使用,并提供免费入门版、订阅方案及永久授权选择。