list
1.双向循环链表list的原理:
list是双向循环链表,每个元素都知道前面一个元素和后面一个元素。在STL中,list和vector一样是俩个常用的容器。和vector不一样的是:list不支持对元素的任意存取。list中提供的成员函数与vector类似,不过list提供对首元素的操作push_front,pop_front,这个vector不具备的。和vector另一点不同的是,list的迭代器不会存在失效的情况,它不像vector会保留备份空间,在超过容量额度时会重新全部分配内存,导致迭代器失效;list没有备份空间的概念,出入一个元素就申请一个元素的空间,所以它的迭代器不会失效。
例如:
int data[6]={3,5,7,9,2,4};
list<int>l(data,data+6);
l.push_back(6);
list初始化时,申请的空间大小为6,存放了data中的6个元素,当向l中插入第七个元素“6”时,list申请新的节点单元,插入list链表中。
如图:
list每次增加一个元素,不存在重新申请内存的情况,它的成本是恒定的。而vector没当增加关键元素的时候,都需要重新申请新的更大的内存空间,会调用元素的自身的复制构造函数,存在构造成本。在销毁旧内存的时候,会调用析构函数,存在析构成本。所以存储复杂类型和大量元素的情况下,list比vector更有优势。
list是一个双向链表,双向链表既可以向前又可以向后链接其他元素。
list将元素按顺序储存在链表中,与向量(vector)相比,它允许快速的插入和删除,但是随机访问却比较慢。
2.list的初始化:
list<int>li(); //申请一个空列表;
list<int>li(n); //声明一个有n个元素的列表,每个元素都有其默认构造函数T()构造出来的;
list<int>li(n,val); //声明一个由n个元素的列表,每个元素都是由其复制构造函数T(val)而来
list<int>li(first,last); //声明一个列表,其元素的初始值来源由区间所指定的序列中的元素
3.list的函数:
a:
crbegin/crend
cbegin/cend
这个4个是c++11新增的四个函数,在set那篇博客有详细的解释。
b:begin()和end()
通过调用list容器的成员函数begin()得到一个指向容器起始位置的iterator,可以调用list容器的 end() 函数来得到list末端下一位置,相当于:int a[n]中的第n+1个位置,实际上是不存在的,不能访问,经常作为循环结束判断结束条件使用。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a[]={1,2,3,4};
list<int>l(a,a+4);
for(list<int>::iterator it=l.begin();it!=l.end();++it){
cout<<*it<<" ";
}
cout<<endl;
for(auto &it:l){
cout<<it<<endl;
}
return 0;
}
c:push_back() 和push_front()
使用list的成员函数push_back和push_front插入一个元素到list中。其中push_back()从list的末端插入,而 push_front()实现的从list的头部插入。
d:front()和back()
通过front()可以获得list容器中的头部元素,通过back()可以获得list容器的最后一个元素。但是有一点要注意,就是list中元素是空的时候,这时候调用front()和back()会发生什么呢?实际上会发生不能正常读取数据的情况,但是这并不报错,那我们编程序时就要注意了,个人觉得在使用之前最好先调用empty()函数判断list是否为空。
e:pop_back和pop_front()
通过删除最后一个元素,通过pop_front()删除第一个元素;序列必须不为空,如果当list为空的时候调用pop_back()和pop_front()会使程序崩掉。
f: empty()
利用empty() 判断list是否为空。
g:clear()
清空list中的所有元素。
#include<bits/stdc++.h>
using namespace std;
int main()
{
list<int>p(2,0);
p.push_back(2);
p.push_front(1);
int len=p.size();
cout<<"p的长度="<<len<<endl;
for(auto &it:p){
cout<<it<<" ";
}
cout<<endl;
cout<<"头部元素="<<p.front()<<endl;
cout<<"尾部元素="<<p.back()<<endl;
p.pop_back();
p.pop_front();
for(auto &it:p){
cout<<it<<" ";
}
cout<<endl;
if(!p.empty()) cout<<"容器p不为空"<<endl;
p.clear();
if(p.empty()) cout<<"容器p为空"<<endl;
return 0;
}
h:resize()
如果调用resize(n)将list的长度改为只容纳n个元素,超出的元素将被删除,如果需要扩展那么调用默认构造函数T()将元素加到list末端。如果调用resize(n,val),则扩展元素要调用构造函数T(val)函数进行元素构造,其余部分相同。
#include<bits/stdc++.h>
using namespace std;
int main()
{
list<int>p;
for(int i=1;i<10;i++) p.push_back(i);
p.resize(5);
p.resize(8,100);
p.resize(12);
for(auto &it:p) cout<<it<<" ";
return 0;
}
1 2 3 4 5 100 100 100 0 0 0 0
i:assign()
具体和vector中的操作类似,也是有两种情况,第一种是:l1.assign(n,val)将 l1中元素变为n个T(val)。第二种情况是:l1.assign(l2.begin(),l2.end())将l2中的从l2.begin()到l2.end()之间的数值赋值给l1。
#include<bits/stdc++.h>
using namespace std;
int main()
{
list<int>first;
list<int>second;
first.assign(7,100);
for(auto &it:first) cout<<it<<" ";
cout<<endl;
second.assign(first.begin(),first.end());
for(auto &it:second) cout<<it<<" ";
cout<<endl;
int a[]={1,2,3};
first.assign(a,a+3);
for(auto &it:first) cout<<it<<" ";
cout<<endl;
return 0;
}
j:reverse():
通过reverse()完成list的逆置。
k:swap()
交换两个链表(两个重载),一个是l1.swap(l2); 另外一个是swap(l1,l2),都可能完成连个链表的交换。
#include<bits/stdc++.h>
using namespace std;
int main()
{
list<int>first;
list<int>second;
first.assign(7,100);
second.assign(2,200);
first.swap(second);
for(auto &it:first) cout<<it<<" ";
cout<<endl;
for(auto &it:second) cout<<it<<" ";
cout<<endl;
return 0;
}
l: merge()
合并两个链表并使之默认升序(也可改),l1.merge(l2); 调用结束后l2变为空,l1中元素包含原来l1 和 l2中的元素,并且排好序,升序。
m: insert() 在指定位置插入一个或多个元素(三个重载):
l1.insert(l1.begin(),100); 在l1的开始位置插入100。
l1.insert(l1.begin(),2,200); 在l1的开始位置插入2个100。
l1.insert(l1.begin(),l2.begin(),l2.end());在l1的开始位置插入l2的从开始到结束的所有位置的元素。
#include <iostream>
#include <list>
#include<bits/stdc++.h>
using namespace std;
int main()
{
list<int>p(2,100);
p.insert(p.begin(),200);
p.insert(p.begin(),3,50);
list<int>l(3,666);
p.insert(p.begin(),l.begin(),l.end());
for(auto &it:p) cout<<it<<" ";
return 0;
}
n:erase() 删除一个元素或一个区域的元素(两个重载)
l1.erase(l1.begin()); 将l1的第一个元素删除。
l1.erase(l1.begin(),l1.end()); 将l1的从begin()到end()之间的元素删除。
remove from list
#include <iostream>
#include <list>
int main ()
{
int myints[]= {17,89,7,14};
std::list<int> mylist (myints,myints+4);
mylist.remove(89);
std::cout << "mylist contains:";
for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
Edit & Run
这个删除的是值不是迭代器指向的指针
mylist contains: 17 7 14