一直在看数据结构的视频,也在力扣上面刷了一些相关的题目,但是对于c++ 自带的list却从没有正儿八经使用过,所以,今天用一两个小时的时间,把list的用法总结一下,算是扫清一个知识疑惑。
一、注意事项
- list是双向链表,可以在常规时间内在list的任意位置插入或删除元素,反之,不能像数组一样直接使用下标[n]来获取元素;
- 使用的时候,添加头文件 #include
二、list函数介绍
从官网可以查询到list的介绍,主要分为以下几类:
- iterator 迭代器
可以看到,里面给出了好几种begin、end,它们都有什么区别呢?
begin,end 传统的迭代器
rbegin,rend ,reverse,逆迭代器
cbegin ,cend ,const ,也就是不能通过迭代器更改指向的值
crbegin,crend,const reverse iterator
- capacity 容量
empty:返回bool值 ,判断list是否为空
size: 返回list的容量(大小)
max_size: 可以开辟的最大的容量 - element access 元素访问
front:list的头部值
back:list的尾部值 - modifies 修改
assign:分配空间
emplace_front: 头部插入值
emplace_back: 尾部插入值
emplace:插入值
push_front:头部插入值
push_back:尾部插入值
insert:插入值
所以,push与emplace有什么区别呢?
答: emplace在插入值的时候,不会产生中间变量,具体的大家可以去搜索查证
clear:全部删除
erase:单独擦除
二者区别:erase可以单独删除某些元素,clear直接删除了所有的元素;
swap:交换两个链表,实际是交换两个链表的地址
resize: 重构大小,重构变小的话,后面的元素被删除
5. operation 操作
splice:拼接两个链表
remove:删除,只是把元素移动到头部,然后把begin往后移动,如果要真的删除,需要使用erase和clear
remove_if:满足条件就remove
unique:删除重复的元素,只保留一个
sort:排序
reverse:反转
merge:合并
附上一些代码验证:
#include <list>
#include <iostream>
using namespace std;
template <class T>
void print_list(list<T> my_list)
{
for (typename list<T>::iterator it = my_list.begin(); it != my_list.end(); ++it)
cout << ' ' << *it;
cout << '\n';
}
// a predicate implemented as a function:
bool equal_digit(const int &value) { return (value == 1); }
// a predicate implemented as a class:
struct is_odd
{
bool operator()(const int &value) { return (value % 2) == 1; }
};
int main()
{
//list初始化
list<int> myListA; //定义空的链表
list<int> myListB(4, 100); //定义链表myListB,4个元素,初始值为100
list<int> myListC(myListB.begin(), myListB.end());
list<int> myListD(myListC); //使用myListC来初始化myListD
/*list的函数*/
//1.assign,assignment 分配
cout << "----1.assign----" << endl;
myListA.assign(3, 19);
print_list(myListA);
myListA.assign(2, 10);
print_list(myListA);
cout << "----------------" << endl;
//2. iterator 迭代器
// begin end ;rbegin rend;cbegin cend;crbegin crend
cout << "----2.iterator----" << endl;
for (list<int>::iterator it = myListB.begin(); it != myListB.end(); ++it)
cout << ' ' << *it;
cout << '\n';
// for (list<int>::iterator it = myListB.rbegin(); it != myListB.rend(); ++it)
// cout << ' ' << *it;
// cout << '\n';
//const iterator 的使用,可以自增,但是其指向的元素值不可被改变,这里就是cbegin cend的存在意义
for (auto it = myListB.cbegin(); it != myListB.end(); ++it)
cout << ' ' << *it;
//*it=0;
cout << '\n';
//reverse iterator 反向迭代器
int intA[] = {111, 26, 3, 45, 5, 6};
myListA.assign(intA, intA + 6);
for (auto it = myListA.cbegin(); it != myListA.end(); ++it)
cout << ' ' << *it;
cout << '\n';
cout << "reverse!" << endl;
for (auto it = myListA.crbegin(); it != myListA.crend(); ++it)
cout << ' ' << *it;
cout << '\n';
//3. capacity
//empty()
if (myListA.empty())
cout << "empty!" << endl;
else
cout << "no empty" << endl;
//size()
cout << "size:" << myListA.size() << endl;
//max_size();
cout << "max_size:" << myListA.max_size() << endl;
//4. element access 元素访问
cout << "element front:" << myListA.front();
cout << "element back:" << myListA.back();
std::cout << '\n';
//5.modifies 修改
//assign 初始化分配 上面提到了
//emplace_front/ emplace_back/emplace 避免临时变量的产生
//push_front push_back 会产生临时变量
// emplace insert
myListA.emplace_front(1000);
for (auto &x : myListA)
std::cout << ' ' << x;
std::cout << '\n';
myListA.emplace_back(1000);
for (auto &x : myListA)
std::cout << ' ' << x;
std::cout << '\n';
myListA.push_front(9);
myListA.push_back(9);
for (auto &x : myListA)
std::cout << ' ' << x;
std::cout << '\n';
myListA.insert(myListA.begin(), 30);
myListA.emplace(myListA.begin(), 300);
for (auto &x : myListA)
std::cout << ' ' << x;
std::cout << '\n';
//erase clear; erase可以单独删除某些元素,clear直接删除了所有的元素;
myListA.clear(); //删除所有的元素
for (auto &x : myListA)
std::cout << ' ' << x;
std::cout << '\n';
cout << "size:" << myListA.size() << endl;
myListA.assign(4, 88);
list<int>::iterator itforList;
itforList = myListA.begin();
cout << *itforList << endl;
cout << "size:" << myListA.size() << endl;
for (auto it = myListA.begin(); it != myListA.end();)
//myListA.erase(it++);
it = myListA.erase(it); //返回指向下一个元素的迭代器
std::cout << '\n';
//使用erase删除某一个元素
myListA.assign(intA, intA + 6);
print_list(myListA);
for (auto it = myListA.begin(); it != myListA.end();)
{
if (*it == 4)
myListA.erase(it++); //返回指向下一个元素的迭代器
else
{
it++;
}
}
print_list(myListA);
//swap
myListB.assign(intA, intA + 3);
myListA.swap(myListB); //交换两个链表的内容
print_list(myListA);
print_list(myListB);
/*
swap函数会交换2个数据类型相同的容器内容。
本身交换的速度非常快,因为swap在交换的时候并不是完全将2个容器的元素互换,
而是交换了2个容器内的内存地址。除了数组,其他容器在交换后本质上是将内存地址进行了交换,
而元素本身在内存中的位置是没有变化的。
换而言之,如果说有2个房间,名字是a和b,
那么swap函数交换的是2个房间的名字,
而房间里的物品根本没有任何移动。
*/
//resize: 重新设置容器的大小
myListB.resize(1);
print_list(myListB);
myListB.resize(6);
print_list(myListB);
//6. operation
// splice 拼接
cout << "myListA" << endl;
print_list(myListA);
cout << "myListB" << endl;
print_list(myListB);
myListA.splice(myListA.begin(), myListB);
cout << "myListA" << endl;
print_list(myListA);
cout << "myListB" << endl;
print_list(myListB);
cout << "size:" << myListB.size() << endl;
//remove remove_if 只是把要删除的元素移动到前端,如果想要真正的删除,需要使用erase clear
myListA.remove(0);
print_list(myListA);
cout << "size:" << myListA.size() << endl;
myListA.remove_if(equal_digit); //根据条件移除元素
print_list(myListA);
cout << "size:" << myListA.size() << endl;
// unique 移除相同的元素
myListA.assign(5, 1);
print_list(myListA);
cout << "size:" << myListA.size() << endl;
myListA.unique();
print_list(myListA);
cout << "size:" << myListA.size() << endl;
//sort 排序
myListA.assign(intA, intA + 6);
myListA.sort();
print_list(myListA);
cout << "size:" << myListA.size() << endl;
//reverse 逆序
myListA.reverse();
print_list(myListA);
cout << "size:" << myListA.size() << endl;
//merge
myListA.merge(myListC);
print_list(myListA);
cout << "size:" << myListA.size() << endl;
return 0;
}