C++ 之STL容器部分

目录

1.STL初识

1.1 STL的诞生

1.2 STL基本概念

1.3 STL六大组件

1.4 STL 之 容器、算法、迭代器

1.5 容器、算法、迭代器 初识

1.5.1 vector 存放内置数据类型

1.5.2 Vector 存放自定义数据类型

2 STL 常用容器

2.1 string 容器

2.1.1 string 基本概念

2.1.2 string 构造函数

2.1.3 string 的赋值操作

2.1.4 string 字符串拼接

2.1.5 string 查找和替换

2.1.6 string 字符串比较

2.1.7 string 字符存取

2.1.8 string 插入 和 删除

2.1.9 string子串

2.2 vector 容器

2.2.1 vector 的基本概念

2.2.2 vector 构造函数

2.2.3 vector 赋值操作

2.2.4 vector 容量和大小

2.2.5 vector 插入 和 删除

2.2.6 vector 数据存取

2.2.7 vector 互换容器

2.2.8 vector 预留空间

2.3 deque 容器

2.3.1 deque 容器基本概念

2.3.2 deque 构造函数

2.3.3 deque 赋值操作

2.3.4 deque 大小操作

2.3.5 deque 插入和删除

2.3.6 deque 数据存取

2.3.7 deque 排序

2.4 stack 容器

2.4.1 stack 概念

2.4.2 stack 常用接口

2.5 queue 容器

2.5.1 queue 基本概念

2.5.2 queue 常用接口

2.6 list 容器

2.6.1 list 容器概念

2.6.2 list 构造函数

2.6.3 list 赋值与交换

2.6.4 list 大小操作

2.6.5 list 插入和删除

2.6.6 list 数据存取

2.6.7 list 反转和排序

2.7 set/multiset 容器:

2.7.1 set 基本概念

2.7.2 set 构造和赋值

2.7.3 set 大小和交换

2.7.4 set 插入和删除

2.7.5 set 查找和统计

2.7.6 set和 multiset 区别

2.7.7 pair 对组创建

2.7.8 set 容器排序

2.8 map/multimap 容器

2.8.1 map 基本概念

2.8.2 map 构造和赋值

2.8.3 map 大小和交换

2.8.4 map 插入和删除

2.8.5 map 查找和统计

2.8.6 map 容器排序


1.STL初识


1.1 STL的诞生


  • 长久以来,软件界一只希望建立一种可重复利用的体系

  • C++的面向对象泛型编程思想,目的在于提升复用性

  • 多数情况下,数据结构和算法都未能有一套标准,导致被迫进行大量重复性工作

  • 为建立数据结构和算法的一套标准,STL应运而生

1.2 STL基本概念


  • STL(Standard Template Library) —— 标准模板库

  • 从广义上分为

    • 容器(container)

    • 算法(algorithm)

    • 迭代器(iterator)

  • 容器算法之间通过迭代器进行无缝连接

  • STL 几乎所有的代码都采用了模板类模板函数

1.3 STL六大组件


  • 大体分为六大组件

    • 容器

    • 算法

    • 迭代器

    • 仿函数

    • 适配器(配接器)

    • 空间配置器

1.容器 —— 各种数据结构,如 vector、list、deque、set、map等,用来存放数据

2.算法 —— 各种常用的算法,如sort、find、copy、for_each等。

3.迭代器 —— 扮演了容器与算法之间的胶合剂

4.仿函数 —— 行为类似函数,可作为算法的某种策略。

5.适配器 —— 一种用来修饰容器或者仿函数或迭代器接口的东西。

6.空间配置器 —— 负责空间的配置与管理

1.4 STL 之 容器、算法、迭代器


容器 —— 置物之所也。

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

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

这些容器分为序列式容器和关联式容器两种: 1.序列式容器 —— 强调值的排序,序列式容器中的每个元素均有固定的位置。

2.关联式容器 —— 二叉树结构。各元素之间没有严格的物理上的顺序关系

算法 —— 问题之解法也

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

算法分为 —— 质变算法和非质变算法。 1.质变算法 —— 是指运算过程中会更改区间内的元素的内容,例如拷贝、替换,删除等。

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

迭代器 —— 容器与算法之间的粘合剂

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

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

迭代器使用非常类似于指针

迭代器种类:

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

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

1.5 容器、算法、迭代器 初识


1.5.1 vector 存放内置数据类型

容器:vector

算法:for_each

迭代器:vector::iterator

示例

#include <vector>
#include <algorithm>
​
void MyPrint(int val) {
    cout << val << " ";
}
​
int main () {
    // 创建vector容器
    vector<int> v;
    // 数据添加
    v.push_pack(10);
    v.push_pack(20);
    v.push_pack(30);
    // 创建vector迭代器
    vector<int>::iterator itBegin = v.begin(); // 起始迭代器
    vector<int>::iterator itEnd = v.end(); // 结束迭代器 指向最后元素的下一位置
    
    // 遍历方法1
    while (itBegin != itEnd) {
        cout << *itBegin << " ";
    }
    
    // 遍历方法2
    for (vector<int> it = v.begin(); it != v.end(); it++) {
        cout << *it << " ";
    }
    
    // 遍历方法3
    for_each(v.begin, v.end(), MyPrint);
    
    return 0;
}

1.5.2 Vector 存放自定义数据类型

示例

#include <iosteam>
#include <string>
#include <vector>
​
class Person {
    public:
        Person(string name, int age) {
            this -> m_Name = name;
            this -> m_Age = age;
        }
    string m_Name;
    int m_Age;
};
​
void test01() {
    // 创建vector容器
    vector<Person> v;
    // 添加数据
    v.push_back(Person("aa", 10));
    v.push_back(Person("bb", 20));
    v.push_back(Person("cc", 30));
    v.push_back(Person("dd", 40));
    v.push_back(Person("ee", 50));
    
    // 遍历 + 指针成员
    for (vector<Person>::iterator it = v.begin(); it != v.end(); it++) {
        cout << "Name: " << it->m_Name << " Age: " << it->m_Age << endl;
    }
}
​
void test02 () {
    // 创建vector容器
    vector<Person> v;
    // 添加数据
    v.push_back(Person("aa", 10));
    v.push_back(Person("bb", 20));
    v.push_back(Person("cc", 30));
    v.push_back(Person("dd", 40));
    v.push_back(Person("ee", 50));
​
    // 遍历 + 解引用
    for (vector<Person>::iterator it = v.begin(); it != v.end(); it++) {
        cout << "Name: " << (*it).m_Name << " Age: " << (*it).m_Age << endl;
    }
}
​
// 存储自定义类型指针
void test03 () {
    // 创建vector容器
    vector<Person*> v;
​
    // 创建测试数据
    Person p1("aa", 10);
    Person p2("bb", 20);
    Person p3("cc", 30);
    Person p4("dd", 40);
    Person p5("ee", 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)->m_Name << " Age: " << (*it)->m_Age << endl;
    }
}
​
int main () {
    test01();
    test02();
    test03();
}

