c++标准模板(STL)- 算法 (std::remove, std::remove_if)

定义于头文件 

算法库提供大量用途的函数(例如查找、排序、计数、操作),它们在元素范围上操作。注意范围定义为 [first, last) ,其中 last 指代要查询或修改的最后元素的后一个元素。

移除满足特定判别标准的元素

std::remove, 
std::remove_if

template< class ForwardIt, class T >
ForwardIt remove( ForwardIt first, ForwardIt last, const T& value );

(1) (C++20 前)

template< class ForwardIt, class T >
constexpr ForwardIt remove( ForwardIt first, ForwardIt last, const T& value );

(C++20 起)

template< class ExecutionPolicy, class ForwardIt, class T >
ForwardIt remove( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, const T& value );

(2) (C++17 起)

template< class ForwardIt, class UnaryPredicate >
ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPredicate p );

(3) (C++20 前)

template< class ForwardIt, class UnaryPredicate >
constexpr ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPredicate p );

(C++20 起)

template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate >
ForwardIt remove_if( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, UnaryPredicate p );

(4) (C++17 起)

从范围 [first, last) 移除所有满足特定判别标准的元素,并返回范围新结尾的尾后迭代器。

1) 移除所有等于 value 的元素。

3) 移除所有 p 对于它返回 true 的元素,用 operator== 比较它们。

2,4) 同 (1,3) ,但按照 policy 执行。这些重载仅若 std::is_execution_policy_v> 为 true 才参与重载决议。

通过以满足不移除的元素出现在范围起始的方式,迁移(以移动赋值的方式)范围中的元素进行移除。保持剩余元素的相对顺序,且不更改容器的物理大小。指向范围的新逻辑结尾和物理结尾之间元素的迭代器仍然可解引用,但元素自身拥有未指定值(因为可移动赋值 (MoveAssignable) 的后置条件)。调用 remove 典型地后随调用容器的 erase 方法,它擦除未指定值并减小容器的物理大小,以匹配其新的逻辑大小。

参数

first, last - 要处理的元素范围
value - 要移除的元素值
policy - 所用的执行策略。细节见执行策略。
p - 若应该移除元素则返回 ​true 的一元谓词。

对每个(可为 const 的) VT 类型参数 v ,其中 VTForwardIt 的值类型,表达式 p(v) 必须可转换为 bool ,无关乎值类别,而且必须不修改 v 。从而不允许 VT& 类型参数,亦不允许 VT ,除非对 VT 而言移动等价于复制 (C++11 起)。 ​

类型要求
- ForwardIt 必须满足遗留向前迭代器 (LegacyForwardIterator) 的要求。
- 解引用 ForwardIt 结果的类型必须满足可移动赋值 (MoveAssignable) 的要求。
- UnaryPredicate 必须满足谓词 (Predicate) 的要求。

返回值

新值范围的尾后迭代器(若它不是 end ,则它指向未指定值,而此迭代器与 end 之间的迭代器所指向的任何值亦然)。

复杂度

准确应用 std::distance(first, last) 次谓词。

异常

拥有名为 ExecutionPolicy 的模板形参的重载按下列方式报告错误:

  • 若作为算法一部分调用的函数的执行抛出异常,且 ExecutionPolicy 为标准策略之一,则调用 std::terminate 。对于任何其他 ExecutionPolicy ,行为是实现定义的。
  • 若算法无法分配内存,则抛出 std::bad_alloc 。

注意

同名的容器成员函数 list::remove 、 list::remove_if 、 forward_list::remove 及 forward_list::remove_if 擦除被移除的元素。

这些算法不可用于关联容器,如 std::set 和 std::map ,因为 ForwardIt 不能解引用为可移动赋值 (MoveAssignable) 类型(这些容器中的关键不可修改)。

标准库亦定义 std::remove 接收 const char* 的重载,用于删除文件: std::remove 。

因为 std::remove 以引用接收 value ,若引用到范围 [first, last) 中的元素,则它能有不期待的行为。

 可能的实现

版本一

template< class ForwardIt, class T >
ForwardIt remove(ForwardIt first, ForwardIt last, const T& value)
{
    first = std::find(first, last, value);
    if (first != last)
        for(ForwardIt i = first; ++i != last; )
            if (!(*i == value))
                *first++ = std::move(*i);
    return first;
}

版本二 

template
ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate p)
{
    first = std::find_if(first, last, p);
    if (first != last)
        for(ForwardIt i = first; ++i != last; )
            if (!p(*i))
                *first++ = std::move(*i);
    return first;
}

调用示例

#include 
#include 
#include 
#include 
#include 

struct Cell
{
    int x;
    int y;
    Cell &operator+=(Cell &cell)
    {
        x += cell.x;
        y += cell.y;
        return *this;
    }

    bool operator ==(const Cell &cell)
    {
        return x == cell.x && y == cell.y;
    }
};

std::ostream &operator<<(std::ostream &os, const Cell &cell)
{
    os << "{" << cell.x << "," << cell.y << "}";
    return os;
}

int main()
{
    auto func1 = []()
    {
        static Cell cell = {-2, -1};
        cell.x += 2;
        cell.y += 2;
        return cell;
    };

    std::vector cells(5);
    std::generate_n(cells.begin(), cells.size(), func1);

    Cell cell{4, 5};
    cells.push_back(cell);

    std::cout << "original   vector:    ";
    std::copy(cells.begin(), cells.end(), std::ostream_iterator(std::cout, " "));
    std::cout << std::endl;

    std::remove(cells.begin(), cells.end(), cell);
    // 并未真正刪除,该元素之后的元素前移
    std::cout << "remove     vector:    ";
    std::copy(cells.begin(), cells.end(), std::ostream_iterator(std::cout, " "));
    std::cout << std::endl << std::endl;


    auto func2 = [](const Cell & ocell, const Cell & cell)
    {
        return ocell.x == cell.x && ocell.y == cell.y;
    };

    std::generate_n(cells.begin(), cells.size(), func1);
    cell = {16, 17};
    std::cout << "original   vector:    ";
    std::copy(cells.begin(), cells.end(), std::ostream_iterator(std::cout, " "));
    std::cout << std::endl;

    std::remove_if(cells.begin(), cells.end(), std::bind(func2, cell, std::placeholders::_1));
    // 并未真正刪除,该元素之后的元素前移
    std::cout << "remove     vector:    ";
    std::copy(cells.begin(), cells.end(), std::ostream_iterator(std::cout, " "));
    std::cout << std::endl;
}

输出

c++标准模板(STL)- 算法 (std::remove, std::remove_if)_第1张图片

 

你可能感兴趣的:(#,修改序列的操作,c++,算法,remove,remove_if)