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()之间的数值赋值给l1 c.assign(n,num); //将n个num拷贝赋值给链表c。 c.assign(beg,end); //将[beg,end)区间的元素拷贝赋值给链表c。
示例:
int a[5] = {1,2,3,4,5}; list<int> a1; list<int>::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<int> a1{1,2,3,4,5}; list<int>::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<int> a1{1,2,3,4,5}; a1.push_back(10); list<int>::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<int> a1{1,2,3,4,5}; list<int>::iterator it; cout << "clear before:"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; a1.clear(); cout << "clear after:"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; list<int> a1{1,2,3,4,5}; list<int>::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<int> a1{1,2,3,4,5}; a1.remove(3); list<int>::iterator it; cout << "remove():"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; list<int> a1{1,2,3,4,5}; a1.remove_if([](int n){return n<3;}); list<int>::iterator it; cout << "remove_if():"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; list<int> a1{1,1,3,3,5}; a1.unique(); list<int>::iterator it; cout << "unique:"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; return 0;
(5)定位操作
begin(); //通过调用list容器的成员函数begin()得到一个指向容器起始位置的iterator end():, //调用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<int> a1{1,2,3,4,5}; list<int>::iterator it; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; list<int> a1{1,2,3,4,5}; list<int>::reverse_iterator it; for(it = a1.rbegin();it!=a1.rend();it++){ cout << *it << " "; } cout << endl; list<int> 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<int> a1{1,2,3,4,5}; a1.reverse(); list<int>::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<int> a1{1,2,3,4,5}; a1.resize(8); list<int>::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<int> a1{1,2,3,4,5},a2,a3; a2.swap(a1); list<int>::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<int>()); //调用结束后l2变为空,l1中元素包含原来l1 和 l2中的元素,并且排好序,升序。 //其实默认是升序,greater<int>()可以省略,另外greater<int>()是可以变的,也可以不按升序排列。 c1.merge(c2); //合并2个有序的链表并使之有序,从新放到c1里,释放c2。 c1.merge(c2,comp); //合并2个有序的链表并使之按照自定义规则排序之后从新放到c1中,释放c2。 c1.splice(c1.beg,c2); // 将c2连接在c1的beg位置,释放c2 c1.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<int> a1{1,2,3},a2{4,5,6}; a1.merge(a2); list<int>::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<int> a1{1,2,3},a2{4,5,6}; a1.splice(a1.begin(), a2); list<int>::iterator it; cout << "a1.merge(a2):"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; list<int> a1{1,2,3},a2{4,5,6}; a1.splice(a1.begin(), a2,++a2.begin()); list<int>::iterator it; cout << "a1.merge(a2):"; for(it = a1.begin();it!=a1.end();it++){ cout << *it << " "; } cout << endl; return 0; list<int> a1{1,2,3},a2{4,5,6}; a1.splice(a1.begin(),a2,a2.begin(),a2.end()); list<int>::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<int> a1{1,3,2,5,4}; a1.sort(); list<int>::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> operator>=
示例:
list<int> a1 {1,2,3,4,5},a2; a2 = a1; list<int>::iterator it; for(it = a2.begin();it!=a2.end();it++){ cout << *it << endl; }