1.C++标准模板库

        标准模板库为标准化组件提供类模板,目的是进行范型编程(数据结构编程)。STL技术是对原有C++技术的一种补充,具有通用性好、效率高、数据结构简单、安全机制完善等特点。下面我们来看看STL库中的一些常用容器和迭代器。

        首先是序列容器,STL序列式容器,其共同的特点是不会对存储的元素进行排序,元素排列的顺序取决于存储它们的顺序。所谓序列容器,即以线性排列(类似普通数组的存储方式)来存储某一指定类型(例如 int、double 等)的数据,需要特殊说明的是该类容器并不会自动对存储的元素按照值的大小进行排序。序列容器中有: array : 是c++ 版本的数组, 模板类的数组。vector :动态数组,底层实现顺序表,用数组实现的表 。list : 双向链表 , 也叫双链表deque : 顺序表实现的循环队列, 数组实现的。forward_list : 单向链表。

        array 容器是 C++ 11 标准中新增的序列容器,简单地理解,它就是在 C++ 普通数组的基础上,添加了一些成员函数和全局函数。在使用上,它比普通数组更安全(原因后续会讲),且效率并没有因此变差。和其它容器不同,array 容器的大小是固定的,无法动态的扩展或收缩,这也就意味着,在使用该容器的过程无法借由增加或移除元素而改变其大小,它只允许访问或者替换存储的元素。

#include <iostream>
#include <array>          //注意在使用stl库中的array时要包含该头文件
using namespace std;

int main()
{
    array<int ,10> a1 = {1,2,3,4,5,6,7,8,9,10};
    cout << "该数组的内容是:" ;
    for(int i=0;i<a1.size();i++)
    {
        cout<<a1[i]<<" ";
    }
    cout<<endl;
    array<float ,10> a2 = {1.1,2.1,3.1,4.1,5.1,6.1,7.1,8.1,9.1,10.1};
    cout << "该数组的内容是:" ;
    for(int i=0;i<a2.size();i++)
    {
        cout<<a2[i]<<" ";
    }
    cout<<endl;
    array<string ,10> a3 = {"beijing","shanghai","guangzhou","shenzhen","chongqing",
                            "tianjin","wulumuqi",  "nanjing",  "xiamen","hangzhou"};
    cout << "该数组的内容是:" ;
    for(int i=0;i<a3.size();i++)
    {
        cout<<a3[i]<<" ";
    }
    cout<<endl;
    return 0;
}

该段程序是使用的序列容器中的array,通过使用模板来存入不同类型的数据,并输出显示出来。

        vector 常被称为向量容器,因为该容器擅长在尾部插入或删除元素,在常量时间内就可以完成,时间复杂度为 O(1) ;而对于在容器头部或者中部插入或删除元素,则花费时间要长一些(移动元素需要耗费时间),时间复杂度为线性阶 O(n) 。

#include <iostream>
#include <vector>          //注意在使用stl库中的vector时要包含该头文件
using namespace std;


int main(int argc, char const *argv[])
{
    vector<int> v1;
    cout << "顺序表的大小是:" << v1.size() << endl;
    cout << "顺序表的入栈顺序是:" ;
    for(int i=0;i < 10;i++)
    {
        v1.push_back(i+1);  //从顺序表的末尾插入元素,即实现入栈
        cout<<v1[i]<<" ";
    }
    cout<<endl;
    cout << "顺序表的大小是:" << v1.size() << endl;

    cout << "顺序表的出栈顺序是:" ;
    for(int i=0;i < 10;i++)
    {
        cout<<v1.back()<<" ";  //返回顺序表中的末尾元素,实现栈顶元素的显示
        v1.pop_back();         //从顺序表的末尾删除元素,实现出栈
    }
    cout<<endl;
    cout << "顺序表的大小是:" << v1.size() << endl;
    return 0;
}

该段程序使用的是序列容器中的vector,通过使用vector来实现一个栈堆中的入栈和出栈。

#include <iostream>
#include <vector>          //注意在使用stl库中的vector时要包含该头文件
using namespace std;


int main(int argc, char const *argv[])
{
    vector<int> v1;
    cout << "顺序表插入顺序:" ;
    for(int i = 0; i < 10 ; i++)
    {
        v1.push_back(i+1);  //从顺序表的末尾插入元素,即实现入栈
        cout<< i+1<<" ";
    }
    cout<<endl;
    cout << "顺序表的内容是:" ;
    for(int i = 0; i < v1.size() ; i++)
    {
        cout<< v1[i] << " ";
    }
    cout<<endl;

    v1.erase(v1.begin()+9);  //删除顺序表中的第10个元素
    v1.erase(v1.begin()+4);   //删除顺序表中的第5个元素
    v1.erase(v1.begin()+0);   //删除顺序表中的第1个元素
    cout << "顺序表的内容是:" ;
    for(int i = 0; i < v1.size() ; i++)
    {
        cout<< v1[i] << " ";
    }
    cout<<endl;

    v1.at(0) = 22;            //将顺序表中的第1个元素修改为22
    v1[6] = 99;               //将顺序表中的第7个元素修改为99,访问该顺序表的方法有两种at()和[]数组下标形式
    cout << "顺序表的内容是:" ;
    for(int i = 0; i < v1.size() ; i++)
    {
        cout<< v1[i] << " ";
    }
    cout<<endl;

    for(int i = 0; i < v1.size() ; i++)
    {
        if(v1[i] == 99)
        {
            cout << "99 found" << endl;
            break;
        }
        if(v1[i] != 99 && i == v1.size()-1)
        {
            cout << "99 not found" << endl;
        }
    }
     for(int i = 0; i < v1.size() ; i++)
    {
        if(v1[i] == 100)
        {
            cout << "100 found" << endl;
            break;
        }
        if(v1[i] != 100 && i == v1.size()-1)
        {
            cout << "100 not found" << endl;
        }
    }
    return 0;
}

该段程序是使用的vector来实现整型数据类型的增删改查。

#include <iostream>
#include <vector>          //注意在使用stl库中的vector时要包含该头文件
using namespace std;


int main(int argc, char const *argv[])
{
    vector<string> v1;
    string citys[10] = {"beijing","shanghai","guangzhou","shenzhen","chongqing",
                        "tianjin","wulumuqi",  "nanjing",  "xiamen","hangzhou"};
    cout << "顺序表插入顺序:" ;
    for(int i = 0; i < 10 ; i++)
    {
        v1.push_back(citys[i]);  //从顺序表的末尾插入元素,即实现入栈
        cout<< citys[i] <<" ";
    }
    cout<<endl;
    cout << "顺序表的内容是:" ;
    for(int i = 0; i < v1.size() ; i++)
    {
        cout<< v1[i] << " ";
    }
    cout<<endl;

    v1.erase(v1.begin()+9);  //删除顺序表中的第10个元素
    v1.erase(v1.begin()+4);   //删除顺序表中的第5个元素
    v1.erase(v1.begin()+0);   //删除顺序表中的第1个元素
    cout << "顺序表的内容是:" ;
    for(int i = 0; i < v1.size() ; i++)
    {
        cout<< v1[i] << " ";
    }
    cout<<endl;

    v1.at(0) = "modu";            //将顺序表中的第1个元素修改为22
    v1[6] = "hunan";               //将顺序表中的第7个元素修改为99,访问该顺序表的方法有两种at()和[]数组下标形式
    cout << "顺序表的内容是:" ;
    for(int i = 0; i < v1.size() ; i++)
    {
        cout<< v1[i] << " ";
    }
    cout<<endl;

    for(int i = 0; i < v1.size() ; i++)
    {
        if(v1[i] == "modu")
        {
            cout << "modu found" << endl;
            break;
        }
        if(v1[i] != "modu" && i == v1.size()-1)
        {
            cout << "modu not found" << endl;
        }
    }
     for(int i = 0; i < v1.size() ; i++)
    {
        if(v1[i] == "xiamen")
        {
            cout << "xiamen found" << endl;
            break;
        }
        if(v1[i] != "xiamen" && i == v1.size()-1)
        {
            cout << "xiamen not found" << endl;
        }
    }
    return 0;
}

