目录
1、std::max_element()和std::min_element() -->找最大/小值
2、std::find()和std::find_if() -->找元素
3、std::copy()和std::copy_if() -->复制元素到新容器中
4、std::remove()和std::remove_if() -->把不用删的元素移到容器前部
5、std::erase()和std::erase_if() -->删除元素(不能给范围,只能整个容器)
6、std::sort() -->排序
(必备知识:迭代器和头等函数)
1、std::max_element()和std::min_element()
分别有两个重载版本,前两个参数分别是序列的指定范围的两个迭代器,输出为该范围中的最大/最小值的迭代器,第三个可选参数是比较器,即回调函数/函数对象,一般用lambda闭包。
举例:
std::vector<int> numbers{ 2,3,1,4,5,7,2,2,3 };
std::cout << *std::max_element(std::begin(numbers), std::end(numbers)); //7
int pivot{ 5 };
std::cout << *std::max_element(std::begin(numbers), std::end(numbers),
[=](int x, int y) {return std::abs(x - pivot) < std::abs(y - pivot); }); //1,离5最远
2、std::find()和std::find_if()
find()有三个实参,分别是序列的两个迭代器和需要寻找的元素,用来在一个范围内寻找等于给定值的元素(它使用==运算符比较值);find_if()也有三个实参,分别是序列的两个迭代器和一个回调函数,使用回调函数可以指定搜索的方式。两者的返回值都是第一个被找到的元素的迭代器。
举例:
std::vector<int> numbers{ 2,3,1,4,5,7,1,2,3 };
std::cout << *std::find(std::begin(numbers), std::end(numbers), 3) << std::endl; //3
std::cout << std::distance(std::begin(numbers),std::find(std::begin(numbers), std::end(numbers), 3)) << std::endl; //1,第一个3与容器首位间隔1
int divisor{ 3 };
std::cout << *std::find_if(std::begin(numbers), std::end(numbers),
[=](int num) {return num % divisor == 0; }) << std::endl; //3,找第一个能被3整除的数
3、std::copy()和std::copy_if()
上面的find()和find_if()只能返回找到的第一个元素的迭代器,如果想返回满足条件的所有元素,可以用copy_if()。它的功能是将原来的序列中满足条件的所有元素赋值到新的序列中;它有四个参数,前两个参数是输入迭代器,指原序列的元素范围,第三个是新的序列的迭代器,即从这个迭代器的位置开始添加筛选出来的元素,第四个参数是回调函数/函数对象,一般是lambda闭包。而std::copy(),它有三个参数,和copy_if()前三个参数一样。copy()和copy_if()算法都是输出新序列的迭代器,该迭代器指向最后一个被复制的元素的后一位。
举例:
std::vector<int> numbers{ 2,3,1,4,5,7,1,2,3 };
std::vector<int> copy (numbers.size());
auto copy_end = std::copy(std::begin(numbers), std::end(numbers),std::begin(copy));
std::cout << "Copy:" << std::endl;
std::cout << *(copy_end-1) << std::endl; //最后一位3被复制后,返回3的后一位
for (auto num : copy)
std::cout << num << "\t";
std::cout << std::endl << "Copy_if:" << std::endl;
std::vector<int> even_numbers(numbers.size());
auto copy_if_end = std::copy_if(std::begin(numbers), std::end(numbers), std::begin(even_numbers), [](int num) {return num % 2 == 0; });
std::cout << *(copy_if_end) << std::endl; //最后一个2被复制后,返回2的后一位,为0
for (auto num : even_numbers)
std::cout << num << "\t";
std::cout << std::endl;
even_numbers.erase(copy_if_end,even_numbers.end());//然后可以根据返回的迭代器删除后面多余的元素
for (auto num : even_numbers)
std::cout << num << "\t";
4、std::remove()和std::remove_if()
用来将不需要删除的元素移动到容器的前部,一般用于“删除-擦除”技术:先用std::remove()和std::remove_if()将需要保留的元素移到容器的前面,然后把后面不需要的元素用容器的erase成员函数删掉。总之,std::remove()和std::remove_if()不会真的去删元素,需要和erase成员函数搭配使用。std::remove()的三个参数是待处理的容器的两个迭代器(用来指定范围)和待删除的元素;std::remove_if()的三个参数是待处理的容器的两个迭代器(用来指定范围)和回调函数,一般是lambda闭包。它们的返回值是一个迭代器,该迭代器指向最后一个需要保留元素的后一位。
std::vector<int> numbers{ 1,2,3,3,4,5,6,3 };
auto remove_end = std::remove(std::begin(numbers), std::end(numbers), 3);
std::cout << "remove()" << std::endl;
std::cout << *remove_end << std::endl; //5,返回的是需要保留元素的后一位的迭代器,减1才指向最后一个不用删的元素
for (auto num : numbers)
std::cout << num << "\t"; //返回1 2 4 5 6 5 6 3
//除了前面不需要删的元素(1,2,4,5,6),后面的是杂乱的,这就是为什么说这个remove得和erase一起用
std::cout << std::endl;
numbers.erase(remove_end, std::end(numbers)); //用成员函数erase删掉后方多余的元素
for (auto num : numbers)
std::cout << num << "\t"; //1 2 4 5 6
std::cout << std::endl;
std::cout << "remove_if()" << std::endl;
std::vector<int> numbers2{ 1,2,3,3,4,5,6,3 };
auto remove_if_end = std::remove_if(std::begin(numbers2), std::end(numbers2),
[](int num) {return num % 2 == 0; });
std::cout << *(remove_if_end - 1) << std::endl;
for (auto num : numbers2)
std::cout << num << "\t"; //1 3 3 5 3 5 6 3 不用删的应该是 1 3 3 5 3
std::cout << std::endl;
numbers2.erase(remove_if_end, std::end(numbers2)); //用成员函数erase删掉后方多余的元素
for (auto num : numbers2)
std::cout << num << "\t";
5、std::erase()和std::erase_if()
上面的“删除-擦除”技术挺麻烦的,而且容易出错。c++20引入了std::erase()和std::erase_if(),试图用来取代上面的“删除-擦除”技术,std::erase()和std::erase_if()也被称为擦除函数。
std::erase()和std::erase_if()用来直接删除容器中指定的元素,这里的容器必须是支持随机访问的容器,如std::vector<T>、std::array<T,N>这样的数组容器,而对于std::list<T>、std::forward_list<T>这样的链表容器,用不了std::erase()(可以用链表容器自己的erase成员函数)。另外,必须是容器,普通数组也用不了。std::erase()和std::erase_if()的第一个实参是容器对象,第二个参数分别是指定的删除元素和指定删除条件的回调函数,两者返回的都是擦除的元素的数目。所以std::erase()和std::erase_if()只能针对整个容器删除元素,不能给范围,所以还是得知道“删除-擦除”技术。
举例:
std::vector<int> numbers{ 2,3,1,4,5,7,1,2,3 };
auto erase_count = std::erase(numbers, 5); //擦除了一个5,返回值为1
std::cout << erase_count << std::endl;
auto erase_if_count = std::erase_if(numbers, [](int num) {return num % 2 == 0; });
std::cout << erase_if_count << std::endl; //擦除了3个偶数,返回值为3
6、std::sort()
用来排序一个元素范围,有两个重载版本,前两个参数是指定范围的首尾迭代器,第三个参数是可选的比较器(回调函数),没有指定比较器的话,默认按升序排。
举例:
std::vector<int> numbers{ 9, 8, 7, 6, 5, 4, 3, 2, 1 };
std::sort(std::begin(numbers), std::end(numbers));
for (int num : numbers)
std::cout << num << "\t"; //1 2 3 4 5 6 7 8 9
std::cout << std::endl;
std::sort(std::begin(numbers), std::end(numbers),
[](const int& num1, const int& num2) {return std::abs(num1-5) < std::abs(num2-6); });
for (int num : numbers) //5 6 4 7 3 8 2 9 1 离5近的数排前面
std::cout << num << "\t";
另外,std::sort()算法还有并行版本,需要import <execution>。
std::vector<int> numbers{ 9, 8, 7, 6, 5, 4, 3, 2, 1 };
std::sort(std::execution::par,std::begin(numbers), std::end(numbers));
std::sort(std::execution::par,std::begin(numbers), std::end(numbers),
[](const int& num1, const int& num2) {return std::abs(num1-5) < std::abs(num2-6); });
暂时就这些,以后用到了好用的再加。
参考书籍:《c++20实践入门》