list容器的基础概念
在 C++ 标准库中,list 是一种双向链表,允许在任何位置进行快速的插入和删除操作。
以下是一些关于 list 的基本信息。
-
存储:list 是一种双向链表结构,它不像 vector 或 array 那样提供连续的内存存储。
-
时间复杂度:
list 在链表的开始、结束或中间位置插入和删除元素的时间复杂度是 O(1)。然而,查找元素的时间复杂度是 O(n)。
-
空间复杂度:由于链表中每个元素都需要额外存储其前后节点的信息,因此 list 相比于使用连续内存的容器(如 vector 或 array)具有更高的空间复杂度。
-
迭代器失效:
当你插入或删除元素时,list 的所有迭代器,包括指向链表开始和结束位置的迭代器,都不会失效。唯一的例外是当你删除一个元素时,指向该元素的迭代器将失效
。 -
元素访问:
list 不支持随机访问。要访问 list 中的元素,你必须从链表的开始(或结束)位置遍历到你要访问的位置。
因此,list 不提供 operator[] 函数(下标运算符)。
list的函数解析
- list有各种各样的成员函数,下面我将以函数的功能对这些函数分一下类,然后按照类别,一一介绍这些函数的用处。
构造函数
list():
创建一个空的 listlist(n, elem)
: 创建一个包含 n 个元素的 list,每个元素的值都是 elemlist(begin, end)
: 创建一个包含 [begin, end) 区间元素的 list
以下是使用这些构造函数创建 std::list 的示例:
#include <iostream>
#include <list>
#include <vector>int main() {// 创建一个空的 liststd::list<int> list1;// 创建一个包含 5 个元素的 list,每个元素的值都是 10std::list<int> list2(5, 10);// 从 vector 创建 liststd::vector<int> vec = {1, 2, 3, 4, 5};std::list<int> list3(vec.begin(), vec.end());// 打印 list2for(int i : list2) {std::cout << i << " ";}std::cout << "\n";// 打印 list3for(int i : list3) {std::cout << i << " ";}return 0;
}
元素访问函数
- front(): 返回首元素
- back(): 返回尾元素
注意:这里是返回的是链表的元素,而不是指向元素的迭代器或指针
。
各种迭代器函数
- begin(): 返回指向首元素的迭代器
- end(): 返回指向尾元素的下一个位置的迭代器
- rbegin(): 返回指向尾元素的反向迭代器
- rend(): 返回指向首元素的前一个位置的反向迭代器
在这里我想详细讲解一下这个迭代器:
你可以把list的这个这个迭代器,详细成一个高级的指针。
- 迭代器是一个对象(指针),假如说list里面的节点元素都是一个个的值了话,这个迭代器就是一个指向这个值的一个指针罢了。我们就可以用解引用符 * 去修改这个值。
- 假如说迭代器指向的这个对象它是一个类,或者是一个结构体,它有成员变量,那你就可以用箭头符 -> 去操作这个对象的成员变量。
你可以把这个对象想象成你自己定义的Listnode,你用箭头符去操作它,hh
判断容器容量函数:
empty():
判断容器是否为空size():
返回容器中元素的个数max_size():
返回容器能够容纳的最大元素数量
添加操作
insert(position, elem)
: 在 position 位置前插入一个元素push_back(elem)
: 在 list 的尾部添加一个元素push_front(elem)
: 在 list 的头部添加一个元素
删除操作
clear()
: 删除所有元素erase(position)
: 删除 position 位置的元素pop_back()
: 删除 list 尾部的一个元素pop_front()
: 删除 list 头部的一个元素unique()
: 删除所有相邻重复元素remove_if(predicate)
: 删除满足条件 predicate 的所有元素remove(elem)
: 删除所有值为 elem 的元素
修改容器大小的函数
resize(size, elem)
: 改变容器的大小,如果需要添加元素,则元素值为 elem
具体讲解一下splice()这个函数
splice() 是list 的一个非常有用的成员函数,它可以高效地将元素从一个列表移到另一个列表,或者从列表的一个位置移动到另一个位置
。因为它是重新链接节点指针,不会导致元素内容的复制或移动,所以速度非常快。它一共有三种重载版本。
三种重载版本如下:
-
void splice (const_iterator position, list& x);
- 将 x 中的所有元素移到当前列表的 position 位置。 x 变为空。
-
void splice (const_iterator position, list& x, const_iterator i);
- 将 x 中的元素 i 移到当前列表的 position 位置。 i 在 x 中的元素被移除。
-
void splice (const_iterator position, list& x, const_iterator first, const_iterator last);
-
将 x 中的 [first, last) 区间的元素移到当前列表的 position 位置。 这个区间在 x 中的元素被移除。
-
注意:position 和 x 可以指向同一个列表,但 position 不能在 [first, last) 区间内。
-
下面是使用 splice() 的例子:
#include <iostream>
#include <list>int main() {std::list<int> list1 = {1, 2, 3};std::list<int> list2 = {4, 5, 6};// move all elements of list2 to list1list1.splice(list1.end(), list2);std::cout << "list1: ";for (int num : list1) {std::cout << num << " ";}std::cout << "\n";std::cout << "list2: ";for (int num : list2) {std::cout << num << " ";}std::cout << "\n";// move back one element from list1 to list2list2.splice(list2.begin(), list1, --list1.end());std::cout << "list1: ";for (int num : list1) {std::cout << num << " ";}std::cout << "\n";std::cout << "list2: ";for (int num : list2) {std::cout << num << " ";}std::cout << "\n";return 0;
}
在这个例子中,我们首先创建了两个列表。然后,我们将 list2 中的所有元素移动到 list1 的尾部。接着,我们将 list1 的最后一个元素移动到 list2 的头部。每次操作后,我们都打印出两个列表的内容。
交换元素的函数
- swap(list): 交换两个 list
反转链表函数
- reverse(): 反转 list
对链表进行排序的函数
- sort(): 排序 list
这是一些使用 list 的示例:
#include <iostream>
#include <list>int main() {std::list<int> numbers;// push elementsnumbers.push_back(5);numbers.push_back(10);numbers.push_front(1);// iterate through the listfor(std::list<int>::iterator it = numbers.begin(); it != numbers.end(); ++it) {std::cout << *it << ' ';}std::cout << '\n';// remove an elementnumbers.remove(1);for(auto &num : numbers) {std::cout << num << ' ';}std::cout << '\n';// sort the listnumbers.sort();for(auto &num : numbers) {std::cout << num << ' ';}std::cout << '\n';return 0;
}
这段代码首先创建了一个空的 list,然后在尾部和头部添加了一些元素。然后它通过迭代器遍历 list 并打印每个元素。然后它删除一个元素,并再次打印 list。最后,它对 list 进行排序,并打印排序后的 list。
总结
-
在C++标准库中,list是一种双向链表,允许在任何位置进行快速的插入和删除操作。list在任何位置插入和删除元素都有相对稳定的性能,而不是依赖于元素在容器中的位置。
-
我们讨论了list的多种构造函数,包括默认构造函数、初始化列表构造函数、以及从其他容器复制元素的构造函数。
-
我们也介绍了 splice() 函数,这是一个非常有用的成员函数,它可以高效地将元素从一个列表移到另一个列表。splice()有三种重载版本,它们都不会导致元素内容的复制或移动,而是重新链接节点指针,因此速度非常快。
最后,我们讨论了一些其他的std::list成员函数,包括元素访问、迭代器、容量查询、列表修改和操作等。
最后的最后,如果你觉得我的这篇文章写的不错的话,请给我一个赞与收藏,关注我,我会继续给大家带来更多更优质的干货内容
。