复杂度的均摊分析法
动态数组的尾插push_back有时会触发扩容一旦扩容就要申请更大的内存、搬运旧元素、再插入新元素。某一次操作的代价完全可能是 O(n)O(n)但是动态数组尾插的复杂度是均摊 O(1)O(1)类似的现象其实非常多单看某一次操作它们都可能很贵但把它们放到足够长的操作序列里平均到每一步复杂度却仍然很低。均摊分析研究的正是这种现象。平均情况分析 vs 均摊分析均摊分析和平均情况分析average-case analysis不是同一个概念。平均情况分析通常要假设输入服从某种概率分布然后计算期望成本。比如快速排序的平均复杂度分析核心就在于对输入或主元分布做假设。例如快速排序平均是 O(nlog⁡n)O(nlogn) 的但最坏可能是平方复杂度。均摊分析则不同。它不依赖概率和输入一个 vector 无论怎样尾插均摊复杂度也是 O(1)O(1) 。我们可以定义对于一个数据结构的一段操作序列σ(o1,o2,…,om),σ(o1​,o2​,…,om​),如果总实际成本是C(σ)∑i1mci,C(σ)i1∑m​ci​,能否证明存在某个函数 f(m)f(m)使得C(σ)≤m⋅f(m)。C(σ)≤m⋅f(m)。如果可以那么就说这类操作的均摊复杂度是 f(m)f(m)。可以理解为均摊分析给出的是“整段序列的总账不贵”的承诺。于是均摊 O(1)O(1) 并不意味着每次操作都只花常数时间它真正的含义是在任意长的合法操作序列里总成本相比操作次数的复杂度没有那么高。经典例子动态数组动态数组是本文最好的主线。假设一个动态数组有两个状态量size当前元素个数capacity当前容量执行push_back(x)时若size capacity直接写入成本记为 11若size capacity则申请一个两倍大的新数组把旧元素全部搬过去再插入新元素。若旧容量为 kk那么这次成本记为 k1k1。单次最坏显然是线性的但长期看却是均摊常数。下面分别用三种方法来理解它。聚合法直接算前 nn 次操作的总成本聚合法直接计算多步的总成本。由于每次扩容是两倍数组容量会按 1,2,4,8,…1,2,4,8,… 这样翻倍增长。做完前 nn 次插入时普通写入本身一共发生了 nn 次成本是 nn。除此之外还会发生若干次扩容搬运搬运量依次是 124⋯2k−1,124⋯2k−1,其中 2k−1n≤2k2k−1n≤2k 。于是124⋯2k−12k≤2n。124⋯2k−12k≤2n。所以总成本满足C(n)≤n2n3n。C(n)≤n2n3n。也就是说前 nn 次push_back的总成本是 O(n)O(n)因此平均到每次操作复杂度就是 O(1)O(1)。这个证明非常重要因为它第一次把“偶尔很贵”和“长期很便宜”这两个看似矛盾的结论接起来了。扩容确实贵但扩容发生得足够稀疏所以总账仍然可控。记账法平时多收一点留着给扩容买单记账法比聚合法更有“预算”的味道。我们不直接算总账而是假装给每次操作都规定一个均摊收费标准。还是看动态数组尾插。设每次push_back都收费常数代价 33。如果这次没有扩容真实成本只有 11那就剩下 22 存起来如果这次触发扩容就从之前存下来的余额里支付搬运成本。为什么这个方案可行考虑一次从容量 mm 扩到 2m2m 的扩容。在这次扩容发生前数组已经经历了从半满到装满的一系列普通插入。也就是说每次扩容时前面都有发生了足够多大约 m/2m/2 的便宜插入每次都能攒出足够余额总共可以积累出足以覆盖这次搬运的资金。势能法从记账的思想更进一步我们就可以引出势能法。它的思想是给数据结构状态 DiDi​ 定义一个势能函数 Φ(Di)Φ(Di​)然后把第 ii 次操作的均摊成本定义为c^iciΦ(Di)−Φ(Di−1)。c^i​ci​Φ(Di​)−Φ(Di−1​)。这里cici​ 是第 ii 次操作的真实成本c^ic^i​ 是我们定义出来的均摊成本Φ(Di)−Φ(Di−1)Φ(Di​)−Φ(Di−1​) 表示状态势能的变化。这样一次操作的均摊成本就是他的实际成本 势能变化如果我们能选取出合适的势能函数表示当前状态要保证势能始终非负并且初始势能为 00那么对前 mm 次操作有∑i1mc^i∑i1mciΦ(Dm)−Φ(D0)≥∑i1mci。i1∑m​c^i​i1∑m​ci​Φ(Dm​)−Φ(D0​)≥i1∑m​ci​。所以只要每一步的均摊成本都有常数上界那么真实总代价也就有同阶上界。对动态数组一个经典势能函数是Φ2⋅size−capacity。Φ2⋅size−capacity。这个定义的直觉是数组越接近装满也就越接近下一次扩容势能越大。对于不扩容的普通插入。真实成本 1势能变化 2因为size增加 1而capacity不变均摊代价 3对于触发扩容的插入。插入前size mcapacity m势能是 ΦoldmΦold​m插入后size m1capacity 2m势能变成Φnew2(m1)−2m2。Φnew​2(m1)−2m2。这次真实成本是搬运 mm 个旧元素再插入新元素共 m1m1势能变化是 ΔΦ2−m。ΔΦ2−m。。所以均摊成本为 33不扩容时是 33扩容时还是 33。因此动态数组尾插的均摊复杂度就是 O(1)O(1)。其他常见例子栈的MULTIPOP考虑一个支持三种操作的栈PUSH(x)压栈成本为 11POP()弹栈成本为 11MULTIPOP(k)连续弹出最多 kk 个元素成本等于实际弹出的元素数。单看一次MULTIPOP(k)它当然可能要弹很多元素代价不是常数。但如果看一整段操作序列总弹出次数其实不可能超过总压栈次数。因为每个元素最多只会被压入一次、弹出一次。因此如果总共有 mm 次操作那么所有弹栈动作加起来不会超过线性级别于是总成本是 O(m)O(m)均摊每次仍是 O(1)O(1)。这个例子特别适合作为均摊分析的第一个训练只要能发现“每个元素最多被贵处理一次”总成本往往就很好控制。二进制计数器的自增再看一个更经典的例子。一个二进制计数器不断执行INCREMENT一次操作的成本定义为被翻转的位数。

