C++11 STL常用算法
C++11 STL常用算法

清平乐·六盘山
天高云淡,望断南飞雁。不到长城非好汉,屈指行程二万。
六盘山上高峰,红旗漫卷西风。今日长缨在手,何时缚住苍龙?
1. 非修改序列操作
1.1 批处理操作
1.1.1 for_each
函数对象,将应用于[first, last) 中每个迭代器解引用后的结果 函数的签名应等效于以下内容 void fun(const Type &a);签名不需要有 const &。 类型 Type 必须是使得类型为 InputIt 的对象可以被解引用,然后隐式转换为 Type。
template< class InputIt, class UnaryFunc >
UnaryFunc for_each( InputIt first, InputIt last, UnaryFunc f );
伪码实现
template<class InputIt, class UnaryFunc>
constexpr UnaryFunc for_each(InputIt first, InputIt last, UnaryFunc f)
{
for (; first != last; ++first)
f(*first);
return f;
}
测试案例:
std::vector<int> v{3, -4, 2, -8, 15, 267};
auto print = [](const int& n) { std::cout << n << ' '; };
std::cout << "before:\t";
std::for_each(v.cbegin(), v.cend(), print);
std::cout << '\n';
// increment elements in-place
std::for_each(v.begin(), v.end(), [](int &n) { n++; });
std::cout << "after:\t";
std::for_each(v.cbegin(), v.cend(), print);
std::cout << '\n';
/// 输出结果
before: 3 -4 2 -8 15 267
after: 4 -3 3 -7 16 268
1.2 搜索操作
1.2.1 all_of | any_of | none_of
template< class InputIt, class UnaryFunc >
// 1. 检查一元谓词 p 对于范围 [first, last) 中至少一个元素是否返回 false
bool all_of( InputIt first, InputIt last, UnaryPred p );
// 2. 检查一元谓词 p 对于范围 [first, last) 中至少一个元素是否返回 true
bool any_of( InputIt first, InputIt last, UnaryPred p );
// 3. 检查一元谓词 p 对于范围 [first, last) 中所有元素是否均不返回 true
bool none_of( InputIt first, InputIt last, UnaryPred p );
伪码实现
template<class InputIt, class UnaryPred>
constexpr bool all_of(InputIt first, InputIt last, UnaryPred p)
{
return std::find_if_not(first, last, p) == last;
}
template<class InputIt, class UnaryPred>
constexpr bool any_of(InputIt first, InputIt last, UnaryPred p)
{
return std::find_if(first, last, p) != last;
}
template<class InputIt, class UnaryPred>
constexpr bool none_of(InputIt first, InputIt last, UnaryPred p)
{
return std::find_if(first, last, p) == last;
}
测试案例:
std::vector<int> v(10, 2);
std::partial_sum(v.cbegin(), v.cend(), v.begin());
std::cout << "Among the numbers: ";
std::copy(v.cbegin(), v.cend(), std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
if (std::all_of(v.cbegin(), v.cend(), [](int i) { return i % 2 == 0; }))
std::cout << "All numbers are even\n";
if (std::none_of(v.cbegin(), v.cend(), std::bind(std::modulus<>(),
std::placeholders::_1, 2)))
std::cout << "None of them are odd\n";
struct DivisibleBy
{
const int d;
DivisibleBy(int n) : d(n) {}
bool operator()(int n) const { return n % d == 0; }
};
if (std::any_of(v.cbegin(), v.cend(), DivisibleBy(7)))
std::cout << "At least one number is divisible by 7\n";
/// 输出结果
Among the numbers: 2 4 6 8 10 12 14 16 18 20
All numbers are even
None of them are odd
At least one number is divisible by 7
1.2.2 find | find_if | find_if_not
寻找第一个满足特定条件的元素
template< class InputIt, class UnaryFunc >
// 1. find 搜索等于 value 的元素(使用 operator==)。
InputIt find( InputIt first, InputIt last, const T& value );
// 2. find_if 搜索谓词 p 返回 true 的元素。
InputIt find_if( InputIt first, InputIt last, UnaryPred p );
// 3. find_if_not 搜索谓词 q 返回 false 的元素。
InputIt find_if_not( InputIt first, InputIt last, UnaryPred q );
伪码实现
template<class InputIt, class T = typename std::iterator_traits<InputIt>::value_type>
constexpr InputIt find(InputIt first, InputIt last, const T& value)
{
for (; first != last; ++first)
if (*first == value)
return first;
return last;
}
template<class InputIt, class UnaryPred>
constexpr InputIt find_if(InputIt first, InputIt last, UnaryPred p)
{
for (; first != last; ++first)
if (p(*first))
return first;
return last;
}
template<class InputIt, class UnaryPred>
constexpr InputIt find_if_not(InputIt first, InputIt last, UnaryPred q)
{
for (; first != last; ++first)
if (!q(*first))
return first;
return last;
}
测试案例:
const auto haystack = {1, 2, 3, 4};
for (const int needle : {3, 5})
if (std::find(haystack.begin(), haystack.end(), needle) == haystack.end())
std::cout << "haystack does not contain " << needle << '\n';
else
std::cout << "haystack contains " << needle << '\n';
for (const auto& haystack : {std::array{3, 1, 4}, {1, 3, 5}})
{
const auto it = std::find_if(haystack.begin(), haystack.end(), is_even);
if (it != haystack.end())
std::cout << "haystack contains an even number " << *it << '\n';
else
std::cout << "haystack does not contain even numbers\n";
}
/// 输出结果
haystack contains 3
haystack does not contain 5
haystack contains an even number 4
haystack does not contain even numbers
1.2.3 count | count_if
返回满足特定条件的元素数量
template< class InputIt, class UnaryFunc >
// 1. find 搜索等于 value 的元素(使用 operator==)。
typename std::iterator_traits<InputIt>::difference_type
count( InputIt first, InputIt last, const T& value );
// 2. find_if 搜索谓词 p 返回 true 的元素。
typename std::iterator_traits<InputIt>::difference_type
count_if( InputIt first, InputIt last, UnaryPred p );
伪码实现
template<class InputIt, class T = typename std::iterator_traits<InputIt>::value_type>
typename std::iterator_traits<InputIt>::difference_type
count(InputIt first, InputIt last, const T& value)
{
typename std::iterator_traits<InputIt>::difference_type ret = 0;
for (; first != last; ++first)
if (*first == value)
++ret;
return ret;
}
template<class InputIt, class UnaryPred>
typename std::iterator_traits<InputIt>::difference_type
count_if(InputIt first, InputIt last, UnaryPred p)
{
typename std::iterator_traits<InputIt>::difference_type ret = 0;
for (; first != last; ++first)
if (p(*first))
++ret;
return ret;
}
测试案例:
constexpr std::array v{1, 2, 3, 4, 4, 3, 7, 8, 9, 10};
std::cout << "v: ";
std::copy(v.cbegin(), v.cend(), std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
// Determine how many integers match a target value.
for (const int target : {3, 4, 5})
{
const int num_items = std::count(v.cbegin(), v.cend(), target);
std::cout << "number: " << target << ", count: " << num_items << '\n';
}
// Use a lambda expression to count elements divisible by 4.
int count_div4 = std::count_if(v.begin(), v.end(), [](int i) { return i % 4 == 0; });
std::cout << "numbers divisible by four: " << count_div4 << '\n';
/// 输出结果
v: 1 2 3 4 4 3 7 8 9 10
number: 3, count: 2
number: 4, count: 2
number: 5, count: 0
numbers divisible by four: 3
1.2.4 search | search_if
搜索一个范围的元素首次出现的位置。
指向范围 [first, last) 中序列 [s_first, s_last) 第一次出现的起始位置的迭代器。如果没有找到这样的出现,则返回 last。
template< class InputIt, class UnaryFunc >
ForwardIt1 search( ForwardIt1 first, ForwardIt1 last,
ForwardIt2 s_first, ForwardIt2 s_last );
伪码实现
template<class ForwardIt1, class ForwardIt2>
constexpr //< since C++20
ForwardIt1 search(ForwardIt1 first, ForwardIt1 last,
ForwardIt2 s_first, ForwardIt2 s_last)
{
while (true)
{
ForwardIt1 it = first;
for (ForwardIt2 s_it = s_first; ; ++it, ++s_it)
{
if (s_it == s_last)
return first;
if (it == last)
return last;
if (!(*it == *s_it))
break;
}
++first;
}
}
测试案例:
std::vector<int> vec1 = {1, 2, 3, 4};
std::vector<int> v2 = {2, 3};
std::vector<int> v = {1, 4};
auto iter = std::search(vec1.cbegin(), vec1.cend(), v.cbegin(), v.cend());
// 检查是否找到
if (iter != vec1.cend()) {
std::cout << "Found at position: " << std::distance(vec1.cbegin(), iter) << std::endl;
} else {
std::cout << "Not found!" << std::endl;
}
/// 输出结果
Not found!
1.2.5 adjacent_find
寻找第一对相等的(或满足给定谓词的)相邻项
在范围 [first, last) 中搜索两个连续相等的元素。
template< class InputIt, class UnaryFunc >
ForwardIt adjacent_find( ForwardIt first, ForwardIt last );
伪码实现
template<class ForwardIt>
ForwardIt adjacent_find(ForwardIt first, ForwardIt last)
{
if (first == last)
return last;
ForwardIt next = first;
++next;
for (; next != last; ++next, ++first)
if (*first == *next)
return first;
return last;
}
测试案例:
std::vector<int> v1{0, 1, 2, 3, 40, 40, 41, 41, 5};
auto i1 = std::adjacent_find(v1.begin(), v1.end());
if (i1 == v1.end())
std::cout << "No matching adjacent elements\n";
else
std::cout << "The first adjacent pair of equal elements is at "
<< std::distance(v1.begin(), i1) << ", *i1 = "
<< *i1 << '\n';
/// 输出结果
The first adjacent pair of equal elements is at 4, *i1 = 40
1.2.6 find_first_if
用于在第一个范围中查找第二个范围中任意一个元素的首次出现位置。
template< class InputIt, class UnaryFunc >
InputIt find_first_of( InputIt first, InputIt last,
ForwardIt s_first, ForwardIt s_last );
伪码实现
template<class InputIt, class ForwardIt>
InputIt find_first_of(InputIt first, InputIt last,
ForwardIt s_first, ForwardIt s_last)
{
for (; first != last; ++first)
for (ForwardIt it = s_first; it != s_last; ++it)
if (*first == *it)
return first;
return last;
}
测试案例:
std::vector<int> data = {1, 2, 3, 4, 5, 6};
std::vector<int> search_for = {3, 5, 7};
// 在data中查找search_for中的任意一个数字
auto it = std::find_first_of(data.begin(), data.end(),
search_for.begin(), search_for.end());
if (it != data.end()) {
std::cout << "Found " << *it << " at position "
<< std::distance(data.begin(), it) << std::endl;
// 输出: Found 3 at position 2
} else {
std::cout << "Not found" << std::endl;
}
2 修改序列操作
2.1 复制操作
2.1.1 copy | copy_if
将源范围内的元素复制到目标位置。
template< class InputIt, class UnaryFunc >
OutputIt copy( InputIt first, InputIt last,
OutputIt d_first );
template< class InputIt, class OutputIt, class UnaryPred >
OutputIt copy_if( InputIt first, InputIt last,
OutputIt d_first, UnaryPred pred );
伪码实现
template<class InputIt, class OutputIt>
OutputIt copy(InputIt first, InputIt last,
OutputIt d_first)
{
for (; first != last; (void)++first, (void)++d_first)
*d_first = *first;
return d_first;
}
template<class InputIt, class OutputIt, class UnaryPred>
OutputIt copy_if(InputIt first, InputIt last,
OutputIt d_first, UnaryPred pred)
{
for (; first != last; ++first)
if (pred(*first))
{
*d_first = *first;
++d_first;
}
return d_first;
}
测试案例:
std::vector<int> source = {1, 2, 3, 4, 5};
std::vector<int> destination(5); // 需要预分配空间
// 复制整个范围
std::copy(source.begin(), source.end(), destination.begin());
// 输出结果:1 2 3 4 5
for (int num : destination) {
std::cout << num << " ";
}
std::cout << std::endl;
std::vector<int> src = {10, 20, 30, 40, 50};
std::vector<int> dst(3);
std::copy(src.begin() + 1, src.begin() + 4, dst.begin());
// dst: {20, 30, 40}
2.2 转换操作
这两个算法用于替换容器中满足条件的元素。
2.2.1 replace| replace_if
将源范围内的元素复制到目标位置。
template< class ForwardIt, class T >
void replace( ForwardIt first, ForwardIt last,
const T& old_value, const T& new_value );
template< class ForwardIt, class UnaryPred,
class T = typename std::iterator_traits
<ForwardIt>::value_type> >
constexpr void replace_if( ForwardIt first, ForwardIt last,
UnaryPred p, const T& new_value );
伪码实现
template<class ForwardIt,
class T = typename std::iterator_traits<ForwardIt>::value_type>
void replace(ForwardIt first, ForwardIt last,
const T& old_value, const T& new_value)
{
for (; first != last; ++first)
if (*first == old_value)
*first = new_value;
}
template<class ForwardIt, class UnaryPred,
class T = typename std::iterator_traits<ForwardIt>::value_type>
void replace_if(ForwardIt first, ForwardIt last,
UnaryPred p, const T& new_value)
{
for (; first != last; ++first)
if (p(*first))
*first = new_value;
}
测试案例:
std::vector<int> numbers = {1, 2, 3, 2, 4, 2, 5};
// 将所有值为 2 的元素替换为 99
std::replace(numbers.begin(), numbers.end(), 2, 99);
// 将所有偶数替换为 0
std::replace_if(numbers.begin(), numbers.end(),
[](int x) { return x % 2 == 0; }, 0);
2.3 生成操作
2.3.1 fill | fill_n
将给定值复制赋给一个范围中的每个元素
template< class ForwardIt, class T >
void fill( ForwardIt first, ForwardIt last, const T& value );
template< class OutputIt, class Size, class T >
OutputIt fill_n( OutputIt first, Size count, const T& value );
伪码实现
template<class ForwardIt,
class T = typename std::iterator_traits<ForwardIt>::value_type>
void fill(ForwardIt first, ForwardIt last, const T& value)
{
for (; first != last; ++first)
*first = value;
}
template<class OutputIt, class Size,
class T = typename std::iterator_traits<OutputIt>::value_type>
OutputIt fill_n(OutputIt first, Size count, const T& value)
{
for (Size i = 0; i < count; i++)
*first++ = value;
return first;
}
测试案例:
std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8};
println(v);
// set all of the elements to 8
std::fill(v.begin(), v.end(), 8);
println(v);
std::vector<int> v1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
// replace values of the first 5 elements with -1
std::fill_n(v1.begin(), 5, -1);
2.3.2 generate
将连续函数调用的结果赋给一个范围中的每个元素
template< class ForwardIt, class Generator >
void generate( ForwardIt first, ForwardIt last, Generator g );
伪码实现
template<class ForwardIt, class Generator>
constexpr //< since C++20
void generate(ForwardIt first, ForwardIt last, Generator g)
{
for (; first != last; ++first)
*first = g();
}
测试案例:
int f()
{
static int i;
return ++i;
}
int main()
{
std::vector<int> v(5);
std::generate(v.begin(), v.end(), f);
println("v: ", v);
// Initialize with default values 0,1,2,3,4 from a lambda function
// Equivalent to std::iota(v.begin(), v.end(), 0);
std::generate(v.begin(), v.end(), [n = 0] () mutable { return n++; });
println("v: ", v);
v: 1 2 3 4 5
v: 0 1 2 3 4
}
2.4 移除操作
2.4.1 remove | remove_if
这两个算法用于"移除"容器中满足条件的元素,但不会真正删除元素,而是将不需要移除的元素移动到容器前面,返回新的逻辑结尾。
template< class ForwardIt, class T >
ForwardIt remove( ForwardIt first, ForwardIt last, const T& value );
template< class ForwardIt, class UnaryPred >
ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPred p );
伪码实现
template<class ForwardIt, class T = typename std::iterator_traits<ForwardIt>::value_type>
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<class ForwardIt, class UnaryPred>
ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPred 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;
}
测试案例:
int main()
{
std::vector<int> numbers = {1, 2, 3, 2, 4, 2, 5, 2};
std::cout << "原始数据: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 移除所有值为2的元素
auto new_end = std::remove(numbers.begin(), numbers.end(), 2);
std::cout << "remove后(容器实际内容): ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
std::cout << "逻辑有效范围: ";
for (auto it = numbers.begin(); it != new_end; ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
// 真正删除
numbers.erase(new_end, numbers.end());
std::cout << "erase后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
std::cout << "容器大小: " << numbers.size() << std::endl;
// 输出
原始数据: 1 2 3 2 4 2 5 2
remove后(容器实际内容): 1 3 4 5 4 2 5 2
逻辑有效范围: 1 3 4 5
erase后: 1 3 4 5
容器大小: 4
}
2.4.2 unique
移除一个范围中的连续重复元素
template< class ForwardIt >
ForwardIt unique( ForwardIt first, ForwardIt last );
伪码实现
template<class ForwardIt>
ForwardIt unique(ForwardIt first, ForwardIt last)
{
if (first == last)
return last;
ForwardIt result = first;
while (++first != last)
if (!(*result == *first) && ++result != first)
*result = std::move(*first);
return ++result;
}
测试案例:
int f()
{
static int i;
return ++i;
}
int main()
{
std::vector<int> numbers = {1, 2, 2, 3, 3, 3, 4, 5, 5, 5, 5, 6};
std::cout << "原始数据: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 先排序
std::sort(numbers.begin(), numbers.end());
std::cout << "排序后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
// 使用 unique 移除相邻重复元素
auto new_end = std::unique(numbers.begin(), numbers.end());
std::cout << "unique后: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
std::cout << "有效范围: ";
for (auto it = numbers.begin(); it != new_end; ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
// 真正删除重复元素
numbers.erase(new_end, numbers.end());
std::cout << "最终结果: ";
for (int n : numbers) std::cout << n << " ";
std::cout << std::endl;
原始数据: 1 2 2 3 3 3 4 5 5 5 5 6
排序后: 1 2 2 3 3 3 4 5 5 5 5 6
unique后: 1 2 3 4 5 6 3 4 5 5 5 6 // 后面是"垃圾"数据
有效范围: 1 2 3 4 5 6
最终结果: 1 2 3 4 5 6
}
2.5 改变顺序操作
2.5.1 reverse
反转一个范围中元素的顺序
template< class BidirIt >
void reverse( BidirIt first, BidirIt last );
伪码实现
template<class BidirIt>
constexpr // since C++20
void reverse(BidirIt first, BidirIt last)
{
using iter_cat = typename std::iterator_traits<BidirIt>::iterator_category;
// Tag dispatch, e.g. calling reverse_impl(first, last, iter_cat()),
// can be used in C++14 and earlier modes.
if constexpr (std::is_base_of_v<std::random_access_iterator_tag, iter_cat>)
{
if (first == last)
return;
for (--last; first < last; (void)++first, --last)
std::iter_swap(first, last);
}
else
while (first != last && first != --last)
std::iter_swap(first++, last);
}
测试案例:
int main()
{
std::vector<int> v {1, 2, 3};
std::reverse(v.begin(), v.end());
println("after reverse, v = ", v);
int a[] = {4, 5, 6, 7};
std::reverse(std::begin(a), std::end(a));
println("after reverse, a = ", a);
// 输出
after reverse, v = 3 2 1
after reverse, a = 7 6 5 4
}
2.5.2 shuffle
重新排列给定范围 [first, last) 中的元素,使得这些元素所有可能的排列都具有相同的出现概率。
template< class RandomIt >
void random_shuffle( RandomIt first, RandomIt last );
伪码实现
template<class RandomIt>
void random_shuffle(RandomIt first, RandomIt last)
{
typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
for (diff_t i = last - first - 1; i > 0; --i)
{
using std::swap;
swap(first[i], first[std::rand() % (i + 1)]);
// rand() % (i + 1) is not actually correct, because the generated number is
// not uniformly distributed for most values of i. The correct code would be
// a variation of the C++11 std::uniform_int_distribution implementation.
}
}
测试案例:
int main()
{
std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(v.begin(), v.end(), g);
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
// 输出
8 6 10 4 2 3 7 1 9 5
}
3. 排序操作
3.1 sort | stable_sort
重新排列给定范围 [first, last) 中的元素,使得这些元素所有可能的排列都具有相同的出现概率。
对一个范围的元素进行排序,同时保留相等元素之间的顺序(stable_sort).
template< class RandomIt >
void sort( RandomIt first, RandomIt last );
template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );
template< class RandomIt >
void stable_sort( RandomIt first, RandomIt last );
伪码实现
测试案例:
int main()
{
std::array<int, 10> s{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
auto print = [&s](std::string_view const rem)
{
for (auto a : s)
std::cout << a << ' ';
std::cout << ": " << rem << '\n';
};
std::sort(s.begin(), s.end());
print("sorted with the default operator<");
std::sort(s.begin(), s.end(), std::greater<int>());
print("sorted with the standard library compare function object");
struct
{
bool operator()(int a, int b) const { return a < b; }
}
customLess;
std::sort(s.begin(), s.end(), customLess);
print("sorted with a custom function object");
std::sort(s.begin(), s.end(), [](int a, int b)
{
return a > b;
});
print("sorted with a lambda expression");
// 输出
0 1 2 3 4 5 6 7 8 9 : sorted with the default operator<
9 8 7 6 5 4 3 2 1 0 : sorted with the standard library compare function object
0 1 2 3 4 5 6 7 8 9 : sorted with a custom function object
9 8 7 6 5 4 3 2 1 0 : sorted with a lambda expression
}
4 集合操作
4.1 includes
如果一个序列是另一个序列的子序列,则返回 true。
template< class InputIt1, class InputIt2 >
bool includes( InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2 );
template< class InputIt1, class InputIt2, class Compare >
bool includes( InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2, Compare comp );
伪码实现
template<class InputIt1, class InputIt2>
bool includes(InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2)
{
for (; first2 != last2; ++first1)
{
if (first1 == last1 || *first2 < *first1)
return false;
if (!(*first1 < *first2))
++first2;
}
return true;
}
template<class InputIt1, class InputIt2, class Compare>
bool includes(InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2, Compare comp)
{
for (; first2 != last2; ++first1)
{
if (first1 == last1 || comp(*first2, *first1))
return false;
if (!comp(*first1, *first2))
++first2;
}
return true;
}
测试案例:
int main()
{
const auto
v1 = {'a', 'b', 'c', 'f', 'h', 'x'},
v2 = {'a', 'b', 'c'},
v3 = {'a', 'c'},
v4 = {'a', 'a', 'b'},
v5 = {'g'},
v6 = {'a', 'c', 'g'},
v7 = {'A', 'B', 'C'};
auto no_case = [](char a, char b) { return std::tolower(a) < std::tolower(b); };
std::cout
<< v1 << "\nincludes:\n" << std::boolalpha
<< v2 << ": " << std::includes(v1.begin(), v1.end(), v2.begin(), v2.end()) << '\n'
<< v3 << ": " << std::includes(v1.begin(), v1.end(), v3.begin(), v3.end()) << '\n'
<< v4 << ": " << std::includes(v1.begin(), v1.end(), v4.begin(), v4.end()) << '\n'
<< v5 << ": " << std::includes(v1.begin(), v1.end(), v5.begin(), v5.end()) << '\n'
<< v6 << ": " << std::includes(v1.begin(), v1.end(), v6.begin(), v6.end()) << '\n'
<< v7 << ": " << std::includes(v1.begin(), v1.end(), v7.begin(), v7.end(), no_case)
<< " (case-insensitive)\n";
// 输出
a b c f h x
includes:
a b c : true
a c : true
a a b : false
g : false
a c g : false
A B C : true (case-insensitive)
}
4.2 set_union
计算两个已经排序好的集合的并集
template< class InputIt1, class InputIt2, class OutputIt >
OutputIt set_union( InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2,
OutputIt d_first );
template< class InputIt1, class InputIt2,
class OutputIt, class Compare >
OutputIt set_union( InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2,
OutputIt d_first, Compare comp );
伪码实现
template<class InputIt1, class InputIt2, class OutputIt>
OutputIt set_union(InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2, OutputIt d_first)
{
for (; first1 != last1; ++d_first)
{
if (first2 == last2)
return std::copy(first1, last1, d_first);
if (*first2 < *first1)
*d_first = *first2++;
else
{
*d_first = *first1;
if (!(*first1 < *first2))
++first2;
++first1;
}
}
return std::copy(first2, last2, d_first);
}
测试案例:
int main()
{
std::vector<int> v1, v2, dest;
v1 = {1, 2, 3, 4, 5};
v2 = {3, 4, 5, 6, 7};
std::set_union(v1.cbegin(), v1.cend(),
v2.cbegin(), v2.cend(),
std::back_inserter(dest));
println(dest);
dest.clear();
v1 = {1, 2, 3, 4, 5, 5, 5};
v2 = {3, 4, 5, 6, 7};
std::set_union(v1.cbegin(), v1.cend(),
v2.cbegin(), v2.cend(),
std::back_inserter(dest));
println(dest);
// 输出
1 2 3 4 5 6 7
1 2 3 4 5 5 5 6 7
}
4.3 set_intersection
计算两个集合的交集。
构造一个始于 d_first 的有序范围,该范围由在两个有序范围 [first1, last1) 和 [first2, last2) 中都存在的元素组成。
如果 [first1, last1) 包含 m 个彼此等价的元素,且 [first2, last2) 包含 n 个与它们等价的元素,则将前 std::min(m, n) 个元素从 [first1, last1) 复制到输出范围,并保留顺序。
template< class InputIt1, class InputIt2, class OutputIt >
OutputIt set_intersection( InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2,
OutputIt d_first );
伪码实现
template<class InputIt1, class InputIt2, class OutputIt>
OutputIt set_intersection(InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2, OutputIt d_first)
{
while (first1 != last1 && first2 != last2)
{
if (*first1 < *first2)
++first1;
else
{
if (!(*first2 < *first1))
*d_first++ = *first1++; // *first1 and *first2 are equivalent.
++first2;
}
}
return d_first;
}
测试案例:
int main()
{
std::vector<int> v1{7, 2, 3, 4, 5, 6, 7, 8};
std::vector<int> v2{5, 7, 9, 7};
std::sort(v1.begin(), v1.end());
std::sort(v2.begin(), v2.end());
std::vector<int> v_intersection;
std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(),
std::back_inserter(v_intersection));
for (int n : v_intersection)
std::cout << n << ' ';
std::cout << '\n';
// 输出
5 7 7
}
4.4 set_difference
用于计算两个已排序集合的差集(A - B),计算在集合 A 中但不在集合 B 中的元素。
将已排序范围 [first1, last1) 中未在已排序范围 [first2, last2) 中找到的元素复制到始于 d_first 的范围。输出范围也已排序。
如果 [first1, last1) 包含 m 个彼此等价的元素,且 [first2, last2) 包含 n 个与它们等价的元素,则将 std::max(m - n, 0) 个元素从 [first1, last1) 复制到输出范围,并保持顺序。
template< class InputIt1, class InputIt2, class OutputIt >
OutputIt set_difference( InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2,
OutputIt d_first );
伪码实现
template<class InputIt1, class InputIt2, class OutputIt>
OutputIt set_difference(InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2, OutputIt d_first)
{
while (first1 != last1)
{
if (first2 == last2)
return std::copy(first1, last1, d_first);
if (*first1 < *first2)
*d_first++ = *first1++;
else
{
if (! (*first2 < *first1))
++first1;
++first2;
}
}
return d_first;
}
测试案例:
int main()
{
std::vector<int> A = {1, 2, 3, 4, 5, 6, 7};
std::vector<int> B = {2, 4, 6, 8, 10};
std::vector<int> difference;
// 确保输入已排序
std::sort(A.begin(), A.end());
std::sort(B.begin(), B.end());
std::cout << "集合A: ";
for (int n : A) std::cout << n << " ";
std::cout << std::endl;
std::cout << "集合B: ";
for (int n : B) std::cout << n << " ";
std::cout << std::endl;
// 计算差集 A - B
std::set_difference(A.begin(), A.end(),
B.begin(), B.end(),
std::back_inserter(difference));
std::cout << "A - B (在A中但不在B中): ";
for (int n : difference) std::cout << n << " ";
std::cout << std::endl;
// 输出
集合A: 1 2 3 4 5 6 7
集合B: 2 4 6 8 10
A - B (在A中但不在B中): 1 3 5 7
}
5 最值操作
5.1 max_element
返回一个范围中最大的元素
template< class ForwardIt >
ForwardIt max_element( ForwardIt first, ForwardIt last );
template< class ForwardIt, class Compare >
ForwardIt max_element( ForwardIt first, ForwardIt last,
Compare comp );
伪码实现
template<class ForwardIt>
ForwardIt max_element(ForwardIt first, ForwardIt last)
{
if (first == last)
return last;
ForwardIt largest = first;
while (++first != last)
if (*largest < *first)
largest = first;
return largest;
}
template<class ForwardIt, class Compare>
ForwardIt max_element(ForwardIt first, ForwardIt last, Compare comp)
{
if (first == last)
return last;
ForwardIt largest = first;
while(++first != last)
if (comp(*largest, *first))
largest = first;
return largest;
}
测试案例:
int main()
{
std::vector<int> v{3, 1, -14, 1, 5, 9, -14, 9};
std::vector<int>::iterator result;
result = std::max_element(v.begin(), v.end());
std::cout << "Max element found at index "
<< std::distance(v.begin(), result)
<< " has value " << *result << '\n';
result = std::max_element(v.begin(), v.end(), [](int a, int b)
{
return std::abs(a) < std::abs(b);
});
std::cout << "Absolute max element found at index "
<< std::distance(v.begin(), result)
<< " has value " << *result << '\n';
// 输出
Max element found at index 5 has value 9
Absolute max element found at index 2 has value -14
}
5.2 min_element
返回一个范围中最小的元素
重新排列给定范围 [first, last) 中的元素,使得这些元素所有可能的排列都具有相同的出现概率。
对一个范围的元素进行排序,同时保留相等元素之间的顺序(stable_sort).
template< class ForwardIt >
ForwardIt min_element( ForwardIt first, ForwardIt last );
template< class ForwardIt, class Compare >
ForwardIt min_element( ForwardIt first, ForwardIt last,
Compare comp );
伪码实现
template<class ForwardIt>
ForwardIt min_element(ForwardIt first, ForwardIt last)
{
if (first == last)
return last;
ForwardIt smallest = first;
while (++first != last)
if (*first < *smallest)
smallest = first;
return smallest;
}
template<class ForwardIt, class Compare>
ForwardIt min_element(ForwardIt first, ForwardIt last, Compare comp)
{
if (first == last)
return last;
ForwardIt smallest = first;
while (++first != last)
if (comp(*first, *smallest))
smallest = first;
return smallest;
}
测试案例:
int main()
{
std::vector<int> v{3, 1, -4, 1, 5, 9};
std::vector<int>::iterator result = std::min_element(v.begin(), v.end());
std::cout << "min element has value " << *result << " and index ["
<< std::distance(v.begin(), result) << "]\n";
// 输出
min element has value -4 and index [2]
}
6 数值操作
6.1 accumulate
对一个范围的元素进行求和或折叠。
template< class InputIt, class T >
T accumulate( InputIt first, InputIt last, T init );
template< class InputIt, class T, class BinaryOp >
T accumulate( InputIt first, InputIt last, T init, BinaryOp op );
伪码实现
template<class InputIt, class T>
constexpr // since C++20
T accumulate(InputIt first, InputIt last, T init)
{
for (; first != last; ++first)
init = std::move(init) + *first; // std::move since C++20
return init;
}
template<class InputIt, class T, class BinaryOperation>
constexpr // since C++20
T accumulate(InputIt first, InputIt last, T init, BinaryOperation op)
{
for (; first != last; ++first)
init = op(std::move(init), *first); // std::move since C++20
return init;
}
测试案例:
int main()
{
std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int sum = std::accumulate(v.begin(), v.end(), 0);
int product = std::accumulate(v.begin(), v.end(), 1, std::multiplies<int>());
auto dash_fold = [](std::string a, int b)
{
return std::move(a) + '-' + std::to_string(b);
};
std::string s = std::accumulate(std::next(v.begin()), v.end(),
std::to_string(v[0]), // start with first element
dash_fold);
// Right fold using reverse iterators
std::string rs = std::accumulate(std::next(v.rbegin()), v.rend(),
std::to_string(v.back()), // start with last element
dash_fold);
std::cout << "sum: " << sum << '\n'
<< "product: " << product << '\n'
<< "dash-separated string: " << s << '\n'
<< "dash-separated string (right-folded): " << rs << '\n';
// 输出
sum: 55
product: 3628800
dash-separated string: 1-2-3-4-5-6-7-8-9-10
dash-separated string (right-folded): 10-9-8-7-6-5-4-3-2-1
}
7 排列操作(17)
7.1 is_permutation
确定一个序列是否是另一个序列的排列
对一个范围的元素进行求和或折叠。
template< class ForwardIt1, class ForwardIt2 >
bool is_permutation( ForwardIt1 first1, ForwardIt1 last1,
ForwardIt2 first2 );
template< class ForwardIt1, class ForwardIt2,
class BinaryPredicate >
bool is_permutation( ForwardIt1 first1, ForwardIt1 last1,
ForwardIt2 first2, BinaryPredicate p );
伪码实现
template<class ForwardIt1, class ForwardIt2>
bool is_permutation(ForwardIt1 first, ForwardIt1 last,
ForwardIt2 d_first)
{
// skip common prefix
std::tie(first, d_first) = std::mismatch(first, last, d_first);
// iterate over the rest, counting how many times each element
// from [first, last) appears in [d_first, d_last)
if (first != last)
{
ForwardIt2 d_last = std::next(d_first, std::distance(first, last));
for (ForwardIt1 i = first; i != last; ++i)
{
if (i != std::find(first, i, *i))
continue; // this *i has been checked
auto m = std::count(d_first, d_last, *i);
if (m == 0 || std::count(i, last, *i) != m)
return false;
}
}
return true;
}
测试案例:
int main()
{
static constexpr auto v1 = {1, 2, 3, 4, 5};
static constexpr auto v2 = {3, 5, 4, 1, 2};
static constexpr auto v3 = {3, 5, 4, 1, 1};
std::cout << v2 << " is a permutation of " << v1 << ": " << std::boolalpha
<< std::is_permutation(v1.begin(), v1.end(), v2.begin()) << '\n'
<< v3 << " is a permutation of " << v1 << ": "
<< std::is_permutation(v1.begin(), v1.end(), v3.begin()) << '\n';
// 输出
{ 3 5 4 1 2 } is a permutation of { 1 2 3 4 5 }: true
{ 3 5 4 1 1 } is a permutation of { 1 2 3 4 5 }: false
}
7.2 next_permutation
生成元素范围的下一个更大的字典序排列
template< class BidirIt >
bool next_permutation( BidirIt first, BidirIt last );
伪码实现
template<class BidirIt>
bool next_permutation(BidirIt first, BidirIt last)
{
auto r_first = std::make_reverse_iterator(last);
auto r_last = std::make_reverse_iterator(first);
auto left = std::is_sorted_until(r_first, r_last);
if (left != r_last)
{
auto right = std::upper_bound(r_first, left, *left);
std::iter_swap(left, right);
}
std::reverse(left.base(), last);
return left != r_last;
}
测试案例:
int main()
{
std::string s = "aba";
do
{
std::cout << s << '\n';
}
while (std::next_permutation(s.begin(), s.end()));
std::cout << s << '\n';
// 输出
aba
baa
aab
}
7.3 sample
用于从序列中随机抽取样本,支持有放回和无放回抽样。
template< class PopulationIt, class SampleIt, class Distance, class URBG >
SampleIterator sample( PopulationIt first, PopulationIt last,
SampleIt out, Distance n, URBG&& g );
伪码实现
测试案例:
int main()
{
std::string in {"ABCDEFGHIJK"}, out;
std::sample(in.begin(), in.end(), std::back_inserter(out), 4,
std::mt19937 {std::random_device{}()});
std::cout << "Four random letters out of " << in << " : " << out << '\n';
// 输出
Four random letters out of ABCDEFGHIJK: EFGK
}
本文来自博客园,作者:Hakuon,转载请注明原文链接:https://www.cnblogs.com/Hakuon/p/19435038
浙公网安备 33010602011771号