C++ STL篇

简介: STL大体分为六大组件:容器、算法、迭代器、仿函数、适配器、空间配置器- 容器:各种数据结构,如:vector、list、deque、set、map等,用来存放数据- 算法:各种常用算法,如:sort、find、copy、foreach等- 迭代器:扮演了容器和算法之间的胶合剂- 仿函数:行为类似函数,可作为算法的某种策略- 适配器:一种用来修饰容器、仿函数或迭代器接口的内容- 空间配置器:负责空间的配置与管理

1 STL

1.1 STL的诞生

C++面向对象和泛型编程思想,目的是提高复用性。为了建立数据结构和算法的一套标注,STL孕育而生。

1.2 STL基本概念

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

1.3 STL六大部件

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

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

1.4 容器概念

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

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

  • 序列式容器:强调值的排序,序列式容器中的每个元素都有固定的位置
  • 关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系

1.5 算法概念

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

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

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

1.6 迭代器概念

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

每个容器都有自己的专属迭代器,迭代器类似指针。

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

2 初识容器算法迭代器

2.1 vector存放内置数据类型

容器:vector

算法:for_each

迭代器:vector::iterator

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

void printfVector(int val){
    cout << val << " ";
}
/// 实现vector存放内置数据类型
void SaveInner(){
    //声明容器vector对象
    vector<int> zhangsan;
    //往容器内插入数据
    zhangsan.push_back(10);
    zhangsan.push_back(20);
    zhangsan.push_back(30);
    //通过迭代器访问容器中的数据
    //起始迭代器:begin()迭代器指向容器第一个元素
    vector<int>::iterator iBegin = zhangsan.begin();
    //结束迭代器:end()迭代器指向容器最后一个元素的下一个位置
    vector<int>::iterator iEnd = zhangsan.end();
    //方式一:遍历输出迭代器中所有内容
    while (iBegin != iEnd) {
        cout << *iBegin << " ";
        iBegin++;
    }
    cout << endl;

    //方式二:遍历输出迭代器中所有内容
    for(vector<int>::iterator it = zhangsan.begin();it != zhangsan.end();it++){
        cout << *it << " ";
    }
    cout << endl;

    //方式三:遍历输出迭代器中所有内容,for_each函数包含在algorithm头文件中
    //参数一:起始迭代器;参数二:结束迭代器;参数三:自定义处理函数
    for_each(zhangsan.begin(), zhangsan.end(), printfVector);
    cout << endl;
}

2.2 vector存放自定义数据类型

实现vector存放自定义数据类型

///实现vector存放自定义数据类型
void SaveOuter(){
    vector<Person> student;
    student.push_back(Person("张三",22));
    student.push_back(Person("李四",19));
    student.push_back(Person("王五",32));

    vector<Person>::iterator iBegin = student.begin();
    vector<Person>::iterator iEnd = student.end();
    //方式一
    while(iBegin != iEnd){
        cout << "name=" << iBegin->name << " " << "age=" << iBegin->age << endl;
        iBegin++;
    }
    //方式二
    for(vector<Person>::iterator it = student.begin(); it != student.end(); it++){
        //下述两种方式都可以
        cout << "name=" << it->name << " " << "age=" << it->age << endl;
        //cout << "name=" << (*it).name << " " << "age=" << (*it).age << endl;
    }
    //方式三
    for_each(student.begin(), student.end(), printfOuter);
}

实现vector存放自定义指针数据类型

下述声明的是Person 类型,当通过(it)取出当前vector内容,实际获取的是 Person *数据类型,所以后面接了一个->成员访问符;取出的就是声明的数据类型

///存放指针
void SaveOuterPointer(){
    vector<Person*> student;
    Person zhangsan("张三",22);
    Person lisi("李四",19);
    Person wangwu("王五",32);
    student.push_back(&zhangsan);
    student.push_back(&lisi);
    student.push_back(&wangwu);

    //其他两种方式,与上面类似
    for(vector<Person*>::iterator it = student.begin(); it != student.end();it++){
        cout << "name=" << (*it)->name << " " << "age=" << (*it)->age << endl;
    }
}

2.3 Vector容器嵌套

//遍历大vector容器内容
void printfVector(vector<int> v){
    //然后在通过一个for_each和lambda语法打印每个子vector中内容
    for_each(v.begin(), v.end(), [](int value) {
        cout << value << " ";
    });
    cout << endl;
}
//Vector容器嵌套
//Vector容器中在嵌套一个Vector
void NestVector(){
    //大vector容器
    vector<vector<int>> bigVector;
    //子vector容器
    vector<int> vector1;
    vector<int> vector2;
    //初始化子vector容器初始值
    for(int i=0; i<3; i++){
        vector1.push_back(i);
        vector2.push_back(i+1);
    }
    //将子vector容器使用尾插法插入大vector容器
    bigVector.push_back(vector1);
    bigVector.push_back(vector2);
    //使用alogrithm库中的for_each算法遍历大vector容器
    for_each(bigVector.begin(), bigVector.end(), printfVector);
}

3 string容器

本质:

  • string是C++风格的字符串,而string本质是一个类

string和char *的区别:

  • char *是一个指针
  • string是一个类,类内部封装了char 管理这个字符串,是一个char 型容器

特点:

  • string类内部封装了大量成员函数
  • 例如:查找find、拷贝copy、删除delete、替换replace、插入insert
  • string管理char *所分配的内存,不用担心复制越界和取值等,由类内部负责

3.1 string构造函数

string构造函数原型:

  • string(); //创建一个空的字符串;默认构造
  • string(const char *s); //使用字符串s进行初始化;有参构造
  • string(const string &str); //使用一个string对象初始化另一个string对象;拷贝构造
  • string(int n,char c); //使用n个字符c初始化c
void stringTest01(){
    //默认构造函数
    string zhangsan;

    //有参构造
    const char *s = "李四";
    string lisi(s);
    cout << lisi << endl;

    //拷贝构造函数
    string wangwu(lisi);
    cout << wangwu << endl;

    string zhaoer(5,'a');
    cout << zhaoer << endl;
}

3.2 string赋值操作

赋值函数原型:

  • string& operator =(const char s); //char s类型赋值给当前字符串
  • string& operator =(const string &s); //字符串s赋值给当前字符串
  • string& operator =(char c); //字符c赋值给当前字符串
  • string& assign (const char *s);//字符串s赋值给当前字符串
  • string& assign (const char *s,int n);//字符串s的前n个字符赋值给当前字符串
  • string& assign (const string &s);//字符串s赋值给当前字符串
  • string& assign (int n,char c); //将n个字符c赋值给当前字符串