该段程序是使用的vector来实现字符串类型数据的增删改查。

        deque 是 double-ended queue 的缩写,又称双端队列容器。deque 容器和 vecotr 容器有很多相似之处,比如:deque 容器也擅长在序列尾部添加或删除元素(时间复杂度为O(1)),而不擅长在序列中间添加或删除元素。

#include <iostream>
#include <deque>          //注意在使用stl库中的deque时要包含该头文件
using namespace std;

int main(int argc, char const *argv[])
{
    deque<int> d1;
    cout << "队列的大小为:" << d1.size() << endl;
    cout << "入队顺序:";
    for(int i = 0; i < 10; i++)
    {
        d1.push_back(i+1);          //用在尾部插入的方式实现入队
        cout << i+1 << " ";
    }
    cout << endl;
    cout << "队列的大小为:" << d1.size() << endl;

    cout << "出队顺序:";
    for(int i = 0; i < 10; i++)
    {
        cout << d1.front() << " ";   //用在显示双端队列首元素的方式实现显示要出队的元素
        d1.pop_front();              //用在从头部删除的方式实现出队
    }
    cout << endl;
    cout << "队列的大小为:" << d1.size() << endl;
    return 0;
}

该段程序使用序列容器中的deque来实现一个队列的出队和入队操作。

#include <iostream>
#include <deque>          //注意在使用stl库中的deque时要包含该头文件
using namespace std;

int main(int argc, char const *argv[])
{
    deque<int> d1;
    cout << "栈的大小为:" << d1.size() << endl;
    cout << "入栈顺序:";
    for(int i = 0; i < 10; i++)
    {
        d1.push_back(i+1);          //用在尾部插入的方式实现入栈
        cout << i+1 << " ";
    }
    cout << endl;
    cout << "栈的大小为:" << d1.size() << endl;

    cout << "出栈顺序:";
    for(int i = 0; i < 10; i++)
    {
        cout << d1.back() << " ";   //用在显示双端队列尾元素的方式实现显示要出栈的元素
        d1.pop_back();              //用在从尾部删除的方式实现出栈
    }
    cout << endl;
    cout << "栈的大小为:" << d1.size() << endl;
    return 0;
}

该段程序是使用的序列容器中的deque来实现的栈的出栈和入栈。

#include <iostream>
#include <deque>          //注意在使用stl库中的deque时要包含该头文件
using namespace std;

int main(int argc, char const *argv[])
{
    deque<int> d1;
    cout << "插入表顺序:";
    for(int i = 0; i < 10; i++)
    {
        d1.push_front(i+1);          //用在头部插入的方式实现表的头插法
        cout << i+1 << " ";
    }
    cout << endl;
    cout << "表的内容是:";
    for(int i = 0; i < 10; i++)
    {
        cout << d1.at(i) << " ";    //用at的形式遍历双端队列实现表的遍历
    }
    cout << endl;

    d1.erase(d1.begin()+9);         //用erase的形式删除双端队列的第10个元素,实现表的指定位置删除
    d1.erase(d1.begin()+4);         //用erase的形式删除双端队列的第5个元素,实现表的指定位置删除
    d1.erase(d1.begin()+0);         //用erase的形式删除双端队列的第1个元素,实现表的指定位置删除
    cout << "表的内容是:";
    for(int i = 0; i < d1.size(); i++)
    {
        cout << d1.at(i) << " ";    //用at的形式遍历双端队列实现表的遍历
    }
    cout << endl;

    d1.at(0) = 99;                 //用at的形式修改双端队列的第1个元素,实现表的指定位置修改
    d1[6] = 22;                    //用数组下标的形式修改双端队列的第7个元素,实现表的指定位置修改
    cout << "表的内容是:";
    for(int i = 0; i < d1.size(); i++)
    {
        cout << d1.at(i) << " ";    //用at的形式遍历双端队列实现表的遍历
    }
    cout << endl;

    for(int i = 0; i < d1.size(); i++)
    {
        if(d1[i] == 99)
        {
            cout << "99 found" << endl;
            break;
        }
        if(d1[i] != 99 && i == d1.size()-1)
        {
            cout << "99 not found" << endl;
        }
    }
    for(int i = 0; i < d1.size(); i++)
    {
        if(d1[i] == 100)
        {
            cout << "100 found" << endl;
            break;
        }
        if(d1[i] != 100 && i == d1.size()-1)
        {
            cout << "100 not found" << endl;
        }
    }

该段程序是使用的序列容器中的deque来实现的链表的增删改查。

         list 容器,又称双向链表容器,该容器的底层是以双向链表的形式实现的。这意味着,list 容器中的元素可以分散存储在内存空间里,而不是必须存储在一整块连续的内存空间中。

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

int main(int argc, char const *argv[])
{
    list<int> l1;
    cout << "l1.size():" << l1.size() << endl;
    cout << "入队顺序为:";
    for(int i = 0; i < 10; i++)
    {
        l1.push_back(i+1);           //用push_back()函数从链表后插入数据实现入队操作
        cout << i+1 << " ";
    }
    cout << endl;
    cout << "l1.size():" << l1.size() << endl;
    cout << "出队顺序为:";
    for(int i = 0; i < 10; i++)
    {
        cout << l1.front() << " ";
        l1.pop_front();              //用pop_front()函数从链表头删除数据实现出队操作
    }
    cout << endl;
    cout << "l1.size():" << l1.size() << endl;
    return 0;
}

该段程序是使用的序列容器中的list来实现的入队和出队操作。

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

int main(int argc, char const *argv[])
{
    list<int> l1;
    cout << "l1.size():" << l1.size() << endl;
    cout << "入栈顺序为:";
    for(int i = 0; i < 10; i++)
    {
        l1.push_front(i+1);           //用push_front()函数从链表头插入数据实现入栈操作
        cout << i+1 << " ";
    }
    cout << endl;
    cout << "l1.size():" << l1.size() << endl;
    cout << "出栈顺序为:";
    for(int i = 0; i < 10; i++)
    {
        cout << l1.front() << " ";
        l1.pop_front();              //用pop_front()函数从链表头删除数据实现出栈操作
    }
    cout << endl;
    cout << "l1.size():" << l1.size() << endl;
    return 0;
}

该段程序使用的是序列容器中的list来实现的入栈和出栈操作。

#include <iostream>
#include <list>          //注意在使用stl库中的list时要包含该头文件
using namespace std;

template <typename T>                      //封装一个模板函数来实现对任意类型的数据进行查找
bool search(list<T> &l1, T value)
{
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        if(*i == value)
        {
            return true;
        }
    }
    return false;
}



