标准模板STL

来源:互联网 发布:光翼网络班客户端 编辑:程序博客网 时间:2024/06/10 23:06
1. STL(1)先回忆数据结构从数据结构的学习中,我知道了有顺序表,链表,哈希表,顺序树,链式数等数据结构可以用于存放数据。在c中,这些数据结构都需要程序员自己实现,但是在面向对象的语言中,为了节省编程者的开发时间,都提供了自己的定义的现成可用的数据结构,这些数据结构本质上还是数组,链表,树(红黑树),哈希表等等。(2)一个数据结构包含哪些内容以我们之前学习的链表这个数据结构为例,它包含如下内容。(1)容器:链表就是一个存放数据的容器,存储结构为链式存储,存放数据时,    需要反映出被存储数据的逻辑结构(2)遍历:向前向后索引节点就是遍历,遍历节点是能够访问数据的前提。当然对于    遍历操作来说,除了可以使用迭代器外。(3)算法:对链表中的数据的具体操作算法,增加,删除,查找,修改,排序实际上对于高级语言自带的数据结构做的也是这些事情,但是这些事情不需要程序员操心,我们只要学会使用就好,有了这些现成的数据结构,我们甚至都可以省去使用自定义数组,因为这些数据结构本身就可以替代数组的功能。某些数据结构中本身就是数组。(1)c++的STL模板库与java中的集合对于哪些封装好的现成可用的数据结构在c++中叫STL,java中称为集合,实际上是一个东西,对于这些现成的数据结构来说,同样涉及如下三个方面的内容:(1)容器(2)遍历:普通指针,迭代器(智能指针),在c++和java都有迭代器,实现原理也    是一样。(3)算法:针对操作容器的算法,可以有如下3情况    (1)可以自己实现操作容器的算法,实际上这么做没有必要    (2)容器提供成员函数方式实现的算法    (3)STL模板库提供全局算法函数对于容器和集合的学习,重点在于学习怎么使用容器,比通过提供的算法去操作容器中的数据。不管是c++还是java的定义的数据结构,都是用到了泛型,在c++称为模板(函数模板和类模板)。2. 容器/迭代器/算法(1)STL容器:(1)存放内容的方式    (1)存放副本:存放副本的特点是,修改副本并不会修改原对象的内容。    (2)存放指针:使用指针好处是,效率很高,比存放副本的方式效率高很多。    在java中没有存放副本的做法,存放的都是指针。(2)STL容器分类    (1)序列容器:以线性方式组织管理存放的数据,STL提供的顺序容器有:        (1)vector<T>:以数组方式实现的数据结构,空间开辟于堆,                其大小和容量可以根据实际情况改变。        (2)deque<T>:可以在两头操作的特殊vector。        (3)list<T>:使用链表实现的数据结构。        (4)stack:栈,使用较少                   (5)queue:队列,使用较少        (6)priority_queue:优先队列,使用较少      (2)关联容器:使用键值(key)与存储的内容关联起来,通过key去访问容        器的中内容。STL提供的关联容器有:        (1)map<key, T>:容器中一部分用于存放key值(key值不能重复)。                另一部分用于存放key值对应的数据,把我们把                Key和对应的数据我们称为键值对。        (2)multimap<key, T>:同map,但是key值可以重复。        (3)set<key>:数据本身就是key值,要求内容不能重复。        (4)multiset<key>:同set,但是内容可以重复。     在c++这只提供了线性容器和关联容器这两类,但是在java提供了更加丰富的容器,    (1)线性容器:vector,list,队列等    (2)非线性容器:树(tree)结构的容器       (3)关联容器:map和set(2)STL迭代器(普通指针)(1)什么是迭代器    迭代器就是封装好的智能指针,在学习前面的课程中,我们知道,智能指针    就是对指针做了类封装的,c和c++中的指针就是最简单的迭代器。(2)按功能对迭代器进行分类    从功能上按照简单到复杂的顺序,迭代器分为如下及种类型,复杂类型的迭    代器兼容简单类型的迭代器。    (1)输入输出迭代器        (1)用于读写一系列的对象,输入迭代器只能进行读操作,输出            迭代只能进行写操作。        (2)只能使用一次,第二次使用需要重新创建        (3)实现的操作有:前后++,==,!=,*    (2)前向迭代器        兼容输入输出迭代器的功能,可以多次使用向前迭代器读写容器        中的对象,迭代器支持++操作(前++/后++都支持)。    (3)双向迭代器        兼容前向迭代器的功能,但同时还允许向后遍历对象。所以迭代器        还支持前后--的操作(前--/后--都支持)。    (4)随机迭代器        兼容双向迭代器的功能,但是同时允许随机访问。因为支持随机访        问,所以必须支持如下操作:        (1)iter+n和iter-n操作,iter[n]等价于*(iter+n)        (2)iter+=n和iter-=n操作        (3)迭代器相减,iter1-iter2操作        (4)迭代器比较操作,比如iter1<iter2,iter1>iter2,            iter1<=iter2,iter1>=iter2操作。    以上功能是累积的,输入输出迭代器功能最弱,随机迭代器功能最强。(3)在迭代器中使用泛型的问题    定义迭代器对象时,需要指定访问的数据类型,比如:        std::vector<int>::iterator iter;    如果类型是泛型的话,定义迭代器是必须使用typename关键字,否者将会无法使用,比如:        typename std::vector<T>::iterator iter;    如果使用typedef给迭代器类型起别名时,如果涉及到泛型,那么同样的也需要使用    typename关键字,比如:        typedef typename std::vector<T>::iterator Iter;        Iter iter;//使用别名定义迭代器(3)如何获取迭代器    (1)自定义迭代器,自定义迭代器可以按照自己要求实现以上4种类型中需要类型的迭代器。    (2)从容器中获取迭代器        STL容器自己提供了访问容器的迭代器。        容器:     提供的迭代器类型        vector                  随机                      deque                   随机                 list                    双向        set                     双向         multiset                双向                     map                     双向        multimap            双向                                stack                   不支持迭代器                          queue               不支持迭代器        priority_queue      不支持迭代器        vector和deque之所以可以随机访问,因为他们本质上都是数组,我们前面讲过,数组        本身就支持随机访问。        list本质是链表,链表是不支持随机访问。        set和map专门用于存放集合类数据,也是不支持随机访问的。        栈,队列,优先队列之所以没有迭代器,因为都是在它们的头尾进行操作的,不需要遍        历和随机访问。    (3)使用容器以外迭代器        比如iostream,istream, ostream, sstream等输入输出流提供的迭代器。(3)算法函数(1)容器提供的成员算法函数    每种容器都提供了哪些成员算法函数,将在后面讲解,成员算法函数中,有些是直接定义的    函数,有些就是通过函数模板实现的。    容器提供的成员算法函数只针对本容器进行的。(2)全局算法函数    (1)查找类        find(),find_end(),adjacent_find(),count(), mismatch(),        seaech(), equal()。    (2)修改类        swap(), copy(), transform(). replace(), remove(), reverse(),        rotate(), fill(), random/_shffle()。    (3)排序        sort() stable_sort(), binary_search(), merage(), min(),         max(), lexicographical_compare()。    实际上一些普通的修改,查找等操作,直接通遍历访问每个元素就可以实现,    不需要使用这些算法函数。全局算法函数大多都是通过函数模板实现的。    全局算法函数可以针对不同种类的容器进行操作,但是也有些容器是无法通过    全局算法函数无法操作的,这个时候只能通过容器的成员算法函数进行操作。(4)STL的头文件(1)容器头文件    <vector>(单端数组), <deque>(双端数组), <list>, <map>, <set>,     <queque>(双端队列),<stack>(栈)   (2)迭代器头文件    <iterator>    但是由于容器使用到了迭代器,因此容器头文件中也有包含<iterator>头文    件,包含容器头文件时,可以不用包含迭代器头文件。        如果使用到了输入输出流提供的迭代器,需要包含输入输出流的头文件,比    如<iostream>, <istream>, <ostream>,<sstream>。(3)全局算法涉及头文件    <algorithm>    如果涉及函数对象,还需要<functional>头文件。3. vector容器(1)普通数组与vector只要能够使用数组的地方,就一定可以使用vector代替,前面说到,vector其实就是数组,只是空间开辟于堆中。普通数组长度是固定的,但是vector容器的容量和大小可以根据实际情况不同而改变。容量与大小:    对于vector来说容量和大小是不同的,容量>=大小,    容量:vector容器最大能够存放的元素个数。    大小:vector容器当前实际存放的元素个数。    使用数组存放数据时实际上也存在容量与大小的关系,只是平时我们不并    不关心这个问题。    当数组空间未存满时,数组实际元素个数就是大小,数组的最大元素空间    就是容量。获取vector的容量和大小:    分别通过vector的size()和capacity()成员函数便可以获取vector的容    量和大小。(2)vector容器的优缺点优点:vector容器的容量和大小可以可根据情况变更。缺点:vector本质上是一个单端数组,在其末尾添加和删除元素,效率都很高,    但是在vector的中间插入和删除效率就很低,这会导致大量的元素需    要被移动。(3)创建vector(1)创建一个空的,存放基本类型数据的vector    std::vector<int> v;    vector属于std命名空间,因此需要使用std::,该定义表示利用vector    容器类的默认构造器创建了一个vector,该容器存放的数据类型为int型,    vector的容量和大小都是0。    cout <<"大小:"<< v.capacity() <<endl;    cout <<"容量:"<< v.size() <<endl;    打印结果都为0。    创建一个空的vector容器并不是一种高效的创建方式,因为向vector    容器添加新元素时,会导致频繁的扩充容器空间,操作效率很低,因此    很多时候我们都会给容器预先指定一定大小的初始空间,提高操作效率。(2)创建一个有一定大小vector   (1)创建存放基本类型数据的vector    std::vector<int> v(10);    调用vector容器的有参构造函数,该参数用于说明容器的大小和容量。    创建有一定空间,用于存放基本类型数据的vector时,    (1)所有元素都会被初始化为0    (2)最开始时,容器的容量==大小,    比如打印出定义的v的容量和大小,    cout <<"容量:"<< v.capacity() <<endl;    cout <<"大小:" v.size() <<endl;    打印结果都为10。    当向容器里面插入新的数据时,容器中的容量扩大的速度大于大小扩大的速度,    多出来的冗余空间是为了提高容器的效率。    比如:      v.insert(v.begin(), 23);        cout <<"容量:" v.capacity() << endl;    cout <<"大小:" v.size() << endl;    打印结果:      容量:20      大小:11   (2)创建存放类类型对象的vector      student() {    public:    private:        string anme;        int num;    };    std::vector<Student> vstus(20);    创建一个vector容器,包含20个Student对象,每个对象都调用Student    类的默认构造函数进行初始化,所以对于Student类来说,要求必须实现    其默认构造函数。    由于这里定义的Student类没有其它构造函数,所以编译器会提供默认    构造函数。    至于需不需要显式定义拷贝构造函数和析构函数,需要根据实际情况而    定,为了保证类定义标准化和完整性,建议写出。    在类中最好提供=和<的重写,否则当涉及给最容器中的内容进行排序时,    可能会出现问题。不过很多时候,容器都提供了默认的比较方法,因此    都能按照默认比较方法对容器中的数据进行排序。(3)创建时给容器给一些初始值    不能够直接使用一组数据初始化vetor容器,但是可以使用定义好的c++    数组初始化vector容器。    (1)方法1:赋值        (1)基本类型数据            int buf[] = {1, 2, 4, 3, 6, 7, 8, 9, 0};                 std::vector<int> v(10);                for(int i=0; i<sizeof(buf)/sizeof(buf[0]); i++) {                        v[i] = buf[i];                }                   for(int i=0; i<v.size(); i++) {                        cout << v[i] << endl;                }           (2)类对象            #include <iostream>            #include <stdio.h>            #include <vector>            using namespace std;            /* 定义一个学生结构体 */            class Student {            public:                    Student(const string name=" "):name(name) { }                    string name;            };            int main(void)            {                        /* 定义一个对象数组并初始化对象数组 */                    Student stu[10];                    char tmp[3] = {0};                    string n("name");                    for(int i=0; i<sizeof(stu)/sizeof(stu[0]); i++) {                            sprintf(tmp, "%d", i);                            stu[i] = Student(n+tmp);                    }                    /* 使用赋值的方式,对象数组元素赋值给vector容器 */                    std::vector<Student> v(10);                    for(int i=0; i<sizeof(stu)/sizeof(stu[0]); i++) {                            v[i] = stu[i];                    }                    for(int i=0; i<v.size(); i++) {                            cout << v[i].name << endl;                    }                    return 0;            }       (2)方法2        (1)基本类型            int buf[] = {1, 2, 4, 3, 6, 7, 8, 9, 0};                 std::vector<int> v(buf, buf+sizeof(buf)/sizeof(buf[0]));                for(int i=0; i<v.size(); i++) {                        cout << v[i] << endl;                }              或者            std::vector<int> v(10, 3.14);                for(int i=0; i<v.size(); i++) {                        cout << v[i] << endl;                }            创建一个10个元素空间的vector容器,初始值都是3.14。        (2)类对象            #include <iostream>            #include <stdio.h>            #include <vector>            using namespace std;            /* 定义一个学生结构体 */            class Student {            public:                    Student(const string name=" "):name(name) { }                    string name;            };             int main(void)            {                        /* 定义一个对象数组并初始化对象数组 */                    Student stu[10];                    char tmp[3] = {0};                    string n("name");                    for(int i=0; i<sizeof(stu)/sizeof(stu[0]); i++) {                            sprintf(tmp, "%d", i);                             stu[i] = Student(n+tmp);                }                /* 利用对象数组初始化vector容器 */                std::vector<Student> v(stu, stu+sizeof(stu)/sizeof(stu[0]));                for(int i=0; i<v.size(); i++) {                        cout << v[i].name << endl;                }                return 0;        }        从例子中不难看出,构造函数需要两个迭代器参数用于指定间隔,        这里使用的是指针,前面讲过,指针其实就是一种特殊的迭代器,        这两个参数指定的是半开间隔,所谓半开间隔(半开区间)就是        包含前一个范围界限,但是不包含后一个范围界限。 (4)resize()函数和reserve()函数    (1)resize()函数        利用参数指定新的元素个数,用于修改容器的大小(不是容量),        如果新的大小比原来小,尾部元素就被删除。如果比原来大小        要大,就在容器尾部添加新元素空间,如果数据是基本类型,        新加的元素的默认值为0,如果对象的话,需要看实际情况。                std::vector<int> v(10);                cout << v.size() << endl;                v.resize(6);                cout << v.size() << endl;    (2)reserves()函数        利用其参数用于指定vector容器的最小容量,如果设置的容量        值小于当前容量,容量就保持不变。                        std::vector<int> v(10);                cout << v.capacity() << endl;                v.reserve(16);                cout << v.capacity() << endl;(5)在容器中存放指针    在前面的内容提到过,可以在容器中存放副本和指针,存放副本方式的    效率比较低,修改了副本后,原对象的值不会变化,修改了原对象的值    后,容器中存放的副本的值又不会发生变化。    存放指针可以提高效率,但是要注意,如果容器存放的指针指向的空间    释放了的话会造成野指针,因此使用时需要格外小心。    (1)例子:存放副本的        #include <iostream>        #include <stdio.h>        #include <vector>        using namespace std;        /* 定义一个学生结构体 */        class Student {        public:                Student(const string name=" "):name(name) { }                string name;        };        int main(void)        {                    Student stu[5];                std::vector<Student> v(5);                for(int i=0; i<5; i++) {                        stu[i] = Student("name");                        v[i] = stu[i];                }                for(int i=0; i<5; i++) cout << v[i].name <<endl;                cout<<endl;                stu[4].name = "zhangsan";                for(int i=0; i<5; i++) cout << v[i].name <<endl;                return 0;        }               运行结果:        name        name        name        name        name        name        name        name        name        name        例子分析:        由于vector容器中存放的是副本,因此对原内容修改后,容器        中的内容并不会发生改变。    (2)例子:存放指针        还是继续上面的例子,只是将容器中存放的数据改为指针。        将主函数的内容修改为如下:            Student *stu[5];            std::vector<Student *> v(5);            for(int i=0; i<5; i++) {                    stu[i] = new Student("name");                    v[i] = stu[i];            }            for(int i=0; i<5; i++) cout << v[i]->name <<endl;            cout<<endl;            stu[4]->name = "zhangsan";            for(int i=0; i<5; i++) cout << v[i]->name <<endl;        运行结果:        name        name        name        name        name        name        name        name        name        zhangsan        例子分析:        由于容器中存放的时指针,因此利用指针修改的是原对象的内容。   (4)访问(读写)vector容器中元素    (1)使用[]访问    在之前访问vector容器的例子中,我们一直使用的都是[]的方式进行    容器元素的当问。(2)迭代器访问   (1)正向迭代器    涉及的成员函数。    begin():返回迭代器,它指向第一个元素    end():返回迭代器,它指向最后一个元素后面的元素    对迭代器可以++/--,+b/-n运算,使用*解引用后,就可以可以访问迭代器指向的元素内容。    例子:    #include <iostream>    #include <stdio.h>    #include <vector>    using namespace std;    class Student {     public:                        Student(const string name=" "):name(name) { }             string name;    };                      void show_vector(std::vector<Student *>::iterator first, std::vector<Student *>::iterator last) {            for(; first!=last; first++)                     cout << (*first)->name <<endl;    }    int main(void)    {            Student *stu[5];            std::vector<Student *> v(5);            for(int i=0; i<5; i++) {                    stu[i] = new Student("name");                    v[i] = stu[i];            }            show_vector(v.begin(), v.end());            (*(v.begin()+2))->name = "wangwu";            (*(v.end()-1))->name = "lisi";            cout<<endl;            show_vector(v.begin(), v.end());            return 0;    }    运行结果:    name    name    name    name    name    name    name    wangwu    name    lisi    例子分析:    (迭代器其实是一种抽象的指针,可以这么理解,所有需要解引用才可以访问)    begin和end函数返回的是vcteor容器提供的随机迭代器,访问器所指    向的元素时,需要使用*进行解引用,由于容器中存放的是对象的地址,    因此访问对象的name时,需要使用->访问符。    (2)反向迭代器    vector提供的反向迭代器为std::vector<Student *>::reverse_iterator    与之对应的是rbegin()和rend()函数。使用反向迭代器时,不能使用    用begin()和end()函数,反之也是如此。    请自己写代码验证反向迭代器。(3)直接访问元素内容         涉及的成员函数:    (1)front():引用第一个元素    (2)back():引用最后一个元素    (3)at():引用指定索引的元素    可以直接访问空间,不需要*解引用。    #include <iostream>    #include <stdio.h>    #include <vector>    using namespace std;    class Student {    public:            Student(const string name=" "):name(name) { }            string name;    };    void show_vector(std::vector<Student *> &v) {            for(int i=0; i<v.size(); i++)                    cout << v.at(i)->name <<endl;    }    int main(void)    {            Student *stu[5];            std::vector<Student *> v(5);            for(int i=0; i<5; i++) {                    stu[i] = new Student("name");                    v[i] = stu[i];            }            show_vector(v);            v.front()->name = "wangwu";            v.back()->name = "joinash";            v.at(2)->name = "washion";            cout<<endl;            show_vector(v);            return 0;    }    运行结果:    name    name    name    name    name    wangwu    name    washion    name    joinash(3)vector访问方式总结    从前面的了解中,我们不难发现,vector的访问方式非常灵活,使用    []/迭代器/直接访问等方式都可以。(5)使用vector提供的成员函数来添加/删除vector中的元素(1)涉及的成员函数    (1)push_back():把参数(对象)添加到vector的最后位置    (2)pop_back():删除vector尾部的元素    (3)erase():删除任意位置的一个或者多个元素    (4)clear():删除所有的元素    (5)insert():在vector中的指定位置插入一个或多个对象。        该函数提供了两个重载版本和一个函数模板。        iterator insert ( iterator position, const T& x );        void insert ( iterator position, size_type n, const T& x );        template <class InputIterator> void insert ( iterator position, InputIterator first, InputIterator last );    (6)empty():判断vector是否为空,避免对空vector进行操作。(2)例子    #include <iostream>    #include <stdio.h>    #include <vector>    #include <algorithm>    void show_vector(std::vector<int>::iterator first, std::vector<int>::iterator end) {            for( ;first!=end; first++) cout << *first << " ";            cout << endl;        cout << endl;    }    int main(void)    {            int buf[] = {1, 2, 3, 5, 4, 7, 8, 9, 0, 23, 54, 32};            std::vector<int> v;            cout << "将buf中下表[1-10)元素插入v,1-10是半开区间,含1不含10 "<<endl;            v.insert(v.end(), buf+1, buf+10);            show_vector(v.begin(), v.end());            cout << "添加一个元素7到vector的末尾"<<endl;            v.push_back(7);            show_vector(v.begin(), v.end());            cout << "删除最后一个元素" << endl;            v.pop_back();            show_vector(v.begin(), v.end());            cout << "删除第2个到第5个半开区间的元素" << endl;            v.erase(v.begin()+1, v.begin()+4);            show_vector(v.begin(), v.end());            cout << "在第4个元素未知插入元素111"<<endl;            v.insert(v.begin()+3, 111);            show_vector(v.begin(), v.end());            return 0;    }    运行结果:    将buf中下表[1-10)元素插入v,1-10是半开区间,含1不含10     2 3 5 4 7 8 9 0 23     添加一个元素7到vector的末尾    2 3 5 4 7 8 9 0 23 7     删除最后一个元素    2 3 5 4 7 8 9 0 23     删除第2个到第5个半开区间的元素    2 7 8 9 0 23     在第4个元素未知插入元素111    2 7 8 111 9 0 23 (6)迭代器的好处(1)数组传参操作    (1)传统方式        例子:求平均值        #include <iostream>        float average(float *buf, int count) {                int sum = 0;                for(int i=0; i<count; i++) {                        sum += buf[i];                }                return sum/count;        }        int main(void)        {            float ret = 0;                float buf[] = {1, 2, 3, 5, 4, 7, 8, 9, 0, 23, 54, 32};                average(buf, sizeof(buf)/sizeof(buf[0]));                return 0;        }         例子分析:        上面显示了数组的经典传参方式,对于数组来说,必须传递两个参数,        第一个是地址,第二是元素个数。        但是对于字符串传参来说就不需要传递元素个数,字符串实际上是一        个特殊形式的字符数组,由于字符串使用\0作为结尾标志,省去了需        要传递元素个数的可能。        函数模板实现求平均值:        有的时候可能会对很多类型都要做求平均的运算,因此可以将求平均        运算定义为一个模板,这样的话就可以根据情况的不同,生成各种不        同求平均值的函数实例。        #include <iostream>        template <class T1> float average(T1 *buf, int count) {                T1 sum = 0;                for(int i=0; i<count; i++) {                        sum += buf[i];                }                   return sum/count;        }               int main(void)        {                float ret = 0;                float buf[] = {1, 2, 3, 5, 4, 7, 8, 9, 0, 23, 54, 32};                ret = average(buf, sizeof(buf)/sizeof(buf[0]));                cout <<"平均值="<< ret << endl;                 return 0;        }        (2)传递首尾指针方式(迭代器)        #include <iostream>        float average(float *first, float *last) {                int sum = 0;                int count = last - first;                for( ; first!=last; first++) {                        sum += *first;                }                   return sum/count;        }        int main(void)        {                float ret = 0;                float buf[] = {1, 2, 3, 5, 4, 7, 8, 9, 0, 23, 54, 32};                ret = average(buf, buf+sizeof(buf)/sizeof(buf[0]));                cout <<"平均值="<< ret << endl;                return 0;        }         函数模板实现求平均值:            前面提到过,指针本身就是一种特殊的迭代器,对于数组的传参,        可以使用传递首尾指针(半开区间)的方式。        #include <iostream>        template <class iter> float average(iter first, iter last) {                int sum = 0;                int count = last - first;                for( ; first!=last; first++) {                        sum += *first;                }                return sum/count;        }        int main(void)        {                float ret = 0;                float buf[] = {1, 2, 3, 5, 4, 7, 8, 9, 0, 23, 54, 32};                ret = average(buf, buf+sizeof(buf)/sizeof(buf[0]));                cout <<"平均值="<< ret << endl;                return 0;        }        例子分析:        由于没有传递元素个数,所以需要使用首尾指针相减得到元素        个数。(2)vector传参操作    (1)普通方式        #include <iostream>        #include <vector>        float average(std::vector<int> &v) {                int sum = 0;                int count = v.size();                for(int i; i<v.size(); i++) {                        sum += v[i];                }                return sum/count;        }        int main(void)        {                float ret = 0;                float buf[] = {1, 2, 3, 5, 4, 7, 8, 9, 0, 23, 54, 32};                std::vector<int> v(buf, buf+sizeof(buf)/sizeof(buf[0]));                ret = average(v);                cout <<"平均值="<< ret << endl;                return 0;        }        例子分析:        将vector对象直接以引用方式进行传参操作。       函数模板求平均值:        #include <iostream>        #include <vector>        template<class T> float average(T &v) {                int sum = 0;                int count = v.size();                for(int i; i<v.size(); i++) {                        sum += v[i];                }                return sum/count;        }        int main(void)        {                float ret = 0;                float buf[] = {1, 2, 3, 5, 4, 7, 8, 9, 0, 23, 54, 32};                std::vector<int> v(buf, buf+sizeof(buf)/sizeof(buf[0]));                ret = average(v);                cout <<"平均值="<< ret << endl;                return 0;        }    (2)迭代器          #include <iostream>        #include <vector>           float average(std::vector<int>::iterator first, std::vector<int>::iterator last) {                int sum = 0;                int count = last - first;                for( ; first!=last; first++) {                        sum += *first;                }                return sum/count;        }        int main(void)        {                float ret = 0;                float buf[] = {1, 2, 3, 5, 4, 7, 8, 9, 0, 23, 54, 32};                std::vector<int> v(buf, buf+sizeof(buf)/sizeof(buf[0]));                ret = average(v.begin(), v.end());                cout <<"平均值="<< ret << endl;                return 0;        }        例子分析:        从这个例子你会发现,这个vector迭代器的传参与传递数组        首尾指针的方式时一样的,从这一点你也可以看出,指针其        实就是迭代器的原始实现方式。       函数模板求平均值:        template<class iter> float average(iter first, iter last) {                int sum = 0;                int count = last - first;                for( ; first!=last; first++) {                        sum += *first;                }                   return sum/count;        }        int main(void)        {                float ret = 0;                float buf[] = {1, 2, 3, 5, 4, 7, 8, 9, 0, 23, 54, 32};                std::vector<int> v(buf, buf+sizeof(buf)/sizeof(buf[0]));                ret = average(v.begin(), v.end());                cout <<"平均值="<< ret << endl;                return 0;        }        例子分析:        这个与传递数组首尾指针的方式是完全一样的,只是这里使        用的不是普通的指针,使用的是由容器自己提供的迭代器。(3)求用输入输出流迭代器获取到的数据的平均值   (1)输入流迭代器    前面的例子中都是将数据先存入数组或者vector容器。    当希望对输入数据求平均值时,传统的做法是先将输入数据存放到数组或    者vector后,再调用average函数求平均值。    但是如果使用输入输出流迭代器的话,可以省去将数据暂存到数组或者    vector环节。    例子:    #include <iostream>    #include <stdio.h>    #include<iterator>    template<class iter> float average(iter first, iter last) {            int sum = 0;            int count = 0;            for( ; first!=last; first++, count++) {                    sum += *first;            }               return sum/count;    }    int main(void)    {            float ret = 0;            cout << "请输入一组需要求平均值的数,之用空格分隔" << endl;                 ret = average(istream_iterator<float>(cin), istream_iterator<float>());            cout <<"平均值="<< ret << endl;             return 0;    }       例子分析:    例子中,直接使用输入迭代器从输入流cin中获取数据,但是count中不    能直接通过迭代器相减的方式得到,因为输入的个数不能立即确定,所    以只能使用count++的方式计算count。    改变输入迭代器的输入流:    对于输入迭代器来说,给定不同的输入流可以对不同来源的数据进行操作,    比如下面的这个例子:    #include <iostream>    #include<iterator>    #include<sstream>    template<class iter> float average(iter first, iter last) {            int sum = 0, count = 0;            for( ; first!=last; first++, count++) {                    sum += *first;            }            return sum/count;    }    int main(void)    {            float ret = 0;            string str = "1 34 45 67 78 44 33";            istringstream iss(str);            ret =average(std::istream_iterator<float>(iss), std::istream_iterator<float>());            cout <<"平均值="<< ret << endl;            return 0;    }    例子分析:    输入迭代器中,将字符串输入流作为了输入迭代器的参数,因此,输    入的数据来自于字符串。    (2)输出流迭代器    如果希望在averae函数中将所有的数据显示出来,除了可以使用循环    打印外,还可以使用输出流迭代器实现。    例子:    #include <iostream>    #include <algorithm>    #include<iterator>    void show_vector(int *first, int *last) {            std::copy(first, last, ostream_iterator<int>(cout, " "));            cout << endl;    }    int main(void)    {            int buf[] = {4, 2, 5, 1, 3, 7, 8, 45, 32, 12};            show_vector(buf, buf+sizeof(buf)/sizeof(buf[0]));            return 0;    }    例子分析:    直接将指针当作迭代器使用,    std::copy(first, last, ostream_iterator<int>(cout, " "));    调用了算法copy函数,该函数的表示,将迭代器first和last之间的    数据复制给输出迭代器,最后输出迭代器利用cout将数据输出显示,    数据之间使用" "间隔。    如果输出流并不是cout,而是一个普通文件流,那么数据将会被输入    到文件中。(4)定义一个对数组/vector/输入迭代器都适用的average函数模板    通过起那面的例子,不难发现,通过迭代器的使用,完全可以定义一个    针对数组/vector/输入迭代器都适用的average函数模板,由此可以看    出迭代器的好处。    #include <iostream>    #include <algorithm>    #include <vector>    #include<iterator>    template<class iter> float average(iter first, iter last) {            int sum = 0, count = 0;            for( ; first!=last; first++, count++) {                    sum += *first;            }               return sum/count;    }       int main(void)    {            float ret = 0;            float buf[] = {4, 2, 5, 1, 3, 7, 8, 45, 32, 12};            std::vector<float> v(buf, buf+sizeof(buf)/sizeof(buf[0]));            cout<<"1.计算数组中数据的平均值" <<endl;            cout<<"2.计算vector容器中数据的平均值" <<endl;            cout<<"3.计算从键盘输入数据的平均值" <<endl;            int select = 0;            cin >> select;            if(1 == select) {                    ret = average(buf,  buf+sizeof(buf)/sizeof(buf[0]));            } else if(2 == select) {                    ret = average(v.begin(),  v.end());            } else if(3 == select) {                    cout << "请输入一组需要求平均值的数,使用空格分隔" << endl;                    ret =average(std::istream_iterator<float>(cin), std::istream_iterator<float>());            }            cout <<"平均值="<< ret << endl;            return 0;    }    例子分析:    有三种不同的选择,分别对数组/vector容器/输入的数据进行求平均    值,但是这三种情况下使用的是同一个模板,这个模板会根据不同的    情况生成不同的函数实例。4.list容器(1)list的特点前面讲的vector是非常常用的容器,使用频繁都非常高。vector的优势:    vectoer的优点直接导致了它的缺点,因为vector本身就是数组,数组    是顺序(连续)存储的,因此可以很好的支持随机访问,支持随机访    问是顺序存储的优势。vector的缺点:    在序列中频繁插入和删除的效率非常的低,因为会涉及大片内存数据被    移动,这也是顺序存储的缺点。list的优点    list的优点就是克服了vector的缺点,链表是链式存储的,链式存储的    优点在于进行频繁插入和删除的效率非常的高,因为链式存储时,链表    的节点空间并不连续,不会涉及大片内存数据移动。list的缺点:    同样,list的有优点直接导致了它的缺点,它不支持随机访问,因为所    有的节点空间并不是连续的,所以不能跳跃性的随机访问,只能是一个    一个节点的遍历。(2)创建一个list     (1)创建空链表    std::list<int> data;(2)创建指定元素个数的链表    std::list<int> data(10);    链表中内容全部会被初始化为0。(3)创建一个给定初始值的链表    (1)所有元素初始值相同的情况        std::list<int> data(10, 9527);        10个节点,所有值会被初始化为9527。    (2)所有元素初始值不同的情况             int buf[] = {1, 2, 4, 56, 23, 45, 3, 55};            std::list<int> l(buf, buf+sizeof(buf)/sizeof(buf[0]));(3)访问list容器的元素(1)如何访问list    (1)方法1:使用迭代器        list支持双向迭代器,但双向迭代器不支持随机访问。        list容器提供正向和逆向两种迭代器,正向迭代器需要使用        begin()函数和end()成员函数,逆向迭代器需要使用rbegin()和        rend()成员函数,这一点与vector同。        由于list不支持随机访问,因此list没有重写[]运算符,就        算是重写了[]运行算符,实际上也是通过迭代器挨个遍历实        现的,并不是真正意义上的随机访问。        使用迭代器访问内容时,需要使用*解引用才能访问迭代器指向        的内容。    (2)front()和back()函数        front():直接返回第一个元素内容。        back()函数直接返回最后一个元素的内容        以上这两个函数与vector提供的front()和back()函数类似,        但是由于list不支持随机访问,因此没有at()函数。 (2)例子    list也有begin()和end()两个成员函数,用于返回访问list的迭代器。    这个迭代器是由list容器提供的,有了迭代器就可以遍历访问list容    器。    例子:    #include <iostream>    #include<iterator>    #include<list>    template<class iter> void show_vector(iter first, iter last) {            for( ;first!=last; first++) {                    cout << *first << " ";            }            cout << endl;    }    int main(void)    {            int buf[] = {1, 2, 4, 56, 23, 45, 3, 55};            std::list<int> l1;            std::list<int> l2(10);            std::list<int> l3(buf, buf+sizeof(buf)/sizeof(buf[0]));            cout << "显示l1中的内容" << endl;            show_vector(l1.begin(), l1.end());            cout << "\n显示l2中的内容" << endl;            show_vector(l2.begin(), l2.end());            cout << "\n显示l3中的内容" << endl;            show_vector(l3.begin(), l3.end());            return 0;    }    运行结果:    显示l1中的内容    显示l2中的内容    0 0 0 0 0 0 0 0 0 0     显示l3中的内容    1 2 4 56 23 45 3 55     例子分析:    例子中分别定义了三个list,然后显示其内容,第一个list是空的    ,因此没有内容被显示。    第二个list元素个数是10个,但是内容全部被默认初始化为了0。    第三个list在被定义时,被直接初始化了一些值,因此这些值可以    被打印出来。(4)使用list容器提供的成员函数实现元素的插入删除等操作(1)涉及函数    (1)push_front()函数:在list头部插入新元素    (2)push_back()函数:在list尾部插入新元素    (3)pop_front()函数:删除list头部元素    (4)pop_back()函数:删除list尾部元素    (5)insert()函数:在list中指定的位置插入新元素,有三个常用的        重载版本。        (1)interator insert(iterator position, const T& x);            在指定位置插入x副本,返回指向该位置的迭代器。        (2)void insert(iterator position, size_type n, const T& x);            在指定位置插入n个x的副本。        (3)void insert(iterator position, InputIterator first, InputIterator last);            在指定位置插入第二个参数和第三个参数指定的半开间            隔中的元素,至于InputIterator类型根据情况而定,            有可能是普通指针也有可能是迭代器。    (6)ereas()函数:删除指定元素,返回的迭代器指向删除元素后面的元素,            该函数有两个重载版本。            (1)iterator erase ( iterator position );                删除position位置的元素。            (2)iterator erase ( iterator first, iterator last );                        删除first与last指定的半开区间之间的元素。    (7)clear()函数:删除所有元素。    (8)empty()函数:判断list是否为空。    (9)slpice()函数:拆分list的函数,该函数提供两个重载版本和一个模板。               (1)void splice ( iterator position, list<T,Allocator>& x );            将list中内容移到调用splice函数的容器的position处。        (2)void splice ( iterator position, list<T,Allocator>& x, iterator i );            将list中i位置的内容移到调用splice函数的容器的position处。                      (3)void splice ( iterator position, list<T,Allocator>& x, iterator first, iterator last );            将list中[first,last)之间的内容移到调用splice函数的容器的position处。    (10)resize():设置list的大小    (11)merge():有两个重载版本,其中一个是模板。        void merge ( list<T,Allocator>& x );        功能:将另外一个list合并到自己中来,合并后进行默认排序。        template <class Compare> void merge ( list<T,Allocator>& x, Compare comp );        功能:同上,但是可以自己提供比较函数。        该函数的例子,在后面讲全局merge时意一并举出。           (2)函数使用举例    (1)push_front/push_back/pop_front/popback函数使用举例        #include <iostream>        #include <algorithm>        #include<iterator>        #include<list>        template<class iter> void show_vector(iter first, iter last) {                for( ;first!=last; first++) {                        cout << *first << " ";                }                cout << endl;        }        int main(void)        {                std::list<int> l;                cout << "向空l中的头尾插入4个int元素" << endl;                l.push_front(1);                l.push_back(4);                l.push_front(5);                l.push_back(3);                show_vector(l.begin(), l.end());                cout << "\n从l中的头和尾删除2个int元素" << endl;                l.pop_front();                l.pop_back();                show_vector(l.begin(), l.end());                return 0;        }    (2)insert/ereas/clear/empty函数使用举例        #include <iostream>        #include <algorithm>        #include<iterator>        #include<list>        template<class iter> void show_vector(iter first, iter last) {                for( ;first!=last; first++) {                        cout << *first << " ";                }                cout << endl;        }        int main(void)        {                int buf[] = {1, 2, 4, 56, 23, 45, 3, 55};                std::list<int> l;            if(l.empty()) cout<<"l为空"<<endl;                cout << "\n向l的begin()指向的位置插入-1" << endl;                l.insert(l.begin(), -1);                show_vector(l.begin(), l.end());                cout << "\n向l的end()指向的位置插入e个-2\" << endl;                l.insert(l.end(), 3, -2);                show_vector(l.begin(), l.end());                cout << "\n向l的begin()指向的位置后面一个位置插入[buf,buf+3)之间的元素" << endl;                //l.insert(l.begin()+2, buf, buf+5);//list不支持随机访问,因此迭代起+n是错误的                l.insert(l.begin()++, buf, buf+5);//支持++ --                show_vector(l.begin(), l.end());                cout << "\n清空l" << endl;                l.clear();                show_vector(l.begin(), l.end());                return 0;        }        运行结果:        l为空        向l的begin()指向的位置插入-1        -1         向l的end()指向的位置插入e个-2        -1 -2 -2 -2         向l的begin()指向的位置后面一个位置插入[buf,buf+3)之间的元素        1 2 4 56 23 -1 -2 -2 -2         清空l    (3)splice函数使用举例        #include <iostream>        #include <algorithm>        #include<iterator>        #include<list>        template<class iter> void show_vector(iter first, iter last) {                for( ;first!=last; first++) {                        cout << *first << " ";                }                cout << endl;        }        int main(void)        {                int buf[] = {1, 2, 4, 56, 23, 45, 3, 55};                std::list<int> l1(buf, buf+sizeof(buf)/sizeof(buf[0]));                std::list<int> l2;                cout << "将l1中的所有内容移到l2中begin()开始的位置,移除后l1就为空" << endl;                l2.splice(l2.begin(), l1);                cout << "l1中的内容" <<endl;                show_vector(l1.begin(), l1.end());                cout << "l2中的内容" <<endl;                show_vector(l2.begin(), l2.end());                cout << "\n将l2中++l2.begin()位置的内容移到l1中begin()开始的位置" << endl;                l1.splice(l1.begin(), l2, ++l2.begin());                cout << "l1中的内容" <<endl;                show_vector(l1.begin(), l1.end());                cout << "l2中的内容" <<endl;                show_vector(l2.begin(), l2.end());                cout << "\n将l2中[++l2.begin(), --l2.end())位置的内容移到l1中++begin()开始的位置" << endl;                l1.splice(++l1.begin(), l2, ++l2.begin(), --l2.end());                cout << "l1中的内容" <<endl;                show_vector(l1.begin(), l1.end());                cout << "l2中的内容" <<endl;                show_vector(l2.begin(), l2.end());                return 0;        }        运行结果:        将l1中的所有内容移到l2中begin()开始的位置,移除后l1就为空        l1中的内容        l2中的内容        1 2 4 56 23 45 3 55         将l2中++l2.begin()位置的内容移到l1中begin()开始的位置        l1中的内容        2         l2中的内容        1 4 56 23 45 3 55         将l2中[++l2.begin(), --l2.end())位置的内容移到l1中++begin()开始的位置        l1中的内容        2 4 56 23 45 3         l2中的内容        1 55 (5)list实现管理学生信息 #include <iostream>#include<iterator>#include<list>#include<stdlib.h>#include<stdio.h>#include<time.h>using namespace std;class Student { public:        Student(const string name=" ", int num=0):name(name),num(num) { }         string getname() const { return name; }        int getnum() const { return num; }private:        string name;        int num;}; template<class T> class List {public:        typedef std::list<T *> Content;        typedef typename std::list<T *>::iterator Iter;        List() { }        List(Iter first, Iter last):load(first, last) { }        void add_list(T* &stu) {load.push_front(stu);}        void add_tail(T* &stu) {load.push_back(stu);}        void ereas_head() {load.pop_front();}        void ereas_tail() {load.pop_back();}        void display() {                for(Iter iter=load.begin(); iter!=load.end(); iter++) {                        cout << (*(iter))->getname() << " " << (*(iter))->getnum() <<endl;                }        }        ~List() {                while(load.begin() != load.end()) {                        delete(load.front());                        load.pop_front();                }        }private:        Content load;};void init_stu_list(List<Student> &list, int count) {        string name = "name", newname = "";        char buf[10] = {0};        int num = 0;        srand(time(NULL));        for(int i=0; i<count; i++) {                num = rand()%100;                int tmp = rand()%100;                sprintf(buf, "%d", tmp);                newname = name+buf;                Student *stup = new Student(newname, num);                list.add_tail(stup);        }}int main(void){        List<Student> list;        init_stu_list(list, 20);        while(1) {                cout<<"1. add stu to list" <<endl;                cout<<"2. delete stu form list" <<endl;                cout<<"3. find stu by num" <<endl;                cout<<"4. alter stu to list" <<endl;                cout<<"5. display list" <<endl;                cout<<"6. sort list" <<endl;                cout<<"7. exit" <<endl;                int select = 0;                cin >> select;                switch(select) {                        case 5: list.display(); break;                        default: cout << "未实现" << endl;                }        }        return 0;}例子分析:例子中需要自己利用迭代器实现排序/查找等算法函数,但是实际上c++的STL模板库提供了现成的全局算法函数。5. 关联容器(1)关联容器的特点(1)容器需要存放对象和key值,key值与对象之间是一种映射关系。(2)每个对象被存入到关联容器中时,会对key进行排序,进过比较后找到合适的    位置后存放。因此key的数据类型需要提供排序方法,可以通过提供orerator<()    或者Compare这两个函数进行比较。(3)map只支持双向迭代器,因此不支持随机访问,虽然map支持[key]的方式访问对象,    但是这并不是随机访问。(2)关联容器分类(1)map类:不允许key重复(2)multimap类:map的特例,允许key重复(3)set类:对象本身就是key值,不允许重复(4)multiset类:set的特例,允许重复(3)map的模板前面的vector和list模板原本需要两个模板参数,但是实际上我们基本都只指定第一个模板参数。map类的模板参数比较多,总共有四个模板参数,map的类模板定义如下:template < class Key, class T, class Compare = less<Key>,       class Allocator = allocator<pair<const Key,T> > > class map;(1)模板参数1:key值的类型(2)模板参数2:key对应数据的类型(3)模板参数3:用于排序时进行比较的函数对象类型(4)模板参数4:用于在map中分配存储空间的函数类型一般情况下,我们只需要指定前两个模板参数即可。(4)定义一个map(1)定义一个空的map    std::map<std::string, Student> stumap;    调用map的默认构造函数,定义一个空的map对象,第一个模板类型参数    string表示key值的类型为string,第二个Student表示需要存储的对象    是Student类型。    但是实际上key和存放的对象的类型可以使任何类型。(2)定义一个map,利用另一个map的袁元素进行初始化    std::map<std::string, Student> stumap<iter1, iter2>;     使用另一个map的[iter1, iter2)之间的元素初始化map。(4)如何构建键值对将key和对应对象构建成为键值对的方法有三个:(1)std::make_pair("123", stu)(2)std::map<string, Student> :: value_type("111",stu)(3)std::pair<string, Student>("222",stu)这三个函数在调用insert()插入新的键值对时很重要,比如:enumMap.insert(map<int,CString> :: value_type("111", stu))enumMap.insert(pair<int,string>("222", stu));   (5)访问map(1)使用[]    (1)作为右值:Student stu = stumap["111"];        如果"111"对应的对象比更不存在,便会使用Student的默认构造函数创        建一个Student对象。实际上只有确保"111"对应的对象存在才有意义。    (2)作为左值:Stumap["222"] = stu;            作为左值时,如果"222"对应的键值对不存在,就创建一个新的键值对,        然后将内容赋值为stu,利用这样的方式可以实现插入新键值对的操作,        当然还可以使用insert()成员函数实现插入操作。              不管是作为左值还是右值,提前确定键值对是否存在非常关键,所以我        们可以使用find成员函数先查找该key值对应的对象是否存在,存在就返        回指向该位置的迭代器,然后使用该迭代器进行操作,否者就不操作。(2)迭代器遍历    (1)使用的是双向迭代器,不支持随机访问    (2)正向迭代器需要用到begin()和end()函数    (3)逆向迭代器rbegin()函数和rend()函数。    (4)通过iter->second成员和iter->first成员就可以获取数据和键值key,        second成员中存放的是数据,first存放的是键值。        这里只能使用->,不能使用*和.操作。(3)例子    #include <iostream>    #include <algorithm>    #include<iterator>    #include<sstream>    #include<stdlib.h>    #include<stdio.h>    #include <map>    using namespace std;    class Student {    public:            Student(const string name=" "):name(name) { }            string getname() const { return name; }    private:            string name;    };    /* 使用迭代器遍历map */    template <class Iter> void show_map(Iter first, Iter last) {            for( ;first!=last; first++) {                        /* 使用first访问键值,使用second访问对象,注意,通过迭代器访问到的                    只是键值对,必须使用->访问first和second才能访问到具体的键值和对应数据,                    由于存储的对象是地址,访问Student的name时,必须再次使用-> */                 cout << first->first<<"        "<< ((first)->second)->getname()<<endl;            }    }    int main(void)    {               /* 定义一个空的map */            std::map<string, Student*> map1;            cout<< "使用[]做为左值插入新元素" <<endl;            map1["111"] = new Student("zhangsan");            map1["222"] = new Student("wangwu");            map1["333"] = new Student("lisi");        map1["333"] = new Student("wwwwww");            map1["444"] = new Student("zhaosi");            /* 使用正向迭代起遍历 */            cout<< "显示map1中的元素" <<endl;            show_map(map1.begin(), map1.end());            /* 使用map1中的内容去初始化map2 */            cout<< "\n使用map1中[++map1.begin(), --map1.end())之间的元素初始化map2" <<endl;            std::map<string, Student*> map2(++map1.begin(), --map1.end());            /* 使用逆向迭代起遍历 */            cout<< "显示map2中的元素" <<endl;            show_map(map2.rbegin(), map2.rend());            return 0;    }    运行结果:    使用[]做为左值插入新元素    显示map1中的元素    111        zhangsan    222        wangwu    333        wwwwww    444        zhaosi    使用map1中[++map1.begin(), --map1.end())之间的元素初始化map2    显示map2中的元素    333        lisi    222        wangwu    例子分析:    map中不允许出现重复的key,如果出现,最后出现的key的对象将会覆盖    之前同名key对应的对象,比如例子中有两个"333"的key值,但是map只存放    最后一个"333"对用的对象。(6)使用map的成员函数实现插入和删除元素等操作   (1)涉及成员函数        (1)clear()        删除所有元素        (2)count()         返回指定元素出现的次数        (3)empty()         如果map为空则返回true        (4)erase()         删除一个元素        void erase ( iterator position );        size_type erase ( const key_type& x );            void erase ( iterator first, iterator last );        (5)find()          查找一个元素        iterator find ( const key_type& x );        const_iterator find ( const key_type& x ) const;        (6)insert()        插入元素        pair<iterator,bool> insert ( const value_type& x );            iterator insert ( iterator position, const value_type& x );        template <class InputIterator>            void insert ( InputIterator first, InputIterator last );        (7)max_size()      返回可以容纳的最大元素个数        (8)size()          返回map中元素的个数        (9)swap()           交换两个map(2)举例    例子1:(1)—(5)函数举例     #include <iostream>    #include <algorithm>    #include<iterator>    #include<sstream>    #include<stdlib.h>    #include<stdio.h>    #include <map>    using namespace std;    class Student {    public:            Student(const string name=" "):name(name) { }            string getname() const { return name; }    private:            string name;    };    /* 使用迭代器便利map */    template <class Iter> void show_map(Iter first, Iter last) {            for( ;first!=last; first++) {                    cout << first->first<<"        "<< ((first)->second)->getname()<<endl;             }    }    int main(void)    {            /* 定义一个空的map */            std::map<string, Student*> map1;            cout<< "使用[]做为左值插入新元素" <<endl;            map1["111"] = new Student("zhangs");            map1["222"] = new Student("wangwu");            map1["333"] = new Student("lisssi");            map1["444"] = new Student("dsfsfd");            map1["555"] = new Student("werrre");            map1["666"] = new Student("qwewss");            map1["777"] = new Student("sdgfgf");            map1["888"] = new Student("zzcvvv");            map1["999"] = new Student("cxbnhh");            map1["000"] = new Student("zqwerz");            if(map1.empty()) cout <<"\nmap1为空"<<endl;            else cout <<"\nmap1不为空"<<endl;            cout<<"\n333键值出现的次数:"<<map1.count("333")<<endl;            cout<< "使用erase删除指定元素" <<endl;            map1.erase(++map1.begin());            map1.erase("222");            map1.erase(++map1.begin(), --map1.end());            cout<< "\nmap1剩余的元素为" <<endl;            show_map(map1.begin(), map1.end());            cout<< "\n查在map1中查找“333”键值对" <<endl;            if(map1.find("333") != map1.end()) {                    cout <<"\n333对应的对象找到:" <<(map1["333"])->getname()<<endl;            }            return 0;    }           例子2:(6)—(9)函数举例    #include <iostream>    #include <algorithm>    #include<iterator>    #include<sstream>    #include<stdlib.h>    #include<stdio.h>    #include <map>    using namespace std;    class Student {    public:            Student(const string name=" "):name(name) { }            string getname() const { return name; }    private:            string name;    };    /* 使用迭代器便利map */    template <class Iter> void show_map(Iter first, Iter last) {            for( ;first!=last; first++) {                    cout << first->first<<"        "<< ((first)->second)->getname()<<endl;            }    }    int main(void)    {                   /* 定义一个空的map */            std::map<string, Student*> map1;            std::map<string, Student*> map2;            cout<< "使用[]做为左值插入新元素" <<endl;            map1["333"] = new Student("lisssi");            map1["111"] = new Student("zhangs");            map1["555"] = new Student("werrre");            map1["777"] = new Student("sdgfgf");            map1["222"] = new Student("wangwu");            map1["444"] = new Student("dsfsfd");            map1["666"] = new Student("qwewss");            map1["888"] = new Student("zzcvvv");            map1["999"] = new Student("cxbnhh");            map1["000"] = new Student("zqwerz");            cout <<"\n交换map1和map2"<<endl;            map1.swap(map2);            cout <<"显示交换后map1的内容"<<endl;            show_map(map1.begin(), map1.end());            cout <<"\n显示交换后map2的内容"<<endl;            show_map(map2.begin(), map2.end());            cout <<"\n使用insert函数向map1中插入新元素"<<endl;            map1.insert(make_pair("123", new Student("zzzzzzz")));            map1.insert(make_pair("234", new Student("bbbbbbb")));            map1.insert(pair<string, Student*>("345", new Student("bbbbbbb")));            map1.insert(map<string, Student*>::value_type("456", new Student("ccccccc")));            map1.insert(map<string, Student*>::value_type("567", new Student("ddddddd")));            show_map(map1.begin(), map1.end());            cout <<"\nmap1中可以容纳的最大元素个数:"<< map1.max_size()<<endl;            cout <<"\nmap1中实际元素个数:"<< map1.size()<<endl;            return 0;    }    运行结果:    使用[]做为左值插入新元素    交换map1和map2    显示交换后map1的内容    显示交换后map2的内容    000        zqwerz    111        zhangs    222        wangwu    333        lisssi    444        dsfsfd    555        werrre    666        qwewss    777        sdgfgf    888        zzcvvv    999        cxbnhh    使用insert函数向map1中插入新元素    123        zzzzzzz    234        bbbbbbb    345        bbbbbbb    456        ccccccc    567        ddddddd    map1中可以容纳的最大元素个数:178956970    map1中实际元素个数:5    例子分析:    从打印结果可以明显的看出,插入map时,会对key值进行自动排序,    主动排序使用的时map提供的默认比较函数。       