2 STL 常用容器


2.1 string 容器

2.1.1 string 基本概念

本质

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

string 和 char* 的区别:

  • char* 是一个指针

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

特点

  • string 类内部封装了很多成员方法

  • 例如:查找find,拷贝copy,删除delete,替换replace,插入insert

  • string 管理插入char* 所分配的内存,不用担心复制越界或取值越界等,由类的内部进行负责。

2.1.2 string 构造函数

构造函数原型

  • string(); —— 创建一个空的字符串 例如:string str

    string(const char* s); —— 使用字符串s初始化

  • string(const string& str); —— 使用一个string对象初始化另一个string对象

  • string(int n, char c); —— 使用n个字符c初始化

示例:

#include <iostream>
using namespace std;
​
// string构造函数
void test01() {
    string s1; // 默认构造
​
    const char * str = "hello~";
    string s2(str);
​
    cout << "s2 = " << s2 << endl;
​
    string s3(s2);
    cout << "s3 = " << s3 << endl;
​
    string s4(10, 'a');
    cout << "s4 = " << s4 << endl;
​
}
​
int main() {
    test01();
    return 0;
}

总结:string 的用法无需对比,灵活使用即可。

2.1.3 string 的赋值操作

功能描述:

  • 给string字符串进行赋值

赋值的函数类型:

  • string& operator = (const char* s);

    • char* 类型字符串 赋值给当前的字符串

  • string& operator = (const string &s);

    • 把字符串s 赋给当前的字符串

  • string& operator = (char 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 赋给当前字符串

示例:

#include <iostream>
using namespace std;
#include <string>
​
//
void test01() {
    string str1;
    str1 = "hello!!";
    cout << "str1 = " << str1 << endl;
​
    string str2;
    str2 = str1;
    cout << "str2 = " << str2 << endl;
​
    string str3;
    str3 = 'x';
    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(10, 'x');
    cout << "str7 = " << str7 << endl;
​
}
​
int main() {
    test01();
    return 0;
}

2.1.4 string 字符串拼接

功能描述:

  • 实现在字符串末尾拼接字符串

函数原型:

  • string& operator += (const char* str);

    • 重载 += 操作符

  • string& operator += (const char c);

    • 重载 += 操作符

  • string& operator += (const string &str);

    • 重载 += 操作符

  • string& append(const char *s);

    • 把字符串s 连接到当前字符串结尾

  • string& append(const char *s, int n);

    • 把字符串s 的前n 个字符连接到当前字符串结尾

  • string& append(const string &s);

    • 同operator += (const string &str)

  • string& append(const string &s, int pos, int n);

    • 字符串s 中从pos 开始的n 个字符连接到字符串结尾

示例:

#include <iostream>
using namespace std;
​
void test01() {
    string str1 = "I";
    str1 += " love study";
    cout << "str1 = " << str1 << endl;
​
    str1 += "!";
    cout << "str1 = " << str1 << endl;
​
    string str2 = "Hey, ";
    str2 += str1;
    cout << "str2 = " << str2 << endl;
​
    string str3 = "You";
    str3.append(" love ");
    cout << "str3 = " << str3 << endl;
​
    str3.append("nothing abc", 8);
    cout << "str3 = " << str3 << endl;
​
    str3.append(str1);
    cout << "str3 = " << str3 << endl;
​
    
    str3.append(str2, 0, 3);
    cout << "str3 = " << str3 << endl;
}
​
int main() {
    test01();
    return 0;
}

2.1.5 string 查找和替换

功能描述:

  • 查找:查找指定字符串是否存在

  • 替换:在指定的位置替换字符串

函数原型:

  • int find(const string &str, int pos = 0) const;

    • 查找str 第一次出现位置,从pos开始查找

  • int find(const char* s , int pos = 0) const;

    • 查找s 第一次出现位置,从pos开始查找

  • int find(const char* s , int pos, int n) const;

    • 从pos 位置查找s 的前n 个字符第一次位置

  • int find(const char c, int pos = 0) const;

    • 查找字符c 第一次出现位置

  • 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 最后一次出现位置

  • string& replace(int pos, int n, const string& str);

    • 替换从pos 开始n 个字符为字符串str

  • string& replace(int pos, int n, const char* s );

    • 替换从pos 开始的n 个字符为字符串s

示例:

#include <iostream>
using namespace std;
​
// 查找
void test01() {
    string str1 = "abcdefgde";
    int pos = str1.find("de");
    if (pos == -1) {
        cout << "Not found" << endl;
    } else {
        cout << "Found, pos = " << pos << endl;
    }
​
    //rfind 从右往左查找
    pos = str1.rfind("de");
    cout << "pos = " << pos << endl;
}
​
// 替换
void test02() {
    string str2 = "abcdefg";
    str2.replace(1, 3, "1111");
    cout << "str2 = " << str2 << endl;
}
​
int main() {
    test01();
    test02();
    return 0;
}

2.1.6 string 字符串比较

功能描述:

  • 字符串之间的比较

比较方式:

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

= 返回 0

> 返回 1

< 返回 -1

函数原型:

  • int compare(const string &s) const;

    • 与字符串s 进行比较

  • int compare(const char *s) const;

    • 与字符串s 进行比较

示例:

#include <iostream>
​
using namespace std;
​
// 字符串比较操作
void test01 () {
    string str1 = "hello";
    string str2 = "hello";
​
    if (str1.compare(str2) == 0) {
        cout << "str1 = str2" << endl;
    } else if (str1.compare(str2) == 1) {
        cout << "str1 > str2" << endl;
    } else {
        cout << "str1 < str2" << endl;
    }
}
​
int main() {
    test01();
    return 0;
}

2.1.7 string 字符存取

string 中单个字符存取方式有两种

  • char& operator[](int n);

    • 通过[] 方式取字符

  • char& at(int n);

    • 通过at 方法获取字符

示例:

#include <iostream>
using namespace std;
​
//
void test() {
    string str = "hello";
​
    cout << "str = " << str << endl;
​
    // 1.通过 [] 来访问单个字符
    for (int i = 0; i < str.size(); i++) {
        cout << str[i] << " ";
    }
    cout << endl;
    // 2.通过 at 方式访问单个字符
    for (int i = 0; i < str.size(); i++) {
        cout << str.at(i) << " ";
    }
    cout << endl;
​
    // 修改单个字符
    str[0] = 'x';
    cout << "str = " << str << endl;
​
    str.at(1) = 'x';
    cout << "str = " << str << endl;
}
​
int main() {
    test();
    return 0;
}

2.1.8 string 插入 和 删除

功能描述:

  • 对string 字符串进行插入和删除字符操作

函数原型:

  • string& insert(int pos, const char* s);

    • 插入字符串

  • string& insert(int pos, const string& str);

    • 插入字符串

  • string& insert(int pos, int n, char c);

    • 在指定位置插入n 个字符c

  • string& erase(int pos, int n = npos);

    • 删除从pos 开始的n 个字符

示例:

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

// 字符串插入 和 删除
void test() {
    string str = "hello";
    cout << "str = " << str << endl;
    str.insert(1, "111");
    cout << "str = " << str << endl;

    // 删除
    str.erase(1, 3);
    cout << "str = " << str << endl;
}

int main(){
    test();
    return 0;
}

总结:

  • 插入和删除的起始下标均为0

2.1.9 string子串

功能描述:

  • 从字符串中获取想要的字符串

函数原型:

  • string sbstr(int pos = 0, int n = npos) const;

    • 返回由pos 开始的n 个字符组成的字符串

示例:

#include <iostream>
using namespace std;

// string 求子串
void test01() {
    string str = "abcdef";
    string subStr = str.substr(0, 2);
    // ab
    cout << "subStr = " << subStr << endl;
}

void test02() {
    string email = "hello@sina.com";

    // 从邮件地址中获取用户名信息
    int pos = email.find('@');
    
    string userName = email.substr(0, pos);
    cout << "userName = " << userName << endl;
}

int main(){
    test01();
    test02();
    return 0;
}

2.2 vector 容器


2.2.1 vector 的基本概念

功能:

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

vector 与普通数组的区别:

  • 数组是静态空间,而vector 可以动态扩展

动态扩展:

  • 并不是在原空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝到新空间,释放原空间

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

2.2.2 vector 构造函数

功能描述:

  • 创建vector 容器

函数原型:

  • vector<T> v

    • 采用模板实现类,默认构造函数

  • vector(v.begin(), v.end());

    • 将v.begin() 到 v.end() 拷贝给本身

  • vector(n, elem);

    • 构造函数将n 个elem 拷贝给本身

  • vector(const vector &vec);

    • 拷贝构造函数

示例:

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

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(v1.begin(), v1.end());
    printVector(v2);

    // n个elem 方式构造
    vector<int> v3(10, 100);
    printVector(v3);

    // 拷贝构造 ---
    vector<int> v4(v3);
    printVector(v4);
}

