C++中Vector的删除操作

本文深入解析了在使用C++的vector容器时,如何正确地使用迭代器进行元素删除操作,避免迭代器越界的问题,并通过详细执行过程展示了每次删除元素后,迭代器位置的变化和内存布局的影响。
vector <int> v;

v.pushback(0);

v.pushback(1);

v.pushback(1);

v.pushback(0);

想要删除值为1的元素

错误代码

 vector<int>::iteratoritr = v.begin();
 
  while(itr!=v.end())
 
  {
 
   if(*v==1)
 
   {
 
         v.erase(itr);
 
    }
 
   itr++;//这里删除后迭代器会更新出错
 
  }

 

正确代码

 vector<int>::iteratoritr = v.begin();
 
  while(itr!=v.end())
 
  {
 
   if(*v==1)
 
   {
 
         itr=v.erase(itr);
 
    }

else
 
   itr++;
 
  }

 

关于迭代器机制,好好研究。参见 http://blog.youkuaiyun.com/bruce_wang_janet/article/details/6879289

 

每一次删除之后,后边的元素都会向前移动。

所以当前迭代器实际已经指向下一个元素,若再+1,实际上是指向了下一个元素的下一个元素。

以下为上述程序的详细执行过程

int main(int argc, char* argv[])
{

 vector<int>v;

 v.push_back(1);
 
v.push_back(2);
 
v.push_back(3);
 
v.push_back(4);

 vector<int>::iteratoritr = v.begin();
 
vector<int>::iteratortem = v.begin();
 
while(itr!=v.end())

 {
 
 cout<<"line1"<<*itr<<endl;
 
 tem=itr;
 
 itr++;
 
 cout<<"line2"<<*itr<<endl;
 
 v.erase(tem);
 
 cout<<"line3"<<*itr<<endl;


 
}
 
printf("删除后的长度为%d",v.size());
 
return 0;
}

 
调试详解:

数据

1

2

3

4

未赋值

内存地址

B0

B4

B8

BC

C0

指针

begin

 

 

 

End

 

 

 

 

 

Last

执行第一个循环

tem=itr;

数据

1

2

3

4

未赋值

内存地址

B0

B4

B8

BC

C0

指针

begin

 

 

 

End

 

Temitr

 

 

 

Last

itr++;

数据

1

2

3

4

未赋值

内存地址

B0

B4

B8

BC

C0

指针

begin

 

 

 

End

 

Tem

itr

 

 

Last

v.erase(tem);

数据

2

3

4

4

未赋值

内存地址

B0

B4

B8

BC

C0

指针

begin

 

 

Last

End

 

Tem

itr

 

 

 

 第二轮循环

tem=itr;

数据

2

3

4

4

未赋值

内存地址

B0

B4

B8

BC

C0

指针

begin

Tem

 

Last

End

 

 

itr

 

 

 

itr++;

数据

2

3

4

4

未赋值

内存地址

B0

B4

B8

BC

C0

指针

begin

Tem

 

Last

End

 

 

 

itr

 

 

v.erase(tem);

数据

2

4

4

4

未赋值

内存地址

B0

B4

B8

BC

C0

指针

begin

Tem

Last

 

End

 

 

 

itr

 

 

 

可见,erase操作之后,last指针前移,而end指针未变,被删除的元素后边的元素前移,last之后的元素保持不变(并未移除)。完成之后计算size是由last-begin得到的。

