前言
整理了一些长相清奇的时间复杂度分析……
约定:
1.如果没有特殊说明,默认
T
(
0
)
=
T
(
1
)
=
1
T(0)=T(1)=1
T(0)=T(1)=1
2.如果没有特殊说明,默认log的底数为2。
3.一些地方会说
T
(
n
)
=
O
(
.
.
.
)
T(n)=O(...)
T(n)=O(...),意会就好qwq
0.一些定义
0.1 大O记号定义
对于函数 f , g f,g f,g,若 ∃ \exist ∃常数 n 0 , c n_0,c n0,c,使得对于 ∀ n > n 0 \forall n>n_0 ∀n>n0, f ( n ) < c ∗ g ( n ) f(n)<c*g(n) f(n)<c∗g(n),那么说 f ( n ) f(n) f(n)是 O ( g ( n ) ) O(g(n)) O(g(n))的,即 f ( n ) ∈ O ( g ( n ) ) f(n)\in O(g(n)) f(n)∈O(g(n))。
0.2 时间复杂度定义
对于一个程序所需要执行的运算次数
T
(
n
)
T(n)
T(n),若
T
(
n
)
∈
O
(
f
(
n
)
)
T(n)\in O(f(n))
T(n)∈O(f(n)),则把
O
(
f
(
n
)
)
O(f(n))
O(f(n))称为这个程序的时间复杂度。
例如当
T
(
n
)
=
1
3
n
3
+
100
n
+
10086
T(n)=\frac{1}{3}n^3+100n+10086
T(n)=31n3+100n+10086时,我们说这个程序的时间复杂度是
O
(
n
3
)
O(n^3)
O(n3)。证明是显然的,随便取个
n
0
=
100
,
c
=
100
n_0=100,c=100
n0=100,c=100就可以了,不多说。
当然,上面的
T
(
n
)
T(n)
T(n)也可以说是
O
(
n
4
)
O(n^4)
O(n4)的,这并不矛盾。一般来说,我们用的时间复杂度是增长速度尽量慢的,也就是说取尽量贴近实际的
T
(
n
)
T(n)
T(n)的增长速度的复杂度。所以一般我们用
O
(
n
3
)
O(n^3)
O(n3)而不是
O
(
n
4
)
O(n^4)
O(n4)来表示上面的
T
(
n
)
T(n)
T(n)。
再举几个例子:
T
(
n
)
=
n
+
l
o
g
n
T(n)=n+logn
T(n)=n+logn,那么
T
(
n
)
T(n)
T(n)是
O
(
n
)
O(n)
O(n)的。对于
n
>
10
n>10
n>10,
n
+
l
o
g
n
<
2
n
n+logn<2n
n+logn<2n。
T
(
n
)
=
2
n
+
l
o
g
n
=
n
2
n
T(n)=2^{n+logn}=n2^n
T(n)=2n+logn=n2n,
T
(
n
)
T(n)
T(n)是
O
(
n
2
n
)
O(n2^n)
O(n2n)的。注意这里不能从
n
+
l
o
g
n
n+logn
n+logn是
O
(
n
)
O(n)
O(n)的推出
2
n
+
l
o
g
n
2^{n+logn}
2n+logn是
2
n
2^n
2n的,要注意。至于为什么这个不是
O
(
2
n
)
O(2^n)
O(2n),因为
n
0
n_0
n0和
c
c
c必须是
常数
\color{red}常数
常数。
1.基本时间复杂度分析
1.0 主定理
对于递归函数,如果满足
T
(
n
)
=
a
T
(
n
b
)
+
f
(
n
)
T(n)=aT(\frac{n}{b})+f(n)
T(n)=aT(bn)+f(n),分类讨论:
假设
c
c
c是一个正常数。
(1)若
f
(
n
)
=
n
l
o
g
b
a
f(n)=n^{log_ba}
f(n)=nlogba,那么
T
(
n
)
=
O
(
n
l
o
g
b
a
l
o
g
n
)
T(n)=O(n^{log_ba}logn)
T(n)=O(nlogbalogn)
(2)若
f
(
n
)
=
n
l
o
g
b
a
−
c
f(n)=n^{log_ba-c}
f(n)=nlogba−c,那么
T
(
n
)
=
O
(
n
l
o
g
b
a
)
T(n)=O(n^{log_ba})
T(n)=O(nlogba)
(3)若
f
(
n
)
=
n
l
o
g
b
a
+
c
f(n)=n^{log_ba+c}
f(n)=nlogba+c,且对于所有足够大的
n
n
n有
a
f
(
n
b
)
<
f
(
n
)
af(\frac{n}{b})<f(n)
af(bn)<f(n),那么
T
(
n
)
=
O
(
f
(
n
)
)
T(n)=O(f(n))
T(n)=O(f(n))
1.1 线性递推式
1.
T
(
n
)
=
T
(
n
−
1
)
+
c
1.T(n)=T(n-1)+c
1.T(n)=T(n−1)+c(
c
c
c是常数),则
T
(
n
)
=
O
(
c
n
)
T(n)=O(cn)
T(n)=O(cn)
2.
T
(
n
)
=
T
(
n
−
1
)
+
n
2.T(n)=T(n-1)+n
2.T(n)=T(n−1)+n,则
T
(
n
)
=
O
(
n
2
)
T(n)=O(n^2)
T(n)=O(n2)
奇水……
1.2 普通分治
T
(
n
)
=
2
T
(
n
2
)
+
n
T(n)=2T(\frac{n}{2})+n
T(n)=2T(2n)+n,则
T
(
n
)
=
O
(
n
l
o
g
n
)
T(n)=O(nlogn)
T(n)=O(nlogn)
证明:展开,
T
(
n
)
=
O
(
n
)
+
2
T
(
n
2
)
T(n)=O(n)+2T(\frac{n}{2})
T(n)=O(n)+2T(2n)
=
O
(
n
)
+
2
∗
O
(
n
2
)
+
4
T
(
n
4
)
=O(n)+2*O(\frac{n}{2})+4T(\frac{n}{4})
=O(n)+2∗O(2n)+4T(4n)
=
.
.
.
=...
=...
=
O
(
n
)
+
O
(
n
)
+
.
.
.
+
O
(
n
)
=O(n)+O(n)+...+O(n)
=O(n)+O(n)+...+O(n) (每次除以
2
2
2,除
l
o
g
n
logn
logn次到1,所以共
l
o
g
n
logn
logn个
O
(
n
)
O(n)
O(n))
=
O
(
n
l
o
g
n
)
=O(nlogn)
=O(nlogn)
主定理版:
a
=
2
,
b
=
2
,
l
o
g
b
a
=
l
o
g
2
2
=
1
a=2,b=2,log_ba=log_22=1
a=2,b=2,logba=log22=1
f
(
n
)
=
O
(
n
1
)
=
O
(
n
l
o
g
b
a
)
f(n)=O(n^1)=O(n^{log_ba})
f(n)=O(n1)=O(nlogba)(打不出中间有一横的符号……意会一下qwq)
=
>
T
(
n
)
=
O
(
f
(
n
)
∗
l
o
g
n
)
=
O
(
n
l
o
g
n
)
=>T(n)=O(f(n)*logn)=O(nlogn)
=>T(n)=O(f(n)∗logn)=O(nlogn)
1.3 诡异的分治(也许这不是分治……)
T
(
n
)
=
2
T
(
n
2
)
+
k
T(n)=2T(\frac{n}{2})+k
T(n)=2T(2n)+k,则
T
(
n
)
=
O
(
n
k
)
T(n)=O(nk)
T(n)=O(nk)
证明:展开,
T
(
n
)
=
O
(
k
)
+
2
T
(
n
2
)
T(n)=O(k)+2T(\frac{n}{2})
T(n)=O(k)+2T(2n)
=
O
(
k
)
+
2
O
(
k
)
+
4
T
(
n
4
)
=O(k)+2O(k)+4T(\frac{n}{4})
=O(k)+2O(k)+4T(4n)
=
.
.
.
=...
=...
=
O
(
k
)
+
2
O
(
k
)
+
4
O
(
k
)
+
.
.
.
+
2
t
−
1
O
(
k
)
+
2
t
T
(
1
)
=O(k)+2O(k)+4O(k)+...+2^{t-1}O(k)+2^{t}T(1)
=O(k)+2O(k)+4O(k)+...+2t−1O(k)+2tT(1) (为了方便,记
t
=
l
o
g
n
t=logn
t=logn)
=
(
2
t
−
1
)
O
(
k
)
+
O
(
2
t
+
1
)
=(2^{t}-1)O(k)+O(2^{t+1})
=(2t−1)O(k)+O(2t+1)
=
O
(
n
k
)
+
O
(
2
n
)
=O(nk)+O(2n)
=O(nk)+O(2n)
=
O
(
n
k
)
=O(nk)
=O(nk)
主定理:????
1.4 玄学分治
T
(
n
)
=
2
T
(
n
2
)
+
n
l
o
g
n
T(n)=2T(\frac{n}{2})+nlogn
T(n)=2T(2n)+nlogn,则
T
(
n
)
=
O
(
n
l
o
g
2
n
)
T(n)=O(nlog^2n)
T(n)=O(nlog2n)
证明:考虑
T
(
2
n
)
T(2^n)
T(2n)
T
(
2
n
)
=
2
T
(
2
n
−
1
)
+
2
n
∗
n
T(2^n)=2T(2^{n-1})+2^n*n
T(2n)=2T(2n−1)+2n∗n
=
2
(
2
T
(
2
n
−
2
)
+
2
n
−
1
∗
(
n
−
1
)
)
+
2
n
∗
n
=2(2T(2^{n-2})+2^{n-1}*(n-1))+2^n*n
=2(2T(2n−2)+2n−1∗(n−1))+2n∗n
=
4
T
(
2
n
−
2
)
+
2
n
∗
(
n
−
1
)
+
2
n
∗
n
=4T(2^{n-2})+2^n*(n-1)+2^n*n
=4T(2n−2)+2n∗(n−1)+2n∗n
=
.
.
.
=...
=...
=
O
(
2
n
)
∗
1
+
O
(
2
n
)
∗
2
+
.
.
.
+
O
(
2
n
)
∗
n
=O(2^n)*1+O(2^n)*2+...+O(2^n)*n
=O(2n)∗1+O(2n)∗2+...+O(2n)∗n
=
O
(
2
n
n
2
)
=O(2^nn^2)
=O(2nn2)
然后
T
(
n
)
=
T
(
2
l
o
g
n
)
=
O
(
2
l
o
g
n
(
l
o
g
n
)
2
)
=
O
(
n
l
o
g
2
n
)
T(n)=T(2^{logn})=O(2^{logn}(logn)^2)=O(nlog^2n)
T(n)=T(2logn)=O(2logn(logn)2)=O(nlog2n)
之前尝试用数学归纳法……发现竟然弄出普通分治也是
O
(
n
l
o
g
2
n
)
O(nlog^2n)
O(nlog2n)……然后才发现那样用数学归纳法是不严谨的……
主定理版:
a
=
2
,
b
=
2
,
l
o
g
b
a
=
l
o
g
2
2
=
1
a=2,b=2,log_ba=log_22=1
a=2,b=2,logba=log22=1
f
(
n
)
=
O
(
n
l
o
g
n
)
=
O
(
n
l
o
g
b
a
l
o
g
n
)
f(n)=O(nlogn)=O(n^{log_ba}logn)
f(n)=O(nlogn)=O(nlogbalogn)
=
>
T
(
n
)
=
O
(
f
(
n
)
∗
l
o
g
n
)
=
O
(
n
l
o
g
2
n
)
=>T(n)=O(f(n)*logn)=O(nlog^2n)
=>T(n)=O(f(n)∗logn)=O(nlog2n)
2.长相奇特的递归式
2.1 巨神mhy弄出的奇怪东西
有一次巨神mhy在CF比赛的时候弄出一个
T
(
n
)
=
2
T
(
n
)
+
l
o
g
n
T(n)=2T(\sqrt n)+logn
T(n)=2T(n)+logn的东西……
那么
T
(
n
)
=
O
(
l
o
g
n
∗
l
o
g
l
o
g
n
)
T(n)=O(logn*loglogn)
T(n)=O(logn∗loglogn)
证明:上式不好直接证,考虑它的等价形式:
因为
2
l
o
g
n
=
n
2^{logn}=n
2logn=n,所以上式等价于
T
(
2
n
)
=
O
(
n
l
o
g
n
)
T(2^n)=O(nlogn)
T(2n)=O(nlogn)
由已知,
T
(
2
n
)
=
2
T
(
2
n
)
+
O
(
l
o
g
(
2
n
)
)
T(2^n)=2T(\sqrt{2^n})+O(log(2^n))
T(2n)=2T(2n)+O(log(2n))
化简,
T
(
2
n
)
=
2
T
(
2
n
2
)
+
O
(
n
)
T(2^n)=2T(2^\frac{n}{2})+O(n)
T(2n)=2T(22n)+O(n)
发现
n
n
n每次都变成
n
2
\frac{n}{2}
2n,所以类比普通分治的证明,
T
(
2
n
)
=
O
(
n
l
o
g
n
)
T(2^n)=O(nlogn)
T(2n)=O(nlogn)
于是
T
(
n
)
=
O
(
l
o
g
n
l
o
g
l
o
g
n
)
T(n)=O(lognloglogn)
T(n)=O(lognloglogn)
主定理:????
2.2 一道诡异的初赛题
给出式子
T
(
n
)
=
2
T
(
n
4
)
+
n
T(n)=2T(\frac{n}{4})+\sqrt n
T(n)=2T(4n)+n
感觉比上面的那一个还水……思路很自然qwq
同样考虑
T
(
4
n
)
=
2
T
(
4
n
−
1
)
+
4
n
T(4^n)=2T(4^{n-1})+\sqrt{4^n}
T(4n)=2T(4n−1)+4n
=
2
(
2
T
(
4
n
−
2
)
+
4
n
−
1
)
+
2
n
=2(2T(4^{n-2})+\sqrt{4^{n-1}})+2^n
=2(2T(4n−2)+4n−1)+2n
=
4
T
(
4
n
−
2
)
+
2
∗
4
n
−
1
+
2
n
=4T(4^{n-2})+2*\sqrt{4^{n-1}}+2^n
=4T(4n−2)+2∗4n−1+2n
=
4
T
(
4
n
−
2
)
+
2
n
+
2
n
=4T(4^{n-2})+2^n+2^n
=4T(4n−2)+2n+2n
=
.
.
.
=...
=...
=
2
n
T
(
1
)
+
2
n
+
2
n
+
.
.
.
+
2
n
=2^nT(1)+2^n+2^n+...+2^n
=2nT(1)+2n+2n+...+2n (共
n
n
n个
2
n
2^n
2n)
=
O
(
2
n
∗
n
)
=O(2^n*n)
=O(2n∗n)
然后
T
(
n
)
=
T
(
4
l
o
g
4
n
)
=
O
(
2
l
o
g
4
n
l
o
g
4
n
)
T(n)=T(4^{log_4n})=O(2^{log_4n}log_4n)
T(n)=T(4log4n)=O(2log4nlog4n)
因为
4
l
o
g
4
n
=
n
4^{log_4n}=n
4log4n=n,所以
2
l
o
g
4
n
=
n
2^{log_4n}=\sqrt n
2log4n=n,而
l
o
g
4
n
log_4n
log4n与
l
o
g
n
logn
logn同级
所以
T
(
n
)
=
O
(
n
l
o
g
n
)
T(n)=O(\sqrt n logn)
T(n)=O(nlogn)
主定理版:
a
=
2
,
b
=
4
,
l
o
g
b
a
=
l
o
g
4
2
=
0.5
a=2,b=4,log_ba=log_42=0.5
a=2,b=4,logba=log42=0.5
f
(
n
)
=
O
(
n
)
=
O
(
n
1
2
)
=
O
(
n
l
o
g
b
a
)
f(n)=O(\sqrt n)=O(n^\frac{1}{2})=O(n^{log_ba})
f(n)=O(n)=O(n21)=O(nlogba)
=
>
T
(
n
)
=
O
(
f
(
n
)
∗
l
o
g
n
)
=
O
(
n
l
o
g
n
)
=>T(n)=O(f(n)*logn)=O(\sqrt nlogn)
=>T(n)=O(f(n)∗logn)=O(nlogn)
2.3 恶臭学军题
T
(
n
)
=
25
T
(
n
5
)
+
n
n
T(n)=25T(\frac{n}{5})+n\sqrt n
T(n)=25T(5n)+nn
考虑
T
(
5
n
)
=
25
T
(
5
n
−
1
)
+
5
n
5
n
T(5^n)=25T(5^{n-1})+5^n\sqrt{5^n}
T(5n)=25T(5n−1)+5n5n
=
2
5
2
T
(
5
n
−
2
)
+
25
∗
5
n
−
1
5
n
−
1
+
5
n
∗
s
q
r
t
5
n
=25^2T(5^{n-2})+25*5^{n-1}\sqrt{5^{n-1}}+5^n*sqrt{5^n}
=252T(5n−2)+25∗5n−15n−1+5n∗sqrt5n
=
.
.
.
=...
=...
=
2
5
n
T
(
1
)
+
2
5
n
−
1
5
5
+
2
5
n
−
2
25
25
+
.
.
.
+
5
n
5
n
=25^nT(1)+25^{n-1}5\sqrt 5+25^{n-2}25\sqrt{25}+...+5^n\sqrt{5^n}
=25nT(1)+25n−155+25n−22525+...+5n5n
=
5
4
n
+
5
4
n
−
1
+
5
4
n
−
2
+
.
.
.
+
5
3
n
=\sqrt{5^{4n}}+\sqrt{5^{4n-1}}+\sqrt{5^{4n-2}}+...+\sqrt{5^{3n}}
=54n+54n−1+54n−2+...+53n
=
5
4
n
+
1
−
5
3
n
5
−
1
=\frac{\sqrt{5^{4n+1}}-\sqrt{5^{3n}}}{\sqrt 5-1}
=5−154n+1−53n (等比数列求和)
=
5
∗
5
2
n
−
5
n
5
n
5
−
1
=\frac{\sqrt 5*5^{2n}-5^n\sqrt{5^n}}{\sqrt 5-1}
=5−15∗52n−5n5n
把
5
n
5^n
5n换成
n
n
n,得
T
(
n
)
=
5
n
2
−
n
n
5
−
1
=
O
(
n
2
)
T(n)=\frac{\sqrt 5n^2-n\sqrt n}{\sqrt 5-1}=O(n^2)
T(n)=5−15n2−nn=O(n2)
主定理版:
a
=
25
,
b
=
5
,
f
(
n
)
=
O
(
n
n
)
=
O
(
n
1.5
)
a=25,b=5,f(n)=O(n\sqrt n)=O(n^{1.5})
a=25,b=5,f(n)=O(nn)=O(n1.5)
l
o
g
b
a
=
l
o
g
5
25
=
2
log_ba=log_5{25}=2
logba=log525=2
f
(
n
)
=
O
(
n
1.5
)
=
O
(
n
l
o
g
b
a
−
0.5
)
f(n)=O(n^{1.5})=O(n^{log_ba-0.5})
f(n)=O(n1.5)=O(nlogba−0.5)
=
>
T
(
n
)
=
O
(
n
l
o
g
b
a
)
=
O
(
n
2
)
=>T(n)=O(n^{log_ba})=O(n^2)
=>T(n)=O(nlogba)=O(n2)
2.4 证明主定理
3.摊还分析
注:为了方便,部分内容里写了 O ( 0 ) O(0) O(0)qwq(不严谨,但是是这个意思)
3.1 进栈1个/出栈k个
你需要维护一个栈,初始为空,要求资磁两种操作:
1.把
x
x
x压进栈
2.弹出
k
k
k个元素(
k
≤
k\le
k≤ 栈大小)
总共
q
q
q中操作,栈大小
<
=
n
<=n
<=n
暴力即珂……时间复杂度?1操作
O
(
1
)
O(1)
O(1),2操作
O
(
k
)
O(k)
O(k)
时间复杂度
O
(
q
k
)
=
O
(
n
q
)
?
O(qk)=O(nq)?
O(qk)=O(nq)?
口胡出时间复杂度为线性qwq
发现每次弹出 k k k个元素, k k k的范围是与栈大小,也就是有多少个 x x x没被弹出的1操作有关。
核算法:(核算法大法吼!)
每一个1操作,以后最多把这个元素弹出一次(废话qwq)
记1操作的摊还代价为
1
1
1,则2操作的复杂度变成
O
(
0
)
O(0)
O(0)
然后1操作的总代价为
O
(
1
)
O(1)
O(1),共
q
q
q次操作,时间复杂度
O
(
q
)
O(q)
O(q)
聚合分析:(聚合分析也还珂以)
发现如果1操作有
x
x
x个,那么2操作的总时间复杂度最高为
O
(
x
)
O(x)
O(x)
所以考虑最坏情况,1操作有
q
q
q个时,2操作的总时间复杂度为
O
(
q
)
O(q)
O(q)
所以总时间复杂度为
O
(
q
)
+
O
(
q
)
=
O
(
q
)
O(q)+O(q)=O(q)
O(q)+O(q)=O(q)
势能法:(恶臭)
势能法蜃孙……
令
T
(
i
,
势能
)
T(i,势能)
T(i,势能)表示前
i
i
i次操作珂能达到的最高复杂度(即势能qwq),
T
(
i
,
实际
)
T(i,实际)
T(i,实际)表示前
i
i
i次操作实际达到的复杂度。
令
f
(
i
)
f(i)
f(i)表示执行了第
i
i
i个操作后的势能
势能公式:
T
(
i
)
=
T
(
i
,
实际
)
+
f
(
i
)
−
f
(
i
−
1
)
T(i)=T(i,实际)+f(i)-f(i-1)
T(i)=T(i,实际)+f(i)−f(i−1)
即:第
i
i
i步操作的(最后平均)总代价等于第
i
i
i步操作的实际代价加上从第
i
−
1
i-1
i−1步操作到第
i
i
i步操作的势能变化。
回到例子,让势能=栈中有多少个元素,那么1操作会让势能+1,2操作会让势能-k。
于是1操作的总代价为
1
+
1
=
2
1+1=2
1+1=2,2操作总代价为
k
−
k
=
0
k-k=0
k−k=0
因此1操作总复杂度为
O
(
1
)
O(1)
O(1),2操作总复杂度为
O
(
0
)
O(0)
O(0)
最后的总复杂度为
O
(
q
)
O(q)
O(q)
恶臭无比……
3.2 bzoj3133 ball machine复杂度分析
推销一波题解
懒得写了……和3.1没多大差别……去题解里看吧qwq
3.3 表扩张(vector的push_back?)
维护一个数组,初始大小为1,要求资磁插入一个数,当数组满了的时候,开一个大小为原来的两倍的数组,把当前的数据复制过去。(规定单次扩容复杂度为
O
(
扩容前数组大小
)
O(扩容前数组大小)
O(扩容前数组大小))
每一次最坏复杂度为
O
(
n
)
O(n)
O(n)……时间复杂度
O
(
n
2
)
O(n^2)
O(n2)?
一共
l
o
g
n
logn
logn次扩容,每次
O
(
n
)
O(n)
O(n),时间复杂度
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)?
然而并不是qwq
核算法:(蜃香)
每次把数组扩大到原来的两倍的时候,这
O
(
n
)
O(n)
O(n)的复杂度均摊到每个插入操作上qwq
于是每个插入操作的摊还代价为
O
(
1
)
O(1)
O(1),扩容操作变为
O
(
0
)
O(0)
O(0)
插入操作总复杂度是
O
(
1
)
O(1)
O(1),所以最后总复杂度
O
(
n
)
O(n)
O(n)
聚合分析:
假设最后数组大小为
n
n
n,则扩容了
l
o
g
n
logn
logn次
扩容复杂度为
O
(
1
)
+
O
(
2
)
+
O
(
4
)
+
.
.
.
+
O
(
2
l
o
g
n
)
=
O
(
n
)
O(1)+O(2)+O(4)+...+O(2^{logn})=O(n)
O(1)+O(2)+O(4)+...+O(2logn)=O(n)
插入复杂度为
O
(
1
)
∗
n
=
O
(
n
)
O(1)*n=O(n)
O(1)∗n=O(n)
所以总复杂度为
O
(
n
)
O(n)
O(n)
势能法:(恶臭)
还没想到什么直观的势能函数……但是想到一个诡异的东西不知道是否正确……口胡一波qwq
令1操作的势能变化为1(意义大概是在扩容的道路上走了多远?),那么2操作的势能变化为-n。
口胡得出1操作总代价为
O
(
1
)
O(1)
O(1),2操作总代价为
O
(
0
)
O(0)
O(0)
于是总复杂度为
O
(
n
)
O(n)
O(n)
//两条分割线以表敬意
令势能函数
f
(
i
)
=
2
n
u
m
−
s
i
z
f(i)=2num-siz
f(i)=2num−siz,其中
n
u
m
num
num表示数组内元素的个数,
s
i
z
siz
siz表示数组大小。
易证若一个插入操作没有触发扩容,引起的势能变化是2。摊还代价为
O
(
1
)
O(1)
O(1)。
若某次插入操作引起了扩容,假设插入前的数组大小是
n
n
n,那么里面的元素个数也是
n
n
n。
扩容前:势能
f
=
2
n
u
m
−
s
i
z
=
2
n
−
n
=
n
f=2num-siz=2n-n=n
f=2num−siz=2n−n=n。
扩容后:势能
f
=
2
n
u
m
−
s
i
z
=
2
(
n
+
1
)
−
2
n
=
2
f=2num-siz=2(n+1)-2n=2
f=2num−siz=2(n+1)−2n=2。
所以势能变化为
2
−
n
2-n
2−n,那么引起扩容操作的插入操作的摊还代价为
n
+
(
2
−
n
)
=
O
(
1
)
n+(2-n)=O(1)
n+(2−n)=O(1)
综上,插入操作的摊还复杂度为
O
(
1
)
O(1)
O(1)。
不得不说,势能函数还是很妙的……
3.4 表扩张&删除(push_back,pop_back)
//咕咕咕
问:如果你需要维护一个数据结构,需要资磁在尾部插入/删除数,还要使浪费的空间尽量少,怎么做?
(扩容,收缩复杂度均为
O
(
数的个数
)
O(数的个数)
O(数的个数))
如果模仿3.3,当数组个数小于
s
i
z
2
\frac{siz}{2}
2siz时收缩,显然会gg(当数的个数为
s
i
z
−
1
siz-1
siz−1时不断插入、删除、插入、删除……)
所以考虑减少收缩次数:
不妨让数的个数少于
s
i
z
4
\frac{siz}{4}
4siz时收缩,这样就不会有毒瘤(LXL)来卡掉了qwq
时间复杂度分析:
核算法:
每次扩容的复杂度分摊到至少
n
n
n个插入操作上,每个插入操作分摊到
O
(
1
)
O(1)
O(1)
收缩时,假设最后一次扩容时数组大小为
s
i
z
siz
siz,那么数的个数最多的时候最少也是
s
i
z
2
\frac{siz}{2}
2siz个,而收缩时数的个数会变成
s
i
z
4
\frac{siz}{4}
4siz个,所以中间最少会有
s
i
z
4
\frac{siz}{4}
4siz级别的删除操作。
把
O
(
s
i
z
)
O(siz)
O(siz)的复杂度分摊到
s
i
z
4
\frac{siz}{4}
4siz级别的操作上,每个操作分到
O
(
1
)
O(1)
O(1)。
综上,插入/删除的摊还复杂度均为
O
(
1
)
O(1)
O(1)
聚合分析:
假设插入、删除操作共有
n
n
n个。那么插入和收缩操作最多都是
n
n
n的数量级。
由3.3的聚合分析珂知,扩容操作的总复杂度为
O
(
n
)
O(n)
O(n)
假设
O
(
2
x
)
O(2^x)
O(2x)的收缩操作出现了
a
x
a_x
ax次,那么收缩操作复杂度
F
(
n
)
=
O
(
1
)
∗
a
1
+
O
(
2
)
∗
a
2
+
.
.
.
+
O
(
2
n
)
∗
a
n
F(n)=O(1)*a_1+O(2)*a_2+...+O(2^n)*a_n
F(n)=O(1)∗a1+O(2)∗a2+...+O(2n)∗an(忽略一些边界问题qwq)
因为若一个收缩操作是
O
(
2
s
i
z
)
O(2^{siz})
O(2siz)的,那么这个收缩操作珂以支配
2
s
i
z
2^{siz}
2siz级别的删除操作,
所以
a
x
a_x
ax个
O
(
2
x
)
O(2^{x})
O(2x)的收缩操作珂以支配
2
x
∗
a
x
2^x*a_x
2x∗ax个收缩操作。
因为收缩操作的总数不超过
n
n
n,所以
1
∗
a
1
+
2
∗
a
2
+
.
.
.
+
2
n
∗
a
n
≤
n
1*a_1+2*a_2+...+2^{n}*a_n\le n
1∗a1+2∗a2+...+2n∗an≤n
所以
F
(
n
)
=
O
(
n
)
F(n)=O(n)
F(n)=O(n)
单次插入/删除的复杂度是
O
(
1
)
O(1)
O(1),
n
n
n次就是
O
(
n
)
O(n)
O(n)
综上,总时间复杂度为
O
(
n
)
O(n)
O(n)
势能法:
咕咕咕……
暂时就这些qwq