int main() {
    test01();
}

2.2.3 vector 赋值操作

功能描述:

  • 给vector 容器进行赋值

函数原型:

  • vector& operator = (const vector &vec);

    • 重载等号操作符

  • assign(beg, end);

    • 将[beg, end) 区间中的数据拷贝赋值给本身

  • assign(n, elem);

    • 将n 个elem 拷贝赋值给本身

示例:

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

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

// vector 赋值
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);

    // assign
    vector<int>v3;
    v3.assign(v1.begin(), v1.end());
    printVector(v3);

    vector<int>v4;
    v4.assign(10, 3);
    printVector(v4);
}

int main() {
    test01();
    return 0;
}

2.2.4 vector 容量和大小

功能描述:

  • 对vector 容器的容量和大小操作

函数原型:

  • empty();

    • 判断容器是否为空

  • capacity();

    • 容器的容量

  • size();

    • 返回容器中元素的个数

  • resize(int num);

    • 重新指定容器的长度为 num,若容器变长,则以默认值填充新位置

    • 如果容器变短,则末尾超出容器长度的元素被删除

  • resize(int num, elem);

    • 重新指定容器长度为 num,若容器变长,则以elem 值填充新位置

    • 如果容器变短,则末尾超出容器长度的元素被删除

示例:

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

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

// vector 容器量 和 大小的操作
void test01() {
    vector<int>v1;
    for (int i = 0; i < 10; i++) {
        v1.push_back(i);
    }
    printVector(v1);

    //
    if (v1.empty()) {
        cout << "empty" << endl;
    } else {
        cout << "not empty" << endl;
        cout << "capacity = " << v1.capacity() << endl;
        cout << "szie = " << v1.size() << endl;

        // 重新指定大小
        v1.resize(15, 1); // 过长未赋值部分默认以0 填充
        printVector(v1);

        v1.resize(5); // 指定size 过短,超出部分被删除
        printVector(v1);
    }
}

int main() {
    test01();
    system("pause");
    return 0;
}

2.2.5 vector 插入 和 删除

功能描述:

  • 对vector 容器进行插入、删除操作

函数原型

  • push_back(ele);

    • 尾部插入元素ele

  • pop_back();

    • 删除最后一个元素

  • insert(const_iterator pos, ele);

    • 迭代器指向位置pos 插入元素ele

  • insert(const_iterator pos, int count, ele);

    • 迭代器指向位置pos 插入count 个元素ele

  • erase(const_iterator pos);

    • 删除迭代器指向的元素

  • erase(const_iterator start, const_iterator end);

    • 删除迭代器从start 到end 之间的元素

  • clear();

    • 删除容器中所有的元素

示例:

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

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

// vector 插入和 删除
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());
    printVector(v1);

    // clear
    v1.clear();
    printVector(v1);
}

int main() {
    test01();
    system("pause");
    return 0;
}

总结:

  • 尾插 —— push_back

  • 尾删 —— pop_back

  • 插入 —— insert(位置迭代器)

  • 删除 —— erase(位置迭代器)

  • 清空 —— clear

2.2.6 vector 数据存取

功能描述:

  • 对 vector 中的数据的存取操作

函数原型:

  • at(int idx);

    • 返回索引idx 所指的数据

  • operator[];

    • 返回索引idx 所指的数据

  • front();

    • 返回容器中第一个数据元素

  • back();

    • 返回容器中最后一个元素

示例:

#include <iostream>
#include <vector>
#include "print.h"
using namespace std;

//void printVector(vector<int>&v) {
//    for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
//        cout << *it << " ";
//    }
//    cout << endl;
//}

// vector 数据存取
void test01() {
    vector<int>v1;
    for (int i = 0; i < 10; i++) {
        v1.push_back(i);
    }

    // 下标访问元素
    for (int i = 0; i < v1.size(); i++) {
        cout << v1[i] << " ";
    }
    cout << endl;

    // at方法访问
    for (int i = 0; i < v1.size(); i++) {
        cout << v1.at(i) << " ";
    }
    cout << endl;

    // 返回第一个元素
    cout << v1.front() << endl;
    // 返回最后一个元素
    cout << v1.back() << endl;

}

int main() {
    test01();
    system("pause");
    return 0;
}

2.2.7 vector 互换容器

功能描述:

  • 实现两个容器内元素进行互换

函数原型:

  • swap(vec);

    • 将vec 与本身的元素互换

示例:

#include <iostream>
#include <vector>
#include "print.h"
using namespace std;

//void printVector(vector<int>&v) {
//    for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
//        cout << *it << " ";
//    }
//    cout << endl;
//}

// vector 容器互换

