Data.Sequence

时间:2015-11-15 16:58:53

标签: haskell time-complexity

我最近正在使用Data.Sequence开展calculating moving average from a stream of input的实施工作。我想我可以通过使用双端队列将整个操作变为O(n)。

我的第一次尝试(在我看来)更容易阅读,但不是真正的双端队列。看起来像是:

  let newsequence = (|>) sequence n
  ...
  let dropFrontTotal = fromIntegral (newtotal - index newsequence 0)
  let newsequence' = drop 1 newsequence. 
  ...

根据Data.Sequence的{​​{3}},index应采用 O(log(min(i,ni)))drop还应该采用 O(log(min(i,ni)))

这是我的问题:

如果我drop 1 someSequence,这不意味着 O(log(min(1,(length someSequence))))的时间复杂度,在这种情况下意味着: 为O(log(1))

如果是, O(log(1)) 是否有效?

我对index someSequence 0有同样的问题:该操作最终不应该是 O(log(0))吗?

最终,我对我的理解有足够的怀疑,我使用Criterion来对这两个实现进行基准测试,以证明index/drop版本较慢(并且随着输入的增长,它的速度变慢了)。我的机器上的非正式结果可以在链接的要点上看到。

我仍然不明白如何计算这些操作的时间复杂度,我希望任何人都可以提供任何澄清。

1 个答案:

答案 0 :(得分:2)

你的建议对我来说是正确的。

作为一个小警告,请记住这些是摊销的复杂性界限,因此单个操作可能需要不止一个时间,但是长链操作只需要链的数量的常数倍

如果您使用标准进行基准测试并在每次计算时“重置”状态,您可能会看到非恒定的时间成本,因为“重置”会阻止摊销。这实际上取决于你如何进行测试。如果你从一个序列开始,对它执行一系列操作,它应该没问题。如果使用相同的操作数重复多次单个操作,则可能不正常。

此外,我认为O(log(...))之类的界限实际上应该被理解为O(log(1 + ...)) - 您实际上不能将O(log(1)) = O(0)或更差O(log(0))= O(-inf)视为复杂界限