大纲:

1. list容器的相关介绍
(1)list是 C++ 标准库<list>头文件中的双向链表容器,属于STL序列式容器的一种,用于存储有序的元素集合。
(2)list的底层:是一个双向循环双链表,每一个结点都包含数据,前向指针,后向指针;结点在内存中非连续存储(元素节点分散在内存中,通过指针连接,无需预留连续内存空间),所以增删元素仅需修改指针指向,无需移动其他元素(可频繁的插入/删除元素)
(3)list支持双向迭代,同时由于结点是动态申请和释放,不存在容量和大小的区别,也就没有reserve()和capacity()成员函数。
(4)list相对于string和vector新增了一些接口,如splice和merge,能实现高效转移和合并列表。
(5)list不支持通过下标访问元素。
2. 构造函数和析构函数
2.1 常用的构造函数
(1)无参构造
cpp
list<int> l1;
(2)构造n个val
cpp
list<int> l2(10, 1);//构造10个1
list<string> l3(10, "abcde");//构造10个字符串"abcde"
(3)拷贝构造函数
cpp
list<string> l4(l3);
(4)迭代器构造
cpp
list<string> l5(l3.begin(), l3.end());
(5)初始化列表构造
cpp
list<int> l6({6,16,26,36,46,56,66});
2.2 析构函数
cpp
~list();
注:后面模拟实现的时候,析构的方法具体分析
3. 修改容器内容的相关函数
3.1 push_front()
push_front:在list首元素前插入值为val的元素,所以打印是倒序。
cpp
void test02()
{
list<int> l;
l.push_front(1);
l.push_front(2);
l.push_front(3);
l.push_front(4);
l.push_front(5);
for (auto& e : l)
{
cout << e << " ";
}
cout << endl;
cout << l.size() << endl;
}
3.2 pop_front()
pop_front:删除list中第一个元素。
cpp
void test02()
{
list<int> l;
l.push_front(13);
l.push_front(28);
l.push_front(33);
l.push_front(41);
l.push_front(52);
l.pop_front();
l.pop_front();
for (auto& e : l)
{
cout << e << " ";
}
cout << endl;
cout << l.size() << endl;
}
注:相对于前面的vector容器,list的插入和删除数据更高效,不需要挪动数据,只需要更改指针指向即可!!!
3.3 insert()
insert:在pos位置中插入值为val的元素。

(1)第1种方式:
cpp
// insert
list<int> l1 = { 10,20,30 };
list<int> l2 = { 60,70,90 };
l2.insert(--l2.end(), 66);
for (auto& e : l2)
{
cout << e << " ";
}
cout << endl;//60 70 66 90
(2)第2种方式:
cpp
// insert
list<int> l1 = { 10,20,30 };
list<int> l2 = { 60,70,90 };
l2.insert(++l2.begin(), l1.begin(), l1.end());
for (auto& e : l2)
{
cout << e << " ";
}
cout << endl;//60 10 20 30 70 66 90
(3)第3种方式:
cpp
l2.insert(--l2.end(), { 1,2,3,4,5 });
for (auto& e : l2)
{
cout << e << " ";
}
cout << endl;//60 70 66 1 2 3 4 5 90
3.4 erase
erase:

(1)第1种方式:
删除指定位置的结点,这里需要注意前置--和后置--的区别,C++标准库只实现了前者;另外需要注意:end()不是最后一个结点;
cpp
void test03()
{
list<int> l({6,16,26,36,46,56,66});
for (auto& e : l)
{
cout << e << " ";
}
cout << endl;
l.erase(l.begin());//头删
l.erase(--l.end());//尾删
for (auto& e : l)
{
cout << e << " ";
}
//16 26 36 46 56
}
(2)第2种方式:
cpp
l.erase(++l.begin(), --l.end());
for (auto& e : l)
{
cout << e << " ";
}
cout << endl;//6 66
3.5 swap
直接实现两个链表的数据交换!!!
cpp
void test04()
{
list<int> l1({ 6,16,26,36,46,56,66 });
list<int> l2({ 9,99,999 });
for (auto& e : l1)
{
cout << e << " ";
}
cout << endl;
l1.swap(l2);
for (auto& e : l1)
{
cout << e << " ";
}
cout << endl;
}
3.6 resize()
resize():强制将链表的元素个数(长度)调整为指定的目标值 n,调整逻辑分扩容和缩容两种情况,且操作是原地修改链表,不会返回新对象。
情况 1:n > 原长度(扩容)-- 尾部插入新节点
情况 2:n < 原长度(缩容)-- 尾部删除节点