//  1.基本使用
void test01() {
    vector<int>v1;
    for (int i = 0; i < 10; i++) {
        v1.push_back(i);
    }
    cout << "v1 before:" << endl;
    printVector(v1);

    vector<int>v2;
    for (int i = 10; i > 0; i--) {
        v2.push_back(i);
    }
    cout << "v2 before:" << endl;
    printVector(v2);

    cout << "after:" << endl;
    v1.swap(v2); // swap
    printVector(v1);
    printVector(v2);
}

// 2.实际应用 —— 收缩内存空间
void test02() {
    vector<int>v;
    for (int i = 0; i < 100000; i++) {
        v.push_back(i);
    }
    cout << "capacity = " << v.capacity() << endl;
    cout << "size = " << v.size() << endl;

    // 空间浪费
    v.resize(3);
    cout << "capacity = " << v.capacity() << endl;
    cout << "size = " << v.size() << endl;

    // 巧用swap 收缩内存
    vector<int>(v).swap(v); // 匿名对象
    cout << "capacity = " << v.capacity() << endl;
    cout << "size = " << v.size() << endl;
}

int main() {
//    test01();
    test02();
    system("pause");
    return 0;
}

2.2.8 vector 预留空间

功能描述:

  • 减少vector 在动态扩展容量时的扩展次数

函数原型:

  • reserve(int len);

    • 容器预留len 个元素的长度,预留位置不初始化,元素不可访问

示例:

#include <iostream>
#include <vector>
#include "print.h"
using namespace std;

//void printVector(vector<int>&v) {
//    for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
//        cout << *it << " ";
//    }
//    cout << endl;
//}

// vector 预留空间
void test01() {
    vector<int>v;
    // 利用reserve预留空间
    v.reserve(10000);
    int num = 0; // 统计内存分配次数
    int *p = NULL;
    for (int i = 0; i < 100000; i++) {
        v.push_back(i);
        if (p != &v[0]) {
            p = &v[0];
            num++;
        }
    }
    // num = 30 => num = 1
    cout << "num = " << num << endl;
}

int main() {
    test01();
    system("pause");
    return 0;
}

2.3 deque 容器

2.3.1 deque 容器基本概念

功能:

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

deque 与vector 区别

  • vector 对于头部的插入删除效率低,数据量越大,效率越低

  • deque相对而言,对头部的插入删除速度会比vector 快

  • vector 访问元素的速度会比deque 快,这和两者内部实现有关

deque 内部工作原理:

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

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

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

2.3.2 deque 构造函数

功能描述:

  • deque 容器构造

函数原型:

  • deque<T> deqT;

    • 默认构造方式

  • deque(beg, end);

    • 构造函数将[beg, end)区间中的元素拷贝给本身

  • deque(n, elem);

    • 构造函数将n 个elem 拷贝给本身

  • deque(const deque &deq);

    • 拷贝构造函数

示例:

#include <iostream>
#include <deque>
#include "print.h"
using namespace std;

// deque 构造函数
void test() {
    deque<int>d1;
    for (int i = 0; i < 10; i++) {
        d1.push_back(i);
    }
    printDeque(d1);

    deque<int>d2(d1.begin(), d1.end());
    printDeque(d2);

    deque<int>d3(10, 100);
    printDeque(d3);

    deque<int>d4(d3);
    printDeque(d4);
}

int main() {
    test();
    return 0;
}


// printDeque()只读状态
void printDeque(const std::deque<int>&d) {
    for (std::deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
}

2.3.3 deque 赋值操作

功能描述:

  • 给deque 容器进行赋值

函数原型:

  • deque& operator = (const deque &deq);

    • 重载等号操作符

  • assign(beg, end);

    • 将[beg, end) 区间中的数据拷贝赋值给本身

  • assign(n, elem);

    • 将n 个elem 拷贝赋值给本身

示例:

#include <iostream>
#include <deque>
#include "print.h"
using namespace std;

// deque 赋值操作
void test() {
    deque<int>d1;
    for (int i = 0; i < 10; i++) {
        d1.push_back(i);
    }
    printDeque(d1);

    // = 赋值
    deque<int>d2;
    d2 = d1;
    printDeque(d2);

    // assign 1
    deque<int>d3;
    d3.assign(d1.begin(), d1.end());
    printDeque(d3);

    // assign 2
    deque<int>d4;
    d4.assign(10, 100);
    printDeque(d4);
}

int main() {
    test();
    return 0;
}

2.3.4 deque 大小操作

功能描述:

  • 对deque 容器的大小进行操作

函数原型:

  • deque.empty();

  • deque.size();

  • deque.resize(int num);

  • deque.resize(int num, elem);

类似于vector,区别在于无容量的概念

示例:

#include <iostream>
#include <deque>
#include "print.h"
using namespace std;

// deque 大小操作
void test() {
    deque<int>d1;
    for (int i = 0; i < 10; i++) {
        d1.push_back(i);
    }
    printDeque(d1);

    // empty or not
    if (d1.empty()) {
        cout << "empty" << endl;
    } else {
        cout << "not empty" << endl;
        cout << "size = " << d1.size() << endl;
        // 没有容量概念
    }

    // 重新指定大小
    d1.resize(15);
    printDeque(d1);

    d1.resize(16, 1);
    printDeque(d1);

    d1.resize(5);
    printDeque(d1);
}

int main() {
    test();
    return 0;
}

总结:

  • deque 没有容量的概念

  • 判断是否为空 —— empty

  • 返回元素个数 —— size

  • 重新指定个数 —— resize

2.3.5 deque 插入和删除

概念描述:

  • 向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);

    • 返回下一个数据的位置

示例:

#include <iostream>
#include <deque>
#include "print.h"
using namespace std;

// deque 插入和删除

// 两端操作
void test01() {
    deque<int>d1;

    // 尾插法
    d1.push_back(10);
    d1.push_back(20);
    // 头插法
    d1.push_front(100);
    d1.push_front(200);
    // 200 100 10 20
    printDeque(d1);

    // 尾删
    d1.pop_back();
    printDeque(d1);
    // 头删
    d1.pop_front();
    printDeque(d1);
}

void test02() {
    deque<int>d1;
    d1.push_back(10);
    d1.push_back(20);
    d1.push_front(100);
    d1.push_front(200);
    printDeque(d1);

    // insert
    // 1000 200 100 10 20
    d1.insert(d1.begin(), 1000);
    printDeque(d1);

    // 10000 10000 1000 200 100 10 20
    d1.insert(d1.begin(), 2, 10000);
    printDeque(d1);

    // 按照区间进行插入
    deque<int>d2;
    d2.push_back(1);
    d2.push_back(2);
    d2.push_back(3);

    d1.insert(d1.begin(), d2.begin(), d2.end());
    // 1 2 3 10000 10000 1000 200 100 10 20
    printDeque(d1);
}

