简体   繁体   English

在向量中插入多个值

[英]Insert multiple values into vector

I have a std::vector<T> variable. 我有一个std::vector<T>变量。 I also have two variables of type T, the first of which represents the value in the vector after which I am to insert, while the second represents the value to insert. 我还有两个类型为T的变量,第一个表示我要插入的向量中的值,而第二个表示要插入的值。

So lets say I have this container: 1,2,1,1,2,2 所以我想说我有这个容器: 1,2,1,1,2,2

And the two values are 2 and 3 with respect to their definitions above. 并且就上面的定义而言,这两个值是2和3。 Then I wish to write a function which will update the container to instead contain: 然后我希望编写一个函数来更新容器,而不是包含:

1,2,3,1,1,2,3,2,3

I am using c++98 and boost. 我正在使用c ++ 98和boost。 What std or boost functions might I use to implement this function? 我可以用什么std或boost函数来实现这个功能?

Iterating over the vector and using std::insert is one way, but it gets messy when one realizes that you need to remember to hop over the value you just inserted. 迭代向量并使用std :: insert是一种方法,但当你意识到你需要记住跳过你刚刚插入的值时它会变得混乱。

This is what I would probably do: 这是我可能会做的:

vector<T> copy;
for (vector<T>::iterator i=original.begin(); i!=original.end(); ++i)
{
    copy.push_back(*i);
    if (*i == first)
        copy.push_back(second);
}
original.swap(copy);

Put a call to reserve in there if you want. 如果你愿意,可以打电话预约。 You know you need room for at least original.size() elements. 你知道至少需要为original.size()元素留出空间。 You could also do an initial iteraton over the vector (or use std::count ) to determine the exact amount of elements to reserve, but without testing, I don't know whether that would improve performance. 你也可以在向量上做一个初始的iteraton(或使用std::count )来确定要保留的元素的确切数量,但是如果没有测试,我不知道这是否会提高性能。

I propose a solution that works in place and in O(n) in memory and O(2n) time. 我提出了一个在内存和O(n)内存和O(2n)时间内工作的解决方案。 Instead of O(n^2) in time by the solution proposed by Laethnes and O(2n) in memory by the solution proposed by Benjamin. 通过本杰明提出的解决方案,Laethnes和O(2n)在记忆中提出的解决方案及时代替O(n ^ 2)。

// First pass, count elements equal to first.
std::size_t elems = std::count(data.begin(), data.end(), first);
// Resize so we'll add without reallocating the elements.
data.resize(data.size() + elems);
vector<T>::reverse_iterator end = data.rbegin() + elems;
// Iterate from the end. Move elements from the end to the new end (and so elements to insert will have some place).
for(vector<T>::reverse_iterator new_end = data.rbegin(); end != data.rend() && elems > 0; ++new_end,++end)
{
  // If the current element is the one we search, insert second first. (We iterate from the end).
  if(*end == first)
  {
    *new_end = second;
    ++new_end;
    --elems;
  }
  // Copy the data to the end.
  *new_end = *end;
}

This algorithm may be buggy but the idea is to copy only once each elements by: 这个算法可能有问题,但想法是每个元素只复制一次:

  1. Firstly count how much elements we'll need to insert. 首先计算我们需要插入多少元素。
  2. Secondly by going though the data from the end and moving each elements to the new end. 其次,从最后遍历数据并将每个元素移动到新的结尾。

This is what I probably would do: 这就是我可能会做的事情:

typedef ::std::vector<int> MyList;
typedef MyList::iterator MyListIter;

MyList data;

// ... fill data ...

const int searchValue = 2;
const int addValue = 3;

// Find first occurence of searched value
MyListIter iter = ::std::find(data.begin(), data.end(), searchValue);

while(iter != data.end())
{
    // We want to add our value after searched one
    ++iter;

    // Insert value and return iterator pointing to the inserted position
    // (original iterator is invalid now).
    iter = data.insert(iter, addValue);

    // This is needed only if we want to be sure that out value won't be used
    // - for example if searchValue == addValue is true, code would create
    // infinite loop.
    ++iter;

    // Search for next value.
    iter = ::std::find(iter, data.end(), searchValue);
}

but as you can see, I couldn't avoid the incrementation you mentioned. 但正如你所看到的,我无法避免你提到的增量。 But I don't think that would be bad thing: I would put this code to separate functions (probably in some kind of "core/utils" module) and - of course - implement this function as template, so I would write it only once - only once worrying about incrementing value is IMHO acceptable. 但我不认为那会是坏事:我会把这些代码放在单独的函数中(可能在某种“core / utils”模块中) - 当然 - 将这个函数实现为模板,所以我只会写它曾经 - 只有一次担心增加价值是恕我直言可以接受的。 Very acceptable. 非常接受。

template <class ValueType>
void insertAfter(::std::vector<ValueType> &io_data,
                 const ValueType &i_searchValue,
                 const ValueType &i_insertAfterValue);

or even better (IMHO) 甚至更好(恕我直言)

template <class ListType, class ValueType>
void insertAfter(ListType &io_data,
                 const ValueType &i_searchValue,
                 const ValueType &i_insertAfterValue);

EDIT: 编辑:

well, I would solve problem little different way: first count number of the searched value occurrence (preferably store in some kind of cache which can be kept and used repeatably) so I could prepare array before (only one allocation) and used memcpy to move original values (for types like int only, of course) or memmove (if the vector allocated size is sufficient already). 好吧,我会用一点点不同的方式解决问题:首先计算搜索值出现的次数(最好存储在某种缓存中,可以保存并重复使用)所以我可以准备数组(只有一次分配)并使用memcpy来移动原始值(对于类似int的类型,当然)或memmove(如果向量分配的大小已经足够)。

In place, O(1) additional memory and O(n) time ( Live at Coliru ): 在适当的位置,O(1)额外的记忆和O(n)时间( 在Coliru生活 ):

template <typename T, typename A>
void do_thing(std::vector<T, A>& vec, T target, T inserted) {
    using std::swap;

    typedef typename std::vector<T, A>::size_type size_t;
    const size_t occurrences = std::count(vec.begin(), vec.end(), target);
    if (occurrences == 0) return;

    const size_t original_size = vec.size();
    vec.resize(original_size + occurrences, inserted);

    for(size_t i = original_size - 1, end = i + occurrences; i > 0; --i, --end) {
        if (vec[i] == target) {
            --end;
        }
        swap(vec[i], vec[end]);
    }
}

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

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