void stringTest02(){
    //原型:string& operator =(const char *s);
    const char *hello = "hello";
    string str1 = hello;
    cout << str1 << endl;

    //原型:string& operator =(const string &s);
    string str2 = str1;
    cout << str2 << endl;

    //原型:string& operator =(char c);
    char c = 'a';
    string str3;
    str3 = c;
    cout << str3 << endl;

    //原型:string& assign (const char *s);
    string str4;
    str4.assign(hello);
    cout << str4 << endl;

    //原型:string& assign (const char *s,int n);
    string str5;
    str5.assign(hello,2);
    cout << str5 << endl;

    //原型:string& assign (const string &s);
    string str6;
    str6.assign(str5);
    cout << str6 << endl;

    //原型:string& assign (int n,char c);
    string str7;
    str7.assign(5,c);
    cout << str7 << endl;
}

3.3 string字符串拼接

拼接函数原型:

  • string& operator +=(const char *s);
  • string& operator +=(const char c);
  • string& operator +=(const string &s);
  • string& append(const char *s); //将字符串s拼接到当前字符串末尾
  • string& append(const string &s,int n); //将字符串s的前n个字符拼接到当前字符串末尾
  • string& append(const string &s,int pos,int n); //将字符串s第pos位置开始之后的n个字符拼接到当前字符串末尾
void stringTest03(){
    const char *hello = "hello";
    const char c = 'c';

    //原型:string& operator +=(const char *s);
    string str1("lisi");
    str1 += hello;
    cout << str1 << endl;

    //原型:string& operator +=(const char c);
    string str2("wangwu");
    str2 += c;
    cout << str2 << endl;

    //原型:string& operator +=(const string &s);
    string str3("zhaoer");
    str3 += str2;
    cout << str3 << endl;

    //原型:string& append(const char *s);
    string str4("start");
    str4.append(hello);
    cout << str4 << endl;

    //原型:string& append(const string &s,int n);
    string str5("start");
    str5.append(hello,2);
    cout << str5 << endl;

    //原型:string& append(const string &s,int pos,int n);
    string str6("start");
    str6.append(hello,2,2);
    cout << str6 << endl; //startll
}

3.4 string查找和替换

描述:

  • 查找:查找指定字符串是否存在
  • 在指定的位置替换字符串

函数原型:

  • int find(const string &str,int pos = 0) const; //查找str第一次出现位置,从pos位置开始查找
  • int find(const char *s,int pos = 0) const; //查找r第一次出现位置,从pos位置开始查找
  • int find(const char *s,int pos,int n) const; //从pos位置查找字符串s的前n个字符第一次出现的位置
  • int find(const char c,int pos = 0) const; //查找字符c第一次出现位置,从pos位置开始查找
  • int rfind(const string &str,int pos = npos) const; //查找str最后一次出现位置,从pos位置开始查找
  • int rfind(const char *s,int pos = npos) const; //查找s最后一次出现位置,从pos位置开始查找
  • int rfind(const char *s,int pos,int n) const; //从pos位置查找字符串s的前n个字符最后一次出现的位置
  • int rfind(const char c,int pos = 0) const; //查找字符c最后一次出现位置,从pos位置开始查找
  • int replace(int pos,int n,const string &str); //将当前字符串的第pos位置开始的n个字符替换成字符串str
  • int replace(int pos,int n,const char *s);//将当前字符串的第pos位置开始的n个字符替换成字符串s
void stringTest04(){
    string str = "hello c++,I'm liszt";

    //原型:int find(const string &str,int pos = 0) const;
    string str1 = "c++";
    int pos1 = str.find(str1);
    cout << pos1 << endl;//6

    //原型:int find(const char *s,int pos = 0) const;
    const char *liszt = "liszt";
    int pos2 = str.find(liszt);
    cout << pos2 << endl;//14

    //原型:int find(const char *s,int pos,int n) const;
    int pos3 = str.find(liszt,0,1);
    cout << pos3 << endl;//2

    //原型:int replace(int pos,int n,const string &str);
    string str2 = "franz";
    str.replace(14, str2.size(), str2);//hello c++,I'm franz
    cout <<"替换:" << str << endl;

    //原型:int replace(int pos,int n,const char *s);
    const char *franz = "hhhhh";
    str.replace(0, strlen(franz), franz);
    cout <<"替换:" << str << endl;//hhhhh c++,I'm franz
}

3.5 string字符串比较

比较方式:

  • 字符串比较是按字符ASIIC码进行对比

返回结果:

  • 相等,返回0
  • 大于,返回第一个相异字符的ASCII码值之差(正数)
  • 小于,返回第一个相异字符的ASCII码值之差(负数)

函数原型:

  • int compare(const string &str) const;
  • int compare(const char *s) const;
void stringTest05(){
    string str1("bda");

    string str2("bx");
    int result1 = str1.compare(str2);
    cout << "result=" << result1 << endl; //-20,d的ASCII码值减x的ASCII码值

    const char *s = "ba";
    int result2 = str1.compare(s);
    cout << "result=" << result2 << endl; //3,d的ASCII码值减a的ASCII码值

    int result3 = str1.compare("bda");
    cout << "result=" << result3 << endl; //0
}

3.6 string字符存取

存取方式包括两种:

  • char& operator;
  • char & at(int n);

3.7 string插入和删除

函数原型:

  • string& insert(int pos,const char *s);
  • string& insert(int pos,const string &s);
  • string& insert(int pos,int n,char c);
  • string& erase(int pos,int n = npos); //删除从pos开始的n个字符
void stringTest06(){
    string str = "hello world!";
    string insertContent = "c++";
    //原型:string& insert(int pos,const char *s);
    str.insert(0,insertContent);
    cout << str << endl;

    //原型:string& insert(int pos,int n,char c);
    str.insert(8, 1,'x');
    cout << str << endl;

    //原型:string& erase(int pos,int n = npos);
    str.erase(8,1);
    cout << str << endl;
}

3.8 string子串

描述:从字符串中截取一部分子串并返回

函数原型:

  • string substr(int pos = 0,int n = npos); //返回从字符串第pos位置开始的n个字符
void stringTest07(){
    string str = "hello world!";

    string sub = str.substr(6,5);
    cout << sub << endl;//world
}

4 vector容器

4.1 vector概念

vector与数组非常类似,称为单端数组

与普通数组的区别:

  • 不同之处在于数组是静态空间,而vector可以动态扩展
  • 动态扩展:并不是在原空间之间继续扩展,而且寻找一片更大的内存空间,然后将原数据拷贝到新空间内,在释放原空间
  • vector容器迭代器是支持随机访问的迭代器

函数原型:

  • vector v;
  • vector v1(v.begin(),v.end()); //[begin,end),左闭右开区间内的元素拷贝给本身
  • vector v1(n,elem); //将n个elem拷贝给本身
  • vector v1(const vector &v); //拷贝构造函数
