简体   繁体   English

将多个偏移量的多个元素插入向量中

[英]Insert multiple elements at multiple offsets into an vector

I've got an vector<uint32_t> values and an vector<std::pair<uint32_t, uint_32_t>> updates that contains (a lot) accumulated updates to the vector, which I want to enact as cheaply as possible. 我有一个vector<uint32_t> values和一个vector<std::pair<uint32_t, uint_32_t>> updates ,其中包含对该向量的(大量)累积更新,我想尽可能便宜地实现它。

An update of {5, 12} should insert 12 right after the the values[5] , not concerning any other modifications , ie values = {10,20,30} and updates = {{0,5}, {1, 6}, {2, 7}} should result in values = {10, 5, 20, 6, 30, 7} . 的更新{5, 12}应该插入12右后的values[5] 不涉及任何其它变型 ,即, values = {10,20,30}updates = {{0,5}, {1, 6}, {2, 7}} values = {10, 5, 20, 6, 30, 7}values = {10, 5, 20, 6, 30, 7}

I want to modify the vector according to the updates vector like this: 我想根据updates向量来修改向量,如下所示:

static void update(std::vector<uint32_t>& values,
    std::vector<std::pair<uint32_t, uint32_t>> updates) {
    std::sort(updates.begin(), updates.end(),
        [](std::pair<uint32_t, uint32_t> a, std::pair<uint32_t, uint32_t> b){
             return a.first < b.first;
        });
    values.reserve(values.size()+updates.size());
    for(uint32_t i = 0; i < updates.size(); ++i){
        values.insert(values.begin()+i+updates[i].first, updates[i].second);
    }

}

If I'd allow duplicated update[i].first , I'd need to use std::stable_sort to keep the relative order. 如果我允许重复的update[i].first ,则需要使用std::stable_sort保持相对顺序。

Obviously, this code is quite slow, using O(n^2) time to move the remainder of the vector back one at a time. 显然,此代码相当慢,使用O(n^2)时间一次将向量的其余部分移回一个。 There should be a better solution. 应该有一个更好的解决方案。

There is a question on SO already, that is quite similar: Insert multiple values into vector . 已经有一个关于SO的问题,它非常相似:将多个值插入vector While there is an answer that I could use to update my vector in O(1) space and O(n) time, the question is quite old using c++03 and I wanted to know if there is a modern way to do that (or even, if I could avoid calling std::sort beforehand). 虽然有一个我可以用来在O(1)空间和O(n)时间中更新向量的答案,但是使用c ++ 03时这个问题已经很老了,我想知道是否有一种现代的方法可以做到这一点(甚至,如果我可以避免事先调用std::sort )。

Perhaps something like this should work. 也许这样的事情应该起作用。 Since we know all updates, we know how much must each value be shifted to make space for the new ones. 由于我们知道所有更新,因此我们知道每个值必须偏移多少才能为新值腾出空间。 That is, exactly the amount equal to the number of updates with lower indices that the given value has. 也就是说,数量恰好等于给定值具有较低索引的更新次数。 we can work from backwards, shifting the values by |updates| 我们可以从后退,通过|updates|移动值 positions, insert the update with the highest index, shift the next batch by |updates-1| 位置,插入具有最高索引的更新,将下一批移动|updates-1| positions, insert the second-highest update... 位置,插入第二高的更新...

static void update(std::vector<uint32_t>& values,
    std::vector<std::pair<uint32_t, uint32_t>> updates) {
    std::sort(updates.begin(), updates.end(),[](auto a, auto b){
             return a.first > b.first;//From highest to lowest indices.
        });

    const std::size_t N = values.size();
    std::size_t K = updates.size();
    values.resize(N+K);
    std::size_t end = N;
    for(auto [i,v]:updates){
        //Shift the values in [i+1,end) K positions right
        std::move_backward(values.begin()+i+1,
                           values.begin()+end,
                           values.begin()+end+K);
        //Insert the update
        values[i+K]=v;
        //Preceding values are shifted only by K-1 positions
        --K;
        //Already shifted values
        end=i+1;
    }
}

This needs O(u log u) to sort the updates and O(u+n) to shift the old and add the new values. 这需要O(u log u)对更新进行排序,并需要O(u+n)对旧数据进行移位并添加新值。 Only one resize is done. resize了一个resize Note that resize zero-initializes the added values, the raw array would be slightly more efficient here. 请注意,将resize为零会初始化添加的值,此处原始数组的效率会稍高一些。 Or do some index magic with emplace_back . 或者使用emplace_back做一些索引魔术。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM