注:读者在阅读本文前,需要有 vector 容器的基础。想学习 vector 请看博主的另一篇文章:https://blog.youkuaiyun.com/qq_41291253/article/details/89840185
一、list 简介
链表是顺序容器,允许在序列中的任何位置进行恒定时间插入和擦除操作,并在两个方向上进行迭代。
链表容器实现为双向链表; 双向链表可以将它们包含的每个元素存储在不同且不相关的存储位置中。顺序通过链接的每个元素之间的关联保持在内部,即指向前面元素的链接,和指向后面元素的链接。
list 与forward_list非常相似:主要区别在于forward_list对象是单链接列表,因此forward_list只能向前迭代,以换取更小和更高效。
与其他基本标准顺序容器vector和deque相比,list在插入,提取和移动任何位置的元素方面通常表现更好,因此也是在大量使用操作元素的算法中,例如排序算法。和其他容器相比list s和forward_list s 的主要缺点是它们无法通过位置直接访问元素; 例如,访问列表中的第六个元素,必须从已知位置(如开始或结束)迭代到该位置,该位置在这些位置之间的距离中采用线性时间。它们还消耗一些额外的内存来保持与每个元素相关联的链接信息(这可能是大型小型元素列表的重要因素)。
序列:序列容器中的元素按严格的线性顺序排序。各个元素按其顺序访问它们的位置。
双向链表:每个元素保存有关如何定位下一个和前一个元素的信息,允许在特定元素之前或之后(甚至整个范围)进行恒定时间插入和擦除操作,但不允许直接随机访问。
分配器感知:容器使用allocator对象来动态处理其存储需求。
二、函数简介
list member function | |||||||||
iterators: | capacity: | element access | modifiers: | operations: | |||||
begin | 返回容器中第一个元素的迭代器 | size | 返回容器中元素数量 | front | 获取队头元素 | assign | 分配元素 | splice | 从列表到列表传输元素 |
end | 返回容器中最后一个元素的迭代器 | max_size | 返回容器能存储最大元素数量 | back | 获取队尾元素 | push_back | 在队尾压入元素 | remove | 删除具有特定值的元素 |
rbegin | 返回容器中最后一个元素的反向迭代器 | resize | 调整容器大小以使其包含指定大小元素 | push_front | 在队头压入元素 | remove_if | 删除满足条件的元素 | ||
rend | 返回容器中第一个元素的反向迭代器 | empty | 判断容器是否为空 | pop_back | 弹出队尾元素 | unique | 删除重复值 | ||
pop_front | 弹出队首元素 | merge | 合并排序列表 | ||||||
insert | 在指定位置插入元素 | sort | 合并排序列表 | ||||||
erase | 删除指定位置元素 | reverse | 反转元素的顺序 | ||||||
swap | 交换两个队列元素 | ||||||||
clear | 清空队列 |
目录
std::list::begin-->std::list::push_frond-->std::list::pop_front-->std::list::splice-->std::list::remove-->std::list::remove_if-->std::list::unique-->std::list::merge-->std::list::sort-->std::list::reverse
三、函数详解
std::list::begin
iterator begin();
将迭代器返回到开头,返回指向列表容器中第一个元素的迭代器。
请注意,与成员list :: front不同,它返回对第一个元素的引用,该函数返回指向它的双向迭代器。
如果容器为空,则不应取消引用返回的迭代器值。
// list::begin
#include <iostream>
#include <list>
int main ()
{
int myints[] = {75,23,65,42,13};
std::list<int> mylist (myints,myints+5);
std::cout << "mylist contains:";
for (std::list<int>::iterator it=mylist.begin(); it != mylist.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
//output:
//mylist contains: 75 23 65 42 13
std::list::push_frond
void push_front(const value_type&val);
//val - 要复制(或移动)到插入元素的值。
//成员类型value_type是容器中元素的类型,在列表中定义为其第一个模板参数(T)的别名。
在开头插入元素,在列表的开头插入一个新元素,就在它当前的第一个元素之前。val的内容被复制(或移动)到插入的元素。
这有效地将容器尺寸增加了一位。
// list::push_front
#include <iostream>
#include <list>
int main ()
{
std::list<int> mylist (2,100); // two ints with a value of 100
mylist.push_front (200);
mylist.push_front (300);
std::cout << "mylist contains:";
for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
//output:
// 300 200 100 100
std::list::pop_front
void pop_front();
删除第一个元素,删除列表容器中的第一个元素,有效地将其大小减小一个。
这会破坏已删除的元素,使指向该元素的迭代器失效。
// list::pop_front
#include <iostream>
#include <list>
int main ()
{
std::list<int> mylist;
mylist.push_back (100);
mylist.push_back (200);
mylist.push_back (300);
std::cout << "Popping out the elements in mylist:";
while (!mylist.empty())
{
std::cout << ' ' << mylist.front();
mylist.pop_front();
}
std::cout << "\nFinal size of mylist is " << mylist.size() << '\n';
return 0;
}
//output:
//Popping out the elements in mylist: 100 200 300
//Final size of mylist is 0
std::list::splice
entire list (1) | |
---|---|
single element (2) | |
element range (3) | |
从列表到列表传输元素,将元素从 x 转移到容器中,将它们插入到指定位置。
这有效地将这些元素插入容器中并将其从 x 中移除(x 链表变空或删除部分元素),从而改变两个容器的大小。该操作不涉及任何元素的构造或破坏。无论x是左值还是右值,或者value_type是否支持move-construction ,它们都会被转移。
- 第一个版本(1)将x的所有元素传输到容器中。
- 第二个版本(2)仅传输元件指出通过我从X进入容器。
- 第三个版本(3)的范围内传送[first,last)从X到容器中。
#include <iostream>
#include <list>
using namespace std;
/*================================================
函数功能:将一个链表的部分元素或全部元素合并到另一个链表中
函数参数:position - 在容器中放置 x 元素的位置。
成员类型iterator和const_iterator是指向元素的双向迭代器类型。
x - 与被插入列表相同类型(即,使用相同的模板的参数,的对象Ť和的Alloc)。
如果位置指向未实际拼接的元素,则此参数可以是* this(对于第一个版本,情况绝对不是这样,但对于其他版本,这是可能的)。
i - x中迭代器的元素。仅转移此单个元素。iterator是一个成员类型,定义为双向迭代器类型。
first & last - 迭代器指定x中的一系列元素。将[first,last]范围内的元素转移到位置。
请注意,该范围包括所有的元件第一和最后一个,包括由指向的元件第一但不是一个由指向最后。
成员类型iterator和const_iterator是指向元素的双向迭代器类型。
函数返回:无
迭代器有效性:在调用之前,与容器相关的迭代器,指针和引用没有任何变化。
引用传递元素的迭代器,指针和引用继续引用那些相同的元素,但迭代器现在迭代到已转移元素的容器中。
===============================================*/
int main()
{
list<int> mylist1, mylist2;
list<int>::iterator it;
// set some initial values:
for (int i=1; i<=4; ++i)
mylist1.push_back(i); // mylist1: 1 2 3 4
for (int i=1; i<=3; ++i)
mylist2.push_back(i*10); // mylist2: 10 20 30
it = mylist1.begin();
++it; // points to 2
mylist1.splice (it, mylist2); // mylist1: 1 10 20 30 2 3 4
// mylist2 (empty)
// "it" still points to 2 (the 5th element)
mylist2.splice (mylist2.begin(), mylist1, it);
// mylist1: 1 10 20 30 3 4
// mylist2: 2
// "it" still points to 2.
it = mylist1.begin();
advance(it,3); // "it" points now to 30
mylist1.splice ( mylist1.begin(), mylist1, it, mylist1.end());
// mylist1: 30 3 4 1 10 20
// 在这里对迭代器有效性做进一步解释;
// 上条语句中的 it 既是引用传递元素的迭代器,其中 mylist1是要传递的链表,
// it 是传递链表中要传递元素的其实位置在这里指向 30,传递后迭代器继续指向该元素 30。
cout << "\"it\" points now to: " << *it << endl;
cout << "mylist1 contains:";
for (it = mylist1.begin(); it != mylist1.end(); ++it)
cout << ' ' << *it;
cout << '\n';
cout << "mylist2 contains:";
for (it = mylist2.begin(); it != mylist2.end(); ++it)
cout << ' ' << *it;
cout << '\n';
return 0;
}
/*==================================================
output:
"it" points now to: 30
mylist1 contains: 30 3 4 1 10 20
mylist2 contains: 2
==================================================*/
std::list::remove
void remove(const value_type&val);
//val - 要删除的元素的值。
//成员类型value_type是容器中元素的类型,在列表中定义为其第一个模板参数(T)的别名。
删除具有特定值的元素,从容器中删除所有比较等于val的元素。这将调用这些对象的析构函数,并通过删除的元素数减少容器大小。
与成员函数list :: erase不同,它按位置(使用迭代器)擦除元素,此函数(list :: remove)按值删除元素。存在类似的函数list :: remove_if,它允许除了相等比较之外的条件来确定是否删除了元素。
#include <iostream>
#include <list>
using namespace std;
/*================================================
函数功能:删除具有特定值的元素
迭代器有效性:引用该函数删除的元素的迭代器,指针和引用无效。
所有其他迭代器,指针和引用保持其有效性。
===============================================*/
int main()
{
int myints[] = {17, 89, 7, 14};
list<int> mylist (myints, myints+4);
list<int>::iterator it;
it = mylist.begin();
it++;
cout << *it << endl; //迭代器指向元素 89
mylist.remove(89);
cout << *it << endl; //引用该元素的的迭代器失效
it++;
cout << *it << endl;
cout << "mylist contains:";
for (list<int>::iterator it = mylist.begin(); it != mylist.end(); ++it)
cout << ' ' << *it;
cout << '\n';
return 0;
}
/*==================================================
output:
89
89
0
mylist contains: 17 7 14
==================================================*/
std::list::remove_if
template <class Predicate>
void remove_if(Predicate pred);
//pred - 一元谓词,取与forward_list对象中包含的值相同的值,对于要从容器中删除的值返回true,对于剩余的值返回false。
//这可以是函数指针或函数对象。
删除符合条件的元素,从容器中删除Predicate pred返回true的所有元素。这将调用这些对象的析构函数,并通过删除的元素数减少容器大小。
该函数为每个元素调用pred(* i)(其中i是该元素的迭代器)。列表中返回true的任何元素都将从容器中删除。
#include <iostream>
#include <list>
using namespace std;
/*================================================
函数功能:删除符合条件的元素
迭代器有效性:引用该函数删除的元素的迭代器,指针和引用无效。
所有其他迭代器,指针和引用保持其有效性。
===============================================*/
// a predicate implemented as a function:
bool single_digit (const int& value) { return (value < 10); }
// a predicate implemented as a class:
struct is_odd {
bool operator() (const int& value) { return (value % 2) == 1; }
};
int main ()
{
int myints[]= {15,36,7,17,20,39,4,1};
list<int> mylist (myints, myints + 8); // 15 36 7 17 20 39 4 1
mylist.remove_if (single_digit); // 15 36 17 20 39
mylist.remove_if (is_odd()); // 36 20
cout << "mylist contains:";
for (list<int>::iterator it = mylist.begin(); it != mylist.end(); ++it)
cout << ' ' << *it;
cout << '\n';
return 0;
}
/*==================================================
output:
mylist contains: 36 20
==================================================*/
std::list::unique
(1) | |
---|---|
(2) | |
注: binary_pred - 二进制谓词,取两个与列表中包含的值相同的值,返回true以从容器中删除作为第一个参数传递的元素,否则返回false。这应该是一个函数指针或一个函数对象。
删除重复值
没有参数(1)的版本从容器中每个连续的相等元素组中删除除第一个元素之外的所有元素。请注意,只有元素与其前面的元素进行比较时,才会从列表容器中删除该元素。因此,此功能对排序后的列表特别有用。
第二个版本(2)将特定比较函数作为参数,该函数确定元素的“唯一性”。实际上,任何行为都可以实现(而不仅仅是相等比较),但请注意该函数将从将从列表中获取的所有元素对调用binary_pred(* i,*(i-1))(其中i是元素的迭代器) ,从第二个开始)如果谓词返回true则删除该元素。
删除的元素被销毁。
// list::unique
#include <iostream>
#include <cmath>
#include <list>
// a binary predicate implemented as a function:
bool same_integral_part (double first, double second)
{ return ( int(first)==int(second) ); }
// a binary predicate implemented as a class:
struct is_near {
bool operator() (double first, double second)
{ return (fabs(first-second)<5.0); }
};
int main ()
{
double mydoubles[]={ 12.15, 2.72, 73.0, 12.77, 3.14,
12.77, 73.35, 72.25, 15.3, 72.25 };
std::list<double> mylist (mydoubles,mydoubles+10);
mylist.sort(); // 2.72, 3.14, 12.15, 12.77, 12.77,
// 15.3, 72.25, 72.25, 73.0, 73.35
mylist.unique(); // 2.72, 3.14, 12.15, 12.77
// 15.3, 72.25, 73.0, 73.35
mylist.unique (same_integral_part); // 2.72, 3.14, 12.15
// 15.3, 72.25, 73.0
mylist.unique (is_near()); // 2.72, 12.15, 72.25
std::cout << "mylist contains:";
for (std::list<double>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
//output:
// 2.72, 12.15, 72.25
std::list::merge
(1) | |
---|---|
(2) | |
合并排序列表
将以排序x的所有元素转移到容器中,将x合并到列表中(两个容器都已经定义)。
这有效地删除了x中的所有元素(变为空),并将它们插入到容器内的有序位置(其大小按传输的元素数量扩展)。在不构造或销毁任何元素的情况下执行操作:无论x是左值还是右值,或者value_type是否支持move-construction ,都会传输它们。
具有两个参数(2)的模板具有相同的行为,但是采用特定谓词(comp)来执行元素之间的比较操作。这种比较应产生严格的元素弱排序(即,一致的传递性比较,而不考虑其反射性)。
此函数要求列表容器的元素在调用之前已按值(或通过comp)排序。有关无序列表的替代方法,请参阅list :: splice。
假设这样的排序,x的每个元素根据严格的弱排序插入到与其值对应的位置由operator <或comp定义。得到的等价元素的顺序是稳定的(即,等效元素保留它们在调用之前的相对顺序,并且现有元素在从x插入的等效元素之前)。
如果(&x == this),该函数不执行任何操作。
#include <iostream>
#include <list>
using namespace std;
/*================================================
函数功能:删除符合条件的元素
函数参数:x - 链表相同类型(即,使用相同的模板的参数,的对象T和的Alloc)。
请注意,无论是否传递左值或右值引用,此函数都会修改x。
comp - 二进制谓词,如果第一个参数被认为是在它定义的严格弱顺序中的第二个参数之前,
则取两个与列表中包含的值相同的值,返回true,否则返回false。
这应该是一个函数指针或一个函数对象。
迭代器有效性:在调用之前,与容器相关的迭代器,指针和引用没有任何变化。
引用传递元素的迭代器,指针和引用继续引用那些相同的元素,但迭代器现在迭代到已转移元素的容器中。
===============================================*/
bool mycomparison (double first, double second)
{ return ( int(first) < int(second) ); }
int main ()
{
std::list<double> first, second;
first.push_back (3.1);
first.push_back (2.2);
first.push_back (2.9);
second.push_back (3.7);
second.push_back (7.1);
second.push_back (1.4);
first.sort();
second.sort();
first.merge(second);
// (second is now empty)
second.push_back (2.1);
first.merge(second,mycomparison);
cout << "first contains:";
for (list<double>::iterator it = first.begin(); it != first.end(); ++it)
cout << ' ' << *it;
cout << '\n';
return 0;
}
/*==================================================
output:
first contains: 1.4 2.2 2.9 2.1 3.1 3.7 7.1
请注意,在第二次合并中,函数mycomparison(仅比较整数部分)不考虑2.1低于2.2或2.9,因此它在3.1之后插入它们之后。
对 float 类型取整,整数值是什么既是什么,不考虑小数
==================================================*/
std::list::sort
(1) | |
---|---|
(2) | |
在容器中排序元素,对列表中的元素进行排序,改变它们在容器中的位置。
排序算法是通过使用opretor<(版本(1))或comp(版本(2))来比较元素来执行的。这种比较应产生严格的元素弱排序(即,一致的传递性比较,而不考虑其反射性)。
得到的等价元素的顺序是稳定的:即,等效元素保留它们在调用之前的相对顺序。
整个操作不涉及任何元素对象的构造,销毁或复制。元素在容器内移动。
// list::sort
#include <iostream>
#include <list>
#include <string>
#include <cctype>
// comparison, not case sensitive.
bool compare_nocase (const std::string& first, const std::string& second)
{
unsigned int i=0;
while ( (i<first.length()) && (i<second.length()) )
{
if (tolower(first[i])<tolower(second[i])) return true;
else if (tolower(first[i])>tolower(second[i])) return false;
++i;
}
return ( first.length() < second.length() );
}
int main ()
{
std::list<std::string> mylist;
std::list<std::string>::iterator it;
mylist.push_back ("one");
mylist.push_back ("two");
mylist.push_back ("Three");
mylist.sort();
std::cout << "mylist contains:";
for (it=mylist.begin(); it!=mylist.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
mylist.sort(compare_nocase);
std::cout << "mylist contains:";
for (it=mylist.begin(); it!=mylist.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
//output
//mylist contains: Three one two
//mylist contains: one Three two
注:对于默认字符串,比较是严格的字符代码比较,其中所有大写字母的比较低于所有小写字母,在第一个排序操作之前将所有字符串以大写字母开头。
使用compare_nocase函数,比较不区分大小写。
std::list::reverse
void reverse();
反转元素的顺序
// reversing list
#include <iostream>
#include <list>
int main ()
{
std::list<int> mylist;
for (int i=1; i<10; ++i) mylist.push_back(i);
mylist.reverse();
std::cout << "mylist contains:";
for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
//output
//mylist contains: 9 8 7 6 5 4 3 2 1