• 学了C++不会STL,简直少了左膀右臂


    什么是STL :

    容器(Container):
    是一种数据结构,如list,vector,和deques ,以模板类的方法提供。为了访问容器中的数据,可以使用由容器类输出的迭代器;
    迭代器(Iterator):
    提供了访问容器中对象的方法。例如,可以使用一对迭代器指定list或vector中的一定范围的对象。迭代器就如同一个指针。事实上,C++的指针也是一种迭代器。但是,迭代器也可以是那些定了operator*()以及其他类似于指针的操作符地方法的类对象;
    算法(Algorithm):
    是用来操作容器中的数据的模板函数。例如,STL用sort()来对一个vector中的数据进行排序,用find()来搜索一个list中的对象,函数本身与他们操作的数据的结构和类型无关,因此他们可以在从简单数组到高度复杂容器的任何数据结构上使用;
    仿函数(Functor)
    适配器(Adaptor)
    分配器(allocator)

    仿函数、适配器、与分配器用的比较少,甚至没用过!在这里不做说明,有兴趣可以自己学习一下,那个东西C++软件工程可能用的比较多。

    一、迭代器(Iterator)

    背景:指针可以用来遍历存储空间连续的数据结构,但是对于存储空间费连续的,就需要寻找一个行为类似指针的类,来对非数组的数据结构进行遍历。
    定义:迭代器是一种检查容器内元素并遍历元素的数据类型。
    迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围。
    迭代器(Iterator)是指针(pointer)的泛化,它允许程序员用相同的方式处理不同的数据结构(容器)。
    (1)迭代器类似于C语言里面的指针类型,它提供了对对象的间接访问。
    (2)指针是C语言中的知识点,迭代器是C++中的知识点。指针较灵活,迭代器功能较丰富。
    (3)迭代器提供一个对容器对象或者string对象的访问方法,并定义了容器范围。

    迭代器和指针的区别:
    容器和string有迭代器类型同时拥有返回迭代器的成员。如:容器有成员begin和end,其中begin成员复制返回指向第一个元素的迭代器,而end成员返回指向容器尾元素的下一个位置的迭代器,也就是说end指示的是第一个不合法地址,所以end返回的是尾后迭代器。

    容器迭代器的使用
    每种容器类型都定义了自己的迭代器类型,如vector:vector< int>:: iterator iter;//定义一个名为iter的变量,数据类型是由vector< int>定义的iterator 类型。简单说就是容器类定义了自己的iterator类型,用于访问容器内的元素。每个容器定义了一种名为iterator的类型,这种类型支持迭代器的各种行为。
    我么们先讲一下各种迭代器的类型,在讲容器所用的迭代器类型,就可以明白怎么操作。

    常见迭代器类型如下:

    所有迭代器 操作
    p++ 后置自增迭代器
    ++p 前置自增迭代器
    输入迭代器 操作介绍
    *p 复引用迭代器,作为右值
    p=p1 将一个迭代器赋给另一个迭代器(迭代器指向地址值)
    p==p1 比较迭代器的相等性(比较地址)
    p!=p1 比较迭代器的不等性
    输出迭代器 操作
    *p 复引用迭代器,作为左值
    p=p1 将一个迭代器赋给另一个迭代器
    正向迭代器 提供输入输出迭代器的所有功能
    双向迭代器 操作
    –p 前置自减迭代器
    p– 后置自减迭代器
    随机迭代器
    p+=i 将迭代器递增i位
    p-=i 将迭代器递减i位
    p+i 在p位加i位后的迭代器
    p-i 在p位减i位后的迭代器
    p[i] 返回p位元素偏离i位的元素引用
    p<p1 如果迭代器p的位置在p1前,返回true,否则返回false
    p<=p1 p的位置在p1的前面或同一位置时返回true,否则返回false
    p>p1 如果迭代器p的位置在p1后,返回true,否则返回false
    p>=p1 p的位置在p1的后面或同一位置时返回true,否则返回false

    只有顺序容器和关联容器支持迭代器遍历,各容器支持的迭代器的类别如下:

    容器 支持的迭代器类别 说明
    vector 随机访问 一种随机访问的数组类型,提供了对数组元素进行快速随机访问以及在序列尾部进行快速的插入和删除操作的功能。可以再需要的时候修改其自身的大小
    deque 随机访问 一种随机访问的数组类型,提供了序列两端快速进行插入和删除操作的功能。可以再需要的时候修改其自身的大小
    list 双向 一种不支持随机访问的数组类型,插入和删除所花费的时间是固定的,与位置无关。
    set 双向 一种随机存取的容器,其关键字和数据元素是同一个值。所有元素都必须具有惟一值。
    multiset 双向 一种随机存取的容器,其关键字和数据元素是同一个值。可以包含重复的元素。
    map 双向 一种包含成对数值的容器,一个值是实际数据值,另一个是用来寻找数据的关键字。一个特定的关键字只能与一个元素关联。
    multimap 双向 一种包含成对数值的容器,一个值是实际数据值,另一个是用来寻找数据的关键字。一个关键字可以与多个数据元素关联。
    stack 不支持 适配器容器类型,用vector,deque或list对象创建了一个先进后出容器
    queue 不支持 适配器容器类型,用deque或list对象创建了一个先进先出容器
    priority_queue 不支持 适配器容器类型,用vector或deque对象创建了一个排序队列

    二、容器

    所有容器都支持自定义数据类型,就是结构体。

    vector

    使用此容器需在程序前加上头文件#include< vector >。
    vector可理解为变长数组,基于倍增思想。当以已申请vector长度为m时,若实际长度n=m,则申请长度为2m的数组,将内容转移至新地址上,并释放旧空间;删除元素时,若n<=m/4,则释放一半空间。
    vector容器能像数组一样随机访问第i个数a[i],但不支持随机插入.

    #include<vector>       //头文件
    vector<int> a;  定义了一个int类型的vector容器a
    vector<int> b[100];定义了一个int类型的vector容器b组
    struct rec{···};
    vector<rec> c;           /定义了一个rec类型的vector容器c
    vector<int>::iterator it;           //vector的迭代器,与指针类似
    

    具体操作如下:

    	a.size()            //返回实际长度(元素个数),O(1)复杂度
        a.empty()           //容器为空返回1,否则返回0,O(1)复杂度
        a.clear()           //把vector清空
        a.begin()           //返回指向第一个元素的迭代器,*a.begin()与a[0]作用相同
        a.end()             //越界访问,指向vector尾部,指向第n个元素再往后的边界
        a.front()           //返回第一个元素的值,等价于*a.begin和a[0]
        a.back()            //返回最后一个元素的值,等价于*--a.end()和a[size()-1]
        a.push_back(x)      //把元素x插入vector尾部
        a.pop_back()        //删除vector中最后一个元素
    

    迭代器使用与指针类似,可如下遍历整个容器

    for ( vector<int>::iterator it=a.begin() ; it!=a.end() ; it++ )
    

    queue

    循环队列queue需使用头文件< queue >

    queue<int> q;   //定义了一个int类型的队列容器q
    struct rec{···};queue<rec> q;      //定义了一个rec类型的队列容器q
    q.push(x);           //从队尾使元素x入队,O(1)
    q.pop(x);            //使队首元素出队,O(1)
    int x=q.front();     //询问队首元素的值,O(1)
    int y=q.back();      //询问队尾元素的值,O(1)
    

    priority_queue

    优先队列priority_queue可理解为一个大根二叉堆,必须定义“小于号”,而int,string本身就能比较。同样需要头文件< queue >。
    其定义方式与queue相似。

    priority_queue<int> q;  由大到小
    priority_queue<pair<int,int>> q; //pair是一个数对,由first和scond两个元素构成,按照第一个排序
    priority_queue<int, vector<int>, greater<int> >qi2; //由小到大,小根堆,vector<int>是适配器,不用知道很详细,记住就行
    struct rec  //举个栗子
    {
    	int a,b,c;
    	bool operator<(const rec&w)
    	{
    		if(a==w.a) return b==w.b?c<w.c:b<w.b;
    		return a<w.a;
    	}
    };
    priority_queue<rec> q; 如果不写重载函数,会出错,他不知道怎么排序
    q.push(x);         //插入   O(log n)
    q.pop();           //删除堆顶元素    O(log n)
    q.top();           //查询堆顶元素   O(1)
    

    可通过插入元素的相反数取出时再取反,或重载“小于号”的方式实现小根堆,通过懒惰删除法实现随机删除操作。

    deque

    双端队列,是一个支持在两端高效插入或删除元素的连续线性存储空间,可像数组一样随机访问,使用前加头文件< deque >。

    q.begin()/q.end()              //头/尾迭代器,与vector类似
    q.front()/q.back()             //头/尾元素,与queue类似
    q.push_back(x)/q.push_front(x) //从队尾/队头入队
    q.pop_back(x)/q.pop_front(x)   //从队尾/队头出队
    q.clear()                      //清空队列
    

    定义方式

    deque<类型> 名称
    

    ps:clear复杂度为O(n),其余为O(1)。

    set/multiset

    两容器相似,但set为有序集合,元素不能重复,multiset为有序多重集合,可包含若干相等的元素,内部通过红黑树实现,支持的函数基本相同,同样必须定义“小于号”运算符,头文件为< set >。
    其迭代器不支持随机访问,支持星号(*)结束引用,仅支持 ++ 、-- 两个与算术有关的操作。迭代器it++,则指向从小到大排序的结果中排在it下一名的元素,两操作时间复杂度均为O(log n)。

    q.size()  //返回容器内元素个数
    q.empty()  //判断容器是否为空
    q.clear() //清空容器
    q.begin()/q.end()          //作用与上文几种容器类似
    q.insert(x)                //将元素x插入集合中,O(log n)
    q.find(x)                  //查找等于x的元素,返回其迭代器,无则返回q.end(),O(log n)
    q.lower_bound(x)           //查找>=x的元素中最小的一个,返回指向该元素的迭代器
    q.upper_bound(x)           //查找>x的元素中最小的一个,返回指向该元素的迭代器
    q.erase(it)                //删除迭代器it指向的元素,O(log n)
    q.erase(x)                 //删除所有等于x的元素,复杂度为O(k+log n),k为被删除的元素个数
    q.count(x)                 //返回等于x的元素个数,O(k+log n),k为元素x的个数
    

    定义方式

    
     
    set<int> demo 定义一个类型为int的set容器
    struct  rec
    {
        int a,b,c;
        bool operator<(const rec&w)
        {
            if(a==w.a) return b==w.b?c<w.c:b<w.b;
            return a<w.a;
        }
    };
      set<rec> ob;  一样所有排序的容器不重载就出错
    

    map/multimap

    map/multimap映射容器的元素数据是由一个Key和一个Value成的,key与映照value之间具有一一映照的关系。

    map/multimap容器的数据结构也采用红黑树来实现的,map插入元素的键值不允许重复,类似multiset,multimap的key可以重复。比较函数只对元素的key进行比较,元素的各项数据只能通过key检索出来。虽然map与set采用的都是红黑树的结构,但跟set的区别主要是set的一个键值和一个映射数据相等,Key=Value。

    map<first,second> a;
    //map,会按照first(键值)排序(查找也是);
    

    map/multimap用法
    头文件

    #include< map >
    

    map成员函数

    begin()				 //返回指向 map 头部的迭代器
    clear(// 删除所有元素
    count() 			//返回指定元素出现的次数
    empty()				// 如果 map 为空则返回 true
    end() 				//返回指向 map 末尾的迭代器
    erase()				// 删除一个元素
    find()				// 查找一个元素
    insert()			 //插入元素
    key_comp() 			//返回比较元素 key 的函数
    lower_bound() 		//返回键值>=给定元素的第一个位置
    max_size() 			//返回可以容纳的最大元素个数
    rbegin() 			//返回一个指向 map 尾部的逆向迭代器
    rend() 				//返回一个指向 map 头部的逆向迭代器
    size() 				//返回 map 中元素的个数
    swap()				 //交换两个 map
    

    创建map对象

    #include<iostream>
    #include<map>
    using namespace std;
    map<int,char>mp;//定义map容器 
    

    创建结构体map对象

    struct student{
    int birth;
    string name;
    };
    int id;
    typedef map<int,student> Student;// 这里相当于给map<int,student> 起了个别名Student,后续代码均可以用student代替map<int,student> 使用。
    

    插入结构体对象
    接上文代码

    Stduent  a; 
    cin>>id>>student.birth>>student.name;
    a.insert(make_pair(id,student));
       
    

    栈(stack)

    1.定义:
    栈是一种只能在某一端插入和删除数据的特殊线性表。他按照先进先出的原则存储数据,先进的数据被压入栈底,最后进入的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后被压入栈的,最先弹出)。因此栈也称先进后出表。
    允许进行插入删除操作的一端称为栈顶,另一端称为栈底。栈底固定,栈顶浮动。插入元素称为进栈,删除一个元素称为进栈,栈内元素为零称为空栈。
    2.stack成员函数

       bool empty ( ) ————>栈为空返回true,否则返回falsevoid pop ( ) ————>删除栈顶元素,出栈;
       void push(const TYPE&value)————> 插入新元素value,放置在栈顶进栈;TYPE:类型intchar…;
       size_type size ( ) ————> 返回堆栈中元素个数;(注意注意!!!!切不可赋值给int ,很容易超过int的范围
       TYPE&top()————> 查看当前栈顶元素;
    

    List

    定义:List类表示可通过索引访问的对象的强类型列表,提供用于对列表进行搜索、排序和操作的方法。
    作用:
    泛型最常见的用途是泛型集合
    我们在创建列表类时,列表项的数据类型可能是int,string或其它类型,如果对列表类的处理方法相同,
    就没有必要事先指定数据类型,留待列表类实例化时再指定。相当于把数据类型当成参数,这样可以最
    大限度地重用代码,保护类型的安全以及提高性能。
    定义 list<类型> 名称
    成员函数

       l.begin()	将迭代器返回到开头(Return iterator to beginning)
       l.end()	将迭代器返回到最后(Return iterator to end)
       l.rbegin()	Return reverse iterator to reverse beginning
       l.rend()	Return reverse iterator to reverse end
       l.l.empty()	检查容器是否为空
       l.size()	返回当前容器内元素个数
       l.max_size()	返回当前容器能容纳的最大元素数量
       l.front()	访问第一个元素
       l.back()	访问最后一个元素
       l.push_front()	将元素插入到开头
       l.pop_front()	删除第一个元素
       l.push_back()	将元素插入到最后
       l.pop_back()	删除最后一个元素
       l.insert()	插入元素
       l.erase()	删除元素
       l.swap()	交换两个 list 内容
       l.resize	()改变容器大小
       l.clear()	删除容器所有内容
    

    bitset

    bitset可看作一个多位二进制数,每8位占用1个字节,相当于采用了状态压缩的二进制数组,并支持基本的位运算。一般以32位整数的运算次数为基准估算运行时间,n位bitset执行一次的位运算复杂度可视为n/32,效率较高。头文件< bitset >。
    同样具有~,&,|,^,<<,>>操作符,==,!=可比较二进制数是否相等

    bitset<10000> q;      //声明一个10000位的二进制数
    q[k]                  //表示q的第k位,可取值,赋值,最低位为q[0]
    q.count()             //返回有多少位1
    q.none()              //所有位都为0则返回true,至少1位为1则返回false
    q.any()               //所有位都为0则返回false,至少1位为1则返回true,与函数none相反
    q.set()               //把所有位变为1
    q.set(k,v)            //把第k位变为v,即q[k]=v
    q.reset()             //把所有位变为0
    q.reset(k)            //把第k位变为0,即q[k]=0
    q.flip()              //把所有位取反,即s=~s
    q.flip(k)             //把第k位取反,即q[k]^=1
    

    三、算法

    查找算法(9个):判断容器中是否包含某个值

    (可以去看看C++primer学学别的,但是我认为太多了没必要)
    1.count:
    利用等于操作符,把标志范围内的元素与输入值比较,返回相等元素个数。

    #include<iostream>
    #include<algorithm>
    using namespace std;
    int main()
    {
        int a[14]={0,1,2,3,4,5,6,7,7,7,7,7,7,8};
        cout<<count(a,a+14,7)<<endl;
        vector<int> demo;
        for(int i=0;i<10;i++)
            demo.push_back(i);
        demo.push_back(1);
        cout<<count(demo.begin(),demo.end(),1)<<endl;
    }
    //运行结果 6 2;
    

    2.count_if:
    利用输入的操作符,对标志范围内的元素进行操作,返回结果为true的个数。

    #include<iostream>
    #include<algorithm>
    using namespace std;
    bool cmp(int a)
    {
        return (a>1);
    }
    int main()
    {
        int a[14]={0,1,2,3,4,5,6,7,7,7,7,7,7,8};
      int po=count_if(a,a+14,cmp);
       cout<<po<<endl;
        vector<int> demo;
        for(int i=0;i<10;i++)
            demo.push_back(i);
        demo.push_back(1);
       int poi=count_if(demo.begin(),demo.end(),cmp);
        cout<<poi<<endl;
    }// 运行结果   8 12
    //看到网上大佬的代码写的比较深奥,特地去查了查书,我这样用没毛病的。
    

    补充:捕获值列表,是允许我们在Lambda表达式的函数体中直接使用这些值,捕获值列表能捕获的值是所有在此作用域可以访问的值,包括这个作用域里面的临时变量,类的可访问成员,全局变量。捕获值的方式分两种,一种是按值捕获,一种是按引用捕获。顾名思义,按值捕获是不改变原有变量的值,按引用捕获是可以在Lambda表达式中改变原有变量的值。

    [捕获值列表]:

    1、空。没有使用任何函数对象参数。
    2、=。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
    3、&。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。
    4、this。函数体内可以使用Lambda所在类中的成员变量。
    5、a。将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符。
    6、&a。将a按引用进行传递。
    7、a, &b。将a按值进行传递,b按引用进行传递。
    8、=,&a,&b。除a和b按引用进行传递外,其他参数都按值进行传递。
    9、&, a, b。除a和b按值进行传递外,其他参数都按引用进行传递。

    3.equal_range:
    功能类似equal,返回一对iterator,第一个表示lower_bound,第二个表示upper_bound。

      #include<iostream>
        #include<algorithm>
        using namespace std;
        bool cmp(int a)
        {
            return (a>1);
        }
        int main()
        {
         //   int a[14]= {0,1,2,3,4,5,6,7,7,7,7,7,7,8};
            //equal_range(a,a+14,auto po);
            vector<int> demo;
            for(int i=0; i<10; i++)  demo.push_back(i);
            demo.push_back(1);
           cout<<*equal_range(demo.begin(),demo.end(),7).first<<endl;
           cout<<*equal_range(demo.begin(),demo.end(),7).second<<endl;
           cout<<equal_range(demo.begin(),demo.end(),7).first-demo.begin()<<endl;
           cout<<equal_range(demo.begin(),demo.end(),7).second-equal_range(demo.begin(),demo.end(),7).first<<endl;
        }
        //也可以加cmp函数,同样适用于数组,在下文中不再举出数组的例子
    

    4.find:
    利用底层元素的等于操作符,对指定范围内的元素与输入值进行比较。当匹配时,结束搜索,返回该元素的一个InputIterator。

    补充
    InputIterator是用于输入的Iterator
    OutputIterator是用于输出的Iterator
    ForwardIterator是InputIterator,同时可以保证++运算不会使之失效
    RandomIterator是ForwardIterator,同时具有+,-,+=,-=等运算及各种比较操作

    #include<iostream>
    #include<algorithm>
    using namespace std;
    int main()
    {
       int a[14]= {0,1,2,3,4,5,6,7,7,7,7,7,7,8};
        vector<int> demo;
        for(int i=0; i<14; i++)  demo.push_back(a[i]);
        demo.push_back(1);
        cout<<find(demo.begin(),demo.end(),8)-demo.begin()<<endl;
    } //可以直接取地址获取值。
    
    

    5.find_end:
    在指定范围内查找"由输入的另外一对iterator标志的第二个序列"的最后一次出现。找到则返回最后一对的第一个ForwardIterator,否则返回输入的"另外一对"的第一个ForwardIterator。重载版本使用用户输入的操作符代替等于操作。

    #include<iostream>
    #include<algorithm>
    using namespace std;
    int main()
    {
       int a[14]= {0,1,2,3,4,5,6,7,7,7,7,7,7,8};
        vector<int> demo;
        for(int i=0; i<14; i++)  demo.push_back(a[i]);
        demo.push_back(1);
        cout<<find_end(demo.begin(),demo.end(),a+2,a+3)-demo.begin()<<endl;
    }
    
    

    6.find_first_of:
    在指定范围内查找"由输入的另外一对iterator标志的第二个序列"中任意一个元素的第一次出现。重载版本中使用了用户自定义操作符。

    #include<iostream>
    #include<algorithm>
    using namespace std;
    int main()
    {
       int a[14]= {0,1,2,3,4,5,6,7,7,7,7,7,7,8};
        vector<int> demo;
        for(int i=0; i<14; i++)  demo.push_back(a[i]);
        demo.push_back(1);
        cout<<find_first_of(demo.begin(),demo.end(),a+2,a+3)-demo.begin()<<endl;
    }
    
    

    7.find_if:
    使用输入的函数代替等于操作符执行find。返回的是迭代器,为了是大家更明白的理解,减去第一个元素的位置,就相当于得到了下标;

    #include<iostream>
    #include<algorithm>
    using namespace std;
    bool cmp(int w)   {
        return w>5;
    }
    int main()
    {
       int a[14]= {0,1,2,3,4,5,6,7,7,7,7,7,7,8};
        vector<int> demo;
        for(int i=0; i<14; i++)  demo.push_back(a[i]);
       cout<< find_if(demo.begin(),demo.end(),cmp)-demo.begin();
    }
    
    

    8.lower_bound:
    返回一个ForwardIterator,指向在有序序列范围内的可以插入指定值而不破坏容器顺序的第一个位置。重载函 数使用自定义比较操作。
    在一个有序的范围内时间复杂度为log2n,普遍适用于二分算法。
    跟3.equal_range的用法一样不过这个返回的是first
    9.upper_bound:
    返回一个ForwardIterator,指向在有序序列范围内插入value而不破坏容器顺序的最后一个位置,该位置标志 一个大于value的值。重载函数使用自定义比较操作。跟3.equal_range的用法一样不过这个返回的是second;

    排序和通用算法(7个):提供元素排序策略

    1. inplace_merge:

      合并两个有序序列,结果序列覆盖两端范围。重载版本使用输入的操作进行排序。

    2. merge:

      合并两个有序序列,存放到另一个序列。重载版本使用自定义的比较。 nth_element:
      将范围内的序列重新排序,使所有小于第n个元素的元素都出现在它前面,而大于它的都出现在后面。重载版本使用自定义的比较操作。

    3. partial_sort:

      对序列做部分排序,被排序元素个数正好可以被放到范围内。重载版本使用自定义的比较操作。

    4. partial_sort_copy:

      与partial_sort类似,不过将经过排序的序列复制到另一个容器。 partition:
      对指定范围内元素重新排序,使用输入的函数,把结果为true的元素放在结果为false的元素之前。 random_shuffle:
      对指定范围内的元素随机调整次序。重载版本输入一个随机数产生操作。 reverse:
      将指定范围内元素重新反序排序。 reverse_copy: 与reverse类似,不过将结果写入另一个容器。

    5. rotate:

    将指定范围内元素移到容器末尾,由middle指向的元素成为容器第一个元素。

    1. rotate_copy:

      与rotate类似,不过将结果写入另一个容器。

    2. sort:(常用,相信大家都不陌生)

      以升序重新排列指定范围内的元素。重载版本使用自定义的比较操作。

     sort(首地址,第一个不合法地址(即末地址+1),cmp)//cmp可以缺省
     bool cmp()//可以用到结构体上 
     {
        	return (); 
      } 
            
    
    1. stable_sort:

      与sort类似,不过保留相等元素之间的顺序关系。 stable_partition:
      与partition类似,不过不保证保留容器中的相对顺序。 <三>删除和替换算法(15个) copy:
      复制序列 copy_backward: 与copy相同,不过元素是以相反顺序被拷贝。 iter_swap:
      交换两个ForwardIterator的值。

    删除修改复制(12个):简单操作区间元素

    1. remove:

      删除指定范围内所有等于指定元素的元素。注意,该函数不是真正删除函数。内置函数不适合使用remove和 remove_if函数。

    2. remove_copy:
      将所有不匹配元素复制到一个制定容器,返回OutputIterator指向被拷贝的末元素的下一个位置。

    3. remove_if:

      删除指定范围内输入操作结果为true的所有元素。

    4. remove_copy_if:

      将所有不匹配元素拷贝到一个指定容器。

    5. replace:

      将指定范围内所有等于vold的元素都用vnew代替。

    6. replace_copy:

      与replace类似,不过将结果写入另一个容器。

    7. replace_if:

      将指定范围内所有操作结果为true的元素用新值代替。

    8. replace_copy_if:

      与replace_if,不过将结果写入另一个容器。

    9. swap:

      交换存储在两个对象中的值。

    10. swap_range:

      将指定范围内的元素与另一个序列元素值进行交换。

    11. unique: (常用于离散化)

      清除序列中重复元素,和remove类似,它也不能真正删除元素。重载版本使用自定义比较操作。

    12. unique_copy: (同上)

      与unique类似,不过把结果输出到另一个容器。

    排列组合算法(2个):提供计算给定集合按一定顺序的所有可能排列组合

    以深搜的形式实现:

    1. next_permutation:

      取出当前范围内的排列,并重新排序为下一个排列。重载版本使用自定义的比较操作。

    2. prev_permutation:

      取出指定范围内的序列并将它重新排序为上一个序列。如果不存在上一个序列则返回false。重载版本使用 自定义的比较操作。

      //常以此方式使用,但时间复杂度N!这个。。。。
      do
      {
      	//操作
      }while((next_permutation(首地址,第一个不合法地址)
      

    生成和异变算法(3个)

    1. fill:
      将输入值赋给标志范围内的所有元素。

      fill(首地址,第一个不合法地址,2); //该区间内全部赋值为2
      

      区别于memset,memset是按位赋值,只能赋每位值相同值。

      memset(首地址,value,(字节数)常用sizeof()获取)
      
    2. fill_n:

      将输入值赋给first到first+n范围内的所有元素。

      // 从开始以此赋值,3个5
      fill_n(首地址,3,5);
      
    3. transform:

      将输入的操作作用与指定范围内的每个元素,并产生一个新的序列。重载版本将操作作用在一对元素上,另外一个元素来自输入的另外一个序列。结果输出到指定容器。

    transform (原始对象首地址, 原始对象第一个不合法地址, 输出对象首地址, operate(操作函数);
        char operate(char c)//常用转化大小写,以此为例子
        {
        	if (isupper(c))
    		{
    			return c+32;
    		}
    		return c;
        }
        
    

    关系算法(6个)

    1. equal:

      如果两个序列在标志范围内元素都相等,返回true。重载版本使用输入的操作符代替默认的等于操作符。

    2. includes:

      判断第一个指定范围内的所有元素是否都被第二个范围包含,使用底层元素的<操作符,成功返回true。重载版本使用用户输入的函数。

    3. max:(很多人问我,这不是cmath吗,呃。。。。。不是)
      返回两个元素中较大一个。重载版本使用自定义比较操作。

      max(3,5)的值是5;
      
    4. max_element:

      返回一个ForwardIterator,指出序列中最大的元素。重载版本使用自定义比较操作。

      max_element(a, a+6)  返回一个最大值位置指针
      
    5. min:

      返回两个元素中较小一个。重载版本使用自定义比较操作。

      min(3,5)的值是5;
      
    6. min_element:

      返回一个ForwardIterator,指出序列中最小的元素。重载版本使用自定义比较操作。

    集合算法(4个)

    1. set_union:
      构造一个有序序列,包含两个序列中所有的不重复元素。重载版本使用自定义的比较操作。

    2. set_intersection:
      构造一个有序序列,其中元素在两个序列中都存在。重载版本使用自定义的比较操作。

    3. set_difference:
      构造一个有序序列,该序列仅保留第一个序列中存在的而第二个中不存在的元素。重载版本使用自定义的比较操作。

    4. set_symmetric_difference:

    构造一个有序序列,该序列取两个序列的对称差集(并集-交集)。
    

    堆算法(4个)

    1. make_heap:

      把指定范围内的元素生成一个堆。重载版本使用自定义比较操作。
      
    2. pop_heap:

      并不真正把最大元素从堆中弹出,而是重新排序堆。它把first和last-1交换,然后重新生成一个堆。可使用容器的back来访问被"弹出"的元素或者使用pop_back进行真正的删除。重载版本使用自定义的比较操作。

    3. push_heap:

      假设first到last-1是一个有效堆,要被加入到堆的元素存放在位置last-1,重新生成堆。在指向该函数前,必须先把元素插入容器后。重载版本使用指定的比较操作。

    4. sort_heap:

      对指定范围内的序列重新排序,它假设该序列是个有序堆。重载版本使用自定义比较操作。

  • 相关阅读:
    JDBC连接数据库的四种方式:DriverManager,DataSource,DBCP,C3P0
    下面代码打印的结果?
    当一个线程进入一个对象的synchronized方法A之后,其他线程是否可进入此对象的synchronized方法B?
    线程的sleep()方法和yield()方法有什么区别?
    今天,想说一说明星涉毒
    【译文】为什么用户体验文案在产品设计中如此重要?
    【译文】东京的外国工程师
    浅谈K8S cni和网络方案
    网易云易盾发布多国家多语种内容安全服务,助力中国互联网出海
    如何着手商业数据分析?
  • 原文地址:https://www.cnblogs.com/lunatic-talent/p/13499508.html
Copyright © 2020-2023  润新知