先了解三个函数remove(),resize(),erase()
在C++编程语言中,std::remove
是一个非常有用的函数。它可以用于从容器中移除特定的元素,而不改变容器的大小。
remove函数
1. std::remove
函数的定义和用法
1.1 定义
std::remove
函数是C++标准库算法的一部分,定义在头文件<algorithm>
中。其函数原型如下:
template <class ForwardIt, class T>
ForwardIt remove(ForwardIt first, ForwardIt last, const T& value);
1.2 参数
std::remove
函数接受三个参数:
first
:表示要操作的容器的起始位置的迭代器。last
:表示要操作的容器的结束位置的迭代器。value
:表示要移除的元素的值。
1.3 返回值
std::remove
函数返回一个指向最后一个不需要移除的元素之后位置的迭代器,也就是移除元素后的新的结束位置。
1.4 用法
std::remove
函数的使用非常简单。下面是一个示例代码,演示了如何使用std::remove
函数从一个std::vector
容器中移除特定的元素。
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> nums {1, 2, 3, 4, 5, 4, 6, 7, 4, 8};
// 移除容器中值为4的元素
auto new_end = std::remove(nums.begin(), nums.end(), 4);
// 输出移除元素后的容器内容
for (auto it = nums.begin(); it != new_end; ++it) {
std::cout << *it << " ";
}
return 0;
}
运行结果:
1 2 3 5 6 7 8
从运行结果可以看出,值为4的元素已经被成功移除,容器中不包含该元素。
2. std::remove
函数的实现原理
2.1 算法思路
std::remove
函数的实现原理是基于谓词的。首先它会遍历容器中的每个元素,使用谓词value == *it
进行比较,如果相等则将该元素移动到容器的末尾,然后将末尾位置返回。这样,容器中相等于value
的元素会被移到容器的末尾,而不等于value
的元素则保持在原位置。
2.2 复杂度分析
std::remove
函数的时间复杂度是O(N),其中N是容器中的元素数量。它的空间复杂度为O(1),因为它只需要常数级别的额外空间。
2.3 实现示例
下面是一个简化版的std::remove
函数实现的示例代码:
template <class ForwardIt, class T>
ForwardIt remove(ForwardIt first, ForwardIt last, const T& value) {
ForwardIt result = first;
while (first != last) {
if (!(*first == value)) {
*result = std::move(*first);
++result;
}
++first;
}
return result;
}
3. std::remove
函数的注意事项
3.1 容器的大小不变
需要注意的是,std::remove
函数只是移除容器中的元素,并不改变容器的大小。如果想要改变容器的大小以适应移除后的元素数量,可以使用erase
函数来实现。
3.2 使用谓词函数
std::remove
函数使用了等于操作符进行元素比较。如果想要自定义元素的比较方式,可以使用谓词函数作为第四个参数传入std::remove_if
函数。谓词函数应返回一个bool
值,指示元素是否满足移除的条件。
3.3 适用于各种容器
std::remove
函数适用于各种容器类型,如std::vector
、std::list
、std::deque
等。只要容器满足迭代器的要求,都可以使用std::remove
函数进行元素的移除操作。
特别的,与 STL 算法库中的 std::remove()
不同,std::list
自带成员函数 remove()
,专门用于删除链表中所有值等于指定值的元素。其操作直接针对链表节点,效率更高(无需移动元素,仅调整指针)。使用示例:
#include <iostream>
#include <list> // 需包含list头文件
int main() {
// 1. 初始化list,包含重复元素
std::list<int> nums{1, 2, 3, 2, 4, 2, 5};
std::cout << "删除前的链表:";
for (int num : nums) {
std::cout << num << " "; // 输出:1 2 3 2 4 2 5
}
std::cout << std::endl;
// 2. 使用remove()删除所有值为2的元素
nums.remove(2);
// 3. 输出删除后的结果
std::cout << "删除后的链表:";
for (int num : nums) {
std::cout << num << " "; // 输出:1 3 4 5
}
std::cout << std::endl;
return 0;
}
与 std::remove () 的区别
对比项 | list::remove ()(成员函数) | std::remove ()(算法库函数) |
---|---|---|
适用对象 | 仅针对 std::list 容器 | 适用于所有支持随机访问迭代器的容器(如 vector) |
实现逻辑 | 直接删除节点(调整指针),真正释放内存 | 仅将匹配元素移到容器末尾,不删除(需配合 erase ()) |
时间复杂度 | O (n)(遍历一次,删除操作 O (1)) | O (n)(遍历 + 移动元素,移动操作 O (n)) |
是否改变容器大小 | 是(删除节点,大小减小) | 否(仅重排元素,大小不变) |
erase()
函数(容器成员函数)
erase函数的原型如下:
(1)string& erase ( size_t pos = 0, size_t n = npos );
(2)iterator erase ( iterator position );
(3)iterator erase ( iterator first, iterator last );
也就是说有三种用法:
(1)erase(pos,n); 删除从pos开始的n个字符,比如erase(0,1)就是删除第一个字符
(2)erase(position);删除position处的一个字符(position是个string类型的迭代器)
(3)erase(first,last);删除从first到last之间的字符(first和last都是迭代器)
例子如下:
#include<string>
#include<iostream>
using namespace std;
int main ()
{
string str ("This is an example phrase.");
string::iterator it;
//第(1)种方法
str.erase (10,8);
cout << str << endl; // "This is an phrase."
//第(2)种方法
it=str.begin()+9;
str.erase (it);
cout << str << endl; // "This is a phrase."
//第(3)种方法
str.erase (str.begin()+5, str.end()-7);
cout << str << endl; // "This phrase."
return 0;
}
resize()
函数(容器成员函数)
-
参数:
有两种重载形式:resize(size_type new_size)
:new_size
:容器调整后的新大小(元素个数)。
resize(size_type new_size, const T& value)
:new_size
:同上。value
:当新大小大于当前大小时,新增元素的初始值(默认值为元素类型的默认构造值)。
-
返回值:
无返回值(void
)。 -
示例:
vector<int> v = {1, 2, 3}; v.resize(5, 10); // 新大小为5,新增元素用10填充,v变为 {1,2,3,10,10}
第一想法是使用remove函数
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int ans=0;
for(int i:nums){
if(i!=val) ans++;
}
remove(nums.begin(),nums.end(),val);
return ans;
}
};
第二想法使用erase函数,复杂度On^2,原因每次删除都需要移动元素
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
for(auto it=nums.begin();it!=nums.end();){
if(*it==val){
nums.erase(it);
}else{
it++;
}
}
return nums.size();
}
};
第三种做法,快慢指针法,时间复杂度On,做题时没有想到
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int index=0;
for(int i=0;i<nums.size();i++){
if(nums[i]!=val){
nums[index++]=nums[i];
}
}
return index;
}
};