list(链表)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的。链表是由一系列节点组成。节点是由一个存储数据元素的数据域及存储下一个节点地址的指针域组成。STL中的链表是一个双向循环链表,如下图所示:
由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器。
链表优点:
- 采用动态存储分配,不会造成内存浪费和溢出
- 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
链表缺点:
- 空间(指针域)和时间(遍历)额外耗费较大
list容器与vector容器比较:
- list容器可以对任意位置进行快速插入或删除元素
- list插入和删除操作不会造成原有list迭代器的失效,而在vector是不成立的
- list容器遍历速度,没有vector容器快,占用空间比vector容器大
函数原型:
- list
lst; //list采用模板类实现,list对象默认的构造形式 - list(beg, end); //构造函数将[beg, end)区间中的元素拷贝给自身
- list(n, elem); //构造函数将n个elem拷贝给本身
- list(const list& lst); //拷贝构造函数
#include
#include
using namespace std;
void print(const list& lst)
{
for (list::const_iterator it = lst.begin(); it != lst.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
// STL - list - 构造函数
/*函数原型:
1、list lst; //list采用模板类实现,list对象默认的构造形式
2、list(beg, end); //构造函数将[beg, end)区间中的元素拷贝给自身
3、list(n, elem); //构造函数将n个elem拷贝给本身
4、list(const list& lst); //拷贝构造函数
*/
//1、list lst;
list l1;
//赋值
for (int i = 0; i < 5; i++)
{
l1.push_back(i + 1);
}
cout << "l1中元素为:";
print(l1);
//2、list(beg, end);
list l2(l1.begin(), l1.end());
cout << "l2中元素为:";
print(l2);
//3、list(n, elem);
list l3(5, 8);
cout << "l3中元素为:";
print(l3);
//4、list(const list& lst);
list l4(l3);
cout << "l4中元素为:";
print(l4);
system("pause");
return 0;
}
输出结果
l1中元素为:1 2 3 4 5
l2中元素为:1 2 3 4 5
l3中元素为:8 8 8 8 8
l4中元素为:8 8 8 8 8
函数原型:
赋值
- list& operator=(const list& lst); //重载运算符=
- assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身
- assign(n, elem); //将n个elem拷贝赋值给本身
交换
- swap(lst); //将lst与本身的元素互换
#include
#include
using namespace std;
void print(const list& lst)
{
for (list::const_iterator it = lst.begin(); it != lst.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
// STL - list - 赋值和交换
/*函数原型:
赋值
1、list& operator=(const list& lst); //重载运算符=
2、assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身
3、assign(n, elem); //将n个elem拷贝赋值给本身
交换
4、swap(lst); //将lst与本身的元素互换
*/
list l1;
for (int i = 0; i < 5; i++)
{
l1.push_back(i + 1);
}
cout << "l1容器中的元素:";
print(l1);
//1、list& operator=(const list& lst);
list l2;
l2 = l1;
cout << "1、l2容器中的元素:";
print(l2);
//2、assign(beg, end);
list l3;
l3.assign(l1.begin(), l1.end());
cout << "2、l3容器中的元素:";
print(l3);
//3、assign(n, elem);
list l4;
l4.assign(6, 9);
cout << "3、l4容器中的元素:";
print(l4);
//4、swap(lst);
l2.swap(l4);
cout << "4、交换后,l2容器中的元素:";
print(l2);
cout << "4、交换后,l4容器中的元素:";
print(l4);
system("pause");
return 0;
}
输出结果
l1容器中的元素:1 2 3 4 5
1、l2容器中的元素:1 2 3 4 5
2、l3容器中的元素:1 2 3 4 5
3、l4容器中的元素:9 9 9 9 9 9
4、交换后,l2容器中的元素:9 9 9 9 9 9
4、交换后,l4容器中的元素:1 2 3 4 5
函数原型:
- size(); //返回容器中的元素个数
- empty(); //判断容器是否为空
- resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置,若容器变短,则末尾超出容器长度的元素被删除
- resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置,若容器变短,则末尾超出容器长度的元素被删除
#include
#include
using namespace std;
void print(const list& lst)
{
for (list::const_iterator it = lst.begin(); it != lst.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
// STL - list - 大小操作
/*函数原型:
1、size(); //返回容器中的元素个数
2、empty(); //判断容器是否为空
3、resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置,若容器变短,则末尾超出容器长度的元素被删除
4、resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置,若容器变短,则末尾超出容器长度的元素被删除
*/
list l1;
//1、size();
cout << "1、l1容器中元素个数:" << l1.size() << endl;
//2、empty();
if (l1.empty())
{
for (int i = 0; i < 5; i++)
{
l1.push_back(i + 1);
}
cout << "2、l1容器为空时,添加元素:";
print(l1);
}
cout << "1、l1容器中元素个数:" << l1.size() << endl;
//3、resize(num);
l1.resize(8);
cout << "3、容器长度变长后大小:" << l1.size() << ",元素:";
print(l1);
l1.resize(3);
cout << "3、容器长度变短后大小:" << l1.size() << ",元素:";
print(l1);
//4、resize(num, elem);
l1.resize(7, 9);
cout << "4、容器长度变长后大小:" << l1.size() << ",元素:";
print(l1);
l1.resize(5, 10);
cout << "4、容器长度变短后大小:" << l1.size() << ",元素:";
print(l1);
system("pause");
return 0;
}
输出结果
1、l1容器中元素个数:0
2、l1容器为空时,添加元素:1 2 3 4 5
1、l1容器中元素个数:5
3、容器长度变长后大小:8,元素:1 2 3 4 5 0 0 0
3、容器长度变短后大小:3,元素:1 2 3
4、容器长度变长后大小:7,元素:1 2 3 9 9 9 9
4、容器长度变短后大小:5,元素:1 2 3 9 9
1.4、list插入和删除
插入
- push_back(elem); //在容器尾部加入一个元素
- push_front(elem); //在容器头部插入一个元素
- insert(pos, elem); //在pos位置插入elem元素的拷贝,返回新数据的位置
- insert(pos, n, elem); //在pos位置插入n个elem数据,无返回值
- insert(pos, beg, end); //在pos位置插入[beg, end)区间的数据,无返回值
删除
- pop_back(); //删除容器中最后一个元素
- pop_front(); //删除容器中第一个元素
- remove(elem); //删除容器中所有与elem值匹配的元素
- erase(pos); //删除pos位置的数据,返回下一个数据的位置
- erase(beg, end); //删除[beg, end)区间的数据,返回下一个数据的位置
- clear(); //删除容器中所有数据
#include
#include
using namespace std;
void print(const list& lst)
{
for (list::const_iterator it = lst.begin(); it != lst.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
// STL - list - 插入和删除
/*函数原型:
插入
1、push_back(elem); //在容器尾部加入一个元素
2、push_front(elem); //在容器头部插入一个元素
3、insert(pos, elem); //在pos位置插入elem元素的拷贝,返回新数据的位置
4、insert(pos, n, elem); //在pos位置插入n个elem数据,无返回值
5、insert(pos, beg, end);//在pos位置插入[beg, end)区间的数据,无返回值
删除
6、pop_back(); //删除容器中最后一个元素
7、pop_front(); //删除容器中第一个元素
8、remove(elem); //删除容器中所有与elem值匹配的元素
9、erase(pos); //删除pos位置的数据,返回下一个数据的位置
10、erase(beg, end);//删除[beg, end)区间的数据,返回下一个数据的位置
11、clear(); //删除容器中所有数据
*/
list lst;
//1、push_back(elem);
lst.push_back(1);
lst.push_back(2);
cout << "1、lst容器中的元素:";
print(lst);
//2、push_front(elem);
lst.push_front(3);
lst.push_front(4);
cout << "2、lst容器中的元素:";
print(lst);
//3、insert(pos, elem);
lst.insert(lst.begin(), 5);
cout << "3、lst容器中的元素:";
print(lst);
//4、insert(pos, n, elem);
lst.insert(lst.begin(), 3, 9);
cout << "4、lst容器中的元素:";
print(lst);
//5、insert(pos, beg, end);
list lst2;
lst2.insert(lst2.begin(), lst.begin(), lst.end());
cout << "5、lst2容器中的元素:";
print(lst2);
//6、pop_back();
lst.pop_back();
cout << "6、lst容器中的元素:";
print(lst);
//7、pop_front();
lst.pop_front();
cout << "7、lst容器中的元素:";
print(lst);
//8、remove(elem);
lst.remove(9);
cout << "8、lst容器中的元素:";
print(lst);
//9、erase(pos);
lst.erase(lst.begin());
cout << "9、lst容器中的元素:";
print(lst);
//10、erase(beg, end);
list::iterator pos = lst.begin();
pos++;
lst.erase(pos, lst.end());
cout << "10、lst容器中的元素:";
print(lst);
//11、clear();
lst.clear();
cout << "11、lst容器中的元素:";
print(lst);
system("pause");
return 0;
}
输出结果
1、lst容器中的元素:1 2
2、lst容器中的元素:4 3 1 2
3、lst容器中的元素:5 4 3 1 2
4、lst容器中的元素:9 9 9 5 4 3 1 2
5、lst2容器中的元素:9 9 9 5 4 3 1 2
6、lst容器中的元素:9 9 9 5 4 3 1
7、lst容器中的元素:9 9 5 4 3 1
8、lst容器中的元素:5 4 3 1
9、lst容器中的元素:4 3 1
10、lst容器中的元素:4
11、lst容器中的元素:
函数原型:
- front(); //返回第一个元素
- back(); //返回最后一个元素
list本质是链表,是非线性空间存储数据,list迭代器是不支持随机访问的。
#include
#include
using namespace std;
void print(const list& lst)
{
for (list::const_iterator it = lst.begin(); it != lst.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
// STL - list - 数据读取
/*函数原型:
1、front(); //返回第一个元素
2、back(); //返回最后一个元素
*/
list lst;
//赋值
for (int i = 0; i < 5; i++)
{
lst.push_back(i + 1);
}
cout << "lst中元素为:";
print(lst);
//1、front();
cout << "1、lst中第一个元素:" << lst.front() << endl;
//2、back();
cout << "2、lst中最后一个元素:" << lst.back() << endl;
//验证迭代器是不支持随机访问的
list::iterator it = lst.begin();
it++;
//it = it + 1; //报错:验证迭代器是不支持随机访问的
it--;
//it = it - 1; //报错:验证迭代器是不支持随机访问的
system("pause");
return 0;
}
输出结果
lst中元素为:1 2 3 4 5
1、lst中第一个元素:1
2、lst中最后一个元素:5
函数原型:
- reverse(); //链表反转
- sort(); //链表排序
- template
void sort (Compare comp) //模板函数,可以让链表排序为升序或降序
所有不支持随机访问迭代器的容器,不可以使用标准算法,list不能使用标准排序算法sort(beg, end)。
#include
#include
#include
using namespace std;
void print(const list& lst)
{
for (list::const_iterator it = lst.begin(); it != lst.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
bool myCompare(int v1, int v2)
{
//降序:第一个元素大于第二个元素
return v1 > v2;
}
int main()
{
// STL - list - 反转和排序
/*函数原型:
1、reverse(); //链表反转
2、sort(); //链表排序
3、template
void sort (Compare comp) //模板函数,可以让链表排序为升序或降序
*/
list lst;
lst.push_back(36);
lst.push_back(88);
lst.push_back(17);
lst.push_front(98);
lst.push_front(24);
cout << "lst中元素为:";
print(lst);
//1、reverse();
lst.reverse();
cout << "1、反转后,lst中元素为:";
print(lst);
//2、sort();
lst.sort();
cout << "2、排序后,lst中元素为:";
print(lst);
//3、void sort (Compare comp)
lst.sort(myCompare);
cout << "3、降序排序后,lst中元素为:";
print(lst);
//所有不支持随机访问迭代器的容器,不可以使用标准算法
// 不支持随机访问迭代器的容器,内部会提供对应的一些算法
//sort(lst.begin(), lst.end()); //编译时报错
system("pause");
return 0;
}
输出结果
lst中元素为:24 98 36 88 17
1、反转后,lst中元素为:17 88 36 98 24
2、排序后,lst中元素为:17 24 36 88 98
3、降序排序后,lst中元素为:98 88 36 24 17
描述:将Person自定义数据类型进行排序,Person属性有姓名,年龄,身高
排序规则:按照年龄进行升序,如果年龄相同按照身高进行降序
#include
#include
#include
using namespace std;
class Person
{
public:
string name;
int age;
int high;
Person(string _name, int _age, int _high): name(_name), age(_age), high(_high) {}
};
void print(const list& lst)
{
for (list::const_iterator it = lst.begin(); it != lst.end(); it++)
{
cout << "姓名:" << it->name << ", 年龄:" << it->age << ", 身高:" << it->high << endl;
}
}
bool comparePerson(Person& p1, Person& p2)
{
if (p1.age == p2.age)
{
return p1.high > p2.high;
}
else
{
return p1.age < p2.age;
}
}
int main()
{
// STL - list - 排序案例
/*
描述:将Person自定义数据类型进行排序,Person属性有姓名,年龄,身高
排序规则:按照年龄进行升序,如果年龄相同按照身高进行降序
*/
list lst;
lst.push_back(Person("Tracy ", 20, 165));
lst.push_back(Person("Timo ", 32, 177));
lst.push_back(Person("Felix ", 27, 169));
lst.push_back(Person("Daniel", 20, 175));
lst.push_back(Person("Summer", 27, 158));
cout << "容器中元素:" << endl;
print(lst);
lst.sort(comparePerson);
cout << endl << "------------------" << endl;
cout << "排序后,容器中元素:" << endl;
print(lst);
system("pause");
return 0;
}
输出结果
容器中元素:
姓名:Tracy , 年龄:20, 身高:165
姓名:Timo , 年龄:32, 身高:177
姓名:Felix , 年龄:27, 身高:169
姓名:Daniel, 年龄:20, 身高:175
姓名:Summer, 年龄:27, 身高:158------------------
排序后,容器中元素:
姓名:Daniel, 年龄:20, 身高:175
姓名:Tracy , 年龄:20, 身高:165
姓名:Felix , 年龄:27, 身高:169
姓名:Summer, 年龄:27, 身高:158
姓名:Timo , 年龄:32, 身高:177
set / multiset容器特点,所有元素都会在插入时自动被排序,属于关联式容器,底层结构是用二叉树实现的。
set 与 multiset区别:
- set不允许容器中有重复的元素
- multiset允许容器中有重复的元素
函数原型:
构造函数
- set
st; //默认构造函数 - set(const set& st); //拷贝构造函数
赋值
- set& operator=(const set& st); //重载运算符=
大小操作
- size(); //返回容器中元素个数
- empty(); //判断容器是否为空
交换
- swap(st); //交换两个集合容器
插入
- insert(elem); //在容器中插入元素
删除
- erase(elem); //删除容器中值为elem的元素
- erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器
- erase(beg, end); //删除区间[beg, end)区间的所有元素,返回下一个元素的迭代器
- clear(); //删除所有元素
查找
- find(key); //查找key是否存在,若存在,返回该键的元素的迭代器,若不存在,返回set.end();
统计
- count(key); //统计key的元素个数,统计结果只能为1 或 0
#include
#include
using namespace std;
void print(const set& st)
{
for (set::const_iterator it = st.begin(); it != st.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
// STL - set - 构造函数和赋值
/*
构造函数
1、set st; //默认构造函数
2、set(const set& st); //拷贝构造函数
赋值
3、set& operator=(const set& st); //重载运算符=
大小操作
4、size(); //返回容器中元素个数
5、empty(); //判断容器是否为空
交换
6、swap(st); //交换两个集合容器
插入
7、insert(elem); //在容器中插入元素
删除
8、erase(elem); //删除容器中值为elem的元素
9、erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器
10、erase(beg, end); //删除区间[beg, end)区间的所有元素,返回下一个元素的迭代器
11、clear(); //删除所有元素
查找
12、find(key); //查找key是否存在,若存在,返回该键的元素的迭代器,若不存在,返回set.end();
统计
13、count(key); //统计key的元素个数
*/
//1、set st;
set st;
cout << "4、st容器元素个数:" << st.size() << endl;
//5、empty();
if (st.empty())
{
//7、insert(elem);
//插入数据,只有insert方式 - 所有元素插入时会被自动排序,且过滤重复值(返回插入失败)
st.insert(1);
st.insert(5);
st.insert(2);
st.insert(3);
st.insert(3); //重复值
}
cout << "7、插入元素后,st容器元素个数:" << st.size() << endl;
cout << "1、st容器中的元素:";
print(st);
//2、set(const set& st);
set st2(st);
cout << "2、st2容器中的元素:";
print(st2);
//3、set& operator=(const set& st);
set st3 = st;
cout << "3、st3容器中的元素:";
print(st3);
//12、find(key);
set::iterator pos = st.find(3);
if (pos != st.end())
{
cout << "12、st容器中查找到元素" << endl;
}
else
{
cout << "12、st容器中未找到元素" << endl;
}
//13、count(key); - 结果只能为1 或 0
cout << "13、st容器中统计某元素个数:" << st.count(3) << endl;
//6、swap(st);
st3.insert(15);
cout << "6、交换前,st容器中的元素:";
print(st);
cout << "6、交换前,st3容器中的元素:";
print(st3);
st.swap(st3);
cout << "6、交换后,st容器中的元素:";
print(st);
cout << "6、交换后,st3容器中的元素:";
print(st3);
//8、erase(elem);
st.erase(3);
cout << "8、删除一个元素后,st容器中的元素:";
print(st);
//9、erase(pos);
st.erase(st.begin());
cout << "9、删除第一个元素后,st容器中的元素:";
print(st);
//10、erase(beg, end);
pos = st.begin();
pos++;
st.erase(pos, st.end());
cout << "10、删除区间元素后,st容器中的元素:";
print(st);
//11、clear();
st.clear();
cout << "11、清空元素后,st容器中的元素:";
print(st);
system("pause");
return 0;
}
输出结果
4、st容器元素个数:0
7、插入元素后,st容器元素个数:4
1、st容器中的元素:1 2 3 5
2、st2容器中的元素:1 2 3 5
3、st3容器中的元素:1 2 3 5
12、st容器中查找到元素
13、st容器中统计某元素个数:1
6、交换前,st容器中的元素:1 2 3 5
6、交换前,st3容器中的元素:1 2 3 5 15
6、交换后,st容器中的元素:1 2 3 5 15
6、交换后,st3容器中的元素:1 2 3 5
8、删除一个元素后,st容器中的元素:1 2 5 15
9、删除第一个元素后,st容器中的元素:2 5 15
10、删除区间元素后,st容器中的元素:2
11、清空元素后,st容器中的元素:
- set 不可插入重复数据,而multiset可以
- set 插入数据的同时会返回插入结果,表示插入是否成功
- multiset不会检测数据,因此可以插入重复数据
#include
#include
using namespace std;
void print(const multiset& st)
{
for (multiset::const_iterator it = st.begin(); it != st.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
// STL - set - set与multiset区别
/*
set 不可插入重复数据,而multiset可以
set 插入数据的同时会返回插入结果,表示插入是否成功
multiset不会检测数据,因此可以插入重复数据
*/
//
set st;
//set 不可插入重复数据
//set 插入数据的同时会返回插入结果,表示插入是否成功
pair::iterator, bool> ret = st.insert(5);
if (ret.second)
{
cout << "set第一次插入元素成功" << endl;
}
else
{
cout << "set第一次插入元素失败" << endl;
}
ret = st.insert(5);
if (ret.second)
{
cout << "set第二次插入元素成功" << endl;
}
else
{
cout << "set第二次插入元素失败" << endl;
}
//multiset可以插入重复数据
//multiset不会检测数据,因此可以插入重复数据
multiset ms;
ms.insert(5);
ms.insert(5);
ms.insert(5);
cout << "nultiset容器中插入重复元素:";
print(ms);
system("pause");
return 0;
}
输出结果
set第一次插入元素成功
set第二次插入元素失败
nultiset容器中插入重复元素:5 5 5
pair对组是成对出现的数据,利用对组可以返回两个数据 。有两种创建pair方式:
- pair
p (val1, val2); - pair
p = make_pair(val1, val2);
#include
using namespace std;
int main()
{
// STL - set - pair对组创建
/*
* 创建方式:
1、pair p (val1, val2);
2、pair p = make_pair(val1, val2);
*/
//1、pair p (val1, val2);
pair p("Tracy", 20);
cout << "1、姓名:" << p.first << ", 年龄:" << p.second << endl;
pair p2 = make_pair("Felix", 27);
cout << "2、姓名:" << p2.first << ", 年龄:" << p2.second << endl;
system("pause");
return 0;
}
输出结果
1、姓名:Tracy, 年龄:20
2、姓名:Felix, 年龄:27
set容器默认排序规则为从大到小,可以利用仿函数改变排序规则。
#include
#include
using namespace std;
class MyCompare
{
public:
//重载运算符()
//需要加const 作为常函数,常函数内不可以修改没有mutable关键字的属性的值
bool operator()(int v1, int v2) const
{
return v1 > v2;
}
};
int main()
{
// STL - set - 内置类型指定排序规则
set st;
st.insert(5);
st.insert(8);
st.insert(2);
st.insert(9);
for (set::iterator it = st.begin(); it != st.end(); it++)
{
cout << *it << " ";
}
cout << endl;
system("pause");
return 0;
}
输出结果
9 8 5 2
#include
#include
using namespace std;
class Person
{
public:
string name;
int age;
Person(string _name, int _age) : name(_name), age(_age) {}
};
class MyCompare
{
public:
//重载运算符()
//需要加const 作为常函数,常函数内不可以修改没有mutable关键字的属性的值
bool operator()(const Person& p1, const Person& p2) const
{
return p1.age > p2.age;
}
};
int main()
{
// STL - set - 自定义类型指定排序规则
set st;
st.insert(Person("Tracy", 20));
st.insert(Person("Felix", 22));
st.insert(Person("Timo ", 24));
st.insert(Person("Alice", 26));
for (set::iterator it = st.begin(); it != st.end(); it++)
{
cout << "姓名:" << it->name << ", 年龄:" << it->age << endl;
}
system("pause");
return 0;
}
输出结果
姓名:Alice, 年龄:26
姓名:Timo , 年龄:24
姓名:Felix, 年龄:22
姓名:Tracy, 年龄:20