list的使用,首先要包含头文件
#include <list>
list的介绍
1.list是一种可以在常数范围内在链表中的任意位置进行插入和删除的序列式容器,并且该容器能够前后双向迭代。
2.list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立结点当中,在结点中通过前驱指针指向其前一个元素和后继指针指向后一个元素。
3.list与forward_list非常相似,最主要的不同在于forward_list是单链表,只能进行单方向迭代。
4.与其它容器相比,list通常在某个位置进行插入、删除元素的执行效率更高。
5.list和forward_list最大的缺陷是不支持在任意位置的随机访问(即不能像vector一样,通过下标+[ ]进行元素访问),其次,list还需要一些额外的空间,以保存每个结点之间的关联信息(对于存储的类型较小元素来说这可能是一个重要的因素)。
list的使用
定义方式
方式一:
构造一个某类型的空容器
list<int> lt; //构造int类型的空容器
方式二:
构造一个含有n个val的某类型容器
list<int> lt2(5,1); //构造含有5个1的int类型容器
方式三:
对某类型的list容器进行拷贝构造
list<int> lt2(lt1); //对int类型的lt1容器进行拷贝构造
方式四:
对其它容器的一段内容进行拷贝构造
string s("hello world");
list<char> lt1(s.begin(),s.end()); //对string对象某段区间的拷贝构造
方式五:
对数组的某段区间进行拷贝构造
int arr[] = { 1, 2, 3, 4, 5 };
int len = sizeof(arr) / sizeof(arr[0]);
list<int> lt1(arr, arr + len); //对数组的某段区间进行拷贝构造
插入和删除
1.push_front和pop_front
push_front:能够进行链表的头部位置数据插入
pop_front:能够进行链表的头部位置数据删除
例子:
int main()
{
list<int> lt;
lt.push_front(1);
lt.push_front(2);
lt.push_front(3);
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //3 2 1
lt.pop_front();
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //2 1
return 0;
}
2.push_back和pop_back
push_back:能够进行链表的尾部位置数据插入
pop_back:能够进行链表的尾部位置数据删除
例子:
int main()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //1 2 3
lt.pop_back();
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;//1 2
return 0;
}
3.insert
insert支持三种插入方式
1、在指定迭代器位置插入一个数。
2、在指定迭代器位置插入n个值为val的数。
3、在指定迭代器位置插入一段迭代器区间(注意左闭右开)。
例子:
int main()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
list<int>::iterator pos = find(lt.begin(), lt.end(), 2);
// 第一种插入方式
lt.insert(pos, 4); //在2的位置插入4
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //1 4 2 3
pos = find(lt.begin(), lt.end(), 4);
// 第二种插入方式
lt.insert(pos, 3, 5); //在pos(4)的位置插入3个3
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //1 5 5 5 4 2 3
vector<int> v(3, 8);
pos = find(lt.begin(), lt.end(), 2);
// 第三种插入方式
lt.insert(pos, v.begin(), v.end()); //在2的位置插入3个8
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //1 5 5 5 4 8 8 8 2 3
return 0;
}
注意: find函数不是list中的成员函数,是头文件< algorithm >
中的一个函数,该函数在指定迭代器区间寻找指定元素的位置,并返回该位置的迭代器
4.erase
erase支持两种删除方式
删除指定迭代器位置的元素。
删除指定迭代器区间(注意左闭右开)的所有元素。
例子:
int main()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);
list<int>::iterator pos = find(lt.begin(), lt.end(), 3);
// 第一种删除方式
lt.erase(pos); //删除3
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //1 2 4 5
pos = find(lt.begin(), lt.end(), 2);
// 第二种删除方式
lt.erase(pos, lt.end()); //删除2及其之后的元素
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //1
return 0;
}
迭代器的使用
1.begin和end
begin:能够得到容器中第一个元素的正向迭代器
end:能够得到容器中最后一个元素的后一个位置的正向迭代器
例子:
int main()
{
list<int> lt(5, 2);
// 正向迭代器遍历容器
list<int>::iterator it = lt.begin();
while (it != lt.end())
{
cout << *it << " ";
it++;
}
cout << endl;
return 0;
}
2.rbegin和rend
rbegin:能够得到容器中最后一个元素的反向迭代器
rend:能够得到容器中第一个元素的前一个位置的反向迭代器
例子:
int main()
{
list<int> lt(5, 2);
//反向迭代器遍历容器
list<int>::reverse_iterator rit = lt.rbegin();
while (rit != lt.rend())
{
cout << *rit << " ";
rit++;
}
cout << endl;
return 0;
}
获取元素
front和back
front:能够获取list容器中的第一个元素
back:能够获取list容器中的最后一个元素
例子:
int main()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
cout << lt.front() << endl; //1
cout << lt.back() << endl; //3
return 0;
}
容器中元素个数和容量的控制
1.size
能够获取当前容器当中的数据个数
例子:
int main()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
cout << lt.size() << endl; //3
return 0;
}
2.resize
resize的使用规则:
1、当所给值大于当前的size时,将size扩大到该值,扩大的数据为第二个所给值,若未给出,则默认为容器所存储类型的默认构造函数所构造出来的值进行填充。
2、当所给值小于当前的size时,将size缩小到该值。
例子:
int main()
{
list<int> lt(5, 2);
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //2 2 2 2 2
lt.resize(8, 3); //将size扩大为8,扩大的填充的值为3
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //2 2 2 2 2 3 3 3
lt.resize(3); //将size缩小为3
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //2 2 2
return 0;
}
3.empty
能够用于判断容器是否为空
例子:
int main()
{
list<int> lt;
cout << lt.empty() << endl; // true 为空
return 0;
}
4.clear
能够用于清空容器
例子:
int main()
{
list<int> lt(5, 2);
cout << lt.size() << endl; //5
lt.clear(); //清空容器
cout << lt.size() << endl; //0
return 0;
}
其它操作函数
1.sort
能够用于将容器中的数据进行排序。
默认排序顺序为升序
例子:
int main()
{
list<int> lt;
lt.push_back(2);
lt.push_back(9);
lt.push_back(4);
lt.push_back(0);
lt.push_back(6);
lt.push_back(7);
lt.push_back(3);
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; // 2 9 4 0 6 7 3
lt.sort(); //默认将容器内数据排为升序
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //0 2 3 4 6 7 9
return 0;
}
注意: 如果要进行降序排序,就需要自己实现比较函数
2.splice
能够用于两个list容器之间的拼接
有三种拼接方式:
1、将整个容器拼接到另一个容器的指定迭代器位置。
2、将容器当中的某一个数据拼接到另一个容器的指定迭代器位置。
3.将容器指定迭代器区间的数据拼接到另一个容器的指定迭代器位置。
例子:
int main()
{
list<int> lt1(3, 2);
list<int> lt2(3, 3);
// 第一种拼接方式
lt1.splice(lt1.begin(), lt2); //将容器lt2拼接到容器lt1的开头
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl; //2 2 2 3 3 3
list<int> lt3(3, 2);
list<int> lt4(3, 3);
// 第二种拼接方式
lt3.splice(lt3.begin(), lt4, lt4.begin()); //将容器lt4的第一个数据拼接到容器lt3的开头
for (auto e : lt3)
{
cout << e << " ";
}
cout << endl; //3 2 2 2
list<int> lt5(3, 2);
list<int> lt6(3, 3);
// 第三种拼接方式
lt5.splice(lt5.begin(), lt6, lt6.begin(), lt6.end()); //将容器lt6的指定迭代器区间内的数据拼接到容器lt5的开头
for (auto e : lt5)
{
cout << e << " ";
}
cout << endl; //3 3 3 2 2 2
return 0;
}
注意: 当一个容器中的数据被拼接到另一个容器中后,数据在原容器中就不存在了。所以拼接即是将该节点拼接到另一个容器中。
3.remove
能够删除容器中特定值的节点
例子:
int main()
{
list<int> lt;
lt.push_back(1);
lt.push_back(3);
lt.push_back(2);
lt.push_back(2);
lt.push_back(3);
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //1 3 2 2 3
lt.remove(2); //删除容器当中值为2的节点
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //1 3 3
return 0;
}
4.remove_if
能够删除容器中满足条件的节点
例子:
bool digit(const int& val)
{
return val > 10;
}
int main()
{
list<int> lt;
lt.push_back(12);
lt.push_back(3);
lt.push_back(6);
lt.push_back(19);
lt.push_back(1);
lt.push_back(5);
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //12 3 6 19 1 5
// 删除条件
lt.remove_if(digit); //删除容器当中值大于10的元素
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //3 6 1 5
return 0;
}
5.unique
能够删除容器中连续的重复函数
例子:
int main()
{
list<int> lt;
lt.push_back(1);
lt.push_back(5);
lt.push_back(2);
lt.push_back(3);
lt.push_back(2);
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //1 5 2 3 2
lt.sort(); //将容器当中的元素排为升序 1 2 2 3 5
lt.unique(); //删除容器当中连续的重复元素
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //1 3 5
return 0;
}
注意: 如果希望通过unique实现去重,需要对容器中的元素进行排序,因为unique是对连续的重复的节点去重,所以前提是连续。
6.merge
能够将一个有序的list容器合并到另一个有序的容器中,使合并之后的list容器仍然有序。即类似于归并排序
例子:
int main()
{
list<int> lt1;
lt1.push_back(3);
lt1.push_back(5);
lt1.push_back(2);
list<int> lt2;
lt2.push_back(4);
lt2.push_back(1);
lt2.push_back(6);
lt1.sort(); //将容器lt1排为升序 2 3 5
lt2.sort(); //将容器lt2排为升序 1 4 6
lt1.merge(lt2); //将lt2合并到lt1当中
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl; //1 2 3 4 5 6
return 0;
}
7.reverse
能够将容器中的节点顺序进行逆置
例子:
int main()
{
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.reverse(); //将容器当中元素的位置进行逆置
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //3 2 1
return 0;
}
8.assign
能够用于将新内容分配给容器,替换当前内容
新内容的两种替换方式:
1.将n个值为val的数据分配给容器
2.将所给迭代器区间当中的内容分配给容器。
例子:
int main()
{
list<char> lt(3, 'a');
// 方式一
lt.assign(3, 'b'); //将新内容分配给容器,替换其当前内容
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //b b b
string s("hello world");
// 方式二
lt.assign(s.begin(), s.end()); //将新内容分配给容器,替换其当前内容
for (auto e : lt)
{
cout << e << " ";
}
cout << endl; //h e l l o w o r l d
return 0;
}
9.swap
能够将两个容器的内容进行交换
例子:
int main()
{
list<int> lt1(3, 1);
list<int> lt2(2, 4);
lt1.swap(lt2); //交换两个容器的内容
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl; //4 4
for (auto e : lt2)
{
cout << e << " ";
}
cout << endl; //1 1 1
return 0;
}