C++ STL之容器介绍(vector、list、set、map)

1 STL基本概念

  • C++有两大思想,面向对象和泛型编程。
  • 泛型编程指编写代码时不必指定具体的数据类型,而是使用模板来代替实际类型,这样编写的函数或类可以在之后应用于各种数据类型。而STL就是C++泛型编程的一个杰出例子。
  • STL(Standard Template Library)即标准模板库。STL通过使用模板实现了容器和算法的分离,允许程序员编写与类型无关的代码,这正是泛型编程的核心思想。

2 STL六大组件

  • STL分为六大组件,分别是容器、算法、迭代器、仿函数、适配器和空间配置器。
  • 容器 :各种数据结构,主要用来存放数据。如vectorlistmap等。
  • 算法 :各种常见的算法,用来处理元素。如sortfindcopyfor_each等。
  • 迭代器:连接容器和算法的桥梁
  • 仿函数:行为类似函数,可作为算法的某种策略
  • 适配器:一种用来修饰容器或者仿函数或迭代器接口的东西
  • 空间配置器:负责空间的配置与管理

3 容器概述

  • 容器分为序列式容器和关联式容器
  • 序列式容器:有序集合,其内的每个元素均有确凿的位置 - 取决于插入时机和地点,与元素值无关。主要有vectordequelistforward_list
  • 关联式容器:已排序集合,元素位置取决于其value(或key)和给定的某个排序准则。主要有setmultisetmapmultimap
类型 容器 迭代器 特点
序列容器 vector - 动态数组 迭代器支持随机访问 插入元素可能导致所有迭代器失效 删除元素会使指向被删除元素及之后元素的迭代器失效 支持快速随机访问 但在末尾以外位置插入或删除元素效率较低
序列容器 deque - 双端队列 迭代器支持随机访问 插入和删除元素都可能导致迭代器失效 两端都可以高效地进行插入和删除操作 随机访问效率没有vector高
序列容器 list - 双向链表 迭代器不支持随机访问 插入新元素不会使现有迭代器失效 删除元素只会使指向被删除元素的迭代器失效 支持高效的中间插入和删除操作,但访问速度较慢
关联容器 set/multiset 插入元素不会使迭代器失效 删除元素只会使指向被删除元素的迭代器失效 查找、插入和删除操作的时间复杂度为 O(log n)。
关联容器 map/multimap 插入元素不会使迭代器失效 删除元素只会使指向被删除元素的迭代器失效 查找、插入和删除操作的时间复杂度为 O(log n)。
容器适配器 stack - 栈 无迭代器 先进后出的数据结构
容器适配器 queue - 队列 无迭代器 先进先出的数据结构

4 vector

  • vector是动态数组。动态扩展时,会将原数据拷贝到一块新的内存中,再释放原内存空间。
  • vector迭代器支持随机访问,即可以进行+2,+3,+n操作。不支持随机访问的迭代器只能进行++操作。
  • 结构图示

4.1 vector构造

  • vector<T> v:默认构造

  • vector(v.begin(), v.end()):将[begin, end)区间的元素拷贝给本身

  • vector(n, elem):将n个elem元素拷贝给本身

  • vector(const vector &vec):拷贝构造

  • vector构造示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <vector>
      
      int main() {
      	// 默认构造
      	std::vector<int> v1;
      
      	// 插入数据
      	v1.push_back(10);
      	v1.push_back(20);
      	v1.push_back(30);
      	v1.push_back(40);
      	v1.push_back(50);
      
      	// 通过区间方式构造
      	std::vector<int> v2(v1.begin(), v1.end());
      
      	// 构造时放入5个100
      	std::vector<int> v3(10, 100);
      
      	// 拷贝构造
      	std::vector<int> v4(v3);
      
      	system("pause");
      	return 0;
      }

4.2 vector赋值

  • vector& operator=(const vector &vec)

  • assign(beg, end):将[beg, end)区间的元素赋值给本身

  • assign(n, elem):将n个elem元素赋值给本身

  • vector赋值示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <vector>
      
      int main() {
      	// 默认构造
      	std::vector<int> v1;
      
      	// 插入数据
      	v1.push_back(10);
      	v1.push_back(20);
      	v1.push_back(30);
      	v1.push_back(40);
      	v1.push_back(50);
      
      	// 通过=赋值
      	std::vector<int> v2;
      	v2 = v1;
      
      	// 通过assign赋值一个区间的值
      	std::vector<int> v3;
      	v3.assign(v1.begin(), v1.end());
      
      	// 通过assign赋值5个100
      	std::vector<int> v4;
      	v4.assign(5, 100);
      
      	system("pause");
      	return 0;
      }

4.3 vector容量和大小

  • empty(): 判断容器是否为空
  • capacity(): 容器的容量
  • size(): 容器中元素个数
  • resize(int num): 重新指定容器的长度为num,若容器变长,则以默认值填充新位置。若容器变短,则末尾超出长度的元素被删除。
  • resize(int num, const value_type& value): 同上,只不过在容器变长时以value填充新位置。
  • void reserve(int len): 容器预留len长度的空间,预留位置不初始化,元素不可访问。预留容器的空间可以减少vector在动态扩展时的扩展次数。

