Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/143.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在特定位置向向量插入多个值_C++_Vector - Fatal编程技术网

C++ 在特定位置向向量插入多个值

C++ 在特定位置向向量插入多个值,c++,vector,C++,Vector,假设我有一个像这样的整数向量std::vector\u data 我知道如果我想从\u data中删除多个项目,那么我只需调用 _data.erase( std::remove_if( _data.begin(), _data.end(), [condition] ), _data.end() ); 这比清除多个元素要快得多,因为向量中需要的数据移动更少。我想知道是否有类似的东西用于插入 例如,如果我有以下几对 auto pair1 = { _data.begin() + 5, 5 }; au

假设我有一个像这样的整数向量
std::vector\u data
我知道如果我想从
\u data
中删除多个项目,那么我只需调用

_data.erase( std::remove_if( _data.begin(), _data.end(), [condition] ), _data.end() );
这比清除多个元素要快得多,因为
向量中需要的数据移动更少。我想知道是否有类似的东西用于插入

例如,如果我有以下几对

auto pair1 = { _data.begin() + 5, 5 };
auto pair2 = { _data.begin() + 12, 12 };
我可以使用一些现有的
std
函数在一次迭代中插入这两个吗?我知道我可以做一些事情,比如:

_data.insert( pair2.first, pair2.second );
_data.insert( pair1.first, pair1.second );
但是对于大向量(说100000+个元素)来说,这(非常)慢

编辑:基本上,我有一个自定义的集合(和映射),它使用
向量
作为底层容器。我知道我可以只使用
std::set
std::map
,但我所做的遍历次数远远超过了插入/删除次数。从
集合
映射
切换到此自定义集合/映射已经减少了20%的运行时间。但目前,插入大约占剩余运行时间的10%,因此减少这一点很重要


不幸的是,订单也是必需的。我尽可能多地使用
无序
版本,但在某些地方,顺序确实很重要

一种方法是创建另一个向量,其容量等于原始大小加上被插入元素的数量,然后执行插入循环,无需重新分配O(N)复杂度:

template<class T>
std::vector<T> insert_elements(std::vector<T> const& v, std::initializer_list<std::pair<std::size_t, T>> new_elements) {
    std::vector<T> u;
    u.reserve(v.size() + new_elements.size());
    auto src = v.begin();
    size_t copied = 0;
    for(auto const& element : new_elements) {
        auto to_copy = element.first - copied;
        auto src_end = src + to_copy;
        u.insert(u.end(), src, src_end);
        src = src_end;
        copied += to_copy;
        u.push_back(element.second);
    }
    u.insert(u.end(), src, v.end());
    return u;
}

int main() {
    std::vector<int> v{1, 3, 5};
    for(auto e : insert_elements(v, {{1,2}, {2,4}}))
        std::cout << e << ' ';
    std::cout << '\n';
}

好的,我们需要一些假设。让
old_end
作为向量最后一个元素的反向迭代器。假设您的
\u数据
已调整大小,以完全适合其当前内容和要插入的内容。假设
inp
是一个
std::pair
容器,其中包含按相反顺序插入的数据(因此首先插入最后面位置的元素,依此类推)。然后我们可以做:

