常用容器
7 list容器
7.1 list 容器基本概念
功能:将数据进行链式存储
定义:
list(链表)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的
链表的组成:
链表由一系列节点组成。
节点的组成:
一个是存储数据元素的数据域,另一个是存储下一个阶段地址的指针域
STL中的列表是一个双向循环列表
链表优点:
(1)采用动态存储分配,不会造成内存浪费和溢出
(2)链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
链表缺点:
链表灵活,但是空间(指针域)和时间(遍历)额外耗费大。容器遍历速度没有数组快(地址连续),并且占用的空间比数组大。
STL中的链表是一个双向循环列表:
由于链表的存储放射式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器
list有一个重要的性质,插入和删除操作都不会造成原有list迭代器的失效,这在vector中是不成立的。
总结:STL中list和vector是两个最常用的容器,各有优缺点。
7.2 list 构造函数
功能:创建list容器
函数原型:
(1)list< T > lit;——list采用模板类实现,默认构造函数
(2)list (beg,end);——构造函数将[beg,end}区间中的元素拷贝给本身
(3)list(n,elem);——构造函数将n个elem拷贝给本身
(4)list(const list &lst);——拷贝构造函数
#include <iostream>
using namespace std;
//包含容器头文件
# include<list>
void printList(const list<int>& l)
{
for (list<int>::const_iterator it = l.begin(); it != l.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
//1.默认构造函数构造:list< T > lit;
list<int> l;
l.push_back(10);
l.push_back(21);
l.push_back(14);
l.push_back(23);
printList(l);
//2.按照区间的方式进行构造:list (beg,end);
list<int>l2(l.begin(), l.end());
printList(l2);
//3.n个elem方式
list<int>l3(6, 24);
printList(l3);
//4.拷贝构造函数
list<int> l5(l);
printList(l5);
}
int main()
{
test01();
}
总结:list构造方式同其它几个STL常用容器类似,熟练掌握即可
7.3 list 赋值和交换
功能描述:给list容器进行
(1)赋值(=或l.assign())
(2)交换list容器(l.swap())
函数原型:
(1)l.assign(beg,end);——将[beg,end}区间中的元素赋值给本身
(2)list &operator= (const list&lst);——重载=运算符
(3)l.assign(n,elem);——将n个elem拷贝给本身
(4)l.swap(lst)——交换两个容器
#include <iostream>
using namespace std;
//包含容器头文件
# include<list>
void printList(const list<int>& l)
{
for (list<int>::const_iterator it = l.begin(); it != l.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
list<int> l;
l.push_back(10);
l.push_back(21);
l.push_back(14);
l.push_back(23);
printList(l);
//1.将[beg,end}区间中的元素赋值给本身:l.assign(beg,end);
list<int>l2;
l2.assign(l.begin(), l.end());
printList(l2);
//2.n个elem方式:l.assign(n,elem)
list<int>l3;
l3.assign(5, 44);
printList(l3);
//3.重载=运算符的方式:
list<int> l5=l;
printList(l5);
//4.两个容器互换:l.swap(lst);
list<int>l6;
l6.assign(10, 100);
cout << "交换前两个容器!" << endl;
printList(l6);
printList(l);
cout << "交换后两个容器!" << endl;
l6.swap(l);
printList(l6);
printList(l);
}
int main()
{
test01();
}
7.4 list 大小操作
功能描述:对容器大小进行操作
函数原型:
(1)l.empty();——判断容器是否为空
(2)l.size();——返回容器中元素个数
(3)l.resize(int num);——重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则超出容器长度的元素被删除
(5)l.resize(int num,elem);——重新指定容器的长度为num,若容器的长度变长,则以elem值填充新位置,如果容器变短则超出容器长度的原始将会被删除
#include <iostream>
using namespace std;
//包含容器头文件
# include<list>
void printList(const list<int>& l)
{
for (list<int>::const_iterator it = l.begin(); it != l.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
list<int> l;
l.push_back(10);
l.push_back(21);
l.push_back(14);
l.push_back(23);
printList(l);
//1.判断容器是否为空:l.empty()
while (!l.empty())
{
cout << "list容器不为空!" << endl;
//2.容器大小:l.size()
cout << "容器大小为:" << l.size() << endl;
//3.重新指定容器大小,若变长,则使用默认值填充,若变短,数据删除:l.resize(int num)
l.resize(6);
printList(l);
//4.重新指定容器大小,若变长,则使用elem值填充,若变短,数据删除:l.resize(int num,elem)
l.resize(4);
printList(l);
l.resize(6, 11);
printList(l);
break;
}
}
int main()
{
test01();
}
7.5 list 插入和删除
功能描述:对list容器
(1)插入(l.insert() )
(2)删除(l.erase())
函数原型:
(1)两端插入操作:
1.l.push_back(elem);——在容器尾部舔加一个数据
2.l.push_front(elem);——在容器头部插入一个数据
3.l.pop_back();——删除容器最后一个数据
4.l.pop_front();——删除容器第一个数据
(2)指定位置操作
1.l.insert(pos,elem);——在pos位置插入一个elem元素的拷贝,返回新数据的位置
2.l.insert(pos,n,elem);——在pos位置插入n个elem数据,无返回值
3.l.insert(pos,beg,end);——在pos位置插入[beg,end)区间的数据,无返回值
4.l.clear();——清空容器中的所有数据
5.l.erase(beg,end);——删除[beg,end)区间的数据,返回下一个数据的位置
6.l.erase(pos);——删除pos位置的数据,返回下一个数据的位置
7.l.remove(elem);——删除容器中所有与elem匹配的元素
上述位置pos,指的是迭代器的位置
#include <iostream>
using namespace std;
//包含容器头文件
# include<list>
void printList(const list<int>& l)
{
for (list<int>::const_iterator it = l.begin(); it != l.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
//(1)两端插入和删除操作
void test01()
{
list<int> l;
//1.在容器尾部舔加一个数据:l.push_back()
l.push_back(10);
l.push_back(21);
//2.在容器头部插入一个数据:l.push_front()
l.push_front(14);
l.push_front(23);
l.push_front(18);
l.push_front(33);
printList(l);
//3.删除容器最后一个数据:l.pop_back()
l.pop_back();
//4.删除容器第一个数据:l.pop_front()
l.pop_front();
printList(l);
}
//(2)内部数据进行插入和删除操作
void test02()
{
cout << "内部数据插入操作------------------》" << endl;
list<int> l;
l.push_back(11);
l.push_back(23);
l.push_front(44);
l.push_front(21);
l.push_front(15);
l.push_front(33);
printList(l);
//(1)插入操作
//1.在pos位置插入一个数据elem:l.insert(pos,elem)
l.insert(l.begin(), 99);
printList(l);
//2.在pos位置插入n个数据elem:l.insert(pos,n,elem)
l.insert(l.begin(),3,12);
printList(l);
//3.在pos位置在pos位置插入[beg,end)区间的数据:l.insert(pos,beg,end);
list<int>l2;
l2.insert(l2.begin(), l.begin(), l.end());
printList(l2);
//(2)删除操作
cout << "内部数据删除操作------------------》" << endl;
printList(l);
//1.删除pos位置的数据:l.erase(pos)
list<int>::iterator it = l.begin();
it++;
l.erase(it);
printList(l);
//2.删除[beg,end)区间的数据:l.erase(beg,end);
l.erase(++l.begin(), --l.end());
printList(l);
//3.清空容器中数据:l.clear()
l.clear();
printList(l);
//4.删除容器中所有与elem匹配的数据:l.remove(elem);
list<int> ll;
ll.push_back(23);
ll.push_back(11);
ll.push_back(23);
ll.push_back(22);
printList(ll);
ll.remove(11);
printList(ll);
}
int main()
{
test01();
test02();
}
7.6 list 数据存取
功能描述:对list容器中的数据进行存取
函数原型:
(1)l.front();——返回容器第一个元素
(2)l.back();——返回容器最后一个元素
list本质是链表,不是用连续线性空间存储数据,迭代器也不支持随机访问,因此不可以用[]或者at来进行访问元素
#include <iostream>
using namespace std;
//包含容器头文件
# include<list>
void printList(const list<int>& l)
{
for (list<int>::const_iterator it = l.begin(); it != l.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
list<int> l;
l.push_back(10);
l.push_back(21);
l.push_front(14);
l.push_front(23);
l.push_front(18);
l.push_front(33);
printList(l);
//1.访问list容器中第一个元素:l.front()
cout << "list容器中第一个元素:" << l.front() << endl;
//2.访问list容器中最后一个元素:l.back()
cout << "list容器中最后一个元素:" << l.back() << endl;
//迭代器不支持随机访问(it+1错误),支持双向访问
list<int>::iterator it = l.begin();
it++;
it--;//支持双向
}
int main()
{
test01();
}
总结:
(1)list不支持[]或at方式访问数据
(2)返回第一个元素front(),返回最后一个元素back()
7.7 list 翻转和排序
功能描述:将容器中的元素翻转(l.reverse()),将容器中的数据进行排序(l.sort())
函数原型:
(1)l.reverse();——容器中元素翻转
(2)l.sort();——容器中元素排序
#include <iostream>
using namespace std;
//包含容器头文件
# include<list>
void printList(const list<int>& l)
{
for (list<int>::const_iterator it = l.begin(); it != l.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
list<int> l;
l.push_back(10);
l.push_back(21);
l.push_front(14);
l.push_front(23);
l.push_front(18);
l.push_front(33);
printList(l);
//1.list容器中数据翻转:l.reverse();
cout << "list数据翻转!" << endl;
l.reverse();
printList(l);
//2.list容器中数据排序:l.sort()
cout << "list数据排序!" << endl;
//sort(l.begin(),l.end());//不可以使用,因为不支持随机访问的迭代器,不能使用标准算法
l.sort();
printList(l);
}
int main()
{
test01();
}
7.8 list排序案例
案例描述:将Person自定义数据类型进行排序,Person中属性有姓名,年龄,身高
排序规则:按照年龄进行升序,如果年龄相同按照身高进行降序
注意:自定义数据类型排序时必须指定排序规则,自己写写回调函数或者仿函数。sort()函数的参数中,填写该回调函数或者仿函数的函数名称。
#include <iostream>
using namespace std;
//包含容器头文件
# include<list>
#include<string>
class Person
{
public:
string m_Name;
int m_Age;
int m_Height;
Person(string name,int age,int height)
{
this->m_Name = name;
this->m_Age = age;
this->m_Height = height;
}
};
//打印容器中数据
void printList(list<Person> &l)
{
for (list<Person>::iterator it = l.begin(); it != l.end(); it++)
{
cout << "姓名:" << (*it).m_Name << " " << "年龄:" << (*it).m_Age << " " << "身高:" << (*it).m_Height << endl;
}
}
//指定排序规则
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 test01()
{
//1.创建list容器
list<Person> l;
//2.准备数据
Person p1("小王", 18, 180);
Person p2("小刘", 19, 176);
Person p3("小赵", 18, 181);
Person p4("小张", 22, 184);
Person p5("小李", 21, 178);
//3.向容器中插入数据
l.push_back(p1);
l.push_back(p2);
l.push_back(p3);
l.push_back(p4);
l.push_back(p5);
//4.打印容器中的数据
printList(l);
//4.按照年龄进行升序
cout << "排序后的效果——————————————————" << endl;
//l.sort();//自定义数据类型排序,必须指定规则,写回调函数或者仿函数
l.sort(comparePerson);//参数为自定义的排序规则
printList(l);
}
int main()
{
test01();
}