// 删除
void test03() {
    deque<int>d1;
    d1.push_back(10);
    d1.push_back(20);
    d1.push_front(100);
    d1.push_front(200);

    deque<int>::iterator it = d1.begin();
    it++;
    d1.erase(it);
    // 200 10 20
    printDeque(d1);

    // 区间删除
    d1.erase(d1.begin(), d1.end());
    printDeque(d1);

    // clear
    d1.clear();
    printDeque(d1);
}

int main() {
    test01();
    test02();
    test03();
    return 0;
}

总结:

  • 插入和删除提供的都是迭代器!

  • 尾删 —— pop_back

  • 尾插 —— push_back``

  • 头插 —— push_front

  • 头删 —— pop_front

2.3.6 deque 数据存取

功能描述:

  • 对deque 中的数据进行存取操作

函数原型:

  • at(int idx);

  • operator[];

  • front();

  • back();

示例:

#include <iostream>
#include <deque>
#include "print.h"
using namespace std;

// deque 数据存取
void test01() {
    deque<int> d1;
    for (int i = 0; i < 10; i++) {
        d1.push_back(i);
    }
    printDeque(d1);

    // at方式
    for (int i = 0; i < d1.size(); i++) {
        cout << d1.at(i) << " ";
    }
    cout << endl;

    // []方式
    for (int i = 0; i < d1.size(); i++) {
        cout << d1[i] << " ";
    }
    cout << endl;

    // front
    cout << d1.front() << endl;
    // back
    cout << d1.back() << endl;
}

int main() {
    test01();
    return 0;
}

总结:

  • 除了用迭代器获取deque 中的元素以外,[] 和 at 也可

  • front 返回首个

  • back 返回末尾

2.3.7 deque 排序

功能描述:

  • 利用算法实现对deque 容器进行排序

算法:

  • sort(iterator beg, iterartor end);

示例:

#include <iostream>
#include <deque>
// 标准算法头文件
#include <algorithm>
#include "print.h"
using namespace std;
// deque 数据存取
void test01() {
    deque<int>d;
    d.push_back(10);
    d.push_back(20);
    d.push_back(30);
    d.push_front(100);
    d.push_front(200);
    d.push_front(300);
    printDeque(d);
    // sort 默认升序
    // 对于支持随机访问的迭代器,都可以使用sort算法排序
    sort(d.begin(), d.end());
    cout << "ordered: " << endl;
    printDeque(d);
}
int main() {
    test01();
    return 0;
}

2.4 stack 容器

2.4.1 stack 概念

概念:

  • stack —— 一种先进后出(LIFO)的数据结构,只有一个出口

  • 栈中只有顶端元素才可以被外部使用,不允许有遍历操作

2.4.2 stack 常用接口

功能描述:

  • 栈容器常用的对外接口

构造函数:

  • stack<T> stk;

    • 默认构造方式

  • stack(const stack &stk);

    • 拷贝构造函数

赋值操作:

  • stack& operator = (const &stk);

    • 重载等号操作符

数据存取:

  • push(elem);

    • 向栈顶添加元素

  • pop();

    • 从栈顶弹出元素

  • top();

    • 返回栈顶元素

大小操作:

  • empty();

    • 判断栈是否为空

  • size();

    • 返回栈的大小

示例:

#include <iostream>
#include <stack>

using namespace std;

// stack
void test01() {
    // definition
    stack<int>s;

    // 入栈
    s.push(10);
    s.push(20);
    s.push(30);
    s.push(40);

    cout << "size = " << s.size() << endl;

    // 只要栈不为空,就查看栈顶并执行出栈操作
    while (!s.empty()) {
        // 查看栈顶元素
        cout << "top = " << s.top() << endl;

        // 出栈
        s.pop();
    }

    cout << "size of s is: " << s.size() << endl;
}

int main () {
    test01();
    return 0;
}

总结:

  • 入栈 —— push

  • 出栈 —— pop

  • 返回栈顶 —— top

  • 判断是否为空 —— empty

  • 返回栈大小 —— size

2.5 queue 容器

2.5.1 queue 基本概念

概念:

  • Queue 是一会走先进先出(FIFO)的数据结构,它有两个出口

  • 队列容器允许从一端新增元素,从另一端移除元素

  • 队列中只有队头和队尾可以被外界使用,因此队列不允许有遍历行为

  • 队列中进数据称为 —— 入队 push

  • 队中中出数据称为 —— 出队 pop

2.5.2 queue 常用接口

功能描述:

  • 栈容器常用的对外接口

构造函数:

  • queue<T> que;

  • queue(const queue &que);

赋值操作:

  • queue& operator = (const queue &que);

数据存取:

  • push(elem);

  • pop();

  • back();

  • front();

大小操作:

  • empty();

  • size();

示例:

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

// queue

class Person {
public:
    Person(string Name, int age) {
        this->m_Name = Name;
        this->m_Age = age;
    };
    string m_Name;
    int m_Age;
};

void test() {
    // definition
    queue<Person> q;

    // data ready
    Person p1("A", 30);
    Person p2("B", 1000);
    Person p3("C", 900);
    Person p4("D", 800);

    cout << "size = " << q.size() << endl;

    // 入队
    q.push(p1);
    q.push(p2);
    q.push(p3);
    q.push(p4);

    // 判断,查看
    while (!q.empty()) {
        // head
        cout << "Name of head = " << q.front().m_Name << " ";
        // tail
        cout << "Name of tail = " << q.back().m_Name << endl;

        // 出队
        q.pop();
    }
    cout << "size = " << q.size() << endl;
}

int main() {
    test();
    return 0;
}

总结:

  • 入队 —— push

  • 出队 —— pop

  • 队头 —— front

  • 队尾 —— back

  • 是否为空 —— empty

  • 大小 —— size

2.6 list 容器

2.6.1 list 容器概念

功能:

  • 将数据进行链式存储

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

链表的组成:

  • 一系列结点

结点的组成:

  • 一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域

STL中的链表是一个双向循环链表

由于链表的存储方式并不是连续的内存空间,因此链表list 中的迭代器只支持前移和后移,属于双向迭代器

list 的优点:

  • 采用动态存储分配,不会造成内存浪费和溢出

  • 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素

list 的缺点:

  • 链表灵活,但是空间(指针域)和时间(遍历)额外消耗较大

List 的一个重要性质 —— 插入操作和删除操作都不会造成原有list 迭代器的失效,这在vector中并不成立

总结:

  • STL中List 和Vector 是两个最常被使用的容器,各有优劣

2.6.2 list 构造函数

功能描述:

  • 创建list 容器

函数原型:

  • list<T> lst;

  • list(beg, end);

  • list(n, elem);

  • list(const list &lst);

示例:

#include <iostream>
#include <list>
#include "print.h"
using namespace std;