int main(int argc, char const *argv[])
{
    list<int> l1;
    cout << "插入表顺序:";
    for(int i = 0; i < 10; i++)
    {
        l1.push_front(i+1);          //用在头部插入的方式实现表的头插法
        cout << i+1 << " ";
    }
    cout << endl;
    cout << "表的内容是:";
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        cout << *i << " ";
    }
    cout << endl;

    l1.remove(1);
    l1.remove(10);
    l1.remove(5);                    //使用链表容器中封装的函数实现对表的值进行删除
    cout << "表的内容是:";
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        cout << *i << " ";
    }
    cout << endl;

    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现找到表中的数据并进行修改
    {
        if(*i == 2)
        {
            *i = 22;
        }
        if(*i == 9)
        {
            *i = 99;
        }
    }
    cout << "表的内容是:";
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        cout << *i << " ";
    }
    cout << endl;

    if(search(l1, 99))
    {
        cout << "99 found" << endl;
    }
    else
    {
        cout << "99 not found" << endl;
    }
    if(search(l1, 100))
    {
        cout << "100 found" << endl;
    }
    else
    {
        cout << "100 not found" << endl;
    }
    return 0;
}

该段程序使用的是序列容器中的list实现的顺序表的增删改查操作,操作的数据类型是整型。

#include <iostream>
#include <list>          //注意在使用stl库中的list时要包含该头文件
using namespace std;

template <typename T>                      //封装一个模板函数来实现对任意类型的数据进行查找
bool search(list<T> &l1, T value)
{
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        if(*i == value)
        {
            return true;
        }
    }
    return false;
}



int main(int argc, char const *argv[])
{
    list<string> l1;
    string citys[10] = {"北京","上海","广州","深圳","成都","重庆","武汉","西安","长沙","南京"};
    cout << "插入表顺序:";
    for(int i = 0; i < 10; i++)
    {
        l1.push_front(citys[i]);          //用在头部插入的方式实现表的头插法
        cout << citys[i] << " ";
    }
    cout << endl;
    cout << "表的内容是:";
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        cout << *i << " ";
    }
    cout << endl;

    l1.remove("北京");
    l1.remove("成都");
    l1.remove("南京");                    //使用链表容器中封装的函数实现对表的值进行删除
    cout << "表的内容是:";
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        cout << *i << " ";
    }
    cout << endl;

    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现找到表中的数据并进行修改
    {
        if(*i == "上海")
        {
            *i = "上新";
        }
        if(*i == "广州")
        {
            *i = "广新";
        }
    }
    cout << "表的内容是:";
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        cout << *i << " ";
    }
    cout << endl;

    if(search(l1, string("上新")))         //注意在使用search函数来查找字符串时,我们直接出入字符串参数,其会认为我们的                                          //
    {                                      //参数是一个常量字符数组所以我们可以用string将该字符数组创建一个字符串对象即可
        cout << "上新 found" << endl;
    }
    else
    {
        cout << "上新 not found" << endl;
    }
    if(search(l1, string("北京")))
    {
        cout << "北京 found" << endl;
    }
    else
    {
        cout << "北京 not found" << endl;
    }

    l1.reverse();                                 //链表逆置
    cout << "表的内容是:";
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        cout << *i << " ";
    }
    cout << endl;
    l1.reverse();
    cout << "表的内容是:";
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        cout << *i << " ";
    }
    cout << endl;
    return 0;
}

该段程序使用的是序列容器中的list实现的增删改查功能,操作的数据类型是字符串类型。

        forward_list 是 C++ 11 新添加的一类容器,其底层实现和 list 容器一样,采用的也是链表结构,只不过 forward_list 使用的是单链表,而 list 使用的是双向链表。

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

int main(int argc, char const *argv[])
{
    forward_list<int> l1;
    cout << "单链表入队顺序:";
    for(int i = 0; i < 10 ; i++)
    {
        cout << i+1 << " ";
        l1.push_front(i+1);       //头插入实现队列入队
    }
    cout << endl;
    l1.reverse();                 //反转链表,因为该容器没有尾部操作,所以要实现队列的先进先出就要先对该单链表容器进行反转操作
    cout << "单链表出队顺序:";
    for(int i = 0 ; i < 10 ; i++)
    {
        cout << l1.front() << " ";
        l1.pop_front();
    }
    cout << endl;    
    return 0;
}

该段程序使用的是序列容器中的forward_list来实现队列的出队和入队操作,但是这里要注意的是因为该容器没有尾部的操作所以就要先反转链表再操作。

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

int main(int argc, char const *argv[])
{
    forward_list<int> l1;
    cout << "单链表入栈顺序:";
    for(int i = 0; i < 10 ; i++)
    {
        cout << i+1 << " ";
        l1.push_front(i+1);   
    }
    cout << endl;
    cout << "单链表出栈顺序:";
    for(int i = 0 ; i < 10 ; i++)
    {
        cout << l1.front() << " ";
        l1.pop_front();
    }
    cout << endl;    
    return 0;
}

该段程序是使用的序列容器中的forward_list来实现出栈和入栈操作。

#include <iostream>
#include <forward_list>          //注意在使用stl库中的forward_list时要包含该头文件
using namespace std;

template <typename T>                      //封装一个模板函数来实现对任意类型的数据进行查找
bool search(forward_list<T> &l1, T value)
{
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        if(*i == value)
        {
            return true;
        }
    }
    return false;
}



int main(int argc, char const *argv[])
{
    forward_list<int> l1;
    cout << "插入表顺序:";
    for(int i = 0; i < 10; i++)
    {
        l1.push_front(i+1);          //用在头部插入的方式实现表的头插法
        cout << i+1 << " ";
    }
    cout << endl;
    cout << "表的内容是:";
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        cout << *i << " ";
    }
    cout << endl;

    l1.remove(1);
    l1.remove(10);
    l1.remove(5);                    //使用链表容器中封装的函数实现对表的值进行删除
    cout << "表的内容是:";
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        cout << *i << " ";
    }
    cout << endl;

    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现找到表中的数据并进行修改
    {
        if(*i == 2)
        {
            *i = 22;
        }
        if(*i == 9)
        {
            *i = 99;
        }
    }
    cout << "表的内容是:";
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        cout << *i << " ";
    }
    cout << endl;

    if(search(l1, 99))
    {
        cout << "99 found" << endl;
    }
    else
    {
        cout << "99 not found" << endl;
    }
    if(search(l1, 100))
    {
        cout << "100 found" << endl;
    }
    else
    {
        cout << "100 not found" << endl;
    }

    l1.reverse();
    cout << "表的内容是:";
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        cout << *i << " ";
    }
    cout << endl;

    l1.sort();
     cout << "表的内容是:";
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        cout << *i << " ";
    }
    cout << endl;

    return 0;
}

该程序使用的是序列容器中的forward_list来实现顺序表的增删改查和反转链表等操作,操作的数据类型是整型。

#include <iostream>
#include <forward_list>          //注意在使用stl库中的forward_list时要包含该头文件
using namespace std;

template <typename T>                      //封装一个模板函数来实现对任意类型的数据进行查找
bool search(forward_list<T> &l1, T value)
{
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        if(*i == value)
        {
            return true;
        }
    }
    return false;
}



