"Analysis of STL Source Code" (4) - Serial Containers

1. Serial container

The so-called serial container, the elements in it can be ordered, but not necessarily orderly, C++ itself provides a serial container array, STL also provides vector, list, deque, stack, queue, priority-queue and other serial containers, among which Stack and queue are technically classified as a kind of adapter (adapater) because they only change the face of deque.

2、vector

2.1 The data structure of vecor

array

2.2 The difference between vector and array

1. Vector is a dynamic space. As elements increase, its internal mechanism will expand by itself to accommodate new elements.
2. Array is a static space, once the configuration cannot be changed.
3. Both are linear memory contiguous spaces.

//扩大内存空间
#include<iostream>
#include<vector>
int main(){
    
    
	int a[5];
	int b[10];
	for (int i = 0; i < 5; i++)
	{
    
    b[i] = a[i]} 
	//vector
	vector<int> vec{
    
    1,2,3};
	cout<< vec.size() << endl; //size表示元素个数
	cout << vec.capacity() << endl; //capacity表示占用的空间
	vec.push_back(4);
	vec.push_back(5);
	cout << vec.size() << endl; //5
	cout<< vec.capacity() << endl; //6
}	

2.3 Analysis of vector memory full load

1. In order to reduce the speed cost of space configuration, the actual configuration size of the vector may be larger than the client's demand for possible future use.
2. When the vector space is fully loaded, "configure new space/data movement/release old space" will be performed, and the time cost is very high. Therefore, when vecto configures new space, it is generally expanded by twice the old space.
3. Space configuration: If the original size is 0, configure the capacity as 1, otherwise it is twice the original size.

2.4 vector iterators

1. Vector maintains a continuous space, and ordinary pointers can meet the requirements and provide random access iterators.
2. Because the vector is fully loaded, the operation of "configure new space/data movement/release old space" is required, so the vector iterator will fail.

2.5vector space release

1. clear() function: clear all elements, but the capacity does not change, that is, size=0, capacity! =0
insert image description here
2. The following demo program shows that the size (number of elements) changes when push_back and pop_back change, and the size of capacity changes only when new space is allocated.
3. Because the capacity of the vector only increases but does not decrease, it is necessary to understand the release of the memory occupied by the vector.
Method 1: Swap() with the temporary variable
Method 2: clear() + shine_to_fit(), first clear all elements, and then adjust the capacity size to the element size.

#include<iostream>
#include<vector>
using namespace std;
int main()
{
    
    
	vector<int> vec{
    
    1,2,3,4,5};
	vector<int>().swap(vec); //方法1:和临时变量进行swap()
	vec.size();//0  
	vec.capacity()//0
	vec.clear();  //方法2:先清除所有元素,再将容量大小调整元素大小
	vec.shrink_to_fit(); 
}

Advantages and disadvantages of vector:
Advantages: random access. The time complexity is O(1).
Disadvantage: Insertion and deletion are O(n) complexity, and elements need to be moved.

3、list

3.1 List data structure

list is a circular doubly linked list, so it only needs one pointer to fully represent the entire linked list.
As long as a blank node is deliberately added to the end of the circular linked list, the "front closed and then open" interval can be satisfied.insert image description here

3.2 List space allocation

Unlike vector, list is a contiguous storage space and needs to reserve space to save the cost of "configure new space/data move/release old space" operations. Therefore, the capacity is equal to the number of elements.
Each time a node size is configured, when an element is deleted, the corresponding space is deleted together.

3.3 The iterator of the list

A list cannot use an ordinary pointer as an iterator like a vector, because its nodes are not guaranteed to exist contiguously in storage space.
List is a circular doubly linked list, and the iterator must have the ability to move forward and backward, so list provides bidirectional iterators.

3.4 Insert operation

insert image description here
Allocate a node, "Insert before"

3.5list advantages and disadvantages

Advantages: No reserved space, insertion and deletion are done in constant time.
Disadvantages: no random access, time complexity is O(n).

4、

4.1 The difference between deque and queue:

Vector is a continuous linear space with one-way openings, and deque is a continuous linear space with two-way openings.
Deque allows insertion and deletion of elements at the beginning in constant time. The vector needs to move the elements of the head end forward or backward as a whole, and the time complexity is O(N), which is extremely inefficient.
deuqe does not have the so-called concept of capacity, it is dynamically composed of segmented continuous spaces, and a new space can be added and connected at any time.

4.2deque's central controller:

