重点总结
- List使用非连续的内存空间进行存储,具有双链表结构,不支持根据下标随机存取元素。
- List中每个元素中都有一个指针指向后一个元素,也有一个指针指向前一个元素,且由于需要额外维护指针 ,开销也比较大。。
优点:
与vector、deque等容器相比,list在将元素进行插入、删除表现的更好,插入操作如图2所示。缺点:
不能进行内部的随机访问,即不支持[ ]操作符和at() ,如需访问list中的第六个元素,则必须从已知位置(如开始或结束)迭代到该位置
List
std::list 全部函数
assign 修改容器中内容
back 返回指向容器尾元素的迭代器
begin 返回指向容器头的迭代器
capacity 返回容器分配的空间大小
cbegin 返回指向容器头的迭代器-const
cend 返回指向容器尾元素后一个位置的迭代器 - const
clear 清空容器
crbegin 返回指向容器最后一个元素的 逆序 迭代器 - const
crend 返回指向容器头元素前一个位置的 逆序 迭代器 - const
emplace 通过迭代器在指定位置插入新元素,move
emplace_back 在容器尾处插入元素新元素,move
emplace_front 在容器头处插入元素新元素,move
empty 判断容器是否为空
end 返回指向容器尾的迭代器
erase 删除元素
front 返回容器头元素的引用
get_allocator 返回与列表容器关联的分配器对象的副本
insert 插入元素
max_size 返回容器可以容纳的最大元素数
pop_back 删除容器的最后一个元素
pop_front 删除容器的第一个元素
push_back 在容器尾处插入元素,copy
push_front 在容器头处插入元素,copy
rbegin 返回指向容器最后一个元素的 逆序 迭代器
remove() 从list删除元素
remove_if() 按指定条件删除元素
rend 返回指向容器头元素前一个位置的 逆序 迭代器
reserve 改变容器所分配空间的大小
resize 改变容器的大小,如果new_size大于当前容量,则填充默认值
size 返回容器中元素个数
sort 按严格弱排序对容器内元素进行排序,可使用自定义compare函数
splice 将容器x中的元素传输至当前容器,删除容器x中对应元素
swap 当前vector与作为参数的vector交换元素
unique 对于容器中重复元素,删除除第一个元素外的所有元素
1、构造函数、assign()
- 头文件
#include <list>
- <1>. 构造函数,函数原型如下:
explicit list (const allocator_type& alloc = allocator_type()); // 1. default 空的容器
explicit list (size_type n);
list (size_type n, const value_type& val,
const allocator_type& alloc = allocator_type()); // 2. fill
template <class InputIterator>
list (InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type()); // 3. range
list (const list& x); // 4. copy
list (const list& x, const allocator_type& alloc);
list (list&& x); // 5. MOVE
list (list&& x, const allocator_type& alloc);
list (initializer_list<value_type> il,
const allocator_type& alloc = allocator_type()); // 6. initializer list
例子: 注释中序号与上述顺序相同
int main () {
// constructors used in the same order as described above:
std::list<int> first; // [1]
std::list<int> second(4,100); // [2]
std::list<int> third(second.begin(),second.end()); // [3]
std::list<int> fourth(third); // [4] copy
// the iterator constructor can also be used to construct from arrays:
int myints[] = {
16,2,77,29};
std::list<int> fifth (myints, myints + sizeof(myints) / sizeof(int) ); // [6] initializer
std::cout << "The contents of fifth are: ";
for (std::list<int>::iterator it = fifth.begin(); it != fifth.end(); it++)
std::cout << *it << ' ';
return 0;
}
The contents of fifth are: 16 2 77 29
- <2>. assign(),函数原型如下:
template <class InputIterator>
void assign(InputIterator first, InputIterator last); // 1. range
void assign(size_type n, const value_type& val); // 2. fill
void assign(initializer_list<value_type> il); // 3. initializer list
例子: 注释中序号与上述顺序相同
int main () {
std::list<int> first;
std::list<int> second;
first.assign(7,100); // [1]. 7 ints with value 100
std::cout << "Size of first: " << int (first.size()) << '\n';
second.assign(first.begin(),first.end()); // [2]. a copy of first
std::cout << "Size of second: " << int (second.size()) << '\n';
int myints[]={
1776,7,4};
first.assign(myints,myints+3); // [3]. first已有元素,assign清空容器,添加新元素,改变size
std::cout << "Size of first: " << int (first.size()) << '\n';
return 0;
}
Size of first: 7
Size of second: 7
Size of first: 3
2、插入 insert, push(pop), emplace
2.1 push_*()
、pop_*()
push_front()、push_back()
,在容器头、尾通过copy
添加元素;pop_front()、pop_back()
,在容器头、尾删除元素,函数原型如下。
void push_back(const value_type& val);
void push_back(value_type&& val); // push_back
void push_front(const value_type& val);
void push_front(value_type&& val); // push_front
void pop_back(); // pop_back
void pop_front(); // pop_front
int main () {
std::list<int> mylist(2,200); // two ints with a value of 100
mylist.push_front(100);
mylist.push_back(300);
// push
std::cout << "push:";
for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
std::cout << ' ' << *it;
mylist.pop_front();
mylist.pop_back();
std::cout << "\npop:";
for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
push: 100 200 200 300
pop: 200 200
2.2 insert
insert()
: 在容器内部添加元素。使用方法与其他序列容器相似,函数原型如下。
// [1] 在迭代器指定位置插入新的元素val. 迭代器指向的元素及后续元素-后移
iterator insert(const_iterator position, const value_type& val);
// [2] 在迭代器指定位置插入几个相同元素val.
iterator insert(const_iterator position, size_type n, const value_type& val);
// [3] 在迭代器指定位置前插入 另一个容器的 Iterator.first 至 Iterator.last 的元素.
template <class InputIterator>
iterator insert(const_iterator position, InputIterator first, InputIterator last);
// 右值
iterator insert(const_iterator position, value_type&& val);
// list
iterator insert(const_iterator position, initializer_list<value_type> il);
例子:
int main () {
std::list<int> mylist{
1,2,3,4,5};
std::list<int>::iterator it;
it = ++mylist.begin(); // it 指向元素2, 用 ^ 表示
mylist.insert(it, 10); // 1 10 2 3 4 5
// ^
mylist.insert(it,2,20); // 1 10 20 20 2 3 4 5
// ^
std::cout << "*it-value:" << *it << std::endl;
--it; // it 指向元素20
std::vector<int> myvector(2,30);
mylist.insert (it, myvector.begin(), myvector.end());
// 1 10 20 30 30 20 2 3 4 5
// ^
std::cout << "mylist contains:";
for (it=mylist.begin(); it!=mylist.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
*it-value:2
mylist contains: 1 10 20 30 30 20 2 3 4 5
重点:
可以看出,通过参数iterator
进行insert
操作,插入结束时,作为参数的迭代器iterator
指向的元素保存不变,说明函数内部在进行插入时,作为参数的迭代器随插入元素的个数后移。insert
函数返回的迭代器,指向新插入元素中的第一个的元素的位置。测试代码如下:
int main () {
std::list<int> mylist{
1,2,3,4,5};
std::list<int>::iterator it = mylist.begin();
auto iter = mylist.insert(it, 2, 10); // 10 10 1 2 3 4 5
std::cout << "参数迭代器指向元素:" << *it << std::endl;
std::cout << "返回迭代器指向元素:" << *iter << std::endl;
return 0;
}
参数迭代器指向元素:1
返回迭代器指向元素:10
2.3 emplace_*()
emplace_*()
方法通过move
插入元素,提高效率,其函数原型如下:
template <class... Args>
void emplace_back(Args&&... args); // 1. emplace_back
template <class... Args>
void emplace_front(Args&&... args); // 2. emplace_front
template <class... Args> // 3. 在指定的位置进行操作
iterator emplace(const_iterator position, Args&&... args);
例子:
int main () {
std::list<std:: string> listOne {
"B", "C", "D", "E"};
listOne.emplace_front("A"); // 1. A B C D E
listOne.emplace_back("100"); // 2. A B C D E Z
listOne.emplace(begin(listOne), "Name"); // 3. Name A B C D E Z 200
for (auto& i:listOne)
std::cout << i << " ";
return 0;
}
Name A B C D E 100
3、删除 erase、remove、remove_if
clear()
删除list中所有元素,使用后list.size()
为0;
3.1 erase
erase()
方法可以删除容器中元素,返回一个迭代器,该迭代器指向被删除位置后的一个元素。- 若
erase()
删除了List
中最后一个元素,则返回List.end()
。函数原型如下:
iterator erase(const_iterator position);
iterator erase(const_iterator first, const_iterator last);
通过迭代器删除所有元素:
int main() {
list<int> listOne{
1,2,4,4,5,6};
// 错误试列
// erase()之后对应位置的迭代器已经失效,这时 iter++ 将无法找到下一个元素。
for (list<int>::iterator iter=listOne.begin(); iter!=listOne.end(); ++iter)
listOne.erase(iter);
// 正确示例
for (list<int>::iterator iter=listOne.begin(); iter!=listOne.end(); ){
iter = listOne.erase(iter); // 或: listOne.erase(iter++);
}
return 0;
}
3.2 remove
remove()
: 从列表容器中删除与val
值相等的元素,减小容器的大小,其减小的长度等于被删除的元素的个数,原型如下:
void remove (const value_type& val);
例子:
int main () {
std::list<int> listOne{
1,2,3,4,5,6};
std::cout << "listOne: ";
for (auto& iter:listOne)
std::cout << iter << " "; // .size() = 6
listOne.remove(2);
std::cout << "\nlistOne: ";
for (auto& iter:listOne)
std::cout << iter << " "; // .size() = 5
return 0;
}
listOne: 1 2 3 4 5 6
listOne: 1 3 4 5 6
3.4 remove_if
remove_if()
: 删除容器中所有满足条件的元素,原型如下:
template <class Predicate>
void remove_if(Predicate pred);
- 使用方式:
- www.cplusplus.com : 从容器中移除谓词pred 返回
true
的所有元素。这将调用这些对象的析构函数,并通过移除的元素数减少容器大小。 - 该函数为每个元素调用
pred(*iter)
,其中iter
是该元素对应的迭代器。列表中返回true
的元素都将从容器中移除。 - 例子如下
// list::remove_if
#include <iostream>
#include <list>
// ### 方法一对应函数 ###
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};
std::list<int> mylist(myints,myints+8); // 15 36 7 17 20 39 4 1
// 方法一,返回true的元素被删除
mylist.remove_if(single_digit); // 15 36 17 20 39
// 方法二,参数为is_odd::operator()函数
mylist.remove_if(is_odd()); // 36 20
// list 打印函数
std::cout << "mylist contains:";
for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
mylist contains: 36 20
4、特殊函数 swap、sort、splice、unique
- 这几个函数里
swap
最易理解,当前容器与参数容器中元素相交换。 - 函数原型为:
void swap (list& x);
int main () {
std::list<int> first(3,100); // three ints with a value of 100
std::list<int> second(5,200); // five ints with a value of 200
first.swap(second);
std::cout << "first contains:";
for (std::list<int>::iterator it=first.begin(); it!=first.end(); it++)
std::cout << ' ' << *it;
std::cout << '\n';
std::cout << "second contains:";
for (std::list<int>::iterator it=second.begin(); it!=second.end(); it++)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
first contains: 200 200 200 200 200
second contains: 100 100 100
4.1 sort
sort()
: 比较容器中的元素大小(严格的元素弱排序),更改其在容器中的位置。- 参数
comp
:第一个参数严格弱于第二个参数,返回true
,否则返回false
。 - ps:
“<”
操作符是一个严格弱序,而“<=”
就不是一个严格弱序。
void sort(); // 使用operator < 比较元素,执行排序
template <class Compare>
void sort(Compare comp); // 使用comp 函数比较元素,执行排序
bool compare_nocase (const std::string& first, const std::string& second) {
unsigned int i=0;
// tolower是<ctype.h>中函数: 把给定的字母转换为小写字母
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;
}
mylist contains: Three one two
mylist contains: one Three two // ASCII: A-65, a-97
4.2 splice
splice()
:将元素从x中传输到当前容器中,按位置位置插元素。- 元素插入当前容器后,x中对应元素将被删除,两个容器的.size()将会改变。
- 容器x无论是左值or右值,
splice()
函数都将支持元素传递。
// 1. 将x的所有元素都转移到 当前容器中。
void splice(const_iterator position, list& x);
void splice(const_iterator position, list&& x);
// 2. 仅将i指向的元素从x传输到 当前容器中。
void splice(const_iterator position, list& x, const_iterator i);
void splice(const_iterator position, list&& x, const_iterator i);
// 3. 将范围[first,last)的元素从x传输到 当前容器中。
void splice(const_iterator position, list& x,
const_iterator first, const_iterator last);
void splice(const_iterator position, list&& x,
const_iterator first, const_iterator last);
int main () {
std::list<int> mylist1, mylist2;
std::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
// [1]
mylist1.splice(it, mylist2); // mylist1: 1 10 20 30 2 3 4
// mylist2.size() = 0
// "it" still points to 2 (the 5th element)
// [2]
mylist2.splice(mylist2.begin(), mylist1, it);
// mylist1: 1 10 20 30 3 4
// mylist2: 2
// "it" 现在是无效的了
it = mylist1.begin();
std::advance(it, 3); // "it" points now to 30,函数功能: 将 it 迭代器前进或后退 n 个位置。
// [3].
mylist1.splice ( mylist1.begin(), mylist1, it, mylist1.end());
// mylist1: 30 3 4 1 10 20
std::cout << "mylist1 contains:";
for (it=mylist1.begin(); it!=mylist1.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
std::cout << "mylist2 contains:";
for (it=mylist2.begin(); it!=mylist2.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
mylist1 contains: 30 3 4 1 10 20
mylist2 contains: 2
4.3 unique
unique()
: 对于容器中重复元素,删除除第一个元素外的所有元素。- 对于自定义二元谓词(
Binary Predicate
)函数,作为传入参数的两个值,返回true
则删除第一个参数,否则返回false
。
void unique();
template <class BinaryPredicate>
void unique (BinaryPredicate binary_pred);
// 函数1-BinaryPredicate
bool same_integral_part(double first, double second){
return ( int(first)==int(second) );
}
// 作为对象实现的-BinaryPredicate
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(); // 1. 默认版本
// 2.72, 3.14, 12.15, 12.77, 15.3, 72.25, 73.0, 73.35
mylist.unique(same_integral_part); // 2. int(element) 比较元素是否相等
// 2.72, 3.14, 12.15, 15.3, 72.25, 73.0
mylist.unique(is_near()); // 3. 两元素差<5, 则认为相等
// 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;
}
mylist contains: 2.72 12.15 72.25