C++20中常用的算法---import <algorithm>

目录

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实践入门》

以下是使用OpenCV实现Lucas-Kanade光流算法处理视频的代码示例: ```python import cv2 import numpy as np # Parameters for Lucas-Kanade optical flow lk_params = dict(winSize=(15, 15), maxLevel=2, criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03)) # Capture video from camera cap = cv2.VideoCapture(0) # Take first frame and convert to grayscale ret, old_frame = cap.read() old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY) # Create a mask image for drawing purposes mask = np.zeros_like(old_frame) while True: # Read new frame ret, frame = cap.read() # Convert to grayscale frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # Calculate optical flow using Lucas-Kanade algorithm p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params) # Select good points good_new = p1[st == 1] good_old = p0[st == 1] # Draw the tracks for i, (new, old) in enumerate(zip(good_new, good_old)): a, b = new.ravel() c, d = old.ravel() mask = cv2.line(mask, (a, b), (c, d), (0, 255, 0), 2) frame = cv2.circle(frame, (a, b), 5, (0, 0, 255), -1) img = cv2.add(frame, mask) # Display the resulting frame cv2.imshow('frame', img) # Exit if ESC key is pressed k = cv2.waitKey(30) & 0xff if k == 27: break # Update previous frame and points old_gray = frame_gray.copy() p0 = good_new.reshape(-1, 1, 2) # Release video capture and close all windows cap.release() cv2.destroyAllWindows() ``` 在此示例,我们首先为Lucas-Kanade算法设置了一些参数,如窗口大小、最大金字塔级别和停止准则。然后,我们从摄像头捕获视频流,并将第一帧转换为灰度图像。我们还创建了一个掩码图像,用于绘制光流轨迹。在循环,我们读取新帧并将其转换为灰度图像。然后,我们使用Lucas-Kanade算法计算光流,并选择好的点。最后,我们在帧上绘制出光流轨迹,并将其与掩码图像合并以显示结果。如果按下ESC键,循环将终止并释放视频捕获。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值