1、List
(1)定义
List是一种序列式容器。List容器完成的功能实际上和数据结构中的双向链表是极其相似的,List中的数据元素是通过链表指针串连成逻辑意义上的线性表,也就是List也具有链表的主要优点,即:在链表的任一位置进行元素的插入、删除操作都是快速的。
(2)底层实现
List的实现大概是这样的,类似双向链表,:list的每个节点有三个域:前驱元素指针域、数据域和后继元素指针域。
前驱元素指针域保存了前驱元素的首地址;数据域则是本节点的数据;后继元素指针域则保存了后继元素的首地址。其实,List和循环链表也有相似的地方,即:头节点的前驱元素指针域保存的是链表中尾元素的首地址,List的尾节点的后继元素指针域则保存了头节点的首地址,这样,List实际上就构成了一个双向循环链。
由于List元素节点并不要求在一段连续的内存中,显然在List中是不支持快速随机存取的,因此对于迭代器,只能通过“++”或“--”操作将迭代器移动到后继/前驱节点元素处。而不能对迭代器进行+n或-n的操作,这点是与vector等不同的地方。
(3)使用
使用list容器之前必须加上<list>头文件:#include<list>;
List属于std命名域的内容,因此需要通过命名限定:using std::list;也可以直接使用全局的命名空间方式:using namespace std。
(4)特点
优点:(1)内存不连续;
(2)动态操作,插入与删除效率高;
(3)可在两端进行pop,push。
缺点:(1)不能随机访问;
(2)相对于vector占用内存多(需要存储前驱后继元素指针域)。
2、成员函数
(1)构造函数
/*构造函数*/list() //声明一个空列表;list(n) //声明一个有n个元素的列表,每个元素都是由其默认构造函数T()构造出来的list(n,val) //声明一个由n个元素的列表,每个元素都是由其复制构造函数T(val)得来的list(n,val) //声明一个和上面一样的列表list(first,last) //声明一个列表,其元素的初始值来源于由区间所指定的序列中的元素
(2)赋值操作
assign()://具体和vector中的操作类似,也是有两种情况://第一种是:l1.assign(n,val)将 l1中元素变为n个T(val);//第二种情况是:l1.assign(l2.begin(),l2.end())将l2中的从l2.begin()到l2.end()之间的数值赋值给l1c.assign(n,num);//将n个num拷贝赋值给链表c。c.assign(beg,end);//将[beg,end)区间的元素拷贝赋值给链表c。
示例:
int a[5] = {1,2,3,4,5}; list a1; list ::iterator it; a1.assign(2,10); for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; a1.assign(a,a+5); for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl;
(3)插入操作
push_back();//push_back()从list的末端插入push_front()://push_front()实现的从list的头部插入insert()://在指定位置插入一个或多个元素(三个重载)c.insert(pos,num);//在pos位置插入元素num。c.insert(pos,n,num);//在pos位置插入n个元素num。c.insert(pos,beg,end);//在pos位置插入区间为[beg,end)的元素。
示例:
list a1{1,2,3,4,5}; list ::iterator it; cout << "insert before:"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; a1.insert(a1.begin(),0); cout << "insert(pos,num) after:"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; a1.insert(a1.begin(),2,88); cout << "insert(pos,n,num) after:"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; int arr[5] = {11,22,33,44,55}; a1.insert(a1.begin(),arr,arr+3); cout << "insert(pos,beg,end) after:"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl;
list a1{1,2,3,4,5}; a1.push_back(10); list ::iterator it; cout << "push_back:"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; a1.pop_back(); cout << "pop_back:"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; a1.push_front(20); cout << "push_front:"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; a1.pop_front(); cout << "pop_front:"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl;
(4)删除操作
pop_back();//通过pop_front()删除第一个元素pop_front()://删除最后一个元素//序列必须不为空,如果当list为空的时候调用pop_back()和pop_front()会使程序崩掉。clear(): //清空list中的所有元素。erase()://删除一个元素或一个区域的元素(两个重载)l1.erase(l1.begin()); //将l1的第一个元素删除。l1.erase(l1.begin(),l1.end()); //将l1的从begin()到end()之间的元素删除。remove(num);//删除链表中匹配num的元素remove_if(comp);//删除条件满足的元素,参数为自定义的回调函数unique();//删除相邻的元素
示例:
list a1{1,2,3,4,5}; list ::iterator it; cout << "clear before:"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << "\t"; } cout << endl; a1.clear(); cout << "clear after:"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << "\t"; } cout << endl;
list a1{1,2,3,4,5}; list ::iterator it; cout << "erase before:"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; a1.erase(a1.begin()); cout << "erase after:"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl;
list a1{1,2,3,4,5}; a1.remove(3); list ::iterator it; cout << "remove():"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl;
list a1{1,2,3,4,5}; a1.remove_if([](int n){return n<3;}); list ::iterator it; cout << "remove_if():"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl;
list a1{1,1,3,3,5}; a1.unique(); list ::iterator it; cout << "unique:"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; return 0;
(5)定位操作
begin();//通过调用list容器的成员函数begin()得到一个指向容器起始位置的iteratorend():,//调用list容器的 end()函数来得到list末端下一位置,相当于:int a[n]中的第n+1个位置a[n],//实际上是不存在的,不能访问,经常作为循环结束判断结束条件使用。c.rbegin();//返回逆向链表的第一个元素,即c链表的最后一个数据。c.rend();//返回逆向链表的最后一个元素的下一个位置,即c链表的第一个数据再往前的位置。front();//通过front()可以获得list容器中的头部元素back(): ,//通过back()可以获得list容器的最后一个元素//但是有一点要注意,就是list中元素是空的时候,这时候调用front()和back()会发生什么呢?//实际上会发生不能正常读取数据的情况,但是这并不报错,那我们编程序时就要注意了,建议在使用之前最好先调用empty()函数判断list是否为空。reverse()://通过reverse()完成list的逆置。
示例:
list a1{1,2,3,4,5};list ::iterator it;for(it = a1.begin();it!=a1.end();it++){cout << *it << "\t";}cout << endl;
list a1{1,2,3,4,5};list ::reverse_iterator it;for(it = a1.rbegin();it!=a1.rend();it++){cout << *it << "\t";}cout << endl;
list a1{1,2,3,4,5};if(!a1.empty()){cout << "the first number is:" << a1.front() << endl;cout << "the last number is:" << a1.back() << endl;}
list a1{1,2,3,4,5}; a1.reverse(); list ::iterator it; cout << "reverse:"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl;
(6)数据大小
empty()://利用empty() 判断list是否为空。resize(): //如果调用resize(n)将list的长度改为只容纳n个元素,超出的元素将被删除,//如果需要扩展那么调用默认构造函数T()将元素加到list末端。//如果调用resize(n,val),则扩展元素要调用构造函数T(val)函数进行元素构造,其余部分相同。c.size();//返回链表c中实际元素的个数。c.max_size();//链表c可能容纳的最大元素数量。
示例:
list a1{1,2,3,4,5}; a1.resize(8); list ::iterator it; cout << "resize(n):"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; a1.resize(10, 10); cout << "resize(n,num):"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl;
(7)交换操作
swap():交换两个链表(两个重载),一个是l1.swap(l2); 另外一个是swap(l1,l2),都可能完成连个链表的交换。c1.swap(c2); 将c1和c2交换。swap(c1,c2); 同上。
示例:
list a1{1,2,3,4,5},a2,a3; a2.swap(a1); list ::iterator it; cout << "a2.swap(a1):"; for(it = a2.begin();it!=a2.end();it++){ cout << *it << " "; } cout << endl; swap(a3,a2); cout << "swap(a3,a2):"; for(it = a3.begin();it!=a3.end();it++){ cout << *it << " "; } return 0;
(8)合并操作
merge()://合并两个链表并使之默认升序(也可改),l1.merge(l2,greater ()); //调用结束后l2变为空,l1中元素包含原来l1 和 l2中的元素,并且排好序,升序。//其实默认是升序,greater ()可以省略,另外greater ()是可以变的,也可以不按升序排列。c1.merge(c2);//合并2个有序的链表并使之有序,从新放到c1里,释放c2。c1.merge(c2,comp);//合并2个有序的链表并使之按照自定义规则排序之后从新放到c1中,释放c2。c1.splice(c1.beg,c2);// 将c2连接在c1的beg位置,释放c2c1.splice(c1.beg,c2,c2.beg);//将c2的beg位置的元素连接到c1的beg位置,并且在c2中施放掉beg位置的元素c1.splice(c1.beg,c2,c2.beg,c2.end);//c2的[beg,end)位置的元素连接到c1的beg位置并且释放c2的[beg,end)位置的元素
示例:
list a1{1,2,3},a2{4,5,6}; a1.merge(a2); list ::iterator it; cout << "a1.merge(a2):"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; a2.merge(a1,[](int n1,int n2){return n1>n2;}); cout << "a2.merge(a1,comp):"; for(it = a2.begin();it!=a2.end();it++){ cout << *it << " "; } cout << endl;
list a1{1,2,3},a2{4,5,6}; a1.splice(a1.begin(), a2); list ::iterator it; cout << "a1.merge(a2):"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl;
list a1{1,2,3},a2{4,5,6}; a1.splice(a1.begin(), a2,++a2.begin()); list ::iterator it; cout << "a1.merge(a2):"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; return 0;
list a1{1,2,3},a2{4,5,6}; a1.splice(a1.begin(),a2,a2.begin(),a2.end()); list ::iterator it; cout << "a1.merge(a2):"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; return 0;
(9)排序操作
c.sort() 将链表排序,默认升序c.sort(comp) 自定义回调函数实现自定义排序
示例:
list a1{1,3,2,5,4}; a1.sort(); list ::iterator it; cout << "sort():"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; a1.sort([](int n1,int n2){return n1>n2;}); cout << "sort(function point):"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl;
(10)重载运算符
operator==operator!=operator<=operator>operator>=
示例:
list a1 {1,2,3,4,5},a2;a2 = a1;list ::iterator it;for(it = a2.begin();it!=a2.end();it++){ cout << *it << endl;}