void vectorTest1(){
    //默认构造,原型:vector<T> v
    vector<int> v1;
    for(int i=0; i<5; i++) v1.push_back(i);
    printfVectorInt(v1);

    //通过区间内容进行构造,原型:vector(v.begin(),v.end());
    vector<int> v2(v1.begin(),v1.end());
    printfVectorInt(v2);

    //原型:vector(n,elem);
    vector<int> v3(5,v1[0]);
    printfVectorInt(v3);

    //拷贝构造,原型:vector v1(const vector &v);
    vector<int> v4(v3);
    printfVectorInt(v4);
}

4.2 vector赋值操作

函数原型:

  • vector& operator =(const vector &v);
  • assign(beg,end);//左闭右开区间内元素拷贝给自身
  • assign(n,elem); //将n个elem拷贝复制给本身
void vectorTest2(){
    vector<int> v1;
    for(int i=0; i<5; i++) v1.push_back(i);
    printfVectorInt(v1);

    //原型:vector& operator =(const vector &v);
    vector<int> v2 = v1;
    printfVectorInt(v2);

    //原型:assign(beg,end);
    vector<int> v3;
    v3.assign(v2.begin(), v2.end());
    printfVectorInt(v3);

    //原型:assign(n,elem);
    vector<int> v4;
    v4.assign(5,v3[0]);
    printfVectorInt(v4);
}

4.3 vector容量和大小

函数原型:

  • empty(); //判断容器是否为空
  • capacity(); //容器容量
  • size(); //返回容器中元素个数
  • resize(int num); //重新指定容器长度为num,若容器变长,则以默认值填充新位置;如果容器变短,则末尾超出容器的长度的元素被删除;
  • resize(int num,elem); //重新指定容器长度为num,若容器变长,则以elem填充新位置;如果容器变短,则末尾超出容器的长度的元素被删除;
void vectorTest3(){
    vector<int> v1;
    for(int i=0; i<5; i++) v1.push_back(i);
    printfVectorInt(v1);

    //判断vector是否为空
    if(v1.empty()){
        cout << "vector为空" << endl;
    }else{
        cout << "vector容量=" << v1.capacity() << endl;
        cout << "vector元素个数=" << v1.size() << endl;
    }

    //容器变长,新位置插入默认值0,因为是int型
    v1.resize(7);
    printfVectorInt(v1);

    //容器变短,尾部超出vector长度,则删除默认元素
    v1.resize(3);
    printfVectorInt(v1);

    //容器变长,并新位置用插入5
    v1.resize(8,5);
    printfVectorInt(v1);
}

4.4 vector插入和删除

函数原型:

  • push_back(elem); //在尾部插入
  • pop_back(); //删除最后一个元素
  • insert(const_iterator pos,ele); //迭代器指向的位置pos插入元素ele,其余位置向后移动,空出一个位置
  • insert(const_iterator pos,int count,ele); //迭代器指向的位置pos插入n个元素ele
  • erase(const_iterator pos); //删除迭代器指向的pos位置元素
  • erase(const_iterator start,const_iterator end);//删除迭代器[start,end)区域的元素
  • clear(); //删除容器所有元素

4.5 vector数据存取

函数原型:

  • at(int index);
  • operator[index];
  • front(); //返回容器中第一个数据元素
  • back(); //返回容器中最好一个数据元素

4.6 vector互换容器

函刷原型:

  • swap(vec); //将vec与本身的元素进行互换

当一个vector容器初始化的时候容量很大,但通过需求使用resize()将原空间大幅度缩减,但是容量并不会减少,就会产生空间浪费,此时可以使用swap创建一个匿名对象交换vector容器,交换后的容量将会与resize()缩减后的容量匹配;因为匿名对象处理完之后就会被回收,所以不必担心内存泄露。

vector (v).swap(v);

4.7 vector预留空间

描述:减少vector在动态扩展容量时的扩展次数

函数原型:

  • reserve(int len); //容器预留len个元素长度,预留位置不能初始化,元素不能被访问

如果事先知道了需要的容量并且较大,则可以通过reserve进行预留空间
防止多次动态扩展空间,通过reserve预留空间之后,开辟次数则变为一次(量级匹配)

void vectorTest6(){
    vector<int> v1;
    v1.reserve(100);
    int *p = NULL;
    int count = 0;
    for(int i=0; i<100; i++) {
        v1.push_back(i);
        if(p != &v1[0]){
            p = &v1[0];
            count++;
        }
    }
    cout << "开辟了" << count << "次空间" << endl;
}

5 deque容器

5.1 deque容器基本概念

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

deque与vector的区别:

  • vector对于头部的插入删除效率低,数据量越大,效率越低
  • deque相对而言,对头部的插入删除速度比vector快
  • vector访问元素速度会比deque快,与其内部实现有关

deque内部工作原理:

deque内部有一个中控器,维护每段缓冲区的内容,缓冲区中存放真实数据

中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间

  • deque容器的迭代器支持随机访问

5.2 deque构造函数

函数原型:

  • deque deq;
  • deque(beg,end);
  • deque(n,elem);
  • deque(const deque &deq);
void dequeTest1(){
    deque<int> deq1;
    //从头部添加数据
    for(int i=0; i<5;i++){
        deq1.push_front(i);
    }
    //从尾部添加数据
    for(int i=5; i<10;i++){
        deq1.push_back(i);
    }
    printf(deq1);//4,3,2,1,0,5,6,7,8,9,

    //区间元素赋值给deque容器本身
    deque<int> deq2(deq1.begin(),deq1.end());
    printf(deq2);//4,3,2,1,0,5,6,7,8,9,

    deque<int> deq3(deq1.size(),deq1[0]);
    printf(deq3);//4,4,4,4,4,4,4,4,4,4,

    //拷贝构造函数
    deque<int> deq4(deq3);
    printf(deq4);//4,4,4,4,4,4,4,4,4,4,
 }

5.3 deque赋值操作

函数原型:

  • deque operator =(const deque &deq);
  • assign(beg,end);
  • assign(n,elem);

5.4 deque大小操作

函数原型:

  • deque.empty();
  • deque.size();
  • deque.resize(num);//重新指定容器长度为num,若容器变长,则以默认值填充新位置;如果容器变短,则末尾超出容器的长度的元素被删除;
  • deqeue.resize(num,elem);

5.5 deque插入和删除

函数原型:

  • 两端插入操作:

    • push_back(elem);//尾法

    • push_front(elem);//头插

    • pop_back();//尾删

    • pop_front();//头删

  • 指定位置操作:

    • insert(pos,elem);

    • insert(pos,n,elem);

    • insert(pos,beg,end);

    • clear();

    • erase(beg,end);

    • erase(pos);

