在讨论涉及散列和搜索类型的算法时,我注意到 O(1) 的一些非常奇怪的用法,通常是在使用语言系统提供的字典类型或使用数组使用的字典或散列数组类型的上下文中-索引符号。
基本上,O(1) 意味着以恒定时间和(通常)固定空间为界。一些非常基本的操作是 O(1),尽管使用中间语言和特殊 VM 往往会扭曲这里的想法(例如,如何将垃圾收集器和其他动态过程摊销到 O(1) 活动中)。
但是忽略延迟、垃圾收集等的摊销,我仍然不明白如何假设某些涉及某种搜索的技术可以是 O(1),除非在非常特殊的条件下。
尽管我之前已经注意到这一点,但Pandincus 问题中刚刚出现了一个示例,“'Proper' collection to use to get items in O(1) time in C# .NET?” .
正如我在那里所说,我所知道的唯一提供 O(1) 访问作为保证边界的集合是具有整数索引值的固定边界数组。假设是该数组是通过一些映射到随机存取存储器来实现的,该映射使用 O(1) 操作来定位具有该索引的单元格。
对于涉及某种搜索以确定不同类型索引(或具有整数索引的稀疏数组)的匹配单元格位置的集合,生活并不容易。特别是,如果存在冲突并且可能出现拥塞,则访问不完全是 O(1)。而且,如果集合是灵活的,则必须认识到并摊销扩展底层结构(例如树或哈希表)的成本,以缓解拥塞(例如,高碰撞发生率或树不平衡)。
我从来没有想过将这些灵活和动态的结构称为 O(1)。然而,我看到它们作为 O(1) 解决方案提供,而没有任何确定必须保持的条件才能确保实际具有 O(1) 访问(并且该常数小到可以忽略不计)。
问题:所有这些准备都是为了一个问题。O(1) 周围的随意性是什么?为什么如此盲目地接受它?是否认识到即使 O(1) 也可能非常大,即使接近恒定?还是 O(1) 只是将计算复杂性概念用于非正式使用?我很困惑。
更新:答案和评论指出了我自己定义 O(1) 的随意之处,我已经修复了它。我仍在寻找好的答案,在某些情况下,一些评论线程比他们的答案更有趣。