2016-11-13 17 views
6

Katlama bazen katlamadan bazen daha yavaş mıdır? Ben Düzgün çalışır (zaman karmaşıklığı (n) O) "a" (++) ile birlikte katlama, katlamadan çok daha yavaştır

a = [[1],[2],[3]] 

gibi listelerin bir liste var ve

foldr (++) [] a 

kat kullanarak bir listeye değiştirmek istiyorum. Fakat bunun yerine katlanırsam, çok yavaştır (zaman karmaşıklığı O (n^2)).

foldl (++) [] a 

foldl sadece sol taraftan giriş listesini katlama ise,

(([] ++ [1]) ++ [2]) ++ [3] 

ve foldr sağ taraftan ise,

[1] ++ ([2] ++ ([3] ++ [])) 

hesaplamaların sayısı (++) her iki durumda da aynı olması gerekiyordu. Foldr neden bu kadar yavaş? Zaman karmaşıklığına göre, katlama giriş listesini iki kez katr olarak tarar gibi görünüyor. Ben Çünkü nasıl ++ eser bulunuyor süre

length $ fold (++) [] $ map (:[]) [1..N] (fold is either foldl or foldr) 
+0

Her iki durumda da '(++)' ın * sonuç * aynı olması beklenir. Bu, hesaplamaların sayısının aynı olduğu anlamına gelmez. –

+1

(büyük liste) ++ (küçük liste) daha küçüktür (küçük liste) ++ (büyük liste) – immibis

+0

Uzun zamandır burada olduğunuzu gördüm ve birini kabul etmeden çok soru sordum. Bir cevap size yardımcı olursa [kabul etmeyi] düşünün (https: // stackoverflow.com/help/kabul-cevap). Ayrıca bu sitenin nasıl çalıştığını anlamak için bir [tur] (https://stackoverflow.com/tour) yaparak 2 dakika harcayalım. –

cevap

10

bilgisayara aşağıdaki kullanılır. Not ilk argümanında indüksiyon ile tanımlanmıştır.

[]  ++ ys = ys 
(x:xs) ++ ys = x : (xs ++ ys) 

özyinelemeli aramaların sayısı yalnızca length xs bağlıdır.

Bu nedenle, xs ++ ys numaralı telefondan, xs numarasına ve ys numaralı telefona sahip olmak daha uygundur. Sağdaki katlama başarır

Not olduğu:

[1] ++ ([2] ++ ([3] ++ ... 

Sadece sahip kısa (O (1) uzunlukta) kat maliyeti O (n) yapmak ++ solundaki hakkında listeler.

yerine solda katlama kötü:
((([] ++ [1]) ++ [2]) ++ [3]) ++ ... 

sol argümanlar

daha büyük ve daha büyük hale gelir. Dolayısıyla, burada O (n^2) karmaşıklığı elde ederiz.

Bu argüman, çıktı listesinin nasıl talep edildiğini dikkate alarak daha hassas yapılabilir. Biri, foldr'un sonucunu "akış" tarzında üretmektedir; İlk çıktı listesi hücresi sadece girişin küçük bir kısmını zorlar - sadece ilk ++ yapılması gerekir ve sadece ilk özyinelemesine ihtiyaç vardır! Bunun yerine sadece foldl sonucundan ilk öğeyi talep etmek tüm çağrılarını ++ numaralı çağrılara zorlar, bu da onu oldukça pahalı kılar (her arama sadece bir tekrarlama adımına ihtiyaç duysa bile, O (n) çağrıları vardır).