介绍使用C++的stl算法
STL
算法就是一种函数模板,C++中的算法是通过迭代器和模板来实现的,简单来说算法就是一系列的计算步骤,用来将输入数据转化成输出结果。
包括的头文件
1 |
算法的分类
- 非可变序列算法
- 可变序列算法
- 排序算法
- 数值算法
遍历算法
for_each
- 用法:实现数组或集合的遍历
- first:开始的迭代器
- last:结束的迭代器
- f:传入的函数
可能的实现:
1
2
3
4
5
6
7
8template<class InputIt, class UnaryFunc>
constexpr UnaryFunc for_each(InputIt first, InputIt last, UnaryFunc f)
{
for (; first != last; ++first)
f(*first);
return f;
}例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
int main()
{
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';
struct Sum
{
void operator()(int n) { sum += n; }
int sum {0};
};
Sum s = std::for_each(v.cbegin(), v.cend(), Sum());
std::cout << "sum:\t" << s.sum << '\n';
}1
2
3
4// 输出
before: 3 -4 2 -8 15 267
after: 4 -3 3 -7 16 268
sum: 281
transform
- 用法:将一个容器中的内容搬运到另一个容器中
- first1:开始的迭代器
- last1:结束的迭代器
- d_first:目的容器开始的迭代器
- f:传入的函数
- 可能的实现:
1
2
3
4
5
6
7
8
9
10// 从first1到last1的元素传入unary_op变换后,放到d_first内
emplate<class InputIt, class OutputIt, class UnaryOp>
constexpr //< since C++20
OutputIt transform(InputIt first1, InputIt last1, OutputIt d_first, UnaryOp unary_op)
{
for (; first1 != last1; ++d_first, ++first1)
*d_first = unary_op(*first1);
return d_first;
}1
2
3
4
5
6
7
8
9
10
11
12// 从first1到last1和从first2后的元素传入unary_op(first1,first2)变换后,放到d_first内
// first2的范围应该小于first1到last1的范围
template<class InputIt1, class InputIt2,
class OutputIt, class BinaryOp>
constexpr //< since C++20
OutputIt transform(InputIt1 first1, InputIt1 last1, InputIt2 first2, OutputIt d_first, BinaryOp binary_op)
{
for (; first1 != last1; ++d_first, ++first1, ++first2)
*d_first = binary_op(*first1, *first2);
return d_first;
} - 例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
void print_ordinals(const std::vector<unsigned>& ordinals)
{
std::cout << "ordinals: ";
for (unsigned ord : ordinals)
std::cout << std::setw(3) << ord << ' ';
std::cout << '\n';
}
char to_uppercase(unsigned char c)
{
return std::toupper(c);
}
void to_uppercase_inplace(char& c)
{
c = to_uppercase(c);
}
void unary_transform_example(std::string& hello, std::string world)
{
// 原地转换成大写字母
std::transform(hello.cbegin(), hello.cend(), hello.begin(), to_uppercase);
std::cout << "hello = " << std::quoted(hello) << '\n';
// for_each版本
std::for_each(world.begin(), world.end(), to_uppercase_inplace);
std::cout << "world = " << std::quoted(world) << '\n';
}
void binary_transform_example(std::vector<unsigned> ordinals)
{
// 转化成两倍的值
print_ordinals(ordinals);
std::transform(ordinals.cbegin(), ordinals.cend(), ordinals.cbegin(),
ordinals.begin(), std::plus<>{});
print_ordinals(ordinals);
}
int main()
{
std::string hello("hello");
unary_transform_example(hello, "world");
std::vector<unsigned> ordinals;
std::copy(hello.cbegin(), hello.cend(), std::back_inserter(ordinals));
binary_transform_example(std::move(ordinals));
}1
2
3
4
5// 输出
hello = "HELLO"
world = "WORLD"
ordinals: 72 69 76 76 79
ordinals: 144 138 152 152 158
find,find_if,find_if_not
- 用法:查找指定元素,找到返回指定元素的迭代器,找不到返回结束迭代器end()
- first:开始迭代器
- last:结束迭代器
- value:查找的元素 | p/q:传入的判断函数
- 可能的实现:
1
2
3
4
5
6
7
8
9
10// find
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;
}1
2
3
4
5
6
7
8
9
10// find_if
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;
}1
2
3
4
5
6
7
8
9
10// find_if_not
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;
} - 例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
int main()
{
const auto v = {1, 2, 3, 4};
for (const int n : {3, 5})
(std::find(v.begin(), v.end(), n) == std::end(v))
? std::cout << "v does not contain " << n << '\n'
: std::cout << "v contains " << n << '\n';
auto is_even = [](int i) { return i % 2 == 0; };
for (const auto& w : {std::array{3, 1, 4}, {1, 3, 5}})
if (auto it = std::find_if(begin(w), end(w), is_even); it != std::end(w))
std::cout << "w contains an even number " << *it << '\n';
else
std::cout << "w does not contain even numbers\n";
std::vector<std::complex<double>> nums{{4, 2}};
// T gets deduced making list-initialization possible
const auto it = std::find(nums.begin(), nums.end(), {4, 2});
const auto it = std::find(nums.begin(), nums.end(), std::complex<double>{4, 2});
assert(it == nums.begin());
}1
2
3
4
5// 输出
v contains 3
v does not contain 5
w contains an even number 4
w does not contain even numbers
adjacent_find
- 用法:查找相邻的重复元素,返回相邻元素的第一个位置的迭代器
- first:开始的迭代器
- last:结束的迭代器
- p:传入的自定义判断函数
可能的实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 默认判断相等
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;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 自定义判断相等
template<class ForwardIt, class BinaryPred>
ForwardIt adjacent_find(ForwardIt first, ForwardIt last, BinaryPred p)
{
if (first == last)
return last;
ForwardIt next = first;
++next;
for (; next != last; ++next, ++first)
if (p(*first, *next))
return first;
return last;
}例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int main()
{
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';
auto i2 = std::adjacent_find(v1.begin(), v1.end(), std::greater<int>());
if (i2 == v1.end())
std::cout << "The entire vector is sorted in ascending order\n";
else
std::cout << "The last element in the non-decreasing subsequence is at "
<< std::distance(v1.begin(), i2) << ", *i2 = " << *i2 << '\n';
}1
2
3//输出
The first adjacent pair of equal elements is at 4, *i1 = 40
The last element in the non-decreasing subsequence is at 7, *i2 = 41
binary_search
- 用法:二分查找
- first:开始的迭代器
- last:结束的迭代器
- value:查找的值
- comp:传入的自定义判断函数
- 可能的实现:
1
2
3
4
5template<class ForwardIt, class T = typename std::iterator_traits<ForwardIt>::value_type>
bool binary_search(ForwardIt first, ForwardIt last, const T& value)
{
return std::binary_search(first, last, value, std::less{});
}1
2
3
4
5
6
7template<class ForwardIt, class T = typename std::iterator_traits<ForwardIt>::value_type,
class Compare>
bool binary_search(ForwardIt first, ForwardIt last, const T& value, Compare comp)
{
first = std::lower_bound(first, last, value, comp);
return (!(first == last) and !(comp(value, *first)));
} - 例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
int main()
{
const auto haystack = {1, 3, 4, 5, 9};
for (const auto needle : {1, 2, 3})
{
std::cout << "Searching for " << needle << '\n';
if (std::binary_search(haystack.begin(), haystack.end(), needle))
std::cout << "Found " << needle << '\n';
else
std::cout << "No dice!\n";
}
using CD = std::complex<double>;
std::vector<CD> nums{{1, 1}, {2, 3}, {4, 2}, {4, 3}};
auto cmpz = [](CD x, CD y){ return abs(x) < abs(y); };
assert(std::binary_search(nums.cbegin(), nums.cend(), {4, 2}, cmpz));
assert(std::binary_search(nums.cbegin(), nums.cend(), CD{4, 2}, cmpz));
}1
2
3
4
5
6
7//输出
Searching for 1
Found 1
Searching for 2
no dice!
Searching for 3
Found 3
count,count_if
- 用法:统计一个区间中元素出现的次数
- first:开始的迭代器
- last:结束的迭代器
- value:查找的值
- p:传入的判断函数
- 可能的实现:
1
2
3
4
5
6
7
8
9
10template<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;
}1
2
3
4
5
6
7
8
9
10template<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;
} - 例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
int main()
{
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';
// 确定有多少整数匹配
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';
}
// 使用lambda找出能被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';
// 一个复杂度为O(n)的计算容器元素距离的函数
auto distance = [](auto first, auto last)
{
return std::count_if(first, last, [](auto) { return true; });
};
static_assert(distance(v.begin(), v.end()) == 10);
std::array<std::complex<double>, 3> nums{{{4, 2}, {1, 3}, {4, 2}}};
// T gets deduced making list-initialization possible
auto c = std::count(nums.cbegin(), nums.cend(), {4, 2});
auto c = std::count(nums.cbegin(), nums.cend(), std::complex<double>{4, 2});
assert(c == 2);
}1
2
3
4
5
6//输出
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
search
- 用法:给出两个范围,返回一个迭代器,查找成功指向第一个范围内第一次出现子序列,查找失败指向last1。
- first:开始的迭代器
- last:结束的迭代器
- p:传入的函数
- 可能的实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20template<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;
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20template<class ForwardIt1, class ForwardIt2, class BinaryPred>
constexpr //< since C++20
ForwardIt1 search(ForwardIt1 first, ForwardIt1 last,
ForwardIt2 s_first, ForwardIt2 s_last, BinaryPred p)
{
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 (!p(*it, *s_it))
break;
}
++first;
}
} - 例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
using namespace std::literals;
bool contains(const auto& cont, std::string_view s)
{
// str.find() (or str.contains(), since C++23) can be used as well
return std::search(cont.begin(), cont.end(), s.begin(), s.end()) != cont.end();
}
int main()
{
const auto str{"why waste time learning, when ignorance is instantaneous?"sv};
assert(contains(str, "learning"));
assert(not contains(str, "lemming"));
const std::vector vec(str.begin(), str.end());
assert(contains(vec, "learning"));
assert(not contains(vec, "leaning"));
// The C++17 overload with searchers demo:
constexpr auto quote
{
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed "
"do eiusmod tempor incididunt ut labore et dolore magna aliqua"sv
};
for (const auto word : {"pisci"sv, "Pisci"sv})
{
std::cout << "The string " << std::quoted(word) << ' ';
const std::boyer_moore_searcher searcher(word.begin(), word.end());
const auto it = std::search(quote.begin(), quote.end(), searcher);
if (it == quote.end())
std::cout << "not found\n";
else
std::cout << "found at offset " << std::distance(quote.begin(), it) << '\n';
}
}1
2
3// 输出
The string "pisci" found at offset 43
The string "Pisci" not found
排序算法
sort
- 用法:快速排序
- first:开始的迭代器
- last:结束的迭代器
- comp:传入的比较函数
- 例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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");
}1
2
3
4
5//输出
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
random_shuffle
- 用法:随机打乱
- first:开始的迭代器
- last:结束的迭代器
- RandomFunc:传入的随机函数
- 可能的实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 默认实现
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.
}
}1
2
3
4
5
6
7
8
9
10
11
12// 自定义随机函数
template<class RandomIt, class RandomFunc>
void random_shuffle(RandomIt first, RandomIt last, RandomFunc&& r)
{
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[r(i + 1)]);
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 不知道
template<class RandomIt, class URBG>
void shuffle(RandomIt first, RandomIt last, URBG&& g)
{
typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
typedef std::uniform_int_distribution<diff_t> distr_t;
typedef typename distr_t::param_type param_t;
distr_t D;
for (diff_t i = last - first - 1; i > 0; --i)
{
using std::swap;
swap(first[i], first[D(g, param_t(0, i))]);
}
} - 例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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';
}1
2//输出
8 6 10 4 2 3 7 1 9 5
merge
- 用法:容器合并
- first1:容器1的开始迭代器
- last1:容器1的结束迭代器
- first2:容器2的开始迭代器
- last2:容器2的结束迭代器
- d_first:目标容器的起始迭代器
- 可能的实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24// 默认小的放后面
template<class InputIt1, class InputIt2, class OutputIt>
OutputIt merge(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;
++first2;
}
else
{
*d_first = *first1;
++first1;
}
}
return std::copy(first2, last2, d_first);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25// 自定义放的顺序
template<class InputIt1, class InputIt2,
class OutputIt, class Compare>
OutputIt merge(InputIt1 first1, InputIt1 last1,
InputIt2 first2, InputIt2 last2,
OutputIt d_first, Compare comp)
{
for (; first1 != last1; ++d_first)
{
if (first2 == last2)
return std::copy(first1, last1, d_first);
if (comp(*first2, *first1))
{
*d_first = *first2;
++first2;
}
else
{
*d_first = *first1;
++first1;
}
}
return std::copy(first2, last2, d_first);
} - 例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
auto print = [](const auto rem, const auto& v)
{
std::cout << rem;
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
};
int main()
{
// 随机数填充
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<> dis(0, 9);
std::vector<int> v1(10), v2(10);
std::generate(v1.begin(), v1.end(), std::bind(dis, std::ref(mt)));
std::generate(v2.begin(), v2.end(), std::bind(dis, std::ref(mt)));
print("Originally:\nv1: ", v1);
print("v2: ", v2);
std::sort(v1.begin(), v1.end());
std::sort(v2.begin(), v2.end());
print("After sorting:\nv1: ", v1);
print("v2: ", v2);
// merge
std::vector<int> dst;
std::merge(v1.begin(), v1.end(), v2.begin(), v2.end(), std::back_inserter(dst));
print("After merging:\ndst: ", dst);
}1
2
3
4
5
6
7
8
9//输出
Originally:
v1: 2 6 5 7 4 2 2 6 7 0
v2: 8 3 2 5 0 1 9 6 5 0
After sorting:
v1: 0 2 2 2 4 5 6 6 7 7
v2: 0 0 1 2 3 5 5 6 8 9
After merging:
dst: 0 0 0 1 2 2 2 2 3 4 5 5 5 6 6 6 7 7 8 9
reverse
- 用法:将容器内的元素进行一个反转
- first:开始的迭代器
- last:结束的迭代器
- 可能的实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20template<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);
} - 例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void println(auto rem, auto const& v)
{
for (std::cout << rem; auto e : v)
std::cout << e << ' ';
std::cout << '\n';
}
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);
}1
2
3//输出
after reverse, v = 3 2 1
after reverse, a = 7 6 5 4
拷贝和替换算法
copy,copy_if
- 用法:将容器内的元素拷贝到另一容器中
- first:开始的迭代器
- last:结束的迭代器
- d_first:目的容器的开始迭代器
- pred:判断函数
- 可能的实现:
1
2
3
4
5
6
7
8
9template<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;
}1
2
3
4
5
6
7
8
9
10
11
12
13template<class InputIt, class OutputIt>
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;
} - 例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
int main()
{
std::vector<int> from_vector(10);
std::iota(from_vector.begin(), from_vector.end(), 0);
std::vector<int> to_vector;
std::copy(from_vector.begin(), from_vector.end(),
std::back_inserter(to_vector));
// 或者还可以这样做,
// std::vector<int> to_vector(from_vector.size());
// std::copy(from_vector.begin(), from_vector.end(), to_vector.begin());
// 同样地,
// std::vector<int> to_vector = from_vector;
std::cout << "to_vector contains: ";
std::copy(to_vector.begin(), to_vector.end(),
std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
std::cout << "odd numbers in to_vector are: ";
std::copy_if(to_vector.begin(), to_vector.end(),
std::ostream_iterator<int>(std::cout, " "),
[](int x) { return x % 2 != 0; });
std::cout << '\n';
std::cout << "to_vector contains these multiples of 3: ";
to_vector.clear();
std::copy_if(from_vector.begin(), from_vector.end(),
std::back_inserter(to_vector),
[](int x) { return x % 3 == 0; });
for (const int x : to_vector)
std::cout << x << ' ';
std::cout << '\n';
}1
2
3
4//输出
to_vector contains: 0 1 2 3 4 5 6 7 8 9
odd numbers in to_vector are: 1 3 5 7 9
to_vector contains these multiples of 3: 0 3 6 9
replace,replace_if
- 用法:将容器内指定范围内的元素替换成新元素
- first:开始的迭代器
- last:结束的迭代器
- old_value:待替换的值
- p:判断是否满足替换条件的函数
- new_value:替换后的值
- 可能的实现:
1
2
3
4
5
6
7
8
9template<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;
}1
2
3
4
5
6
7
8
9template<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;
} - 例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void println(const auto& seq)
{
for (const auto& e : seq)
std::cout << e << ' ';
std::cout << '\n';
}
int main()
{
std::array<int, 10> s{5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
// 将所有的8替换成88
std::replace(s.begin(), s.end(), 8, 88);
println(s);
// 将所有的5替换成55
std::replace_if(s.begin(), s.end(),
std::bind(std::less<int>(), std::placeholders::_1, 5), 55);
println(s);
std::array<std::complex<double>, 2> nums{{{1, 3}, {1, 3}}};
std::replace(nums.begin(), nums.end(), {1, 3}, {4, 2});
std::replace(nums.begin(), nums.end(), std::complex<double>{1, 3},
std::complex<double>{4, 2});
println(nums);
}1
2
3
4//输出
5 7 4 2 88 6 1 9 0 3
5 7 55 55 88 6 55 9 55 55
(4,2), (4,2)
swap
- 用法:交换元素
- c1:容器A
- c2:容器B
- 可能的实现:
1
void swap(Container1 c1,Container c2);
- 例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
namespace Ns
{
class A
{
int id {};
friend void swap(A& lhs, A& rhs)
{
std::cout << "swap(" << lhs << ", " << rhs << ")\n";
std::swap(lhs.id, rhs.id);
}
friend std::ostream& operator<<(std::ostream& os, A const& a)
{
return os << "A::id=" << a.id;
}
public:
A(int i) : id {i} {}
A(A const&) = delete;
A& operator = (A const&) = delete;
};
}
int main()
{
int a = 5, b = 3;
std::cout << a << ' ' << b << '\n';
std::swap(a, b);
std::cout << a << ' ' << b << '\n';
Ns::A p {6}, q {9};
std::cout << p << ' ' << q << '\n';
// std::swap(p, q); // 标准库中没有相关实现
swap(p, q); // 需要自定义swap函数
std::cout << p << ' ' << q << '\n';
}1
2
3
4
5
6//输出
5 3
3 5
A::id=6 A::id=9
swap(A::id=6, A::id=9)
A::id=9 A::id=6
算数生成算法
所属的头文件并不是algorithm,而是我们开头提到过的 numeric
accumulate
- 用法:计算一个指定区间内的总和
- first:容器A
- last:容器B
- init:初始值
- op:计算函数
- 可能的实现:
1
2
3
4
5
6
7
8
9template<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;
}1
2
3
4
5
6
7
8
9template<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;
} - 例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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]), // 从第一个开始
dash_fold);
// 从右开始,使用反向迭代器
std::string rs = std::accumulate(std::next(v.rbegin()), v.rend(),
std::to_string(v.back()), // 从最后一个开始
dash_fold);
std::cout << "sum: " << sum << '\n'
<< "product: " << product << '\n'
<< "dash-separated string: " << s << '\n'
<< "dash-separated string (right-folded): " << rs << '\n';
}1
2
3
4
5//输出
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
fill
- 用法:向容器中填充指定的元素
- first:开始的迭代器
- last:结束的迭代器
- value:填充的值
- 可能的实现:
1
2
3
4
5
6
7template<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;
} - 例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void println(const auto& seq)
{
for (const auto& e : seq)
std::cout << e << ' ';
std::cout << '\n';
}
int main()
{
std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8};
println(v);
// 把所有的元素设置成8
std::fill(v.begin(), v.end(), 8);
println(v);
std::vector<std::complex<double>> nums{{1, 3}, {2, 2}, {4, 8}};
println(nums);
std::fill(nums.begin(), nums.end(), {4, 2});
std::fill(nums.begin(), nums.end(), std::complex<double>{4, 2});
println(nums);
}1
2
3
4
5//输出
0 1 2 3 4 5 6 7 8
8 8 8 8 8 8 8 8 8
(1,3) (2,2) (4,8)
(4,2) (4,2) (4,2)
集合算法
set_intersection,set_union,set_difference
- 用法:求两个容器中元素的交集,并集,差集
- first1:容器A开始迭代器
- last1:容器A结束迭代器
- first2:容器B开始迭代器
- last2:容器B结束迭代器
- d_first:目标容器迭代器
- comp:比较的函数
- 可能的实现:
set_intersection
1 | template<class InputIt1, class InputIt2, class OutputIt> |
1 | template<class InputIt1, class InputIt2, class OutputIt, class Compare> |
set_union
1 | template<class InputIt1, class InputIt2, class OutputIt> |
1 | template<class InputIt1, class InputIt2, class OutputIt, class Compare> |
set_difference
1 | template<class InputIt1, class InputIt2, class OutputIt> |
1 | template<class InputIt1, class InputIt2, class OutputIt, class Compare> |
- 例子:
set_intersection
1 |
|
1 | //输出 |
set_union
1 |
|
1 | //输出 |
set_intersection
1 |
|
1 | //输出 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 lnpbqc!