C++ STL(七)容器_list
list(双向链表):是一个双向链表容器,可以高效的地进行插入和删除元素。
同前二种序列式容器相比,它不支持随机存取元素,不能使用数组[]和at方式进行访问。
它对元素的搜寻速度是所有容器中最慢的。
所需头文件:#include<list>
构造函数:
1 list<int> listA; //构造个空的list 2 list<int> listB(5); //定义有5个int元素的list (listB={0,0,0,0,0}) 3 list<int> listC(5,1);//定义有5个int元素的list,每个元素的值为1 (listC={1,1,1,1,1}) 4 list<int> listD(listC); //通过listC拷贝构造一个listD (listD={1,1,1,1,1}) 5 int nArray[] = {1,2,3}; 6 int nLeng = sizeof(nArray)/sizeof(int); 7 list<int> listE(nArray, nArray+nLeng); //通过数组拷贝构造一个listE (listE={1,2,3}) 8 //使用迭代器构造 9 list<int> listDD; 10 listDD.push_back(1); 11 listDD.push_back(2); 12 listDD.push_back(3); 13 listDD.push_back(4); 14 listDD.push_back(5); 15 list<int> dIt(listDD.begin(),listDD.end()); //正向迭代器方式构造list (dIt={1,2,3,4,5}) 16 list<int> dRit(listDD.rbegin(), listDD.rend()); //反向迭代器方式构造list (dRit={5,4,3,2,1}) 17 18 //注意: 19 //begin()与end()配套使用. 正向迭代器 20 //rbegin()与rend()配套使用. 反向迭代器 21 //begin()返回指向list第一个元素的迭代器 end()返回指向list最后一个元素+1位置的迭代器 22 //rbegin()返回指向list最后一个元素的迭代器 rend()返回指向list第一个元素-1位置的迭代器 23 24 return;
获取大小:
empty() 返回是否为空
size() 返回大小
max_size() 返回所能存储的最大元素个数,这是由系统自动定义的值
resize() 重新设置size,如果变长,变长的元素部份使用默认值,变短就删除多余的元素
1 list<int> listA; 2 bool bEmpty = listA.empty(); //bEmpty = true 是否为空 3 listA.push_back(1); 4 listA.push_back(2); 5 bEmpty = listA.empty(); //bEmpty = false 6 int nLeng = listA.size(); //nLeng = 2 容器大小 7 int nMaxSize = listA.max_size(); //nMaxSize = 1073741823 所能存储的最大元素个数,这是由系统自动定义的值 8 9 //resize重新设置size,如果变长,变长的元素部份使用默认值,变短就删除多余的元素. 10 listA.resize(10); 11 nLeng = listA.size(); //nLeng = 10 12 listA.resize(1); 13 nLeng = listA.size(); //nLeng = 1 14 15 //注意:deque没有deque中的capacity和reserdE方法 16 return;
赋值操作:
注意:不能使用数组[]和at方式进行访问
1 //使用assign()方式赋值 2 list<int> listC; 3 //void assign(size_type _Count, const _Ty& _listAl) 4 listC.assign(2,6); //给listC赋值二个int型元素,元素值为6 (listC={6,6}) 5 //void assign(_Iter _First, _Iter _Last) 6 list<int> listD; 7 listC.assign(listD.begin(),listD.end()); //使用迭代器方式把listD中所有元素赋值给listC (listC={}) 8 9 //使用swap()交换方式赋值 10 list<int> listE(2,3); 11 list<int> listF(4,4); 12 listE.swap(listF); //ListE = {4,4,4,4} listF = {3,3} 13 14 return;
增加元素操作:
push_front() 往头部插入一个元素
push_back() 往末尾插入一个元素
insert() 往任意位置插入一个元素,指定位置或者指定区间进行插入,第一个参数都是个迭代器。返回值是指向新元素的迭代器
1 list<int> listA; 2 //使用push_front()方式,头部插入元素 3 listA.push_front(1); //listA = {1} 4 //使用push_back()方式,末尾插入元素 5 listA.push_back(2); //listA = {1,2} 6 7 //使用insert()方式插入元素, 第一个参数都是迭代器,返回值是指向新元素的迭代器 8 list<int>::iterator it; 9 //iterator insert(const_iterator _Where, const _Ty& _listAl) 指定位置插入 10 it = listA.insert(listA.begin(),2); //往begin()之前插入一个int元素2 (listA={2,1,2}) 此时it指向第一个元素2 11 //void insert(const_iterator _Where, size_type _Count, const _Ty& _listAl) 指定位置插入 12 it = listA.insert(listA.end(),2,3);//往end()之前插入2个int元素3 (listA={2,1,2,3,3}) 此时it指向最后一个元素3 13 //void insert(const_iterator _Where, _Iter _First, _Iter _Last) 指定区间插入 14 list<int> listB(3,6); 15 it = listA.insert(listA.end(),listB.begin(),listB.end()); //把listB中所有元素插入到listA的end()之前 (listA={2,1,2,3,3,6,6,6}) 16 //此时*it=6,指向最后一个元素值为6的元素位置
删除元素操作:
pop_front() 从头部删除一个元素
pop_back() 从末尾删除一个元素
erase() 从任意位置删除一个元素,指定位置或者指定区间进行删除,第一个参数都是个迭代器。返回值是指向删除后的下一个元素的迭代器
clear() 清除中所有元素, size=0
1 list<int> listA; 2 listA.push_back(1); 3 listA.push_back(2); 4 listA.push_back(3); 5 listA.push_back(4); 6 listA.push_back(5); 7 //使用pop_front()方式删除头部元素 8 listA.pop_front(); //listA={2,3,4,5} 9 //使用pop_back()方式删除末尾元素 10 listA.pop_back(); //listA={2,3,4} 11 //使用erase()方式删除元素,第一个参数都是迭代器,返回值是指向删除后的下一个元素的迭代器 12 list<int>::iterator it; 13 //iterator erase(const_iterator _Where) 指定位置删除 14 it = listA.erase(listA.begin()); //删除Where位置的元素 (listA={3,4}) 此时it指向元素3 15 //void _Reverse(pointer _First, pointer _Last) 指定区间删除 16 it = listA.erase(listA.begin(),listA.end()); //把begin()到end()之间的所有元素删除 (listA={}) 17 //此时list中己经没有元素了,迭代器指向的下一个元素就是end() 18 19 //使用clear()方式清除所有元素,size变为0 20 list<int> listB(5,5); 21 listB.clear(); //(listB={},size=0) 22 23 return;
遍历元素操作:
注意:list不支持随机访问,只能通过迭代器进行遍历
1 list<int> dd; 2 dd.push_back(1); 3 dd.push_back(2); 4 dd.push_back(3); 5 dd.push_back(4); 6 dd.push_back(5); 7 8 //使用正向迭代器方式遍历 9 list<int>::iterator it; 10 it = dd.begin(); 11 for (it; it!=dd.end(); ++it) 12 { 13 cout<<*it<<" "; 14 } 15 cout<<endl; 16 //使用反向迭代器方式遍历 17 list<int>::reverse_iterator rit; 18 rit = dd.rbegin(); 19 for (rit; rit!=dd.rend(); ++rit) 20 { 21 cout<<*rit<<" "; 22 } 23 24 return;
释放内存操作:
注意:除了vector以外,其它容器使用clear都会自动释放内存,不需要使用空的容器进行swap
小练习题:
定义一个int型vector,包含1,3,2,3,3,3,4,3,5,3
删除容器中所有等于3的元素,然后剩余元素{1,2,4,5} 每二个元素之间插入6个6
使用vector deque list, 比较三种序列式容器在随机插入和删除上的性能效率
1. 先声明相关变量
1 int nArray[] = {1,3,2,3,3,3,4,3,5,3}; 2 int nLeng = sizeof(nArray)/sizeof(int); 3 double run_time; 4 _LARGE_INTEGER time_start; //开始时间 5 _LARGE_INTEGER time_over; //结束时间 6 double dqFreq; //计时器频率 7 LARGE_INTEGER f; //计时器频率 8 QueryPerformanceFrequency(&f); 9 dqFreq=(double)f.QuadPart;
2. vector代码
1 //vector 2 QueryPerformanceCounter(&time_start); //计时开始 3 4 vector<int> vA(nArray,nArray+nLeng); 5 vector<int>::iterator itA = vA.begin(); 6 while (itA!=vA.end()) 7 { 8 if(*itA == 3) 9 { 10 itA = vA.erase(itA); 11 }else 12 { 13 ++itA; 14 } 15 } 16 17 QueryPerformanceCounter(&time_over); //计时结束 18 //乘以1000000把单位由秒化为微秒,精度为1000 000/(cpu主频)微秒 19 run_time=1000000*(time_over.QuadPart-time_start.QuadPart)/dqFreq; 20 printf("vector删除花费时间:%fus\n",run_time); 21 22 QueryPerformanceCounter(&time_start); //计时开始 23 //剩余元素{1,2,4,5} 每二个元素之间插入6个6 24 itA = vA.begin(); 25 while (++itA!=vA.end()) 26 { 27 for (int i=0; i<6; i++) 28 { 29 itA = vA.insert(itA,6); 30 } 31 itA += 6; 32 } 33 QueryPerformanceCounter(&time_over); //计时结束 34 //乘以1000000把单位由秒化为微秒,精度为1000 000/(cpu主频)微秒 35 run_time=1000000*(time_over.QuadPart-time_start.QuadPart)/dqFreq; 36 printf("vector插入花费时间:%fus\n",run_time); 37 38 39 //deque 40 QueryPerformanceCounter(&time_start); //计时开始 41 42 deque<int> dB(nArray,nArray+nLeng); 43 deque<int>::iterator itB = dB.begin(); 44 while (itB!=dB.end()) 45 { 46 if(*itB == 3) 47 { 48 itB = dB.erase(itB); 49 }else 50 { 51 ++itB; 52 } 53 } 54 QueryPerformanceCounter(&time_over); //计时结束 55 run_time=1000000*(time_over.QuadPart-time_start.QuadPart)/dqFreq; 56 printf("deque删除花费时间:%fus\n",run_time); 57 58 QueryPerformanceCounter(&time_start); //计时开始 59 itB = dB.begin(); 60 while (++itB!=dB.end()) 61 { 62 for (int i=0; i<6; i++) 63 { 64 itB = dB.insert(itB,6); 65 } 66 itB += 6; 67 } 68 69 QueryPerformanceCounter(&time_over); //计时结束 70 run_time=1000000*(time_over.QuadPart-time_start.QuadPart)/dqFreq; 71 printf("deque插入花费时间:%fus\n",run_time);
3.deque代码
1 //deque 2 QueryPerformanceCounter(&time_start); //计时开始 3 4 deque<int> dB(nArray,nArray+nLeng); 5 deque<int>::iterator itB = dB.begin(); 6 while (itB!=dB.end()) 7 { 8 if(*itB == 3) 9 { 10 itB = dB.erase(itB); 11 }else 12 { 13 ++itB; 14 } 15 } 16 QueryPerformanceCounter(&time_over); //计时结束 17 run_time=1000000*(time_over.QuadPart-time_start.QuadPart)/dqFreq; 18 printf("deque删除花费时间:%fus\n",run_time); 19 20 QueryPerformanceCounter(&time_start); //计时开始 21 itB = dB.begin(); 22 while (++itB!=dB.end()) 23 { 24 for (int i=0; i<6; i++) 25 { 26 itB = dB.insert(itB,6); 27 } 28 itB += 6; 29 } 30 31 QueryPerformanceCounter(&time_over); //计时结束 32 run_time=1000000*(time_over.QuadPart-time_start.QuadPart)/dqFreq; 33 printf("deque插入花费时间:%fus\n",run_time);
4.list代码
1 //list 2 QueryPerformanceCounter(&time_start); 3 4 list<int> listC(nArray,nArray+nLeng); 5 list<int>::iterator itC = listC.begin(); 6 while (itC!=listC.end()) 7 { 8 if(*itC == 3) 9 { 10 itC = listC.erase(itC); 11 }else 12 { 13 ++itC; 14 } 15 } 16 QueryPerformanceCounter(&time_over); //计时结束 17 run_time=1000000*(time_over.QuadPart-time_start.QuadPart)/dqFreq; 18 printf("list删除花费时间:%fus\n",run_time); 19 20 QueryPerformanceCounter(&time_start); 21 itC = listC.begin(); 22 while (++itC!=listC.end()) 23 { 24 for (int i=0; i<6; i++) 25 { 26 listC.insert(itC,6); 27 } 28 } 29 30 QueryPerformanceCounter(&time_over); 31 run_time=1000000*(time_over.QuadPart-time_start.QuadPart)/dqFreq; 32 printf("list插入花费时间:%fus\n",run_time);
输出结果:
ps:这里因为计算的时间片很短,使用了高精度计时器方便比较
总结:从输出结果可以看出在任意位置(除了头部和尾部)删除和插入元素上,list效率最高,vector和deque差不多