4.4 vector插入和删除

  • push_back(elem): 尾部插入元素。

  • pop_back(): 删除尾部元素。

  • iterator insert(pos, elem): 迭代器指向位置pos处插入元素elem,返回新元素的位置。

  • iterator insert(pos, count, elem): 迭代器执行位置pos处插入count个元素elem,返回新元素的位置。

  • iterator erase(pos): 删除迭代器pos指向的元素,返回下一个数据的位置。

  • iterator erase(first, last): 删除迭代器从first带last之间的元素,返回下一个数据的位置。

  • clear(): 删除容器中所有元素。

  • 插入删除示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <vector>
      #include <algorithm>
      
      void printVector(std::vector<int>& vec) {
      	// 遍历数据
      	std::cout << "vector: ";
      	for (std::vector<int>::iterator iter = vec.begin(); iter != vec.end(); iter++) {
      		std::cout << *iter << " ";
      	}
      	std::cout << std::endl;
      }
      
      
      int main() {
      	std::vector<int> v;
      
      	// 插入数据
      	v.push_back(10);
      	v.push_back(20);
      	v.push_back(30);
      	v.push_back(40);
      	printVector(v);
      
      	v.pop_back();
      	printVector(v);
      
      	v.insert(v.begin(), 1024);
      	printVector(v);
      
      	v.insert(v.begin(), 2, 520);
      	printVector(v);
      
      	// 删除
      	v.erase(v.begin());
      	printVector(v);
      
      
      	system("pause");
      	return 0;
      }
  • 打印结果
    *

        vector: 10 20 30 40
        vector: 10 20 30
        vector: 1024 10 20 30
        vector: 520 520 1024 10 20 30
        vector: 520 1024 10 20 30
        请按任意键继续. . .
    
  • vector插入自定义数据类型
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <vector>
      #include <algorithm>
      
      class Person {
      public:
      	Person(int code, std::string name) {
      		mCode = code;
      		mName = name;
      	}
      
      	int mCode;
      	std::string mName;
      };
      
      void vPrint(Person data) {
      	std::cout << "code: " << data.mCode << std::endl;
      	std::cout << "name: " << data.mName << std::endl;
      }
      
      int main() {
      	Person p1(10010, "Tom");
      	Person p2(10020, "Jack");
      	Person p3(10030, "Lucy");
      	Person p4(10040, "Mary");
      
      
      	std::vector<Person> v;
      
      	// 插入数据
      	v.push_back(p1);
      	v.push_back(p2);
      	v.push_back(p3);
      	v.push_back(p4);
      
      	// 通过迭代器遍历数据
      	for (std::vector<Person>::iterator iter = v.begin(); iter != v.end(); iter++) {
      		std::cout << "code " << (*iter).mCode << std::endl;
      		std::cout << "name " << (*iter).mName << std::endl;
      	}
      
      	// 通过算法遍历
      	std::for_each(v.begin(), v.end(), vPrint);
      	
      	system("pause");
      	return 0;
      }

4.5 vector数据存取

  • at( size_type pos ): 返回索引pos处的数据

  • operator[]( size_type pos ): 返回索引pos处的数据

  • front(): 返回容器中第一个元素

  • back(): 返回容器中最后一个元素

  • 数据存储示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <vector>
      
      void printVector(std::vector<int>& vec) {
      	// 遍历数据
      	std::cout << "vector[]: ";
      	for (int i = 0; i < vec.size(); i++) {
      		std::cout << vec[i] << " ";
      	}
      	std::cout << std::endl;
      
      	std::cout << "vector at: ";
      	for (int i = 0; i < vec.size(); i++) {
      		std::cout << vec.at(i) << " ";
      	}
      	std::cout << std::endl;
      }
      
      
      int main() {
      	std::vector<int> v;
      
      	// 插入数据
      	v.push_back(10);
      	v.push_back(20);
      	v.push_back(30);
      	v.push_back(40);
      	printVector(v);
      
      	system("pause");
      	return 0;
      }

4.6 通过swap缩小容器容量

  • void swap( vector& other ): 交换两个容器中的元素。常用的一个场景是缩小容器容量

  • 示例如下
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <vector>
      
      int main() {
      	// 默认构造
      	std::vector<int> v1;
      
      	// 插入50万个数据
      	for (int i = 0; i < 500000; i++) {
      		v1.push_back(i);
      	}
      	
      	// 容器中元素为50万,容器容量可能为70万
      	std::cout << "v1.size: " << v1.size() << std::endl;
      	std::cout << "v1.cap: " << v1.capacity() << std::endl;
      
      	// 后续如果要删除元素,比如只剩下3个元素了
      	// 此时容器元素个数为3,但容器容量依然是70万,造成资源浪费
      	v1.resize(3);
      	std::cout << "v1.size: " << v1.size() << std::endl;
      	std::cout << "v1.cap: " << v1.capacity() << std::endl;
      
      	// 通过匿名对象交换容器
      	// 匿名对象中的元素会被系统自动回收
      	std::vector<int>(v1).swap(v1);
      
      	// v1此时的元素个数和容量都为3
      	std::cout << "v1.size: " << v1.size() << std::endl;
      	std::cout << "v1.cap: " << v1.capacity() << std::endl;
      
      	system("pause");
      	return 0;
      }

5 deque

  • deque是双端队列,可以在头部进行插入删除操作
  • vector对于头部的插入删除效率低,数据量越大,效率越低。deque对头部的插入删除速度比vector快。vector访问元素的速度比deque快。
  • deque容器的迭代器支持随机访问。
  • 结构图示
  • deque工作原理:deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据。中控器维护的是每段缓冲区的地址。图示如下
  • deque的构造、赋值、遍历、数据存取和vector基本类似,这里就不再介绍。

5.1 deque容量和大小

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

