remove函数详解(27. 移除元素)

先了解三个函数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::vectorstd::liststd::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() 函数(容器成员函数)

  • 参数
    有两种重载形式:

    1. resize(size_type new_size)
      • new_size:容器调整后的新大小(元素个数)。
    2. 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}

力扣likoulikoliklil27. 移除元素


第一想法是使用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;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值