<think>我们正在讨论C++ vector删除元素的方法。根据用户要求,我们需要参考之前的引用内容(引用[1]、[2]、[3])以及用户上一次的问题和回答(关于vector插入元素的方法)来组织回答。 用户上一次的问题:关于vector插入元素的方法,我们详细总结了push_back, emplace_back, insert, emplace等方法。 现在用户的问题:查找C++vector删除元素的方法。 我们将按照以下结构组织回答: 1. 删除末尾元素:pop_back() 2. 删除指定位置的元素:erase() 3. 删除所有元素:clear() 4. 注意事项:迭代器失效问题(重点参考引用[1]和引用[2]) 5. 完整代码示例 同时,我们将结合引用内容: 引用[1]:强调删除元素后迭代器失效问题。 引用[2]:给出了删除指定元素(单个和多个)的代码示例。 引用[3]:介绍了vector的基本概念(动态数组)。 另外,由于用户之前的问题是关于插入的,我们可以在注意事项中对比插入和删除操作在迭代器失效方面的异同。 最后,生成相关问题。 注意:使用中文回答,LaTeX公式按规则书写。 </think>### C++ vector删除元素方法总结 在C++中,`std::vector` 的动态数组特性使其支持高效的元素删除操作删除方法主要包括 `pop_back()`、`erase()` 和 `clear()` ,每种方法有特定用途和注意事项。结合引用内容和迭代器失效风险,以下是详细解析: --- #### 1. **删除末尾元素:`pop_back()`** - **功能**:移除vector的最后一个元素 - **语法**:`void pop_back();` - **示例**: ```cpp std::vector<int> vec = {1, 2, 3}; vec.pop_back(); // vec变为{1, 2} ``` - **特点**: - 时间复杂度:$O(1)$ - 不返回被删除元素的值 - **迭代器安全性**:仅使指向最后一个元素的迭代器失效,其他迭代器仍有效[^1] --- #### 2. **删除指定元素:`erase()`** - **功能**:删除迭代器指定位置的一个或多个元素 - **语法**: ```cpp iterator erase(const_iterator pos); // 删除单个元素 iterator erase(const_iterator first, const_iterator last); // 删除范围 ``` - **示例**(结合引用[2]): ```cpp std::vector<int> vec = {10, 20, 30, 40}; // 删除单个元素(如值=30) for (auto it = vec.begin(); it != vec.end(); ) { if (*it == 30) { it = vec.erase(it); // 关键:接收返回值更新迭代器 } else { ++it; } } // 删除范围(索引1到3) vec.erase(vec.begin() + 1, vec.begin() + 3); // 删除{20, 30}[^2] ``` - **关键注意事项**: - **迭代器失效**:删除后所有指向被删元素及之后的迭代器失效(包括`end()`)。必须接收 `erase()` 返回的新迭代器[^1]。 - 时间复杂度:$O(n)$,$n$ 为删除位置后的元素数量(需移动后续元素) - 批量删除重复元素时可结合 `std::remove`(见第4节优化方案) --- #### 3. **清空所有元素:`clear()`** - **功能**:删除所有元素,容器大小(`size()`)变为0 - **语法**:`void clear();` - **示例**: ```cpp std::vector<std::string> names = {"Alice", "Bob"}; names.clear(); // names变为空vector ``` - **特点**: - 时间复杂度:$O(n)$,$n$ 为元素数量 - **内存处理**:不释放容量(`capacity()`),需配合 `shrink_to_fit()` 释放内存[^3] --- #### 4. **优化删除操作** - **批量删除重复元素**(引用[2]扩展): 使用 **Erase-Remove惯用法** 避免手动循环迭代器失效问题: ```cpp std::vector<int> vec = {2, 5, 2, 8, 2}; // 删除所有值为2的元素 vec.erase(std::remove(vec.begin(), vec.end(), 2), vec.end()); // vec变为{5, 8} ``` - `std::remove` 将保留元素移到前面,返回新逻辑终点 - `erase()` 删除尾部冗余元素,时间复杂度 $O(n)$ - **预分配内存**:频繁删除时调用 `vec.shrink_to_fit()` 释放未使用内存 --- #### 5. **完整代码示例** ```cpp #include <iostream> #include <vector> #include <algorithm> // std::remove int main() { std::vector<int> data = {1, 2, 3, 2, 4, 2, 5}; // 1. 删除末尾元素 data.pop_back(); // {1, 2, 3, 2, 4, 2} // 2. 删除单个指定元素(值=3) for (auto it = data.begin(); it != data.end(); ) { if (*it == 3) { it = data.erase(it); // 更新迭代器 } else { ++it; } } // data变为{1, 2, 2, 4, 2} // 3. 批量删除重复元素(值=2) data.erase(std::remove(data.begin(), data.end(), 2), data.end()); // data变为{1, 4} // 4. 清空容器 data.clear(); // size=0 return 0; } ``` --- #### 6. **核心注意事项** 1. **迭代器失效**: - `erase()` 和 `pop_back()` 会使被删元素及之后的所有迭代器失效[^1] - **正确做法**:循环中始终使用 `erase()` 返回值更新迭代器(见第2节示例) 2. **性能影响**: - 头部/中部删除效率低(需移动元素),优先从末尾删除 - 批量删除用 Erase-Remove 模式比手动循环高效 3. **内存管理**: - `clear()` 后容量不变,需显式调用 `shrink_to_fit()` 释放内存[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值