给定一个空数组,我需要进行两种类型的查询
在数组中插入元素
查找某个元素 k 的索引(显然数组必须保持排序)
可以使用set
容器
set<int> st;
set.insert(t);
这会将我的元素插入O(log(n))
。
第二次查询
set<int>::iterator it;
it = st.find(k);
idx = distance(st.begin(), it);
这需要O(n)
次。 (O(n)
[for distance()
[+ O(log(n)
[for set::find()
])。
有没有办法在O(log(n))
中使用预定义的C ++容器进行两个查询?
答案 0 :(得分:5)
我不认为这对标准库的容器是可行的,因为通过索引支持访问需要更改实现(向每个节点添加一个计数器)。这会增加每个节点的大小。而C ++的哲学是“不要付出你不使用的东西”。
如果你确实需要这个,那么建议使用countertree实现boost(并且它至少支持一些C ++ 11功能)来满足你的要求。
答案 1 :(得分:4)
没有。这是不可能的(使用预定义的容器)。 C ++标准库的序列容器具有:
请注意,deque
是一个例外,但仅在插入/删除发生在数组末尾时才会出现。一般情况仍为O(N)。
此外,迭代器的分类不包括此案例的类别。你有双向迭代器(list
,set
,multiset
,map
和multimap
),它们取O( N)跳转到随机位置的时间,下一个类别是随机访问迭代器(vector
,deque
和string
的类别)。没有中间类别。
添加新类别根本不会是微不足道的。该库还实现了许多适用于容器的算法(如for_each
)。每个迭代器类别都有一个实现。
已在Boost多次提出订单统计树。据我所知:
他们被接受的主要困难是普遍认为他们不是利益,而是危险。今天的程序员习惯于用典型的容器解决他们所知道的所有问题。经验丰富的程序员担心新手可能会盲目地使用建议的容器来做所有事情,而不是仔细选择。
答案 2 :(得分:0)
虽然我同意在C ++中没有完全内置的方法,但有一个很好的解决方法:使用分段树。让段树表示遇到的每个元素的频率。插入元素基本上将计数更新为1,而查询只是从索引0
到element - 1
的段总和操作。这些都可以在O(logn)
中轻松完成。我知道缺点是你需要知道可以存在的元素数量,但在许多实际问题中,一个好的上限就足够了。