int main(int argc, char const *argv[])
{
    forward_list<string> l1;
    string citys[10] ={"北京","上海","广州","深圳","成都","重庆","武汉","长沙","南京","苏州"};
    cout << "插入表顺序:";
    for(int i = 0; i < 10; i++)
    {
        l1.push_front(citys[i]);          //用在头部插入的方式实现表的头插法
        cout << citys[i] << " ";
    }
    cout << endl;
    cout << "表的内容是:";
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        cout << *i << " ";
    }
    cout << endl;

    l1.remove("北京");
    l1.remove("苏州");
    l1.remove("成都");                    //使用链表容器中封装的函数实现对表的值进行删除
    cout << "表的内容是:";
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        cout << *i << " ";
    }
    cout << endl;

    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现找到表中的数据并进行修改
    {
        if(*i == "上海")
        {
            *i = "上新";
        }
        if(*i == "长沙")
        {
            *i = "长新";
        }
    }
    cout << "表的内容是:";
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        cout << *i << " ";
    }
    cout << endl;

    if(search(l1, string("上新")))
    {
        cout << "上新 found" << endl;
    }
    else
    {
        cout << "上新 not found" << endl;
    }
    if(search(l1, string("长沙")))
    {
        cout << "长沙 found" << endl;
    }
    else
    {
        cout << "长沙 not found" << endl;
    }

    l1.reverse();
    cout << "表的内容是:";
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        cout << *i << " ";
    }
    cout << endl;

    l1.sort();                                    //对中文的排序是按照字符的Unicode码点值进行排序
     cout << "表的内容是:";
    for(auto i = l1.begin(); i != l1.end(); i++)  //使用迭代器遍历链表实现表的遍历
    {
        cout << *i << " ";
    }
    cout << endl;

    return 0;
}

该段程序使用的是序列容器中的forward_list实现的顺序表中的增删改查操作,操作的数据类型是字符串类型。

        STL 标准库中另一类容器,即关联式容器,包括 map、multimap、set 以及 multiset 这 4 种容器。set和map的底层数据结构为红黑树,因为map和set要求是自动排序的,红黑树能够实现这一功能,并且各个操作的时间复杂度都较低,而unordered_set和unordered_map的底层数据结构为哈希表,查找时间复杂度为常数级。关联式容器可以快速查找、读取或者删除所存储的元素,同时该类型容器插入元素的效率也比序列式容器高。

         map 容器定义在<map>头文件中,使用该容器存储的数据,其各个元素的键必须是唯一的(即不能重复),该容器会根据各元素键的大小,默认进行升序排序(调用 std::less)

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

int main(int argc, char const *argv[])
{
    map<string,string> m1;                  //map容器的定义方式为map<key_type,value_type> map_name;
                                            //该定义的是键和值都是string类型的键值对
    m1["姓名"] = "张三";
    m1["性别"] = "男";
    m1["年龄"] = "18";
    cout << "姓名:" << m1["姓名"] << endl;
    cout << "性别:" << m1["性别"] << endl;
    cout << "年龄:" << m1["年龄"] << endl;

    for(auto i = m1.begin(); i != m1.end(); i++)
    {
        cout << i->first << ":" << i->second << endl;
    }
    return 0;
}

该段程序展示的是关联容器中map的基本用法,放入数据和提取数据。

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

int main(int argc, char const *argv[])
{
    pair<string,double> p1("数学",90.0);    //通过pair可以创建一个键值对
    pair<string,double> p2("语文",80.0);
    pair<string,double> p3("英语",70.5);
     
    cout << p1.first << ":" << p1.second << endl;   //first是键值对中的键,second是键值对中的值
    cout << p2.first << ":" << p2.second << endl;
    cout << p3.first << ":" << p3.second << endl;
    
    cout << "*****************************************" << endl;

    map<string,double> m1;//创建一个空的键值对容器
    m1.insert(p1);       //可以通过insert,向map容器中里面插入键值对
    m1.insert(p2);
    m1.insert(p3);
    for(auto i = m1.begin(); i != m1.end(); i++) //使用迭代器循环遍历该容器里面的内容
    {
        cout << i->first << ":" << i->second << endl;
    }


    return 0;
}

该段显示的是使用pair来构建一个键值对。

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


int main(int argc, char const *argv[])
{
    string quhao[] = {"010","020","021","022","023","024","025","026","027","028","029"};
    string city[] = {"北京","广州","上海","天津","重庆","沈阳","南京","杭州","武汉","成都","西安"};
    map<string,string> m1;          //放入的键值对默认会进行升序排序
    for(int i = 0; i < 11; i++)
    {
        m1.insert(pair<string,string>(quhao[i],city[i]));  //通过insert的方式将键值对放入map容器当中
    }
    for(auto i = m1.begin(); i != m1.end(); i++)
    {
        cout << i->first << ":" << i->second << endl;
    }
    cout << "***************************************" << endl;
    map<string,string,greater<string>> m2;  //带上第三个参数,通过greater<string>实现降序排序
    for(int i = 0; i < 11; i++)
    {
        //m2.insert(pair<string,string>(quhao[i],city[i]));
        m2.emplace(quhao[i],city[i]);                      //还可以通过emplace的方式放入键值对
    }
    for(auto i = m2.begin(); i != m2.end(); i++)
    {
        cout << i->first << ":" << i->second << endl;
    }
    return 0;
}

该段程序展示了关联容器中map的自动排序特点,默认使用的是升序排序,再带入第三个参数后可以调整排序的升降序。

        multimap 容器也用于存储 pair<const K, T> 类型的键值对(其中 K 表示键的类型,T 表示值的类型),其中各个键值对的键的值不能做修改;并且,该容器也会自行根据键的大小对存储的所有键值对做排序操作。和 map 容器的区别在于,multimap 容器中可以同时存储多(≥2)个键相同的键值对。

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

int main(int argc, char const *argv[])
{
    map<string,double> m1;
    m1.emplace("数学",90);          //当使用map容器时,不能出现重复的键值,若出现重复的键值只会使用第一个后面的会自动忽略
    m1.emplace("数学",70);
    m1.emplace("数学",80);
    m1.emplace("语文",91);
    m1.emplace("语文",81);
    m1.emplace("英语",92);
    for(auto i = m1.begin(); i != m1.end(); i++)
    {
        cout << i->first << ":" << i->second << endl;
    }
    cout << "*************************" << endl;
    multimap<string,double> m2;
    m2.emplace("数学",90);
    m2.emplace("数学",70);          //使用multimap容器时,就可以出现重复的键值,重复的键值也会被放入到容器中
    m2.emplace("数学",80);          //对于重复键值的排序,因为键是一样的所以根据的排序顺序进行排序
    m2.emplace("语文",91);
    m2.emplace("语文",81);
    m2.emplace("英语",92);
    for(auto i = m2.begin(); i != m2.end(); i++)
    {
        cout << i->first << ":" << i->second << endl;
    }
    return 0;
}

该段程序用来展示关联容器中multimap与map的不同点。

        set 容器存储的各个键值对,要求键 key 和值 value 必须相等。

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