void dequeTest2(){
    deque<int> deq1;
    //从头部添加数据
    for(int i=5; i>0;i--){
        deq1.push_front(i);
    }
    //从尾部添加数据
    for(int i=6; i<=10;i++){
        deq1.push_back(i);
    }
    printf(deq1);//1,2,3,4,5,6,7,8,9,10,

    //头删
    deq1.pop_front();
    printf(deq1);//2,3,4,5,6,7,8,9,10,

    //尾删
    deq1.pop_back();
    printf(deq1);//2,3,4,5,6,7,8,9,

    //指定位置插入
    deq1.insert(deq1.begin(), 1);
    printf(deq1);//1,2,3,4,5,6,7,8,9,

    //在指定位置插入n次element元素
    deq1.insert(deq1.begin(),2,0);
    printf(deq1);//0,0,1,2,3,4,5,6,7,8,9,

    deque<int> deq2;
    deq2.push_back(10);
    deq2.push_back(11);

    //将deq2区间内元素通过尾插到deq1中
    deq1.insert(deq1.end(), deq2.begin(),deq2.end());
    printf(deq1);//0,0,1,2,3,4,5,6,7,8,9,10,11,

    deque<int>::iterator it = deq1.begin();
    //指针向下移动一个位置
    it++;
    //删除指定位置元素,需要迭代器作为参数
    deq1.erase(it);//删除之后,指针相当于向前移动一个位置
    printf(deq1);//0,1,2,3,4,5,6,7,8,9,10,11,


    //范围性删除,左闭右开
    deq1.erase(it,it+5);
    printf(deq1);//5,6,7,8,9,10,11,

    //清空容器内元素
    deq1.clear();
    printf(deq1);
}

5.6 deque 数据存取

函数原型:

  • at(int index);
  • operator [] (int indext);
  • front(); //返回容器中第一个数据元素
  • back(); //返回容器中最后一个数据元素

5.7 deque排序

函数原型:

  • sort(iterator beg,iterator end); //默认排序是升序

6 stack容器

6.1 stack基本概念

概念:

  • stack是一种先进后出(First In Last Out)的数据结构

  • 尾部称为栈底,头部称为栈顶;

  • stack是一种受限序列,只允许在栈顶进行插入和删除
  • 栈内插入数据称为入栈,栈内删除数据称为出栈

6.2 stack常用接口

  • 构造函数:

    • stack stack;

    • stack(const stack &s); //拷贝构造函数

  • 赋值操作:

    • stack& operator = (const stack &s);
  • 数据存取:

    • push(elem); //栈顶插入元素

    • pop(); //栈顶删除元素

    • top(); //返回栈顶元素

  • 大小操作:

    • empty(); //判断栈是否为空

    • size(); //返回栈的大小

7 queue容器

7.1 queue 基本概念

概念:

  • queue是一种先进先出(First In First Out)的数据结构,允许在两端进行操作
  • queue只允许在队尾进行插入,队头进行删除
  • 队内插入数据称为入队,队内删除数据称为出队

7.2 queue 常用接口

  • 构造函数:

    • queue que;

    • queue(const queue &s); //拷贝构造函数

  • 赋值操作:

    • queue& operator = (const queue &q);
  • 数据存取:

    • push(elem); //队尾插入元素

    • pop(); //队头删除元素

    • back(); //返回队内第一个元素元素

    • top(); //返回队内最后一个元素元素
  • 大小操作:

    • empty(); //判断队是否为空

    • size(); //返回队的大小

8 list容器

8.1 list基本概念

描述:

  • 使用链式存储
  • 物理存储单元非连续,通过额外的指针记录元素之间的关系
  • 一个数据结点由数据域和指针域组成
  • STL的链表是一个双向循环链表
  • 链表的迭代器属于双向迭代器

插入和删除操作不会造成原有list迭代器的实效(在list中删除一个数据记录,非当前迭代器所指位置,则不会对迭代器造成影响),这在vector不成立

优点:

  • 采用动态存储分配,不会造成内存的浪费和溢出
  • 链表对插入和删除操作十分便利

缺点:

  • 空间(指针域)和时间(遍历)额外耗费较大

8.2 list构造函数

函数原型:

  • list list;
  • list;
  • list(n,elem);
  • list(const list &l);

8.3 list赋值和交换

函数原型:

  • assign(beg,end);
  • assign(n,elem);
  • list& operator = (const list &l);
  • swap(list);

8.4 list大小操作

函数原型:

  • size();
  • empty();
  • resize(num);
  • resize(num,elem);

8.5 list插入和删除

函数原型:

  • 两端插入操作:

    • push_back(elem);//尾法

    • pop_back();//尾删

    • push_front(elem);//头插

    • pop_front();//头删

  • 指定位置插入操作:

    • insert(pos,elem);
  • insert(pos,n,elem);
  • insert(pos,beg,end);
  • 删除操作:

    • clear();
  • erase(beg,end);
  • erase(pos);
  • remove(elem); //删除容器中所有与elem匹配的元素
void listTest1(){
    list<int> l;
    for(int i=5; i<=10; i++) l.push_back(i);//尾插
    for(int i=4; i>=0; i--) l.push_front(i);//头插
    printfList(l);//0 1 2 3 4 5 6 7 8 9 10

    l.pop_front();//头删
    printfList(l);//1 2 3 4 5 6 7 8 9 10
    l.pop_back();//尾删
    printfList(l);//1 2 3 4 5 6 7 8 9

    list<int>::iterator it = l.begin();
    l.insert(it, 0);//在第一个元素位置插入一个0
    printfList(l);//0 1 2 3 4 5 6 7 8 9

    l.erase(it);//因为上述插入操作在第一个位置进行插入,完成后迭代器指针后移,所以此时删除的是第二个元素位置的内容
    printfList(l);//0 2 3 4 5 6 7 8 9

    l.remove(5); //删除容器内所有与elemnt匹配的元素
    printfList(l);//0 2 3 4 6 7 8 9

    l.clear(); //清空容器内所有元素
}

8.6 list数据存取

函数原型:

  • front(); //返回容器内第一个元素
  • back(); //返回容器内最后一个元素

8.7 list反转和排序

函数原型:

  • reverse(); //反转链表
  • sort(); //链表排序
bool compare(int a,int b){
    return a>b;
}
void listTest3(){
    list<int> l;
    l.push_back(20);
    l.push_back(10);
    l.push_back(40);
    l.push_back(30);

    l.sort();//默认从小到大升序排序
    printfList(l);

    //自定义一个函数,在其中实现降序定义,例如第一个数大于第二个数为真,则为降序
    l.sort(compare);
    printfList(l);
}

对自定义数据类型进行排序

