技巧 同时遍历多个容器的[index,value] for循环实现 对A和B容器的遍历。
1 2 3 4 5 for (const auto &I : enumerate (zip (A, B))) { std::get <0 >(I.value ()); std::get <1 >(I.value ()); I.index () }
循环
v.at(index),相对[INDEX]会处理越界异常
size_t
for_each()
forrange - const auto &node:v
类型转换
string
char *
char
int
float
double
string
x
直接赋值
…
to_string()
to_string()
to_string()
char *
c_str()
x
…
std::to_string(someInt).c_str()
…
char
…
…
x
‘0’+i
…
int
stoi()
atoi()
int(ch) - 48; int(ch-‘0’)
x
…
float
stof()
…
…
…
x
double
stod()
atof()
…
…
…
x
相同点:
都是C++的字符处理函数,把数字字符串转换成int输出
头文件都是#include <cstring>
不同点:
atoi()的参数是 const char*
,因此对于一个字符串str
我们必须调用 c_str()
的方法把这个string转换成 const char*
类型的,
stoi()的参数是const string*
,不需要转化为 const char*
;
stoi()会做范围检查,默认范围是在int的范围内的,如果超出范围的话则会runtime error!
而atoi()不会做范围检查,如果超出范围的话,超出上界,则输出上界,超出下界,则输出下界;
1 2 3 to_chars () #include <cctype> toupper ()
批处理 - 查找判断 基本都是头文件的常用函数,包装常用操作,来简化代码,非必须操作。
all_of;any_of;none_of;
判断数据序列元素(全部、部分,没有)满足判断条件,返回bool类型。
1 2 bool all_even = std::all_of (nums.begin (), nums.end (), [](int n) { return n % 2 == 0 ; });
find_if
std::find_if
是 C++ 标准库中的算法,用于在给定范围内查找满足指定条件的第一个元素。
它遍历范围内的元素,直到找到第一个使谓词返回 true
的元素,然后返回该元素的迭代器。
std::find_if
适用于需要根据复杂条件查找某个元素的场景,例如查找符合特定属性的对象或根据条件筛选数据。
1 2 template <class InputIt , class UnaryPredicate >InputIt find_if (InputIt first, InputIt last, UnaryPredicate p) ;
first, last
: 输入范围 [first, last)
。
p
: 一元谓词,用于检查元素是否满足条件。谓词函数返回 true
表示找到目标元素。
如果找到满足条件的元素,则返回指向该元素的迭代器;否则返回 last
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <iostream> #include <vector> #include <algorithm> bool isOdd (int i) { return i % 2 != 0 ; } int main () { std::vector<int > v = {2 , 4 , 6 , 7 , 10 }; auto it = std::find_if (v.begin (), v.end (), isOdd); if (it != v.end ()) { std::cout << "First odd number: " << *it << std::endl; } else { std::cout << "No odd number found" << std::endl; } return 0 ; }
使用 Lambda 表达式:你可以使用 lambda 表达式代替独立的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 int main () { std::vector<int > v = {2 , 4 , 6 , 7 , 10 }; auto it = std::find_if (v.begin (), v.end (), [](int i) { return i % 2 != 0 ; }); if (it != v.end ()) { std::cout << "First odd number: " << *it << std::endl; } else { std::cout << "No odd number found" << std::endl; } return 0 ; }
equal 1 2 3 4 5 6 7 8 9 10 11 12 template < class InputIt1, class InputIt2 >bool equal ( InputIt1 first1, InputIt1 last1, InputIt2 first2 ) ;template < class InputIt1, class InputIt2, class BinaryPredicate > constexpr bool equal ( InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, BinaryPredicate p ) ;
用 == 运算符来比较两个序列
三个参数版本
前两个参数是第一个序列的开始和结束迭代器,
第三个参数是第二个序列的开始迭代器。
4 个参数:
第一个序列的开始和结束迭代器,第二个序列的开始和结束迭代器,
如果两个序列的长度不同,那么结果总是为 false。
特殊使用: 比较容器内元素是否全部相同
equal(cnt.begin() + 1, cnt.end(), cnt.begin());
支持lambda 表达式
1 std::equal (std::begin (r1) , std::end (r1) , std::begin (r2),[](const string& s1, const string& s2) { return s1[0 ] = s2[0 ]; })
max_element() 1 2 3 4 5 6 7 8 #include <algorithm> vector<int >::iterator result = std::max_element (v.begin (), v.end ()); int index = result - v.begin ();int value = (*result)double max = *max_element (vector.begin (), vector.end ());cout<<"Max value: " <<max<<endl;
upper_bound()
如果查找失败,迭代器的指向和 last 迭代器相同。
1 2 3 4 5 6 7 8 9 ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val) ;ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val, Compare comp) ;
lower_bound()
二分查找指定区域内查找不小于目标值的第一个元素
如果查找失败,迭代器的指向和 last 迭代器相同。
1 2 3 4 5 6 7 8 9 ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val) ;ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val, Compare comp) ;
1 2 3 4 5 6 7 8 9 std::set<int > s = {1 , 3 , 5 , 7 , 9 }; auto it1 = s.lower_bound (5 );if (it1 != s.end ()) { std::cout << "Lower bound of 5 is: " << *it1 << std::endl; } else { std::cout << "5 is greater than all elements in the set." << std::endl; }
如下:
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 template <class ForwardIterator , class T >ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val) { ForwardIterator it; iterator_traits<ForwardIterator>::difference_type count, step; count = std::distance (first,last); while (count>0 ) { it = first; step=count/2 ; std::advance (it,step); if (!(val<*it)) { first=++it; count-=step+1 ; } else count=step; } return first; } template <class ForwardIterator , class T >ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val) { ForwardIterator it; iterator_traits<ForwardIterator>::difference_type count, step; count = distance (first,last); while (count>0 ) { it = first; step=count/2 ; advance (it,step); if (*it<val) { first=++it; count-=step+1 ; } else count=step; } return first; }
binary_search() std::binary_search 用于在已排序的范围内查找某个值是否存在。如果找到该值,则返回 true,否则返回 false。
1 2 3 4 5 6 std::vector<int > nums = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 }; int value = 5 ;bool found = std::binary_search (nums.begin (), nums.end (), value);
equal_range() std::equal_range 用于在已排序的范围内查找值的范围。它返回一对迭代器,分别指向第一个不小于给定值的元素和第一个大于给定值的元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 std::vector<int > nums = {1 , 2 , 2 , 3 , 3 , 3 , 4 , 5 , 5 }; int value = 3 ;auto range = std::equal_range (nums.begin (), nums.end (), value);if (range.first != range.second) { std::cout << "值 " << value << " 的范围从索引 " << (range.first - nums.begin ()) << " 到 " << (range.second - nums.begin ()) << std::endl; } else { std::cout << "值 " << value << " 未找到" << std::endl; }
批处理 - 修改 for_each() 1 2 3 4 5 6 std::vector<int > nums = {1 , 2 , 3 , 4 , 5 }; std::for_each(nums.begin (), nums.end (), [](int n) { std::cout << n << " " ; });
fill 和 fill_n 1 2 fill (ForwardIt first, ForwardIt last, const T& value) fill_n (OutputIt first, Size count, const T& value)
copy_if + back_inserter
在 C++ 中,std::copy_if
是一个常用的算法,用于将符合特定条件的元素从一个容器复制到另一个容器。
结合 std::back_inserter
,它可以动态地将符合条件的元素插入到目标容器的末尾。std::back_inserter
是一个迭代器适配器,用于确保元素被插入到目标容器的末端,而不需要手动管理目标容器的大小。
1. std::copy_if
概述 std::copy_if
的作用是从输入范围中复制那些满足给定谓词条件的元素到输出范围。它的函数签名如下:
1 2 template < class InputIt, class OutputIt, class UnaryPredicate >OutputIt copy_if ( InputIt first, InputIt last, OutputIt d_first, UnaryPredicate pred ) ;
first
, last
:输入范围的开始和结束迭代器。
d_first
:目标容器的开始迭代器(通常配合 std::back_inserter
使用)。
pred
:一个一元谓词函数或 lambda 表达式,表示元素需要满足的条件。
2. std::back_inserter
概述 std::back_inserter
是一个迭代器适配器,用来将元素插入到容器的末尾。它通过调用容器的 push_back()
来实现动态扩展容器的大小,因此适合用于那些支持 push_back()
的容器,比如 std::vector
、std::deque
和 std::list
。
1 std::back_inserter (Container& c);
使用 std::back_inserter
时不需要事先调整目标容器的大小,因为每次插入都会自动调整。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <iostream> #include <vector> #include <algorithm> #include <iterator> int main () { std::vector<int > numbers = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 }; std::vector<int > evens; std::copy_if (numbers.begin (), numbers.end (), std::back_inserter (evens), [](int n) { return n % 2 == 0 ; }); for (int n : evens) { std::cout << n << " " ; } return 0 ; }
示例解析
输入容器 :numbers
包含从 1 到 10 的整数。
条件 :我们使用了一个 lambda 表达式 [](int n) { return n % 2 == 0; }
,来筛选偶数。
目标容器 :evens
用来存放筛选出的偶数。由于使用了 std::back_inserter(evens)
,无需提前调整 evens
的大小。
输出结果:
std::copy_if
复制符合条件的元素。
std::back_inserter
可以避免提前设置目标容器大小,并通过 push_back
将元素添加到容器末尾。
二者结合使得代码简洁高效,尤其是在需要筛选并动态插入元素时非常有用。
reduce
(C++17 引入)reduce
是一个用于对一组数据进行归约操作的算法,它将范围内的元素合并为单个值,通常通过加法或乘法等操作。
1 2 template <class InputIt, class T, class BinaryOp>T reduce (InputIt first, InputIt last, T init, BinaryOp binary_op) ;
first
和 last
: 要归约的数据范围 [first, last)
。
init
: 初始值。
binary_op
: 二元操作函数,用于将两个元素归约为一个。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <iostream> #include <numeric> #include <vector> int main () { std::vector<int > v = {1 , 2 , 3 , 4 , 5 }; int sum = std::reduce (v.begin (), v.end (), 0 ); std::cout << "Sum: " << sum << std::endl; int product = std::reduce (v.begin (), v.end (), 1 , std::multiplies<>()); std::cout << "Product: " << product << std::endl; return 0 ; }
输出:
transform
是一个变换算法,用于将一个/两个范围内的元素通过某个函数变换为另一个值,可以将结果保存到原范围或另一个容器中。
1 2 template <class InputIt, class OutputIt, class UnaryOperation>OutputIt transform (InputIt first, InputIt last, OutputIt d_first, UnaryOperation unary_op) ;
first
和 last
: 输入范围 [first, last)
。
d_first
: 输出的起始迭代器,结果会写入此位置。
unary_op
: 一元操作函数,用于将每个元素进行变换。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <iostream> #include <vector> #include <algorithm> int main () { std::vector<int > v = {1 , 2 , 3 , 4 , 5 }; std::vector<int > result (v.size()) ; std::transform (v.begin (), v.end (), result.begin (), [](int i) { return i * 2 ; }); for (int i : result) { std::cout << i << " " ; } std::cout << std::endl; return 0 ; }
输出:
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 #include <iostream> #include <vector> #include <algorithm> int main () { std::vector<int > vec1 = {1 , 2 , 3 , 4 }; std::vector<int > vec2 = {5 , 6 , 7 , 8 }; std::vector<int > result (vec1. size()) ; std::transform (vec1. begin (), vec1. end (), vec2. begin (), result.begin (), std::plus <int >()); std::transform (vec1. begin (), vec1. end (), vec2. begin (), result.begin (), [](int a, int b) { return a * b; }); for (int num : result) { std::cout << num << " " ; } std::cout << std::endl; return 0 ; }
nth_element & accumulate
nth_element 默认的升序排序规则(std::less)时,
从某个序列中找到第 n 小的元素 K,并将 K 移动到序列中第 n 的位置处。
不仅如此,整个序列经过 nth_element() 函数处理后,所有位于 K 之前的元素都比 K 小,所有位于 K 之后的元素都比 K 大。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 void nth_element (RandomAccessIterator first, RandomAccessIterator nth, RandomAccessIterator last) ;void nth_element (RandomAccessIterator first, RandomAccessIterator nth, RandomAccessIterator last, Compare comp) ;nth_element(r1.begin(), r1.end() - k, r1.end()); return accumulate(r1.end() - k, r1.end(), 0 ) long long sum = accumulate(num.begin(), num.end(), 0LL );
其他 位运算 按位取反~
,按位异或^
在用到位运算的时候用这些函数会更加快捷
__builtin_ffs(x)
返回 x 的最后一位 1 是从后向前第几位 find first set
__builtin_clz(x)
返回 x 的二进制下前导的0 的个数,count left zero
__builtin_ctz(x)
返回 x 的二进制下末尾的0 的个数
__builtin_popcount(x)
返回 x 的二进制下 1 的个数
__builtin_parity(x)
返回 x 的二进制下 1 的个数的奇偶性, 偶数个1,输出0; 奇数个1,输出1。
数学概念 1 2 3 4 5 std::__gcd();为内置函数 求最大公因数the greatest common divisor #include <cmath> std::round (double_x);
字符串 1 2 3 int sprintf ( char *buffer, const char *format [, argument] ... ) ;eg.sprintf (s, "%d" , 123 );
字符串拆分
数字变成字符串保留小数位
初始化 1 2 #include <numeric> iota (ids, ids + n, 0 );
排序 1 2 3 4 sort (begin (nums1), end (nums1)); stable_sort (ids, ids + n, [&](int i, int j) { return nums[i] < nums[j]; });
参考文献