簡體   English   中英

Haskell中的復雜性分析

[英]Complexity Analysis in Haskell

positions2              :: (Eq a) => a -> [a] -> [Int]
positions2              = f where
    f aa aas        = filter (g aa aas) [0 .. (length aas - 1)]
    g aa aas it     = aa == aas !! it

此代碼用於查找給定列表中給定元素的位置。

為了找出它的復雜性,我想過filter采用的函數是g和列表[0..length-1]

現在,我無法弄清楚positions2復雜性是什么(n)還是由於filter功能會有任何循環。

請建議是否有任何其他方法來編寫更緊湊的代碼,以降低復雜性。

  • 過濾器具有O(n)復雜度。
  • [0..x]具有O(n)復雜度。
  • (!!)具有O(n)復雜度。

由於嵌套(!!),您的天真實現是二次的

列表在這里是懶惰的,因此過濾器和列表生成器具有組合的O(n)復雜度加上每個元素的一些常量(具有惰性,列表的生成和過濾在一次傳遞中有效地發生)。

即生成和過濾的工作是在惰性列表上的(O(n + n * k)) ,而不是嚴格列表中的O(2 * n) ,其中k是生成單個cons單元的成本。

但是,無論如何,使用線性索引會使這個二次方成為正方形。 我注意到,在具有融合的嚴格向量上,由於常數j查找復雜度,或者使用日志結構化查找O(n + n * log n) ,這將是O(n + n * j) (線性

線性復雜性

positions2 :: Eq a => a -> [a] -> [Int]
positions2 x = map fst . filter ((x==).snd) . zip [0..]

main = print $ positions2 3 [1,2,3,4,1,3,4]

(我建議你閱讀並理解究竟是如何工作的)

(你的代碼需要二次時間,因為(!!)需要線性時間)

首先,幾乎沒有變化:

positions2              :: (Eq a) => a -> [a] -> [Int]
positions2              = f where
    f aa aas        = filter (g aa aas) [0 .. (length aas - 1)]
    g aa aas it     = aa == aas !! it
-- ==
positions2 aa aas  = filter (g aa aas) [0 .. (length aas - 1)]
    g aa aas it     = aa == aas !! it
-- ==
positions2 aa aas  = [it | it <- [0 .. (length aas - 1)], aa == (aas !! it)]
{- 
positions2 aa aas = for each it in [0 .. (length aas - 1)]
                      if (aas !! it) == aa
                        emit it
-}

現在,你可以清楚地看到,對於給定it的列表的遍歷aas重新反復 ,從一開始,由(!!) 這是一個經典的二次行為,當完全探索positions2 aa aas的結果時,你執行1 + 2 + 3 + 4 + ... + n = O(n 2步驟(返回的列表遍歷到它最后)。

但是你探索逐步增加指標,所以你可以和沿列表中的前點開始(而不是從自身做起 ),並通過每次1個位置提前(而不是全it指數,如(!!)是這樣做):

positions2 aa aas = g 0 aas
   where
      g i (a:as) | a == aa = i : g (i+1) as
                 | otherwise =   g (i+1) as
      g _ [] = []

在這里你可以看到如何將索引的遞增1( i --> i+1 )與列表中的推進一起編織一個位置( (a:as) --> as )。

再次使用列表推導,使用zip實現編織(或實際上更像是拉鏈):

positions2 aa aas = [it | (a,it) <- zip aas [0 .. (length aas - 1)]
                        , a == aa]
{-
    = for each a in aas while incrementing it by 1 from 0 to (length aas - 1),
        if a == aa
          emit it
-}

現在,這顯然是一種O(n)解決方案。 而且因為Haskell的列表是懶惰的,並且當最短列表結束時zip停止,

positions2 aa aas = [it | (a,it) <- zip aas [0 ..], a == aa]

(這相當於此答案中的代碼)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM