什么被认为是按顺序推送内容的最佳数据结构(所以在任何位置插入,能够找到正确的位置),按顺序迭代,并从顶部弹出N个元素(因此N个最小元素,N确定通过与阈值比较)?推送和弹出需要特别快(在循环的每次迭代中运行),而数据的有序完全迭代以可变速率发生,但可能不太经常地减少一个数量级。完整迭代无法清除数据,需要保持不变。推送的所有内容最终都会被弹出,但由于pop可以删除多个元素,因此弹出比弹出更多。任何时候结构中的数据规模可能达到数百或数千个元素。
我目前正在使用std::deque
和二分搜索以按升序插入元素。分析显示它占据了大部分时间,因此必须改变一些东西。 std::priority_queue
不允许迭代,我看到这样做的黑客不会按顺序迭代。即使是在有限的测试中(没有完整的迭代!),std::set
类的表现也比我的std::deque
方法更差。
我正在搞乱的类似乎都没有考虑到这个用例。如果在STL中找不到数据结构或者出于某种原因需要提升数据结构,我不反对自己创建类。
编辑:
现在有两个主要功能,push
和prune
。 push
使用65%的时间,prune
使用32%。 push
中使用的大部分时间都是由于插入deque
(65%中的64%)。只有1%来自二元搜索以找到位置。
template<typename T, size_t Axes>
void Splitter<T, Axes>::SortedData::push(const Data& data) //65% of processing
{
size_t index = find(data.values[(axis * 2) + 1]);
this->data.insert(this->data.begin() + index, data); //64% of all processing happens here
}
template<typename T, size_t Axes>
void Splitter<T, Axes>::SortedData::prune(T value) //32% of processing
{
auto top = data.begin(), end = data.end(), it = top;
for (; it != end; ++it)
{
Data& data = *it;
if (data.values[(axis * 2) + 1] > value) break;
}
data.erase(top, it);
}
template<typename T, size_t Axes>
size_t Splitter<T, Axes>::SortedData::find(T value)
{
size_t start = 0;
size_t end = this->data.size();
if (!end) return 0;
size_t diff;
while (diff = (end - start) >> 1)
{
size_t mid = diff + start;
if (this->data[mid].values[(axis * 2) + 1] <= value)
{
start = mid;
}
else
{
end = mid;
}
}
return this->data[start].values[(axis * 2) + 1] <= value ? end : start;
}
答案 0 :(得分:2)
根据您的要求,根据您的需求量身定制的混合数据结构可能表现最佳。正如其他人所说,连续内存非常重要,但我不建议始终对数组进行排序。我建议你使用3个缓冲区(1 std::array
和2 std::vector
s):
推送元素时,可以通过std::push_heap
将其添加到插入堆中。由于插入堆的大小是常量,因此可能会溢出。当发生这种情况时,您std::sort
向后并std::merge
将已排序的序列缓冲区(A)放入第三个(B),并根据需要调整它们的大小。这将是新的已排序缓冲区,旧的缓冲区可以被丢弃,即您将A和B交换为下一个批量操作。当您需要排序的迭代序列时,您也会这样做。删除元素时,将堆中的顶部元素与排序序列中的最后一个元素进行比较并删除它(这就是为什么要对其进行排序,以便pop_back
代替pop_front
)
作为参考,这个想法基于sequence heaps。
答案 1 :(得分:0)
您是否尝试过使用std :: vector?听起来很奇怪它可能实际上非常快,因为它使用连续的内存。如果我没记错的话Bjarne Stroustrup在2012年的Going Native(http://channel9.msdn.com/Events/GoingNative/GoingNative-2012/Keynote-Bjarne-Stroustrup-Cpp11-Style中谈到了这个问题,但我并不是100%肯定这是在这个视频中。)
答案 2 :(得分:0)
您可以使用二进制搜索节省时间,但在双端队列的随机位置插入速度很慢。我会建议使用std :: map。
答案 3 :(得分:0)
你不能比o(log n)排序的插入时间做得更好,一个set和一个priority_queue(无论如何都是deque)都可以。您可以查看STL的地图,但我认为您不会看到任何改进。
对我来说,你所说的是优化的STL插入操作对你来说不够快。如果是这种情况,我建议您查看比较函数并可能对其进行优化,或者考虑编写自己的执行相同操作的数据结构,但可能会利用有关容器中对象的假设,然后在不考虑任何异常处理的情况下,首先优化它。
答案 4 :(得分:0)
从您的编辑中,听起来就像延迟是在复制 - 这是一个复杂的对象吗?你可以在结构中堆积和存储指针,这样每个条目只创建一次;你需要提供一个带指针的自定义比较器,因为不会调用对象操作符&lt;()。 (自定义比较器可以简单地调用operator&lt;())
编辑: 你自己的数字显示它是插入花费时间,而不是'排序'。虽然一些插入时间是创建对象的副本,但有些(可能是大多数)是创建将保存对象的内部结构 - 我认为这不会在list / map / set / queue等之间发生变化。如果您可以预测数据集的可能最终/最大大小,并且可以编写或找到您自己的排序算法,并且在分配对象时丢失了时间,那么矢量可能是最佳选择。