cpp
void test05()
{
list<int> l1({ 6,16,26,36,46,56,66 });
cout << l1.size() << endl;
l1.resize(5);//7
for (auto& e : l1)//缩容
{
cout << e << " ";
}
cout << endl;
//6 16 26 36 46
l1.resize(10, 1);//扩容
for (auto& e : l1)
{
cout << e << " ";
}
cout << endl;
//6 16 26 36 46 1 1 1 1 1
}
3.7 clear
clear:清空list中的有效元素
cpp
l1.clear();
for (auto& e : l1)
{
cout << e << " ";
}
cout << endl;
4. 迭代器
4.1 begin() 和 end()
正向迭代器,链表第一个元素和尾后位置。
cpp
list<int> l1({ 6,16,26,36,46,56,66 });
list<int>::iterator start = l1.begin();
list<int>::iterator finish = l1.end();
while (start != finish)
{
cout << *start << " ";
++start;
}
cout << endl;
//6,16,26,36,46,56,66
4.2 rbegin() 和 rend()
反向迭代器,链表最后一个元素和头前位置,这里的++rbegin,倒着往前移动指向。
cpp
list<int>::reverse_iterator rstart = l1.rbegin();
list<int>::reverse_iterator rfinish = l1.rend();
while (rstart != rfinish)
{
cout << *rstart << " ";
++rstart;
}
cout << endl;
5. 容器访问相关函数
5.1 front() 和 back()
访问第一个元素和最后一个有效元素
cpp
void test07()
{
list<int> l1 = { 10,20,30,40,50 };
cout << l1.front() << endl;//10
cout << l1.back() << endl;//50
}
6. 操作容器的相关函数
6.1 splice()
splice:将元素从一个列表转移到另一个列表。
**注意:**这里的移动不是复制,移动数据后,原链表的数据会被移除。

这里和insert声明类似,这里就选择第二种方式说明:
(把lt2的200移动到lt1的30之前)
cpp
void test07()
{
list<int> lt1 = { 10, 20, 30 };
list<int> lt2 = { 100, 200, 300 };
printList(lt1, "移动前 lt1");
printList(lt2, "移动前 lt2");
cout << endl;
list<int>::const_iterator ele_to_move = ++lt2.begin();
lt1.splice(--lt1.end(), lt2, ele_to_move);
printList(lt1, "移动后 lt1");
printList(lt2, "移动后 lt2");
}
//移动前 lt1: 10 20 30
//移动前 lt2: 100 200 300
//移动后 lt1: 10 20 200 30
//移动后 lt2: 100 300
6.2 remove()
remove() -- 移除特定的数据
cpp
void test08()
{
int arr[] = { 17,89,7,14 };
list<int> mylist(arr, arr + 4);
printList(mylist, "移除前 mylist");
mylist.remove(89);
printList(mylist, "移除后 mylist");
}
6.3 unique()
unique() -- 移除连续的重复元素。功能特性和标准的搜索二叉树和标准的AVL数类似,后面说。
cpp
void test09()
{
list<int> mylist({ 17,89,7,14,99,66,66,6,2,17,17 });
printList(mylist, "移除前 mylist");
mylist.unique();
printList(mylist, "移除后 mylist");
}
//移除前 mylist: 17 89 7 14 99 66 66 6 2 17 17
//移除后 mylist: 17 89 7 14 99 66 6 2 17
6.4 merge()
merge():合并已排序的列表,必须是升序的,否则程序会崩溃!!
cpp
void test10()
{
list<int> list1({ 1,2,3,4,5 });
list<int> list2({ 88,99 });
printList(list1, "排序前 mylist");
list1.merge(list2);
printList(list1, "排序后 mylist");
}
//排序前 mylist: 1 2 3 4 5
//排序后 mylist: 1 2 3 4 5 88 99
6.5 sort()
字符串排序先按照第一个字符进行比较ASCLL码值,相同再比较第二个字符!!
cpp
void test10()
{
list<string> sl = { "acb","efg","qwe","qqc","aad","aw" };
for (auto& e : sl)
{
cout << e << " ";
}
cout << endl;
sl.sort();
for (auto& e : sl)
{
cout << e << " ";
}
cout << endl;
}
//排序前:acb efg qwe qqc aad aw
//排序后:aad acb aw efg qqc qwe
6.6 reverse()
reverse():逆置元素
cpp
void test11()
{
list<int> mylist({ 17,89,7,14,99,66,66,6,2,17,17 });
printList(mylist, "反转前 mylist");
mylist.reverse();
printList(mylist, "反转后 mylist");
}
//反转前 mylist: 17 89 7 14 99 66 66 6 2 17 17
//反转后 mylist: 17 17 2 6 66 66 99 14 7 89 17
那么list的相关介绍就到这里,下期将对list的结构和常用的结构进行模拟实现,敬请期待~