描述一个数据结构:
n
没有漏洞i
位置(即:与整数i
相关联的项目)应尽可能快
i
位置插入新项目应尽快
i
以后的任何项目右移i
上的项目也应尽可能快
i+1
开始左移任何项目在此说明中,n
是结构的大小(即:它包含多少项),i
是一般通用整数(1 <= i
&lt; = n
),当然。
我是从我在教职员工中遇到的那个人那里听到的。不知道这是一个面试问题,一个考试问题,只是一个谜语或什么,但我想这可能是一切。
如果我没记错的话(但是嘿,那是在12月24日之前),他说这样的数据结构可以通过O(sqrt n)
插入/移位和O(1)
访问时间实现,或者用{{1对于任何操作。
编辑:已经给出了一些正确的答案。如果您不想再考虑这个问题,请阅读它。
答案 0 :(得分:3)
嗯,任何类型的自平衡二叉树(例如,红黑)都将为O(logn)
提供所有三种操作。提到的C ++ map RB 是一个例子(如果我没有完全忘记C ++)。
对于索引(get
操作),有一个标准技巧。我们将在每个节点中存储其左子树有多少个节点。现在,我们可以在i
时间内将元素定位到O(logn)
位置,方式如下
Data get(Node root, int i) {
if (i <= root.leftCount) {
return get(root.left, i);
} else if (i == root.leftCount + 1) {
return node;
} else {
return get(root.right, i - root.leftCount - 1);
}
}
显然,每次添加或删除元素时,都必须重新计算leftCount
值,但这只需要O(logn)
个节点。 (想想有多少节点包括在他们的左子树中删除了一个 - 只有它们直接在它们之间的根节点)
答案 1 :(得分:2)
跳过列表可以在O(log n)
中进行插入/删除/索引查找:http://en.wikipedia.org/wiki/Skip_list#Indexable_skiplist
对于O(n^1/2)
插入/删除和O(1)
索引,我假设有点像C ++ deque
,但由n^1/2
个连续块组成,每个n^1/2
个O(n^1/2)
连续块1}}元素(当然每个平方根上+/- 1)。要删除,您必须将包含已删除元素(O(n^1/2)
)的块的一部分随机移动,然后将较高块的整个拖放,您可以通过调整每个块的偏移量(最多O(n^1/2)
个块)而不是实际移动任何块。要插入,您可能必须重新分配块(O(n^1/2)
)并调整偏移量。在这两种情况下,您可能还必须将一个或两个元素从一些块的开始/结束移动到上一个/下一个块的结束/开始,再次最多O(1)
次,以保持不变的不存在两个块的大小差异超过1,除了用于消除松弛的最后一个块。最后,您有时必须创建或销毁块。查找是{{1}}因为您可以通过单个分区进入要查找的元素的一个块内,然后查询存储的偏移量以获得一个或两个块以实际找到它。
不知道那叫什么,或者我是否错过了一些重要的细节,这意味着它不像我所描述的那样有效。