一、概述
list就是C++封装好的双链表,本文主要是记录其具体的使用方法,包括需要包含的头文件,如何定义,每一个成员函数的使用方法。最后以一个demo来展示如何使用list的方法。要使用list,需要包含#include
二、定义
list<int> b; //创建一个空的list
list<int> c(5); //声明一个n个元素的列表,每个元素都是0
list<int> d(n, m); //声明一个n个元素的列表,每个元素都是m
list<int>e(d.begin(),d.end()); //声明一个列表,其元素的初始值来源于由区间所指定的序列中的元素,first和last是迭代器,如他们分别是另外一个list的迭代器。
list<int>f(e); //拷贝另一个list
list<Mytype>g; //声明一个自定义类型的list
三、成员函数
3.1 返回迭代器类的函数
iterator begin(); //返回指向第一个元素的迭代器
iterator end() //返回末尾的迭代器
const reverse_iterator rbegin() //返回指向第一个元素的逆向迭代器
const reverse_iterator rend() //指向list末尾的逆向迭代器
理解上面几个成员函数的用法,其实一张图就搞定:
我们用遍历list时候,用到迭代器,存在一个正向遍历和逆向遍历问题,这4个成员函数就是返回不同位置的迭代器。
例如我们遍历list:
list<int> test;
for (list<int>::iterator it =test.begin(); it != test.end();){
cout<<*it<<endl;
it++;
}
逆向遍历:
list<int> test;
for (list<int>::reverse_iterator it =test.rbegin(); it != test.rend();){
cout<<*it<<endl;
it++;
}
3.2 list的容量相关的成员函数
bool empty ( ) const; //判断list是否为空,若为空返回true
size_type size() const; //返回list个数
size_type max_size () const; //返回list最大容量
void resize ( size_type sz, T c = T());//重新分配lsit的大小。
前面三个都比较好理解,这里重点说下第四个:
如果sz小于目前的size就将多余的值删除;如果sz大于目前的size,就在增加容量,且用c填充。T指的是当前list的类型.
list<int> test;
test.push_back(1);
test.push_back(2);
test.resize(1); //将size定为1,会删除list中的2
test.resize(5,20); //将size定为5,多出的用20填充
3.3 获取list中元素
reference front() noexcept;//返回第一个元素,可以对该元素进行读写
const_reference front() noexcept;//返回第一个元素,只读
reference back ( );//返回最后一个元素,可以对该元素进行读写
const_reference back ( ) const
3.4 操作list相关函数
void assign ( InputIterator first, InputIterator last );//根据迭代器,重新给list分配空间,并赋值
void assign ( size_type n, const T& u) // 分配n个空间,并赋值相同的元素u
void push_front(value_type&& __x);//从头插入一个元素
void push_back(value_type&& __x);//从尾插入一个元素
iterator insert ( iterator position, const T& x );//在position位置处插入元素x
void insert ( iterator position, size_type n, const T& x );//在position位置处开始插入n个x
template <class InputIterator>
void insert ( iterator position, InputIterator first, InputIterator last );//在position之后,插入迭代器fir--last范围的元素
iterator erase ( iterator position );//清除链表中position 处元素
iterator erase ( iterator first, iterator last );//清除链表中[first,last)范围内的元素
void swap ( list<T,Allocator>& lst);//交换两个list
void clear();//清空list
void splice ( iterator position, list<T,Allocator>& x );//将list x中的所有元素插入到调用该函数的position处。List x会被清空。可以理解为将list x插入到调用该函数的position位置
void splice ( iterator position, list<T,Allocator>& x, iterator i );//将x中指向i的位置处的元素插入到list2的position处。X会将i位置处的值删除。
void splice ( iterator position, list<T,Allocator>& x, iterator first, iterator last ); //将x中[first,last)位置处的元素插入到list2的position处,插入范围的list元素会被删除。
void remove ( const T& value );//清除list中的某个元素
template <class Predicate>
void remove_if ( Predicate pred );//在满足Predicate pred返回true值时,移除元素。pred可以是一个返回bool类型的函数,还可以是一个重写operator函数的类
void unique ( );//清除相同元素
template <class BinaryPredicate>
void unique ( BinaryPredicate binary_pred );按照规则binary_pred消除重复值。
void merge ( list<T,Allocator>& x );
template <class Compare>
void merge ( list<T,Allocator>& x, Compare comp );
void sort ( );
template <class Compare>
void sort ( Compare comp );
reverse()//将list中的元素逆置。
至此,列出了所有list成员函数的定义,上面大部分函数从后面的解释,基本能明确其用法,但后面几个会比较晦涩难以理解,即:remove_if,unique,merge,sort四个成员函数。下面会主要对上面一些不太好理解的函数做详细的解释和使用demo说明:
(1) assign的使用:
功能:重新给list分配空间,并赋值。
(1)void assign ( InputIterator first, InputIterator last );//根据迭代器,重新给list分配空间,并赋值
(2)void assign ( size_type n, const T& u) // 分配n个空间,并赋值相同的元素u
list<int> test;
list<int> test2;
list<int> test3;
test.push_back(1);
test.push_back(2);
test3.push_front(2);
test2.assign(test.begin(),test.end());//用法1
for (list<int>::iterator it =test2.begin(); it != test2.end();){
cout<<*it<<endl;
it++;
}
test2.assign(5,4);//用法2
for (list<int>::iterator it =test2.begin(); it != test2.end();){
cout<<*it<<endl;
it++;
}
上面这段demo还包含了push_back和push_front的使用。
(2)insert()的使用:
(1)iterator insert ( iterator position, const T& x );//在position位置处插入元素x
(2)void insert ( iterator position, size_type n, const T& x );//在position位置处开始插入n个x
(3)template
void insert ( iterator position, InputIterator first, InputIterator last );//在position之
功能:从字面意思来看,就是忘list中特定位置插入元素,实施也是如此。
iterator insert ( iterator position, const T& x );//在position位置处插入元素x
void insert ( iterator position, size_type n, const T& x );//在position位置处开始插入n个x
template <class InputIterator>
void insert ( iterator position, InputIterator first, InputIterator last );//在position之后,插入迭代器fir--last范围的元素
使用demo:
list<int>::iterator it2 =test2.begin();
list<int>::iterator it1 =test1.begin();
test1.insert(it1,0);//方式1
test1.insert(it1,5,0);//方式2
test2.insert(it2,test1.begin(),test1.end());//方式2
这里只贴出了关键的代码,详细的代码可以在我上传的文件中得到,这里给出文件链接:
传送门
(3) remove_if
(1)void remove ( const T& value );//清除list中的某个元素
(2)template
void remove_if ( Predicate pred );//在满足Predicate pred返回true值时,移除元素。pred可以是一个返
功能:删除符合自定义规则的元素。该函数实际上是遍历整个list,一一比较每个元素,若元素符合删除的规则,就删除,所以说,我们需要自定义符合删除规则的函数:
struct Student{
int age;
string name;
};
bool delete_rule(const Student& student)
{
return student.age <= 12;
}
int main(){
list<Student> test1;
Student temp;
temp.age = 11;
temp.name = "张三";
test1.push_back(temp);
temp.age = 12;
temp.name = "王五";
test1.push_back(temp);
temp.age = 13;
temp.name = "李四";
test1.emplace_back(temp);//c++11新增的函数,提升效率,如果编译不过,可以换成push_back;
for (list<Student>::iterator it =test1.begin(); it != test1.end();){
cout<<"name:"<<(*it).name<<"age: "<<(*it).age<<endl;
it++;
}
cout<<endl;
test1.remove_if(delete_rule);
for (list<Student>::iterator it =test1.begin(); it != test1.end();){
cout<<"name:"<<(*it).name<<"age: "<<(*it).age<<endl;
it++;
}
}
这里我们根据自己定义的规则删除掉所有年龄小于12的学生。
(4)unique
(1)void unique ( );//清除相同元素
(2)template
void unique ( BinaryPredicate binary_pred );按照规则binary_pred消除重复值。
功能:删除列表中重复的元素,unique会遍历整个list,并对比相邻的元素是否重复。当然“重复”是 可以自定义的,也就是说我们可以自定义所谓重复的规则,如下面这个例子:
有了remove_if的经验,理解unique会容易很多。
注意:再执行unique之前,要先进行排序,因为该函数是对比相邻两个元素是否“重复”;
#include <iostream>
#include <cmath>
#include <list>
// a binary predicate implemented as a function:
bool my_type (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
cout<<"before unique of type1:";
for (std::list<double>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
std::cout << ' ' << *it;
std::cout <<std::endl;
mylist.unique(); // 2.72, 3.14, 12.15, 12.77
// 15.3, 72.25, 73.0, 73.35
cout<<"after unique of type1:";
for (std::list<double>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
std::cout << ' ' << *it;
cout<<endl;
mylist.unique (my_type); // 2.72, 3.14, 12.15
// 15.3, 72.25, 73.0
cout<<"after unique of type2:";
for (std::list<double>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
std::cout << ' ' << *it;
cout<<endl;
mylist.unique (is_near()); // 2.72, 12.15, 72.25
cout<<"after unique of type3:";
for (std::list<double>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
std::cout << ' ' << *it;
cout<<endl;
std::cout << "mylist contains:";
for (std::list<double>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
std::cout << ' ' << *it;
cout<<endl;
return 0;
}
上面这段demo使用了三种去除重复方式。
(6)merge
(1)void merge ( list<T,Allocator>& x );
(2)template
void merge ( list<T,Allocator>& x, Compare comp );
功能:合并其他list到当前list
void merge ( list<T,Allocator>& x );
template <class Compare>
void merge ( list<T,Allocator>& x, Compare comp );
demo:
#include <iostream>
#include <list>
// compare only integral part:
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();
std::cout << "first sort:";
for (std::list<double>::iterator it=first.begin(); it!=first.end(); ++it)
std::cout << ' ' << *it;
cout<<endl;
second.sort();
std::cout << "second sort:";
for (std::list<double>::iterator it=second.begin(); it!=second.end(); ++it)
std::cout << ' ' << *it;
cout<<endl;
first.merge(second);
// (second is now empty)
std::cout << "after merge the first is:";
for (std::list<double>::iterator it=first.begin(); it!=first.end(); ++it)
std::cout << ' ' << *it;
cout<<endl;
std::cout << "after merge the second is:";
for (std::list<double>::iterator it=second.begin(); it!=second.end(); ++it)
std::cout << ' ' << *it;
cout<<endl;
second.push_back (2.1);
first.merge(second,mycomparison);
std::cout << "after merge type2 the first is::";
for (std::list<double>::iterator it=first.begin(); it!=first.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
运行结果:
first sort: 2.2 2.9 3.1
second sort: 1.4 3.7 7.1
after merge the first is: 1.4 2.2 2.9 3.1 3.7 7.1
after merge the second is:
after merge type2 the first is:: 1.4 2.2 2.9 2.1 3.1 3.7 7.1
从结果来看,merge自动给合并完的list排序了,默认是比较大小,在合适位置插入,但这个所谓的合适位置,其实也是我们可以自定义的,上述demo即自定义了规则:mycomparison:即当整数位小于,才插入。可以看到,新插入的数据是在3.1之前插入,因为待插入的数据是2.1,它只比较整数位。
(7)sort
(1)void sort();
(2)template
void sort (Compare comp);
功能:给list排序,默认是使用升序排序。我们也可以自定义比较的规则:
struct Student{
int age;
string name;
bool operator < (Student& b) {
return age < b.age;
}
// 重新定义小于,因为默认的sort函数调用的操作符是<,所以我们只需要重载 < 就好了
};
int main(){
std::list<Student> student;
Student stu;
std::list<Student>::iterator iter;
stu.name ="李";
stu.age = 5;
student.push_back (stu);
stu.name ="张";
stu.age = 9;
student.push_back (stu);
stu.name ="罗";
stu.age = 7;
student.push_back (stu);
stu.name ="王";
stu.age = 25;
student.push_back (stu);
std::cout << "before sort the list is:";
for (std::list<Student>::iterator it=student.begin(); it!=student.end(); ++it)
cout<<(*it).name << ":"<<(*it).age<<endl;;
cout<<endl;
student.sort();
std::cout << "after sort the list is:";
for (std::list<Student>::iterator it=student.begin(); it!=student.end(); ++it)
cout<<(*it).name << ":"<<(*it).age<<endl;;
cout<<endl;
return 0;
}
这里介绍了升序的方法,其实降序,可以直接sort()之后,使用reverse()完成。当然这样会影响速度,后续会继续介绍降序的方法。