[算法导论]#1 摊还分析

目录

  • 引言
  • 聚集分析
  • 记账方法
  • 势能法
  • 总结

引言

一个哈希表多大合适?

数据量为\(n?\),如果哈希表无限大(>=\(n?\)),那么时间复杂度是\(O(1)?\)的,不过很显然,虽然节省了时间,但是浪费了空间.

实际上在我们不知道数据量的情况下,我们无法确定哈希表的大小,这时我们有个很美丽的数据结构->动态表

动态表的工作原理

  • 建立一个表,初始化大小为1.
  • 如果表的容量不够,那么就把大小扩大为原来的两倍,将原来表的内容复制一遍
  • 把原来表的内存释放,再执行插入
  • 容量会以1,2,4,8,16……(2的幂次)的增长

接下来我们来分析一下插入操作的复杂度:

  • 当表里存在\(n\)个元素,最坏复杂度是\(O(n)?\)
  • 那\(n\)个元素插入的最坏复杂度是\(O(n^2)?\)

这个复杂度分析肯定是错的,理由是并不是每一项都是最坏的\(O(n)?\)的复杂度

这时就要用到平摊分析了,我们先从最简单的聚集分析说起.

聚集分析

容易发现,\(n\)个元素的插入必然需要一个\(n?\),但是只有当2的幂次的时候才会复制一遍

复杂度应该是:
\[
n+\sum_{j=0}^{\lfloor lg(n-1)\rfloor} 2^j
\]
右边这个最后也不会超过\(2n\)

证明
\[
\sum_{j=0}^{\lfloor log_2(n-1)\rfloor} 2^j<=2n
\]

最后总复杂度为\(3n\),就是\(O(n)\),平均下来每个操作就是\(O(1)\).

用平摊分析来分析一个操作序列,证明每个操作的平均代价很小,尽管有个别操作可能代价很大.值得注意的是这个平均并没有用到概率论.它是最坏情况下的平均操作.就像上面这个例子,平均下来每步操作是常数级别的.\(\frac{O(n)}{n}?\)

综上所述:

  • 平摊分析可以用来证明在一系列操作中,通过对所有操作求平均之后,即使其中单一的操作具有较大的代价,平均代价还是很小的
  • 平摊分析与平均情况分析的不同之处在于它不牵涉到概率
  • 平摊分析保证在最坏情况下,每个操作具有平均性能。

上文采用的方法是聚集分析,在聚集分析中,如证明对所有的n,由n个操作所构成的序列的总时间在最坏情况下为\(O(n)\)。因此,在最坏情况下,每个操作的平均代价(或称平摊分析)为\(\frac{O(n)}{n}\)。请注意这个平摊代价对每个操作都是成立的,即使当序列中存在几种类型的操作时也是一样的。

换句话说,就是对\(n\)条操作整体考虑其复杂度,而不是单独考虑一条指令的最坏复杂度,然后再平摊.

但是,并不是所有情况都能像上文一样轻易地求出平摊复杂度,要采用更精确的方法.

记账方法

算法导论上称为核算法

设想自己是一个财务会计,而你要做的就是给第\(i\)个操作“付钱”,设一个虚构的平摊代价,称之为\(\check C_i\),而每个操作的实际代价为\(C_i\) .

设每一步运算要花费1元.例如执行一次普通的插入操作要花费1元,由空间为2的表扩大为空间为4的表再复制需要2元.

如果还有剩余的钱,那就把钱存起来,用于支付以后的操作.

如果$ \check C_i?$不足以支付给这些操作,那就从银行里取出钱来付款.

存款余额要求不能是负数,当然所有的平摊代价减去操作代价的余额必须是非负数.

也就是相当于
\[
\sum_{i=1}^{n}C_i\leq \sum_{i=1}^{n}\check C_i
\]
以动态表为例:

  • 初始设置\(\check C_i=3?\),其中1元用于插入,2元用于将表翻倍的预存费用.
  • 当表扩大两倍,就从存款里取出1美元来移动新项,还有1美元来移动旧项.
  • 当长度为8的时候:

    里面的数字就是余额,前四个余额为0,这时开始执行插入操作

    花费1元用于插入,余额为2元,插入四个之后:

  • 这时动态表需要扩大两倍,扩大两倍需要多少钱?没错,非常完美地,余额为8刚好可以支付复制操作,然后新插入的第九项也是花费1元进行插入,余额为2元.

通过这个计算,我只需要每个操作预设\(F_i=3\),就可以足够支付了.

这样就可以得到总复杂度是 \(3n\)

当然进行平摊分析并不只有一个可行方案,若将平摊代价设置为4也是可以的,但是设置为2就不行了.

对记账方法进行总结:

在平摊分析的记帐方法中,决定每一个操作的均摊成本,对不同的操作赋予不同的费用,某些操作的费用比它们的实际代价或多或少。我们对一个操作的收费的数量称为平摊代价\(\check C_i?\)。当一个操作的平摊代价超过了它的实际代价$ C_i ?$时,两者的差值就被当作存款,并赋予数据结构中的一些特定对象,可以用来补偿那些平摊代价低于其实际代价的操作。这种方法与聚集分析不同的是,对后者,所有操作都具有相同的平摊代价,对前者,操作的平摊代价被分解为实际代价余额。数据结构中存储的总存款等于总的平摊代价和总的实际代价之差。注意:总存款不能是负的。在开始阶段的存款,是为了在后面的操作序列中再支付。

势能法

好的势能方法,就像初恋一样无法忘怀.

我们由数据结构\(D_0\)开始讲起

  • 操作\(i\)将\(D_{i-1}\)转化为\(D_i\),操作\(i\)的操作代价还是$ C_i $
  • 定义势能函数\(\phi\),将数据结构映射为实数
  • 这样初始的势能是\(\phi (D_0)=0\) ,对于所有\(i\)都有$\phi (D_0) \geq 0 $
  • 平摊代价\(\check C_i=C_i+\phi(D_i)-\phi(D_{i-1})\)
  • \(\Delta \phi_i=\phi(D_i)-\phi(D_{i-1})?\)是势能的改变量

势能法与记账法不同的是后者考虑的是平摊代价,前者考虑的是银行存款,也就是势能函数.

其中:

  • 如果\(\Delta \phi_i \geq 0\) ,第\(i\)次操作存储了后面数据结构所需的代价
  • 如果\(\Delta \phi _i \leq0\), 第\(i\)次操作消耗了之前数据结果存储的代价

平摊代价正确性证明:
\[
\sum _{i=1}^{n}\check C_i = \sum_{i=1}^{n}(C_i+\phi(D_i)-\phi(D_{i-1}))
\]

\[
=\sum_{i=1}^{n}C_i+\phi(D_n)-\phi(D_0)    \phi(D_0)=0   \phi(D_n) \geq 0
\]

\[
\geq \sum_{i=1}^{n}C_i
\]

动态表的势能法分析:

  • 定义势能函数\(\phi(D_i)=2i-2^{\lceil logi \rceil}\)
  • 可得\(\phi(D_0)=2^{log0}=0\)
  • 因为\(\lceil lgi \rceil?\)向上取整,所以最大取到$ lgi +1?$,所以\(2^{\lceil lgi \rceil}?\)最大取到\(2i?\),\(\phi(D_i)\ge0?\)
  • 由$ \check C_i=C_i+\phi(D_i)-\phi(D_{i-1})$
  • 实际代价\(C_i\)由上文可知分两种情况,一般情况下是\(1\),而当\(i-1\)为\(2\)的幂时为\(i\)
    \[
    \phi(D_i)-\phi(D_{i-1})=(2i-2^{\lceil lgi \rceil})-(2(i-1)-2^{\lceil lg(i-1)\rceil})
    \]

    \[
    =2-2^{\lceil lgi \rceil}+2^{\lceil lg(i-1) \rceil}
    \]

  • 分情况分析:当\(i-1\)为\(2\)的幂次时:
    \[
    \check C_i=i+2-2^{\lceil lgi \rceil}+2^{\lceil lg(i-1) \rceil}
    \]

    \[
    = i+2-2(i-1)+i-1
    =3
    \]

  • 其他情况:
    \[
    \check C_i=1+2-2^{\lceil lgi \rceil}+2^{\lceil lg(i-1) \rceil}
    \]

    \[
    =1+2=3
    \]

总结

  • 平摊分析为数据结构的性能提供了一个简洁的抽象概念。
  • 在不关注实时表现,只关注聚集行为时,平摊分析是一种很好的描述方式。
  • 在有些情况中,不同的操作会有不同的平摊代价,它们的和仍然是实际代价的上限。
  • 三种方法都是可用的,但都有各自的适用情况使得它们是简单准确的,不同的方法可能得到不同的上限结果。

原文地址:https://www.cnblogs.com/smallocean/p/12251446.html

时间: 2024-10-07 19:04:02

[算法导论]#1 摊还分析的相关文章

简单理解算法篇--摊还分析

摊还分析是用来评价程序中的一个操作序列的平均代价,有时可能某个操作的代价特别高,但总体上来看也并非那么糟糕,可以形象的理解为把高代价的操作“分摊”到其他操作上去了,要求的就是均匀分摊后的平均代价. 摊还分析有三种常用的技术:聚合分析,核算法,势能法. 首先看个例子,现在有三种操作,push(s),pop(s),mutlipop(s,k),push(s),统称为栈操作. push(s)每次只能压一个数据,所以规定操作的代价为1,pop(s)每次只能弹一个数据,所以也规定操作的代价为1,而mutli

机智零崎不会没梗Ⅲ (摊还分析)

题目描述 零崎总是说自己有一百种梗可玩,然而其实都是假的,是化学成分的,是特技.想要给摊还分析加个梗,实在是不好想,因为这个内容并不是什么算法,而是算法分析. 不过既然还得考,那么没有办法…… “势能法”是摊还分析中一种比较简单常用的方法,而且容易理解.现在零崎有K个硬币,规定每次“翻动”操作只能从最右侧开始翻转硬币,且如果把一个硬币从正面向上翻到背面向上,则需要对其左侧相邻的那个硬币也执行“翻动”操作(翻至最左则结束).定义硬币组的势为硬币中正面向上的硬币的个数.现在要求你求出从某个给定的硬币

