美文网首页
C++基础一文通(六)STL

C++基础一文通(六)STL

作者: 熊爸天下_56c7 | 来源:发表于2022-08-12 08:42 被阅读0次

    一. STL 标准模板库

    • STL(Standard Template Library,标准模板库)
    • STL 从广义上分为: 容器(container) 算法(algorithm) 迭代器(iterator)
    • 容器算法之间通过迭代器进行无缝连接。
    • STL 几乎所有的代码都采用了模板类或者模板函数

    1. STL六大组件

    STL大体分为六大组件,分别是:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器

    1. 容器:各种数据结构,如vector、list、deque、set、map等,用来存放数据。
    2. 算法:各种常用的算法,如sort、find、copy、for_each等
    3. 迭代器:扮演了容器与算法之间的胶合剂。
    4. 仿函数:行为类似函数,可作为算法的某种策略。
    5. 适配器:一种用来修饰容器或者仿函数或迭代器接口的东西。
    6. 空间配置器:负责空间的配置与管理。

    2. STL中容器、算法、迭代器概念

    (1). 容器:置物之所也

    STL容器就是将运用最广泛的一些数据结构实现出来

    常用的数据结构:数组, 链表,树, 栈, 队列, 集合, 映射表 等

    这些容器分为序列式容器关联式容器两种:

    **序列式容器**:强调值的排序,序列式容器中的每个元素均有固定的位置。
    **关联式容器**:二叉树结构,各元素之间没有严格的物理上的顺序关系
    
    (2). 算法:问题之解法也

    有限的步骤,解决逻辑或数学上的问题,这一门学科我们叫做算法(Algorithms)

    算法分为:质变算法非质变算法

    质变算法:是指运算过程中会更改区间内的元素的内容。例如拷贝,替换,删除等等

    非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找、计数、遍历、寻找极值等等

    (3). 迭代器:容器和算法之间粘合剂

    提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该容器的内部表示方式。

    每个容器都有自己专属的迭代器

    迭代器使用非常类似于指针,初学阶段我们可以先理解迭代器为指针

    迭代器种类:

    种类 功能 支持运算
    输入迭代器 对数据的只读访问 只读,支持++、==、!=
    输出迭代器 对数据的只写访问 只写,支持++
    前向迭代器 读写操作,并能向前推进迭代器 读写,支持++、==、!=
    双向迭代器 读写操作,并能向前和向后操作 读写,支持++、--,
    随机访问迭代器 读写操作,可以以跳跃的方式访问任意数据,功能最强的迭代器 读写,支持++、--、[n]、-n、<、<=、>、>=

    常用的容器中迭代器种类为双向迭代器,和随机访问迭代器

    二. string容器

    1. 创建一个string

    构造函数原型:

    • string(); //创建一个空的字符串 例如: string str;
      string(const char* s); //使用字符串s初始化
    • string(const string& str); //使用一个string对象初始化另一个string对象
    • string(int n, char c); //使用n个字符c初始化
    #include <string>
    //string构造
    void test01()
    {
        string s1; //创建空字符串,调用无参构造函数
        cout << "str1 = " << s1 << endl;
    
        const char* str = "hello world";
        string s2(str); //把c_string转换成了string
    
        cout << "str2 = " << s2 << endl;
    
        string s3(s2); //调用拷贝构造函数
        cout << "str3 = " << s3 << endl;
    
        string s4(10, 'a');
        cout << "str3 = " << s3 << endl;
    }
    
    int main() {
    
        test01();
    
        system("pause");
    
        return 0;
    }
    

    2. string的赋值

    方法一 : 赋值
    方法二 : assign方法

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    void test01()
    {
        string str1;
        str1 = "hello world";
        cout << "str1 = " << str1 << endl;
    
        string str2;
        str2 = str1;
        cout << "str2 = " << str2 << endl;
    
        string str3;
        str3 = 'a';
        cout << "str3 = " << str3 << endl;
    
        string str4;
        str4.assign("hello c++");
        cout << "str4 = " << str4 << endl;
    
        string str5;
        str5.assign("hello c++",5);
        cout << "str5 = " << str5 << endl;
    
    
        string str6;
        str6.assign(str5);
        cout << "str6 = " << str6 << endl;
    
        string str7;
        str7.assign(5, 'x');
        cout << "str7 = " << str7 << endl;
    }
    
    int main() {
    
        test01();
        
        return 0;
    }
    

    3. string字符串拼接

    方法一 : 相加是拼接
    方法二 : append方法

    //字符串拼接
    void test01()
    {
      string str1 = "我";
    
      str1 += "爱玩游戏";
    
      cout << "str1 = " << str1 << endl;
      
      str1 += ':';
    
      cout << "str1 = " << str1 << endl;
    
      string str2 = "LOL DNF";
    
      str1 += str2;
    
      cout << "str1 = " << str1 << endl;
    
      string str3 = "I";
      str3.append(" love ");
      str3.append("game abcde", 4);
      //str3.append(str2);
      str3.append(str2, 4, 3); // 从下标4位置开始 ,截取3个字符,拼接到字符串末尾
      cout << "str3 = " << str3 << endl;
    }
    int main() {
    
      test01();
    
      system("pause");
    
      return 0;
    }
    

    4. string查找(find)和替换(replace)

    查找 : find
    替换 : replace

    //查找和替换
    void test01()
    {
        //查找
        string str1 = "abcdefgde";
    
        int pos = str1.find("de");
    
        if (pos == -1)
        {
            cout << "未找到" << endl;
        }
        else
        {
            cout << "pos = " << pos << endl;
        }
        
    
        pos = str1.rfind("de");
    
        cout << "pos = " << pos << endl;
    
    }
    
    void test02()
    {
        //替换
        string str1 = "abcdefgde";
        str1.replace(1, 3, "1111");
    
        cout << "str1 = " << str1 << endl;
    }
    
    int main() {
    
        //test01();
        //test02();
    
        system("pause");
    
        return 0;
    }
    

    5. string字符串比较

    字符串比较是按字符的ASCII码进行对比

    6. string字符存取

    方法一 : 按索引取值法
    方法二 : at方法

    void test01()
    {
        string str = "hello world";
    
        for (int i = 0; i < str.size(); i++)
        {
            cout << str[i] << " ";
        }
        cout << endl;
    
        for (int i = 0; i < str.size(); i++)
        {
            cout << str.at(i) << " ";
        }
        cout << endl;
    
    
        //字符修改
        str[0] = 'x';
        str.at(1) = 'x';
        cout << str << endl;
        
    }
    
    int main() {
    
        test01();
    
        system("pause");
    
        return 0;
    }
    

    7. string插入(insert)和删除(erase)

    插入 : insert
    删除: erase

        string str = "hello";
        str.insert(1, "111");
        cout << str << endl;
    
        str.erase(1, 3);  //从1号位置开始3个字符
        cout << str << endl;
    

    8. string切片 ( 子串 )

    用substr(起始索引, 长度);

    //子串
    void test01()
    {
        string str = "abcdefg";
        string subStr = str.substr(1, 3);
        cout << "subStr = " << subStr << endl;
    }
    
    int main() {
    
        test01();
        return 0;
    }
    

    三. Vector容器

    • vector数据结构和数组非常相似,也称为单端数组

    vector与普通数组区别:

    • 不同之处在于数组是静态空间,而vector可以动态扩展 ( 并不是在原空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝新空间,释放原空间 )

    1. vector的创建

    vector<T> v; //采用模板实现类实现,默认构造函数

    2. vector的赋值

    方法1 : =号赋值
    方法2 : assign(头,尾迭代器)
    方法3 : assign(多少个, 什么)

    #include <vector>
    
    void printVector(vector<int>& v) {
    
        for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
            cout << *it << " ";
        }
        cout << endl;
    }
    
    //赋值操作
    void test01()
    {
        vector<int> v1; //无参构造
        for (int i = 0; i < 10; i++)
        {
            v1.push_back(i);
        }
        printVector(v1);
        //
        vector<int>v2;
        v2 = v1;
        printVector(v2);
    
        vector<int>v3;
        v3.assign(v1.begin(), v1.end());
        printVector(v3);
    
        vector<int>v4;
        v4.assign(10, 100);
        printVector(v4);
    }
    
    int main() {
    
        test01();
    
        system("pause");
    
        return 0;
    }
    

    3. vector数据存取

    方法 说明
    []; 索引取值
    at(int idx); 索引取值
    front(); 第一个数据元素
    back(); 最后一个数据元素

    4. 容量和大小相关方法

    方法 说明
    empty(); 判断容器是否为空
    capacity(); 容器的容量
    size(); 返回容器中元素的个数
    resize(int num); 重新指定容器的长度为num,
    若容器变长,则以默认值填充新位置。
    如果容器变短,则末尾超出容器长度的元素被删除。
    resize(int num, elem); 重新指定容器的长度为num,
    若容器变长,则以elem值填充新位置。
    如果容器变短,则末尾超出容器长度的元素被删除

    5. vector的增删

    方法 说明
    push_back 尾插
    pop_back 尾删
    insert 插入
    erase (位置迭代器) 删除
    clear 清空
    #include <vector>
    
    void printVector(vector<int>& v) {
    
        for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
            cout << *it << " ";
        }
        cout << endl;
    }
    
    //插入和删除
    void test01()
    {
        vector<int> v1;
        //尾插
        v1.push_back(10);
        v1.push_back(20);
        v1.push_back(30);
        v1.push_back(40);
        v1.push_back(50);
        printVector(v1);
        //尾删
        v1.pop_back();
        printVector(v1);
        //插入
        v1.insert(v1.begin(), 100);
        printVector(v1);
    
        v1.insert(v1.begin(), 2, 1000);
        printVector(v1);
    
        //删除
        v1.erase(v1.begin());
        printVector(v1);
    
        //清空
        v1.erase(v1.begin(), v1.end());
        v1.clear();
        printVector(v1);
    }
    
    int main() {
    
        test01();
    
        return 0;
    }
    

    6. vector数据互换 swap

    #include <vector>
    
    void printVector(vector<int>& v) {
    
        for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
            cout << *it << " ";
        }
        cout << endl;
    }
    
    void test01()
    {
        vector<int>v1;
        for (int i = 0; i < 10; i++)
        {
            v1.push_back(i);
        }
        printVector(v1);
    
        vector<int>v2;
        for (int i = 10; i > 0; i--)
        {
            v2.push_back(i);
        }
        printVector(v2);
    
        //互换容器
        cout << "互换后" << endl;
        v1.swap(v2);
        printVector(v1);
        printVector(v2);
    }
    
    void test02()
    {
        vector<int> v;
        for (int i = 0; i < 100000; i++) {
            v.push_back(i);
        }
    
        cout << "v的容量为:" << v.capacity() << endl;
        cout << "v的大小为:" << v.size() << endl;
    
        v.resize(3);
    
        cout << "v的容量为:" << v.capacity() << endl;
        cout << "v的大小为:" << v.size() << endl;
    
        //收缩内存
        vector<int>(v).swap(v); //匿名对象
    
        cout << "v的容量为:" << v.capacity() << endl;
        cout << "v的大小为:" << v.size() << endl;
    }
    
    int main() {
    
        test01();
    
        test02();
    
        system("pause");
    
        return 0;
    }
    

    7. vector的遍历

    容器: vector

    算法: for_each

    迭代器: vector<int>::iterator

    示例:

    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    // vector遍历的回调函数
    void PrintItem(int val)
    {
        cout << val << endl;
    }
    
    int main()
    {
        /*-------------创建容器-------------------------*/
        //创建vector容器对象,并且通过模板参数指定容器中存放的数据的类型
        vector<int> v;
    
        //向容器中放数据
        v.push_back(10);
        v.push_back(20);
        v.push_back(30);
        v.push_back(40);
        v.push_back(50);
    
        //每一个容器都有自己的迭代器,迭代器是用来遍历容器中的元素
        // v.begin()返回迭代器,这个迭代器指向容器中第一个数据
        // v.end()返回迭代器,这个迭代器指向容器元素的最后一个元素的下一个位置
        // vector<int>::iterator 拿到vector<int>这种容器的迭代器类型
    
        /*-------------创建迭代器-------------------------*/
        vector<int>::iterator pBegin = v.begin();
        vector<int>::iterator pEnd = v.end();
    
        /*-------------遍历容器-------------------------*/
        //使用STL提供标准遍历算法  头文件 algorithm
        for_each(pBegin, pEnd, PrintItem);
    
        return 0;
    }
    

    其实我们也可以不用foreach 自己用循环操作迭代器来遍历

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    int main()
    {
        /*-------------创建容器-------------------------*/
        //创建vector容器对象,并且通过模板参数指定容器中存放的数据的类型
        vector<int> v;
    
        //向容器中放数据
        v.push_back(10);
        v.push_back(20);
        v.push_back(30);
        v.push_back(40);
        v.push_back(50);
    
        /*-------------创建迭代器-------------------------*/
        vector<int>::iterator pBegin = v.begin();
        vector<int>::iterator pEnd = v.end();
    
        /*-------------遍历容器-------------------------*/
        for (vector<int>::iterator it = pBegin; it != pEnd; it++)
        {
            cout << *it << endl;
        }
    
        return 0;
    }
    

    8. vector也可以存放 对象 / 地址 等

    #include <vector>
    #include <string>
    
    //自定义数据类型
    class Person {
    public:
        Person(string name, int age) {
            mName = name;
            mAge = age;
        }
    public:
        string mName;
        int mAge;
    };
    //存放对象
    void test01() {
    
        vector<Person> v;
    
        //创建数据
        Person p1("aaa", 10);
        Person p2("bbb", 20);
        Person p3("ccc", 30);
        Person p4("ddd", 40);
        Person p5("eee", 50);
    
        v.push_back(p1);
        v.push_back(p2);
        v.push_back(p3);
        v.push_back(p4);
        v.push_back(p5);
    
        for (vector<Person>::iterator it = v.begin(); it != v.end(); it++) {
            cout << "Name:" << (*it).mName << " Age:" << (*it).mAge << endl;
    
        }
    }
    
    
    //放对象指针
    void test02() {
    
        vector<Person*> v;
    
        //创建数据
        Person p1("aaa", 10);
        Person p2("bbb", 20);
        Person p3("ccc", 30);
        Person p4("ddd", 40);
        Person p5("eee", 50);
    
        v.push_back(&p1);
        v.push_back(&p2);
        v.push_back(&p3);
        v.push_back(&p4);
        v.push_back(&p5);
    
        for (vector<Person*>::iterator it = v.begin(); it != v.end(); it++) {
            Person * p = (*it);
            cout << "Name:" << p->mName << " Age:" << (*it)->mAge << endl;
        }
    }
    
    
    int main() {
    
        test01();
        
        test02();
    
        system("pause");
    
        return 0;
    }
    

    四. list 列表(链表)

    链表(list)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的

    list是一个线性链表结构,它的数据由若干个节点构成,每一个节点都包括一个信息块(即实际存储的数据)、一个前驱指针和一个后驱指针。它无需分配指定的内存大小且可以任意伸缩,这是因为它存储在非连续的内存空间中,并且由指针将有序的元素链接起来。

    list的优点:

    • 采用动态存储分配,不会造成内存浪费和溢出
    • 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素

    list的缺点:

    • 链表灵活,但是空间(指针域) 和 时间(遍历)额外耗费较大
    • 由于其结构的原因,list 随机检索的性能非常的不好,因为它不像vector那样直接找到元素的地址,而是要从头一个一个的顺序查找,这样目标元素越靠后,它的检索时间就越长。检索时间与目标元素的位置成正比。

    0. list和vector的区别

    • vector底层实现是数组;list是双向 链表。
    • vector支持随机访问,list不支持。
    • vector是顺序内存,list不是。
    • vector在中间节点进行插入删除会导致内存拷贝,list不会。
    • vector一次性分配好内存,不够时才进行2倍扩容;list每次插入新节点都会进行内存申请。
    • vector随机访问性能好,插入删除性能差;list随机访问性能差,插入删除性能好。
    • vector拥有一段连续的内存空间,因此支持随机访问,如果需要高效的随即访问,而不在乎插入和删除的效率,使用vector。
    • list拥有一段不连续的内存空间,如果需要高效的插入和删除,而不关心随机访问,则应使用list。

    1. list的创建

    list<T> lst; //采用模板实现类实现,默认构造函数

    2. list的赋值

    方法1 : =号赋值
    方法2 : assign(头,尾迭代器)
    方法3 : assign(多少个, 什么)

    3. list数据存取

    方法 说明
    front(); 第一个数据元素
    back(); 最后一个数据元素

    注意 : list容器中不可以通过[]或者at方式访问数据

    4. 容量和大小相关方法

    方法 说明
    empty(); 判断容器是否为空
    size(); 返回容器中元素的个数
    resize(int num); 重新指定容器的长度为num,
    若容器变长,则以默认值填充新位置。
    如果容器变短,则末尾超出容器长度的元素被删除。
    resize(int num, elem); 重新指定容器的长度为num,
    若容器变长,则以elem值填充新位置。
    如果容器变短,则末尾超出容器长度的元素被删除

    list没有容量的概念

    5. list的增删

    两端插入操作:

    • push_back(elem); //在容器尾部添加一个数据
    • push_front(elem); //在容器头部插入一个数据
    • pop_back(); //删除容器最后一个数据
    • pop_front(); //删除容器第一个数据

    指定位置操作:

    • insert(pos,elem); //在pos位置插入一个elem元素的拷贝,返回新数据的位置。
    • insert(pos,n,elem); //在pos位置插入n个elem数据,无返回值。
    • insert(pos,beg,end); //在pos位置插入[beg,end)区间的数据,无返回值。
    • clear(); //清空容器的所有数据
    • erase(beg,end); //删除[beg,end)区间的数据,返回下一个数据的位置。
    • erase(pos); //删除pos位置的数据,返回下一个数据的位置。
    • remove(elem); //删除容器中所有与elem值匹配的元素。

    多了一个remove

    6. list数据互换 swap

    同vector

    7. list的遍历

    容器: list

    算法: for_each

    迭代器: list<int>::iterator

    8. list的排序

    sort(iterator beg, iterator end) //对beg和end区间内元素进行排序

    9. list的翻转

    reverse(iterator beg, iterator end) //对beg和end区间内元素进行排序

    五. deque容器 (队列)

    • 双端数组,可以对头端进行插入删除操作

    deque与vector区别:

    • vector对于头部的插入删除效率低,数据量越大,效率越低
    • deque相对而言,对头部的插入删除速度回比vector快
    • vector访问元素时的速度会比deque快,这和两者内部实现有关
    • deque没有容量的概念

    0. 一般很少使用deque

    一般很少使用deque
    只是简单的存储元素使用vector即可,如果对元素任意位置进行插入或者删除操作比较多,使用list即可,所以一般很少使用deque;deque的最大应用,就是用其作为标准库中stack和queue的底层结构。

    关于deque的话了解即可,将重点放在vector、list、map、set等容器上即可。

    1. deque的创建

    deque<T> d; //采用模板实现类实现,默认构造函数

    2. deque的赋值

    方法1 : =号赋值
    方法2 : assign(头,尾迭代器)
    方法3 : assign(多少个, 什么)

    3. deque数据存取

    方法 说明
    []; 索引取值
    at(int idx); 索引取值
    front(); 第一个数据元素
    back(); 最后一个数据元素

    4. 容量和大小相关方法

    方法 说明
    empty(); 判断容器是否为空
    size(); 返回容器中元素的个数
    resize(int num); 重新指定容器的长度为num,
    若容器变长,则以默认值填充新位置。
    如果容器变短,则末尾超出容器长度的元素被删除。
    resize(int num, elem); 重新指定容器的长度为num,
    若容器变长,则以elem值填充新位置。
    如果容器变短,则末尾超出容器长度的元素被删除

    deque没有容量的概念

    5. deque的增删

    两端插入操作:

    • push_back(elem); //在容器尾部添加一个数据
    • push_front(elem); //在容器头部插入一个数据
    • pop_back(); //删除容器最后一个数据
    • pop_front(); //删除容器第一个数据

    指定位置操作:

    • insert(pos,elem); //在pos位置插入一个elem元素的拷贝,返回新数据的位置。

    • insert(pos,n,elem); //在pos位置插入n个elem数据,无返回值。

    • insert(pos,beg,end); //在pos位置插入[beg,end)区间的数据,无返回值。

    • clear(); //清空容器的所有数据

    • erase(beg,end); //删除[beg,end)区间的数据,返回下一个数据的位置。

    • erase(pos); //删除pos位置的数据,返回下一个数据的位置。

    6. deque数据互换 swap

    同vector

    7. deque的遍历

    容器: deque

    算法: for_each

    迭代器: deque<int>::iterator

    示例:

    #include <iostream>
    #include <deque>
    #include <algorithm>
    using namespace std;
    
    void printItem(int val)
    {
        cout << val << endl;
    }
    
    int main()
    {
        deque<int> v1;
        for (int i = 0; i < 10; i++)
            v1.push_back(i);
    
        for_each(v1.begin(), v1.end(), printItem);
        return 0;
    }
    

    8. deque的排序

    sort(iterator beg, iterator end) //对beg和end区间内元素进行排序

    #include <iostream>
    #include <deque>
    #include <algorithm>
    using namespace std;
    
    void printItem(int val)
    {
        cout << val << endl;
    }
    
    int main()
    {
        deque<int> d1;
        d1.push_back(5);
        d1.push_back(2);
        d1.push_back(3);
        d1.push_back(1);
        d1.push_back(4);
        
        sort(d1.begin(), d1.end());
    
        for_each(d1.begin(), d1.end(), printItem);
        return 0;
    }
    

    9. deque的翻转

    reverse(iterator beg, iterator end) //对beg和end区间内元素进行排序

    相关文章

      网友评论

          本文标题:C++基础一文通(六)STL

          本文链接:https://www.haomeiwen.com/subject/bjmjirtx.html