5.2 deque插入和删除

  • push_back(elem):容器尾部插入数据。

  • push_front(elem):容器头部插入数据。

  • pop_back():删除容器尾部最后一个数据。

  • pop_front():删除容器头部第一个容器。

  • iterator intsert(pos, elem):在pos位置插入一个elem数据,返回新数据的位置。

  • iterator intsert(pos, n, elem):在pos位置插入n个elem数据,返回新数据的位置。

  • iterator intsert(pos, beg, end):在pos位置插入[beg, end)区间的数据,返回新数据的位置。

  • clear():清空容器的所有数据。

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

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

  • 代码示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <deque>
      
      void printDeque(std::deque<int> & de) {
      	std::cout << "deque: ";
      	for (std::deque<int>::iterator iter = de.begin(); iter != de.end(); iter++) {
      		std::cout << *iter << " ";
      	}
      	std::cout << std::endl;
      }
      
      int main() {
      	// 默认构造
      	std::deque<int> d1;
      
      	// 尾部插入
      	d1.push_back(10);
      	d1.push_back(20);
      	d1.push_back(30);
      	printDeque(d1);
      
      	// 头部插入
      	d1.push_front(40);
      	d1.push_front(50);
      	d1.push_front(60);
      	printDeque(d1);
      
      	// 删除尾部元素
      	d1.pop_back();
      	printDeque(d1);
      
      	// 删除头部元素
      	d1.pop_front();
      	printDeque(d1);
      
      	// insert插入
      	std::deque<int>::iterator iter1 = d1.insert(d1.begin(), 1024);
      	printDeque(d1);
      	std::cout << "*iter1: " << *iter1 << std::endl;
      
      	// insert插入多个元素
      	std::deque<int>::iterator iter2 = d1.insert(d1.begin(), 2, 256);
      	printDeque(d1);
      	std::cout << "*iter2: " << *iter2 << std::endl;
      
      	std::deque<int> d2;
      	d2.push_back(1);
      	d2.push_back(2);
      	d2.push_back(3);
      
      	// insert 区间插入
      	std::deque<int>::iterator iter3 = d1.insert(d1.begin(), d2.begin(), d2.end());
      	printDeque(d1);
      	std::cout << "*iter3: " << *iter3 << std::endl;
      
      	// 删除指定位置元素
      	std::deque<int>::iterator iter4 = d1.begin();
      	iter4++;
      	std::deque<int>::iterator iter5 = d1.erase(iter4);
      	printDeque(d1);
      	std::cout << "*iter5: " << *iter5 << std::endl;
      
      	// 删除所有元素
      	d1.clear();
      
      	system("pause");
      	return 0;
      }
  • 打印结果
    *

        deque: 10 20 30
        deque: 60 50 40 10 20 30
        deque: 60 50 40 10 20
        deque: 50 40 10 20
        deque: 1024 50 40 10 20
        *iter1: 1024
        deque: 256 256 1024 50 40 10 20
        *iter2: 256
        deque: 1 2 3 256 256 1024 50 40 10 20
        *iter3: 1
        deque: 1 3 256 256 1024 50 40 10 20
        *iter5: 3
        请按任意键继续. . .
    

5.3 deque排序

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

  • 迭代器支持随机访问的容器都可以使用sort进行排序

  • 代码示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <deque>
      #include <algorithm>
      
      void printDeque(std::deque<int> & de) {
      	std::cout << "deque: ";
      	for (std::deque<int>::iterator iter = de.begin(); iter != de.end(); iter++) {
      		std::cout << *iter << " ";
      	}
      	std::cout << std::endl;
      }
      
      int main() {
      	// 默认构造
      	std::deque<int> d1;
      
      	// 尾部插入
      	d1.push_back(10);
      	d1.push_back(900);
      	d1.push_back(23);
      	d1.push_back(250);
      	d1.push_back(18);
      	printDeque(d1);
      
      	sort(d1.begin(), d1.end());
      	printDeque(d1);
      
      	system("pause");
      	return 0;
      }
  • 结果打印
    *

    c 复制代码
      deque: 10 900 23 250 18
      deque: 10 18 23 250 900
      请按任意键继续. . .

6 stack

  • stack是栈,一种先进后出的数据结构,只有一个出口。
  • 栈中只有顶端元素才可以被外部使用,因此栈没有遍历操作。
  • 结构图示

6.1 stack赋值操作

  • stack& operator=(const stack &stk)

6.2 stack数据存取

  • push(elem):向栈顶添加元素(入栈)。
  • pop():从栈顶移除元素(出栈)。
  • top():返回栈顶元素。

6.3 stack 大小操作

  • empty():判断栈是否为空。

  • size():返回栈大小。

  • 使用示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <stack>
      
      int main() {
      	// 默认构造
      	std::stack<int> st1;
      
      	// 入栈
      	st1.push(10);
      	st1.push(20);
      	st1.push(30);
      	st1.push(40);
      
      	// 获取栈顶元素
      	std::cout << "stack top: " << st1.top() << std::endl;
      	std::cout << "stack size: " << st1.size() << std::endl;
      
      	while (!st1.empty()) {
      		std::cout << "stack top: " << st1.top() << std::endl;
      
      		// 出栈
      		st1.pop();
      	}
      
      	std::cout << "stack size: " << st1.size() << std::endl;
      
      
      	system("pause");
      	return 0;
      }
  • 打印结果
    *

        stack top: 40
        stack size: 4
        stack top: 40
        stack top: 30
        stack top: 20
        stack top: 10
        stack size: 0
        请按任意键继续. . .
    

