一、vector容器(向量)
vector属于序列容器,序列是对基本容器的一种改进,在保持其基础功能上增加一些我们需要的更为方便的功能。要求序列的元素必须是严格的线性顺序排序。因此序列中的元素具有确定的顺序,可以执行将值插入到特定位置、删除特定区间等操作。下面要说明的deque、list同样属于序列(也叫顺序)容器。vector是动态数组,在内存中具有连续的存储空间,支持快速随机访问。由于具有连续的存储空间,所以在插入和删除操作方面,效率比较慢。
/* * @Author: Stylle * @Date: 2020-08-23 14:53:32 * @LastEditors: Stylle * @LastEditTime: 2020-08-23 16:40:27 * @FilePath: \c-master\常用容器vector的使用.cpp */ #include <iostream> #include <vector> #include <algorithm> // #include <list> // #include <queue> // #include <map> using namespace std; /* 遍历方式1 :迭代器的方式遍历*/ void PrintVector(vector<int> &v) { /* 容器遍历:利用begin和end迭代器方式 */ for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; } /* 遍历方式2 :size方式数组下标方式*/ void PrintVector_size(vector<int> &v) { for (std::vector<int>::size_type i = 0; i != v.size(); i++) { cout << v[i] << " "; } cout << endl; } /* 遍历方式3 :平常使用更推荐auto,速度更快,需要C++11支持*/ void PrintVector_auto(vector<int> &v) { for (auto const &value : v) { cout << value << " "; } cout << endl; } /* 遍历方式4 :如果在遍历的过程中需要更改其中的数据更推荐使用本方法,需要C++17支持*/ template <typename T> void printer(const T &val) { cout << val << " "; } void PrintVector_for_each(vector<int> &v) { //#include <algorithm>使用需要包含 for_each(v.cbegin(), v.cend(), printer<int>); cout << endl; } int main(int argc, char **argv) { vector<int> v1; //初始化方式1:无初始值 /* 容器赋值 */ for (int i = 0; i < 10; i++) { v1.push_back(i * 10); } cout << "V1: "; PrintVector(v1); v1.pop_back(); //删除最后一位数据 cout << "V1: "; PrintVector(v1); vector<int> v2(10, 1); //初始化方式2:赋值10个1 cout << "V2: "; PrintVector(v2); v1.swap(v2); //交换两个容器的数据 cout << "V1: "; PrintVector(v1); cout << "V2: "; PrintVector(v2); cout << "V1元素个数:" << v1.size() << endl; v1.insert(v1.begin() + 5, 2, 8); //在容器元素第五个的后面插入两个8 cout << "V1: "; PrintVector(v1); v1.erase(v1.begin() + 5); //删除第五个元素 cout << "V1: "; PrintVector(v1); v1.erase(v1.begin() + 5, v1.end()); //删除第五个元素到最后一个元素的数据 cout << "V1: "; PrintVector(v1); int &vNum1 = v1.front(); //返回容器V1的第一个元素的引用 //如果这里定义的不是&元素则无法更改v1的内容,而这里却可以 //front、back与end、begin的区别在于返回的一个是引用一个是迭代器 int &vNum2 = v1.back(); //返回容器V1的最后一个元素的引用 if (!v1.empty()) { v1.clear(); //如果不为空则清空容器 } cout << "V1: "; PrintVector(v1); vector<int> v3; v3.resize(10, 5); //指定空间大小 cout << "V3的容量 = " << v3.capacity() << endl; cout << "V3:"; PrintVector_auto(v3); cout << "V3:"; PrintVector_for_each(v3); reverse(v2.begin(), v2.end()); //逆序储存从开始位置到结束位置,需要包含头文件#include <algorithm> PrintVector_auto(v2); return 0; }
vector容器特点:
(1) 一个动态分配的数组(当数组空间内存不足时,都会执行: 分配新空间-复制元素-释放原空间);
(2) 当删除元素时,不会释放限制的空间,所以向量容器的容量(capacity)大于向量容器的大小(size);
(3) 对于删除或插入操作,执行效率不高,越靠后插入或删除执行效率越高;
(4) 高效的随机访问的容器。
二、deque容器(队列)
deque容器类与vector类似,支持随机访问和快速插入删除,它在容器中某一位置上的操作所花费的是线性时间。与vector不同的是,deque还支持从开始端插入数据:push_front()。其余类似vector操作方法的使用。
/* * @Author: Stylle * @Date: 2020-08-23 17:07:22 * @LastEditors: Stylle * @LastEditTime: 2020-08-23 17:45:36 * @FilePath: \c-master\常用容器deque的使用.cpp */ #include <iostream> #include <deque> #include <algorithm> using namespace std; template <typename T> void printer(const T &val) { cout << val << " "; } //for_each遍历方式 void PrintVector_for_each(deque<int> &deq) { //#include <algorithm>使用需要包含 for_each(deq.cbegin(), deq.cend(), printer<int>); cout << endl; } int main(int argc, char **argv) { deque<int> deq1; for (int i = 0; i < 5; i++) { deq1.push_back(i * 10); } //从队列前面插入数据 for (int i = 25; i > 20; i--) { deq1.push_front(i * 10); } //从队列后面插入数据 for (int i = 10; i > 5; i--) { deq1.push_back(i * 10); } PrintVector_for_each(deq1); //除了前后插入与vector容器使用方法相同 return 0; }
deque容器特点:
deque类似于C语言中的双向队列,即两端都可以插入或者删除的队列。queue支持 [] 操作符,也就是支持随机存取,而且跟vector的效率相差无几。它支持两端的操作:push_back,push_front,pop_back,pop_front等,并且在两端操作上与list的效率也差不多,在中间插入元素则会比较费时,因为必须移动中间其他的元素。或者我们可以这么认为,deque是vector跟list的折中。
三、list容器(列表)
list是STL实现的双向链表,与vector相比, 它允许快速的插入和删除,但是随机访问却比较慢。
/* * @Author: Stylle * @Date: 2020-08-23 16:31:50 * @LastEditors: Stylle * @LastEditTime: 2020-08-23 19:09:07 * @FilePath: \c-master\常用容器list的使用.cpp */ #include <iostream> #include <list> #include <algorithm> using namespace std; template <typename T> void printer(const T &val) { cout << val << " "; } void printList_for_each(list<int> &lst) { for_each(lst.cbegin(), lst.cend(), printer<int>); cout << endl; } int main(int argc, char **argv) { list<int> lst1; lst1.push_back(7); lst1.push_back(4); lst1.push_back(1); lst1.push_back(6); lst1.push_back(5); lst1.push_back(2); lst1.push_back(3); cout << "List1:"; printList_for_each(lst1); list<int> lst2(lst1.begin(), lst1.end()); cout << "List2:"; printList_for_each(lst2); lst2.sort(); cout << "List2:"; printList_for_each(lst2); //相对于vector和deque新增的使用方法 lst1.assign(lst2.begin(), lst2.end()); //分配值 cout << "List1:"; printList_for_each(lst1); //删除相同元素 lst1.push_back(1); lst1.push_back(1); cout << "List1:"; printList_for_each(lst1); lst1.remove(1); //删除列表中所有的1元素 cout << "List1:"; printList_for_each(lst1); lst1.push_front(2); lst1.push_front(2); lst1.push_front(2); cout << "List1:"; printList_for_each(lst1); lst1.unique(); //删除相邻重复元素 cout << "List1:"; printList_for_each(lst1); //将 lst1中的首元素移到 lst1的最后 lst1.splice(lst1.end(), lst1, lst1.begin()); cout << "List1:"; for (list<int>::iterator it = lst1.begin(); it != lst1.end(); it++) { cout << *it << " "; } cout << endl; //将 lst2中的所有元素移到 lst1的最后 lst1.splice(lst1.end(), lst2); cout << "List1:"; for_each(lst1.begin(), lst1.end(), [](int val) { cout << val << " "; }); //这个我暂时没找到什么作用 lst1.rbegin(); //返回第一个元素的前向指针 return 0; }
list类似于c语言中的双向链表,它通过指针来进行数据的访问,因此维护的内存空间可以不连续,这也非常有利于数据的随机存取,因而它没有提供 [] 操作符重载。
四、map容器
map属于关联容器与序列容器有着根本性的不同,序列容器的元素是按照在容器中的位置来顺序保存和访问的,而关联容器的元素是按关键元素来保存和访问的。关联容器支持高效的关键字查找与访问。两个主要的关联容器类型是map与set。
/* * @Author: Stylle * @Date: 2020-08-23 16:32:10 * @LastEditors: Stylle * @LastEditTime: 2020-08-23 20:45:41 * @FilePath: \c-master\常用容器map的使用.cpp */ #include <iostream> #include <map> #include <algorithm> using namespace std; int main(int argc, char **argv) { map<int, string> map1; //常用操作方法 map1[3] = "Three"; //添加元素 map1.insert(map<int, string>::value_type(2, "Two")); //插入元素1 map1.insert(pair<int, string>(4, "Four")); //插入元素2 map1.insert(make_pair<int, string>(1, "One")); //插入元素3 string str = map1[3]; //根据key取得value,key不能修改 map<int, string>::iterator iter_map = map1.begin(); //取得迭代器首地址 int key = iter_map->first; //取得eky string value = iter_map->second; //取得value map1.erase(iter_map); //删除迭代器数据 //遍历方式1 for (map<int, string>::iterator it = map1.begin(); it != map1.end(); it++) { //遍历输出key value cout << it->first << " " << it->second << endl; } map1.erase(3); //根据key删除value //遍历方式2:使用auto指针 for (auto it = map1.begin(); it != map1.end(); it++) { cout << it->first << " " << it->second << endl; } return 0; }
map容器特点:
map内部自建了一颗红黑二叉树,可以对数据进行自动排序,所以map里的数据都是有序的。
五、set容器
set类似于数学里面的集合,不过set的集合中不包含重复的元素,这是和vector的第一个区别,第二个区别是set内部用平衡二叉树实现,便于元素查找,而vector是使用连续内存存储,便于随机存取。
/* * @Author: Stylle * @Date: 2020-08-23 17:08:20 * @LastEditors: Stylle * @LastEditTime: 2020-08-23 21:11:19 * @FilePath: \c-master\常用容器set的使用.cpp */ #include <iostream> #include <set> #include <algorithm> #include <random> #include <ctime> using namespace std; int main(int argc, char **argv) { set<string> set1; set1.insert("one"); //第一种方法:直接添加 set1.insert("two"); set<string> set2; set2.insert(set1.begin(), set1.end()); //第二中方法:通过指针迭代器 //迭代器遍历set容器 cout << "Set2:"; for (auto it = set2.begin(); it != set2.end(); it++) { cout << *it << " "; } cout << endl; set<int> set3; srand((unsigned)time(NULL)); for (int i = 0; i < 10; i++) { set3.insert(rand() % 10); } cout << "Set3:"; for (auto it = set3.begin(); it != set3.end(); it++) { cout << *it << " "; } cout << endl; if (!set3.count(6)) //存在,返回1,不存在,返回0 { set3.insert(6); } set3.find(1); // 返回指向元素内容为1的指针 cout << "Set3:"; for (auto it = set3.begin(); it != set3.end(); it++) { cout << *it << " "; } cout << endl; return 0; }
set容器特点:
储存同一类型的数据元素(这点和vector、queue等其他容器相同),每个元素的值都唯一(没有重复的元素),根据元素的值自动排列大小(有序性),无法直接修改元素,高效的插入删除操作
六、四种容器遍历方式
其中比较重要的四种容器遍历方式:
/* 遍历方式1 :迭代器的方式遍历*/ void PrintVector(vector<int> &v) { /* 容器遍历:利用begin和end迭代器方式 */ for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout << *it << " "; } cout << endl; } /* 遍历方式2 :size方式数组下标方式*/ void PrintVector_size(vector<int> &v) { for (std::vector<int>::size_type i = 0; i != v.size(); i++) { cout << v[i] << " "; } cout << endl; } /* 遍历方式3 :平常使用更推荐auto,速度更快,需要C++11支持*/ void PrintVector_auto(vector<int> &v) { for (auto const &value : v) { cout << value << " "; } cout << endl; } /* 遍历方式4 :如果在遍历的过程中需要更改其中的数据更推荐使用本方法,需要C++17支持*/ template <typename T> void printer(const T &val) { cout << val << " "; } void PrintVector_for_each(vector<int> &v) { //#include <algorithm>使用需要包含 for_each(v.cbegin(), v.cend(), printer<int>); cout << endl; }
七、总结
1、如需高效的随机存取,不在乎插入和删除的效率,使用vector;
2、如需大量的插入和删除元素,不关心随机存取的效率,使用list;
3、如需随机存取,并且关心两端数据的插入和删除效率,使用deque;
4、如果打算存储数据字典,并且要求方便地根据key找到value,一对一的情况使用map,一对多的情况使用multimap;
5、如果打算查找一个元素是否存在于某集合中,唯一存在的情况使用set,不唯一存在的情况使用multiset