(7)multimap
与map一样,操作的成员函数与map都一样,只是multimap允许出现键值对重复。
但是与map也有些其它不同。
(1)multimap不能使用[]
(2)find函数只返回指向重复key的第一个键值对的迭代器

例子:    #include <iostream>    #include <algorithm>    #include<iterator>    #include<sstream>    #include<stdlib.h>    #include<stdio.h>    #include <map>    using namespace std;    class Student {    public:            Student(const string name=" "):name(name) { }            string getname() const { return name; }    private:            string name;    };    /* 使用迭代器便利map */    template <class Iter> void show_map(Iter first, Iter last) {            for( ;first!=last; first++) {                    cout << first->first<<"        "<< ((first)->second)->getname()<<endl;            }    }    int main(void)    {            /* 定义一个空的map */            std::multimap<string, Student*> map1;            cout <<"\n使用insert函数向map1中插入新元素"<<endl;            map1.insert(make_pair("123", new Student("aaazzzzzzz")));            map1.insert(make_pair("123", new Student("zzzzzzz")));            map1.insert(make_pair("123", new Student("zzzzzzz")));            map1.insert(make_pair("234", new Student("bbbbbbb")));            map1.insert(pair<string, Student*>("345", new Student("bbbbbbb")));            map1.insert(map<string, Student*>::value_type("456", new Student("ccccccc")));            map1.insert(map<string, Student*>::value_type("567", new Student("ddddddd")));            show_map(map1.begin(), map1.end());            cout <<"\n查找123对应的对象:"<< map1.max_size()<<endl;            cout<<(map1.find("123")->second)->getname() << endl;            cout <<"\nmap1中可以容纳的最大元素个数:"<< map1.max_size()<<endl;            cout <<"\nmap1中实际元素个数:"<< map1.size()<<endl;            return 0;    }    运行结果:    使用insert函数向map1中插入新元素    123        aaazzzzzzz    123        zzzzzzz    123        zzzzzzz    234        bbbbbbb    345        bbbbbbb    456        ccccccc    567        ddddddd    查找123对应的对象:aaazzzzzzz    map1中可以容纳的最大元素个数:178956970    map1中实际元素个数:7

