我有一个 std::vector
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
vec.erase(???);
要删除单个元素,您可以执行以下操作:
std::vector<int> vec;
vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);
// Deletes the second element (vec[1])
vec.erase(std::next(vec.begin()));
或者,一次删除多个元素:
// Deletes the second through third elements (vec[1], vec[2])
vec.erase(std::next(vec.begin(), 1), std::next(vec.begin(), 3));
std::vector 上的擦除方法已重载,因此调用可能更清晰
vec.erase(vec.begin() + index);
当您只想擦除单个元素时。
vec.begin()
。
vec.erase(0)
不起作用,但 vec.erase(vec.begin()+0)
(或没有 +0)可以。否则我没有得到匹配的函数调用,这就是我来这里的原因
vec.erase(0)
如果 0
恰好被解释为空指针常量,则实际上可能会编译...
template <typename T>
void remove(std::vector<T>& vec, size_t pos)
{
std::vector<T>::iterator it = vec.begin();
std::advance(it, pos);
vec.erase(it);
}
template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }
我并不是说两者都更好,只是出于个人兴趣并返回此问题可能获得的最佳结果。
vector<T>::iterator
是随机访问迭代器,因此您的版本很好,可能更清晰一些。但是,如果您将容器更改为另一个不支持随机访问迭代器的容器,Max 发布的版本应该可以正常工作
erase
方法将以两种方式使用:
擦除单个元素:vector.erase(vector.begin() + 3); // 删除第四个元素 擦除元素范围:vector.erase(vector.begin() + 3, vector.begin() + 5 ); // 从第四个元素删除到第六个元素
擦除带有 index 的元素:
vec.erase(vec.begin() + index);
擦除具有值的元素:
vec.erase(find(vec.begin(),vec.end(),value));
实际上,erase
函数适用于两个配置文件:
删除单个元素迭代器擦除(迭代器位置);
删除一系列元素迭代器擦除(首先迭代器,最后迭代器);
由于 std::vec.begin() 标志着容器的开始,如果我们想删除向量中的第 i 个元素,我们可以使用:
vec.erase(vec.begin() + index);
如果仔细观察,vec.begin() 只是一个指向向量起始位置的指针,将 i 的值添加到它会增加指向 i 位置的指针,因此我们可以通过以下方式访问指向第 i 个元素的指针:
&vec[i]
所以我们可以写:
vec.erase(&vec[i]); // To delete the ith element
如果你有一个无序向量,你可以利用它是无序的这一事实,并使用我在 CPPCON 的 Dan Higgins 那里看到的东西
template< typename TContainer >
static bool EraseFromUnorderedByIndex( TContainer& inContainer, size_t inIndex )
{
if ( inIndex < inContainer.size() )
{
if ( inIndex != inContainer.size() - 1 )
inContainer[inIndex] = inContainer.back();
inContainer.pop_back();
return true;
}
return false;
}
由于列表顺序无关紧要,只需将列表中的最后一个元素复制到要删除的项目的顶部,然后弹出并删除最后一个项目。
iterator + index
实际上会给您返回该索引处的迭代器位置的假设,这并非所有可迭代容器都如此。通过利用反向指针,它也是恒定的复杂性而不是线性的。
unordered_remove
和 unordered_remove_if
的形式添加到 std 库中......除非它已经被添加并且我错过了它,这种情况现在越来越频繁地发生了 :)
std::remove
对容器重新排序,以便所有要删除的元素都位于末尾,如果您使用的是 C++ 17,则无需像这样手动执行此操作。
std::remove
有什么帮助? cppreference 声称即使在 C++17 中,所有 remove
重载都需要谓词,并且没有一个需要索引。
对某些人来说似乎很明显,但要详细说明上述答案:
如果您在整个向量的循环中使用 erase
删除 std::vector
元素,您应该以 reverse order 处理您的向量,也就是说使用
for (int i = v.size() - 1; i >= 0; i--)
而不是(古典)
for (int i = 0; i < v.size(); i++)
原因是索引受 erase
影响,因此如果您删除第 4 个元素,那么之前的第 5 个元素现在是新的第 4 个元素,如果您的循环不会处理它正在做i++
。
下面是一个简单的例子,说明我想删除一个 int 向量的所有赔率元素;
#include <iostream>
#include <vector>
using namespace std;
void printVector(const vector<int> &v)
{
for (size_t i = 0; i < v.size(); i++)
{
cout << v[i] << " ";
}
cout << endl;
}
int main()
{
vector<int> v1, v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i);
}
// print v1
cout << "v1: " << endl;
printVector(v1);
cout << endl;
// print v2
cout << "v2: " << endl;
printVector(v2);
// Erase all odd elements
cout << "--- Erase odd elements ---" << endl;
// loop with decreasing indices
cout << "Process v2 with decreasing indices: " << endl;
for (int i = v2.size() - 1; i >= 0; i--)
{
if (v2[i] % 2 != 0)
{
cout << "# ";
v2.erase(v2.begin() + i);
}
else
{
cout << v2[i] << " ";
}
}
cout << endl;
cout << endl;
// loop with increasing indices
cout << "Process v1 with increasing indices: " << endl;
for (int i = 0; i < v1.size(); i++)
{
if (v1[i] % 2 != 0)
{
cout << "# ";
v1.erase(v1.begin() + i);
}
else
{
cout << v1[i] << " ";
}
}
return 0;
}
输出:
v1:
0 1 2 3 4 5 6 7 8 9
v2:
0 1 2 3 4 5 6 7 8 9
--- Erase odd elements ---
Process v2 with decreasing indices:
# 8 # 6 # 4 # 2 # 0
Process v1 with increasing indices:
0 # # # # #
请注意,在索引增加的第二个版本中,偶数不会显示,因为它们会因为 i++
而被跳过
另请注意,以相反的顺序处理向量,您不能对索引使用无符号类型(for (uint8_t i = v.size() -1; ...
不起作用)。这是因为当 i
等于 0
时,例如 i--
将溢出并等于 255
(例如,对于 uint8_t
,循环不会停止,因为 i
仍然是 >= 0
,并且可能超出向量范围)。
如果您使用大型向量(大小 > 100,000)并且想要删除大量元素,我建议您执行以下操作:
int main(int argc, char** argv) {
vector <int> vec;
vector <int> vec2;
for (int i = 0; i < 20000000; i++){
vec.push_back(i);}
for (int i = 0; i < vec.size(); i++)
{
if(vec.at(i) %3 != 0)
vec2.push_back(i);
}
vec = vec2;
cout << vec.size() << endl;
}
该代码获取 vec 中不能被 3 整除的每个数字并将其复制到 vec2。之后它将 vec2 复制到 vec 中。它非常快。要处理 20,000,000 个元素,这个算法只需要 0.8 秒!
我用擦除方法做了同样的事情,它需要很多很多时间:
Erase-Version (10k elements) : 0.04 sec
Erase-Version (100k elements) : 0.6 sec
Erase-Version (1000k elements): 56 sec
Erase-Version (10000k elements): ...still calculating (>30 min)
要删除元素,请使用以下方式:
// declaring and assigning array1
std:vector<int> array1 {0,2,3,4};
// erasing the value in the array
array1.erase(array1.begin()+n);
如需更广泛的概述,您可以访问:http://www.cplusplus.com/reference/vector/vector/erase/
我建议阅读此内容,因为我相信这就是您要寻找的内容。https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom
如果您使用例如
vec.erase(vec.begin() + 1, vec.begin() + 3);
您将擦除向量的第 n 个元素,但是当您擦除第二个元素时,向量的所有其他元素将被移动并且向量大小将为 -1。如果您循环遍历向量,这可能会出现问题,因为向量 size() 正在减小。如果您遇到此类问题,建议您使用标准 C++ 库中的现有算法。和“删除”或“remove_if”。
希望这有帮助
如果您需要擦除 for 循环内的元素,请执行以下操作:
for(int i = 0; i < vec.size(); i++){
if(condition)
vec.erase(vec.begin() + i);
}
前面的答案假定您总是有一个有符号索引。遗憾的是,std::vector
将 size_type
用于索引,而 difference_type
用于迭代器算术,因此如果您启用了“-Wconversion”和朋友,它们就不能一起工作。这是回答问题的另一种方式,同时能够处理有符号和无符号:
去除:
template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
void remove(std::vector<T> &v, I index)
{
const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
v.erase(iter);
}
采取:
template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
T take(std::vector<T> &v, I index)
{
const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
auto val = *iter;
v.erase(iter);
return val;
}
如果你想通过在向量中找到它的值来删除一个元素,这是另一种方法,你只需要在向量上执行此操作。
vector<int> ar(n);
ar.erase(remove(ar.begin(), ar.end()), (place your value here from vector array));
它会从这里删除你的价值。谢谢
这个怎么样?
void squeeze(vector<int> &v)
{
int j = 0;
for (int i = 1; i < v.size(); i++)
if (v[i] != v[j] && ++j != i)
v[j] = v[i];
v.resize(j + 1);
}
最快的方式(时间复杂度()=常数的编程竞赛)
1秒可擦除100M条;
vector<int> it = (vector<int>::iterator) &vec[pos];
vec.erase(it);
和最易读的方式:vec.erase(vec.begin() + pos);
vector<int>::iterator
不一定与 int *
相同
不定期副业成功案例分享
operator+
不一定必须为其他容器类型上的迭代器定义,例如list<T>::iterator
(您不能在std::list
上执行list.begin() + 2
,您必须为此使用std::advance
)std::find_if