相关新闻

JMeter 2.6多线程压力测试实战指南:从脚本设计到结果分析

JMeter 2.6多线程压力测试实战指南:从脚本设计到结果分析

1. 项目概述:为什么我们需要一个实战指南?如果你做过性能测试,尤其是接口或者Web应用的压力测试,那你大概率听说过或者用过Apache JMeter。它是一个老牌的开源性能测试工具,功能强大,社区活跃,但…

2026/6/25 15:04:27阅读更多 →
轻量级大模型边缘部署:Open Assistant工程实践指南

轻量级大模型边缘部署:Open Assistant工程实践指南

1. 项目概述:这不是另一个“开源LLM套壳”,而是一套轻量级大模型落地的完整工程范式“Inside Open Assistant: The Open Source Platform for Light, High-Performance LLMs”——这个标题里藏着三个被行业反复误读却极少被真正拆解的关键词:…

2026/6/25 15:04:27阅读更多 →
AI音乐跨风格重编曲工具全解析:合规改编与自然风格切换指南

AI音乐跨风格重编曲工具全解析:合规改编与自然风格切换指南

音乐改编与Remix是内容创作的高频需求,无论是短视频BGM换风格、老素材二次创作,还是个人音乐二创,都希望在保留原曲核心旋律的基础上,实现自然的曲风转换。但在实际操作中,创作者常面临三大痛点:一是版权风…

2026/6/25 15:04:27阅读更多 →
【AI】Codex 的工作流更新-v3 [Codex-maxxing for long-running work]

【AI】Codex 的工作流更新-v3 [Codex-maxxing for long-running work]

Codex 工作流更新-v3 最近 OpenAI 的一篇博客: Codex-maxxing for long-running work 分享了关于长周期复杂任务的指南,并针对我已有的工作流作出一些更新。 长周期的复杂任务通常不是一次 prompt 改完代码就结束。它可能要经历调查、实现、预览、反馈…

2026/6/25 16:34:51阅读更多 →
AI/ML论文核心句:如何写出一句精准的Thesis Statement

AI/ML论文核心句:如何写出一句精准的Thesis Statement

1. 为什么一句“ thesis statement”能决定你AI/ML论文的生死线刚带完今年第三组硕士生开题,有位同学交来初稿,标题是《基于Transformer的多模态情感分析研究》,全文写得密密麻麻,模型结构图画了四页,实验表格堆了十七…

2026/6/25 16:34:51阅读更多 →
Ryujinx Nintendo Switch模拟器深度解析与实战指南

Ryujinx Nintendo Switch模拟器深度解析与实战指南

Ryujinx Nintendo Switch模拟器深度解析与实战指南 【免费下载链接】Ryujinx 用 C# 编写的实验性 Nintendo Switch 模拟器 项目地址: https://gitcode.com/GitHub_Trending/ry/Ryujinx Ryujinx是一款基于C#开发的Nintendo Switch模拟器,为技术爱好者和游戏玩…