(8)函数类类型(函数对象)

(1)函数指针类型    讲函数类类型之前先回忆函数指针类型,函数指针类型的形式,    返回类型 (*)(形参类型列表);    比如:void *(*)(void *);    这就是我们之前讲的线程函数的函数类型,由于该类型比较复杂,因此    往往会使用typedef将其简化。    typedef void *(*ftype)(void *);    ftype fp =NULL;    通过ftype定义的fp就是我们希望得到的函数指针变量。(2)函数类类型与函数指针类型的区别    使用函数指针类型定义的变量只是用于存储函数地址,必须明白,函数指针变量    并不是函数本身,该变量只是指向了某个函数。    换句话说,不能使用函数指针类型定义一个函数,只能用它定义一个存放函数    地址的函数指针变量,至于该函数指针变量指向的函数,我们需要另外定义。    但是c++中扩展了函数类类型,有了这个类型后,就可以实例化一个函数    对象,也就是可以像定义一个类对象一样定义一个函数,使用非常的方便。(3)函数类类型如何定义和使用   (1)函数类类型     使用函数类类型,我们可以像实例化一个普通对象一样去实例化一个函数对象,    在实例化的时候,这个函数对象包含了函数的实现,可以将函数对象直接作为    参数进行传递时非常的方便。    如果没有函数对象,那么我们就必须使用函数指针实现,实际上如果没有函数    对象,c++并不会因此而少了什么,完全可以使用函数指针替代,不过在c++在STL    模板库中大量的使用到了函数对象。    有了函数类类型,我们就可以根据需求实例化任何我们需要的函数对象。    (2)函数类类型的实现原理    声明一个类型(class/struct),在类型中对()操作符进行重载,对()重载了    的类型就被认为是函数类类型。    使用该函数类类型就可以实例化函数对象,实例化对象时就实现了一个函数,    对象名字可以被认为就是函数的的名字。    可以使用结构体实现函数类类型,只是在使用结构体时,它成员默认是public的,    请自行测试使用结构体方式实现的函数类类型。(4)将函数作为参数进行传递时    (1)传统方式:传递函数地址    (2)新的方法:传递函数对象    例子:    #include <iostream>    #include <algorithm>    #include<iterator>    #include<sstream>    #include<stdlib.h>    #include<stdio.h>    #include <map>    using namespace std;    class Student {     public:            Student(const string name=" "):name(name) { }             string getname() const { return name; }    private:            string name;    }    /* 声明一个函数类类型,使用typedef为其定义一个别名 */    typedef class Funclass {    public:            void operator()(const Student &stu) {                    cout<<stu.getname() <<endl;            }    }Funtype;       /* 定义一个普通函数,使用函数对象进行传参 */    void display(Funtype func1, Funtype &func2, Funtype *func3, const Student &stu){            cout << "通过函数对象调用实例化的函数" <<endl;            func1(stu);            cout << "\n通过函数对象引用调实例化的用函数" <<endl;            func2(stu);            cout << \n"通过函数对象指针调用实例化的函数" <<endl;            (*func3)(stu);    }    int main(void)    {            Student stu("zhangsan");            Funtype func;//定义一个函数对象            /* 将函数对象作为参数进行传递            *参数1:传递对象            *参数2:传递对象引用            *参数3:传递对象地址 */            display(func, func, &func, stu);            return 0;    }    运行结果:    通过函数对象调用函数    zhangsan    通过函数对象引用调用函数    zhangsan    通过函数对象指针调用函数    zhangsan(2)函数类类型模板      继续上面的例子,将上面例子中的函数类类型改为函数类模板。    #include <algorithm>    #include<iterator>    #include<sstream>    #include<stdlib.h>    #include<stdio.h>    #include <map>    using namespace std;    class Student {     public:            Student(const string name=" "):name(name) { }             string getname() const { return name; }    private:            string name;    };     /* 声明一个函数类模板,使用typedef为其定义一个别名 */    template<class T> class Funclass {    public:            void operator()(const T &stu) {                    cout<<stu.getname() <<endl;            }    };    /* 定义一个普通函数,使用函数对象进行传参 */    void display(Funclass<Student> func1, Funclass<Student> &func2, Funclass<Student> *func3, const Student &stu){            cout << "通过函数对象调用实例化的函数" <<endl;            func1(stu);            cout << "\n通过函数对象引用调实例化的用函数" <<endl;            func2(stu);            cout << "\n通过函数对象指针调用实例化的函数" <<endl;            (*func3)(stu);    }    int main(void)    {            Student stu("zhangsan");            Funclass<Student> func;//定义一个函数对象            /* 将函数对象作为参数进行传递             *参数1:传递对象            *参数2:传递对象引用            *参数3:传递对象地址 */            display(func, func, &func, stu);            return 0;    }    运行结果:    通过函数对象调用实例化的函数    zhangsan    通过函数对象引用调实例化的用函数    zhangsan    通过函数对象指针调用实例化的函数    zhangsan    例子分析:    例子并没有做太大的改动,只是将函数类类型改成了函数类模板。(3)给map自定义比较函数  (1)给基本类型的key定义比较函数    前面讲到,向map中插入数据时,map会自动调用默认的比较函数进行排序    (默认的是升序排序)。    但是map中的排序实在插入的时候进行的,目的是为插入的元素找到一个合    适的位置,排序只在插入元素时进行,之后不能单独对map进行调用sort函    数进行排序。    但是map只对key为基本类型时,实现了默认的升序排序,如果希望对基本    类型实现降序排序,或者想对非基本类型的key实现自定义类型排序,需要    自己实现比较函数。    如果比较函数返回true,小的在前,大的在后,这里的大小概念只是逻辑    上的,不是数据的真实大小,我们完全可以定义数值大的为小,数值小的    为大。    通过map模板的第三个模板参数给map指定函数类类型或者函数类模板后,    map会用它实例化一个比较函数。    例子:对map中string类型key值进行降序排序    #include <iostream>    #include <algorithm>    #include<iterator>    #include<sstream>    #include<stdlib.h>    #include<stdio.h>    #include <map>    using namespace std;    class Student {     public:            Student(const string name=" "):name(name) { }             string getname() const { return name; }    private:            string name;    };         /* 使用迭代器便利map */    template <class Iter> void show_map(Iter first, Iter last) {            for( ;first!=last; first++) {                    cout << first->first<<"        "<< ((first)->second)->getname()<<endl;            }    }    /* 声明一个函数类模板,使用typedef为其定义一个别名 */    template<class T> class Funclass {    public:            bool operator()(const T &op1, const T &op2) {                    return op1 > op2;//按照从大到小比较            }    };    int main(void)    {                       std::map<string, Student *> map1;            /* 利用map的第三个模板参数指定用于比较函数的类模板,            * map会使用该函数类模板自动实例化一个比较函数,            * 如果该比较函数返回 */            std::map<string, Student *, Funclass<string> > map2;            map1["444"] = map2["444"] =  new Student("mnjnkkl");            map1["222"] = map2["222"] =  new Student("qqqqqqs");            map1["111"] = map2["111"] =  new Student("ddsfass");            map1["888"] = map2["888"] =  new Student("asdfdff");            map1["666"] = map2["666"] =  new Student("eqwewqe");            map1["555"] = map2["555"] =  new Student("sdfsfds");            cout<<"显示map1的内容"<<endl;            show_map(map1.begin(), map1.end());            cout<<"\n显示map2的内容"<<endl;            show_map(map2.begin(), map2.end());            return 0;    }    运行结果:    显示map1的内容    111        ddsfass    222        qqqqqqs    444        mnjnkkl    555        sdfsfds    666        eqwewqe    888        asdfdff    显示map2的内容    888        asdfdff    666        eqwewqe    555        sdfsfds    444        mnjnkkl    222        qqqqqqs    111        ddsfass    例子分析:    从运行的结果中很容易看出,如果不给map1指定比较函数类类型或者模板    的话,默认会提供升序排序的比较函数。    在给map2提供了降序排序的比较函数模板后,map2便进行降序排序,从打    印结果中很容易看出这一点。   (2)给map类类型的key自定义比较函数    如果map中键值对的key是类类型的话,必须给map指定自定义的比较函数类    类型或者模板,否则将无法通过编译。    例子:    #include <iostream>    #include <algorithm>    #include<iterator>    #include<sstream>    #include<stdlib.h>    #include<stdio.h>    #include <map>    using namespace std;    class Stukey{    public:            Stukey(int key=1):key(key) {}            int key;    };    class Student {    public:            Student(const string name=" "):name(name) { }            string getname() const { return name; }    private:            string name;    };    /* 使用迭代器便利map */    template <class Iter> void show_map(Iter first, Iter last) {            for( ;first!=last; first++) {                    cout << (first->first).key<<"     "<< ((first)->second)->getname()<<endl;            }    }    class Funclass {    public:            bool operator()(const Stukey &op1, const Stukey &op2) {                    return op1.key > op2.key;//按照从大到小比较            }    };    int main(void)    {            /* 如果不给map1和map2指定自定义的比较函数类             * 类行或者模板,将无法通过编译 */            std::map<Stukey, Student *, Funclass> map1;            /* 利用map的第三个模板参数指定比较函数类模板,            * map会使用该函数类模板自动实例化一个比较函数 */            std::map<Stukey, Student *, Funclass> map2;            map1[Stukey(444)] = map2[Stukey(444)] =  new Student("mnjnkkl");            map1[Stukey(222)] = map2[Stukey(222)] =  new Student("qqqqqqs");            map1[Stukey(111)] = map2[Stukey(111)] =  new Student("ddsfass");            map1[Stukey(888)] = map2[Stukey(888)] =  new Student("asdfdff");            map1[Stukey(666)] = map2[Stukey(666)] =  new Student("eqwewqe");            map1[Stukey(555)] = map2[Stukey(555)] =  new Student("sdfsfds");            cout<<"显示map1的内容"<<endl;            show_map(map1.begin(), map1.end());            cout<<"\n显示map2的内容"<<endl;            show_map(map2.begin(), map2.end());            return 0;    }    运行结果:    显示map1的内容    888        asdfdff    666        eqwewqe    555        sdfsfds    444        mnjnkkl    222        qqqqqqs    111        ddsfass    显示map2的内容    888        asdfdff    666        eqwewqe    555        sdfsfds    444        mnjnkkl    222        qqqqqqs    111        ddsfass    6.算法(1)算法介绍(1)什么是算法    所谓算法就是数据的具体处理方式,在程序中算法的常见组织形式就是    函数,单个的子函数就是一个小型的算法单元。(2)c++中涉及的算法有两类    (1)c++函数库提供的算法函数(现成可用的算法)        (1)成员算法函数            所有的容器的都有自己的成员算法函数,比如vector/list/map都提供了            swap算法函数。            除此外C++中所有类库提供的类,比如string/array都有成员算法。            成员算法的特点是,成员算法的操作几乎只与当前类有关。        (2)全局算法            c++中实现了大量的全局算法,这些全局算法的特点就是,可以针对很多            类型的数据操作,几乎都是利用函数模板实现,具有高度的抽象性,与具            体的数据类型无关。            c++的STL模板库就提供了专门针对容器的全局算法函数。    (2)自定义算法        (1)c++编程的工作是什么            编写各种算法函数,定义类只是实现各种成员算法的封装的一种手段,整个            c++程序真正核心是各种算法函数。        (2)全局算法和成员算法            (1)与类相关的就写为成员算法函数            (2)超脱各种类类型的,就写成全局算法,这一点在讲函数时就已经提到过。(3)操作STL容器时涉及的算法    (1)使用容器成员算法    (2)STL全局算法    (3)自定义自己的针对这些容器操作的算法函数(成员/全局)        也就是说我们可以通过容器提供的迭代器遍历,自己实现对容器的增加/删除/查找/        修改/排序等算法,但不提倡这样的做法。    注意:如果使用STL提供的外部算法函数的话,必须包含<algorithm>头文件。

