C++提高编程 3 STL常用容器 -list容器
3.7 list容器
3.7.1 list基本概念
功能:将数据进行链式存储
链表(list)是一种物理存储单元格上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的;
链表的组成:链表由一系列结点组成;
结点的组成:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域
STL中的链表是一个双向循环链表(下图中的第一个结点的prev其实不指向NULL,而是指向最后一个结点的data;而最后一个结点的next指向第一个结点的data)
PS:单向链表:
缺点:容器遍历速度没有数组快,因为得通过指针查找下一个元素;
占用空间大,因为数据域占4字节,还有指针占4字节;
由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器;
list的优点:
采用动态内存分配,不会造成内存浪费和溢出
链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
list的缺点:
链表灵活,但是空间(指针域)和时间(遍历)额外耗费较大
list有一个重要的性质,插入和删除操作都不会造成原有的list迭代器的失效(在元素中间插删数据并不会因为内存满了而影响前后的数据),这在vector容器中是不成立的(vector容器内存满了以后,要重新找一块更大内存的容器来存储,从而导致之前的迭代器更替);
总结:STL中list和vector是两个最常被使用的容器,各有优缺点
3.7.2 list构造函数
#include<iostream> #include<list> using namespace std; //list容器构造函数 void printList(const list<int>&L) { for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { //创建链表list list<int>L1; //默认构造 //添加元素 L1.push_back(10); L1.push_back(20); L1.push_back(30); L1.push_back(40); //遍历容器 printList(L1); //10 20 30 40 //区间方式构造 list<int>L2(L1.begin(), L1.end()); printList(L2); //10 20 30 40 //拷贝构造 list<int>L3(L2); printList(L3); //10 20 30 40 //n个elem list<int>L4(4, 100); printList(L4); //100 100 100 100 }; int main() { test1(); system("pause"); return 0; }
3.7.3 list赋值和交换
功能描述:
给list容器进行赋值,以及交换list容器
#include<iostream> #include<list> using namespace std; //list容器赋值和交换 void printList(const list<int>&L) { for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) { cout << *it << " "; } cout << endl; } //赋值 void test1() { //创建链表list list<int>L1; L1.push_back(10); L1.push_back(20); L1.push_back(30); L1.push_back(40); printList(L1); //10 20 30 40 list<int>L2; L2 = L1; //operator=赋值 printList(L2); //10 20 30 40 list<int>L3; L3.assign(L2.begin(), L2.end()); printList(L3); //10 20 30 40 list<int>L4; L4.assign(10, 100); printList(L4); //100 100 100 100 100 100 100 100 100 100 }; //交换 void test2() { list<int>L1; L1.push_back(10); L1.push_back(20); L1.push_back(30); L1.push_back(40); list<int>L2; L2.assign(10, 100); cout << "交换前:" << endl; printList(L1); //10 20 30 40 printList(L2); //100 100 100 100 100 100 100 100 100 100 L1.swap(L2); cout << "交换后:" << endl; printList(L1); //100 100 100 100 100 100 100 100 100 100 printList(L2); //10 20 30 40 } int main() { //test1(); test2(); system("pause"); return 0; }
3.7.4 list大小操作
#include<iostream> #include<list> using namespace std; //list容器大小操作 void printList(const list<int>&L) { for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) { cout << *it << " "; } cout << endl; } //赋值 void test1() { //创建链表list list<int>L1; L1.push_back(10); L1.push_back(20); L1.push_back(30); L1.push_back(40); printList(L1); //10 20 30 40 //判断容器是否为空 if (L1.empty()) { cout << "L1为空" << endl; } else { cout << "L1不为空" << endl; cout << "L的元素个数为:" << L1.size() << endl; } //重新指定大小 L1.resize(6); printList(L1); //10 20 30 40 0 0 L1.resize(10, 1000); printList(L1); //10 20 30 40 0 0 1000 1000 1000 1000 L1.resize(2); printList(L1); //10 20 }; int main() { test1(); system("pause"); return 0; }
3.7.5 list插入与删除
对list容器进行数据的插入与删除
#include<iostream> #include<list> using namespace std; //list插入与删除 void printList(const list<int>&L) { for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { list<int>L; //尾插 L.push_back(10); L.push_back(20); L.push_back(30); //头插 L.push_front(100); L.push_front(200); L.push_front(300); printList(L); //300 200 100 10 20 30 //尾删 L.pop_back(); printList(L); //300 200 100 10 20 //头删 L.pop_front(); printList(L); //200 100 10 20 //insert插入 //L.insert(L.begin(), 1000); //printList(L); //1000 200 100 10 20 list<int>::iterator it = L.begin(); L.insert(++it, 1000); printList(L); //200 1000 100 10 20 //删除 it = L.begin(); //200 1000 100 10 20 //L.erase(it); //printList(L); //1000 100 10 20 L.erase(++it); printList(L); //200 100 10 20 //移除 L.push_back(10000); L.push_back(10000); L.push_back(10000); printList(L); //200 100 10 20 10000 10000 10000 L.remove(10000); printList(L); //200 100 10 20 L.clear(); printList(L); //空白 }; int main() { test1(); system("pause"); return 0; }
3.7.6 list数据存取
函数原型:
front(); //返回第一个元素
back(); //返回最后一个元素
#include<iostream> #include<list> using namespace std; //list数据存取void test1() { list<int>L1; L1.push_back(10); L1.push_back(20); L1.push_back(30); L1.push_back(40); //L1[0]; // 不可以用[]访问list容器中的元素 //L1.at(0); // 不可以用at方式访list容器中的元素 //原因是list本质链表,不是用连续连续线性空间存储数据,迭代器也是不支持随机访问的 cout << "第一个元素是:" << L1.front() << endl; //10 cout << "最后一个元素是:" << L1.back() << endl; //40 //验证迭代器是不支持随机访问的 list<int>::iterator it = L1.begin(); it++; //支持双向 it--; //如果 -- 报错,说明这个迭代器只支持向前走,是单向的 //it = it + 1; //不支持随机访问 因为可以+1的话,也可以+2、+3 迭代器不允许这样的操作 //it = it - 3; }; int main() { test1(); system("pause"); return 0; }
3.7.7 list反转和排序
功能描述:将list容器中的元素反转,以及将容器中的数据进行排序
函数原型:
reverse(); //反转链表
sort(); //链表排序
#include<iostream> #include<list> using namespace std; #include<algorithm> //list数据存取 void printList(const list<int>&L) { for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) { cout << *it << " "; } cout << endl; } void test1() { list<int>L1; L1.push_back(50); L1.push_back(20); L1.push_back(40); L1.push_back(10); L1.push_back(30); cout << "反转前:" << endl; printList(L1); //50 20 40 10 30 //反转 cout << "反转后:" << endl; L1.reverse(); printList(L1); //30 10 40 20 50 }; bool myCompare(int v1, int v2) { //降序 就让第一个数 > 第二个数 return v1 > v2; } //排序: void test2() { list<int>L1; L1.push_back(50); L1.push_back(20); L1.push_back(40); L1.push_back(10); L1.push_back(30); cout << "排序前:" << endl; printList(L1); //50 20 40 10 30 cout << "排序后:" << endl; //sort(L1.begin(), L1.end()); //所有不支持随机访问迭代器的容器,不可以使用标准算法,但内部会提供对应的一些算法 L1.sort(); //默认排序规则 从小到大 升序 printList(L1); //10 20 30 40 50 //反转 //L1.reverse(); //50 40 30 20 10 /way1 L1.sort(myCompare); printList(L1); //50 40 30 20 10 } int main() { //test1(); test2(); system("pause"); return 0; }
3.7.8 排序案例
#include<iostream> #include<list> using namespace std; #include<string> //list案例 class Person { public: Person(string name, int age,int height) { this->m_Name = name; this->m_Age = age; this->m_Height = height; } public: string m_Name; int m_Age; int m_Height; }; //指定排序规则 bool comparePerson(Person& p1, Person& p2) { //按照年龄升序 if (p1.m_Age == p2.m_Age) { //年龄相同 按照身高降序 return p1.m_Height > p2.m_Height; } else { return p1.m_Age < p2.m_Age; } } void test1() { list<Person>L; //创建容器 //准备数据 Person p1("刘备", 35, 160); Person p2("曹操", 42, 170); Person p3("孙权", 39, 180); Person p4("赵云", 26, 179); Person p5("张飞", 35, 175); Person p6("关羽", 36, 183); //插入数据 L.push_back(p1); L.push_back(p2); L.push_back(p3); L.push_back(p4); L.push_back(p5); L.push_back(p6); for (list<Person>::iterator it = L.begin(); it != L.end(); it++) { cout << "姓名:" << (*it).m_Name << "年龄:" << it->m_Age << "身高:" << (*it).m_Height << endl; } //排序 cout << "--------------------------------" << endl; cout << "排序后: " << endl; L.sort(comparePerson); for (list<Person>::iterator it = L.begin(); it != L.end(); it++) { cout << "姓名:" << (*it).m_Name << "年龄:" << it->m_Age << "身高:" << (*it).m_Height << endl; } } int main() { test1(); system("pause"); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)