L5.Containers
约 742 个字 4 行代码 2 张图片 预计阅读时间 3 分钟
Sequence Containers¶
Operator[] does not perform bounds checking.
C++ | |
---|---|
Vectors does not have a push_front
function because it is very slow and expensive.
So if you really want fast insertion to the front,use std::deque
.
C++ | |
---|---|
How is a deque implemented?¶
There is no single specific implementation of a deque,but one common one might look like:
We have four blocks of memory,each of which can store 4 integers.
The earlier elements are stored in the first block,and the later elements are stored in the last block.
- If we do
push_back(3)
,we will add number 3 to the last place of the last block.Finally,we get:{x,x,3,1},{4,1,5,9},{2,6,5,3},NULL
.(x means empty) - Then we do
push_front(1)
,we will insert number 1 before the first element.Finally,we get:{x,1,3,1},{4,1,5,9},{2,6,5,3},NULL
. - Then we do
push_back(7)
,we find that the last block is full,so we need to allocate a new block and insert number 7.Finally,we get:{x,1,3,1},{4,1,5,9},{2,6,5,3},{7,x,x,x}
. - Then we do
push_front(8)
andpush_front(0)
.When inserting0
,we find that the first block is full,so we need to allocate a new block before the first block.Finally,we get:{x,x,x,0},{8,1,3,1},{4,1,5,9},{2,6,5,3},{7,x,x,x}
. - Other operations are similar.
When to use which Sequence Container?¶
std::list
is kind of like std::stack
+ std::queue
.
std::list
provides fast removal from the front and end but you can't access any elements in the middle.
std::vector |
std:deque |
std::list |
|
---|---|---|---|
Indexed Access | Super fast | Fast | Impossible |
Insert/remove front | Slow | Fast | Fast |
Insert/remove back | Super Fast | Very Fast | Fast |
Ins/rem elsewhere | Slow | Fast | Very Fast |
Memory | Low | High | High |
Splicing/Joining | Slow | Very Slow | Fast |
Stability(Iterators.concurrency) | Poor | Very Poor | Good |
Summary
"vector is the type of sequence that should be used by default...deque is the data structure of choice when most insertions and deletions take place at the beginning or at the end of the sequence."
- C++ ISO Standard(section 23.1.1.2).
How is a vector implemented?¶
Internally,a vector consists of an fixed-size array,The array is automatically resized when necessary.
- size = number of elements in the vector.
- capacity = amount of space saved for the vector.
If possible,reserve the space for the vector in advance.
Create a vector of the first 1,000,000 integers
In the first practice,we will have to resize the vector 1,000,000 times,which is very slow.But in the second practice,we only need to resize the vector once,which is much faster.
Container Adaptors¶
Stack¶
How to design a stack?
Container adaptors provide a different interface for sequence containers.You can choose what the underlying container is.
Through the adaptor,we can do push()
and pop()
to the stack.
We can see that in C++,the default container for stack is std::deque
.Because we need many insertions and deletions at the end and the beginning of the stack.
Other containers
std::stack<int> stack_d;
: container = dequestd::stack<int, std::vector<int>> stack_v;
: container = vectorstd::stack<int, std::list<int>> stack_l;
: container = list
Priority Queue¶
C++ | |
---|---|
A priority queue is a container adaptor that provides constant time lookup of the largest(by default) element,at the expense of logarithmic insertion and extraction.
A user-provided Compare can be supplied to change the ordering, e.g. using std::greater<T>
would cause the smallest element to appear as the top()
.
Working with a priority_queue is similar to managing a heap in some random access container,with the benefit of not being able to accidentally invalidate the heap.
Set and Map¶
Set¶
Every element in a set has a unique key.We can search for an element through key with efficiency.
insertion¶
C++ | |
---|---|
After running the code above,we will get:1 2 3 4 5
.
From the output we can know that set will automatically remove the duplicate elements and sort the elements.
find¶
We have two ways to find an element in a set.
find
set<int>::iterator pos = s.find(3);
set<int>::iterator pos = find(s.begin(), s.end(), 3);
The first way takes \(O(\log n)\) time complexity beacuse it's based on binary search tree. The second way takes \(O(n)\) time complexity beacuse we need to go through the whole set.
Deletion¶
Directly use erease()
function.
If the element is in the set,just delete it and if there is no such element,nothing will happen.
Swap¶
If we have two sets s1
and s2
,we can use s1.swap(s2)
to swap the two sets.
In fact,the swap
function is just exchanging the pointers of the two sets,so it's very fast.
Map¶
Different from set
,map
has a key-value pair.value
can be the same but key
must be unique.
Each element in a map is a pair.The first is called key
and the second is called value
.
Map also automatically sorts the elements by key.
Insertion¶
We can use operator[]
to find a value by key or insert a new key-value pair.
C++ | |
---|---|