class Student{
    string name;
    int age;
public:
    Student(string name,int age){
        this->name = name;
        this->age = age;
    }

    string getName(){
        return this->name;
    }

    int getAge(){
        return this->age;
    }
};
void printfStudent(list<Student> &l){
    for_each(l.begin(), l.end(), [](Student stu){
        cout << "名字=" << stu.getName() << " " << "年龄=" << stu.getAge() << endl;
    });
    cout << endl;
}

//升序
bool StuCompare(Student &stu1,Student &stu2){
    return stu1.getAge() < stu2.getAge();
}

void listTest4(){
    list<Student> stus;
    stus.push_back(Student("张三",20));
    stus.push_back(Student("李四",40));
    stus.push_back(Student("王五",10));
    stus.push_back(Student("赵二",30));

    stus.sort(StuCompare);
    printfStudent(stus);
}

9 set 容器和multiset

9.1 简述

基本概念:

  • 所有元素都会在插入时自动被排序
  • set/multiset属于关联式容器,底层结构是用二叉树实现

set/multiset的区别:

  • set不允许容器中有重复的元素,如果插入重复的元素,set会默认忽视此元素

  • multiset允许容器中有重复的元素

    9.2 set构造和赋值

    构造:

    • set st;
    • set(const set &st);

    赋值:

    • set& operator =(const set &st);
    void setTest1(){
        //默认构造函数
        set<int> s1;
        for(int i=0; i<50; i+=10){
            s1.insert(i);
        }
        printfSet(s1);//0 10 20 30 40
    
        ///set容器会对插入的元素进行默认排序且不允许出现重复元素
        ///如果插入的重复元素,set会自动忽视这个元素,则不进行插入
        set<int> s2;
        s2.insert(20);
        s2.insert(0);
        s2.insert(10);
        s2.insert(40);
        s2.insert(30);
        printfSet(s2);//0 10 20 30 40
    
        //拷贝构造函数
        set<int> s3(s2);
        printfSet(s3);//0 10 20 30 40
    
        //赋值
        set<int> s4 = s3;
        printfSet(s3);//0 10 20 30 40
    }
    
    int main(int argc, const char * argv[]) {
        setTest1();
        return 0;
    }
    

9.3 set大小和交换

函数原型:

  • size();
  • empty();
  • swap(st);

9.4 set插入和删除

函数原型:

  • insert(elem);
  • clear();
  • erase(pos);
  • erase(beg,end);
  • erase(elem);

9.5 set查找和统计

  • find(key); //若key存在,则返回该key的元素迭代器;反之,返回end()迭代器
  • count(key);//统计key的元素个数,对于set容易不允许插入重复元素,故结果只在0和1之间

9.6 pair 对组容器

描述:

  • 成对出现的数据,利用对组可以返回两个数据

创建方式:

  • pari p(value1,value2);
  • pair p = make_pair(value1,value2);

9.7 set容器排序

描述:

set默认插入排序规则是从小到大,可以通过仿函数进行改变排序规则

class MyCompare{
public:
    bool operator()(int a,int b){
        return a>b;
    }
};
...
void setTest2(){
    set<int> s1;
    //默认从小到大
    for(int i=0; i<50; i+=10){
        s1.insert(i);
    }
    printfSet(s1);

    //通过仿函数,改变排序规则,从大到小
    set<int,MyCompare> s2;
    for(int i=0; i<50; i+=10){
        s2.insert(i);
    }
    printfSet(s2);
}

9.8 改变自定义数据类型set排序规则

通过将自定义数据类型Student的进行排序,按其成员字段age从大到小进行降序排序

class Student{
public:
    string name;
    int age;

    Student(string name,int age){
        this->name = name;
        this->age = age;
    }
};
...
class MyCompare{
public:
    bool operator()(Student a,Student b){
        return a.age > b.age;
    }
};
...
void setTest3(){
    set<Student,MyCompare> s1;
    s1.insert(Student("张三",20));
    s1.insert(Student("李四",10));
    s1.insert(Student("王五",40));
    s1.insert(Student("赵二",30));

    printfSet(s1);
}

10 map和multimap容器

10.1 map基本概念

描述:

  • map的所以元素都是pair
  • pair中第一个元素为key-键值,起到索引作用;第二个元素为value-实值
  • 所有元素都会根据元素的键值自动排序
  • map/multimap属于关联式容器,底层结果使用二叉树实现

优点:

  • 根据快速根据key值找到value值

map/multimap区别

  • map不允许容器中重复的key值元素
  • multimap允许容器中重复的key值元素

10.2 map构造和赋值

函数原型:

  • 构造:

    • map mp;

    • map(const map &mp);

  • 赋值

    • map & operator = (const map &mp);

10.3 map大小和交换

函数原型:

  • size();
  • empty();
  • swap(st);

10.4 map 插入和删除

函数原型:

  • insert(elem);
  • clear();
  • erase(pos);
  • erase(begin,end);
  • erase(key);
void printfMap(map<string,int> &m){
    for_each(m.begin(), m.end(), [](pair<string, int> value){
        cout << "name=" << value.first << " " << "age=" << value.second << endl;
    });
}
void mapTest1(){
    map<string,int> map1;
    ///下列四种方式都可以实现插入map数据
    ///默认通过key值进行升序排序
    map1.insert(pair<string, int>("peter",12));
    map1.insert(make_pair("jerry", 24));
    map1.insert(map<string,int>::value_type("liszt",30));
    //若执行map1["www"];没有找到"www"所管理的值,则会默认创建一个以“www”为key值的默认数据类型值的数据
    map1["franz"] = 7;
    printfMap(map1);

    //通过key值进行删除
    map1.erase("jerry");
    printfMap(map1);
}

10.5 map查找和统计

函数原型:

  • find(key);
  • count(key);

10.6 map排序

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

class MyCompare{
public:
    bool operator()(string a, string b){
        return a > b;
    }
};

void printfMap(map<string,int,MyCompare> &m){
    for_each(m.begin(), m.end(), [](const pair<string, int> &value){
        cout << "name=" << value.first << " " << "age=" << value.second << endl;
    });
}

void mapTest2(){
    map<string,int,MyCompare> map1;
    map1.insert(make_pair("jack", 14));
    map1.insert(make_pair("jerry", 24));
    map1.insert(make_pair("liszt", 4));
    printfMap(map1);
}

int main(int argc, const char * argv[]) {
    mapTest2();
    return 0;
}

11 函数对象

11.1 函数对象

概念:

  • 重载函数调用操作符的类,其对象称为函数对象
  • 函数对象使用重载的()时,行为类似函数调用,也称为仿函数
  • 函数对象(仿函数)是一个类,不是一个函数

特点:

  • 函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值
  • 函数对象超出普通函数的概念,函数对象可以有自己的状态
  • 函数对象可以作为参数传递