int main()
{
    set<string> s = {"数学","语文","英语","物理","化学","生物","政治"};
    for(auto i = s.begin(); i != s.end(); i++)
    {
        cout << *i << " ";
    }
    cout << endl;
    cout << "s.size() = " << s.size() << endl;
    cout << "*************************" << endl;
    s.insert("历史") ;
    s.emplace("地理");        //可以通过该两种方式进行插入
    for(auto i = s.begin(); i != s.end(); i++)
    {
        cout << *i << " ";
    }
    cout << endl;
    cout << "s.size() = " << s.size() << endl;
    cout << "****************************" << endl;
    s.erase("英语");
    for(auto i = s.begin(); i != s.end(); i++)
    {
        cout << *i << " ";
    }
    cout << endl;
    cout << "s.size() = " << s.size() << endl;
    cout << "****************************" << endl;
    //set不支持修改元素的值,只能通过删除再插入的方式进行修改

    if(s.find("数学") != s.end())   //s.end()返回的是指向最后一个元素的下一个位置的迭代器,所以句程序说明判断已经遍历完了所有元素看
                                   //find返回的迭代器是否等于s.end()来判断是否找到该元素
    {
        cout << "数学课程存在" << endl;
    }
    else
    {
        cout << "数学课程不存在" << endl;
    }
    if(s.find("英语") != s.end())
    {
        cout << "英语课程存在" << endl;
    }
    else
    {
        cout << "英语课程不存在" << endl;
    }



    return 0;
}

该段程序使用的是关联容器中的set来对数据进行操作,该容器要求的是其中数据的键值对相同。

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

int main()
{
    multiset<string> s = {"数学","语文","英语","物理","化学","生物","政治"};  //multiset允许存在重复元素,底层使用红黑树会自动对元素进行排序
    for(auto i = s.begin(); i != s.end(); i++)                             //排序采用升序,set中用来存放键值一样的键值对,存入的是值
    {
        cout << *i << " ";
    }
    cout << endl;
    cout << "s.size() = " << s.size() << endl;
    cout << "*************************" << endl;
    s.insert("历史") ;
    s.insert("历史");
    s.insert("历史");
    s.emplace("地理");        //可以通过该两种方式进行插入
    for(auto i = s.begin(); i != s.end(); i++)
    {
        cout << *i << " ";
    }
    cout << endl;
    cout << "s.size() = " << s.size() << endl;
    cout << "****************************" << endl;
    s.erase("历史");                          //当我们要删除有相同值的值时,用erase会将所有的相同值全部删除
    for(auto i = s.begin(); i != s.end(); i++)
    {
        cout << *i << " ";
    }
    cout << endl;
    cout << "s.size() = " << s.size() << endl;
    cout << "****************************" << endl;
    //set不支持修改元素的值,只能通过删除再插入的方式进行修改

    if(s.find("数学") != s.end())   //s.end()返回的是指向最后一个元素的下一个位置的迭代器,所以句程序说明判断已经遍历完了所有元素看
                                   //find返回的迭代器是否等于s.end()来判断是否找到该元素
    {
        cout << "数学课程存在" << endl;
    }
    else
    {
        cout << "数学课程不存在" << endl;
    }
    if(s.find("历史") != s.end())
    {
        cout << "历史课程存在" << endl;
    }
    else
    {
        cout << "历史课程不存在" << endl;
    }



    return 0;
}

该段程序使用的是关联容器中的multiset展示的是与set的不同,multi里面可以存放相同的元素,注意的是在multiset中不再以键值对的形式来存放数据而是只存放的键值对中的值。

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


int main(int argc, char const *argv[])
{
    string quhao[] = {"010","020","021","022","023","024","025","026","027","028","029"};
    string city[] = {"北京","广州","上海","天津","重庆","沈阳","南京","杭州","武汉","成都","西安"};
    unordered_map<string,string> um1;  //unordered_map相比于map,unordered_map是基于哈希表实现的,而map是基于红黑树实现的
    for(int i = 0; i < 11; i++)        //unordered_map是无序的,元素的存储位置由键的哈希值决定
    {
        um1.emplace(quhao[i],city[i]);  //emplace可以直接在容器中构造元素,避免了先构造临时对象再插入的过程
    }
    for(auto i = um1.begin(); i != um1.end(); i++)
    {
        cout << i->first << " " << i->second << endl;
    }
    return 0;
}

该段程序使用的关容器中的unordered_map,该容器是无序的于map的不同就是不再对存入的数据进行升降序的排序了。

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

int main(int argc, char const *argv[])
{
    unordered_map<string,double> m1;
    m1.emplace("数学",90);          //当使用map容器时,不能出现重复的键值,若出现重复的键值只会使用第一个后面的会自动忽略
    m1.emplace("数学",70);
    m1.emplace("数学",80);
    m1.emplace("语文",91);
    m1.emplace("语文",81);
    m1.emplace("英语",92);
    for(auto i = m1.begin(); i != m1.end(); i++)
    {
        cout << i->first << ":" << i->second << endl;
    }
    cout << "*************************" << endl;
    unordered_multimap<string,double> m2;
    m2.emplace("数学",90);
    m2.emplace("数学",70);          //使用multimap容器时,就可以出现重复的键值,重复的键值也会被放入到容器中
    m2.emplace("数学",80);          //对于重复键值的排序,因为键是一样的所以根据的排序顺序进行排序
    m2.emplace("语文",91);
    m2.emplace("语文",81);
    m2.emplace("英语",92);
    for(auto i = m2.begin(); i != m2.end(); i++)
    {
        cout << i->first << ":" << i->second << endl;
    }
    return 0;
}

该段程序使用的关联容器中的unordered_multimap用来展示其于unordered_map的不同,就是在容器可以存储相同的元素。

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

int main()
{
    unordered_set<string> s = {"数学","语文","英语","物理","化学","生物","政治"};
    for(auto i = s.begin(); i != s.end(); i++)
    {
        cout << *i << " ";
    }
    cout << endl;
    cout << "s.size() = " << s.size() << endl;
    cout << "*************************" << endl;
    s.insert("历史") ;
    s.emplace("地理");        //可以通过该两种方式进行插入
    for(auto i = s.begin(); i != s.end(); i++)
    {
        cout << *i << " ";
    }
    cout << endl;
    cout << "s.size() = " << s.size() << endl;
    cout << "****************************" << endl;
    s.erase("英语");
    for(auto i = s.begin(); i != s.end(); i++)
    {
        cout << *i << " ";
    }
    cout << endl;
    cout << "s.size() = " << s.size() << endl;
    cout << "****************************" << endl;
    //set不支持修改元素的值,只能通过删除再插入的方式进行修改

    if(s.find("数学") != s.end())   //s.end()返回的是指向最后一个元素的下一个位置的迭代器,所以句程序说明判断已经遍历完了所有元素看
                                   //find返回的迭代器是否等于s.end()来判断是否找到该元素
    {
        cout << "数学课程存在" << endl;
    }
    else
    {
        cout << "数学课程不存在" << endl;
    }
    if(s.find("英语") != s.end())
    {
        cout << "英语课程存在" << endl;
    }
    else
    {
        cout << "英语课程不存在" << endl;
    }



    return 0;
}

该段程序使用的是unordered_set区别于set的不同就是不再对存入的数据进行排序。

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

