序列式容器-vector/deque/list
1.序列式容器-vector/queue/list三种主要构造方式与四种遍历方式。
知识点:
1.三种容器的初始化方式都是一样的
2.vector/deque可以支持下标运算符访问,list不允许,list容器里面没有重载[]运算符。
vector容器的三种构造函数
vector容器构造函数:--plus deque和list,构造函数源码基本差不多。
1.vector( size_type count,
const T& value,//初始化count个value,如果value不写,默认为0
const Allocator& alloc = Allocator());//空间适配器2.迭代器返回,左闭右开,迭代器--->广义的指针
template< class InputIt > //迭代器方式进行初始化
vector( InputIt first, InputIt last,
const Allocator& alloc = Allocator() );3.大括号形式进行初始化构造
vector( std::initializer_listinit,//给出初始化列表
const Allocator& alloc = Allocator() );
vector容器的4种遍历方式
1.数组下标形式--不支持list
2.使用迭代器-->广义指针
3.auto自动推导迭代器形式
4.通用遍历形式:auto &elem;//用elem去 *** 作迭代器里面的数据
ps:可以把vector全部改成deque或者list,改成list的时候需要把数组下标形式注释掉,list不支持下标访问
//1.vector容器的构造和遍历 void test01() { //1.初始化count个value vectornum(10,1);//10个1 vector num1(10);//value默认为0 //2.以迭代器的方式进行初始化 int p[10] = {1,2,3,4,5,6,7,8,9,10}; vector num3(p,p+10);//左闭右开 //3.以列表形式进行初始化 vector num4 = {10,100,1000,9,99,999,1,11,111,20}; //1.第一种遍历方式:数组下标形式 for(int i=0;i ::iterator it=num3.begin();it!=num3.end();it++) { cout<<*it<<" "; }//1 2 3 4 5 6 7 8 9 10 cout< 运行结果
1 1 1 1 1 1 1 1 1 1 //数组下标方式进行遍历
1 2 3 4 5 6 7 8 9 10 //迭代器方式
1 2 3 4 5 6 7 8 9 10 //auto自动推导迭代器类型
10 100 1000 9 99 999 1 11 111 20 //auto通用引用类型遍历2.序列式容器-vector/deque/list的插入和删除
1.vector/deque/list尾插和尾删结果都一样的
-pushback(val)
-pop_back()
2.deque/list支持头插头删,结果一样,vector不支持,由于vector在头部进行插入的话,后面的元素需要总体往后移,时间复杂度是O(n),因此没有提供头部插入的接口。
3.可以用一个通用打印函数模板来对三者的打印。
#includeusing namespace std; #include #include #include template
void print(const T &con) { for(auto &elem:con) { cout< number = {1,2,3,4,56,7,7,8,8,13}; print(number);//1 2 3 4 56 7 7 8 8 13 cout<<"vector尾部插入20和30:"< number = {1,2,3,4,56,7,7,8,8,13}; cout<<"原列表:"; print(number);//1 2 3 4 56 7 7 8 8 13 cout<<"list尾部插入20和30:"< number = {1,2,3,4,56,7,7,8,8,13}; cout<<"原队列:"; print(number);//1 2 3 4 56 7 7 8 8 13 cout<<"deque尾部插入20和30:"< 运行结果
1 2 3 4 56 7 7 8 8 13
vector尾部插入20和30:
1 2 3 4 56 7 7 8 8 13 20 30
vector删除尾部元素:
1 2 3 4 56 7 7 8 8 13 20
原列表:1 2 3 4 56 7 7 8 8 13
list尾部插入20和30:
1 2 3 4 56 7 7 8 8 13 20 30
list删除尾部元素:
1 2 3 4 56 7 7 8 8 13 20
list头部插入元素:
888 999 1 2 3 4 56 7 7 8 8 13 20
list头部删除元素:
999 1 2 3 4 56 7 7 8 8 13 20
原队列:1 2 3 4 56 7 7 8 8 13
deque尾部插入20和30:
1 2 3 4 56 7 7 8 8 13 20 30
deque删除尾部元素:
1 2 3 4 56 7 7 8 8 13 20
deque头部插入元素:
888 999 1 2 3 4 56 7 7 8 8 13 20
deque头部删除元素:
999 1 2 3 4 56 7 7 8 8 13 203.细谈vector
3.1 vector的底层实现有多少个指针?
1.vector里面有两个函数,一个是size(),一个capacity();
2.vector有个头指针,一个尾指针,size()大小就是两指针的差值;
3.还有个指针指向capacity,用来进行扩容。
sizeof(vector<类型>)=24;//三个指针大小243.2 at和下标访问有什么区别?
用下标访问,有越界的风险,不安全;at加了一个异常检查,会抛出异常。
3.3 打印第一个元素的地址的方式
&number;//这返回的是个迭代器 &number[0]; &*number.begin(); int *pdata = number.data();3.4 vector中insert扩容原理
1.vector在进行insert的时候,每次都需要重写置位迭代器的位置,因为有可能因为进行扩容,之前的迭代器失效了。
2.deque在进行insert范围插入的时候,会去判断是往前面插入还是往后面进行插入,根据size()/2的大小来判断。
3.list的插入是以链表形式vector insert扩容原理
1.push_back可以进行size()的两倍进行扩容,因为每次只插入一个元素。
2.insert插入的元素是不确定的,进行两倍扩容就不合适了insert的元素个数为t;
1.t <= capacity-size,此时不会扩容
2.capacity - size3.capacity-size 4.capacity-size #includeusing namespace std; #include template void Print(T &val) { for(auto &elem: val) { cout< void Show_CapacityAndSize(T &number) { Print(number); cout<<"capacity:c = "< capacity或者t>size情况:" < size,扩容方式:t+size:"< size的情况 Show_CapacityAndSize(number);//size = 24+21=45,capacity =21+24=45,t=24 cout<<"插入个数:t>capacity,扩容方式:t+size:"< 运行结果
1 3 5 7 9 11 13 15 18
capacity:c = 9
size: s = 91 3 5 7 9 11 13 15 18 14 999
capacity:c = 18
size: s = 11使用insert进行插入,查看insert扩容原理:
*it=5
1.插入个数t<=capacity-size:空间足够,不会扩容:
1 3 68 20 5 7 9 11 13 15 18 14 999
capacity:c = 18
size: s = 132.t:capacity - size< t < size:插入个数大于当前可存储的空间,小于size:
按照2*size进行扩容.
1 3 11 11 11 11 11 11 11 11 68 20 5 7 9 11 13 15 18 14 999
capacity:c = 26
size: s = 213.capacity-size
capacity或者t>size情况:
按照t+size方式进行扩容。
插入个数:t>size,扩容方式:t+size:
*it=7
1 3 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 11 11 11 11 11 11 11 11 68 20 5 7 9 11 13 15 18 14 999
capacity:c = 45
size: s = 45插入个数:t>capacity,扩容方式:t+size:
1 3 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 11 11 11 11 11 11 11 11 68 20 5 7 9 11 13 15 18 14 999
capacity:c = 125
size: s = 1253.5 vetor中的erase、clear()、和shrink_to_fit()
1.使用erase删除对应元素的迭代器有个坑,需要避免
2.clear()和shrink_to_fit()配合时候回收vector空间
3.vector中的clear()/shrink_to_fit()和deque容器的使用方法是一样的,list中只有clear(),在clear()后,内存已被回收。#include#include using namespace std; template void print(const T &con) { for(auto &elem: con) { cout< number = {1,3,6,6,5,7}; print(number); for(auto it=number.begin();it!=number.end();it++) { if(6==*it) { number.erase(it);//以迭代器的方式来删除 //只会删除第一个6,为什么? //迭代器被删除后,后面一个6的迭代器顶替了当前被删除的元素 //it进行++,因此有个6没被删除 //这样进行删除是有问题的 it--;//加个这个可以解决 } } print(number); cout< number = {1,3,6,6,5,7}; print(number); for(auto it=number.begin();it!=number.end();) { if(6==*it) { it = number.erase(it);//以迭代器的方式来删除 //只会删除第一个6,为什么? //迭代器被删除后,后面一个6的迭代器顶替了当前被删除的元素 //it进行++,因此有个6没被删除 //it--;//这样进行删除是有问题的 } else { ++it; } } print(number); } int main() { test01(); //test02(); return 0; } 3.6 vector/deque/list emplace_back的使用
往容器尾部进行插入,识别右值
template< class... Args >
void emplace_back( Args&&... args );#include#include using namespace std; #include
class Point { public: Point(int ix=0,int iy = 0) :_ix(ix),_iy(iy) {} void print()const { cout<<_ix<<","<<_iy< p1; p1.emplace_back(Point(1,2)); auto it = p1.begin(); it->print(); list l1; l1.emplace_back(Point(2,3)); l1.begin()->print(); } int main() { test01(); return 0; } 4.list *** 作
1.sort()排序:
1.number.sort(std::less());//从小到大
2.number.sort(std::greater()); //从大到小
3.number.sort(CompareList()); //自定义仿函数
2.reverse();链表反转3.unique()去重:需要首先对list进行排序,再进行去重。
4.number1.merge(number2);//1.对已排好序的两个链表进行合并,两个链表有序(小->大),合并后的结果才会有序
//2.合并后,number2链表被清空
//3.对于两个从大到小的进行排序的列表进行排序,想要合并后的列表还是从大到小有 序,需要传入自定义Compare函数或者直接调用标准库函数
Merge接口参考:
void merge( list& other );
(1)
void merge( list&& other );
(1) (since C++11)
template
void merge( list& other, Compare comp );
(2)
template
void merge( list&& other, Compare comp );#include#include using namespace std; template
void print(const T &con) { for(auto &elem: con) { cout< struct CompareList { bool operator()(const T &lhs,const T &rhs)const { return lhs>rhs; } }; void test01() { list number = {1,212,12,3,413,56,87,12,43,21,42}; print(number); cout<<"对list进行排序:"< ()); // print(number); // number.sort(less ()); // print(number); number.sort(CompareList ()); print(number); cout<<"list反转:"< number2 = {2,22,3,33,4, 44,5,55,6,66,7,77}; number2.sort(); //number.merge(number); number.merge(number2); print(number); print(number2);//此时number2为空了 } void test02()//合并两个从大到小的链表,合并后的链表还是从大到小排序 { list number = {1,212,12,3,413,56,87,12,43,21,42}; list number2 = {2,22,3,33,4, 44,5,55,6,66,7,77}; number.sort(greater ()); number2.sort(greater ()); cout<<"合并两个从大到小排序的链表:number.merge(number2,greater ()):"< ()); print(number); } int main() { test01(); cout< 5.list: splice:把一个链表的元素移到另外一个链表。
接口参考: void splice( const_iterator pos, list& other ); (1) void splice( const_iterator pos, list&& other ); (1) (since C++11) void splice( const_iterator pos, list& other, const_iterator it ); (2) void splice( const_iterator pos, list&& other, const_iterator it ); (2) (since C++11) void splice( const_iterator pos, list& other, const_iterator first, const_iterator last);//按范围取 (3) void splice( const_iterator pos, list&& other, const_iterator first, const_iterator last );#include#include using namespace std; template
void show_Value(T &con) { for(auto &elem: con) { cout< number1 = {8,12,3,45,6,123}; list number3 = {33,44,66,99,11}; auto it = number1.begin(); it++; number1.splice(it,number3); show_Value(number1);//8 33 44 66 99 11 12 3 45 6 123 show_Value(number3);//空 } void test02() { list number1 = {1,2,3,4,5,6,7,8}; list number2 = {2,4,6,8,10,12,14}; auto it1 = number1.begin(); it1++;//2 auto it2 = number2.begin(); it2++;//4的迭代器 it2++;//6的迭代器 number1.splice(it1, number2,it2);//把number2 迭代器it2插入到number1 it1的位置 show_Value(number1);//1 6 2 3 4 5 6 7 8 show_Value(number2);// 4 8 10 12 14 } void test03() { list number1 = {1,2,3,4,5,6,7,8}; list number2 = {2,4,6,8,10,12,14}; auto it1 = number1.begin(); it1++;//2 auto it2 = number2.begin(); it2++;//4的迭代器 it2++;//6的迭代器 auto it_end = number2.end(); //it_end--; number1.splice(it1,number2,it2,it_end);//左闭右开,number2[it2,end)插入到number1 show_Value(number1);//1 6 8 10 12 14 2 3 4 5 6 7 8 show_Value(number2);//2 4 } int main() { //test01(); //test02(); test03(); return 0; } 欢迎分享,转载请注明来源:内存溢出
评论列表(0条)