7 queue

  • queue是队列,一种先进先出的数据结构。
  • 队列允许从一端新增元素,另一端移除元素。队列中只有队头和队尾才可以被外部使用,因此队列不允许有遍历行为。
  • 结构图示

7.1 queue构造

  • queue<T> que:默认构造。
  • queue(const queue &que):拷贝构造。

7.2 queue赋值

  • queue& operator=(const queue &que)

7.3 queue数据存取

  • push(elem):队尾添加元素(入队)。
  • pop():移除队头元素(出队)。
  • back():返回队尾元素。
  • front():返回队头元素。

7.4 queue大小操作

  • empty():判断队列是否为空。

  • size():返回队列大小。

  • 使用示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <queue>
      
      int main() {
      	// 默认构造
      	std::queue<int> que1;
      
      	// 入队
      	que1.push(10);
      	que1.push(20);
      	que1.push(30);
      	que1.push(40);
      
      	std::cout << "size: " << que1.size() << std::endl;
      	while (!que1.empty()) {
      		// 查看队头和队尾元素
      		std::cout << "front: " << que1.front()  << ", back: "<< que1.back() << std::endl;
      
      		// 出队
      		que1.pop();
      	}
      	std::cout << "size: " << que1.size() << std::endl;
      
      
      	system("pause");
      	return 0;
      }
  • 打印结果
    *

        size: 4
        front: 10, back: 40
        front: 20, back: 40
        front: 30, back: 40
        front: 40, back: 40
        size: 0
        请按任意键继续. . .
    

8 list

  • list是链表,一种物理存储单元上非连续的存储结构。list可以在任意位置进行快速插入和删除元素,但遍历速度没有vector快。list的迭代器属于双向迭代器。
  • list插入和删除都不会造成原有list迭代器的失效。list的迭代器不支持随机访问。
  • STL中的链表是一个双向循环链表。
  • 结构图示

8.1 list构造

  • list<T> lst:默认构造

  • list(begin, end):将[begin, end)区间的元素拷贝给本身

  • list(n, elem):将n个elem元素拷贝给本身

  • list(const list &lst):拷贝构造。

  • 使用示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <list>
      
      void printList(std::list<int>& lst) {
      	std::cout << "list: ";
      	for (std::list<int>::iterator iter = lst.begin(); iter != lst.end(); iter++) {
      		std::cout << *iter << " ";
      	}
      	std::cout << std::endl;
      }
      
      int main() {
      	// 默认构造
      	std::list<int> lst1;
      
      	// 添加数据
      	lst1.push_back(10);
      	lst1.push_back(20);
      	lst1.push_back(30);
      	lst1.push_back(40);
      
      	printList(lst1);
      
      	// 区间方式构造
      	std::list<int> lst2(lst1.begin(), lst1.end());
      	printList(lst2);
      
      	// 拷贝构造
      	std::list<int> lst3(lst2);
      	printList(lst3);
      
      	std::list<int> lst4(5, 10);
      	printList(lst4);
      
      	system("pause");
      	return 0;
      }
  • 打印结果
    *

        list: 10 20 30 40
        list: 10 20 30 40
        list: 10 20 30 40
        list: 10 10 10 10 10
        请按任意键继续. . .
    

8.2 list赋值和交换

  • assign(beg, end):将[beg, end)区间的数据拷贝给本身。

  • assign(n, elem):将n个elem元素拷贝给本身。

  • list& operator=(const list &lst)

  • swap(lst):将lst元素与本身元素互换。

  • 使用示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <list>
      
      void printList(std::list<int>& lst) {
      	std::cout << "list: ";
      	for (std::list<int>::iterator iter = lst.begin(); iter != lst.end(); iter++) {
      		std::cout << *iter << " ";
      	}
      	std::cout << std::endl;
      }
      
      int main() {
      	// 默认构造
      	std::list<int> lst1;
      
      	// 添加数据
      	lst1.push_back(10);
      	lst1.push_back(20);
      	lst1.push_back(30);
      	lst1.push_back(40);
      
      	printList(lst1);
      
      	// 赋值
      	std::list<int> lst2;
      	lst2 = lst1;
      	printList(lst2);
      
      	std::list<int> lst3;
      	lst3.assign(lst1.begin(), lst1.end());
      	printList(lst3);
      
      	std::list<int> lst4;
      	lst4.assign(5, 10);
      	printList(lst4);
      
      	// 交换
      	std::list<int> lst5;
      
      	// 添加数据
      	lst5.push_back(100);
      	lst5.push_back(200);
      	lst5.push_back(300);
      	lst5.push_back(400);
      
      	std::cout << "交换前" << std::endl;
      	printList(lst1);
      	printList(lst5);
      	lst1.swap(lst5);
      	std::cout << "交换前" << std::endl;
      	printList(lst1);
      	printList(lst5);
      
      
      	system("pause");
      	return 0;
      }
  • 打印结果
    *

        list: 10 20 30 40
        list: 10 20 30 40
        list: 10 20 30 40
        list: 10 10 10 10 10
        交换前
        list: 10 20 30 40
        list: 100 200 300 400
        交换前
        list: 100 200 300 400
        list: 10 20 30 40
        请按任意键继续. . .
    

8.3 list容量和大小

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