std::merge(old_end,_data.rend(),inp.begin(),inp.end(),data.rend(),[int i=inp.size()-1](常数&T,常数&std::对p)可变{
如果(std::distance(_data.begin(),p.first)=i){
--一,;
返回false;
}
返回true;
}
但是,我认为这并不比使用一个好的
for
更清楚。stl算法的问题是谓词作用于值而不是迭代器,这对于这个问题来说有点烦人。

我的观点如下:

template<class Key, class Value>
class LinearSet
{
public:
    using Node = std::pair<Key, Value>;

    template<class F>
    void insert_at_multiple(F&& f)
    {
        std::queue<Node> queue;
        std::size_t index = 0;
        for (auto it = _kvps.begin(); it != _kvps.end(); ++it)
        {
            // The container size is left untouched here, no iterator invalidation.
            if (std::optional<Node> toInsert = f(index))
            {
                queue.push(*it);
                *it = std::move(*toInsert);
            }
            else
            {
                ++index;
                // Replace current node with queued one.
                if (!queue.empty())
                {
                    queue.push(std::move(*it));
                    *it = std::move(queue.front());
                    queue.pop();
                }
            }
        }

        // We now have as many displaced items in the queue as were inserted,
        // add them to the end.
        while (!queue.empty())
        {
            _kvps.emplace_back(std::move(queue.front()));
            queue.pop();
        }
    }

private:
    std::vector<Node> _kvps;
};


同样,在索引0和1处插入意味着什么,这可能会造成混淆(是否会在两者之间插入一个原始元素?在第一个片段中,您会,在第二个片段中,您不会)。您可以在同一索引中多次插入吗?插入前索引有意义,插入后索引则没有意义。您也可以通过传递当前的
*it
(即键值对)来编写此命令对函子来说,但这一点似乎并不太有用…

这是我的一次尝试,它以相反的顺序插入。我确实去掉了用于此的迭代器/索引

template<class T>
void insert( std::vector<T> &vector, const std::vector<T> &values ) {
    size_t last_index = vector.size() - 1;
    vector.resize( vector.size() + values.size() ); // relies on T being default constructable
    size_t move_position = vector.size() - 1;

    size_t last_value_index = values.size() - 1;
    size_t values_size = values.size();

    bool isLastIndex = false;

    while ( !isLastIndex && values_size ) {
        if ( values[last_value_index] > vector[last_index] ) {
            vector[move_position] = std::move( values[last_value_index--] );
            --values_size;
        } else {
            isLastIndex = last_index == 0;
            vector[move_position] = std::move( vector[last_index--] );
        }
        --move_position;
    }

    if ( isLastIndex && values_size ) {
        while ( values_size ) {
            vector[move_position--] = std::move( values[last_value_index--] );
            --values_size;
        }
    }
}
模板
无效插入(标准::向量和向量,常量标准::向量和值){
size\t last\u index=vector.size()-1;
vector.resize(vector.size()+values.size());//依赖于T是默认可构造的
size\u t move\u position=vector.size()-1;
size\t last\u value\u index=values.size()-1;
size\u t values\u size=values.size();
bool islastinex=false;
while(!isLastIndex&&values\u size){
if(值[last_值\u索引]>向量[last_索引]){
向量[move_position]=std::move(值[last_value_index--]);
--大小值;
}否则{
isLastIndex=last_索引==0;
向量[move_position]=std::move(向量[last_index--]);
}
--移动位置;
}
if(islastinex&&value\u size){
while(值大小){
向量[move_position--]=std::move(值[last_value_index--]);
--大小值;
}
}
}
在Godbolt上使用ICC、Clang和GCC进行了尝试,vector的插入速度更快(对于插入的5个数字)。在我的机器MSVC上,结果相同,但不太严重。我还根据Maxim的回答将其版本与之进行了比较。我意识到使用Godbolt不是一种很好的比较方法,但我无法访问当前机器上的其他3个编译器

来自我的机器的结果:

我的插页:659us
马克西姆插页:712us
矢量插入:315us

戈博尔特国际刑事法院

我的插页:470us
马克西姆插页:139us
矢量插入:127us

Godbolt'sgc

我的插页:815us
Maxim insert:97us
矢量插入:97us

戈博尔特的叮当声:

我的插页:477us
马克西姆插页:188美元
矢量插入:96us


也许<代码>预留()/<代码>或<代码> Resie()/代码>会有帮助吗?向量的内部容量已经足够(预分配在200000左右),如果你在中间插入很多,那么你就不应该使用<代码> STD::向量< /代码>,但是其他的东西。什么是“其他东西”??这取决于实际的应用程序-您的代码解决的问题。因此,您的问题基本上受到影响。据我所知,没有标准的库算法。您可能必须自己编写。@胡桃,抱歉,只是一个示例。我已改变了顺序。我希望您的答案。我必须对使用迭代器而不是位置,或者我可以将它包装起来,然后使用距离。我发现了一种稍微好一点的方法,它不使用迭代器或位置,而是使用插入排序。编辑:我实际上只是将它与向量进行比较。插入
,两者都比向量
慢:(
template<class F>
void insert_at_multiple(F&& f)
{
    std::queue<Node> queue;
    std::size_t index = 0;
    for (auto it = _kvps.begin(); it != _kvps.end(); ++it)
    {
        if (std::optional<Node> toInsert = f(index))
            queue.push(std::move(*toInsert));

        if (!queue.empty())
        {
            queue.push(std::move(*it));
            *it = std::move(queue.front());
            queue.pop();
        }

        ++index;
    }

    // We now have as many displaced items in the queue as were inserted,
    // add them to the end.
    while (!queue.empty())
    {
        if (std::optional<Node> toInsert = f(index))
        {
            queue.push(std::move(*toInsert));
        }

        _kvps.emplace_back(std::move(queue.front()));
        queue.pop();
        ++index;
    }
}
template<class T>
void insert( std::vector<T> &vector, const std::vector<T> &values ) {
    size_t last_index = vector.size() - 1;
    vector.resize( vector.size() + values.size() ); // relies on T being default constructable
    size_t move_position = vector.size() - 1;

    size_t last_value_index = values.size() - 1;
    size_t values_size = values.size();

    bool isLastIndex = false;

    while ( !isLastIndex && values_size ) {
        if ( values[last_value_index] > vector[last_index] ) {
            vector[move_position] = std::move( values[last_value_index--] );
            --values_size;
        } else {
            isLastIndex = last_index == 0;
            vector[move_position] = std::move( vector[last_index--] );
        }
        --move_position;
    }

    if ( isLastIndex && values_size ) {
        while ( values_size ) {
            vector[move_position--] = std::move( values[last_value_index--] );
            --values_size;
        }
    }
}