一丶list介绍
C++中的list
容器底层确实是以双向链表的形式实现的。
list
容器是C++标准模板库(STL)中的一部分,它提供了对列表数据结构的实现。
- 双向链表结构:
list
容器的每个元素都是通过指针链接在一起的,每个元素都包含指向前一个和后一个元素的指针。这种双向链表的结构使得在list
容器中插入和删除元素时无需移动其他元素,因此这些操作的时间复杂度为O(1)。 - 内存分配:由于
list
容器基于双向链表,其元素可以分散存储在内存中,不需要像数组或vector
那样连续分配内存空间。这使得list
在内存使用上更加灵活,特别适合于需要频繁插入和删除操作的场景。 - 迭代器稳定性:
list
容器的迭代器在插入和删除操作中保持稳定性,即使在进行这些操作时,指向其他元素的迭代器也不会失效。
二丶list的使用
C++中list
容器提供了多种用于操作列表的函数,使得对元素的插入、删除和访问变得灵活而高效。以下是一些常用的list
容器函数:
- push_back():在列表的尾部插入一个新元素。
- push_front():在列表的头部插入一个新元素。
- pop_back():删除列表尾部的元素。
- pop_front():删除列表头部的元素。
- size():返回列表中元素的个数。
- empty():判断列表是否为空,如果为空则返回true,否则返回false。
- clear():清除列表中的所有元素。
- erase():删除列表中的一个或多个元素。
- remove():移除列表中所有等于特定值的元素。
- sort():对列表中的元素进行排序。
- reverse():反转列表中元素的顺序。
#include<iostream>
#include<list>
using namespace std;
template<class T>
void PrintList(const list<T>& l) //打印函数
{
auto it = l.begin();
while (it != l.end())
{
cout << *it << " ";
it++;
}
cout << endl;
}
void ListTest()
{
list<int> l; //空
l.push_back(1); //尾插
l.push_back(2);
l.push_back(3);
PrintList(l);
list<int> _l(l); //构造函数重载
PrintList(_l);
_l.clear();
l.push_front(4); //头插
l.push_front(5);
l.push_front(6);
PrintList(l);
l.sort(); //排序
PrintList(l);
l.pop_back(); //尾删
l.pop_back();
PrintList(l);
l.pop_front(); //头删
l.pop_front();
PrintList(l);
}
int main()
{
ListTest();
return 0;
}
这些用法其实很简单,主要还是要学会灵活使用。这里要注意一下sort函数,默认是升序函数
底层使用的一般是快速排序算法,然后sort重载了另一个函数,这里的Compare 是用来控制升序或者降序的,称为仿函数
std::list::sort
(1)
void sort();
(2)
template <class Compare>
void sort (Compare comp);
如下,MyCompare 只重载了运算符(),然后我们自己写了一个sort,调用的是std::sort,std::sort(迭代器1,迭代器2,仿函数),不传仿函数就调用另一个重载函数将迭代器范围内升序排序
struct MyCompare {
bool operator()(int a, int b) {
return a > b; // 降序排列
}
};
template <class ForwardIt, class Compare>
void sort(ForwardIt first, ForwardIt last, Compare comp) {
// ... 其他代码 ...
while (first != last) {
// ... 其他代码 ...
// 使用comp比较函数对象比较两个元素
if (comp(*i, *j)) {
// ... 其他代码 ...
} else {
// ... 其他代码 ...
}
// ... 其他代码 ...
}
// ... 其他代码 ...
}
三丶与vector比较
-
内存分配:
vector
:在内存中连续存储元素,当需要添加或删除元素时,可能会导致整个容器的内存重新分配。list
:在内存中非连续存储元素,每个元素都是一个单独的节点,包含数据和指向前后节点的指针。因此,添加或删除元素时,只需要修改相邻节点的指针,不会影响其他元素的内存位置。
-
访问方式:
vector
:支持随机访问,可以直接通过索引访问任何元素,访问速度快。list
:不支持随机访问,只能通过迭代器进行顺序访问。
-
插入和删除操作:
vector
:在尾部插入和删除元素的效率高,因为不需要移动其他元素;而在中间或头部插入和删除元素效率较低,因为需要移动其他元素。list
:在任何位置插入和删除元素的效率都较高,因为只需要修改相邻节点的指针。
-
容量和大小:
vector
:有固定的容量,可以容纳的元素数量有限。当超过容量时,会自动扩容,可能会引起内存重新分配和元素移动。list
:没有固定容量的概念,只要内存允许,可以不断地添加新元素。
-
性能:
vector
:在内存中连续存储,有利于缓存的利用,因此访问速度较快。但在插入和删除操作时可能需要移动大量元素,效率较低。list
:在内存中非连续存储,不利于缓存的利用,访问速度较慢。但在插入和删除操作时只需要修改指针,效率较高。
总之,vector
和list
各有优缺点,具体使用哪个容器取决于具体的应用场景和需求。如果需要频繁访问元素,可以选择vector
;如果需要频繁插入和删除元素,可以选择list
。