8.4 list插入和删除

  • push_back(elem):容器尾部插入一个元素elem

  • pop_back():删除容器中最后一个元素

  • push_front(elem):在容器头部插入一个元素

  • pop_front():移除容器头部的一个元素

  • insert(pos, elem):在pos位置插入elem元素,返回新元素的位置

  • insert(pos, n, elem):在pos位置插入n个elem元素,返回新元素的位置

  • insert(pos, beg, end):在pos位置插入[beg, end)区间的元素,返回新元素的位置

  • clear():移除容器中所有元素

  • erese(beg, end):删除[beg, end)区间的元素,返回下一个元素的位置

  • erese(pos):删除pos位置处的元素,返回下一个元素的位置

  • remove(elem):删除容器中所有与elem值匹配的元素

  • 使用示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <list>
      
      void printList(std::list<int>& lst) {
      	std::cout << "list: ";
      	for (std::list<int>::iterator iter = lst.begin(); iter != lst.end(); iter++) {
      		std::cout << *iter << " ";
      	}
      	std::cout << std::endl;
      }
      
      int main() {
      	// 默认构造
      	std::list<int> lst1;
      
      	// 尾部添加数据
      	lst1.push_back(10);
      	lst1.push_back(20);
      	lst1.push_back(30);
      	lst1.push_back(40);
      
      	// 头部添加元素
      	lst1.push_front(50);
      	lst1.push_front(60);
      
      	printList(lst1);
      
      	// 尾部删除
      	lst1.pop_back();
      
      	// 头部删除
      	lst1.pop_front();
      
      	printList(lst1);
      
      	std::list<int>::iterator iter;
      	// insert插入
      	iter = lst1.begin();
      	iter++;
      	lst1.insert(iter, 1024);
      	printList(lst1);
      
      	// 删除
      	iter = lst1.begin();
      	lst1.erase(iter);
      	printList(lst1);
      
      	// 移除
      	lst1.push_back(30);
      	lst1.push_back(30);
      	lst1.remove(30);
      	printList(lst1);
      
      	system("pause");
      	return 0;
      }
  • 打印结果
    *

        list: 60 50 10 20 30 40
        list: 50 10 20 30
        list: 50 1024 10 20 30
        list: 1024 10 20 30
        list: 1024 10 20
        请按任意键继续. . .
    

8.5 list数据存取

  • front():返回容器中第一个元素
  • back():返回容器中最后一个元素

8.6 list反转和排序

  • reverse():反转链表

  • sort():链表排序

  • 使用示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <list>
      
      void printList(std::list<int>& lst) {
      	std::cout << "list: ";
      	for (std::list<int>::iterator iter = lst.begin(); iter != lst.end(); iter++) {
      		std::cout << *iter << " ";
      	}
      	std::cout << std::endl;
      }
      
      bool myCompare(int data1, int data2) {
      	// 设置降序
      	return data1 > data2;
      }
      
      int main() {
      	// 默认构造
      	std::list<int> lst1;
      
      	// 尾部添加数据
      	lst1.push_back(10);
      	lst1.push_back(200);
      	lst1.push_back(54);
      	lst1.push_back(1024);
      	lst1.push_back(521);
      	printList(lst1);
      
      	// 反转
      	lst1.reverse();
      	printList(lst1);
      
      	// 排序 - 升序
      	lst1.sort();
      	printList(lst1);
      
      	// 排序 - 降序
      	lst1.sort(myCompare);
      	printList(lst1);
      
      	system("pause");
      	return 0;
      }
  • 打印结果
    *

        list: 10 200 54 1024 521
        list: 521 1024 54 200 10
        list: 10 54 200 521 1024
        list: 1024 521 200 54 10
        请按任意键继续. . .
    

9 pair对组

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

9.1 创建方式

  • pair<type, type> p(value1, value2)

  • pair<type, type> p = make_pair(value1, value2)

  • 使用示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      
      int main() {
      	// 第一种创建方式
      	std::pair<int, std::string> pa(10010, "Tom");
      	std::cout << "pa.first: " << pa.first << ", pa.second: " << pa.second << std::endl;
      
      	// 第二种创建方式
      	std::pair<int, std::string> pa2 = std::make_pair(10020, "Mary");
      	std::cout << "pa2.first: " << pa2.first << ", pa2.second: " << pa2.second << std::endl;
      
      	system("pause");
      	return 0;
      }
  • 打印结果
    *

        pa.first: 10010, pa.second: Tom
        pa2.first: 10020, pa2.second: Mary
        请按任意键继续. . .
    

10 set/multiset

  • set/multiset属于关联式容器,底层结构是用二叉树实现(通常为平衡二叉树),所有元素会在插入时自动排序。
  • set不允许容器中有重复的元素,multiset允许容器中有重复的元素。
  • 结构图示