(2)STL全局算法大致有三类

(1)查找类    find(),find_end(),adjacent_find(),count(), mismatch(),    seaech(), equal()。(2)修改类    swap(), copy(), transform(). replace(), remove(), reverse(),    rotate(), fill(), random_shffle()。(3)排序类    sort() stable_sort(), binary_search(), merage(), min(),     max()。      

(3)查找类算法
(1)常用全局算法函数

find():只有一个函数模板    函数模板:    template <class InputIterator, class T>    InputIterator find ( InputIterator first, InputIterator last, const T& value );    功能:查找[first,last)之间是否有value,没有就返回end()。find_if():只有一个模板    template <class InputIterator, class Predicate>    InputIterator find_if ( InputIterator first, InputIterator last, Predicate pred );    功能:根据自定义函数进行比较查找。由于该函数默认只允许一个参数。        为了让比较更为灵活,往往需要定义函数类类型(或者利用仿函数和绑定实现也可以,        具体请看例子)。find_end():提供两个函数模板    template <class ForwardIterator1, class ForwardIterator2>        ForwardIterator1 find_end ( ForwardIterator1 first1, ForwardIterator1 last1,                           ForwardIterator2 first2, ForwardIterator2 last2 );    功能:在[ForwardIterator1,ForwardIterator2)查找[first2, last2)中        任何一个元素出现的最后位置,返回指向该位置的迭代器。    template <class ForwardIterator1, class ForwardIterator2, class BinaryPredicate>        ForwardIterator1 find_end ( ForwardIterator1 first1, ForwardIterator1 last1,                           ForwardIterator2 first2, ForwardIterator2 last2.                           BinaryPredicate pred);    功能:在[ForwardIterator1,ForwardIterator2)查找[first2, last2),但是        多了一个参数,可以用于传递一个比较函数的地址。find_first_of:功能与模板和find_end相似,只是返回的是第一次出现的位置的    迭代器。adjacent_find():有两个模板    template <class ForwardIterator>        ForwardIterator adjacent_find ( ForwardIterator first, ForwardIterator last );    功能:查询相邻两个元素是否相等,如果相等就返回指向第一个元素的        迭代器。        template <class ForwardIterator, class BinaryPredicate>        ForwardIterator adjacent_find ( ForwardIterator first, ForwardIterator last,                              BynaryPredicate pred );    功能:查询相邻两个元素是否相等,如果相等就返回指向第一个元素的        迭代器,可以提供自己定义的比较函数。count():只有一个函数模板    template <class InputIterator, class T>        typename iterator_traits<InputIterator>::difference_type            count ( ForwardIterator first, ForwardIterator last, const T& value );    功能:在[ForwardIterator1,ForwardIterator2)查找value的出现的次数并返回。    

