我有一个std::vector<T>
变量。我还有两个类型为T的变量,第一个表示我要插入的向量中的值,而第二个表示要插入的值。
所以我想说我有这个容器:1,2,1,1,2,2
关于上面的定义,这两个值是2和3。然后我希望编写一个函数来更新容器,而不是包含:
1,2,3,1,1,2,3,2,3
我正在使用c ++ 98和boost。我可以用什么std或boost函数来实现这个功能?
迭代向量并使用std :: insert是一种方法,但当你意识到你需要记住跳过你刚刚插入的值时它会变得混乱。
答案 0 :(得分:7)
这就是我可能会做的事情:
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);
如果你愿意,可以打电话预约。您知道至少需要original.size()
元素的空间。您还可以对向量执行初始迭代(或使用std::count
)来确定要保留的元素的确切数量,但是如果不进行测试,我不知道这是否会提高性能。
答案 1 :(得分:3)
我提出了一个在内存和O(n)内存和O(2n)时间内工作的解决方案。通过本杰明提出的解决方案,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;
}
这个算法可能有问题,但想法是每个元素只复制一次:
答案 2 :(得分:1)
这就是我可能会做的事情:
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);
}
但是你可以看到,我无法避免你提到的增量。但我不认为那会是坏事:我会把这些代码放在单独的函数中(可能在某种“core / utils”模块中) - 当然 - 将这个函数实现为模板,所以我只会写它曾经 - 只有一次担心增加价值是恕我直言可以接受的。非常接受。
template <class ValueType>
void insertAfter(::std::vector<ValueType> &io_data,
const ValueType &i_searchValue,
const ValueType &i_insertAfterValue);
甚至更好(恕我直言)
template <class ListType, class ValueType>
void insertAfter(ListType &io_data,
const ValueType &i_searchValue,
const ValueType &i_insertAfterValue);
修改强>
好吧,我会以一点点不同的方式解决问题:首先计算搜索值出现的次数(最好存储在某种缓存中,可以保存并重复使用)所以我可以准备数组(只有一次分配)并使用memcpy用于移动原始值(当然,仅用于类型的int)或memmove(如果已经足够的向量分配大小)。答案 3 :(得分:1)
到位,O(1)额外的记忆和O(n)时间(Live at 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]);
}
}