使用[('a', 1), ('a', 2), ('c', 3)]
时,我偶然发现了一个奇怪的时间复杂度行为。这是我想出的最简单的情况。
Seq.unfold
函数let idUnfolder sequence =
sequence
|> Seq.tryHead
|> Option.map (fun head -> (head, Seq.tail sequence))
let seqIdWithUnfold sequence =
Seq.unfold idUnfolder sequence
返回给定序列本身。我希望结果序列在线性时间内迭代,因为seqIdWithUnfold
为O(n),Seq.unfold
和Seq.tryHead
为O(1)(如果我错了,请纠正我)。但是,据我所知,它具有三次复杂性。
我使用了一组带有Seq.tail
值的以下函数来测试执行时间。
n
是什么使此操作变得复杂?
答案 0 :(得分:5)
seq
几乎总是O(n)
。
seq
或IEnumerable<T>
本质上是:
type Enumerator<'a> = {
getNext : unit -> 'a option
}
type Seq<'a> = {
getEnumerator: unit -> Enumerator<'a>
}
每次评估序列时,都会创建一个新的Enumerator
来捕获枚举状态。然后反复调用getNext
,直到序列终止。
如果您随时用
替换seq
,则可以自己查看
source |> Seq.map(fun x -> printfn "Eval %A" x; x)
让我们也显示对getEnumerator
的呼叫:
let sq =
seq {
let mutable ctr = 0
do printfn "Init _"
while true do
ctr <- ctr + 1
printfn "Yield %d" ctr
yield ctr
}
seqIdWithUnfold (sq |> Seq.take 3) |> Seq.toList |> printfn "%A"
有输出:
Init _
Yield 1
Init _
Yield 1
Yield 2
Init _
Yield 1
Yield 2
Yield 3
Init _
Yield 1
Yield 2
Yield 3
[1; 2; 3]
这向您展示了经典的n(n+1)/2
模式。
您会看到,复杂度中将包含 n + n 2 个术语。
如果可以使用列表,则会得到O(n)
而不是O(n^2)
。
如果您确实想要O(1)
,请使用数组。
答案 1 :(得分:0)
菲利普·卡特(Philip Carter)在评论中<% @question.answers.each do |answer| %>
<% if answer.errors.any? %>
<% end %>
<% end %>
提到的是O(n)。
我不确定为什么F#列表是不可接受的,F#列表是单链接列表,因此您可以获得恒定的时间尾巴。如果您需要接受任何序列,因为您的签名只是在展开之前转换为List,它仍然使它成为O(n)。无论如何,除非您真的不需要尾巴,否则您展示的这个示例也不会很懒。
@answer
您的处理示例仍适用于“列表”模块
<% if @answer.errors.any? %>
但是我认为它看起来会更干净
import { AdMobFreeOriginal, AdMobFreeBannerConfig } from '@ionic-native/admob-free';
@NgModule({
declarations: [AppComponent],
entryComponents: [],
imports: [
BrowserModule,
IonicModule.forRoot(),
AppRoutingModule,
HttpClientModule, ],
providers: [
StatusBar,
SplashScreen,
AdMobFreeOriginal,
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
],
bootstrap: [AppComponent]
})
export class AppModule {}
Benchamarks
Seq.tail