list(链表)的基本概念
功能:
将数据进行链式存储
链式存储是线性表的另一种表现形式。链表(list)是一种具体的实现形式。链表由一系列结点构成。结点由数据域和指针域构成。(具体请参考相关数据结构书籍)
STL中的链表是一个双向循环链表
双向循环链表内部实现原理
双向链表中的结点由结构体或类实现,内部有两个指针域和一个数据域。指针域分别为front和back。front指向前一个结点,rear指向当前结点的后一个结点。链表中第一个结点的front指针指向最后一个结点,最后一个结点的back指针指向第一个结点,从而在遍历时达到循环的效果。
双向循环链表的结构示意图为:
由于链表的存储方式并不是连续的内存空间,因此链表list的迭代器只支持前移和后移,属于双向迭代器。
list优缺点分析
list的优点
1、采用动态存储分配,不会造成内存的浪费和溢出
2、链表执行插入和删除操作十分方便,时间开销小,不需要移动大量元素,只需修改指针即可
list的缺点
链表虽然插入和删除操作十分方便,但由于在实际内存中并非是连续存取,因此不能实现对数据的随机访问。且由于每个结点都需要用多余的空间存储指针域,因此对空间的耗费更高
list与vector的对比
1、list插入操作和删除操作并不会使原有list迭代器失效(只要不删除迭代器所指向的元素),而vector的迭代器在进行插入和删除操作后,迭代器会立即失效
2、STL中vector和list是两个最常被使用的容器,各有优缺点
list构造函数
注:list同样可以用push_back(尾插法)将数据插入到链表尾,同样支持用push_front(头插法)将数据插入到表头
list构造函数与其他几个STL常用容器类似,熟练掌握即可
list容器赋值与交换
作用:给list容器赋值以及交换list容器
eg:
#include<iostream>
using namespace std;
#include<list>
#include<string>
void printList(const list<int>&l)
{
for (list<int>::const_iterator it = l.begin(); it != l.end(); it++)
{
cout << *it << ' ';
}
cout << endl;
}
int main()
{
list<int>l;
l.push_back(10);//尾插
l.push_back(20);
l.push_front(10);//头插
l.push_front(20);
printList(l);
list<int>L1 = l;//将l的值赋给L1
printList(L1);
list<int>L2(l.begin(), l.end());//将l区间范围内的元素赋给L2
printList(L2);
list<int>L3(5,100);//5个100
printList(L3);
L3.swap(l);//将L3与l的元素进行交换
printList(l);
printList(L3);
system("pause");
return 0;
}
list大小操作
作用:提供容器list指定大小/查询大小的操作
注:与其他容器的大小操作基本一致,熟练掌握即可
list容器的插入与删除
作用:对容器进行插入和元素删除
总结:
尾插--push_back 头插--push_front 尾删--pop_back 尾插--pop_front 插入--insert
删除--erase 移除--remove 清空--clear
eg:
#include<iostream>
using namespace std;
#include<list>
#include<string>
void printList(const list<int>&l)
{
for (list<int>::const_iterator it = l.begin(); it != l.end(); it++)
{
cout << *it << ' ';
}
cout << endl;
}
int main()
{
list<int>l;
l.push_back(10);//尾插
l.push_back(20);
l.push_front(10);//头插
l.push_front(20);
printList(l);//20 10 10 20
l.pop_back();//尾删
l.pop_front();//头删
printList(l);//10 10
l.insert(l.begin(), 100);//从链表头插入元素100
printList(l);//100 10 10
l.insert(l.end(), 5, 100);//在表尾插入5个100
printList(l);//100 10 10 100 100 100 100 100
l.erase(l.begin());//删除链表头的元素
printList(l);// 10 10 100 100 100 100 100
l.remove(100);//删除链表中所有数据为100的元素
printList(l);//10 10
l.clear();//清空链表
printList(l);
return 0;
}
list数据存取
可以通过front和back成员函数访问容器的首尾元素,若要遍历各个元素,可以用迭代器进行++的操作,从而遍历容器中所有元素。
注:链表不能随机存取,即list不能用下标/at访问容器中的元素
list反转和排序
作用:可以利用reverse逆置链表或将链表元素排列有序
函数原型:
reverse()--反转
(成员函数)sort()---排序
eg:
#include<iostream>
using namespace std;
#include<list>
#include<string>
void printList(const list<int>&l)
{
for (list<int>::const_iterator it = l.begin(); it != l.end(); it++)
{
cout << *it << ' ';
}
cout << endl;
}
bool compare(int a,int b)
{
return a > b;//当a>b时返回true,即不交换
}
int main()
{
list<int>l;
l.push_back(50);//尾插
l.push_back(20);
l.push_front(10);//头插
l.push_front(30);
printList(l);//30 10 50 20
reverse(l.begin(),l.end());
printList(l);//20 50 10 30
//由于链表不能随机存取,因此不能使用全局函数sort(即只有空间上连续存储的容器才能使用),但list成员函数中提供了排序函数
l.sort();//默认升序
printList(l);//10 20 30 50
l.sort(compare);//若想实现其他排序,则需要自己定义比较函数
printList(l);//50 30 20 10
return 0;
}