有序集合的高性能合并

时间:2013-08-04 18:50:01

标签: performance algorithm sorting c++11 real-time-updates

希望保持一组数字排序(升序或降序,但下面的示例仅显示升序)。最快速度的数据结构表示是个问题。

假设聚合程序不断从许多不同的监视代理程序获取数据包,例如通过网络。这个想法是让它们在任何时候都保持快速排序。例如,您可能会按顺序获取这些数据包(使用整数但实际情况是double):

A = [1, 3, 4, 6]
B = [1, 2, 3]
C = [2, 3, 5]
A = [2, 4, 7, 8]

等等。在第一个数据包之后,聚合器中的数据结构将已经排序(数据结构会记住排序中每个数字所指的来源):

  

[1,3,4,6] =>事件

在下一个数据包之后,因为它是一个新的源,所以数据结构将如下所示

  

[1,1,2,3,3,4,6] =>事件

在下一个数据包之后,

  

[1,1,2,2,3,3,3,4,5,6] =>事件

现在自A发送新数据包以来,我们必须找到A的旧值,并用新的替换它们,最后以新的排序结束。替换和排序可以单独发生或不发生(就地),目标是极速:

  

[1,2,2,3,3,3,4,5,7,8] =>事件

请注意,当您获得第二个A时,所有旧的As必须在保持排序的同时被新的As数据包“替换”。在将每个数据包分类到数据结构之后,它被复制并需要作为“事件”发送。每隔几微秒,这些数据包就会在合并排序算法中疯狂而持续地发生。

*执行此操作的最佳数据结构是什么?也许是Splay Tree或AVL树? *

1 个答案:

答案 0 :(得分:1)

这不是最快的数据结构&我想你的特定目的的算法,但它可能足够快。自己测试一下。

请注意,std::forward_list甚至std::vector可能会更快,具体取决于实际情况( - > big-O-notation中的常数因素)。

tmyklebu提到了另一种方法in the comments:根据具体情况,按需合并可能会更快,例如:单独存储所有数据集并将它们合并到vector以传递给事件处理程序,甚至使用“合并”迭代器(其增量获取各个数据集的下一个元素)。

通过使用自定义内存池可以实现进一步的性能改进 - >自定义分配器。

#include <set>
#include <iostream>
#include <iterator>
#include <algorithm>

// inserts a sorted range into the `to` container
template < typename To, typename InputIt >
void insert_new_sorted(To& to,
                       InputIt beg_old, InputIt end_old,
                       InputIt beg_new, InputIt end_new)
{
    auto const& comp = to.value_comp();
    typename To::iterator i = to.begin();

    // might improve performance: don't remove elements which are in both
    // ranges (old and new)
    while(beg_old != end_old && beg_new != end_new)
    {
        if(comp(*beg_old, *beg_new))
        {
            // remove old element
            i = to.find(*beg_old);  // "slow", no hint :(
            i = to.erase(i);
            ++beg_old;
        }else if(comp(*beg_new, *beg_old))
        {
            // insert new element
            // using the hint to achieve better performance
            i = to.insert(i, *beg_new);
            ++beg_new;
        }else
        {
            // both equal, do nothing
            ++beg_new;
            ++beg_old;
        }
    }

    // remove remaining old elements
    for(; beg_old != end_old; ++beg_old)
    {
        to.erase(to.find(*beg_old));  // "slow", no hint :(
    }

    // insert remaining new elements
    for(; beg_new != end_new; ++beg_new)
    {
        i = to.insert(i, *beg_new);
    }

    std::copy(to.begin(), to.end(),
        std::ostream_iterator<typename To::value_type>(std::cout, ", "));
    std::cout << std::endl;
}

int main()
{
    using set_t = std::multiset<double>;

    set_t const A = {1, 3, 4, 6};
    set_t const B = {1, 2, 3};
    set_t const C = {2, 3, 5};
    set_t const A2 = {2, 4, 7, 8};

    set_t result;
    insert_new_sorted(result, A.end(), A.end(), A.begin(), A.end());
    insert_new_sorted(result, B.end(), B.end(), B.begin(), B.end());
    insert_new_sorted(result, C.end(), C.end(), C.begin(), C.end());
    insert_new_sorted(result, A.begin(), A.end(), A2.begin(), A2.end());
}

输出:

  

1,3,4,6,
  1,1,3,3,4,6,
  1,1,2,2,3,3,3,4,5,6,
  1,2,3,3,3,4,5,7,8,


另一种方法:存储插入元素的迭代器,以加快擦除速度。