我想出了一个idea来解决另一个SO question,我希望能帮助确定函数的复杂性,因为我对此并不太了解。我是否正确地猜测每个块的“未分类”将是O (n * log 2)
?然后sortBy函数的复杂性是什么,它将一个块的最后一个与另一个块的头部进行比较?我的猜测是,该函数只会比较对,而不需要根据总列表找到一个块的顺序。另外,由于整体功能的懒惰优化,Haskell会提供不同的复杂性吗?提前谢谢!
import Data.List.Split (chunksOf)
import Data.List (sortBy)
rearrange :: [Int] -> [Int]
rearrange = concat
. sortBy (\a b -> compare (last a) (head b))
. map (sortBy (\a b -> compare b a))
. chunksOf 2
答案 0 :(得分:5)
让我们孤立地看一下这些部分(让n
成为list参数的长度):
chunksOf 2
为O(n)
,生成长度为(n+1) `quot` 2
的列表。map (sortBy ...)
:由于传递给sortBy ...
的所有列表的长度都为<= 2
,因此每个排序都为O(1)
,因此整个map
为再次O(n)
。sortBy (\a b -> compare (last a) (head b))
:比较始终为O(1)
,因为采用last
元素的列表具有有限长度(<= 2
),因此整个sortBy
} operation是O(n*log n)
concat
再次O(n)
。总的来说,我们有O(n*log n)
。
但请注意
cmp = \a b -> compare (last a) (head b)
是一个不一致的比较,对于两个列表a
和b
(比如[30,10]
和[25,15]
),您可以
cmp a b == cmp b a = LT
我不确定您的算法是否始终有效。
在查看sortBy
的实现并在我的脑海中稍微跟踪排序之后,我认为对于给定的目的,它可行(如果列表元素是不同的)并且不一致的比较没有坏处。对于某些排序算法,不一致的比较可能导致排序循环,但对于合并排序变体,不应该发生。
答案 1 :(得分:4)
一步一步
chunksOf 2
必须遍历整个列表,所以O(n)
和我们列表长度的一半。但是,由于常数倍数不会影响复杂性,我们可以忽略它。map (sortBy...
遍历整个列表O(n)
执行常量操作* O(1)
= O(1*n)
= O(n)
sortBy
与O( n * log n)
concat
,O(n)
总共O(n + n + n log n + n)
= O ((3 + log n) * n)
= O(n log n)
*由于列表的保证长度为2或更短,我们可以说排序和访问最后一个元素的操作分别是O(2 * log 2)
和O(2)
,它们都是常量时间{ {1}}