The deque uses a so-called map (not a map container) as the master. The so-called map here is a small piece of contiguous space, in which each element is a pointer, pointing to another (larger) contiguous space, called a buffer, The buffer is the main storage space of the deque.
The continuous space of deque is an illusion, which is composed of a quantitative continuous space.
map is actually a T**, that is, a pointer, and the pointed thing is a pointer, pointing to a space of type T.
insert image description here

4.3 Deque's iterator

The iterator of deque contains four pointers:
cur iterator points to the current element of the
buffer first points to the head of the
buffer last points to the tail of the buffer
node points to the control center
When the buffer pointed to by map is full, the map needs to be expanded , the expansion process, configure a larger, copy the original, release the original, so the iterator of the deque will be invalid.
Deque's central controller, buffer, and iterator interrelationship:
insert image description here
deque adds elements at the end, triggering the configuration of a new buffer. insert image description here
The deque adds elements to the front, triggering the configuration of the new buffer.insert image description here

4.4 Data structure of deque

class deque{
    
    
	iterator strat;  //指向第一个节点
	iterator finish; //指向最后一个节点
	map_pointer map; //(T **类型)指向map是一块连续空间,每个元素是一个指针,指向一个缓冲区
	size_type map_size; //map内的指针数量 
}

4.5 How deque simulates continuous space

reference operator[](size_type n)
{
    
    	return start[difference_type(m)];}
reference front()
{
    
    	return * start;}
reference back()
{
    
    	iterator tmp = finish;
	--tmp;
	return *tmp;}
size_type size()cosnt
{
    
    	return finsh-start;}
bool empty() const
{
    
    	return finish == start;}
reference operator*() const
{
    
    	return *cur;}
pointer operator->()const
{
    
    	return &(operator*());}
//两个iterator之间的距离相当于:(1)两个迭代器之间buffer的总长度+(2)迭代器1到尾部的长度+(3)x到迭代器2头的长度
difference_type operator-(const self&x) const
{
    
    
	return difference_type(buffer_size()) *(node - x.node - 1) + (cur - first) +(x.last - x.cur);
}
self& operator++()
{
    
    ++cur;
if(cur == last){
    
    
	set_node(node+ 1); //如果到达尾部则跳跃至下一节点的起点
	cur = first;
	}
	return *this;
}
// 后置++ 和--同理
self& operator+=(difference_type n)
{
    
    
	difference_type offset = n+ (cur-first);
	if(offsrt >=0 && offset < buffer_size()) // 在同一个缓冲区中
	{
    
    	cur +=n;
	}
	else{
    
      //不在同一个缓冲区中
		difference_type node_offset = offset >0? offset/buffer_size():(-offset-1)/buffer_size() - 1;
	}
	set_node(node+node_offset);
	cur = first+(offset- node_offset * buffer_size());
	return * this;
}
// +, -= [(difference_type)n]操作中使用+= 实现

4.6deque advantages and disadvantages

1. It can be accessed randomly, and the time complexity is O(1). Insertion can be performed at the head and tail, which is more efficient than vector head insertion.
2. The time complexity of insertion and deletion is O(N), (head insertion and deletion and tail insertion and deletion are O(1)) If the number before the insertion position is small, the previous element will move forward, otherwise the latter element will move backward .

5, queue and stack

5.1queue

template<class T, class Sequence=deque<T>>
class queue{
    
    
protecred:
	Sequence c; //底层容器
public:
	bool empty()const{
    
    return c.empty();}
	size_type size() const{
    
    return c.size();}
	reference front() {
    
    return c.front();}
	const_reference front() const {
    
    return c.front()};
	reference back() {
    
    return c.back();}
	const_reference back() const {
    
    return c.back();}
	void push(const value_type &x) {
    
    c.push_back(x);}
	void pop() {
    
    c.pop_front();}
}

Queue can be implemented with list and deque, but not with map, set, and vector.

5.2stack

template<class T, class Sequence=deque<T>>
class stack{
    
    
protecred:
	Sequence c; //底层容器
public:
	bool empty()const{
    
    return c.empty();}
	size_type size() const{
    
    return c.size();}
	reference top() {
    
    return c.back();}
	const_reference top() const {
    
    return c.back()};
	void push(const value_type &x) {
    
    c.push_back(x);}
	void pop() {
    
    c.pop_back();}
};

You can use list, deque and vetor to implement stack, but not map and set.
Neither queue nor stack provide iterators, because these two containers do not allow element traversal.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324469269&siteId=291194637