博主是haskell新手。學習haskll的時候遇到了一些問題,在尋求答案的過程中產生了一些思考,可能理解存在偏差,希望各位不吝賜教。
《learn you a haskell for great good》裡第六章關於函式foldl
(左fold)的部分提到,++
操作符比:
要昂貴很多,所以我們一般用foldr
來構造乙個list
第一次看這段話的時候我並沒有深究(實際上我認為這句話根本就有毛病,因為foldr也得用++,原文作者根本沒把核心問題指出來),因為haskell用都沒用過幾次,自然理解不了內在機制。最近剛好遇上了乙個用(++
)的機會,我想把乙個char陣列轉成string陣列,實現如下(不重要,大致就是用foldl將剩餘陣列的內容塞進累加器陣列裡,用++來連線,不想看的直接跳過**吧):
chars2string :: [char] -> [string]
chars2str chars = foldl (\strs c -> strs ++ [[c]]) chars
-- 當時沒想到的更簡便實現
chars2string :: [char] -> [string]
chars2str chars = map (\c -> [c]) chars
突然想到這不正是使用++
的最壞情況嗎?所以我花了不少時間去sof等地方看別人的回答,為什麼++
會顯得更加昂貴。
++
的原始碼實現是遞迴式的,並且底層使用了:
,大部分的答案都有提到這一點,去看了原始碼確實是這樣沒錯。(大致的做法就是將++
左邊的部分拆成 x1:x2:x3 ... 這樣,右邊不需要遞迴遍歷)
可是
仔細想一想這種遞迴的開銷是o(n)。懂一些資料結構知識就知道,往陣列(非鏈式)底部插入乙個(或x個)值,相當於把已經存在的n個值全部抬高乙個(或x個)陣列位,開銷必然是o(n)。也就是說不論你是什麼語言,想要用非鏈式陣列資料結構實現這樣的功能開銷都應該是一樣的。
證明開銷昂貴
先不論別的語言如何,現在博主來證明++
開銷的巨大,假如有這樣的情況:
-- 從sof的這個回答裡受到很大啟發:
let a = ( ( ( [1,2] ) ++ [3] ) ++ [4] )
計算步驟(偽**):
[1,2] ++ [3] => 1 : 2 : [3] => [1,2,3]
,這裡通過遞迴遍歷將[1,2]拆開,大致消耗o(2)
[1,2,3] ++ [4] => 1 : 2 : 3 : [4] => [1,2,3,4]
,又通過遞迴遍歷將[1,2,3]拆開,大致消耗o(3)
... 很明顯在步驟2,重複了遞迴遍歷拆開[1,2]這個操作,也就是說繼續這樣迴圈下去,時間複雜度大致為o(1+2+3+4+...+n),似乎可以化簡為o(k * n^2)
(k代表++
左邊陣列的長度,n代表重複++
的次數)
再觀察剛才的**,可以看到這和函式foldl所做的事情差不多,這就是為什麼++
開銷在foldl會很昂貴的原因
也可以很廉價
但是
,++也可以很廉價,想象這樣的情況:
let a = ( [1] ++ ( [2] ++ [3,4] ) )
相當於1 : 2 : [3,4]
,時間複雜度是o(n),n是++的次數,這和:
操作是一樣的。
上面的**剛好是foldr
所做的事情。這就是《learn you a haskell for great good》作者寫下那段話的原因。
對比其他語言
現在回頭反觀其他語言。假設對乙個非鏈式陣列進行如下操作:
nolinkedarray =
nolinkedarray.prepend(1).prepend(2).prepend(3)
排除該語言對陣列操作優化的可能,難道時間複雜度不也是o(0+1+2+3+...+n)嗎?
我由此思考得出結論,這是乙個普遍存在的問題,和haskell的底層機制沒多大關係。
可是一碼歸一碼,現在陣列的首選應該都是linkedarray吧,鏈式陣列無論往頭部還是尾部插入元素,單次時間複雜度都是o(1),多次操作時間複雜度則是o(n),不會出現o(k * n^2)這種天文運算
Haskell 為什麼列表操作 很昂貴?
博主是haskell新手。學習haskll的時候遇到了一些問題,在尋求答案的過程中產生了一些思考,可能理解存在偏差,希望各位不吝賜教。learn you a haskell for great good 裡第六章關於函式foldl 左fold 的部分提到,操作符比 要昂貴很多,所以我們一般用fold...
為什麼需要列表
變數可以儲存乙個元素,而列表是乙個大容器可以儲存n多個元素,程式可以方便地對這些資料進行整體操作 列表相當於其他語言中的陣列 注意這邊列表強大的地方在於,其可以儲存不同型別的物件,這是容器,是廣義陣列,更加符合我們人的日常思維,變數組的有序結合 變數儲存的是乙個變數的引用 而列表儲存的是多個變數的引...
zz Intel IPP 為什麼很便宜,呵呵
ipp intel integrated performance primitives,英特爾 r 整合效能原件 一直有所聽聞,這次opencv研討會上,ipp的chief architect李信弘 shinn horng lee 也來參加。跟他了解了一下ipp 1.intel不靠ipp賺錢 199...