void test01() {
    // definition
    list<int>l1;
    // 添加数据
    l1.push_back(10);
    l1.push_back(20);
    l1.push_back(30);
    l1.push_back(40);

    // 遍历链表
    printList(l1);

    // scope
    list<int>l2(l1.begin(), l1.end());
    printList(l2);

    // copy
    list<int>l3(l2);
    printList(l3);

    // n elems
    list<int>l4(10, 1000);
    printList(l4);
}

int main() {
    test01();
    return 0;
}

总结:

  • list 构造函数方法同其它几个STL常用容器,熟练掌握即可

2.6.3 list 赋值与交换

功能描述:

  • 给list 容器进行赋值,以及交换list 容器

函数原型:

  • assign(beg, end);

  • assign(n, elem);

  • list& operator = (const list &lst);

  • swap(lst);

示例:

#include <iostream>
#include <list>
#include "print.h"
using namespace std;

// list 赋值 交换
void test01() {
    // definition
    list<int>l1;
    // 添加数据
    l1.push_back(10);
    l1.push_back(20);
    l1.push_back(30);
    l1.push_back(40);
    printList(l1);

    // 赋值
    list<int>l2;
    l2 = l1;
    printList(l2);

    list<int>l3;
    l3.assign(l2.begin(), l2.end());
    printList(l3);

    list<int>l4;
    l4.assign(10, 100);
    printList(l4);
}

void test02() {
    // definition
    list<int>l1;
    // 添加数据
    l1.push_back(10);
    l1.push_back(20);
    l1.push_back(30);
    l1.push_back(40);
    cout << "before: \n";
    printList(l1);

    list<int>l2;
    l2.assign(10, 100);
    printList(l2);
    // 交换
    cout << "after: \n";
    l1.swap(l2);
    printList(l1);
    printList(l2);
}

int main() {
//    test01();
    test02();
    return 0;
}

2.6.4 list 大小操作

功能描述:

  • 对list 容器的大小进行操作

函数原型:

  • size();

  • empty();

  • resize(num);

  • resize(num, elem);

示例:

#include <iostream>
#include <list>
#include "print.h"
using namespace std;

// list 大小操作
void test01() {
    // definition
    list<int>l1;
    // 添加数据
    l1.push_back(10);
    l1.push_back(20);
    l1.push_back(30);
    l1.push_back(40);
    printList(l1);

    // 判断
    if (l1.empty()) {
        cout << "empty" << endl;
    } else {
        cout << "not empty" << endl;
        cout << "size = " << l1.size() << endl;
    }

    // 重新指定大小
    l1.resize(10);
    printList(l1);

    l1.resize(3);
    printList(l1);
}


int main() {
    test01();
    return 0;
}

总结:

  • 判断是否为空 —— empty

  • 返回元素个数 —— size

  • 重新指定个数 —— resize

2.6.5 list 插入和删除

功能描述:

  • 对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 的元素

示例:

#include <iostream>
#include <list>
#include "print.h"
using namespace std;

// list 插入与删除
void test01() {
    list<int>L;

    // 尾插
    L.push_back(10);
    L.push_back(20);
    L.push_back(30);
    // 头插
    L.push_front(100);
    L.push_front(200);
    L.push_front(300);

    printList(L);

    // 尾删
    L.pop_back();
    printList(L);

    // 头删
    L.pop_front();
    printList(L);

    // insert
    list<int>::iterator it = L.begin();

    L.insert(L.begin(), 1000);
    printList(L);

    L.insert(it++, 2000);
    printList(L);

    // 删除
    it = L.begin();
    L.erase(++it);
    printList(L);

     // remove
    L.push_back(10000);
    L.push_back(10000);
    L.push_back(10000);
     printList(L);
     L.remove(10000);
     printList(L);

     // clear
     L.clear();
     printList(L);
}


int main() {
    test01();
    return 0;
}

总结:

  • 尾插 —— push_back

  • 尾删 —— pop_back

  • 头插 —— push_front

  • 头删 —— pop_front

  • 插入 —— insert

  • 删除 —— erase

  • 移除 —— remove

  • 清空 —— clear

2.6.6 list 数据存取

功能描述:

  • 对list 容器中数据进行存取

函数原型:

  • front();

    • 返回第一个元素

  • back();

    • 返回最后一个元素

示例:

#include <iostream>
#include <list>
#include "print.h"
using namespace std;

// list 数据存取
void test01() {
    list<int>L1;

    // 尾插
    L1.push_back(10);
    L1.push_back(20);
    L1.push_back(30);
    L1.push_back(40);

    cout << "first = " << L1.front() << endl;
    cout << "back = " << L1.back() << endl;

    // 不能用L1[0]
    // 不能用L1.at(0)
    // 迭代器不支持 随机访问
    // 验证
    list<int>::iterator it = L1.begin();
    it++; // 支持
    it--; // 支持
//    it = it + 1; 不支持

}


int main() {
    test01();
    return 0;
}

总结:

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

  • 返回第一个元素 —— front

  • 返回最后一个元素 —— back

2.6.7 list 反转和排序

功能描述:

  • 将容器中的元素反转,以及将容器中的数据进行排序

函数原型:

  • reverse();

    • 反转链表

  • sort();

    • 链表排序

示例:

#include <iostream>
#include <list>
#include <algorithm>
#include "print.h"
using namespace std;

// list  反转 排序
void test01() {
    list<int>L1;

    L1.push_back(10);
    L1.push_back(50);
    L1.push_back(40);
    L1.push_back(90);
    printList(L1);

    // reverse
    L1.reverse();
    cout << "reversed: \n";
    // 90 40 50 10
    printList(L1);
}

// 排序规则
bool myCompare(int v1, int v2) {
    // desc
    return v1 > v2;
}

void test02() {
    list<int>L1;

    L1.push_back(10);
    L1.push_back(50);
    L1.push_back(40);
    L1.push_back(90);
    cout << "before: \n";
    printList(L1);

    // sort
    //sort(L1.begin(), L1.end()); // 错误,因为迭代器不支持随机访问
    L1.sort();
    cout << "sorted: \n";
    // 10 40 50 90  默认升序
    printList(L1);

    // 降序
    L1.sort(myCompare);
    cout << "desc: \n";
    // 90 50 40 10
    printList(L1);
}

int main() {
    test01();
    test02();
    return 0;
}

总结:

  • 反转 —— reverse

  • 排序 —— sort(成员函数)

2.7 set/multiset 容器:

2.7.1 set 基本概念

简介:

  • 所有元素都会在插入时自动被排序

本质:

  • set/multiset 属于关联式容器,底层结构是用二叉树实现

set和multiset 区别:

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

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

2.7.2 set 构造和赋值

功能描述:

  • 创建set 容器以及赋值

构造:

  • set<T> st;

    • 默认构造函数

  • set(const set &st);

    • 拷贝构造函数

赋值:

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

示例:

#include <iostream>
#include <set>
#include "print.h"

using namespace std;

