C++ - List
文章目录
- 介绍
- 基本概念和特性
- 数据结构
- 主要特性
- 使用
- List 的构造函数
- List 的迭代器
- List的迭代失效问题
- List capacity
- List element access
- List modifiers
- List的模拟实现
- myList.hpp
- main.cpp
介绍
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) 区间中的元素构造 |
#include <iostream>
#include <list>
using namespace std;int main() {// 默认构造函数 - 构造空的listlist<int> list1;// 包含n个相同元素的listlist<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 位置 |
#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的迭代器失效的,只有在删除时才会失效,并且失效的只是指向被删除节点的迭代器,其他迭代器不会受到影响。
#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;
}
// 改正
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中有效节点的个数 |
#include <iostream>
#include <list>
using namespace std;int main()
{list<int> list1 = {10, 20, 30, 40, 50};cout << list1.empty() << endl; // 0cout << list1.size() << endl; // 5list<int> list2;cout << list2.empty() << endl; // 1cout << list2.size() << endl; // 0return 0;
}
List element access
函数声明 | 接口说明 |
---|---|
front | 返回List的第一个节点中值的引用 |
back | 返回List的最后一个节点中值的引用 |
#include <iostream>
#include <list>
using namespace std;int main()
{list<int> list1 = {10, 20, 30, 40, 50};cout << list1.empty() << endl; // 0cout << list1.size() << endl; // 5list<int> list2;cout << list2.empty() << endl; // 1cout << list2.size() << endl; // 0cout << list1.front() << endl; // 10cout << list1.back() << endl; // 50return 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中的有效元素 |
#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_backmylist.push_back(30);mylist.push_front(20);mylist.push_back(40);mylist.push_front(10);mylist.push_back(50);printList("初始列表", mylist);// pop_front 和 pop_backmylist.pop_front();mylist.pop_back();printList("删除首尾后", mylist);// insert 操作auto it = mylist.begin();++it; // 指向第二个元素mylist.insert(it, 25); // 在第二个位置插入25it = mylist.end();mylist.insert(it, 3, 100); // 在末尾插入3个100printList("插入操作后", 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
#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 traitstypedef 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 curprev->_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 overloadconst T &front() const{assert(!empty());return _head->_next->_data;}// 返回尾元素T &back(){assert(!empty());return _head->_prev->_data;}// const overloadconst 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
#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(); // 应该触发assertcout << "边界测试通过!" << 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/backassert(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::findauto it = std::find(lst.begin(), lst.end(), 3);assert(it != lst.end());assert(*it == 3);cout << "找到元素: " << *it << endl;// 使用std::countint count = std::count(lst.begin(), lst.end(), 4);assert(count == 1);cout << "元素4出现次数: " << count << endl;// 使用std::for_eachcout << "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;
}