为什么此F#序列表示三次时间而不是线性时间?

时间:2020-02-10 08:18:22

标签: algorithm debugging f# time-complexity sequence

使用[('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.unfoldSeq.tryHead为O(1)(如果我错了,请纠正我)。但是,据我所知,它具有三次复杂性。

我使用了一组带有Seq.tail值的以下函数来测试执行时间。

n

是什么使此操作变得复杂?

2 个答案:

答案 0 :(得分:5)

seq几乎总是O(n)seqIEnumerable<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