void test01 () {
    set<int>s1;
    // 插入 只有insert方法
    s1.insert(10);
    s1.insert(40);
    s1.insert(30);
    s1.insert(20);
    s1.insert(30);

    // 遍历容器 set容器默认自动无重复、排序遍历
    printSet(s1);

    // 拷贝构造
    set<int>s2(s1);
    printSet(s2);

    // 赋值操作
    set<int>s3;
    s3 = s2;
    printSet(s3);
}

int main() {
    test01();
    return 0;
}

总结:

  • set 容器插入数据时用insert

  • set 容器插入数据的数据会自动排序

2.7.3 set 大小和交换

功能描述:

  • 统计set 容器大小以及交换set 容器L

函数原型:

  • size();

  • empty();

  • swap(st);

示例:

#include <iostream>
#include <set>
#include "print.h"

using namespace std;

// 大小
void test01 () {
    set<int>s1;

    // 插入 INSERT
    s1.insert(10);
    s1.insert(40);
    s1.insert(30);
    s1.insert(20);
    s1.insert(30);

    // 打印容器
    printSet(s1);

    // empty?
    if (s1.empty()) {
        cout << "empty" << endl;
    } else {
        cout << "size = " << s1.size() << endl;
    }
}

// 交换
void test02() {
    set<int>s1;
    set<int>s2;
    // 插入 INSERT
    s1.insert(10);
    s1.insert(40);
    s1.insert(30);
    s1.insert(20);
    s2.insert(100);
    s2.insert(400);
    s2.insert(300);
    s2.insert(200);

    printSet(s1);
    printSet(s2);

    // swap
    cout << "swapped: \n";
    s1.swap(s2);
    printSet(s1);
    printSet(s2);
}

int main() {
//    test01();
    test02();
    return 0;
}

总结:

  • 统计大小 —— size

  • 判断是否为空 —— empty

  • 交换容器 —— swap

2.7.4 set 插入和删除

功能描述:

  • set 容器进行插入数据和删除数据

函数原型:

  • insert(elem);

  • clear();

  • erase(pos);

    • 返回下一个元素的迭代器

  • erase(beg, end);

    • 返回下一个元素的迭代器

  • erase(elem);

    • 删除容器中值为elem 的元素

示例:

#include <iostream>
#include <set>
#include "print.h"

using namespace std;

// 插入和删除
void test01 () {
    set<int>s1;

    // insert
    s1.insert(30);
    s1.insert(10);
    s1.insert(20);
    s1.insert(30);

    // traversal
    printSet(s1);

    // delete
    s1.erase(s1.begin());
    printSet(s1);

    // 删除重载版本
    s1.erase(30);
    printSet(s1);

    // 清空
    s1.erase(s1.begin(), s1.end());
    printSet(s1);

    s1.clear();
    printSet(s1);
}

int main() {
    test01();
    return 0;
}

总结:

  • 插入 —— insert

  • 删除 —— erase

  • 清空 —— clear

2.7.5 set 查找和统计

功能描述:

  • 对 set 容器进行查找以及统计数据

函数原型:

  • find(key);

    • 查找key 是否存在。存在则返回对应迭代器,否则返回set.end()

  • count(key);

    • 统计set 的元素个数

示例:

#include <iostream>
#include <set>
#include "print.h"

using namespace std;

// 查询 和 统计
void test01 () {
    set<int>s1;

    // insert
    s1.insert(30);
    s1.insert(10);
    s1.insert(20);
    s1.insert(30);
    printSet(s1);

    // find
    set<int>::iterator pos = s1.find(200);
    if (pos != s1.end()) {
        cout << "found: " << *pos << endl;
    } else {
        cout << "not found" << endl;
    }

    // count 对于set 统计的结果仅限于 0 和 1
    int num = s1.count(30);
    cout << "num = " << num << endl;
}

int main() {
    test01();
    return 0;
}

总结:

  • 查找 —— find (返回的是迭代器)

  • 统计 —— count (对于set,结果为0 或 1)

2.7.6 set和 multiset 区别

区别:

  • set 不可以插入重复的数据,而multiset 可以

  • set 插入数据的同时会返回插入结果,表示插入是否成功

  • multiset 不会检测数据,因此可以插入重复数据

示例:

#include <iostream>
#include <set>
#include "print.h"

using namespace std;

// set 和 multiset 的区别
void test01 () {
    set<int>s;
    // 对组
    pair<set<int>::iterator, bool> ret = s.insert(10);

    if (ret.second) {
        cout << "first success" << endl;
    } else {
        cout << "first fail" << endl;
    }

    ret = s.insert(10);
    if (ret.second) {
        cout << "second success" << endl;
    } else {
        cout << "second fail" << endl;
    }


    // multiset 可重复
    multiset<int>ms;
    ms.insert(10);
    ms.insert(10);
    ms.insert(10);
    printMultiset(ms);
}

int main() {
    test01();
    return 0;
}

总结:

  • 若不允许插入重复数据,则使用set

  • 若允许插入重复数据,则使用multiset

2.7.7 pair 对组创建

功能描述:

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

两种创建方式:

  • pair<type, type> p(val1, val2);

  • pair<type, type> p = make_pair(val1, val2);

示例:

#include <iostream>
using namespace std;

// pair
void test01 () {
    // 1
    pair<string, int> p("Tom", 90);
    cout << "name: " << p.first << ", age: " << p.second << endl;

    // 2
    pair<string, int> p1 = make_pair("alan", 20);
    cout << "name: " << p1.first << ", age: " << p1.second << endl;
}

int main() {
    test01();
    return 0;
}

总结:

  • 两种方式都可以创建对组。

2.7.8 set 容器排序

主要技术点:

  • 利用仿函数,改变排序规则

示例1 —— set 存放内置数据类型

#include <iostream>
#include <set>
#include "print.h"
using namespace std;

// sorting rule
class myCompare {
    public:
    // 具有类型“XXX”的表达式会丢失一些 const-volatile 限定符以调用“XXX” 此时可以在函数体前添加const 限定符
        bool operator()(int v1, int v2) const{
            return v1 > v2;
        }
};

// set 内置排序
void test () {
    // 指定排序规则 desc
    set<int, myCompare>s; // 第二参数为 一个类

    s.insert(10);
    s.insert(40);
    s.insert(20);
    s.insert(50);
    s.insert(30);

    for (set<int, myCompare>::iterator it = s.begin(); it != s.end(); it++) {
        cout << *it << " ";
    }
    cout << endl;
}

int main() {
    test();
    return 0;
}

总结:

  • 利用仿函数可以指定set 容器的排序规则

示例2 —— set 存放自定义数据类型

#include <iostream>
#include <set>
#include "print.h"

using namespace std;

// self-definition
class Person {
public:
    string m_Name;
    int m_Age;

    Person(string name, int age) {
        this->m_Name = name;
        this->m_Age = age;
    }
};

