什么是list
在C++中,
list
是一种序列容器,属于标准模板库(STL)的一部分。它是一个双向链表,可以高效地进行插入和删除操作,尤其是在序列的中间部分
list的特点
- 动态数组:
list
是一个动态数组,其长度可以根据需要增长或缩小。- 双向链表:每个节点包含数据和两个指针,分别指向前一个和后一个节点,允许双向遍历。
- 插入和删除操作高效:在任何位置插入或删除元素都非常快速,因为不需要移动其他元素。
- 没有随机访问:
list
不支持通过索引直接访问元素,访问必须从头开始迭代。- 内存分配:元素可以非连续地存储在内存中,无需连续的内存块。
- 迭代器:提供双向迭代器,可以向前和向后遍历。
- 常用成员函数:如
push_back
,push_front
,pop_back
,pop_front
,insert
,erase
,splice
等,用于链表操作。小结:选择使用list还是其他容器(如vector或deque)取决于具体的应用场景和性能需求。如果应用需要频繁地在序列中间插入或删除元素,list是一个很好的选择。
如果需要快速随机访问元素,则vector可能是更好的选择。
list常用的函数接口
构造函数
1)无参构造
list();
创建一个空的
list
容器,不包含任何元素
2)用n个val值构造
list(size_t n, const value_type& val = value_type());
创建一个包含n个元素的
list
容器,所有元素都被初始化为val的副本。如果不提供val参数,则使用默认构造函数初始化元素
3)拷贝构造函数
list(const list& x);
创建一个新的
list
容器,它是另一个同类型list
容器x的副本。这个构造函数会复制x中的所有元素到新的容器中
4)用迭代器进行初始化构造
1. template <class InputIterator> 2. list(InputIterator first, InputIterator last);
创建一个
list
容器,并用迭代器范围[first, last)
中的元素来初始化它。这个构造函数可以用来从一个已存在的容器或者迭代器指定的序列中复制元素到新的
list
容器中。InputIterator
可以是任何能够提供输入迭代器功能的迭代器类型
容量操作接口
1)size
size_t size() const;
返回
list
中实际元素的个数。这个操作的时间复杂度是常数时间O(1),因为它不需要遍历整个容器来计算元素的数量
2)empty
bool empty() const;
检查
list
是否为空,即是否不包含任何元素。如果容器为空,则返回
true
;否则返回false
。这个操作同样具有常数时间复杂度O(1)
3)resize
void resize(size_type n); void resize(size_type n, const value_type& val);
调整list
容器的大小以包含n个元素。
如果n小于当前容器的大小,则删除末尾的元素以缩小容器。
如果n大于当前容器的大小,则通过在末尾插入新元素来扩展容器。
如果提供了第二个参数val,那么新添加的元素会被初始化为val的副本;如果没有提供第二个参数,则使用默认构造函数来初始化新元素
访问和遍历
1)迭代器(正向迭代器和反向迭代器)
iterator begin(); const_iterator begin() const; iterator end(); const_iterator end() const; reverse_iterator rbegin(); const_reverse_iterator rbegin() const; reverse_iterator rend(); const_reverse_iterator rend() const;
begin()
返回指向容器中第一个元素的迭代器。end()
返回指向容器中最后一个元素之后位置的迭代器。rbegin()
返回指向容器中最后一个元素的逆向迭代器。rend()
返回指向容器中第一个元素之前位置的逆向迭代器。const_iterator
和const_reverse_iterator
类型的迭代器只能用于读取元素,不能用于修改元素。
2)front and back
reference front(); const_reference front() const; reference back(); const_reference back() const;
front()
返回对容器中第一个元素的引用。back()
返回对容器中最后一个元素的引用。const_reference
类型的引用只能用于读取元素,不能用于修改元素
list的增删查改
1)push_front
void push_front(const value_type& val);
在
list
的开始处插入一个新元素,这个元素是val
的副本
2)push_back
void push_back(const value_type& val);
在
list
的末尾添加一个新元素,这个元素是val
的副本
3)pop_front
void pop_front();
删除
list
中的第一个元素
4)pop_back
void pop_back();
删除
list
中的最后一个元素
5)find
template <class InputIterator, class T> InputIterator find(InputIterator first, InputIterator last, const T& val);
在list
中查找值为val
的第一个元素,返回一个指向该元素的迭代器,如果未找到则返回last
注意:find
不是list
的成员函数,而是算法的一部分,通常在<algorithm>
头文件中定义
6)insert
iterator insert(iterator position, const value_type& val); void insert(iterator position, size_type n, const value_type& val); template <class InputIterator> void insert(iterator position, InputIterator first, InputIterator last);
在position
指定的位置插入一个新元素val
,或者插入n
个值为val
的元素,或者插入由迭代器范围[first, last)
指定的元素序列
7)erase
iterator erase(iterator position); iterator erase(iterator first, iterator last);
删除由position
指定的单个元素,或者删除由迭代器范围[first, last)
指定的元素序列
注: list的insert和erase会不会造成迭代器失效的问题?
list
的insert
和erase
操作不会导致迭代器失效。解释:
- insert:在 list 中插入元素时,由于 list 是由双向链表实现的,插入操作会创建新的节点并将其链接到链表中,不会影响到其他节点的内存位置,因此所有迭代器(包括指向插入点之前、之后和插入点本身的迭代器)仍然有效。
- erase:当从 list 中删除元素时,只会移除特定的节点并重新链接其前后的节点,而不会影响其他节点的位置。因此,除了被擦除元素的那个迭代器外,其他迭代器仍然有效。
简单来说:
- insert:非侵入式节点插入,迭代器保持有效。
- erase:节点移除,仅影响目标迭代器,其他迭代器保持有效
8)swap
void swap(list& other);
交换两个
list
容器的内容,这个操作非常高效,因为它只交换内部数据结构,而不需要交换实际的元素
9)assign
void assign(size_t n, const value_type& val); template <class InputIterator> void assign(InputIterator first, InputIterator last);
将list
的内容替换为n
个值为val
的元素,或者替换为由迭代器范围[first, last)
指定的元素序列
10)clear
void clear();
删除
list
中的所有元素,使容器变为空
list顺序修改接口
void reverse();
reverse
函数会反转list
中元素的顺序。也就是说,列表中的第一个元素会变成最后一个元素,第二个元素会变成倒数第二个元素,以此类推。这个操作会就地(in-place)进行,不需要额外的存储空间。调用这个函数后,列表的迭代器、引用和指针仍然有效,但它们现在会指向反转后的列表中的不同元素