文章目录
- 介绍
- 使用
-
- [List 的构造函数](#List 的构造函数)
- [List 的迭代器](#List 的迭代器)
- [List capacity](#List capacity)
- [List element access](#List element access)
- [List modifiers](#List modifiers)
- List的模拟实现
介绍
List
是 C++ 标准模板库(STL)中的一个双向链表容器,它提供了高效的插入和删除操作,特别适合需要频繁在序列中间进行修改的场景。
基本概念和特性
数据结构
List
实现为一个双向链表,其中每个节点包含:
- 数据值
- 指向前一个节点的指针
- 指向后一个节点的指针
主要特性
- 双向遍历:可以从头到尾或从尾到头遍历
- 动态大小:大小可根据需要自动增长或缩小
- 非连续存储:元素存储在内存的不同位置
- 无随机访问 :不能使用下标运算符
[]
直接访问元素 - 稳定的迭代器:插入和删除操作不会使其他元素的迭代器失效(除非删除的是该迭代器指向的元素)
使用
以下是常用的接口函数
List 的构造函数
构造函数 | 说明 |
---|---|
list (size_type n, const value_type& val = value_type()) | 构造的list中包含n个值为val的元素 |
list() | 构造空的list |
list (const list& x) | 拷贝构造函数 |
list (InputIterator first, InputIterator last) | 用[first, last) 区间中的元素构造 |
cpp
#include <iostream>
#include <list>
using namespace std;
int main() {
// 默认构造函数 - 构造空的list
list<int> list1;
// 包含n个相同元素的list
list<int> list2(5, 100); // 5个值为100的元素
// 拷贝构造函数
list<int> list3(list2);
// 使用迭代器范围构造
int arr[] = {1, 2, 3, 4, 5};
list<int> list4(arr, arr + 5);
// 使用初始化列表构造
list<int> list5 = {10, 20, 30, 40, 50};
cout << "list2: ";
for (auto it = list2.begin(); it != list2.end(); ++it) {
cout << *it << " ";
}
cout << endl;
cout << "list4: ";
for (auto num : list4) {
cout << num << " ";
}
cout << endl;
return 0;
}

List 的迭代器
将迭代器理解成一个指针,该指针指向list中的某个节点。
函数声明 | 接口说明 |
---|---|
begin+end | 返回第一个元素的迭代器+返回最后一个元素下一个位置的迭代器 |
rbegin+rend | 返回第一个元素的reverse_iterator ,即end 位置,放回最后一个下标位置的reverse_iterator ,即begin 位置 |
cpp
#include <iostream>
#include <list>
using namespace std;
int main() {
list<int> mylist = {1, 2, 3, 4, 5};
// 正向迭代器
cout << "正向遍历: ";
for (auto it = mylist.begin(); it != mylist.end(); ++it) {
cout << *it << " ";
}
cout << endl;
// 反向迭代器
cout << "反向遍历: ";
for (auto rit = mylist.rbegin(); rit != mylist.rend(); ++rit) {
cout << *rit << " ";
}
cout << endl;
// 使用auto关键字简化
cout << "使用auto遍历: ";
for (auto num : mylist) {
cout << num << " ";
}
cout << endl;
return 0;
}

List的迭代失效问题
将迭代器暂时理解成类似于指针,迭代器失效即迭代器所指向的节点的无效,即该节点被删除了。因为list的底层结构为带头结点的双向循环链表,因此在list中进行插入时是不会导致list的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。
cpp
#include <iostream>
#include <list>
using namespace std;
void TestListIterator1()
{
int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
list<int> l(array, array + sizeof(array) / sizeof(array[0]));
auto it = l.begin();
while (it != l.end())
{
// erase()函数执行后,it所指向的节点已被删除,因此it无效,在下一次使用it时,必须先给其赋值
l.erase(it);
++it;
}
}
int main()
{
TestListIterator1();
return 0;
}

cpp
// 改正
void TestListIterator()
{
int array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
list<int> l(array, array + sizeof(array) / sizeof(array[0]));
auto it = l.begin();
while (it != l.end())
{
l.erase(it++); // it = l.erase(it);
}
}
int main()
{
TestListIterator();
return 0;
}

List capacity
函数声明 | 接口说明 |
---|---|
empty | 检测list是否为空,是则返回true,否则返回false |
size | 返回list中有效节点的个数 |
cpp
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<int> list1 = {10, 20, 30, 40, 50};
cout << list1.empty() << endl; // 0
cout << list1.size() << endl; // 5
list<int> list2;
cout << list2.empty() << endl; // 1
cout << list2.size() << endl; // 0
return 0;
}

List element access
函数声明 | 接口说明 |
---|---|
front | 返回List的第一个节点中值的引用 |
back | 返回List的最后一个节点中值的引用 |
cpp
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<int> list1 = {10, 20, 30, 40, 50};
cout << list1.empty() << endl; // 0
cout << list1.size() << endl; // 5
list<int> list2;
cout << list2.empty() << endl; // 1
cout << list2.size() << endl; // 0
cout << list1.front() << endl; // 10
cout << list1.back() << endl; // 50
return 0;
}

List modifiers
函数声明 | 接口说明 |
---|---|
push_front | 在List首元素前插入值为val的元素 |
pop_front | 删除List中的首元素 |
push_back | 在List尾部插入值为val的元素 |
pop_back | 删除List中最后一个元素 |
insert | 在List position 位置中插入值为val的元素 |
erase | 删除List position 位置的元素 |
swap | 交换两个List中的元素 |
clear | 清空List中的有效元素 |
cpp
#include <iostream>
#include <list>
using namespace std;
void printList(const string& name, const list<int>& lst) {
cout << name << ": ";
for (auto num : lst) {
cout << num << " ";
}
cout << endl;
}
int main() {
list<int> mylist;
// push_front 和 push_back
mylist.push_back(30);
mylist.push_front(20);
mylist.push_back(40);
mylist.push_front(10);
mylist.push_back(50);
printList("初始列表", mylist);
// pop_front 和 pop_back
mylist.pop_front();
mylist.pop_back();
printList("删除首尾后", mylist);
// insert 操作
auto it = mylist.begin();
++it; // 指向第二个元素
mylist.insert(it, 25); // 在第二个位置插入25
it = mylist.end();
mylist.insert(it, 3, 100); // 在末尾插入3个100
printList("插入操作后", mylist);
// erase 操作
it = mylist.begin();
++it; // 指向第二个元素
mylist.erase(it); // 删除第二个元素
it = mylist.begin();
auto it2 = it;
advance(it2, 3); // it2指向第4个元素
mylist.erase(it, it2); // 删除[第一个, 第四个)元素
printList("删除操作后", mylist);
// swap 操作
list<int> otherList = {1, 2, 3};
cout << "\n交换前:" << endl;
printList("mylist", mylist);
printList("otherList", otherList);
mylist.swap(otherList);
cout << "交换后:" << endl;
printList("mylist", mylist);
printList("otherList", otherList);
// clear 操作
mylist.clear();
cout << "\n清空mylist后:" << endl;
cout << "mylist大小: " << mylist.size() << endl;
cout << "mylist是否为空: " << (mylist.empty() ? "是" : "否") << endl;
return 0;
}

List的模拟实现
myList.hpp
cpp
#pragma once
#include <assert.h>
#include <iterator>
namespace my
{
// list的结点
template <class T>
struct list_node
{
/* data */
T _data; // 内容
// 指向前后节点的指针
list_node<T> *_next;
list_node<T> *_prev;
// 初始化
list_node(const T &x = T())
: _data(x), _next(nullptr), _prev(nullptr)
{
}
};
// 迭代器类型
// typedef list_iterator<T, T&, T*> iterator;
// typedef list_iterator<T, const T&, const T*> const_iterator;
template <class T, class Ref, class Ptr>
struct list_iterator
{
/* data */
typedef list_node<T> Node;
typedef list_iterator<T, Ref, Ptr> Self;
Node *_node;
// iterator traits
typedef std::bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef ptrdiff_t difference_type;
list_iterator()
: _node(nullptr)
{
}
list_iterator(Node *node)
: _node(node)
{
}
Ref operator*() const // Ref是T&或const T&
{
return _node->_data; // 根据Ref类型返回可写/只读引用
}
Ptr operator->() const // Ptr是T*或const T*
{
return &_node->_data; // 用于访问成员:it->method()
}
// 前置++
Self &operator++()
{
_node = _node->_next;
return *this;
}
// 前置--
Self &operator--()
{
_node = _node->_prev;
return *this;
}
// 后置++
Self operator++(int)
{
Self tmp(*this);
_node = _node->_next;
return tmp;
}
// 后置--
Self operator--(int)
{
Self tmp(*this);
_node = _node->_prev;
return tmp;
}
bool operator!=(const Self &s) const
{
return _node != s._node;
}
bool operator==(const Self &s) const
{
return _node == s._node;
}
};
template <class T>
class list
{
typedef list_node<T> Node;
public:
typedef list_iterator<T, T &, T *> iterator;
typedef list_iterator<T, const T &, const T *> const_iterator;
iterator begin()
{
return iterator(_head->_next);
}
iterator end()
{
return iterator(_head);
}
const_iterator begin() const
{
return const_iterator(_head->_next);
}
const_iterator end() const
{
return const_iterator(_head);
}
// 插入首元素
void push_front(const T &x)
{
insert(begin(), x);
}
// 删除尾元素
void pop_front()
{
erase(begin());
}
// 初始化
void empty_init()
{
_head = new Node();
_head->_next = _head;
_head->_prev = _head;
_size = 0;
}
// 构造
list()
{
empty_init();
}
// 指定位置插入
iterator insert(iterator pos, const T &val)
{
Node *cur = pos._node;
Node *newnode = new Node(val);
Node *prev = cur->_prev;
// prev newnode cur
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = cur;
cur->_prev = newnode;
++_size;
return iterator(newnode);
}
// 尾插
void push_back(const T &x)
{
insert(end(), x);
}
// 构造
list(size_t n, const T &val = T())
{
empty_init();
for (size_t i = 0; i < n; i++)
{
push_back(val);
}
}
// 初始化列表构造
list(std::initializer_list<T> il)
{
empty_init();
for (auto &e : il)
{
push_back(e);
}
}
// 拷贝构造
list(const list<T> <)
{
empty_init();
for (auto &e : lt)
{
push_back(e);
}
}
// 指定位置删除
iterator erase(iterator pos)
{
assert(pos != end());
Node *del = pos._node;
Node *prev = del->_prev;
Node *next = del->_next;
prev->_next = next;
next->_prev = prev;
delete del;
--_size;
return iterator(next);
}
// 清空
void clear()
{
auto it = begin();
while (it != end())
{
it = erase(it);
}
}
// 析构
~list()
{
clear();
delete _head;
_head = nullptr;
}
// 尾删
void pop_back()
{
erase(--end());
}
// 交换
void swap(list<T> &tmp)
{
std::swap(_head, tmp._head);
std::swap(_size, tmp._size);
}
// 运算符重载
list<T> &operator=(list<T> lt)
{
swap(lt);
return *this;
}
// 返回大小
size_t size() const
{
return _size;
}
// 判断是否为空
bool empty() const
{
return _size == 0;
}
// 返回首元素
T &front()
{
assert(!empty());
return _head->_next->_data;
}
// const overload
const T &front() const
{
assert(!empty());
return _head->_next->_data;
}
// 返回尾元素
T &back()
{
assert(!empty());
return _head->_prev->_data;
}
// const overload
const T &back() const
{
assert(!empty());
return _head->_prev->_data;
}
private:
Node *_head;
size_t _size;
};
template <class T>
void swap(T &a, T &b)
{
T c(a);
a = b;
b = c;
}
template <class T>
void swap(list<T> &a, list<T> &b)
{
a.swap(b);
}
} // namespace my
main.cpp
cpp
#include <iostream>
#include <string>
#include <cassert>
#include <vector>
#include <algorithm>
#include "myList.hpp" // 包含你的list头文件
using namespace std;
using namespace my;
// Person moved to file scope so operator<< can be a non-local friend
struct Person {
std::string name;
int age;
Person(std::string n = "", int a = 0) : name(n), age(a) {}
bool operator==(const Person& other) const {
return name == other.name && age == other.age;
}
};
// stream output for Person
static inline std::ostream& operator<<(std::ostream& os, const Person& p) {
os << p.name << "(" << p.age << ")";
return os;
}
// 打印list内容的辅助函数
template<class T>
void print_list(const string& name, const list<T>& lst) {
cout << name << ": ";
for (auto& val : lst) {
cout << val << " ";
}
cout << " | size: " << lst.size() << endl;
}
// 测试基本构造和析构
void test_constructor_destructor() {
cout << "=== 测试构造函数和析构函数 ===" << endl;
// 默认构造
list<int> lst1;
assert(lst1.size() == 0);
assert(lst1.empty());
print_list("默认构造", lst1);
// 指定大小和初始值构造
list<int> lst2(5, 100);
assert(lst2.size() == 5);
print_list("5个100", lst2);
// 初始化列表构造
list<int> lst3 = {1, 2, 3, 4, 5};
assert(lst3.size() == 5);
print_list("初始化列表构造", lst3);
// 拷贝构造
list<int> lst4(lst3);
assert(lst4.size() == 5);
print_list("拷贝构造", lst4);
cout << "测试通过!" << endl << endl;
}
// 测试迭代器功能
void test_iterator() {
cout << "=== 测试迭代器 ===" << endl;
list<int> lst = {1, 2, 3, 4, 5};
// 正向迭代
cout << "正向遍历: ";
for (auto it = lst.begin(); it != lst.end(); ++it) {
cout << *it << " ";
}
cout << endl;
// 范围for循环
cout << "范围for: ";
for (auto val : lst) {
cout << val << " ";
}
cout << endl;
// 修改元素
auto it = lst.begin();
*it = 100;
assert(*lst.begin() == 100);
cout << "修改第一个元素后: " << *lst.begin() << endl;
// 测试迭代器算术运算
it = lst.begin();
++it;
assert(*it == 2);
it--;
assert(*it == 100);
cout << "测试通过!" << endl << endl;
}
// 测试插入操作
void test_insert() {
cout << "=== 测试插入操作 ===" << endl;
list<int> lst;
// 尾插
lst.push_back(1);
lst.push_back(2);
lst.push_back(3);
assert(lst.size() == 3);
assert(lst.back() == 3);
print_list("尾插3个元素", lst);
// 头插
lst.push_front(0);
lst.push_front(-1);
assert(lst.size() == 5);
assert(lst.front() == -1);
print_list("头插2个元素", lst);
// 指定位置插入
auto it = lst.begin();
++it; // 指向第二个元素
lst.insert(it, 999);
assert(lst.size() == 6);
print_list("在第二个位置插入999", lst);
cout << "测试通过!" << endl << endl;
}
// 测试删除操作
void test_erase() {
cout << "=== 测试删除操作 ===" << endl;
list<int> lst = {1, 2, 3, 4, 5, 6};
assert(lst.size() == 6);
print_list("初始列表", lst);
// 尾删
lst.pop_back();
assert(lst.size() == 5);
assert(lst.back() == 5);
print_list("尾删后", lst);
// 头删
lst.pop_front();
assert(lst.size() == 4);
assert(lst.front() == 2);
print_list("头删后", lst);
// 指定位置删除
auto it = lst.begin();
++it; // 指向第二个元素
lst.erase(it);
assert(lst.size() == 3);
print_list("删除第二个元素后", lst);
// 连续删除
it = lst.begin();
while (it != lst.end()) {
if (*it % 2 == 0) { // 删除偶数
it = lst.erase(it);
} else {
++it;
}
}
print_list("删除所有偶数后", lst);
cout << "测试通过!" << endl << endl;
}
// 测试容量相关函数
void test_capacity() {
cout << "=== 测试容量相关 ===" << endl;
list<int> lst;
assert(lst.empty());
assert(lst.size() == 0);
cout << "空列表 - empty: " << (lst.empty() ? "true" : "false") << endl;
lst.push_back(1);
lst.push_back(2);
lst.push_back(3);
assert(!lst.empty());
assert(lst.size() == 3);
cout << "添加元素后 - empty: " << (lst.empty() ? "true" : "false") << endl;
cout << "size: " << lst.size() << endl;
lst.clear();
assert(lst.empty());
assert(lst.size() == 0);
cout << "清空后 - empty: " << (lst.empty() ? "true" : "false") << endl;
cout << "size: " << lst.size() << endl;
cout << "测试通过!" << endl << endl;
}
// 测试元素访问
void test_element_access() {
cout << "=== 测试元素访问 ===" << endl;
list<int> lst = {10, 20, 30, 40, 50};
assert(lst.front() == 10);
assert(lst.back() == 50);
cout << "front: " << lst.front() << endl;
cout << "back: " << lst.back() << endl;
// 修改首尾元素
lst.front() = 100;
lst.back() = 500;
assert(lst.front() == 100);
assert(lst.back() == 500);
cout << "修改后 - front: " << lst.front() << endl;
cout << "修改后 - back: " << lst.back() << endl;
print_list("最终列表", lst);
cout << "测试通过!" << endl << endl;
}
// 测试赋值操作
void test_assignment() {
cout << "=== 测试赋值操作 ===" << endl;
list<int> lst1 = {1, 2, 3};
list<int> lst2 = {4, 5, 6, 7};
print_list("赋值前 lst1", lst1);
print_list("赋值前 lst2", lst2);
lst1 = lst2; // 赋值操作
assert(lst1.size() == 4);
assert(lst2.size() == 4);
print_list("赋值后 lst1", lst1);
print_list("赋值后 lst2", lst2);
// 自赋值测试
lst1 = lst1;
assert(lst1.size() == 4);
print_list("自赋值后 lst1", lst1);
cout << "测试通过!" << endl << endl;
}
// 测试交换操作
void test_swap() {
cout << "=== 测试交换操作 ===" << endl;
list<int> lst1 = {1, 2, 3};
list<int> lst2 = {4, 5, 6, 7, 8};
assert(lst1.size() == 3);
assert(lst2.size() == 5);
print_list("交换前 lst1", lst1);
print_list("交换前 lst2", lst2);
lst1.swap(lst2);
assert(lst1.size() == 5);
assert(lst2.size() == 3);
print_list("交换后 lst1", lst1);
print_list("交换后 lst2", lst2);
// 使用全局swap函数
swap(lst1, lst2);
assert(lst1.size() == 3);
assert(lst2.size() == 5);
print_list("再次交换后 lst1", lst1);
print_list("再次交换后 lst2", lst2);
cout << "测试通过!" << endl << endl;
}
void test_complex_type() {
// use file-scope Person and operator<<
list<Person> people;
people.push_back(Person("Alice", 25));
people.push_back(Person("Bob", 30));
people.push_back(Person("Charlie", 35));
assert(people.size() == 3);
cout << "人员列表: ";
for (auto& p : people) {
cout << p << " ";
}
cout << endl;
// 使用->操作符访问成员
auto it = people.begin();
assert(it->name == "Alice");
assert(it->age == 25);
cout << "第一个人: " << it->name << ", 年龄: " << it->age << endl;
cout << "测试通过!" << endl << endl;
}
// 测试边界情况
void test_edge_cases() {
cout << "=== 测试边界情况 ===" << endl;
// 空列表操作
list<int> empty_list;
assert(empty_list.size() == 0);
assert(empty_list.empty());
cout << "空列表size: " << empty_list.size() << endl;
cout << "空列表empty: " << (empty_list.empty() ? "true" : "false") << endl;
// 单元素列表
list<int> single_list;
single_list.push_back(42);
assert(single_list.size() == 1);
assert(single_list.front() == 42);
assert(single_list.back() == 42);
cout << "单元素front: " << single_list.front() << endl;
cout << "单元素back: " << single_list.back() << endl;
single_list.pop_front();
assert(single_list.size() == 0);
assert(single_list.empty());
cout << "删除后size: " << single_list.size() << endl;
// 大量数据测试
list<int> large_list;
for (int i = 0; i < 1000; ++i) {
large_list.push_back(i);
}
assert(large_list.size() == 1000);
assert(large_list.front() == 0);
assert(large_list.back() == 999);
cout << "1000个元素size: " << large_list.size() << endl;
// 测试空列表删除(应该断言失败)
// list<int> empty;
// empty.pop_front(); // 应该触发assert
cout << "边界测试通过!" << endl << endl;
}
// 性能测试
void test_performance() {
cout << "=== 性能测试 ===" << endl;
const int TEST_SIZE = 10000;
list<int> perf_list;
// 测试尾插性能
for (int i = 0; i < TEST_SIZE; ++i) {
perf_list.push_back(i);
}
assert(perf_list.size() == TEST_SIZE);
cout << "尾插" << TEST_SIZE << "个元素完成" << endl;
// 测试头插性能
for (int i = 0; i < 1000; ++i) {
perf_list.push_front(i);
}
assert(perf_list.size() == TEST_SIZE + 1000);
cout << "头插1000个元素完成" << endl;
// 测试遍历性能
int sum = 0;
for (auto val : perf_list) {
sum += val;
}
cout << "遍历" << perf_list.size() << "个元素完成,总和: " << sum << endl;
// 测试中间插入性能
auto it = perf_list.begin();
for (int i = 0; i < 100; ++i) {
perf_list.insert(it, i);
}
assert(perf_list.size() == TEST_SIZE + 1000 + 100);
cout << "中间插入100个元素完成" << endl;
cout << "性能测试通过!" << endl << endl;
}
// 测试const迭代器
void test_const_iterator() {
cout << "=== 测试const迭代器 ===" << endl;
list<int> lst = {1, 2, 3, 4, 5};
const list<int>& const_lst = lst;
cout << "const遍历: ";
for (auto it = const_lst.begin(); it != const_lst.end(); ++it) {
cout << *it << " ";
// *it = 10; // 这行应该编译错误!
}
cout << endl;
// 测试const版本的front/back
assert(const_lst.front() == 1);
assert(const_lst.back() == 5);
cout << "const front: " << const_lst.front() << endl;
cout << "const back: " << const_lst.back() << endl;
cout << "const迭代器测试通过!" << endl << endl;
}
// 测试STL算法兼容性
void test_stl_compatibility() {
cout << "=== 测试STL算法兼容性 ===" << endl;
list<int> lst = {5, 3, 1, 4, 2};
// 使用std::find
auto it = std::find(lst.begin(), lst.end(), 3);
assert(it != lst.end());
assert(*it == 3);
cout << "找到元素: " << *it << endl;
// 使用std::count
int count = std::count(lst.begin(), lst.end(), 4);
assert(count == 1);
cout << "元素4出现次数: " << count << endl;
// 使用std::for_each
cout << "for_each遍历: ";
std::for_each(lst.begin(), lst.end(), [](int x) {
cout << x << " ";
});
cout << endl;
cout << "STL兼容性测试通过!" << endl << endl;
}
// 主测试函数
int main() {
cout << "开始测试my::list实现..." << endl;
cout << "================================" << endl;
try {
test_constructor_destructor();
test_iterator();
test_insert();
test_erase();
test_capacity();
test_element_access();
test_assignment();
test_swap();
test_complex_type();
test_edge_cases();
test_performance();
test_const_iterator();
test_stl_compatibility();
cout << "================================" << endl;
cout << "🎉 所有测试通过!my::list实现正确!" << endl;
cout << "✅ 实现了所有基本功能" << endl;
cout << "✅ 迭代器工作正常" << endl;
cout << "✅ 内存管理正确" << endl;
cout << "✅ 边界情况处理得当" << endl;
cout << "✅ 与STL算法兼容" << endl;
} catch (const exception& e) {
cout << "❌ 测试失败,异常: " << e.what() << endl;
return 1;
} catch (...) {
cout << "❌ 测试失败,未知异常" << endl;
return 1;
}
return 0;
}