10.1 set构造和赋值

  • set<T> st:默认构造

  • set(const set& st):拷贝构造

  • set& operator=(const set& st):赋值

  • 使用示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <vector>
      #include <algorithm>
      #include <set>
      
      void printSet(std::set<int>& st) {
      	// 遍历数据
      	std::cout << "list: ";
      	for (std::set<int>::iterator iter = st.begin(); iter != st.end(); iter++) {
      		std::cout << *iter << " ";
      	}
      	std::cout << std::endl;
      }
      
      
      int main() {
      	std::set<int> st;
      
      	// 插入数据
      	st.insert(10);
      	st.insert(100);
      	st.insert(100);
      	st.insert(15);
      	st.insert(520);
      	st.insert(2);
      
      	printSet(st);
      
      	// 拷贝构造
      	std::set<int> st2(st);
      	printSet(st2);
      
      	// 赋值
      	std::set<int> st3;
      	st3 = st;
      	printSet(st3);
      
      	system("pause");
      	return 0;
      }
  • 打印结果
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <vector>
      #include <algorithm>
      #include <set>
      
      void printSet(std::set<int>& st) {
      	// 遍历数据
      	std::cout << "list: ";
      	for (std::set<int>::iterator iter = st.begin(); iter != st.end(); iter++) {
      		std::cout << *iter << " ";
      	}
      	std::cout << std::endl;
      }
      
      
      int main() {
      	std::set<int> st;
      
      	// 插入数据
      	st.insert(10);
      	st.insert(100);
      	st.insert(100);
      	st.insert(15);
      	st.insert(520);
      	st.insert(2);
      
      	printSet(st);
      
      	// 拷贝构造
      	std::set<int> st2(st);
      	printSet(st2);
      
      	// 赋值
      	std::set<int> st3;
      	st3 = st;
      	printSet(st3);
      
      	system("pause");
      	return 0;
      }

10.2 set大小和交换

  • size():获取容器中元素个数。
  • empty():判断容器是否为空。
  • swap(st):交换两个容器。

10.3 set插入和删除

  • insert(elem):插入元素。
  • clear():清除所有元素。
  • erase(pos):删除pos迭代器指向的元素,返回下一个元素的迭代器。
  • erase(beg, end):删除区间[beg, end)的所有元素,返回下一个元素的迭代器。
  • erase(elem):删除容器中值为elem的元素。

10.4 set查找和统计

  • find(key):查找key是否存在,若存在,返回该键的元素的迭代器,若不存在,返回set.end()。

  • count(key):统计key的元素个数。对于set容器,只有0或者1。

  • 使用示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <vector>
      #include <algorithm>
      #include <set>
      
      void printSet(std::set<int>& st) {
      	// 遍历数据
      	std::cout << "list: ";
      	for (std::set<int>::iterator iter = st.begin(); iter != st.end(); iter++) {
      		std::cout << *iter << " ";
      	}
      	std::cout << std::endl;
      }
      
      
      int main() {
      	std::set<int> st;
      
      	// 插入数据
      	st.insert(10);
      	st.insert(100);
      	st.insert(100);
      	st.insert(15);
      	st.insert(520);
      	st.insert(2);
      
      	printSet(st);
      
      	std::set<int>::iterator iter = st.find(100);
      	if (iter != st.end()) {
      		std::cout << "*iter: " << *iter << std::endl;
      	}
      
      	std::cout << "st.count(100): " << st.count(100) << std::endl;
      
      	system("pause");
      	return 0;
      }
  • 打印结果
    *

        list: 2 10 15 100 520
        *iter: 100
        st.count(100): 1
        请按任意键继续. . .
    

10.5 set和multiset区别

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

  • set插入数据的同时会返回插入结果,表示是否插入成功。multiset不会检测数据,因此可以插入重复数据。

  • 示例
    *

    c 复制代码
      #include <iostream>
      #include <set>
      
      int main() {
      	std::set<int> st;
      
      	// 插入数据
      	
      	std::pair<std::set<int>::iterator, bool> ret;
      	// 返回值为pair, 第一个参数为插入位置迭代器,第二个参数表示是否插入成功
      	ret = st.insert(100);
      	if (ret.second) {
      		// 插入成功
      		std::cout << "插入成功: " << *ret.first <<std::endl;
      	}
      	else {
      		// 插入失败
      		std::cout << "插入失败" << std::endl;
      	}
      
      	ret = st.insert(100);
      	if (ret.second) {
      		// 插入成功
      		std::cout << "插入成功: " << *ret.first << std::endl;
      	}
      	else {
      		// 插入失败
      		std::cout << "插入失败" << std::endl;
      	}
      
      	std::multiset<int> mst;
      
      	std::set<int>::iterator iter;
      	// 返回值为插入位置迭代器
      	iter = mst.insert(200);
      	std::cout << "*iter: " << *iter << std::endl;
      	iter = mst.insert(200);
      	std::cout << "*iter: " << *iter << std::endl;
      
      	system("pause");
      	return 0;
      }
  • 打印结果
    *

        插入成功: 100
        插入失败
        *iter: 200
        *iter: 200
        请按任意键继续. . .
    

