Table of contents
1. Introduction to list
In C++, std::list
it is a container class provided by the standard library for chain storage of data. A linked list (list) is a non-continuous storage structure on a physical storage unit. The logical order of data elements is implemented through pointer links in the linked list.
- Composition of linked list: Linked list consists of a series of nodes .
- The composition of the node: 1. Data field to store data elements 2. Pointer field to store the address of the next node .
The linked list in STL is a bidirectional circular linked list . Since the storage method of the linked list is not a continuous memory space, the iterator in the linked list only supports forward and backward movements and is a bidirectional iterator .
2. The difference between std::list and std::vector
-
Low-level implementation:
list
Is implemented by a doubly linked list, each element contains pointers to the previous and next elements. This implementation makes inserting and deleting elements anywhere in the list efficient, but has poor performance for random access to elements.vector
It is implemented by a dynamic array, and the elements are stored continuously in memory. This implementation makes the performance of random access to elements very good, but inserting/removing elements in the middle or at the beginning involves moving elements, and the performance is relatively low.
-
Dynamic resizing:
list
The size of can grow and shrink dynamically because it uses a linked list to store elements, and the performance of insertion and deletion operations is independent of the size of the list.vector
The size can also grow dynamically, but this may result in a large number of element copying and memory reallocation operations when memory needs to be reallocated.
-
Access efficiency:
list
Random access is not supported, only sequential access via iterators. For scenarios that require frequent insertion and deletion operations,list
the performance is better.vector
Supports random access, elements can be accessed directly through subscripts. For operations that require frequent random access,vector
the performance is better.
-
Memory usage:
list
When storing elements, in addition to the value of the element itself, additional space is required to store pointers to the previous and next elements. Therefore, it usuallyvector
uses more memory than .vector
When storing an element, only the value of the element itself and some additional control information need to be stored, so it usually useslist
less memory than .
-
Insertion and deletion operations:
list
It is efficient for inserting and deleting elements at arbitrary positions because it only requires modifying the pointers of adjacent elements and does not require moving other elements.list
There is an important property. Neither insertion nor deletion operations will cause the original list iterator to become invalid. Thisvector
is not true in .vector
It is efficient for inserting and deleting elements at the end because it only needs to operate at the end of the array and does not require moving other elements. But when inserting/removing elements in the middle or beginning, other elements need to be moved.
To sum up, choosing to use list
or vector
depends on the specific application scenarios and needs. You can choose this if frequent insertion and deletion operations are required and frequent random access to elements is not required list
. If you need frequent random access to elements and fewer insertion and deletion operations, you can choose it vector
. In addition, if you need to perform insertion and deletion operations in the middle of the container, and the access efficiency is not high, you can consider using it list
.
3. List constructor
Constructor prototype | explain | |
---|---|---|
1 | list<T> lt | Default constructor, implemented using template classes |
2 | list(lt.begin(), lt.end()) | Copy the elements in the lt[begin, end) interval to itself |
3 | list(n, Element) | The constructor copies n Elements to itself |
4 | list(const list <) | copy constructor |
Example:
#include <iostream>
#include <list> //必须包含该头文件
using namespace std;
void printVec(list<int> &v)
{
for (list<int>::iterator At = v.begin(); At != v.end(); At++)
{
cout << *At << " ";
}
cout << endl;
}
void printVec(list<double> &v)
{
for (list<double>::iterator At = v.begin(); At != v.end(); At++)
{
cout << *At << " ";
}
cout << endl;
}
void test01()
{
list<int> v1;
v1.push_back(10); //添加元素
v1.push_back(20);
printVec(v1);
list<int> v2(v1.begin(), v1.end());
printVec(v2);
list<double> v3(5, 6.32);
printVec(v3);
list<double> v4(v3);
printVec(v4);
}
int main()
{
test01();
system("pause");
return 0;
}
//result
10 20
10 20
6.32 6.32 6.32 6.32 6.32
6.32 6.32 6.32 6.32 6.32
Notice:
When list is used as a parameter or return value of a function, the "&" cannot be missing.
4. List assignment
Function prototype: =, assign | explain | |
---|---|---|
1 | list& operator=(const list <) | Overloaded = operator |
2 | assign(begin, end) | Copy and assign the data in the [begin, end) interval to itself |
3 | assign(n, Element) | Assign n Element copies to itself |
Example:
#include <iostream>
#include <list> //必须包含该头文件
using namespace std;
void printVec(list<int> &v)
{
for (list<int>::iterator At = v.begin(); At != v.end(); At++)
{
cout << *At << " ";
}
cout << endl;
}
void test01()
{
list<int> v1;
v1.push_back(10); //添加元素
v1.push_back(20);
printVec(v1);
list<int> v2 = v1;
printVec(v2);
list<int> v3;
v3.assign(v1.begin(), v1.end());
printVec(v3);
list<int> v4;
v4.assign(6, 1);
printVec(v4);
}
int main()
{
test01();
system("pause");
return 0;
}
//result
10 20
10 20
10 20
1 1 1 1 1 1
5. List length operation
Function prototype: empty, size, resize | explain | |
---|---|---|
1 | empty() | Determine whether the container is empty |
2 | size() | Returns the number of elements in the container |
3 | resize(int num) | Respecify the length of the container to num. If the container becomes longer, the new position is filled with the default value; if the container becomes shorter, the elements at the end that exceed the length of the container are deleted. |
4 | resize(int num, Element) | Respecify the length of the container to num. If the container becomes longer, the new position is filled with the Element value; if the container becomes shorter, the elements at the end that exceed the length of the container are deleted. |
Example:
#include <iostream>
#include <list> //必须包含该头文件
using namespace std;
void printVec(list<int> &v)
{
for (list<int>::iterator At = v.begin(); At != v.end(); At++)
{
cout << *At << " ";
}
cout << endl;
}
void test01()
{
list<int> v1;
if (v1.empty()) //判断是否为空
{
cout << "当前v1为空!" << endl;
}
v1.push_back(10); //添加元素
v1.push_back(20);
v1.push_back(30);
if (!v1.empty())
{
cout << "v1中元素个数:" << v1.size() << endl;
printVec(v1);
}
v1.resize(5);
printVec(v1);
v1.resize(10, 1);
printVec(v1);
}
int main()
{
test01();
system("pause");
return 0;
}
//result
当前v1为空!
v1中元素个数:3
10 20 30
10 20 30 0 0
10 20 30 0 0 1 1 1 1 1
6. List insertion and deletion
Function prototype: push_back, pop_back, insert, erase, clear | explain | |
---|---|---|
1 | push_back(Element) | Insert element at the end |
2 | pop_back() | Remove last element |
3 | push_front(Element) | Insert an element at the beginning of the container |
4 | pop_front() | Remove the first element from the beginning of the container |
5 | insert(iterator p, Element) | The iterator points to position p to insert the element Element |
6 | insert(iterator p, int n, Element) | The iterator points to position p and inserts n elements Element |
7 | insert(p,iterator start, iterator end) | Insert data in the interval [start, end) at position p, no return value |
8 | erase(iterator p) | Delete the element pointed to by the iterator |
9 | erase(iterator start, iterator end) | Delete the elements from start to end of the iterator |
10 | remove(elem) | Delete all elements in the container that match the elem value |
11 | clear() | Delete all elements in the container |
Example:
#include <iostream>
#include <list> //必须包含该头文件
using namespace std;
void printVec(list<int> &v)
{
for (list<int>::iterator At = v.begin(); At != v.end(); At++)
{
cout << *At << " ";
}
cout << endl;
}
void test01()
{
list<int> v1;
v1.push_back(1); //尾部添加元素
v1.push_back(2);
v1.push_back(3);
v1.push_back(3);
cout << "尾部添加元素: " << endl;
printVec(v1);
v1.pop_back(); //尾部删除元素
cout << "尾部删除元素: " << endl;
printVec(v1);
v1.push_front(100); //头部添加元素
v1.push_front(200);
v1.push_front(300);
cout << "头部添加元素: " << endl;
printVec(v1);
v1.pop_front(); //头部删除元素
v1.pop_front();
cout << "头部删除元素: " << endl;
printVec(v1);
v1.insert(v1.begin(), 100); //插入元素100
cout << "插入元素100: " << endl;
printVec(v1);
v1.insert(v1.begin(), 5, 100); //插入5个元素100
cout << "插入5个元素100: " << endl;
printVec(v1);
v1.erase(v1.begin()); //删除元素
cout << "删除元素v1.begin(): " << endl;
printVec(v1);
v1.remove(100);
cout << "删除所有100元素: " << endl;
printVec(v1);
v1.clear(); //清空容器
printVec(v1);
}
int main()
{
test01();
system("pause");
return 0;
}
//result
尾部添加元素:
1 2 3 3
尾部删除元素:
1 2 3
头部添加元素:
300 200 100 1 2 3
头部删除元素:
100 1 2 3
插入元素100:
100 100 1 2 3
插入5个元素100:
100 100 100 100 100 100 100 1 2 3
删除元素v1.begin():
100 100 100 100 100 100 1 2 3
删除所有100元素:
1 2 3
7. List data acquisition
Function prototype: front(), back | explain | |
---|---|---|
1 | front() | Returns the first data element in the container |
2 | back() | Returns the last data element in the container |
Example:
#include <iostream>
#include <list> //必须包含该头文件
using namespace std;
void test01()
{
list<int> v1 = {
1, 2, 3, 4, 5, 6 };
cout << "v1.front() = " << v1.front() << endl;
cout << "v1.back() = " << v1.back() << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
//result
v1.front() = 1
v1.back() = 6
8. List exchange, reversal, sorting
Function prototype: swap, reverse, sort | explain | |
---|---|---|
1 | swap(list lt) | Swap the elements in lt with its own elements |
2 | reverse() | Reverse linked list |
3 | sort() | Linked list sorting |
Example:
#include <iostream>
#include <list> //必须包含该头文件
using namespace std;
void printVec(list<int> &v)
{
for (list<int>::iterator At = v.begin(); At != v.end(); At++)
{
cout << *At << " ";
}
cout << endl;
}
void test01()
{
list<int> v1 = {
9, 5, 7, 8, 6 };
list<int> v2 = {
5, 4, 3, 2, 1 };
v1.swap(v2); //互换v1与v2中的元素
cout << "list v1 : " ;
printVec(v1);
cout << "list v2 : " ;
printVec(v2);
v2.sort(); //链表排序
cout << "v2链表排序 : ";
printVec(v2);
v2.reverse(); //反转链表v2
cout << "v2反转链表 : ";
printVec(v2);
}
int main()
{
test01();
system("pause");
return 0;
}
//result
list v1 : 5 4 3 2 1
list v2 : 9 5 7 8 6
v2链表排序 : 5 6 7 8 9
v2反转链表 : 9 8 7 6 5