在这篇文章我们不介绍容器是怎样使用的,因为STL容器的使用还是比较简单的。我们着重讲一下容器的底层实现。同时我整理了一些文章,供参阅。
1.顺序容器
1.vector
底层是可以两倍动态扩容的数组 0->1->2->4...
常用的方法有:reserve /resize /size /empty /push_back /pop_back /insert /erase等
2.deque:双端队列
底层是通过一小块内存map,map里面存储着指针,每个指针指向一个更大dequeue块,每个dequeque的大小一般为512B,由于dequeque是采取多个连续的内存块存储,而不是像vector一样采取一个连续的内存块,因此dequeue在头部或者尾部插入或删除元素的时候是不需要进行元素的移动的。
常用的方法有:push_back /pop_back /push_front /pop_front /insert /erase等
关于dequeque可以看下这一篇文章:https://blog.csdn.net/Lison_Zhu/article/details/80030711
3.list链表
底层是带头节点的双向链表。
_list_node的定义如下:
template<typename T,...>
struct __List_node{
//...
__list_node<T>* prev;
__list_node<T>* next;
T myval;
//...
}
常用的方法有:push_back /pop_back /push_front /pop_front /insert /erase/merge等.
关于STL::list可以参阅这篇文章:https://www.cnblogs.com/aiguona/p/7231609.html
2.关联容器
1.set和multiset、unordered_set和unordered_multiset
set和multiset一样,存储的是有序的元素,两者不同的一个允许重复,一个不允许重复,set和multiset的底层实现为红黑树。unordered_set和unordered_multiset存储的无序的元素,底层实现是hash_table.
2.map和multimap、unordered_和unordered_ultimap
map和set的区别是map存储的是键值对,而set存储的只是元素值。map和multimap的底层实现也是红黑树,unordered_和unordered_ultimap的底层实现是hash_table。
关于关联容器的知识点和操作可以参考下面这两篇博文:
https://blog.csdn.net/xiajun07061225/article/details/7459206
https://blog.csdn.net/qq_18539301/article/details/81780194
3.器适配器(没有自己的数据结构,因此没有迭代器)
1.stack
底层是deque
常用的方法有:
1.empty() 堆栈为空则返回真
2.pop() 移除栈顶元素
3.push() 在栈顶增加元素
4.size() 返回栈中元素数目
5.top() 返回栈顶元素
2.queue
底层是deque
常用的方法有:
1.back() 返回一个引用,指向最后一个元素
2.empty() 如果队列空则返回真
3.front() 返回第一个元素
4.pop() 删除第一个元素
5.push() 在末尾加入一个元素
6.size() 返回队列中元素的个数
3.priority_queue
底层是vector
priority_queue<int> maxHeap; //大根堆
maxHeap.push(10);
maxHeap.pop();
maxHeap.top();
maxHeap.empty();
maxHeap.size();
//小根堆
priority_queue<int, vector<int>, greater<int>> minHeap;
用priority_queue可以实现top k 问题
srand((unsigned)time(NULL));
vector<uint>vec;
for (int i = 0; i < 2000000; ++i)
{
vec.push_back(rand()+i);
}
priority_queue<uint> vec1;
priority_queue<uint,vector<uint>,greater<uint>> vec2;
//求最小的
for (int i = 0; i < 10; ++i)
{
vec1.push(vec[i]);
}
for (int i = 10; i < 2000000; ++i)
{
if (vec[i] < vec1.top())
{
vec1.pop();
vec1.push(vec[i]);
}
}
for (int i = 0; i < 10; ++i)
{
const int& iv = vec1.top();
cout << iv << ends;
vec1.pop();
}
cout << endl;
//海量数据问题:请在最短的时间内,找到所有整数中,最大/最小的10个元素,并且打印
//找top k大的用小根堆, top k小的用大根堆
for (int i = 0; i < 10; ++i)
{
vec2.push(vec[i]);
}
for (int i = 10; i < 2000000; ++i)
{
if (vec[i] > vec2.top())
{
vec2.pop();
vec2.push(vec[i]);
}
}
for (int i = 0; i < 10; ++i)
{
cout << vec2.top() << ends;
vec2.pop();
}
解决查重和top k的复合问题
int main()
{
srand(time(NULL));
//查重复和top k 结合的问题
vector<int> vec;
for (int i = 0; i < 200000; ++i)
{
vec.push_back(rand());
}
//在这组数字中,找重复次数最大的前10个数并进行打印
//无序容器+优先级队列
//1.统计所有数字重复次数
unordered_map<int, int> _map;
for (int val : vec)
{
auto it = _map.find(val);
if (it == _map.end())
{
_map.insert(make_pair(val, 1));
}
else
{
it->second++;
}
}
struct Node
{
Node(int v, int c) :val(v), count(c)
{}
bool operator>( const Node &src) const
{
return count > src.count;
}
int val;
int count;
};
priority_queue <Node,vector<Node>,greater<Node>> que;
int k = 0;
unordered_map<int, int>::iterator it = _map.begin() ;
for (pair<int, int> item : _map)
{
que.push(Node(item.first,item.second));
++it;
if (++k == 10)
{
break;
}
}
//将k+1到末尾的元素和堆顶的元素进行比较
while (it != _map.end())
{
if (it->second > que.top().count)
{
que.pop();
que.push(Node(it->first,it->second));
}
++it;
}
for (int i = 0; i < 10; ++i)
{
cout << que.top().val << "重复" << que.top().count << "次" << endl;
que.pop();
}
system("pause");
return 0;
}
4.其他容器:STL::bitset
很明显bitset就是位图容器,相信大家对位图法都不陌生,位图法在大量元素求重复的问题中非常有用,依稀记得当初采取的位图法都是通过左移右移来完成的,那么现在可以使用bistset来替代了,bistset可以让程序员们像使用数组一样去使用类。
bitset继承自_Base_bitse。_Base_bitse包含了一个unsigned long的数组,一般地,一个unsigned long有32位,可以表示32个数,最低位的数最小,最高位的数最大。
关于bistset的底层详细介绍和使用方法,可以参考下面两篇文章。
https://blog.csdn.net/u012069890/article/details/59108840
https://blog.csdn.net/shudaqi2010/article/details/23406063