10.6 set容器排序

  • set容器默认排序规则是从小到大,利用仿函数,可以改变默认排序规则。

  • set存放内置数据类型

  • 使用示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <vector>
      #include <algorithm>
      #include <set>
      
      // 利用仿函数指定排序规则为从大到小
      class myCompare {
      public:
      	bool operator()(int data1, int data2) {
      		return data1 > data2;
      	}
      };
      
      int main() {
      	std::set<int> st;
      
      	// 插入数据
      	st.insert(10);
      	st.insert(100);
      	st.insert(15);
      	st.insert(520);
      	st.insert(2);
      	std::cout << "st: ";
      	for (std::set<int>::iterator iter = st.begin(); iter != st.end(); iter++) {
      		std::cout << *iter << " ";
      	}
      	std::cout << std::endl;
      
      	// 指定排序规则为从大到小
      	// 利用仿函数
      	std::set<int, myCompare> st2;
      	st2.insert(10);
      	st2.insert(100);
      	st2.insert(15);
      	st2.insert(520);
      	st2.insert(2);
      	std::cout << "st2: ";
      	for (std::set<int, myCompare>::iterator iter = st2.begin(); iter != st2.end(); iter++) {
      		std::cout << *iter << " ";
      	}
      	std::cout << std::endl;
      
      	system("pause");
      	return 0;
      }
  • 打印结果
    *

        st: 2 10 15 100 520
        st2: 520 100 15 10 2
        请按任意键继续. . .
    
  • set存放自定义数据类型

  • 使用示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <set>
      
      class Person {
      public:
      	Person(int code, std::string name) {
      		mCode = code;
      		mName = name;
      	}
      
      	int mCode;
      	std::string mName;
      };
      
      // 利用仿函数指定排序规则
      class myComparePerson {
      public:
      	bool operator()(const Person &p1, const Person &p2) {
      		return p1.mCode < p2.mCode;
      	}
      };
      
      int main() {
      	std::set<Person, myComparePerson> st;
      
      	Person p1(10010, "Tom");
      	Person p2(10080, "Jack");
      	Person p3(10000, "Mary");
      	Person p4(11100, "Lucy");
      
      	// 插入数据
      	st.insert(p1);
      	st.insert(p2);
      	st.insert(p3);
      	st.insert(p4);
      
      	for (std::set<Person, myComparePerson>::iterator iter = st.begin(); iter != st.end(); iter++) {
      		std::cout << iter->mCode << " " << iter->mName << std::endl;
      	}
      
      	system("pause");
      	return 0;
      }
  • 打印结果
    *

        10000 Mary
        10010 Tom
        10080 Jack
        11100 Lucy
        请按任意键继续. . .
    

11 map/multimap

  • map中所有元素都是pair,pair中第一个元素为key(键值),起到索引作用,第二个元素为value(值),所有元素都会根据元素的键值自动排序。
  • map/multimap属于关联式容器,底层结构是用二叉树实现(通常为平衡二叉树)。
  • map中不允许容器中有重复key值,multimap允许容器中有重复key值。
  • 结构图示

11.1 map构造和赋值

  • map<T1, T2> mp:默认构造

  • map(const map &mp):拷贝构造

  • map& operator=(const map& mp):等号赋值。

  • 使用示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <map>
      
      void printMap(std::map<int, std::string>& mp) {
      	// 遍历数据
      	for (std::map<int, std::string>::iterator iter = mp.begin(); iter != mp.end(); iter++) {
      		std::cout << "iter->first: " << iter->first << ", iter->second: " << iter->second << std::endl;
      	}
      }
      
      
      int main() {
      	std::map<int, std::string> mp;
      
      	// 插入数据
      	mp.insert(std::pair<int, std::string>(10010, "AA"));
      	mp.insert(std::pair<int, std::string>(11000, "BB"));
      	mp.insert(std::pair<int, std::string>(11110, "CC"));
      	mp.insert(std::pair<int, std::string>(10000, "DD"));
      	mp.insert(std::pair<int, std::string>(10001, "EE"));
      	std::cout << "mp: " << std::endl;
      	printMap(mp);
      
      	// 拷贝构造
      	std::map<int, std::string> mp2(mp);
      	std::cout << "mp2: " << std::endl;
      	printMap(mp2);
      
      	// 赋值
      	std::map<int, std::string> mp3;
      	mp3 = mp;
      	std::cout << "mp3: " << std::endl;
      	printMap(mp3);
      
      	system("pause");
      	return 0;
      }
  • 打印结果
    *

        mp:
        iter->first: 10000, iter->second: DD
        iter->first: 10001, iter->second: EE
        iter->first: 10010, iter->second: AA
        iter->first: 11000, iter->second: BB
        iter->first: 11110, iter->second: CC
        mp2:
        iter->first: 10000, iter->second: DD
        iter->first: 10001, iter->second: EE
        iter->first: 10010, iter->second: AA
        iter->first: 11000, iter->second: BB
        iter->first: 11110, iter->second: CC
        mp3:
        iter->first: 10000, iter->second: DD
        iter->first: 10001, iter->second: EE
        iter->first: 10010, iter->second: AA
        iter->first: 11000, iter->second: BB
        iter->first: 11110, iter->second: CC
        请按任意键继续. . .
    

11.2 map大小和交换

  • size():返回容器中元素个数。
  • empty():判断容器是否为空。
  • swap(st):交换两个容器数据。

11.3 map插入和删除

  • insert(elem):插入元素。

  • clear():清除所有元素。

  • erase(pos):删除pos迭代器指向的元素,返回下一个元素的迭代器。

  • erase(beg, end):删除区间[beg, end)的所有元素,返回下一个元素的迭代器。

  • erase(elem):删除容器中值为elem的元素。

  • 使用示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <map>
      
      void printMap(std::map<int, std::string>& mp) {
      	// 遍历数据
      	for (std::map<int, std::string>::iterator iter = mp.begin(); iter != mp.end(); iter++) {
      		std::cout << "iter->first: " << iter->first << ", iter->second: " << iter->second << std::endl;
      	}
      }
      
      int main() {
      	std::map<int, std::string> mp;
      
      	// 插入数据
      	// 第一种插入方式
      	mp.insert(std::pair<int, std::string>(10010, "AA"));
      	mp.insert(std::pair<int, std::string>(11000, "BB"));
      	
      	// 第二种插入方式
      	mp.insert(std::make_pair(11110, "CC"));
      	mp.insert(std::make_pair(10000, "DD"));
      
      	// 第三种插入方式
      	mp.insert(std::map<int, std::string>::value_type(10001, "EE"));
      
      	// 第四种插入方式(不建议使用)
      	mp[11111] = "FF";
      
      	std::cout << "mp: " << std::endl;
      	printMap(mp);
      
      	// 删除
      	// 根据迭代器删除
      	mp.erase(mp.begin());
      	std::cout << "根据迭代器删除: " << std::endl;
      	printMap(mp);
      
      	// 根据key值删除
      	mp.erase(11111);
      	std::cout << "根据key值删除: " << std::endl;
      	printMap(mp);
      
      	system("pause");
      	return 0;
      }
  • 打印结果
    *

        mp:
        iter->first: 10000, iter->second: DD
        iter->first: 10001, iter->second: EE
        iter->first: 10010, iter->second: AA
        iter->first: 11000, iter->second: BB
        iter->first: 11110, iter->second: CC
        iter->first: 11111, iter->second: FF
        根据迭代器删除:
        iter->first: 10001, iter->second: EE
        iter->first: 10010, iter->second: AA
        iter->first: 11000, iter->second: BB
        iter->first: 11110, iter->second: CC
        iter->first: 11111, iter->second: FF
        根据key值删除:
        iter->first: 10001, iter->second: EE
        iter->first: 10010, iter->second: AA
        iter->first: 11000, iter->second: BB
        iter->first: 11110, iter->second: CC
        请按任意键继续. . .
    