// 自定义数据类型 必须指定排序规则
class comparePerson {
public:
    bool operator() (const Person p1, const Person p2) const{
        return p1.m_Age > p2.m_Age;
    }
};

// 存放自定义数据来下
void test() {
    set<Person, comparePerson>s;

    // 创建对象
    Person p1("a", 24);
    Person p2("b", 28);
    Person p3("c", 25);
    Person p4("d", 21);

    // insert
    s.insert(p1);
    s.insert(p2);
    s.insert(p3);
    s.insert(p4);

    // traversal
    for (set<Person, comparePerson>::iterator it = s.begin(); it != s.end(); it++) {
        cout << "Name: " << it->m_Name << " , age: " << it->m_Age << endl;
    }

}

int main() {
    test();
    return 0;
}

总结:

  • 对于自定义数据类型,set 必须指定排序规则才可以插入数据

2.8 map/multimap 容器

2.8.1 map 基本概念

简介:

  • map 中所有元素都是pair

  • pair 中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)

  • 所有元素都会根据元素的键值自动排序

本质:

  • 关联式容器,底层结构用二叉树实现

优点:

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

map与 multimap 的区别:

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

  • multimap允许容器中有重复key值元素

2.8.2 map 构造和赋值

功能描述:

  • 对map 容器进行构造和赋值操作

函数原型:

构造:

  • map(T1, T2) mp;

  • map(const map &mp);

赋值:

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

示例:

#include <iostream>
#include <map>
#include "print.h"
using namespace std;

// map 构造和赋值
void test() {
    // definition
    map<int, int>m;
    // insert
    m.insert(pair<int, int>(1, 10));
    m.insert(pair<int, int>(3, 30));
    m.insert(pair<int, int>(2, 20));
    m.insert(pair<int, int>(4, 40));

    // traversal 按照key 值自动升序排序
    printMap(m);

    // copy construction 拷贝构造
    map<int, int>m2(m);
    printMap(m2);

    // assignment
    map<int, int>m3;
    m3 = m2;
    printMap(m3);
}

int main() {
    test();
    return 0;
}

总结::

  • map 中所有元素都是成对出现,插入数据时要使用对组

2.8.3 map 大小和交换

功能描述:

  • 统计map 容器大小以及交换map 容器

函数原型:

  • size();

  • empty();

  • swap(st);

    • 交换两个集合容器

示例:

#include <iostream>
#include <map>
#include "print.h"
using namespace std;

// map 大小和被交换
// size
void test01() {
    // definition
    map<int, int>m;
    // insert
    m.insert(pair<int, int>(1, 10));
    m.insert(pair<int, int>(3, 30));
    m.insert(pair<int, int>(2, 20));
    m.insert(pair<int, int>(4, 40));

    if (m.empty()) {
        cout << "empty" << endl;
    } else {
        cout << "not empty" << endl;
        cout << "size = " << m.size() << endl;
    }
}

// swap
void test02() {
    // definition
    map<int, int>m1;
    map<int, int>m2;
    // insert
    m1.insert(pair<int, int>(1, 10));
    m1.insert(pair<int, int>(3, 30));
    m1.insert(pair<int, int>(2, 20));
    m1.insert(pair<int, int>(4, 40));

    m2.insert(pair<int, int>(1, 100));
    m2.insert(pair<int, int>(3, 300));
    m2.insert(pair<int, int>(2, 200));
    m2.insert(pair<int, int>(4, 400));

    // swap
    cout << "before:\n";
    printMap(m1);
    printMap(m2);
    cout << "after:\n";
    m1.swap(m2);
    printMap(m1);
    printMap(m2);
}

int main() {
    test01();
    test02();
    return 0;
}

总结:

  • 统计大小 —— size

  • 判断是否为空 —— empty

  • 交换容器 —— swap

2.8.4 map 插入和删除

功能描述:

  • map 容器进行插入和删除数据

函数原型:

  • insert(elem);

  • clear();

  • erase(pos);

  • erase(beg, end);

  • erase(key);

    • 删除容器中值为key 的元素

示例:

#include <iostream>
#include <map>
#include "print.h"
using namespace std;

// map 插入 和 删除
void test01() {
    // definition
    map<int, int>m;

    // insert 1
    m.insert(pair<int, int>(1, 10));

    // insert 2
    m.insert(make_pair(2, 20));

    // insert 3
    m.insert(map<int, int>::value_type(3, 30));

    // insert 4 not recommended 主要利用key来访问value
    m[4] = 40;

    // key: 5, value: 0
    //cout << m[5] << endl;
    printMap(m);

    // erase --- according to key
    m.erase(m.begin());
    printMap(m);

    m.erase(3);
    printMap(m);

    m.erase(m.begin(), m.end());
    printMap(m);

    // clear
    m.clear();
    printMap(m);
}

int main() {
    test01();
    return 0;
}

总结:

  • 插入 —— insert

  • 删除 —— erase

  • 清空 —— clear

2.8.5 map 查找和统计

功能描述:

  • 对map 容器进行数据查找以及统计数据

函数原型:

  • find(key);

    • 若存在,返回该键对应的迭代器;若不存在,返回set.end();

  • count(key);

    • 统计key 元素的个数

示例:

#include <iostream>
#include <map>
#include "print.h"
using namespace std;

// map 查找 和 统计
void test01() {
    // find
    map<int, int>m;
    m.insert(make_pair(1, 10));
    m.insert(make_pair(2, 20));
    m.insert(make_pair(3, 30));
//    m.insert(make_pair(3, 40)); 不允许插入重复键值

    map<int, int>::iterator pos = m.find(3);

    if (pos != m.end()) {
        cout << "found, key = " << (*pos).first << ", val = " << pos->second << endl;
    } else {
        cout << "not found" << endl;
    }

    // statistics
    int num = m.count(3);
    cout << "num = " << num << endl;
}

int main() {
    test01();
    return 0;
}

总结:

  • 查找 —— find(返回迭代器)

  • 统计 —— count(对于map, 结果为0 或 1)

2.8.6 map 容器排序

主要技术点:

  • 利用仿函数,客户以改变排序规则

示例:

#include <iostream>
#include <map>
#include "print.h"

using namespace std;

class my {
public:
    bool operator()(int v1, int v2) const {
        return v1 > v2;
    }
};

void test01() {
    map<int, int, my>m;
    m.insert(make_pair(1, 10));
    m.insert(make_pair(2, 20));
    m.insert(make_pair(3, 30));
    m.insert(make_pair(4, 40));
    m.insert(make_pair(5, 50));

    // desc
    for (map<int, int, my>::iterator it = m.begin(); it != m.end(); it++) {
        cout << "key: " << it->first << ", val: " << it->second << endl;
    }
    cout << endl;
}

int main() {
    test01();
    return 0;
}

总结:

  • 利用仿函数可以指定map 容器的排序规则

  • 对于自定义数据类型,map 必须指定排序规则,同set 容器

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_廿_尘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值