int main()
{
    unordered_multiset<string> s = {"数学","语文","英语","物理","化学","生物","政治"};  //multiset允许存在重复元素,底层使用红黑树会自动对元素进行排序
    for(auto i = s.begin(); i != s.end(); i++)                             //排序采用升序,set中用来存放键值一样的键值对,存入的是值
    {
        cout << *i << " ";
    }
    cout << endl;
    cout << "s.size() = " << s.size() << endl;
    cout << "*************************" << endl;
    s.insert("历史") ;
    s.insert("历史");
    s.insert("历史");
    s.emplace("地理");        //可以通过该两种方式进行插入
    for(auto i = s.begin(); i != s.end(); i++)
    {
        cout << *i << " ";
    }
    cout << endl;
    cout << "s.size() = " << s.size() << endl;
    cout << "****************************" << endl;
    s.erase("历史");                          //当我们要删除有相同值的值时,用erase会将所有的相同值全部删除
    for(auto i = s.begin(); i != s.end(); i++)
    {
        cout << *i << " ";
    }
    cout << endl;
    cout << "s.size() = " << s.size() << endl;
    cout << "****************************" << endl;
    //set不支持修改元素的值,只能通过删除再插入的方式进行修改

    if(s.find("数学") != s.end())   //s.end()返回的是指向最后一个元素的下一个位置的迭代器,所以句程序说明判断已经遍历完了所有元素看
                                   //find返回的迭代器是否等于s.end()来判断是否找到该元素
    {
        cout << "数学课程存在" << endl;
    }
    else
    {
        cout << "数学课程不存在" << endl;
    }
    if(s.find("历史") != s.end())
    {
        cout << "历史课程存在" << endl;
    }
    else
    {
        cout << "历史课程不存在" << endl;
    }



    return 0;
}

该段程序使用的是关联容器中的unordered_multiset,该容器区别于unordered_set的不同就是苦于存储相同的元素。

        容器适配器是一个封装了序列容器的类模板,它在一般序列容器的基础上提供了一些不同的功能。之所以称作适配器类,是因为它可以通过适配容器现有的接口来提供不同的功能。一般的理解是在vector、deque、list之上做了一层封装,可以实现高效的性能。下面用一些程序来展示容器适配器的一些用法。

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


int main(int argc, char const *argv[])
{
    stack<int> s;
    cout << "s.size() = " << s.size() << endl;
    cout << "入栈顺序:";
    for(int i = 0 ; i < 10 ; i++)
    {
        s.push(i+1);          //容器适配器,对基本容器进行封装,提供了栈的操作接口,简化了接口
        cout << i+1 << " ";
    }
    cout <<endl;
    cout << "s.size() = " << s.size() << endl;
    cout << "出栈顺序:";
    for(int i = 0 ; i < 10 ; i++)
    {
        cout << s.top() << " ";  //top()函数返回的是栈顶元素的引用,显示栈顶元素
        s.pop();                 //pop()函数删除栈顶元素,不返回值,出栈
    }
    cout <<endl;
    cout << "s.size() = " << s.size() << endl;
    return 0;
}

该段程序使用容器适配器中的stack,来实现栈的入栈和出栈操作。

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


int main(int argc, char const *argv[])
{
    queue<int> q;
    cout << "q.size():" << q.size() << endl;
    cout << "入队顺序:" ;
    for(int i = 0 ; i < 10 ; i++)
    {
        q.push(i+1);              //可见入队和入栈的接口一样,这也是简化接口的一个体现
        cout << i+1 << " ";
    }
    cout <<endl;
    cout << "q.size():" << q.size() << endl;
    cout << "出队顺序:" ;
    for(int i = 0 ; i < 10 ; i++)
    {
        cout << q.front() << " ";
        q.pop();
    }
    cout <<endl;
    cout << "q.size():" << q.size() << endl;
    return 0;
}

该段程序使用容器适配器中的queue来实现队列的入队和出队操作。

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


int main(int argc, char const *argv[])
{
    priority_queue<int> q1;    //带默认排序的队列,默认是从大到小,可以通过less<int>或greater<int>改变排序,less<int>是从大到小,greater<int>是从小到大
    int array[] = {1,41,6,22,4,26,40,5,100,38};
    cout << "q1.size():" << q1.size() << endl;
    cout << "入队顺序:" ;
    for(int i = 0 ; i < 10 ; i++)
    {
        q1.push(array[i]);              //可见入队和入栈的接口一样,这也是简化接口的一个体现
        cout << array[i] << " ";
    }
    cout <<endl;
    cout << "q1.size():" << q1.size() << endl;
    cout << "出队顺序:" ;
    for(int i = 0 ; i < 10 ; i++)
    {
        cout << q1.top() << " ";         //优先队列中要显示对头没有front()函数,要使用top()函数
        q1.pop();
    }
    cout <<endl;
    cout << "q1.size():" << q1.size() << endl;
    cout << "********************************" << endl;
    priority_queue<int,vector<int>,greater<int>> q2;    //从小到大排序
    for(int i = 0 ; i < 10 ; i++)
    {
        q2.push(array[i]);
        cout << array[i] << " ";
    }
    cout <<endl;
    cout << "q2.size():" << q2.size() << endl;
    cout << "出队顺序:" ;
    for(int i = 0 ; i < 10 ; i++)
    {
        cout << q2.top() << " ";
        q2.pop();
    }
    cout <<endl;
    cout << "q2.size():" << q2.size() << endl;
    return 0;
}

该段程序使用的是容器适配器中的priority_queue来实现一个队列的出队于入队操作,该容器适配器会默认对其中的数据进程从大到小的排列。

        迭代器和 C语言的指针非常类似,它可以是需要的任意类型,通过迭代器可以指向容器中的某个元素,也可以对该元素进行读/写操作,迭代器适配器,其本质也是一个模板类,就是通过的迭代器再实现的,下面我们来看看一些常用迭代器适配器的用法。

#include <iostream>
#include <vector>
#include <iterator>
using namespace std;


int main(int argc, char const *argv[])
{
    vector<int> v1 = {1,2,3,4,5,6,7,8,9,10};
    reverse_iterator<vector<int>::iterator> rit(v1.end());   //定义一个反向迭代器,指向v1的最后一个元素
    cout << "*rit:" << *rit << endl;
    cout << "*(rit+1):" << *(rit+1) << endl;
    cout << "rit[9]:" << rit[9] << endl;

    for(int i = 0 ; i < 10 ; i++)
    {
        cout << rit[i] << " ";     //从容器的尾部开始遍历到头部
    }
    cout << endl;

    return 0;
}

该段程序使用的是迭代器中的反向迭代器适配器reverse_iterator,通过反向迭代来对vector内的数据进行访问。

#include <iostream>
#include <deque>
#include <iterator>
using namespace std;

int main(int argc, char const *argv[])
{
    deque<int> d1;
    back_insert_iterator<deque<int>> bit(d1);   //在插入迭代器定义中我们可以看到<>里面是容器的类型,不需要再使用::啦
    bit = 1;     //通过后插入迭代器,我们可以使用赋值运算符将元素插入到容器的末尾
    bit = 2;
    bit = 3;
    for(auto i = d1.begin() ; i != d1.end() ; i++)
    {
        cout << *i << " ";
    }
    cout << endl;
    bit = 10;
    bit = 20;
    bit = 30;
    for(auto i = d1.begin() ; i != d1.end() ; i++)
    {
        cout << *i << " ";
    }
    cout << endl;
    return 0;
}

该段程序是使用的迭代适配器中的后插入迭代适配器back_insert_iterator来进行双端队列容器中数据的插入。

        在C++中,函数对象(Function Object)是一种特殊的对象,可以像函数一样被调用。函数对象可以通过重载函数调用运算符 operator() 来实现,使得它们可以像函数一样被调用,并且可以拥有自己的状态和行为。

#include <iostream>
using namespace std;

int add(int a,int b)
{
    return a+b;
}

class funcobj
{
    public:
    int operator()(int a,int b)   //对()运算符进行重载,使funcobj类的对象可以像函数一样调用
    {
        return a+b;
    }
};