class MyAdd{
public:
    int operator() (int a, int b){
        return a+b;
    }
};
///函数对象可以作为参数传递
void doAdd(MyAdd &add){
    cout << "result=" << add(20,20) << endl;
}
void test1(){
    //构建函数对象
    MyAdd add;
    cout << "result=" << add(10,20) << endl;
    doAdd(add);
}

11.2 谓词

概念:

  • 返回bool类型的仿函数称为谓词
  • 如果operator()接受一个参数,称为一元谓词
  • 如果operator()接受俩个参数,称为二元谓词
///一元谓词
bool FindNumber(int a){
    return a > 5;
}
void test2(){
    vector<int> v1;
    for(int i=0; i<10; i++){
        v1.push_back(i);
    }
    ///find_if如果条件成立,则返回元素迭代器位置;未找到,则返回end()迭代器
    vector<int>::iterator it = find_if(v1.begin(), v1.end(),FindNumber);

    if(it == v1.end()){
        cout << "没有大于5的数字" << endl;
    }else{
        cout << "result=" << *it << endl;
    }
}

11.3 内建函数对象

分类:

  • 算术仿函数
  • 关系仿函数
  • 逻辑仿函数
  • 引用时,需要导入#include

11.3.1 算术仿函数

功能描述:

  • 实现四则运算
  • 其中negate是一元运算,其他都是二元运算

仿函数原型:

  • template T plus //加法仿函数
  • template T minus //减法仿函数
  • template T multiplies //乘法仿函数
  • template T divides //除法仿函数
  • template T modulus //取模仿函数
  • template T negate //取反仿函数
///取反反函数
void test3(){
    negate<int> n;
    cout << "50的相反数=" << n(50) << endl;
 }

///加法仿函数
void test4(){
    plus<int> p1;

    cout << "10 + 20 = " << p1(10,20) << endl;
}

11.3.2 关系仿函数

仿函数原型:

  • template bool equal //等于
  • template bool not_equal //不等于
  • template bool greater //大于
  • template bool greater_equal //大于等于
  • template bool less //小于等于
  • template bool less_equal //小于等于
void test5(){
    vector<int> v1;
    v1.push_back(10);
    v1.push_back(5);
    v1.push_back(20);

    //使用内置的greater仿函数,作为使用降序
    sort(v1.begin(), v1.end(), greater<int>());

    for_each(v1.begin(), v1.end(), [](int num){
        cout << num << " ";
    });
    cout << endl;
}

11.3.3 逻辑仿函数

仿函数原型:

  • template bool logical_and //逻辑与
  • template bool logical_or //逻辑或
  • template bool logical_not //逻辑非
