list是順序容器的一種。list是一個雙向鏈表。使用list需要包含頭文件list。雙向鏈表的每一個元素中都有一個指針指向後一個元素,也有一個指針指向前一個元素
在list容器中,在已經定位到要增刪元素的位置的情況下,增刪元素能在常數時間內完成,比如在ai和ai+1之間插入一個元素,值需要修改ai和ai+1中的指針即可
list的內部結構和vector不同,存在明顯的區別
1.list不支持隨機存取
2.在list的任何位置執行元素的插入和移除都非常快,可以迅速實現。插入和刪除動作不會影響指向其他元素的指針、引用、迭代器,不會造成失效
3.list不支持隨機存取,不提供下標操作符和at()函數
4.list沒有提供容量、空間重新分配等操作函數,每個元素都有自己的內存
5.list提供了特殊成員函數,專門用於移動元素
list模板類實現了標準C++11數據結構中鏈表的所有功能。list一旦定義了類對象後,就可以完成鏈表操作
STL 中的算法 sort 可以用來對 vector 和 deque 排序,它需要隨機訪問迭代器的支持。因爲 list 不支持隨機訪問迭代器,所以不能用算法 sort 對 list 容器排序。因此,list 容器引入了 sort 成員函數以完成排序
list的使用
#include <iostream>
#include <stdlib.h>
#include <list>
using namespace std;
int main()
{
list<int> l1; //構造空的l1
list<int> l2 (4, 100); //l2中放入4個值爲100的元素
list<int> l3(l2.begin(), l2.end()); //用l2的begin(),end()左閉右開區間構造l3
list<int> l4(l3); //用l3拷貝構造l4
//以數組作爲迭代器區間構造l5
int arr[] = {32,543,23,53};
list<int> l5(arr, arr + sizeof(arr) / sizeof(int));
cout << "l4: data";
//C++11打印方式
for (auto &x : l4)
{
cout << x << " ";
}
cout << endl;
cout << "l5:data:";
//用迭代器方式打印l5中的元素
for (list<int>::iterator it = l5.begin(); it != l5.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
cout << endl;
system("pause");
return 0;
}
list iterator的使用
1. begin與end爲正向迭代器,對迭代器執行++操作,迭代器向後移動
2. rbegin(end)與rend(begin)爲反向迭代器,對迭代器執行++操作,迭代器向前移動
3. cbegin與cend爲const的正向迭代器,與begin和end不同的是:該迭代器指向節點中的元素值不能修 改
4. crbegin與crend爲const的反向得帶器,與rbegin和rend不同的是:該迭代器指向節點中的元素值不能修改
#include <iostream>
#include <stdlib.h>
#include <list>
using namespace std;
int main()
{
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
list<int> v(a, a + sizeof(a) / sizeof(int));
//使用正向迭代器打印list中的元素
for (list<int>::iterator it = v.begin(); it != v.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
//使用反向迭代器打印list中的元素
for (list<int>::reverse_iterator it = v.rbegin(); it != v.rend(); ++it)
{
cout << *it << " ";
}
cout << endl;
for (auto cit : v)
{
cout << cit << " ";
}
system("pause");
return 0;
}
list capacity
#include <iostream>
#include <stdlib.h>
#include <list>
using namespace std;
int main()
{
int a[] = {1,2,3,4,5,6,7,8,9,0};
list<int> v(a, a + sizeof(a) / sizeof(a[0]));
//打印list中有效節點的個數
cout << v.size() << endl;
//檢測list是否爲空
if (v.empty()){
cout << "空的list" << endl;
}
else
{
for (const auto&e : v)
{
cout << e << " ";
}
cout << endl;
}
system("pause");
return 0;
}
#include <iostream>
#include <stdlib.h>
#include <list>
using namespace std;
int main()
{
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
list<int> v(a, a + sizeof(a) / sizeof(a[0]));
for (auto&e : v)
{
cout << e << " ";
}
cout << endl;
//將list中的第一個節點與最後一個節點中的值改爲10
v.front() = 10;
v.back() = 10;
for (auto&e : v)
{
cout << e << " ";
}
const list<int> v2(a, a + sizeof(a) / sizeof(a[0]));
const int& ca = v2.front();
cout << endl;
cout << ca << " ";
system("pause");
return 0;
}
// push_back/pop_back/push_front/pop_front
//打印函數
void PrintList(list<int>&v)
{
for (auto&e : v)
{
cout << e << " ";
}
cout << endl;
}
//////////////////////////////////////////////////////
// push_back/pop_back/push_front/pop_front
void TestList1()
{
int a[] = { 1, 2, 3 };
list<int> v(a, a + sizeof(a) / sizeof(a[0]));
//在list的尾部插入4,頭部插入0
v.push_back(4);
v.push_front(0);
PrintList(v);
//刪除尾節點和頭結點
v.pop_back();
v.pop_front();
PrintList(v);
}
// emplace_back / emplace_front / emplace
// emplace_back / emplace_front / emplace
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
:_year(year)
, _month(month)
, _day(day)
{
cout << "Date(int,int,int):" << this << endl;
}
Date(const Date&d)
:_year(d._year)
, _month(d._month)
, _day(d._day)
{
cout << "Date(const Date&):" << this << endl;
}
private:
int _year;
int _month;
int _day;
};
// push_back尾插:先構造好元素,然後將元素拷貝到節點中,插入時先調構造函數,再調拷貝構造函數
// emplace_back尾插:先構造節點,然後調用構造函數在節點中直接構造對象
// emplace_back比push_back更高效,少了一次拷貝構造函數的調用
void TestList2()
{
list<Date> l;
Date d(2018, 10, 20);
l.push_back(d);
l.emplace_back(2018, 10, 21);
l.emplace_front(2018, 10, 19);
}
// insert /erase
// insert /erase
void TestList3()
{
int a[] = { 1, 2, 3 };
list<int> v1(a, a + sizeof(a) / sizeof(a[0]));
//獲取鏈表中第二個節點
auto pos = ++v1.begin();
cout << *pos << endl;
//在pos前插入值爲4的元素
v1.insert(pos, 4);
PrintList(v1);
//在pos前插入5個值爲5的元素
v1.insert(pos, 5, 5);
PrintList(v1);
//在pos前插入[v.begin(),v.end())區間中的元素
vector<int> v2{ 7, 8, 9 };
v1.insert(pos, v2.begin(), v2.end());
PrintList(v1);
//刪除pos位置上的元素
v1.erase(pos);
PrintList(v1);
//刪除list中[begin,end)區間中的元素,即刪除所有元素
v1.erase(v1.begin(), v1.end());
PrintList(v1);
}
// resize/swap/clear
void TestList4()
{
int a[] = { 1, 2, 3 };
list<int> v1(a, a + sizeof(a) / sizeof(a[0]));
PrintList(v1);
//將v中的元素個數增加到10個,多出的元素用默認值填充
//list中放置的是內置類型,默認值爲0,如果list中放置自定義類型元素,調用缺省構造函數
v1.resize(10);
PrintList(v1);
//將v中的元素增加到20個,多出的元素用4來填充
v1.resize(20, 4);
PrintList(v1);
//將V中的元素減少到5個
v1.resize(5);
PrintList(v1);
//用Vector中的元素來構造list
vector<int> v2{ 4, 5, 6 };
list<int> l(v2.begin(), v2.end());
cout << "構造後l:";
PrintList(l);
//交換v1和l中的元素
v1.swap(l);
cout << "v1:";
PrintList(v1);
cout << "l:";
PrintList(l);
//將l中的元素清空
cout << "清空後:";
l.clear();
cout << l.size() << endl;
}
list的迭代器失效
迭代器失效即迭代器所指向的節點的無效,即該節點被刪除了。因爲list的底層結構爲帶頭結點的雙向循環鏈表,因此在list中進行插入時是不會導致list的迭代 器失效的,只有在刪除時纔會失效,並且失效的只是指向被刪除節點的迭代器,其他迭代器不會受到影響
void TestListIterator1()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
list<int> l(array, array+sizeof(array)/sizeof(array[0]));
auto it = l.begin();
while (it != l.end())
{
// erase()函數執行後,it所指向的節點已被刪除,因此it無效,在下一次使用it時,必須先給其賦
值
l.erase(it);
++it;
}
}
// 改正
void TestListIterator()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
list<int> l(array, array+sizeof(array)/sizeof(array[0]));
auto it = l.begin();
while (it != l.end())
{
l.erase(it++); // it = l.erase(it);
}
}