int main(int argc, char const *argv[])
{
    int(*ptr1)(int,int);             //定义一个函数指针
    ptr1 = add;                      //将add函数的地址赋值给函数指针ptr1,即该函数指针指向add函数
    cout << "ptr1(1,2):" << ptr1(1,2) << endl;

    int(*ptr2)(int,int);             //定义一个函数指针
    ptr2 = &add;                     //将add函数的地址赋值给函数指针ptr2,即该函数指针指向add函数
    cout << "ptr2(1,2):" << ptr2(1,2) << endl;
    cout << "(*ptr2)(1,2):" << (*ptr2)(1,2) << endl; //都会得到add(1,2)的结果,即3,在C++语法中add会自动转化成指向函数指针
                                                     //&和*都是可选的,使用或者不使用函数指针都是指向该函数。

    funcobj fobj;
    cout << "fobj(1,2):" << fobj(1,2) << endl; //fobj(1,2)会调用funcobj类的operator()函数,返回1+2=3
                                               //实际上fobj(1,2)会转化成fobj.operator()(1,2)
    
    return 0;
}

该段程序定义了一个函数对象,展示了函数对象的基本用法。

#include <iostream>
using namespace std;

template <typename T>
class mygreater
{
public:
    bool operator()(T a,T b)
    {
        return a > b;
    }
};

template <typename T>
class myless
{
public:
    bool operator()(T a,T b)
    {
        return a < b;
    }
};



template <typename T1,typename T2>   //模板函数
bool compare(T1 a,T1 b, T2 comp)
{
    return comp(a,b);
}

int main(int argc, char const *argv[])
{
    bool ret1 = compare(1,2,mygreater<int>());    //使用函数对象来对1和2进行大于比较,注意要加上(),因为要传入一个对象
    cout << "ret1 = " << ret1 << endl;
    bool ret2 = compare(1,2,myless<int>());       //使用函数对象来对1和2进行小于比较
    cout << "ret2 = " << ret2 << endl;
    return 0;
}

该段程序使用函数对象来实现对两个数进行比较的功能。

        lambda表达式(也称为lambda函数)是在调用或作为函数参数传递的位置处定义匿名函数对象的便捷方法。通常,lambda用于封装传递给算法或异步方法的几行代码 。下面看看lambda表达式的基本使用方法。

#include <iostream>
using namespace std;

class lambda1
{
public:
    void operator()()
    {
        cout << "hello world" << endl;
    }
};

class lambda2
{
public:
    int operator()(int a,int b)
    {
        return a + b;
    }
};

class lambda3
{
public:
    void operator()(int &a,int &b)
    {
        int t = a;
        a = b;
        b = t;
    }
};



int main(int argc, char const *argv[])
{
    //1.无参数,无返回值的lambda表达式
    auto func1 = []()
    {
        cout << "hello world" << endl;
    };
    func1();
    //2.有参数,有返回值的lambda表达式
    auto func2 = [](int a,int b)     
    {
        return a + b;             //有返回值的lambda表达式可以不用写返回值
    };
    int ret = func2(10,20);
    cout << ret << endl;
    //3.有参数,无返回值的lambda表达式
    auto func3 = [](int &a,int &b)
    {
        int t = a;
        a = b;
        b = t;
    };
    int a  = 10 ,b = 20;
    func3(a,b);
    cout << "a = " << a << " b = " << b << endl;
    cout << "******************************************" << endl;
    //lamgbda表达式等价于对象函数调用,在底层lambda表达式会被转换为对象函数调用
    lambda1 l1;
    l1();
    lambda2 l2;
    cout << l2(10,20) << endl;
    lambda3 l3;
    l3(a,b);
    cout << "a = " << a << " b = " << b << endl;

    return 0;
}

该段程序展示了lambda表达式的三种基本用法。

2.C++的内存管理与文件操作

        我们在这里主要来看看指针的用法和与文件操作的一些相关函数。

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

class point
{
    private:
    int x,y;
    public:
    point(int x , int y)
    {
        cout << "构造函数被调用" << endl;
        this -> x = x;
        this -> y = y;
    }
    ~point()
    {
        cout << "析构函数被调用"  << endl;
    }
    void show()
    {
        cout << "(" << x << "," << y << ")" << endl;
    }
};



int main(int argc, char const *argv[])
{
    //创建空智能指针
    unique_ptr<point> ptr1;                //指针指针的定义需要指明该智能指针要指向的类
    unique_ptr<point> ptr2(nullptr);       //两种空智能指针的定义方法
    if(ptr1.get() != nullptr)              //使用get()函数可以获取智能指针所指向的对象的地址
    {                                      //要使用智能指针访问对象时可以使用get()也可以不使用get()
        ptr1.get()  -> show();
    }                                           //在使用智能指针时最好要加上非空的判断,不然容易造成程序运行崩掉

    //创建指向一个对象的智能指针
    unique_ptr<point> ptr3(new point(10,20));   //创建一个智能指针,指向一个新创建的point对象
    if(ptr3.get() != nullptr)
    {
        ptr3.get() -> show();
    }
    cout << "***********************************" << endl;

    //销毁旧对象,绑定新对象
    ptr3.reset(new point(30,40));   //reset()函数先销毁旧对象,绑定新对象
    if(ptr3.get() != nullptr)
    {
        ptr3.get() -> show();
    }
    cout << "***********************************" << endl;

    //改变所有权
    ptr1 = move(ptr3);   //move()函数可以将一个智能指针转移给另一个智能指针,转移后原智能指针指向空
    if(ptr1.get() != nullptr)
    {
        ptr1.get() -> show();
    }
    cout << "***********************************" << endl;
    //改变所有权
    ptr2.reset(ptr1.release());   //先释放ptr1的所有权,然将所有权转移给ptr2
    if(ptr2.get() != nullptr)
    {
        ptr2.get() -> show();
    }
    cout << "***********************************" << endl;

    //销毁对象
    ptr2 = nullptr;         //将ptr2指向空,调用析构函数销毁对象
    cout << "***********************************" << endl;



    return 0;
}

该段程序展示了unique_ptr指针的基本使用。

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

int main(int argc, char const *argv[])
{
    shared_ptr<int> ptr1(new int(10));
    cout << "*ptr1 = " << *ptr1 << "  ptr1.use_count() = " << ptr1.use_count() << endl;
    shared_ptr<int> ptr2(ptr1);
    cout << "*ptr2 = " << *ptr2 << "  ptr2.use_count() = " << ptr2.use_count() << endl;
    shared_ptr<int> ptr3 = ptr2;
    cout << "*ptr3 = " << *ptr3 << "  ptr3.use_count() = " << ptr3.use_count() << endl;
    cout << "*******************************************" << endl;

    ptr1.reset(new int(20));      //销毁原来的对象,指向新对象
    cout << "*ptr1 = " << *ptr1 << "  ptr1.use_count() = " << ptr1.use_count() << endl;
    cout << "*ptr2 = " << *ptr2 << "  ptr2.use_count() = " << ptr2.use_count() << endl;
    cout << "*ptr3 = " << *ptr3 << "  ptr3.use_count() = " << ptr3.use_count() << endl;
    cout << "*******************************************" << endl;

    ptr2.reset();                //将ptr2指向空,当引用计数为0时,销毁对象
    cout << "*ptr1 = " << *ptr1 << "  ptr1.use_count() = " << ptr1.use_count() << endl;
    cout << "*ptr3 = " << *ptr3 << "  ptr3.use_count() = " << ptr3.use_count() << endl;
    cout << "*******************************************" << endl;

    return 0;
}

