std :: inserter with set - insert to begin()或end()?

Ash*_*ain 18 c++ iterator stl insert set

我有一些看起来像这样的代码:

std::set<int> s1, s2, out;

// ... s1 and s2 are populated ...

std::set_intersection(s1.begin(), s1.end(),
                      s2.begin(), s2.end(),
                      std::inserter(out, out.end()));
Run Code Online (Sandbox Code Playgroud)

如果插入到集合中的值紧跟在作为"提示"给出的迭代器之后,我已经读过插入可以在分摊的常量时间内完成.这在运行集合交集时显然是有益的,特别是因为写入的所有内容out已经按排序顺序排列.

我如何保证这种最佳性能?在创建时std::inserter,out是空的,out.begin() == out.end()所以我看不出它是否有任何区别,无论我指定out.begin()还是out.end()作为提示.但是,如果在插入每个元素时解释这一点begin(),那么我似乎不会获得最佳的算法性能.这可以做得更好吗?

Ash*_*ain 5

我选择亚历山大·盖斯勒的答案作为"正确"的答案,因为它引导我找到了这个解决方案,我认为无论如何我都会发布这个解决方案.我写了一个last_inserter(),它保证插入位置始终是最后一个元素的迭代器(或者如果为空则为begin()),因为set想要一个迭代器到实际插入位置之前的元素以获得最佳性能(所以不是end() - 这将是实际插入位置之后的一个).

根据原始示例的用法如下:

std::set<int> s1, s2, out;

// ... s1 and s2 are populated ...

std::set_intersection(s1.begin(), s1.end(),
                      s2.begin(), s2.end(),
                      last_inserter(out));  // note no iterator provided
Run Code Online (Sandbox Code Playgroud)

这保证了插入提示始终是最后一个元素的迭代器,希望在将输出迭代器用于具有排序范围的集合时提供最佳情况性能,如上所述.

以下是我的实施.我认为它是特定于Visual C++ 2010的STL实现的平台,因为它主要基于现有的insert_iterator,我只能通过派生来实现它std::_Outit.如果有人知道如何使这个便携式,请告诉我:

// VC10 STL wants this to be a checked output iterator.  I haven't written one, but
// this needs to be defined to silence warnings about this.
#define _SCL_SECURE_NO_WARNINGS

template<class Container>
class last_inserter_iterator : public std::_Outit {
public:
    typedef last_inserter_iterator<Container> _Myt;
    typedef Container container_type;
    typedef typename Container::const_reference const_reference;
    typedef typename Container::value_type _Valty;

    last_inserter_iterator(Container& cont)
        : container(cont)
    {
    }

    _Myt& operator=(const _Valty& _Val)
    {
        container.insert(get_insert_hint(), _Val);
        return (*this);
    }

    _Myt& operator=(_Valty&& _Val)
    {
        container.insert(get_insert_hint(), std::forward<_Valty>(_Val));
        return (*this);
    }

    _Myt& operator*()
    {
        return (*this);
    }

    _Myt& operator++()
    {
        return (*this);
    }

    _Myt& operator++(int)
    {
        return (*this);
    }

protected:
    Container& container;

    typename Container::iterator get_insert_hint() const
    {
        // Container is empty: no last element to insert ahead of; just insert at begin.
        if (container.empty())
            return container.begin();
        else
        {
            // Otherwise return iterator to last element in the container.  std::set wants the
            // element *preceding* the insert position as a hint, so this should be an iterator
            // to the last actual element, not end().
            return (--container.end());
        }
    }
};

template<typename Container>
inline last_inserter_iterator<Container> last_inserter(Container& cont)
{
    return last_inserter_iterator<Container>(cont);
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*ler 2

您可以使用自定义函子来代替std::inserterout.end()在每次插入新元素时重新调用。

或者,如果您的值按降序排序,out.begin()也可以。