代码展示
#include<iostream>
#include<string>
#include<list>
using namespace std;
void printlist(const list<int>&l) {for (list<int>::const_iterator it = l.begin(); it != l.end(); it++) {cout << *it << " ";}cout << endl;
}
void test01() {list<int>l1;l1.push_back(10);l1.push_back(20);l1.push_back(30);l1.push_back(40);l1.push_back(50);printlist(l1);list<int>l2(l1.begin(), l1.end());printlist(l2);list<int>l3(l2);printlist(l3);list<int>l4(10, 100);printlist(l4);
}
void test02() {list<int>l1;l1.push_back(10);l1.push_back(20);l1.push_back(30);l1.push_back(40);list<int>::iterator it = l1.begin();it++;it--;}
void test03() {list<int>l1;l1.push_back(10);l1.push_back(50);l1.push_back(20);l1.push_back(15);l1.push_back(70);l1.push_back(90);printlist(l1);l1.reverse();printlist(l1);l1.sort();printlist(l1);}
int main() {test03();system("pause");return 0;}
写者总结
1.List容器的优点:可以对任意位置进行快速插入或者删除元素
List容器的缺点:容器遍历速度没有数组快,占用的空间比数组大
但是这些优点和缺点同时又是数组的缺点和优点,因此我们说链表和数组在性质上是互补的
2.STL中的链表是双向循环链表
List链表迭代器只支持前移和后移
List链表的优点是采用动态存储分配,不会造成内存浪费和溢出,并且执行插入和删除操作十分方便,修改指针即可,不用移动大量元素。
但同时list链表的缺点就是时间和空间耗费大
3.L1[0]不可以用[]的方式访问list中的元素
L1.at(0)同样也不可以用at访问
原因是List本质链表,不是用连续性空间存储数据,迭代器也不支持随机访问
it=it+1就是不行的,因为list不是连续存储,it=it+2,it=it+3也是不行
但是,it++和it--都是可以的,list链表支持双向访问
在C++的STL(标准模板库)中,list
容器是一个双向链表结构,它允许以常数时间复杂度O(1)在容器的任意位置插入和删除元素,这种特性使得list
非常适合频繁进行插入和删除操作的场景。然而,list
并不支持快速随机访问,因为它的元素不是连续存储的,这意味着我们不能通过下标直接访问某个节点。
list
容器的优点
-
高效的插入和删除:由于
list
内部实现为双向链表,所以在列表中的任何位置执行插入或删除操作的时间复杂度都是O(1),这与基于数组实现的容器如vector
形成对比,在后者中插入或删除中间元素可能需要移动大量的数据来保持连续性。 -
灵活性:可以轻松地创建循环链接的数据结构,并且支持多种构造方式,包括但不限于从另一个
list
实例复制、使用区间构造等。
list
容器的缺点
-
不支持随机访问:不像
vector
那样可以通过索引迅速定位到特定位置,list
只能通过迭代器从前向后或者从后向前逐步遍历到达目标位置,因此查询效率较低。 -
额外的空间开销:每个节点除了保存实际数据外,还需要额外存储指针信息指向前后相邻的节点,这就导致了相比同样数量元素但使用连续内存分配的容器而言,
list
会占用更多的内存空间。
与数组的比较
-
存取速度:数组是连续分配的一块内存区域,因此提供了非常快的随机访问性能;而
list
则不具备这样的优势,因为其元素分散存储,必须逐个访问才能到达指定位置。 -
动态调整大小:数组一旦初始化后其大小固定不变,若要改变长度,则需重新分配一块新的内存并复制旧内容过去;相反,
list
能够方便地调整自身尺寸而不影响现有元素的位置。 -
内存布局:数组所有元素都紧密排列在一起,便于缓存命中率优化;而
list
则是松散分布,不利于CPU缓存机制发挥最佳效能。
创建list
容器的方式
-
默认构造函数:创建一个空的
list
对象,例如list<int> l1;
。 -
加数构造函数:用n个相同值填充新创建的
list
,如list<int> l4(10, 100);
表示创建包含十个100的整数列表。 -
区间构造:从给定范围内的元素初始化
list
,比如list<int> l2(l1.begin(), l1.end());
是从已有list
的一部分生成一个新的list
。 -
拷贝构造:通过复制另一个
list
的内容来初始化当前list
,即list<int> l3(l2);
。 -
初始化列表:C++11引入了初始化列表语法,可以直接用大括号包围一系列初始值,如
list<int> l = {1, 2, 3};
。
数据存取功能
-
迭代器:
list
提供的迭代器仅支持前移(++
)和后退(--
),不允许跳跃式前进,也不支持算术运算符(如+
,-
)。此外,list
还拥有特殊的成员函数如front()
和back()
用于获取第一个和最后一个元素。 -
反转与排序:
list
具备内置的方法来进行反转(reverse()
)和排序(sort()
),它们会按照一定规则重新排列内部元素顺序。
代码的解释
1. 包含头文件与命名空间声明
#include <iostream>
#include <string>
#include <list>
using namespace std;
这里包含了三个必要的头文件:<iostream>
用于输入输出流操作,<string>
虽然在这个例子中没有直接用到字符串类,但通常是为了完整性而包含的,<list>
则是为了使用std::list
容器。此外,通过using namespace std;
语句,我们避免了每次调用标准库成员时都需要加上std::
前缀
2. 定义打印函数
void printlist(const list<int>& l) {for (list<int>::const_iterator it = l.begin(); it != l.end(); ++it) {cout << *it << " ";}cout << endl;
}
此函数接收一个常量引用参数l
,表示要打印的list<int>
对象。它遍历整个列表,将每个元素输出到控制台,之后换行。注意这里使用了const_iterator
迭代器,确保不会修改列表内容
3. 测试函数 test01()
void test01() {list<int> l1;l1.push_back(10);l1.push_back(20);l1.push_back(30);l1.push_back(40);l1.push_back(50);printlist(l1);list<int> l2(l1.begin(), l1.end());printlist(l2);list<int> l3(l2);printlist(l3);list<int> l4(10, 100);printlist(l4);
}
- 创建了一个空的
list<int>
实例l1
,然后向其中添加了五个整数值。 - 调用了
printlist()
函数显示l1
的内容。 - 使用区间构造法从
l1
复制所有元素到新的list<int>
实例l2
,并再次调用printlist()
显示结果。 - 通过拷贝构造函数创建另一个
list<int>
实例l3
,它是l2
的一个副本。 - 最后,通过指定大小和初始值的方式创建了含有十个相同元素(均为100)的新列表
l4
,同样调用了printlist()
进行输出。
4. 测试函数 test02()
void test02() {list<int> l1;l1.push_back(10);l1.push_back(20);l1.push_back(30);l1.push_back(40);list<int>::iterator it = l1.begin();it++;it--;
}
这个测试函数主要是用来演示迭代器的基本操作。首先创建了一个包含四个元素的list<int>
实例l1
。接着获取了指向第一个元素的迭代器it
,并通过自增(++
)和自减(--
)操作展示了如何在双向链表上前后移动迭代器的位置。需要注意的是,由于list
是双向链表结构,所以它的迭代器支持前后双向迭代
5. 测试函数 test03()
void test03() {list<int> l1;l1.push_back(10);l1.push_back(50);l1.push_back(20);l1.push_back(15);l1.push_back(70);l1.push_back(90);printlist(l1);l1.reverse();printlist(l1);l1.sort();printlist(l1);
}
- 构建了一个包含六个不同整数值的
list<int>
实例l1
。 - 使用
printlist()
函数打印原始顺序下的列表内容。 - 调用了
reverse()
成员函数反转列表内元素的顺序,并再次打印。 - 接着调用了
sort()
成员函数对列表内的元素进行了排序,并最终打印排序后的结果。
6. 主函数 main()
int main() {test03();system("pause");return 0;
}
主函数仅调用了test03()
以执行上述一系列操作,并且通过system("pause")
命令暂停程序,以便用户可以查看输出信息。这种方法并不推荐用于实际项目中,因为它依赖于特定平台的支持