该段程序展示指针中使用shared_ptr指针中的计数机制。

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

class testB;    ///前向声明,B类还没有声明时要先使用B类的指针的话则需要在A类前对于B类进行前向声明
class testA
{
    private:
    //shared_ptr<testB> ptra;
    weak_ptr<testB> ptra;      
    public:
        testA()
        {
            cout << "testA()" << endl;
        }
        ~testA()
        {
            cout << "~testA()" << endl;
        }
        void funA(const shared_ptr<testB>& b)
        {
            cout << "funA()" << endl;
            ptra = b;
        }
};

class testB
{
    private:
    //shared_ptr<testA> ptrb;
    weak_ptr<testA> ptrb;
    public:
        testB()
        {
            cout << "testB()" << endl;
        }
        ~testB()
        {
            cout << "~testB()" << endl;
        }
        void funB(const shared_ptr<testA>& a)
        {
            cout << "funB()" << endl;
            ptrb = a;
        }
};

//当两个普通对象互相引用时,会导致循环引用,不能正确调用析构函数,导致内存泄漏
//解决方法:使用弱指针weak_ptr,弱指针不会增加引用计数,不会导致循环引用
//弱指针可以通过lock()函数将其转换为共享指针,但是如果对象已经被销毁,则返回空指针
//弱指针可以用于解决循环引用问题,但是不能直接使用弱指针访问对象的成员,需要先将其转换为共享指针
//如果弱指针指向的对象已经被销毁,则转换为共享指针时会返回空指针,避免了访问已销毁对象的风险


int main(int argc, char const *argv[])
{
    shared_ptr<testA> ptra(new testA());
    shared_ptr<testB> ptrb(new testB());
    ptra->funA(ptrb);
    ptrb->funB(ptra);
    return 0;
}

该段程序用来展示shared_ptr指针和weak_ptr指针的联合用法。

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

int main(int argc, char const *argv[])
{
    fstream file1("test1.txt" , ios::out | ios::in | ios::trunc); //以可读可写打开文件,文件不存在则创建,存在则清空文件内容
    cout << "file1.is_open() = " << file1.is_open() << endl;
    file1 << "file info" << endl;
    file1 << "students number :" << 1 << endl;
    file1 << "students name   :" << "zhangsan" << endl;
    file1 << "students age    :" << 18 << endl;
    file1 << "students sex    :" << "male" << endl;
    file1 << "students score  :" << 90 << endl;
    file1.close();

    fstream file2("test2.txt" , ios::out | ios::in | ios::trunc); //以可读可写打开文件,文件不存在则创建,存在则清空文件内容
    cout << "file2.is_open() = " << file2.is_open() << endl;
    file2 << "file info" << endl;
    file2 << "students number :" << 2 << endl;
    file2 << "students name   :" << "lisi" << endl;
    file2 << "students age    :" << 20 << endl;
    file2 << "students sex    :" << "male" << endl;
    file2 << "students score  :" << 91.5 << endl;
    file2.close();


    return 0;
}

该段程序是打开或创建两个文件并且向文件里面写入内容。

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


//app file1 file2
//argv[0] = app
//argv[1] = file1
//argv[2] = file2


int main(int argc, char const *argv[])
{
    if(argc != 3)
    {
        cout << "Usage: " << argv[0] << " file1 file2" << endl;
        exit(-1);
    }
    fstream file1(argv[1] ,ios::in); //以可读打开文件
    if(!file1.is_open())
    {
        cout << "open file1 failed" << endl;
        exit(-1);
    }
    fstream file2(argv[2] ,ios::in | ios::out | ios::trunc); //以可读可写打开文件,文件不存在则创建,存在则清空文件内容
    if(!file2.is_open())
    {
        cout << "open file2 failed" << endl;
        exit(-1);
    }

    //从file1中读取字符,写入file2
    //判断文件是否到达文件末尾
    //到达文件末尾,file1.get(ch) 返回eof   返回false
    //未到达文件末尾,file1.get(ch) 返回ch字符 返回true
    char ch;
    while(file1.get(ch))
    {
        file2.put(ch);
    }
    file1.close();
    file2.close();

    return 0;
}

该段程序是打开两个文件将一个文件中的内容写入到另一个文件中。get和put一次读取或写入一个字符。

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


//app file1 file2
//argv[0] = app
//argv[1] = file1
//argv[2] = file2


int main(int argc, char const *argv[])
{
    if(argc != 3)
    {
        cout << "Usage: " << argv[0] << " file1 file2" << endl;
        exit(-1);
    }
    fstream file1(argv[1] ,ios::in); //以可读打开文件
    if(!file1.is_open())
    {
        cout << "open file1 failed" << endl;
        exit(-1);
    }
    fstream file2(argv[2] ,ios::in | ios::out | ios::trunc); //以可读可写打开文件,文件不存在则创建,存在则清空文件内容
    if(!file2.is_open())
    {
        cout << "open file2 failed" << endl;
        exit(-1);
    }

    
    char buf[128] = {0};
    while(!file1.eof())  //判断是否到达文件末尾
    {
        file1.read(buf ,128); //从文件1读取128字节到buf
        file2.write(buf , file1.gcount());//将buf中的数据写入文件2,写入的字节数为file1.gcount()
                                          //file1.gcount()返回实际读取的字节数
    }
    file1.close();
    file2.close();

    return 0;
}

该段程序和上面的实现一样都式将一个文件的内容写入到另一个文件中,其中read和write一次读取指定字节数和一次写入指定字节数内容。

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


//app file1 file2
//argv[0] = app
//argv[1] = file1
//argv[2] = file2


int main(int argc, char const *argv[])
{
    if(argc != 4)
    {
        cout << "Usage: " << argv[0] << " file1 file2 file3" << endl;
        exit(-1);
    }
    fstream file1(argv[1] ,ios::in); //以可读打开文件
    if(!file1.is_open())
    {
        cout << "open file1 failed" << endl;
        exit(-1);
    }
    fstream file2(argv[2] ,ios::in | ios::out | ios::trunc); //以可读可写打开文件,文件不存在则创建,存在则清空文件内容
    if(!file2.is_open())
    {
        cout << "open file2 failed" << endl;
        exit(-1);
    }
    fstream file3(argv[3] ,ios::in | ios::out | ios::trunc); //以可读可写打开文件,文件不存在则创建,存在则清空文件内容
    if(!file3.is_open())
    {
        cout << "open file3 failed" << endl;
        exit(-1);
    }


    
    file1.seekg(0 , ios::end); //将文件1的读取指针定位到文件末尾
    int file1_size = file1.tellg(); //返回文件1的读取指针当前位置,即文件1的大小
    file1.seekg(0 , ios::beg); //将文件1的读取指针定位到文件开头

    char ch = 0;
    for(int i = 0 ; i < file1_size/2 ; i++)
    {
        file1.get(ch); //从文件1读取一个字符
        file2.put(ch); //将字符写入文件2
    }
    for(int i = file1_size/2 ; i < file1_size ; i++)
    {
        file1.get(ch); //从文件1读取一个字符
        file3.put(ch); //将字符写入文件3
    }

    
    file1.close();
    file2.close();
    file3.close();

    return 0;
}

该段程序实现的式将一个文件拆分成两个文件。seekg位移字节数,相对位置用于输入文件中指针的移动。tellg:用于查找输入文件中的文件指针位置。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