这是一个有趣的难题。感觉应该是可以的,但细节却难以捉摸。问题出在删除后的索引更新操作中。例如,如果索引存储在树节点中,则在删除操作后平均必须更改 n/2 个索引,这会破坏您所追求的 O(log n) 属性。
如果您同时将对象存储在树和 ArrayList 中,那么仍然存在在 ArrayList 中定位对象的问题,我无法在小于 O(n) 的时间内以简单的方式完成工作。 ArrayList 可能有一些变化,也许是自定义构造,但这似乎需要大量工作。
相反,我建议您考虑红黑树或类似的平衡树,并进行修改通过序数索引访问红黑树 https://stackoverflow.com/questions/9953557/red-black-tree-access-by-ordinal-index:对于树的每个节点,还存储以给定节点为根的子树中的节点数。在插入和删除操作期间,您必须更新受旋转操作影响的所有节点的计数。这仍然可以在 O(log n) 时间内完成,但很复杂。
然后,像往常一样,通过通常的递归算法,对第 k 个最小(或最大)元素的二分搜索也将在 O(log n) 时间内运行。
以下是该技术的更多参考:http://www.cs.usfca.edu/~galles/cs673/lecture/lecture8.pdf http://www.cs.usfca.edu/~galles/cs673/lecture/lecture8.pdf, http://fdatamining.blogspot.ca/2011/09/function-red-black-tree-with-dynamic.html http://fdatamining.blogspot.ca/2011/09/functional-red-black-tree-with-dynamic.html, http://en.wikipedia.org/wiki/Order_statistic_tree http://en.wikipedia.org/wiki/Order_statistic_tree。这应该可以帮助你开始。
更新:实施细节
您要做的就是创建两棵树。其中一个可以是普通的平衡树(如红黑树),用于保存对带有键/值对的对象的引用。您可以搜索键并在 O(log n) 中获取相应的值;插入和删除也将是 O(log n)。此外,第一棵树中的节点将保存对第二棵树(如下)中节点的引用。
第二棵树也将保存对第一棵树中节点的引用,但它将是一个顺序统计树,如上面讨论的那样。插入总是将新项目放置在树的右端。
对此数据结构的插入操作将是按键普通插入第一棵树,插入顺序统计树的右侧,并且每个插入节点中的引用将更新为指向另一个节点中的适当位置树。
可以在第一棵树上对给定键进行搜索操作,时间复杂度为 O(log n),这将返回适当的值,并且在对另一棵树的引用之后,可用于查找节点的“顺序统计量”通过向上遍历树到根并执行简单计算,在 O(log n) 时间内找到第二棵树。
可以在 O(log n) 时间内对第二棵树完成队列中第 k 个位置的搜索操作,返回对第二棵树的引用,可以取消引用该第二棵树以获得关联的键/值对。
在删除任一树中之前,都会先引用对另一棵树的引用,然后删除第一棵树中的节点,然后删除另一棵树中的相应节点,这两个操作都是 O(log n) 操作。
我想就是这样。一切都可以在 O(log n) 时间内完成。第二棵树的空间成本很小,但它只包含引用;空间仍然是 O(n)。
那样有用吗?