11.4 map查找和统计

  • find(key):查找key是否存在,若存在,返回该键的元素的迭代器,若不存在,返回map.end()。

  • count(key):统计key的元素个数。对于map容器,只有0或者1。

  • 使用示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <map>
      
      void printMap(std::map<int, std::string>& mp) {
      	// 遍历数据
      	for (std::map<int, std::string>::iterator iter = mp.begin(); iter != mp.end(); iter++) {
      		std::cout << "iter->first: " << iter->first << ", iter->second: " << iter->second << std::endl;
      	}
      }
      
      int main() {
      	std::map<int, std::string> mp;
      
      	// 插入数据
      	mp.insert(std::pair<int, std::string>(10010, "AA"));
      	mp.insert(std::pair<int, std::string>(11000, "BB"));
      	mp.insert(std::pair<int, std::string>(11110, "CC"));
      	mp.insert(std::pair<int, std::string>(10000, "DD"));
      	mp.insert(std::pair<int, std::string>(10001, "EE"));
      	
      	// 查找
      	std::map<int, std::string>::iterator iter = mp.find(11110);
      	if (iter != mp.end()) {
      		std::cout << "找到了" << std::endl;
      		std::cout << "key: " << iter->first << ", value: " << iter->second << std::endl;
      	}
      	else {
      		std::cout << "未找到" << std::endl;
      	}
      
      	// 统计
      	std::cout << "mp.count(10000): " << mp.count(10000) <<std::endl;
      
      	system("pause");
      	return 0;
      }
  • 打印结果
    *

        找到了
        key: 11110, value: CC
        mp.count(10000): 1
        请按任意键继续. . .
    

11.5 map容器排序

  • map容器默认排序规则是从小到大,利用仿函数,可以改变默认排序规则。

  • 使用示例
    *

    c 复制代码
      #include <iostream>
      #include <string>
      #include <map>
      
      class myCompare {
      public:
      	bool operator()(int data1, int data2) {
      		return data1 > data2;
      	}
      };
      
      int main() {
      	std::map<int, std::string, myCompare> mp;
      
      	// 插入数据
      	mp.insert(std::pair<int, std::string>(10010, "AA"));
      	mp.insert(std::pair<int, std::string>(11000, "BB"));
      	mp.insert(std::pair<int, std::string>(11110, "CC"));
      	mp.insert(std::pair<int, std::string>(10000, "DD"));
      	mp.insert(std::pair<int, std::string>(10001, "EE"));
      	
      	for (std::map<int, std::string, myCompare>::iterator iter = mp.begin(); iter != mp.end(); iter++) {
      		std::cout << "iter->first: " << iter->first << ", iter->second: " << iter->second << std::endl;
      	}
      
      	system("pause");
      	return 0;
      }
  • 打印结果
    *

        iter->first: 11110, iter->second: CC
        iter->first: 11000, iter->second: BB
        iter->first: 10010, iter->second: AA
        iter->first: 10001, iter->second: EE
        iter->first: 10000, iter->second: DD
        请按任意键继续. . .
    
相关推荐
多多*8 分钟前
初识JVM HotSopt 的发展历程
java·开发语言·jvm·c++·学习·算法
axecute8 分钟前
矩阵Strassen 算法
线性代数·算法·机器学习·矩阵
pzx_00110 分钟前
【集成学习】Stacking算法详解
人工智能·算法·leetcode·机器学习·职场和发展·集成学习
燕双嘤10 分钟前
JVM:ZGC详解(染色指针,内存管理,算法流程,分代ZGC)
jvm·算法
m0_dawn15 分钟前
(蓝桥杯)二维数组前缀和典型例题——子矩阵求和
python·学习·算法·职场和发展·蓝桥杯
周杰伦_Jay24 分钟前
P2图文解析:算法复杂度
数据结构·算法·链表·哈希算法·图搜索算法
慌糖25 分钟前
数组排序------冒泡排序
数据结构·算法·排序算法
sjsjs1126 分钟前
【区间DP】【hard】力扣1312. 让字符串成为回文串的最少插入次数
算法·leetcode·职场和发展
Naion37 分钟前
机器学习算法——决策树
算法·决策树·机器学习
一个平凡而乐于分享的小比特43 分钟前
深拷贝与浅拷贝
c++·深拷贝与浅拷贝