Hot interview questions: comparison of the advantages and disadvantages of vector and list in stl, and the difference between list iterators and vector iterators

Advantages of vectors

  1. The bottom
    layer of the subscript random access vector is a continuous physical space, so it supports random access
  2. Tail insertion and tail deletion are highly efficient.
    Similar to an array, we can easily find the last element and complete various operations
  3. The cpu cache hit rate is high
    because when the system acquires space at the bottom layer, it takes a section into the cpu, instead of just taking a single one, it will take a little more in advance and back. The physical addresses of the vector are continuous, so we get the data again. Sometimes, the cpu will access the data behind it faster

Disadvantages of vectors

  1. The efficiency of inserting and deleting data in the front part is low.
    If we want to insert or delete data in the front or in the middle, we cannot delete it directly. We need to move the data to overwrite or add a space, so that the efficiency of our moving data is O(N)
  2. Expansion has consumption, and there may be a certain amount of space waste.
    Under normal circumstances, our vector expansion mechanism is once the capacity of the current space is reached, then we expand the original space by 1.5 times or 2 times (vs is generally 1.5 times and g++ is 2 times ), such expansion may lead to waste of space, and frequent expansion will also affect efficiency

Advantages of lists

  1. Apply for release on demand, no need to expand
    the list is a leading two-way circular linked list, then the linked list is connected by independent spaces, as many as you need, just as much as new, there is no waste of space
  2. The efficiency of insertion and deletion at any position is high (compared to vector).
    Because list is a two-way circular linked list, we need to insert new elements only need to change the next and prev (next and previous) of the original data, so our insertion and deletion efficiency is O( 1)

Disadvantages of lists

  1. Does not support subscript random access
    Because our list is a linked list, the physical addresses where we store data are not continuous, so we cannot support random access
  2. The low hit rate of the cpu cache
    is still related to the discontinuity of its physical space address. A piece of data stored by the cpu in advance may not be related to the next data at all, because their space is not continuous, so the hit rate is low

Vector and list are a complementary relationship

iterator difference

Since the list does not support random access, how should we access the data? We certainly cannot directly access the underlying next and prev, we still use iterators, so what is the difference between this iterator and the iterators of vector and string?

What is the value of an iterator?

  1. Encapsulate the underlying implementation without exposing the underlying implementation details
  2. Provide a unified access method to reduce usage costs

iterator:

  1. Embedded type (int double)
  2. Wrapped types that behave like pointers

insert image description here
insert image description here
Refer to the list iterator to simulate the underlying code:

template<class T, class Ref, class Ptr>
	struct __list_iterator
	{
    
    
		typedef list_node<T> node;
		typedef __list_iterator<T, Ref, Ptr> Self;
		node* _pnode;

		__list_iterator(node* p)
			:_pnode(p)
		{
    
    }
		
		Ptr operator->()
		{
    
    
			return &_pnode->_data;
		}
		
		Ref operator*()
		{
    
    
			return _pnode->_data;
		}

		Self& operator++()
		{
    
    
			_pnode = _pnode->_next;
			return *this;
		}

		Self operator++(int)
		{
    
    
			Self tmp(*this);
			_pnode = _pnode->_next;		
			return tmp;
		}

		Self& operator--()
		{
    
    
			_pnode = _pnode->_prev;
			return *this;
		}

		Self operator--(int)
		{
    
    
			Self tmp(*this);
			_pnode = _pnode->_prev;
			return tmp;
		}

		bool operator!=(const Self& it) const
		{
    
    
			return _pnode != it._pnode;
		}

		bool operator==(const Self& it) const
		{
    
    
			return _pnode == it._pnode;
		}
	};

template<class T, class Ref, class Ptr> Three template parameters are used here to distinguish between ordinary iterators and const iterators

Two types instantiated from the same class template
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;

Why do const iterators need to instantiate two types like this, instead of adding const in front of ordinary iterators?
insert image description here

Guess you like

Origin blog.csdn.net/DEXTERFUTIAN/article/details/128939232