2026/6/25 16:34:51阅读更多 →
Android 架构组件官方示例集:Google 手把手教你写规范代码

Android 架构组件官方示例集:Google 手把手教你写规范代码

文章目录Android 架构组件官方示例集:Google 手把手教你写规范代码具体包含哪些示例为什么值得看适合谁Android 架构组件官方示例集:Google 手把手教你写规范代码 做 Android 开发的人都知道,写一个能跑的 App 不难,难的是写一个…

2026/6/25 16:34:51阅读更多 →
OpenClaw:让 AI 拥有执行能力的开源自主智能体框架一、何为 OpenClaw?从聊天 AI 到实干型数字助手

OpenClaw:让 AI 拥有执行能力的开源自主智能体框架一、何为 OpenClaw?从聊天 AI 到实干型数字助手

在大模型普及的当下,绝大多数 AI 工具仅停留在文字问答、内容生成层面,只能输出方案却无法落地执行。OpenClaw 的出现补齐了这一短板,它是一套开源、本地优先、全自主可控的 AI 智能体自动化框架,业内俗称 “龙虾”,由…

2026/6/25 16:34:51阅读更多 →
Hadoop练习卷大题部分简洁答案

Hadoop练习卷大题部分简洁答案

一、hadoop 集群,负责资源的管理和调度组件HDFS 操作:使用 hadoop fs 命令查看文件(查看文件名称、文件的大小等)Hive 中数据的存储格式,了解每一种存储格式的适合存储什么样的类型的数据Linux 中权限的设置&#xff0…

2026/6/25 16:29:50阅读更多 →
【人工智能】一文搞定到底什么是智能体

【人工智能】一文搞定到底什么是智能体

【人工智能】一文搞定到底什么是智能体 一文搞定到底什么是智能体【人工智能】一文搞定到底什么是智能体一. LM,WorkFlow,Agent分别有什么么不同二. Agent的思考过程是怎样的三. Agent的五个核心部分1)LLM2)Prompt3)Me…

2026/6/25 9:39:54阅读更多 →
嵌入式GUI控件实战:ROTARY、SCROLLBAR、SLIDER原理与应用

嵌入式GUI控件实战:ROTARY、SCROLLBAR、SLIDER原理与应用

1. 嵌入式GUI控件:从原理到实战的深度解析在嵌入式系统开发中,图形用户界面(GUI)的设计与实现往往是项目从“能用”到“好用”的关键一跃。不同于资源充沛的PC或移动平台,嵌入式设备的GUI需要在有限的CPU性能、内存空间…

2026/6/25 2:52:24阅读更多 →
Google AI Studio 300美元额度的真相与实战指南

Google AI Studio 300美元额度的真相与实战指南

1. 这300美金不是“送钱”,而是Google埋下的第一道技术门槛 你看到标题里那个醒目的“$300美金”时,第一反应可能是:又一个免费额度?领完就完事?我亲手试过——这300美金根本不是红包,而是一张入场券&…

2026/6/25 9:01:34阅读更多 →
面试辅助工具横评:我试了5款AI面试工具,最后留下了OfferGo

面试辅助工具横评:我试了5款AI面试工具,最后留下了OfferGo

上半年跳槽,面了十几家公司。说句实话,不是能力不行,是面试现场太容易崩了。 明明准备了一周,面试官换个问法脑子就一片白。面完之后那个懊悔——其实我会的。 后来开始试市面上的AI面试辅助工具。前前后后装了5款,踩…

2026/6/25 11:52:11阅读更多 →
Claude Code 提示词设计:从塑造“人格”到建立“状态机”

Claude Code 提示词设计:从塑造“人格”到建立“状态机”

当前 AI Agent 设计的核心痛点在于:大模型不缺写代码的能力,缺的是克制力、边界感和验证逻辑。Prompt 不再是用来塑造“人格”的,而是用来建立“状态机(State Machine)”和“行为门禁(Guardrails&#xff0…

2026/6/25 11:52:11阅读更多 →
MC-037 | 自定义 Skill 开发:创建你的AI能力模块

MC-037 | 自定义 Skill 开发:创建你的AI能力模块

MONKEYCODE 教程系列 MonkeyCode教程及推广系列 MC-037 自定义 Skill 开发:创建你的AI能力模块 >官网链接注册更放心哦https://monkeycode-ai.com/?ic019e0aed-c823-783c-b08a-4f030f891e4e 系列: 不爱土豆唯爱马铃薯 MonkeyCode 教程系列 字数: 约 1400 字…

2026/6/25 11:52:11阅读更多 →