list 接口拆解:我踩过的坑,帮你避开
个人主页:小则又沐风个人专栏:数据结构竞赛专栏C语言CLinux座右铭路虽远行则将至事虽难做则必成目录前言构造函数迭代器list capacitylist element accesslist modifiers总结前言在数据结构中我们学习了链表的相关的语法知识,并且我们用了C语言模拟实现了这个数据结构但是我们在C中还是需要来学习一下在C库中的链表是什么样子的,并且我们来模拟实现一下这个结构构造函数首先我们就来了解一下链表的构造函数我们来一个一个看这些构造函数list (size_type n, const value_type val value_type())这个构造函数就是构造出n个节点并且这些节点的数值都是value那么我们来代码演示一下这个构造函数的行为#includeiostream #includelist using namespace std; templateclass T void print(const listT t) { auto it t.begin(); while (it ! t.end()) { cout *it ; it; } } int main() { listintt1(10, 8); print(t1); return 0; }可以看出来这个构造函数的行为就是构造出的n个value的节点并且连接到一起list()这个构造函数就是一个无参构造他的行为就是构造出一个空的链表#includeiostream #includelist #includestring using namespace std; templateclass T void print(const listT t) { auto it t.begin(); while (it ! t.end()) { cout *it ; it; } cout endl; } int main() { listintt1(10, 8); print(t1); liststringt2; print(t2); return 0; }list (const list x)这个就是大名鼎鼎的拷贝构造函数了#includeiostream #includelist #includestring using namespace std; templateclass T void print(const listT t) { auto it t.begin(); while (it ! t.end()) { cout *it ; it; } cout endl; } int main() { listintt1(10, 8); print(t1); liststringt2; print(t2); listintt3(t1); print(t3); return 0; }ist (InputIterator first, InputIterator last)这个就是可以利用其他容器的迭代器来构造#includeiostream #includelist #includestring #includevector using namespace std; templateclass T void print(const listT t) { auto it t.begin(); while (it ! t.end()) { cout *it ; it; } cout endl; } int main() { listintt1(10, 8); print(t1); liststringt2; print(t2); listintt3(t1); print(t3); vectorstringv({ apple,banana,pear }); liststringt4(v.begin(), v.end()); print(t4); return 0; }迭代器在list中的迭代器我们可以这样来理解这个迭代器,他是一个指向一个节点的指针,因为我们知道每个节点是存储着下一个节点的指针的,所以我们的list迭代器是支持加加的,也就是把我们的指向节点的指针进行了修改但是在实际的实现的时候我们的迭代器不仅仅是一个指针了,他是由节点的指针封装的一个类这时候有人问了为什么必须把他封装成一个类呢?我们需要知道的是我们在之前迭代器的使用的时候我们解引用一个迭代器得到的就是这个迭代器的数据了,但是如果我们没有对这个指针进行封装的时候我们解引用得到的就是一个节点我们要想得到数据的话我们还需要进一步的对这个节点的内容进行访问,这样就违背了我们之前的使用的习惯了在之后的迭代器的模拟实现下我将会仔细讲解这个我们来看看这个迭代器是怎么使用的void print(const listT t) { auto it t.begin(); while (it ! t.end()) { cout *it ; it; } cout endl; }在上面的代码中我的print的模板函数就已经使用了迭代器,因为迭代器是真的一个访问容器的好东西list capacity下面就是有关容量的接口了这个非常的简单empty判断这个链表是否为空#includeiostream #includelist #includestring #includevector using namespace std; templateclass T void print(const listT t) { auto it t.begin(); while (it ! t.end()) { cout *it ; it; } cout endl; } int main() { listintt1(10, 8); print(t1); liststringt2; print(t2); listintt3(t1); print(t3); vectorstringv({ apple,banana,pear }); liststringt4(v.begin(), v.end()); print(t4); if (t1.empty()) { cout 空 endl; } else { cout 非空 endl; } return 0; }size就是返回这个链表有多少个数据#includeiostream #includelist #includestring #includevector using namespace std; templateclass T void print(const listT t) { auto it t.begin(); while (it ! t.end()) { cout *it ; it; } cout endl; } int main() { listintt1(10, 8); print(t1); liststringt2; print(t2); listintt3(t1); print(t3); vectorstringv({ apple,banana,pear }); liststringt4(v.begin(), v.end()); print(t4); if (t1.empty()) { cout 空 endl; } else { cout 非空 endl; cout 数据个数为: t1.size() endl; } return 0; }list element accessfront返回的是头节点数据的引用back返回尾节点数据的引用list modifierspush_front在链表的开头插入数据void text1() { listintt1; t1.push_front(3); t1.push_front(2); t1.push_front(1); }pop_front删除头节点的数据void text1() { listintt1; t1.push_front(3); t1.push_front(2); t1.push_front(1); t1.pop_front(); }push_back在链表的尾部进行插入数据void text2() { listintt2; t2.push_back(1); t2.push_back(2); t2.push_back(3); t2.push_back(4); t2.push_back(5); }pop_back删除尾节点void text2() { listintt2; t2.push_back(1); t2.push_back(2); t2.push_back(3); t2.push_back(4); t2.push_back(5); t2.pop_back(); }insert在pos的位置插入数据需要注意的是这个函数的返回值是插入数据的迭代器void text3() { listintt3; t3.insert(t3.begin(), 100); t3.insert(t3.begin(), 100); }erase删除pos位置的节点void text3() { listintt3; t3.insert(t3.begin(), 100); t3.insert(t3.begin(), 100); t3.erase(t3.end()); }这个函数的返回值是删除节点的下一个节点需要注意的是如果我们删除了一个节点但是我们并没有对这个节点的迭代器进行更新的话,我们再去对这个迭代器访问的时候就会造成迭代器失效的问题swap交换两个链表的元素void text4() { listintt1({ 1,2,3 }); listintt2(10, 8); t1.swap(t2); }clear清理掉链表中的有效的数据void text4() { listintt1({ 1,2,3 }); listintt2(10, 8); t1.swap(t2); t1.clear(); }总结本章节聚焦std::list的核心修改接口系统梳理了链表节点增删、替换与重组的各类操作。从基础的头尾插入删除push/pop到迭代器区间操作insert/erase再到链表专属的splice、merge、sort等高级功能完整覆盖了 STL list 容器的修改能力。之后我会模拟实现一下这个链表.谢谢大家的观看!!!