void test01()
{
    vector<bool>v;
    v.push_back(true);
    v.push_back(true);
    v.push_back(false);
    v.push_back(true);
    v.push_back(false);

    for (vector<bool>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;

    //利用逻辑非    将容器v搬运到    容器v2中,并执行取反操作
    vector<bool>v1;
    v1.resize(v.size());
    // transform  必须先开辟空间指定大小v1.resize(v.size()); 在执行搬运
    transform(v.begin(), v.end(), v1.begin(), logical_not<bool>());

    for (vector<bool>::iterator it = v1.begin(); it != v1.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}

12 常用算法

概述:

  • 算法主要由头文件、、组成
  • 是STL中头文包含最广的之一,涉及范围包括:比较、交换、查找、遍历、复制、修改等
  • 包括几个在序列上进行简单运算的模版函数
  • 包括函数对象等模版类

12.1 常用遍历算法

描述:

  • for_each //遍历容器
  • transform //搬运容器到另一个容器中

12.1.1 for_each

函数原型:

for_each(iterator beg,iterator end,_func);

12.1.2 transform

函数原型:

  • transform(iterator beg1,iterator end1,iterator beg2,_func);
class MyTransform{
public:
    int operator()(int a){
        return a;
    }
};

void printf(vector<int> &v){
    for_each(v.begin(), v.end(), [](int value){
        cout << value << " ";
    });
    cout << endl;
}
void test1(){
    vector<int> v1;
    v1.push_back(10);
    v1.push_back(20);
    v1.push_back(30);


    vector<int> v2;
    //需要给目标容器开辟空间
    v2.resize(v1.size());
    transform(v1.begin(), v1.end(), v2.begin(),MyTransform());
    printf(v2);
}

12.2 常用查找算法

描述:

  • find //查找元素
  • find_if //按条件查找元素
  • adjacent_find //查找相邻元素
  • binary_search //二分查找法
  • count //统计元素个数
  • count_if //按条件统计元素个数

12.2.1 find

函数原型:

  • find(iterator beg,iterator end,value);

查找内置数据类型:

void test2(){
    vector<int> v1;
    for(int i=0;i<5;i++){
        v1.push_back(i);
    }
    //如果找到这个元素,则返回key的迭代器位置;否则,容器的end()迭代器
    vector<int>::iterator it =  find(v1.begin(), v1.end(),3);
    if(it != v1.end()){
        cout << "success" << endl;
    }else{
        cout << "failed" << endl;
    }
}

查找自定义数据类型:

class Student{

public:
    string name;
    int age;
    Student(string name,int age){
        this->name = name;
        this->age = age;
    }

    bool operator == (const Student &stu){
        return (this->name == stu.name) && (this->age == stu.age);
    }
};
...
void test3(){
    vector<Student> stus;
    Student zhangsan("张三",20);
    Student lisi("李四",30);
    Student wangwu("王五",40);
    stus.push_back(zhangsan);
    stus.push_back(lisi);
    stus.push_back(wangwu);

    ///对自定义数据类型进行遍历,需要重写操作法==
    vector<Student>::iterator it =  find(stus.begin(), stus.end(), Student("张三",20));
    if(it != stus.end()){
        cout << "success" << endl;
    }else{
        cout << "failed" << endl;
    }
}

12.2.2 find_if

函数原型:

  • find_if(iterator beg,iterator end,_pred);

条件查询内置数据类型:

///一元谓词
bool find_number(int num){
    return num >= 4;
}

void test4(){
    vector<int> v1;
    for(int i=0;i<5;i++){
        v1.push_back(i);
    }
    vector<int>::iterator it = find_if(v1.begin(), v1.end(), find_number);
    if(it != v1.end()){
        cout << "success" << endl;
    }else{
        cout << "failed" << endl;
    }
}

条件查询自定义数据类型:

bool find_student(const Student &stu){
    return stu.age > 30;
}
void test5(){
    vector<Student> stus;
    Student zhangsan("张三",20);
    Student lisi("李四",30);
    Student wangwu("王五",40);
    stus.push_back(zhangsan);
    stus.push_back(lisi);
    stus.push_back(wangwu);

    ///对自定义数据类型进行遍历,需要重写操作法==
    vector<Student>::iterator it =  find_if(stus.begin(), stus.end(), find_student);
    if(it != stus.end()){
        cout << "success" << endl;
    }else{
        cout << "failed" << endl;
    }
}

12.2.3 adjacent_find

函数原型:

  • adjacent_find(iterator beg,iterator end); //查找相邻重复元素

返回第一个相邻元素的迭代器

void test6(){
    vector<int> v1;
    v1.push_back(1);
    v1.push_back(0);
    v1.push_back(1);
    v1.push_back(3);//和下一个3相邻且相邻,返回次元素迭代器
    v1.push_back(3);

    vector<int>::iterator it = adjacent_find(v1.begin(), v1.end());
    if(it != v1.end()){
        cout << "success" << endl;
    }else{
        cout << "failed" << endl;
    }
}

12.2.4 binary_search

函数原型:

  • bool binary_find(iterator beg,iterator end,value);

需要查找序列有序,如果无序不会报逻辑错误,只是查找算法失效

void test7(){
    vector<int> v1;
    for(int i=0;i<5;i++){
        v1.push_back(i);
    }
    bool result = binary_search(v1.begin(), v1.end(), 2);
    if(result){
        cout << "success" << endl;
    }else{
        cout << "failed" << endl;
    }
}

12.2.5 count

函数原型:

count(iterator beg,iterator end,value); //返回容器中与value相同的元素个数

统计内置数据类型:

void test8(){
    vector<int> v1;
    for(int i=0;i<5;i++){
        v1.push_back(i);
    }
    v1.push_back(4);
    int num = count(v1.begin(), v1.end(),4 );
    cout << "容器中存在" << num << "个与数字4相同的数据" << endl;
}

统计自定义数据类型:

class Student{

public:
    string name;
    int age;
    Student(string name,int age){
        this->name = name;
        this->age = age;
    }

    bool operator == (const Student &stu){
        return this->age == stu.age;
    }

};
...
void test9(){
    vector<Student> stus;
    Student zhangsan("张三",20);
    Student lisi("李四",30);
    Student wangwu("王五",20);

    stus.push_back(zhangsan);
    stus.push_back(lisi);
    stus.push_back(wangwu);

    Student zhangsi("张三",20);

    int num = count(stus.begin(), stus.end(), zhangsan);
    cout << "容器中存在" << num << "个与年龄为20的人" << endl;
}

12.2.6 count_if

函数原型:

  • count_if(iterator beg,iterator end,_pred);

条件统计内置数据类型:

bool count_less_3(int num){
    return num < 3;
}
void test10(){
    vector<int> v1;
    for(int i=0;i<5;i++){
        v1.push_back(i);
    }
    int num = count_if(v1.begin(), v1.end(), count_less_3);
    cout << "小于3的数据条数有:" << num << endl;
}

条件统计自定义数据类型:

bool count_age_pass_20(const Student &stu){
    return stu.age > 20;
}
void test11(){
    vector<Student> stus;
    Student zhangsan("张三",20);
    Student lisi("李四",30);
    Student wangwu("王五",20);
    Student zhaoer("赵二",50);

    stus.push_back(zhangsan);
    stus.push_back(lisi);
    stus.push_back(wangwu);
    stus.push_back(zhaoer);

    int num = count_if(stus.begin(), stus.end(), count_age_pass_20);
    cout << "年龄大于20的数据条数有:" << num << endl;
}

12.3 常用排序算法

描述:

  • sort
  • random_shuffle //将指定范围你的元素随机调整次序
  • merge //容器元素合并,并存储到另一容器中
  • reverse //反转指定范围的元素

12.3.1 sort

函数原型:

  • sort(iterator beg,iterator end,_pred);
bool sort_less(int a,int b){
    return a > b;
}
void test12(){
    vector<int> v1;
    v1.push_back(10);
    v1.push_back(50);
    v1.push_back(30);
    v1.push_back(20);
    //默认升序
    sort(v1.begin(), v1.end());
    for_each(v1.begin(), v1.end(), [](int value){
        cout << value << " ";
    });
    cout << endl;
    //sort(v1.begin(), v1.end(),sort_less);
    //内置降序
    sort(v1.begin(), v1.end(),greater<int>());
    for_each(v1.begin(), v1.end(), [](int value){
        cout << value << " ";
    });
    cout << endl;
}

12.3.2 random_shuffle

函数原型:

  • random_shuffle(iterator beg,iterator end);

12.3.3 merge

函数原型:

两个容器必须是有序的,将俩个容器合并到另一容器

  • merge(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
void test14(){
    vector<int> v1;
    for(int i=0;i<5;i++){
        v1.push_back(i);
    }

    vector<int> v2;
    for(int i=5;i<10;i++){
        v2.push_back(i);
    }
    //给目标容器分配空间
    vector<int> v3;
    v3.resize(v1.size()+v2.size());
    merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());

    for_each(v3.begin(), v3.end(), [](int value){
        cout << value << " ";
    });
    cout << endl;
}

12.3.4 reverse

函数原型:

容器内元素反转

  • reverse(iterator beg,iterator end);
void test15(){
    vector<int> v1;
    for(int i=0;i<5;i++){
        v1.push_back(i);
    }
    reverse(v1.begin(), v1.end());
    for_each(v1.begin(), v1.end(), [](int value){
        cout << value << " ";
    });
    cout << endl;
}

12.4 常用拷贝和替换算法

描述:

  • copy //容器指定范围的元素拷贝到另一容器中
  • replace //将容器内指定范围的旧元素修改为新元素
  • replace_if //容器内指定范围内满足条件的元素替换为新元素
  • swap //互换两个容器内的元素

12.4.1 copy

函数原型:

  • copy(iterator beg,iterator end,iterator dest);
void test16(){
    vector<int> v1;
    for(int i=0;i<5;i++){
        v1.push_back(i);
    }
    vector<int> v2;
    v2.resize(v1.size());
    copy(v1.begin(), v1.end(), v2.begin());
    for_each(v2.begin(), v2.end(), [](int value){
        cout << value << " ";
    });
    cout << endl;
}

12.4.2 replace

函数原型:

  • replace(iterator beg,iterator end,oldvalue,newvalue);
void test17(){
    vector<int> v1;
    for(int i=0;i<5;i++){
        v1.push_back(i);
    }
    //将容器内容为2的元素替换为0
    replace(v1.begin(), v1.end(), 2, 0);
    for_each(v1.begin(), v1.end(), [](int value){
        cout << value << " ";
    });
    cout << endl;
}

12.4.3 replace_if

函数原型:

  • replace_if(iterator beg,iterator end,_pred,newvalue);
bool replace_condition(int num){
    return num > 2;
}
void test18(){
    vector<int> v1;
    for(int i=0;i<5;i++){
        v1.push_back(i);
    }
    //将容器大于2的元素替换为0
    replace_if(v1.begin(), v1.end(), replace_condition, 0);
    for_each(v1.begin(), v1.end(), [](int value){
        cout << value << " ";
    });
    cout << endl;
}

12.4.4 swap

函数原型:

  • swap(container c1,container c2);
void test19(){
    vector<int> v1;
    for(int i=0;i<5;i++){
        v1.push_back(i);
    }
    vector<int> v2;
    for(int i=5;i<10;i++){
        v2.push_back(i);
    }
    cout << "before swap v1:";
    printf(v1);
    cout << "before swap v2:";
    printf(v2);
    swap(v1, v2);
    cout << "after swap v1:";
    printf(v1);
    cout << "after swap v2:";
    printf(v2);
}

12.5 常用算法生成算法

描述:

  • 下列算法包含于#include头文件内
  • accumulate
  • fill

12.5.1 accumulate

函数原型:

计算容器内元素总和

  • accumulate(iterator beg,iterator end,value);
void test20(){
    vector<int> v1;
    for(int i=0;i<5;i++){
        v1.push_back(i);
    }
    //最后面那个0是初始值
    int sum = accumulate(v1.begin(), v1.end(), 0);
    cout << "result=" << sum << endl;
}

12.5.2 fill

函数原型:

向容器内填充指定的元素

  • fill(iterator beg,iterator end,value);
void test21(){
    vector<int> v1;
    for(int i=0;i<5;i++){
        v1.push_back(0);
    }
    //将容器内指定范围的元素填充为对应元素
    fill(v1.begin(), v1.end(), 1);
    printf(v1);
}

12.6 常用集合算法

描述:

  • set_intersection //求两个容器的交集
  • set_union //求两个容器的并集
  • set_difference //求两个容器的差集

12.6.1 set_intersection

函数原型:

  • set_intersection(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
void test22(){
    vector<int> v1;
    for(int i=0;i<7;i++){
        v1.push_back(i);
    }

    vector<int> v2;
    for(int i=2;i<10;i++){
        v2.push_back(i);
    }
    vector<int> v3;
    int size = min(v1.size(), v2.size());
    v3.resize(size);
    //set_intersection会返回交集的最后一个迭代器位置
    vector<int>::iterator itEnd =  set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
    ///如果此处使用v3.end()作为结束迭代器,如果容器的空间大于交集元素,则会默认填充0(int),则会导致遍历容器,非交集元素0也会被输出
    ///使用set_intersection返回的结束迭代器为最后一个交集元素的下一个位置,则不会输出0
    for_each(v3.begin(), itEnd, [](int value){
        cout << value << " ";
    });
    cout << endl;
}

12.6.2 set_union

函数原型:

  • set_union(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest);
void test23(){
    vector<int> v1;
    for(int i=0;i<7;i++){
        v1.push_back(i);
    }

    vector<int> v2;
    for(int i=2;i<10;i++){
        v2.push_back(i);
    }
    vector<int> v3;
    int size = max(v1.size(), v2.size());
    v3.resize(size);
    vector<int>::iterator itEnd = set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
    for_each(v3.begin(), itEnd, [](int value){
        cout << value << " ";
    });
    cout << endl;
}

12.6.3 set_different

差集:

  • 不是交集的部分

  • 分v1对v2和v2对v1两种情况

    • 例如v1:1 2 3 4 5. v2: 3 4 5 6 7
    • 则v1对v2的差集 = 1 2
    • v2对v1的差集 = 6 7

函数原型:

  • set_different(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest)
void test24(){
    vector<int> v1;
    for(int i=1;i<6;i++){
        v1.push_back(i);
    } //1 2 3 4 5

    vector<int> v2;
    for(int i=3;i<8;i++){
        v2.push_back(i);
    }//3 4 5 6 7
    vector<int> v3;
    int size = max(v1.size(), v2.size());
    v3.resize(size);
    //v1对v2的差集
    vector<int>::iterator itEnd1 = set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
    for_each(v3.begin(), itEnd1, [](int value){
        cout << value << " ";
    });//1 2
    cout << endl;
    //v2对v1的差集
    vector<int>::iterator itEnd2 = set_difference(v2.begin(), v2.end(), v1.begin(), v1.end(), v3.begin());
    for_each(v3.begin(), itEnd2, [](int value){
        cout << value << " ";
    });//6 7
    cout << endl;
}
相关文章
|
2月前
|
存储 算法 C++
C++ STL 初探:打开标准模板库的大门
C++ STL 初探:打开标准模板库的大门
108 10
|
13天前
|
存储 编译器 C语言
【c++丨STL】vector的使用
本文介绍了C++ STL中的`vector`容器,包括其基本概念、主要接口及其使用方法。`vector`是一种动态数组,能够根据需要自动调整大小,提供了丰富的操作接口,如增删查改等。文章详细解释了`vector`的构造函数、赋值运算符、容量接口、迭代器接口、元素访问接口以及一些常用的增删操作函数。最后,还展示了如何使用`vector`创建字符串数组,体现了`vector`在实际编程中的灵活性和实用性。
36 4
|
15天前
|
C语言 C++ 容器
【c++丨STL】string模拟实现(附源码)
本文详细介绍了如何模拟实现C++ STL中的`string`类,包括其构造函数、拷贝构造、赋值重载、析构函数等基本功能,以及字符串的插入、删除、查找、比较等操作。文章还展示了如何实现输入输出流操作符,使自定义的`string`类能够方便地与`cin`和`cout`配合使用。通过这些实现,读者不仅能加深对`string`类的理解,还能提升对C++编程技巧的掌握。
37 5
|
15天前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
25 2
|
20天前
|
存储 算法 Linux
【c++】STL简介
本文介绍了C++标准模板库(STL)的基本概念、组成部分及学习方法,强调了STL在提高编程效率和代码复用性方面的重要性。文章详细解析了STL的六大组件:容器、算法、迭代器、仿函数、配接器和空间配置器,并提出了学习STL的三个层次,旨在帮助读者深入理解和掌握STL。
40 0
|
2月前
|
存储 搜索推荐 C++
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
55 2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
|
2月前
|
存储 程序员 C++
C++常用基础知识—STL库(2)
C++常用基础知识—STL库(2)
74 5
|
2月前
|
存储 自然语言处理 程序员
C++常用基础知识—STL库(1)
C++常用基础知识—STL库(1)
67 1
|
2月前
|
安全 测试技术 C++
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化2
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化
65 6
|
2月前
|
安全 测试技术 C++
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化1
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化
67 7