一、list容器的基本概念
功能:进数据进行链式存储
链表(list)是一种物理存储单元上非连续的存储结构(存储的地址是非连续的),数据元素的逻辑顺序是通过链表中的指针链接来实现
链表的组成:链表由一系列结点组成
节点的组成:一个存储数据元素的数据域,另一个储存下一个结点的指针域
STL中的链表是一个双向循环链表
由于链表的存储方式不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器。
list的优点:
1、采用动态存储分配,不会造成内存浪费和溢出
2、链表实行插入和删除操作十分方便,修改指针即可,不需要移动大量的元素
list的缺点:
1、链表灵活,但是空间(指针域)和时间(遍历)额外耗费较大
list有一个重要性质,插入操作和删除操作不会造成原有list迭代器的失效,这个在vector中不成立的。
二、List构造函数
学习目标:学会创建list容器
函数原型:
list<T> lst; //list采用模板类实例化对象。默认构造形式
list(beg,end); //构造函数将[beg,end)区间的元素拷贝给本身
list(n,elem); //构造函数将n个elem拷贝给本身
list(const list &lst); //拷贝构造函数
示例:
#include "iostream"
#include <list>
using namespace std;
void PrintList02(const list<int> &L)
{
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void testList02() {
//1、创建list容器的对象 默认构造形式
list<int> lst1;
lst1.push_back(10);
lst1.push_back(20);
lst1.push_back(30);
lst1.push_front(40);
//遍历List容器
PrintList02(lst1);
//2、区间拷贝
list<int> l2(lst1.begin(),lst1.end());
PrintList02(l2);
//3.n个elem拷贝
list<int> l3(10, 100);
PrintList02(l3);
//4、拷贝构造函数
list<int> l4(l3);
PrintList02(l4);
}
int main()
{
testList02();
system("pause");
return 0;
}
三、list容器的赋值与交换
学习目标:给list容器进行赋值,以及交换list容器
函数原型:
assign(beg,end); //将某一容器的[beg,end)区间中的数据拷贝赋值给本身
assign(n,elem); //将n个elem拷贝给本身
list& operator=(const list &lst); //重载等号操作符
swap(lst); //将lst与本身互换
示例:
#include "iostream"
#include <list>
using namespace std;
void PrintList03(const list<int> &L)
{
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void testList03()
{
list<int> L1;
L1.push_front(40);
L1.push_front(30);
L1.push_front(20);
L1.push_front(10);
PrintList03(L1);
//1、区间赋值操作
list<int> L2(L1.begin(), L1.end());
PrintList03(L2);
//2、重载等号操作符
list<int> L3;
L3 = L2;
PrintList03(L3);
//3、n个elem赋值
list<int> L4(10, 66);
cout << "L4与L5互换前:" << endl;
PrintList03(L4);
//4、list容器互换
list<int> L5(5,55);
PrintList03(L5);
cout << "L4与L5互换后:" << endl;
L4.swap(L5);
PrintList03(L4);
PrintList03(L5);
}
int main()
{
testList03();
system("pause");
return 0;
}
四、list容器的大小操作
学习目标:对list容器的大小进行操作
函数原型:
size();
empty();
resize(num);
resize(n,elem);
示例:
#include "iostream"
#include <list>
using namespace std;
void PrintList04(const list<int> &L)
{
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void testList04()
{
list<int> L1;
L1.push_front(40);
L1.push_front(30);
L1.push_front(20);
L1.push_front(10);
PrintList04(L1);
//1、resize(elem)
L1.resize(10);
PrintList04(L1);
//2、resize(n,elem)
L1.resize(15, 66);
PrintList04(L1);
//3、判断是否为空
while (!L1.empty())
{
if (!L1.empty())
{
L1.pop_back();
cout << "容器中的元素个数:" << L1.size() << endl;
PrintList04(L1);
}
else
{
cout << "容器为空!" << endl;
}
}
}
int main()
{
testList04();
system("pause");
return 0;
}
五、list容器的插入与删除
学习目标:对list容器进行数据的插入与删除
函数原型:
push_back(elem); //在容器尾部加一个元素
push_front(elem); //在容器头部加一个元素
pop_front(); //删除容器的第一个元素
pop_back(); //删除容器的最后一个元素
insert(pos,elem); //在pos位置插入elem元素的拷贝,返回新数据的位置
insert(pos,n,elem); //在pos位置插入n个elem元素,无返回
insert(pos,beg,end); //在pos位置插入[beg,end)区间的数据,无返回值
clear(); //移除容器中所有元素
erase(beg,end); //删除[beg,end)区间的数据,返回下一个数据的位置
erase(pos); //删除pos位置的数据,返回下一个数据的位置
erase(elem); //删除容器中所有与elem值匹配的数据
示例:
#include "iostream"
#include <list>
using namespace std;
void PrintList05(const list<int> &L)
{
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void listtest05()
{
list<int> L1;
L1.push_back(30);
L1.push_back(40);
L1.push_front(20);
L1.push_front(10);
PrintList05(L1);
//1、insert(pos,elem) pos为迭代器
L1.insert(L1.begin(),1000);
PrintList05(L1);
//2、insert(pos,n,elem) pos为迭代器
L1.insert(L1.begin(), 3, 666);
PrintList05(L1);
list<int>::iterator it = L1.begin();
it++;
list<int>::iterator itend = L1.end();
itend--;
//3、insert(pos,beg,end)
L1.insert(it, it, itend);
PrintList05(L1);
//4、erase(beg,end)
L1.erase(it, itend);
PrintList05(L1);
//5、erase(pos)
list<int>::iterator it1 = L1.begin();
L1.erase(it1);
PrintList05(L1);
//6、remove(elem)
L1.remove(666);
PrintList05(L1);
//clear();
L1.clear();
PrintList05(L1);
}
int main()
{
listtest05();
system("pause");
return 0;
}
六、list数据存取
学习目标:能灵活的对list容器中的数据进行存取操作
注意:list容器不支持随机迭代器,因为链表中数据的存取不是在一段连续的内存空间中。所以不能使用下标[]索引和at方式访问链表中的数据
函数原型:
front(); //返回第一个元素
back(); //返回最后一个元素
示例:
#include "iostream"
#include <list>
using namespace std;
void PrintList28(const list<int> &L)
{
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void listTest28()
{
list<int> L1;
for (int i = 0; i < 5; i++)
{
L1.push_back(i);
}
for (int i = 10; i > 5; i--)
{
L1.push_front(i);
}
PrintList28(L1);
//L1[0]; 代码报错,不支持下标[]方式访问
//L1.at(0); 代码报错,不支持at方式访问
//原因:list本质是链表,不是用连续性的空间存储数据,迭代器也不支持随机访问
list<int>::iterator it = L1.begin();
it++;
it--; //不报错,说明list容器支持双向迭代器
//it=it + 3; 报错,list容器的迭代器不能跳跃式访问,所以不是随机迭代器
cout << "第一个元素为:" << L1.front() << endl;
cout << "最后一个元素为:" << L1.back() << endl;
}
int main()
{
listTest28();
system("pause");
return 0;
}
七、list容器的反转与排序
学习目标:对list容器中的元素进行反转,以及将容器中的数据进行排序
函数原型:
reverse(); //反转链表
sort(); //链表排序
示例:
#include "iostream"
#include <list>
using namespace std;
void PrintList29(const list<int> &L)
{
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
bool MyCompare(int v1, int v2) {
return v1 > v2;
}
void ListTest29()
{
list<int> L1;
for (int i = 10; i > 0; i--)
{
L1.push_back(i);
}
cout << "反转之前:" << endl;
PrintList29(L1);
//1、反转
cout << "反转之后:" << endl;
L1.reverse();
PrintList29(L1);
list<int> L2(L1);
cout << "L2的拷贝构造结果" << endl;
PrintList29(L2);
L2.reverse();
cout << "L2反转:" << endl;
PrintList29(L2);
//2、排序 默认是从小到大 升序
L2.sort();
cout << "L2排序:" << endl;
PrintList29(L2);
//3、所有不支持随机访问迭代器的容器,不可以使用标准算法
//sort(L1.begin(), L1.end());
//L2的降序排列
L2.sort(MyCompare);
cout << "L2使用仿函数降序:" << endl;
PrintList29(L2);
}
int main()
{
ListTest29();
system("pause");
return 0;
}
总结:反转 reverse()
排序 sort(仿函数)
八、list排序案例
案例描述:将person自定义数据类型进行排序,Person中属性有姓名、年龄、身高
排序规则:按照年龄进行升序,如果年龄相同,按照身高进行降序
示例:
#include "iostream"
#include <list>
#include <string>
using namespace std;
class Person
{
public:
Person(string name, int age, int height)
{
this->m_Name = name;
this->m_Age = age;
this->m_Height = height;
}
string m_Name;
int m_Age;
int m_Height;
};
int a = 1;
bool PsCompare(Person &p1, Person &p2)
{
if (a == 1)
{
if (p1.m_Age == p2.m_Age)
{
return p1.m_Height > p2.m_Height;
}
else
{
return p1.m_Age > p2.m_Age;
}
}
else
{
if (p1.m_Age == p2.m_Age)
{
return p1.m_Height < p2.m_Height;
}
else
{
return p1.m_Age < p2.m_Age;
}
}
}
void PrintList30(const list<Person> &P)
{
for (list<Person>::const_iterator it = P.begin(); it != P.end(); it++)
{
cout << "姓名:" << it->m_Name << " " << "年龄:" << it->m_Age << " " << "身高:" << it->m_Height << endl;
}
}
void ListTest30()
{
list<Person> LP;
Person p1("小兰", 20, 170);
Person p2("小红", 20, 160);
Person p3("小明", 12, 164);
Person p4("小花", 23, 180);
Person p5("小绿", 18, 170);
LP.push_back(p1);
LP.push_back(p2);
LP.push_back(p3);
LP.push_back(p4);
LP.push_back(p5);
cout << "排序前:" << endl;
PrintList30(LP);
cout << "降序排序后:" << endl;
LP.sort(PsCompare);
PrintList30(LP);
}
int main()
{
ListTest30();
system("pause");
return 0;
}
总结:对于自定义数据类型,必须指定排序规则,否则编译器不知道该如何排序