(2)例子:
#include
#include
#include
#include

using namespace std;class Student {public:        Student(const string name=" ", const string num=" "):name(name), num(num) { }        string getname() const { return name; }        string getnum() const { return num; }private:        string name;        string num;};class Compare {public:        Compare(const Student *stu, int comptype):stu(stu), comptype(comptype) {  }        bool operator()(Student *op) {                if(1 == comptype) {                        return(op->getname()==stu->getname());                } else if(2 == comptype) {                        return(op->getnum()==stu->getnum());                }        }private:        const Student *stu;        int comptype;};bool compare(Student *&op) {        return (op->getname() == "name1");}bool compare1(Student *&op1, Student *&op2) {        return (op1->getname() == op2->getname());}bool compare2(Student *&op1, Student *&op2) {        if(op1 == op2) return true;        else if(op1->getname() == op2->getname()&&op1->getnum() == op2->getnum()) {                return true;        } else return false;}void print_find_element(std::list<Student *>::iterator it, std::list<Student *>::iterator end) {        if(it != end) {                cout <<"查找结果:" <<(*it)->getname()<<"   "<<(*it)->getnum()<<endl;        } else cout<<"没有找到"<<endl;}int main(void){        Student *stu[10] = {NULL};        std::list<Student *>::iterator it;//定义一个空的list,存放的数据类型伟Student *        /* 初始化对象数组 */        for(int i=0; i<sizeof(stu)/sizeof(stu[0]); i++) {                stu[i] = new Student(string("name")+string(1, i+'0'), string("11")+string(1, i+'0'));        }        /* 利用对象数组初始化list */        std::list<Student *> v1(stu, stu+sizeof(stu)/sizeof(stu[0]));        cout<<"使用find查找,由于容器存放的是对象地址,所以需要为对象地址查找 "<<endl;        it = find(v1.begin(), v1.end(), stu[1]);        print_find_element(it, v1.end());        cout<<"\n使用find_if查找,自定义比较函数,在函数中确定查找方式为按名字查找 "<<endl;        it = find_if(v1.begin(), v1.end(), compare);        print_find_element(it, v1.end());        cout<<"\n使用find_if查找,定义比较函数类类型,重写()后按照学号查找 "<<endl;        it = find_if(v1.begin(), v1.end(), Compare(new Student("wwwww", "111"), 2));        print_find_element(it, v1.end());        cout<<"\n使用find_first_of查找[stu+2, stu+5)中某个在list中出现的最开始的位置,自定义比较函数"<<endl;        it = find_first_of(v1.begin(), v1.end(), stu+2, stu+5,compare1);        print_find_element(it, v1.end());        cout<<"\n使用adjacent_find在list中使用自定义比较函数查找否有相等的相邻元素"<<endl;        it = adjacent_find(v1.begin(), v1.end(), compare2);        print_find_element(it, v1.end());        return 0;}

(4)修改类算法
(1)常见函数
swap():只有一个函数模板
template void swap ( T& a, T& b );
功能:交换两个a和b两个容器中的内容。

copy():只有一个模板    template <class InputIterator, class OutputIterator>     OutputIterator copy ( InputIterator first, InputIterator last, OutputIterator result );    功能:将[InputIterator, OutputIterator)内容复制到result开始的位置。                但是被复制的容器不能为空,比如使用vector和list为空时,必须        是使用resize函数预先开辟元素空间,如果开辟的空间不够只能复制        一部分,如果空间过多,会导致无效内容的存在。    使用copy函数只能实现浅拷贝,如果容器存放的是指针,那么经过copy复制后,    两个容器里面存放的所有指针指向的都是相同的数据空间。transform():有两个模板,实现对容器中数据进行指定操作。    前面提到,copy只能浅拷贝,如果希望实现深拷贝,我们就需要使用transform    函数。之所以能够实现深拷贝,是因为我们可以通过指定自定义的函数实现具体    的拷贝过程。    对transform来说,同样要求被复制的容器不能为空,比如vector和list,必须    是使用resize函数开辟元素空间,如果开辟的空间不够只能复制一部分,如果空    间过多,会导致无效内容存在。    template < class InputIterator, class OutputIterator, class UnaryOperator >        OutputIterator transform ( InputIterator first1, InputIterator last1,                         OutputIterator result, UnaryOperator op);    功能:对[first1, last1)之间内容做指定的op操作,将结果转存到result容器中,    template < class InputIterator1, class InputIterator2,            class OutputIterator, class BinaryOperator >        OutputIterator transform ( InputIterator1 first1, InputIterator1 last1,                         InputIterator2 first2, OutputIterator result,                         BinaryOperator binary_op );    功能:对[first1, first1)和first2开时的内容进行指定的op运算,结果转存到         result中,要求用于做运算的两个容器内容要想等,否者会抛出异常。replace():只有一个模板    template < class ForwardIterator, class T >        void replace ( ForwardIterator first, ForwardIterator last,                    const T& old_value, const T& new_value );    功能:将[first, last)之间old_value替换为new_value。remove():只有一个模板    template < class ForwardIterator, class T >        ForwardIterator remove ( ForwardIterator first, ForwardIterator last,                       const T& value );    功能:将[first, last)之间等于value的数据删除。remove_if():只有一个模板    template < class ForwardIterator, class Predicate >     ForwardIterator remove_if ( ForwardIterator first, ForwardIterator last,                          Predicate pred );    功能:同remove,但是可以按照自定义的pred的要求删除。reverse():只有一个模板    template <class BidirectionalIterator>    void reverse ( BidirectionalIterator first, BidirectionalIterator last);    功能:将[first, last)之间元素顺序颠倒。rotate():只有一个模板    template <class ForwardIterator>    void rotate ( ForwardIterator first, ForwardIterator middle,            ForwardIterator last );    功能:将[middle,last)元素旋转到开始位置,middle为第一个元素,将        [first,middle)元素旋转到后面。        比如123456789,以4为middle进行旋转后为456789123。fill():只有一个模板    template < class ForwardIterator, class T >    void fill ( ForwardIterator first, ForwardIterator last, const T& value );     功能:使用value填充[first,last)之间内容。random_shuffle():有两个模板    template <class RandomAccessIterator>    void random_shuffle ( RandomAccessIterator first, RandomAccessIterator last );    功能:将[first,last)之间的内容按照默认算法进行随机排序。    template <class RandomAccessIterator, class RandomNumberGenerator>    void random_shuffle ( RandomAccessIterator first, RandomAccessIterator last,                    RandomNumberGenerator& rand );    功能:将[first,last)之间的内容按照rand指定的随机序列号进行随机        重新排序,需要自己实现rand函数。        但是这个函数只能对数组/数组类型的容器如vector操作,对list操作        无效,因为list等其它容器不支持随机访问。

(2)例子
#include
#include
#include
#include

using namespace std;class Student {public:        Student(const string name=" ", const string num=" "):name(name), num(num) { }        void setname(const string name) { this->name = name; }        void setnum(const string num) { this->num=num; }        string getname() const { return name; }        string getnum() const { return num; }private:        string name;        string num;};class Trans_operate {public:        Trans_operate(const string str=" "):str(str) {  }        Student *operator()(Student *op) {                Student *tmp = new Student(op->getname()+str, op->getnum()+str);                return tmp;        }private:        const string str;};class Remove_operate {public:        Remove_operate(const Student *stu, int optype):stu(stu), optype(optype) {  }        bool operator()(Student *op) {                if(1 == optype) return(op->getname()==stu->getname());                else if(2 == optype) return(op->getnum()==stu->getnum());                else return false;        }private:        const Student *stu;        int optype;};int random_fun(int i) {        return (rand()%i);}/* 使用迭代器便利map */template <class Iter> void show_list(Iter first, Iter last) {        for( ;first!=last; first++) {                cout << (*first)->getname() <<endl;        }}int main(void){        Student *stu[10] = {NULL};        /* 初始化对象数组 */        for(int i=0; i<sizeof(stu)/sizeof(stu[0]); i++) {                stu[i] = new Student(string("name")+string(1, i+'0'), string("11")+string(1, i+'0'));        }        /* 利用对象数组初始化list */        std::list<Student *> l1(stu, stu+sizeof(stu)/sizeof(stu[0]));        std::list<Student *> l2;        cout<<"\n交换l1和l2"<<endl;        swap(l1, l2);        if(!l1.empty()) {                cout<<"显示l1"<<endl;                show_list(l1.begin(), l1.end());        }        else cout<<"l1是空的"<<endl;        if(!l2.empty())  {                cout<<"显示l2"<<endl;                show_list(l2.begin(), l2.end());        }        else cout<<"l2是空的"<<endl;        cout<<"\n交换l1和l2后,l1变成了空,将l2的部分内容复制会l1"<<endl;        cout<<"但是由于l1变成了空,需要使用resize函数开辟需要的元素空间"<<endl;        l1.resize(l2.size()-2);        copy(++l2.begin(), --l2.end(), l1.begin());        cout<<"显示l1"<<endl;        show_list(l1.begin(), l1.end());        cout<<"显示l2"<<endl;        show_list(l2.begin(), l2.end());        cout<<"\n将l1中的对象深拷贝到l3中,需要自定义操作函数类"<<endl;        cout<<"要求l3容器不能为空"<<endl;        std::list<Student *> l3(l1.size());        transform(l1.begin(), l1.end(), l3.begin(), Trans_operate("**"));        cout<<"\n将l3中的[begin(), ++begin())替换l3begin()开始的元素"<<endl;        replace(l1.begin(), l1.end(), *(++l1.begin()), *(++l3.begin()));        cout<<"显示l1"<<endl;        show_list(l1.begin(), l1.end());        cout<<"\n按照条件删除元素"<<endl;        remove_if(l1.begin(), l1.end(), Remove_operate(new Student("name4", "111"), 1));        cout<<"显示l1"<<endl;        show_list(l1.begin(), l1.end());        cout<<"\n将l1[++++++l1.begin(), l1.end())的元素进行反转"<<endl;        reverse(++++++l1.begin(), l1.end());        cout<<"显示l1"<<endl;        show_list(l1.begin(), l1.end());        cout<<"\n将l2[l2.begin(), l2.end())的元素以++++++l2.begin()为中心进行rotate"<<endl;        rotate(l2.begin(), ++++++l2.begin(), l2.end());        cout<<"显示l2"<<endl;        show_list(l2.begin(), l2.end());        cout<<"\n将l2中[++++++l2.begin(), ------l2.end())使用new Student(\"wwwww\", \"999\")填充"<<endl;        fill(++++++l2.begin(), ------l2.end(), new Student("wwwww", "999"));        cout<<"显示l2"<<endl;        show_list(l2.begin(), l2.end());        ptrdiff_t (*p_myrandom)(ptrdiff_t) = random_fun;        cout<<"\n将stu中的元素按照自定义的方式随机化"<<endl;        random_shuffle(stu, stu+sizeof(stu)/sizeof(stu[0]), p_myrandom);        cout<<"显示stu"<<endl;        show_list(stu, stu+sizeof(stu)/sizeof(stu[0]));        return 0;}

(5)排序相关的算法
(1)常见函数

sort():有两个模板    template <class RandomAccessIterator>    void sort ( RandomAccessIterator first, RandomAccessIterator last );    功能:将[first,last)之间的内容进行默认的升序排序,但是注意,只有        基本类型有被提供默认的升序排序。    template <class RandomAccessIterator, class Compare>    void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );    功能:将[first,last)之间的内容进行自定义的排序,需要提供比较函数的        函数对象。特别是如果容器中存放的类类型的数据来说,就必须提        供自定义的比较函数对象,否者会导致编译不通过。   注意:    由于sort全局算法函数只支持随机迭代器,所以sort只能对数组和数组类型    的容器比如vetor进行排序。    如果希望对list按照自定义继续宁排序,需要调用list自己成员函数sort。    对于关联容器map来说,只能在存入元素的时候进行排序,寻找一个合适    的位置后将元素插入,所以只能在插入的时候排序,不能进行独立的排序。stable_sort():两个模板,与sort功能与参数同,唯一的区别是遇到相等元素时    不会对其进行交换。search():有两个模板    template <class ForwardIterator1, class ForwardIterator2>    ForwardIterator1 search ( ForwardIterator1 first1, ForwardIterator1 last1,                         ForwardIterator2 first2, ForwardIterator2 last2 );    功能:在[firs,last)之间查询有没有[first,last2)元素序列,有的话,返回        第一次出现的迭代器。注意与find区别,search查找的是一整块序列,        而find查找的是序列中的一个或者元素有没有在容器中出现。               template <class ForwardIterator1, class ForwardIterator2, class BinaryPredicate>    ForwardIterator1 search ( ForwardIterator1 first1, ForwardIterator1 last1,                         ForwardIterator2 first2, ForwardIterator2 last2.                         BinaryPredicate pred );    功能:与上同,但是可以提供带两个参数的自定义比较函数。具体查阅函数手册binary_search():二分法查找,有两个模板    template <class ForwardIterator, class T>    bool binary_search ( ForwardIterator first, ForwardIterator last,                   const T& value );    功能:在[first, last)之间搜索value,找到返回true,失败返回false        与前面讲解find_if函数功能基本相同,只是find_if如果成功,返回        的是指向找到元素的迭代器,失败则返回end()。    template <class ForwardIterator, class T, class Compare>    bool binary_search ( ForwardIterator first, ForwardIterator last,                   const T& value, Compare comp );    指定比叫函数时,比较函数格式如下:        bool myfunction (int op1,int op2) { return op1>op2); }    其中op2时需要查找的元素。    功能:与上同,但是可以指定自定义比较函数。比较函数格式请查阅手册merge():两个模板    template <class InputIterator1, class InputIterator2, class OutputIterator>    OutputIterator merge ( InputIterator1 first1, InputIterator1 last1,                     InputIterator2 first2, InputIterator2 last2,                     OutputIterator result );    功能:将[first1, last1)和[firsr2, last2)之间的内容合并,合并时会        按照默认排序函数进行排序,这只能针对基本类型操作。    template <class InputIterator1, class InputIterator2,        class OutputIterator, class Compare>    OutputIterator merge ( InputIterator1 first1, InputIterator1 last1,                     InputIterator2 first2, InputIterator2 last2,                     OutputIterator result, Compare comp );    功能:同上,但是可以指定自定义的比较函数。    备注:    list也提供了一个属于自己的merge成员函数,利用该函数可以将其它链表合并到        自己中。使用全局的merge可以将两个链表合并到第三个链表中。    这二者还有一个区别就是,list的merge函数合并成功后,被合并的list会被清空,    但是全局的merge函数实现合并操作后,被合并的两个list不会被清空。min():经过比较后,返回最小值,有两个模板。    template <class T> const T& min ( const T& a, const T& b );    功能:返回最小值,调用默认比较函数(只对基本类型有效)。            template <class T, class Compare>    const T& min ( const T& a, const T& b, Compare comp );    功能:同上,可以提供自定义比较函数,对类类型对象操作时,必须使用        这个模板,因为必须指定比较函数。max():功能与模板同min,只是返回的是最大的值。   (2)演示例子#include <iostream>#include <algorithm>#include<iterator>#include<list>#include<string.h>#include<stdio.h>using namespace std;class Student { public:        Student(const string name=" ", const string num=" "):name(name), num(num) { }         void setname(const string name) { this->name = name; }        void setnum(const string num) { this->num=num; }        string getname() const { return name; }        string getnum() const { return num; }private:        string name;        string num;};   class Compare {public:        Compare(int cmptype, int cmpoder):cmpoder(cmpoder), cmptype(cmptype) {  }        /* 如果是二分法binary_search函数调用比较函数,那么op2表示需要被查找的元素 */        bool operator()(Student *op1, Student *op2) {                cout <<op1<<endl;                cout <<op2<<endl;                cout <<op1->getname()<<endl;                cout <<op2->getnum()<<endl;                if(1 == cmptype) {//按照名字排序                        if(1 == cmpoder) {                                return(op1->getname() > op2->getname());                        } else if(2 == cmpoder) {                                return(op1->getname() < op2->getname());                        } else if(3==cmpoder) return(op1->getname() == op2->getname());                }                else if(2 == cmptype) {//按照学号排序                        if(1 == cmpoder) {                                return(op1->getnum() > op2->getnum());                        } else if(2 == cmpoder) {                                return(op1->getnum() < op2->getnum());                        } else if(3==cmpoder) return(op1->getnum() == op2->getnum());                } else return false;        }private:        int cmpoder;        int cmptype;};      /* 使用迭代器便利map */template <class Iter> void show_list(Iter first, Iter last) {        for( ;first!=last; first++) {                cout << (*first)->getname() << "   "<<(*first)->getnum()<<endl;        }}int main(void){        Student *stu[10] = {NULL};        /* 初始化对象数组 */        for(int i=0; i<sizeof(stu)/sizeof(stu[0]); i++) {                stu[i] = new Student(string("name")+string(1, i+'0'), string("11")+string(1, i+'0'));        }        /* 利用对象数组初始化list */        std::list<Student *> l1(stu, stu+sizeof(stu)/sizeof(stu[0]));        cout<<"\n对stu的内容按照要求排序"<<endl;        sort(stu, stu+sizeof(stu)/sizeof(stu[0]), Compare(2, 2));        show_list(stu, stu+sizeof(stu)/sizeof(stu[0]));        cout<<"\n全局sort不能对list进行排序,对list排序需要调用list的成员函数sort"<<endl;        l1.sort(Compare(1, 1));        show_list(l1.begin(), l1.end());        cout<<"\n在l2中搜索[++++l1.begin(), ------l1.end())区间的内容"<<endl;        std::list<Student*>::iterator it;        it = search(l1.begin(), l1.end(), ++++l1.begin(), ------l1.end(), Compare(2, 3));        if(it!=l1.end()) {                cout <<"找到,第一个元素是:"<<endl;                cout <<(*it)->getname()<<"  "<<(*it)->getnum() <<endl;        }        cout<<"\n使用二分法在l2中按照要求查找new Student(\"name4\", \"111\")"<<endl;        bool ret = binary_search(l1.begin(), l1.end(), new Student("name4", "111"), Compare(2, 1));        cout << "ret = " << ret << endl;        if(ret) cout <<"找到"<<endl;        else cout <<"未找到"<<endl;        cout << "\n使用全局merge函数,将l1和l2合并到l3中,自定义合并后的排序顺序 " << endl;        std::list<Student *> l2(++++l1.begin(), ------l1.end());        std::list<Student *> l3(l1.size()+l2.size());        Student *stu3[13];        merge(l1.begin(), l1.end(), l2.begin(), l2.end(), l3.begin(), Compare(2, 2));        show_list(l3.begin(), l3.end());        cout << "\n调用l1的merge函数,将l2合并到自己空间中,使用自定义排序函数 " << endl;        l1.merge(l2, Compare(2, 2));        show_list(l1.begin(), l1.end());        cout << "\n比较*l1.begin(), *(++++l1.begin()谁最小,使用自定义比较函数比较"<<endl;        Student *p = min(*l1.begin(), *(++++l1.begin()), Compare(2, 2));        cout << p->getname()<<"   "<<p->getnum()<<endl;        cout << "\n比较*l1.begin(), *(++++l1.begin()谁最大,使用自定义比较比较"<<endl;        p = max(*l1.begin(), *(++++l1.begin()), Compare(2, 2));        cout << p->getname()<<"   "<<p->getnum()<<endl;        return 0;}
原创粉丝点击