1.STL中的容器
-
序列容器
vector,(优点)允许容器元素随机存取,允许通过数组的方式引用容器中的元素值。(缺点)但在容器的中间部位插入或删除容器的元素的代价是比较大的。
list,基于双向链表的,要定位某一元素的话,就需要从首节点一个一个遍历,直到遍历到目标node为止。优缺点和vector正好相反
deque,双端队列
forward_list(C++11),基于单向链表
queue,队列,先入先出
priority_queue,优先队列,总是将队列中最大的值放到队首
stack,栈
-
有序关联容器
set,集合,不允许重复的值,类型要都一样
multiset,允许有重复值
map,不允许key重复
multimap,允许key重复
-
无序关联容器(C++11),使用哈希的存储方式,通过key定位
unordered_set
unordered_multiset
unordered_map
unordered_multimap
2.双向链表容器类 list
#include <iostream>
#include <list>
using namespace std;
void output(int value)
{
cout << value << " ";
}
bool removeIf(int value)
{
if(value % 2 == 0)
{
return true;
}
else
{
return false;
}
}
bool compareInt(int n1, int n2)
{
if(n1 >= n2)
{
return true;
}
else
{
return false;
}
}
int main(int argc, const char * argv[]) {
// 双向链表容器类:list
// vector<int> v; v[1]
// list不允许像vector一样使用数组的方式随机访问元素值
// insert O(1)
// remove
// remove_if
// sort // NLogN
// splice
// merge:// 被合并的两个链表最好是已经被排序的
// unique:去掉list中重复的值
// vector:随机访问
// list:插入和删除
list<int> one(10, 3);
for_each(one.begin(), one.end(), output);
cout << endl; // 3 3 3 3 3 3 3 3 3 3
// 插入
list<int> two;
int intArray[]{1,2,3,4,5,6};
two.insert(two.begin(), intArray, intArray + 6);//此时two是 1 2 3 4 5 6从two的开头开始插入,插入intArray的第一个到第6个范围的数值
two.insert(two.end(), 100); // 此时two是 1 2 3 4 5 6 100
two.insert(two.begin(), 200); // 此时two是 200 1 2 3 4 5 6 100
for_each(two.begin(), two.end(), output);
cout << endl; // 200 1 2 3 4 5 6 100
// 删除
two.remove(4); // 参数是元素值,不是索引,即将4这个值从two中找到并删除
for_each(two.begin(), two.end(), output);
cout << endl; // 200 1 2 3 5 6 100
two.remove_if(removeIf); // 参数是函数,把能被2整除的数都删除
for_each(two.begin(), two.end(), output);
cout << endl; // 1 3 5
// 排序
two.sort(compareInt); // 降序排列
for_each(two.begin(), two.end(), output);
cout << endl; // 5 3 1
// splice
two.splice(two.begin(), one); // 将one插到two的最开始位置,list<int> one(10, 3);
for_each(two.begin(), two.end(), output);
cout << endl; // 3 3 3 3 3 3 3 3 3 3 5 3 1
// 去掉重复的,O(N)
two.unique(); // 去掉相邻元素重复的值
for_each(two.begin(), two.end(), output);
cout << endl; // 3 5 3 1
for_each(one.begin(), one.end(), output);
cout << endl; // 此时one为空,因为splice是移动元素,不是复制元素
// merge
one.insert(one.begin(), intArray + 3, intArray + 6); // 此时one是 4,5,6
two.sort(); // 1 3 3 5
two.unique();
for_each(two.begin(), two.end(), output);
cout << endl; // 1 3 5
two.merge(one); // merge:将有序的one,合并到有序的two中
for_each(two.begin(), two.end(), output);
cout << endl; // 1 3 4 5 5 6
two.unique();
for_each(two.begin(), two.end(), output);
cout << endl; // 1 3 4 5 6
return 0;
}
3.同时兼具vector和list优势的双端队列deque
#include <iostream>
#include <deque>
using namespace std;
int main(int argc, const char * argv[]) {
// 同时兼具vector和list优势的双端队列:deque
deque<int> values {1,2,3,4,5};
cout << values[2] << endl; // 3
values.erase(values.begin());
cout << values[0] << endl; // 2
values.insert(values.begin(), 20);
cout << values[0] << endl; // 20
values.erase(values.end() - 1);
cout << *(values.end() - 1) << endl; // 4
return 0;
}
4.单向链表容器forward_list(C++11)
#include <iostream>
#include <forward_list>
#include <list>
using namespace std;
int main(int argc, const char * argv[]) {
// 单链表容器:forward_list(C++ 11)
// list:双向链表,支持从尾节点往前遍历
// 对于链表来说,不能对迭代器+1或-1来访问元素,因为这就属于随机访问了,链表是不支持的
list<int> list_values {1,2,3,4,5};
for(auto it = list_values.rbegin(); it != list_values.rend(); it++) // rbegin和rend,逆向遍历
{
cout << *it << " ";
}
cout << endl; // 5 4 3 2 1
forward_list<int> forward_list_values{1,2,3,4,5};
for(auto it = forward_list_values.begin(); it != forward_list_values.end(); it++)
{
cout << *it << " ";
}
cout << endl; // 1 2 3 4 5
return 0;
}
5.队列容器queue
#include <iostream>
#include <queue>
using namespace std;
int main(int argc, const char * argv[]) {
// 队列容器类:queue,先进先出
queue<int> q;// queue<int> q {1,2,3,4,5} error; 只能将数一个一个的压入队列中
q.push(10);
q.push(20); // 在10出队之前,我们不能访问这个20
q.push(30);
// 获得队首元素值
cout << q.front() << endl; // 10 front返回的不是迭代器,是元素值
// 获取队尾元素值
cout << q.back() << endl; // 30
// q[2]; 报错,不能索引
q.pop(); // 出队 队首元素
cout << q.front() << endl; // 20
cout << q.size() << endl; // 2
q.pop();
q.pop();
cout << (q.empty()?"true":"false") << endl; // true
return 0;
}
6.永远获得最大值的的队列容器类priority_queue
#include <iostream>
#include <queue>
using namespace std;
int main(int argc, const char * argv[]) {
// 永远获得最大值的队列容器类:priority_queue,出队的值永远是队列中的最大值
priority_queue<int> p;
p.push(10);
p.push(20);
p.push(30);
cout << p.top() << endl; // 30
p.pop();
cout << p.top() << endl; // 20
return 0;
}
7.栈容器类stack
#include <iostream>
#include <stack>
using namespace std;
int main(int argc, const char * argv[]) {
// 栈容器类:stack
stack<int> stack_int;
stack_int.push(10);
stack_int.push(20);
stack_int.push(30); // 将容器倒过来去理解,就像一个水桶,往水桶里push
cout << stack_int.top() << endl; // 30
stack_int.pop();
cout << stack_int.top() << endl; // 20
cout << stack_int.size() << endl; // 2
cout << stack_int.empty() << endl; // 0
return 0;
}
8.数组模板类array
#include <iostream>
#include <array>
using namespace std;
void output(int n)
{
cout << n << " ";
}
int main(int argc, const char * argv[]) {
// 数组模板类array
// 没有insert,push_back等方法
// 有:[],at,begin,end
array<int, 5> array_int {1,2,3,4,5};
for_each(array_int.begin(), array_int.end(), output);
cout << endl; // 1 2 3 4 5
for_each(array_int.rbegin(), array_int.rend(), output);
cout << endl; // 5 4 3 2 1
cout << array_int[2] << endl; // 3
cout << array_int.at(3) << endl; // 4,第四个数组元素
cout <<array_int.size() << endl; // 5
return 0;
}
9.集合容器类set
#include <iostream>
#include <set>
#include <array>
using namespace std;
void output(string s)
{
cout << s << " ";
}
int main(int argc, const char * argv[]) {
// 集合容器类:set
// 集合的特点:元素是唯一的,不能重复
// 插入、copy、合并、交集
set<string> set1 {"Bill", "Mike"};
// set1.insert("John");
set1.insert("Bill"); // 添加了重复值,集合大小不变
cout << set1.size() << endl; // 2
// copy
array<string, 2> array_string;
copy(set1.begin(), set1.end(), array_string.begin());
for_each(array_string.begin(), array_string.end(), output);
cout << endl; // Bill Mike
set<string> set2;
copy(set1.begin(), set1.end(), insert_iterator<set<string>>(set2, set2.begin())); // 如果第三个参数使用set2.begin()那么系统会将其看作常量,编译会报错,就不能插入了,所以要用插入迭代器
for_each(set2.begin(), set2.end(), output);
cout << endl; // Bill Mike
// insert
set2.insert("abc");
set2.insert("ok");
for_each(set2.begin(), set2.end(), output);
cout << endl; // Bill Mike abc ok
// 取交集
set<string> set3; // set1 set2取交集存到set3,set3也要用到insert迭代器
set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), insert_iterator<set<string>>(set3,set3.begin()));
for_each(set3.begin(), set3.end(), output);
cout << endl; // Bill Mike
// union
set<string> set4;
set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), insert_iterator<set<string>>(set4,set4.begin()));
for_each(set4.begin(), set4.end(), output);
cout << endl; // Bill Mike abc ok
return 0;
}
10.支持重复值的集合容器类multiset
#include <iostream>
#include <set>
using namespace std;
int main(int argc, const char * argv[]) {
// 支持重复值的集合容器类:multiset
set<int> values1 {1,2,2,4,5};
for(auto value:values1)
{
cout << value << " ";
}
cout << endl; // 1 2 4 5
multiset<int> values2{1,2,2,4,5};
for(auto value:values2)
{
cout << value << " ";
}
cout << endl; // 1 2 2 4 5
return 0;
}
11.映射容器类map
#include <iostream>
#include <map>
using namespace std;
int main(int argc, const char * argv[]) {
// 映射容器类:map
// 存储形式:key-value
// 特点:key不能重复
map<int, string> persons; // 参数一是key的类型,参数二是value的类型
pair<int, string> person1(10, "Bill"); // pair代表map中的每一对儿值
persons.insert(person1);
pair<int, string> person2(20, "Mike");
persons.insert(person2);
pair<int, string> person3(30, "John");
persons.insert(person3);
// first:key
cout << persons.find(20)->first << endl; // 20 find(20)返回的是指向pair对象的指针,其中first是key值,second是value值
// second:value
cout << persons.find(30)->second << endl; // John
map<int,string>::iterator it = persons.find(35);
if(it != persons.end())
{
cout << "key = " << it->first << " value = " << it->second << endl;
}
else
{
cout << "没找到!" << endl; // 没找到!
}
pair<int,string> person4(20, "Bee");
cout << "size1 = " << persons.size() << endl; // 3
persons.insert(person4);
cout << "size2 = " << persons.size() << endl; // 3
cout << persons.find(20)->second << endl; // Mike,并没有替换
return 0;
}
12.允许key重复的映射容器类multimap
#include <iostream>
#include <map>
using namespace std;
int main(int argc, const char * argv[]) {
// 允许key重复的映射容器类:multimap
// set multiset
// map multimap
// 核心问题:如何获取重复的key对应的所有value(3种方法)
multimap<int, string> values;
pair<int, string> value1(10, "Bill");
pair<int, string> value2(10, "Mike");
pair<int, string> value3(10, "Mary");
pair<int, string> value4(20, "John");
values.insert(value1);
values.insert(value2);
values.insert(value3);
values.insert(value4);
cout << values.size() << endl; // 4
cout << values.count(10) << endl; // 3
// 第1种获取重复的key对应的所有value的方法
multimap<int, string>::iterator it = values.find(10);
size_t count = values.count(10);
for(int i = 0; i < count; i++)
{
cout << (*(it++)).second << endl; // Bill Mike Mary,这里只能用++,用加1的话,不支持随机访问
}
// 第2种获取重复的key对应的所有value的方法,使用了两个迭代器
multimap<int, string>::iterator it_lower = values.lower_bound(10);
multimap<int, string>::iterator it_upper = values.upper_bound(10);
for(auto it = it_lower; it != it_upper;it++)
{
cout << "key = " << it->first << " value = " << it->second << endl;
}
// 第3种获取重复的key对应的所有value的方法,和第二种方法类似,只不过两个迭代器是同时获得的
pair<multimap<int, string>::iterator, multimap<int, string>::iterator> range = values.equal_range(10);
for(auto it = range.first; it != range.second;it++) // first相当于lower,second相当于upper
{
cout << "key = " << it->first << " value = " << it->second << endl;
}
return 0;
}
13.无序关联容器(C++11)
#include <iostream>
#include <unordered_set>
#include <unordered_map>
using namespace std;
int main(int argc, const char * argv[]) {
// 无序关联容器(C++ 11)
// unordered_set、unordered_multiset、unordered_map和unordered_multimap:基于hash,定位查找速度更快
// set multiset map multimap :基于树的结构(有序关联容器)
//
unordered_set<int> set_int{1,2,3,4,4};
cout << set_int.size() << endl; // 4 重复的只保留一个
unordered_multimap<int, string> multimap_int;
pair<int, string> value1(10, "Bill");
pair<int, string> value2(10, "Mike");
pair<int, string> value3(20, "John");
multimap_int.insert(value1);
multimap_int.insert(value2);
multimap_int.insert(value3);
pair<unordered_multimap<int, string>::iterator, unordered_multimap<int, string>::iterator> range = multimap_int.equal_range(10);
for(auto it = range.first; it!=range.second;it++)
{
cout << it->second << endl; // Bill Mike
}
return 0;
}