STL algorithm学习笔记

本篇主要总结在C++标准库algorithm头文件下的函数的使用方法

1 lower_bound和upper_bound(应用于有序区间)

template <class ForwardIterator, class T>
inline ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last, const T& value) {
    return __lower_bound(first, last, value, distance_type(fist), iterator_category(first));
}

template <class ForwardIterator, class T>
inline ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last, const T& value) {
    return upper_bound(first, last, value, distance_type(fist), iterator_category(first));
}

lower_bound和upper_bound都是利用二分查找的方法在一个排好序(默认是按照从小到大地排序)的数组中进行查找。

lower_bound是二分查找的一种版本,试图在已经排好序的[first, last)中寻找元素value。如果在区间内有与value值相等的元素,便返回指向其中第一个元素的迭代器。如果没有这样的元素存在,其返回值是在不破坏排序状态的原则下,可插入value的第一个位置注意喽,这里并不一定返回的是指向last的迭代器)。我看到很多博客里面都说:如果寻找的value不存在则返回last。注意了!这样的说法是错误的!

upper_bound也是二分查找的一种版本,和lower_bound很像。唯一的区别在于:它会返回在不破坏顺序的情况下,可插入value的最后一个合适的位置举个栗子:如果查找某值value,它存在于区间[first, last)之中,则lower_bound返回的是第一个指向value的迭代器,而upper_bound回的是一个指向最后一个值为value的迭代器的下一个位置,而非value本身。

在从大到小的排序数组中,需要重载lower_bound()和upper_bound()。

lower_bound(begin, end, val, greater<type>());

upper_bound(begin, end, val, greater<type>());

2  sort函数

sort函数可以有两个参数或者三参数,它使用的排序方法是类似于快排的方法,事件复杂度为nlogn.

sort函数一共有三个参数,第三个参数可以不写:

  • 第一个参数是要排序的数组的起始地址
  • 第二个参数是数组结束的地址(最后一位要排序的元素的地址)
  • 第三个参数是排序的方法,如果不写第三个参数默认是按元素从小到大的排序

 2.1 两个参数的用法

以vector为例,一般的默认的(按照元素从小到大排序)写法为:

#include <iostream>
#include <algorithm>
using namespace std;

int main() {
    int a[5] = {1, 34, 23, 5, 14};
    vector<int> vec(a, a+5);
    sort(vec.begin(), vec.end());    //输出: 1 5 14 23 34

    return 0;
}

2.2 三个参数的用法

在2.1中默认使用从小到大的排序,其等价于:

sort(a, a+5, less<int>());

因此,less实现了元素按照从小到大的排序,本质上是这样一个函数:

bool less(int a, int b) {
    return a < b;
}

同样的如果想要实现从大到小的排序,只需要将上面代码中的小于号换成大于号即可,在stl模板库中定义了对应的greater<type>, 所以,想让元素按照从大到小的排序,只需要将其修改为:

sort(a, a+5, greater<int>());

*进阶1

那么问题来了,如果我的数据结构比较复杂不单单是int,我想自定义比较函数应该怎么写呢?选择很多

【第一种写法】一般的如果是自定义的数据结构,那么会使用结构体来定义结构,只需要在结构体中重载比较函数即可,例如:

struct carRunTime
{
	int carId;
	int runTime;
	int maxSpeed;
	carRunTime(int id, int time, int speed) : carId(id), runTime(time), maxSpeed(speed) {}
	bool operator < (const carRunTime & crt) const {
	    if(runTime == crt.runTime) {
	        return maxSpeed > crt.maxSpeed;
	    }
	    return runTime <= crt.runTime;
	}
};

上面的代码中,我们重载了<比较函数,那么在后面使用的时候就使用less<type>:

sort(carList.begin(), carList.end(), less<carRunTime>());

【第二种写法】不过,也可以像下面这样直接定义一个函数作为sort的第三个参数,而不需要使用less或greater模板:

#include <iostream>
#include <algorithm>
using namespace std;

bool cmp (int i, int j) { return i < j; }

int main() {
    int a[5] = {1, 34, 23, 5, 14};
    vector<int> vec(a, a+5);
    sort(vec.begin(), vec.end(), cmp);    //输出: 1 5 14 23 34

    return 0;
}

【第三种写法】对于比较简单的数据结构如int,还可以直接定义一个结构体来作为sort的第三个参数:

#include <iostream>
#include <algorithm>
using namespace std;

struct myclass {
    bool operator() (int i, int j) { return i < j; }
} myobject;

int main() {
    int a[5] = {1, 34, 23, 5, 14};
    vector<int> vec(a, a+5);
    sort(vec.begin(), vec.end(), myobject);    //输出: 1 5 14 23 34

    return 0;
}

**进阶2

再深入一点,如果给你一个vector<vector<int>>,现在想对其中的数据进行排序应该如何排序呢?

vector<vector<int>> vec中的数据格式如下:

[[4,10], [24,200], [50,40], [45,22]]

现在需要对其中的数据按照每个子vector中的第一个元素从小到大排序,下面的写法你能看懂吗:

sort(vec.begin(), vec.end(), [](vector<int>& a, vector<int>& b) {
    return a[0] < b [0];
});

在上面的代码中使用了lambda表达式,直接将比较函数嵌入到了sort函数中!

同样的,如果需要对其中的数据按照每个子vector中的第一个元素和第二个元素的差值从小到大的排序,应该这样写:

sort(vec.begin(), vec.end(), [](vector<int>& a, vector<int>& b) {
    return a[0] - a[1] < b [0] - b[1];
});

3 for_each

for_each可以简单理解为遍历容器[first, last)区间的每一个元素,for_each不可修改元素内容,如果想要一一修改元素的内容,应该使用算法transform()。源码:

template <class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f) {
    for (; first != last; ++first)
        f(*first);
    return f;
}

最简单的使用方法:

#include<iostream>
#include<vector>
#include<algorithm>
#include<typeinfo>
using namespace std;

struct Play
{
    void operator () (int i)
    {
        cout<<i<<endl;
    }
};

int main()
{
    int a[] = { 1, 3, 4, 5};
    vector<int> vc(a, a+sizeof(a)/sizeof(int));
    for_each(vc.begin(), vc.end(), Play());
}

使用lambda表达式的使用方法:

#include<iostream>
#include<vector>
#include<algorithm>
#include<typeinfo>
using namespace std;

int main()
{
    int a[] = { 1, 3, 4, 5};
    vector<int> vc(a, a+sizeof(a)/sizeof(int));
    for_each(vc.begin(), vc.end(), [](int a){
    	cout << a << ", ";
    });
}

常用容器使用for_each举例:

发布了115 篇原创文章 · 获赞 96 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/qq_26822029/article/details/89298650
今日推荐