Table of contents
2.6 The iterator of the list is invalid
3. The simulation implementation of List
3.1 list simulation implementation (skipable)
3.2 Reverse iterator implementation
4. Comparison of List and Vector
1. List introduction
- list is a sequential container that can be inserted and deleted at any position within a constant range, and the container can be iterated back and forth.
- The bottom layer of the list is a doubly linked list structure. Each element in the doubly linked list is stored in an independent node that is not related to each other, and the pointer points to the previous element and the next element in the node.
- list is very similar to forward_list: the main difference is that forward_list is a singly linked list that can only be iterated forward, which makes it simpler and more efficient .
- Compared with other serial containers (array, vector, deque), list usually has better execution efficiency for inserting and removing elements at any position.
- Compared with other sequential containers, the biggest defect of list and forward_list is that it does not support random access at any position. For example, to access the sixth element of the list, you must iterate from a known position (such as the head or tail) to the position over which iterating requires linear time overhead; the list also requires some additional space to hold the associated information for each node (this can be an important factor for large lists storing elements of smaller types ).
2. Common use of List
2.1 The constructor of list
Constructor (construct) | Interface Description |
list (size_type n, const value_type& val = value_type())
|
The constructed
list
contains
n
elements
whose value is
val
|
list()
|
Construct an empty
list
|
list (const list& x)
|
copy constructor
|
list (InputIterator fifirst, InputIterator last)
|
Constructs
a list with elements in the range
[first, last)
|
2.2 Use of list iterators
function declaration | Interface Description |
begin+end |
Returns an iterator to the first element
+
returns an iterator to the next position of the last element
|
rbegin+rend |
Return the reverse_iterator
of the first element ,
that is,
the end
position
+ return
the reverse_iterator
of the next position of the last element ,
that is, the begin position
|
end is the next position of the last node, begin is the position of the first node
【Notice】
- begin and end are forward iterators, perform ++ operations on the iterator, and the iterator moves backward
- rbegin(end) and rend(begin) are reverse iterators, perform ++ operations on the iterator, and the iterator moves forward
Simple test:
void test3()
{
list<int>lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
list<int>::iterator it = lt.begin();
while (it != lt.end())
{
cout << *it << " ";
++it;
}
cout << endl;
//反向迭代器
list<int>::reverse_iterator rit = lt.rbegin();
while (rit != lt.rend())
{
cout << *rit << " ";
++rit;
}
cout << endl;
}
2.3 list capacity
function declaration | Interface Description |
empty | Check whether the list is empty, return true, otherwise return false |
size | Returns the number of valid nodes in the list |
2.4 list element access
function declaration | Interface Description |
front | Returns a reference to the value in the first node of the list |
back | Returns a reference to the value in the last node of the list |
2.5 list modifiers
function declaration | Interface Description |
push_front | Insert an element with value val before the first element of the list |
pop_front | delete the first element in the list |
push_back | Insert an element with value val at the end of the list |
pop_back | delete the last element in the list |
insert | Insert an element with value val at position pos |
erase | Delete the element at position pos |
swap | Swap the elements of two lists |
clear | Clear the valid elements in the list |
2.6 The iterator of the list is invalid
- The list will only become invalid after the delete operation
Because the underlying structure of the list is a two-way circular linked list with the leading node , the iterator of the list will not be invalidated when it is inserted into the list . It will only be invalidated when it is deleted, and only the iteration pointing to the deleted node will be invalidated. , other iterators are not affected .
Use the same as vector, accepting iterator return value.
void test4()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
list<int> l(array, array + sizeof(array) / sizeof(array[0]));
auto it = l.begin();
//while (it != l.end())
//{
// // erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给其赋值
// l.erase(it);
// ++it;
//}
//改正
while (it != l.end())
{
// erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给其赋值
it=l.erase(it);
++it;
}
}
3. The simulation implementation of List
3.1 list simulation implementation (skipable)
Node structure:
Iterator structure:
What is stored in the pointer is the address pointing to the data, -> (because the pointer has the address pointing to the data, it can directly point to the data, so it needs to return the address pointing to the data). p->a is equivalent to (*p).a
//T* operator->() Ptr operator->() { return &(operator*()); }
Linked list structure:
Private member variables:
private:
Node* _head;
Constructor:
Copy constructor:
Assignment operator overloading:
Destructor:
iterators:
insert:
erase:
push_back和pop_back:
push_front和pop_front:
3.2 Reverse iterator implementation
Iterator classification: (functional perspective) one-way, two-way, random.
Random iterators are special one-way and two-way iterators (inheritance relationship)
3.2.1 list reverse iterator
3.2.2 vector reverse iterator
4. Comparison of List and Vector
vector
|
list
|
|
underlying
structure
|
Dynamic sequence table, a continuous space
|
Doubly linked circular list with head node
|
random
access
|
Support random access, the efficiency of accessing an element
is O(1)
|
Random access is not supported, and
the efficiency of accessing an element
is O(N)
|
insert
and
delete
|
Insertion and deletion at any position is inefficient, and elements need to be moved. The time complexity
is
O(N)
. When inserting, it may need to increase capacity. Increase: open up new
space , copy elements, and release old space, resulting in lower efficiency
|
Insertion and deletion at any position are highly efficient,
do not need to move elements, and the time complexity is O(1)
|
space
utilization
|
The bottom layer is a continuous space, which is not easy to cause memory fragmentation,
high space utilization rate, and high cache utilization rate
|
The underlying nodes are dynamically opened, and small nodes are likely
to cause memory fragmentation, low space utilization, and
low cache utilization
|
iterator
_
|
Original ecological pointer
|
Encapsulate the original ecological pointer
(
node pointer
)
|
iterator
invalidation
_
|
When inserting elements, all iterators must be reassigned, because inserting
elements may cause re-expansion, causing the original iterator to become invalid. When
deleting , the current iterator needs to be reassigned or it will become invalid
|
Inserting an element will not invalidate the iterator.
When deleting an element, only the current
iterator will be invalidated, and other iterators will not be affected
|
usage
scenario
|
Requires efficient storage, supports random access, and does not care about insertion and deletion efficiency
|
Lots of insert and delete operations, don't care about
random access
|