算法导论——lec 12 平摊分析与优先队列

在平摊分析中,执行一系列数据结构操作所需要的时间是通过对执行的所有操作求平均得出,反映在任何情况下(即最坏情况下),每个操作具有平均性能.掌握了平摊分析主要有三种方法,聚集分析.记账方法.势能方法.掌握了平摊分析的方法以后,我们就可以利用他来分析一些优先队列. 一. 平摊分析 [问题一]对作用于一个初始为空的栈上的n个PUSH.POP和MULTIPOP组成的序列进行分析. [问题二]考虑一个由0开始向上计数的k位二进制计数器.作用于一个初始为零的计数器上的n个INCREMENT操作的时间分析.

摊还分析

摊还分析 本章内容: 1.聚合分析 2.核算法 3.势能法 4.动态表 一 聚合分析 1. 在摊还分析中,我们求数据结构的一个操作序列中所执行的所有操作的平均时间,来评价操作的代价,它不涉及概率,可以保证最坏情况下每个操作的平均性能. 2. 摊还代价:对所有n,一个n个操作的序列最坏情况下话费时间为T(n),从而摊还代价(平均代价)为 T(n) / n. 3. 栈操作中加入MULTIPOP(S, k),可以同时删除栈顶的k个元素,总元素少于k则全部删除. 下面分析一个由n个PUSH, POP,

算法导论17:摊还分析学习笔记

在摊还分析中,通过求数据结构的一系列的操作的平均时间,来评价操作的代价.这样,即使这些操作中的某个单一操作的代价很高,也可以证明平均代价很低.摊还分析不涉及概率,它可以保证最坏情况下每个操作的平均性能. 摊还分析有三种常用的技术: 聚合分析,它确定$n$个操作的总代价的上界为$T(n)$,所以每个操作的平均代价为$\frac{{T(n)}}{n}$.每个操作都有相同的摊还代价. 核算法:分析每个操作的摊还代价,不同于聚合分析,每种操作的摊还代价是不同的,核算法将序列中较早的操作的余额作为“信用”

算法导论第十九章 斐波那契堆

<算法导论>第二版中在讨论斐波那契堆之前还讨论了二项堆,但是第三版中已经把这块的内容放到思考题中,究极原因我想大概是二项堆只是个引子,目的是为了引出斐波那契堆,便于理解,而且许多经典的算法实现都是基于斐波那契堆,譬如计算最小生成树问题和寻找单源最短路径问题等,此时再把二项堆单独作为一章来讲显然没有必要.类似的堆结构还有很多,如左倾堆,斜堆,二项堆等,下次我打算开一篇博客来记录下它们的异同点. 一.摊还分析(第十七章) 这些高级的数据结构的性能分析一般是基于一个技术——摊还分析,可以理解成一种时

红黑树&mdash;&mdash;算法导论(15)

1. 什么是红黑树 (1) 简介     上一篇我们介绍了基本动态集合操作时间复杂度均为O(h)的二叉搜索树.但遗憾的是,只有当二叉搜索树高度较低时,这些集合操作才会较快:即当树的高度较高(甚至一种极端情况是树变成了1条链)时,这些集合操作并不比在链表上执行的快.     于是我们需要构建出一种"平衡"的二叉搜索树.     红黑树(red-black tree)正是其中的一种.它可以保证在最坏的情况下,基本集合操作的时间复杂度是O(lgn). (2) 性质     与普通二叉搜索树不

算法导论.pdf

下载地址:网盘下载 内容简介  · · · · · · 在有关算法的书中,有一些叙述非常严谨,但不够全面:另一些涉及了大量的题材,但又缺乏严谨性.本书将严谨性和全面性融为一体,深入讨论各类算法,并着力使这些算法的设计和分析能为各个层次的读者接受.全书各章自成体系,可以作为独立的学习单元:算法以英语和伪代码的形式描述,具备初步程序设计经验的人就能看懂:说明和解释力求浅显易懂,不失深度和数学严谨性. 全书选材经典.内容丰富.结构合理.逻辑清晰,对本科生的数据结构课程和研究生的算法课程都是非常实用的教

算法录 之 复杂度分析。

一个算法的复杂度可以说也就是一个算法的效率,一般来说分为时间复杂度和空间复杂度... 注意接下来说的均是比较YY的,适用与ACM等不需严格分析只需要大致范围的地方,至于严格的算法复杂度分析的那些数学证明,主定理什么的在<算法导论>这本书上有十分详细的讲解,网上应该也会有人写过,这里就不多说了(其实,是我不会而已o(╯□╰)o...). — 到底啥是复杂度呢?先来个栗子. 小明有10个苹果,有一天他饿了,然后准备吃掉一个苹果,但是小明有中二病,他要吃里面重量最大的那个,于是...他需要一个找到那