是否可以在保留 O(1) 访问时间的同时将数组建模为函数?

Is it possible to model arrays as functions while preserving O(1) access times?

提问人:Charlim 提问时间:4/8/2021 最后编辑:Lauren YimCharlim 更新时间:5/10/2021 访问量:107

问:

将链接列表建模为函数非常容易,无需任何底层集合数据类型,如下所示:

-- This is Lua code, but the specific language shouldn't matter
function createList(first, rest)
  return function(isFirst)
    if isFirst
    then
      return first
    else
      return rest
    end
  end
end

function nth(list, n)
  -- replace with n==0 for 0 indexing,
  if (n == 1)
  then
    return list(true)
  else
    return nth(list(false), n-1)
  end
end

但是,与索引访问具有时间复杂性的数组相比,这具有缺点。我一直在想数组文字很容易实现,这样:O(n)

-- {1, 2, 4, 8} ==
function someArray(n)
  if (n == 1)
    return 1
  elseif (n == 2)
    return 2
  elseif (n == 3)
    return 4
  elseif (n == 4)
    return 8
  end
end

但是我意识到一次浏览每一个仍然是 访问时间 .我考虑了一个 switch 语句,因为我的印象是 C 的 switch 语句直接跳转到与条件结果匹配的标签,但这似乎不正确。对于分支,C 的开关似乎会及时选择一个分支。是否可以在不使用数组的情况下在恒定时间内选择分支?是否有其他技术可以恒定时间访问建模为我错过的函数的数组?elseifO(n)nO(n)

数组 函数式编程 时间复杂度 与语言无关

评论

2赞 Jörg W Mittag 4/8/2021
这是一个超级有趣的问题!我的直觉说,数组的性能是它在内存中的物理表示的属性,而不是它的 API,而 Church Encoding(和其他类似的函数编码)的美妙之处在于在某种意义上没有物理表示;它只是一个 API。但我很想看看这个问题会带来什么。
0赞 Charlim 4/8/2021
是的,我怀疑你是对的......但我希望不是,我想找到一个用于数组访问的函数定义
1赞 Jörg W Mittag 4/8/2021
例如,Clojure 使用 32 元树作为其“数组”(称为向量)。Java 仅支持 32 位数组索引,.NET 也允许 64 位数组索引。一个有 40 亿个条目的 Clojure 向量只有不到 7 个层次的深度,所以你的性能是 “O(7)”。具有 2^64 个条目的向量深度仅小于 14 级。一个有 328,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000 个元素(宇宙中的粒子数)的向量只有 45 级深。因此,对于与 Java 或 .NET 支持的大小相同的向量,性能是......
1赞 Jörg W Mittag 4/8/2021
不可变的数据结构是不可变的。你不需要保护自己,防止它在不同的线程/函数中被从你下面改变出来,因为它不能改变,时期
1赞 Jörg W Mittag 4/8/2021
这取决于你如何建模。Clojure 对节点使用 Java 数组,因此每个级别的数组索引都是 O(1)。当你“修改”一个元素时,你必须将路径从根复制到该元素,但这最多只有 log_32(n) 个数组,每个数组需要复制 32 个元素,所以 O(32 * log_32 n),当然只是 O(log_32 n)。无论如何,m 是常数,所以即使你把它建模为链表,O(m) 仍然只是 O(1)。

答: 暂无答案