目录
3.3.1. void splice (iterator position, list& x)
3.3.2.void splice (iterator position, list& x, iterator i)
3.3.3. void splice (iterator position, list& x, iterator first, iterator last)
1. list的介绍及使用
// std::list
template < class T, class Alloc = allocator<T> > class list;
2. list的介绍
- list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代;
- list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素;
- list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能向前迭代,list 是双链表,可以双向迭代;
- 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好;
- 与其他序列式容器相比,list 和 forward_list 最大的缺陷是不支持任意位置的随机访问。比如:要访问 list 的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销 (O(N));
- list还需要一些额外的空间,以保存每个节点的相关联信息。
3. list的使用
3.1. constructor的使用
void Test1(void)
{
//使用标准库中list的constructor
//default
std::list<int> lt1;
//fill
std::list<int> lt2(10, 1);
//range
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
std::list<int> lt3(v.begin(), v.end());
//copy
std::list<int> lt4(lt3);
std::list<int>::iterator it1 = lt1.begin();
while (it1 != lt1.end())
{
cout << *it1 << " ";
++it1;
}
cout << endl;
for (auto e : lt2)
{
cout << e << " ";
}
cout << endl;
for (auto e : lt3)
{
cout << e << " ";
}
cout << endl;
for (auto e : lt4)
{
cout << e << " ";
}
cout << endl;
}
现象如下:
3.2. 数据修改接口的使用
void Test2(void)
{
//关于Modifiers的接口的使用
std::list<int> lt;
//1.支持头插尾插
lt.push_front(3);
lt.push_front(2);
lt.push_front(1);
lt.push_back(2);
lt.push_back(1);
//2.支持任意位置插入
//同样list没有提供find,统一用算法库#include <algorithm>里面的find
std::list<int>::iterator pos1 = find(lt.begin(), lt.end(), 3);
if (pos1 != lt.end())
{
lt.insert(pos1, 100);
}
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
//3. 支持头删尾删
lt.pop_front();
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
lt.pop_back();
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
//4.支持任意位置删除
std::list<int>::iterator pos2 = std::find(lt.begin(), lt.end(), 100);
if (pos2 != lt.end())
{
pos2 = lt.erase(pos2);
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
}
}
现象如下:
3.3. splice的使用:
splice()的功能就是将一个list的数据转移到另一个list上;
//entire list (1)
//转移所有数据
void splice (iterator position, list& x);
//single element (2)
//仅仅转移i这个位置的数据
void splice (iterator position, list& x, iterator i);
//element range (3)
//转移一段区间
void splice (iterator position, list& x, iterator first, iterator last);
3.3.1. void splice (iterator position, list& x)
void Test3(void)
{
std::list<int> dst_lt;
dst_lt.push_back(1);
dst_lt.push_back(2);
dst_lt.push_back(3);
dst_lt.push_back(4);
dst_lt.push_back(5);
cout << "old dst_lt: " << endl;
for (auto e : dst_lt)
{
cout << e << " ";
}
cout << endl;
std::list<int> sur_lt;
sur_lt.push_back(6);
sur_lt.push_back(7);
sur_lt.push_back(8);
sur_lt.push_back(9);
sur_lt.push_back(10);
cout << "old sur_lt: " << endl;
for (auto e : sur_lt)
{
cout << e << " ";
}
cout << endl;
std::list<int>::iterator pos1 = dst_lt.begin();
pos1++;
//转移所有数据
dst_lt.splice(pos1, sur_lt);
cout << "new dst_lt: " << endl;
for (auto e : dst_lt)
{
cout << e << " ";
}
cout << endl;
cout << "new sur_lt: " << endl;
for (auto e : sur_lt)
{
cout << e << " ";
}
cout << endl;
}
现象如下:
3.3.2.void splice (iterator position, list& x, iterator i)
void Test3(void)
{
std::list<int> dst_lt;
dst_lt.push_back(1);
dst_lt.push_back(2);
dst_lt.push_back(3);
dst_lt.push_back(4);
dst_lt.push_back(5);
cout << "old dst_lt: " << endl;
for (auto e : dst_lt)
{
cout << e << " ";
}
cout << endl;
std::list<int> sur_lt;
sur_lt.push_back(6);
sur_lt.push_back(7);
sur_lt.push_back(8);
sur_lt.push_back(9);
sur_lt.push_back(10);
cout << "old sur_lt: " << endl;
for (auto e : sur_lt)
{
cout << e << " ";
}
cout << endl;
std::list<int>::iterator pos1 = dst_lt.begin();
pos1++;
std::list<int>::iterator pos2 = std::find(sur_lt.begin(), sur_lt.end(), 8);
dst_lt.splice(pos1, sur_lt,pos2);
cout << "new dst_lt: " << endl;
for (auto e : dst_lt)
{
cout << e << " ";
}
cout << endl;
cout << "new sur_lt: " << endl;
for (auto e : sur_lt)
{
cout << e << " ";
}
cout << endl;
}
结果如下:
3.3.3. void splice (iterator position, list& x, iterator first, iterator last)
void Test3(void)
{
std::list<int> dst_lt;
dst_lt.push_back(1);
dst_lt.push_back(2);
dst_lt.push_back(3);
dst_lt.push_back(4);
dst_lt.push_back(5);
cout << "old dst_lt: " << endl;
for (auto e : dst_lt)
{
cout << e << " ";
}
cout << endl;
std::list<int> sur_lt;
sur_lt.push_back(6);
sur_lt.push_back(7);
sur_lt.push_back(8);
sur_lt.push_back(9);
sur_lt.push_back(10);
cout << "old sur_lt: " << endl;
for (auto e : sur_lt)
{
cout << e << " ";
}
cout << endl;
std::list<int>::iterator pos1 = dst_lt.begin();
pos1++;
std::list<int>::iterator pos2 = std::find(sur_lt.begin(), sur_lt.end(), 7);
std::list<int>::iterator pos3 = std::find(sur_lt.begin(), sur_lt.end(), 9);
//转移一段区间
dst_lt.splice(pos1, sur_lt,pos2,pos3);
cout << "new dst_lt: " << endl;
for (auto e : dst_lt)
{
cout << e << " ";
}
cout << endl;
cout << "new sur_lt: " << endl;
for (auto e : sur_lt)
{
cout << e << " ";
}
cout << endl;
}
结果如下:
3.4. remove的使用
//Removes from the container all the elements that compare equal to val.
void remove (const value_type& val);
这里的remove是删除list<T>中的一个等于val的数据还是删除list<T>中所有等于val的数据呢?验证如下:
void Test4(void)
{
std::list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);
for (auto e : lt)
cout << e << " ";
cout << endl;
// 删除3
lt.remove(3);
for (auto e : lt)
cout << e << " ";
cout << endl;
}
结果如下:
从结果来看,remove会删除list<T>中所有等于val的数据。
3.5. std::list::sort
我们知道,算法库里面也是有sort的(以快排的方式实现),为什么list要自己实现一个sort(以归并方式实现)呢?
答案是list不能使用标准算法库里面的sort,因为算法库里面的sort需要物理存储空间是连续的,而list的存储空间可不是连续的,如果使用标准库中的 std::sort,就会报错,如下:
因此, list 自己有一个成员函数 sort, 如下:
void Test5(void)
{
std::list<int> lt;
lt.push_back(1);
lt.push_back(3);
lt.push_back(2);
lt.push_back(5);
lt.push_back(4);
lt.sort();
for (auto e : lt)
cout << e << " ";
cout << endl;
}
结果如下:
对比下std::sort和list::sort的效率:
void Test6(void)
{
srand(time(0));
const int N = 10000000;
std::vector<int> v;
v.reserve(N);
std::list<int> lt;
for (size_t i = 0; i < N; ++i)
{
auto e = rand();
v.push_back(e);
lt.push_back(e);
}
int begin1 = clock();
std::sort(v.begin(), v.end());
int end1 = clock();
int begin2 = clock();
lt.sort();
int end2 = clock();
cout << "std::sort :" << end1 - begin1 << endl;
cout << "list::sort :" << end2 - begin2 << endl;
}
在release版的结果如下:
有时候当数据量很大的时候,我们直接用list::sort还不如先把数据拷贝到vector里面进行排序,然后再拷回去,如下:
void Test6(void)
{
srand(time(0));
const int N = 10000000;
std::vector<int> v;
v.reserve(N);
std::list<int> lt1;
std::list<int> lt2;
for (size_t i = 0; i < N; ++i)
{
auto e = rand();
lt1.push_back(e);
lt2.push_back(e);
}
int begin1 = clock();
//1. 将数据插入到vector里
for (auto e : lt1)
{
v.push_back(e);
}
//2. 让vector调用std::sort进行排序
std::sort(v.begin(), v.end());
size_t i = 0;
//3. 将数据拷回list
for (auto& e : lt1)
{
e = v[i++];
}
int end1 = clock();
int begin2 = clock();
// 让list直接排序
lt2.sort();
int end2 = clock();
cout << "copy vector sort :" << end1 - begin1 << endl;
cout << "list::sort :" << end2 - begin2 << endl;
}
relese版下结果如下:
可以看出,链表自身提供的排序效率有点低。