C++之STL线性容器

这篇博客详细介绍了C++中的STL线性容器,包括vector、list、stack、queue和string。主要内容涵盖容器特性、初始化、元素访问、插入与删除、迭代器、容器大小与判断、内存管理等方面,并探讨了相关面试题。例如,vector的内存管理和扩容原理,以及list底层实现为双向链表。此外,还讲解了如何在各种容器中插入、删除元素以及访问元素的方法。
摘要由CSDN通过智能技术生成

1. vector容器

1.1 容器特性

  • 顺序序列:顺序容器中的元素按照严格的线性顺序排序,可以通过元素在序列中的位置访问对应的元素。
  • 动态数组:支持对序列中的任意元素进行快速直接访问,甚至可以通过指针算述进行该操作,操供了在序列末尾相对快速地添加/删除元素的操作。
  • 能够感知内存分配:容器使用一个内存分配器对象来动态地处理它的存储需求。

1.2 vector容器的初始化

  • 直接初始化vector<int> vec{1,2,3};//一维容器vector<vector<int>> vec{ {1,2,3},{4,5,6} };//二维容器
  • 赋值初始化vector<int> vec1(5, 1);//带参数构造vec1;vector<int>vec2(vec1);//拷贝构造
  • 迭代器初始化:在这种迭代器范围拷贝时,不要求容器类型相同,而且新容器和原容器的元素类型也可以不同,只要能够将要拷贝的元素转换成要初始化的容器元素即可。例如:int a[5] = { 1,2,3,4,5 };vector<int> c(a, a + 5);//数组迭代器初始化vector<int> c2(c1.begin(),c1.begin()+5);//vector容器迭代器初始化;
  • 不带参数的构造函数vector<int> vec;//初始化一个空的vector,元素个数size()为0
  • 带参数的构造函数vector<int> vec(10);//初始化size,但每个元素值为默认值;vector<int> vec(10,1);//初始化size,并且设置初始值

1.3 访问元素

  • 数组下标访问cout<<vec[i]<<endl;//或者 cout<<vec.at(i)<<endl;,后者如果index越界,抛出out_of_range,这是两者的区别。
  • 使用迭代器vector<int>::iterator it; for(it=vec.begin();it!=vec.end();it++) cout<<*it<<endl;
  • 容器的首元素迭代器vec.front();
  • 容器的尾后迭代器vec.back();
  • 查找元素是否存在该元素find(vec.begin(),vec.end(),value); 在vec.begin()(包括)开始到vec.end()(不包括)中开始查找是否有value的元素,若存在,则返回位置。
  • 查找元素值为value在容器的个数int num=count(vec.begin(),vec.end(),value);
  • 查找符合条件的元素个数
bool cmp(Student s){
   
	return 90<s.score;
}
int num=count_if(vec.begin(),vec.end(),cmp);

1.4 插入元素

  • 在末尾添加元素vec.push_back(val);
  • 向容器迭代器插入单个元素vec.insert(vec.begin()+pos,x);
  • 向容器迭代器插入n个相同元素vec.insert(vec.begin()+post,n,x);
  • 向容器迭代器插入一段其他容器的元素:vec.insert(vec.begin()+pos,vec1.begin()+beginpos,vec1.begin()+endpos);

1.5 删除元素

  • 删除容器最后的元素vec.pop_back();
  • 删除容器迭代器指向的元素vec.erase(vec.begin()+pos);
  • 删除容器中[first,last)中元素vec.erase(first,last);
  • 清空容器vec.clear();vector.clear()的真正作用是:把size设置成0,但是capacity不变。
  • 注意:如果是删除指定位置的元素时,返回值是一个迭代器,指向删除元素的下一个位置;如果是删除某范围内的元素时,返回值也是一个迭代器,指向最后删除元素的下一个位置

1.6 容器迭代器

  • 返回向量头指针,指向第一个元素:vec.begin()
  • 返回向量尾指针,指向向量最后一个元素的下一个位置:vec.end();
  • 反向迭代器,指向最后一个元素:vec.rbegin();
  • 反向迭代器,指向第一个元素之前的位置:vec.rend();
  • 翻转容器reverse(vec.begin(),vec.end());
  • 容器排序sort(vec.begin(),vec.end();
  • 删除元素vec.erase(remove(vec.begin(),vec.end(),value),vec.end());,查找得到第一个元素的位置,然后从此位置开始遍历容器,将后面的元素依次前移,跳过与value相同的元素,即所有与value相同的元素均被覆盖,而其他元素都依次向前移动。
  • 指向首元素指针int *x=vec.data();链接例题在C++11中,vector 增加了data()的用法,它返回内置vecotr所指的数组内存的第一个元素的指针。 int *p = myvec.data();则p指向myvector的第一个元素指针,而++p;则p指向了myvector的第二个指针,也即p[0]为myvector的第二个元素,则p[2]指向myvector的第四个元素
  • 常量迭代器vec.cbegin();vec.cend();cbegin和cend是不管是对象本身是不是常量,换回值都是const_iterator.
  • 常量反向迭代器vec.crbegin();vec.crend();

1.7 容器的大小与判断

  • 返回值为容器大小vec.size();
  • 重新指定有效元素的个数 :vec.resize(10);指定容器有效容器为10个元素,此时vec.size()=10。将vec的现有元素个数调至10个,多则删少则补,其值随机。同时vec.resize(10,2);是将a的现有元素个数调至10个,多则删少则补,其值为2。
  • 返回值为目前容器能存数据的个数vec.capacity();当创建空容器时, 容量(capacity)为 0;当用完时,增加原容量的 1/2 。capacity 一般大于size的原因是为了避免每次增加数据时都要重新分配内存,所以一般会生成一个较大的空间,以便随后的数据插入。注意,每次当容器的内存不够用的时候,需要扩大容器的存储,指的就是capacity
  • 指定容器预留空间,即能存储数据的个数vec.reserve(100);指定容器能够容纳100个单位,此时vec.capacity()=100。不过这一过程是只增不减的,如果n小于当前capacity,否则reserve(n)无效。
  • 下面,我们顺便说一下capacity()的大小的问题: vector<T>默认构造函数 此时:capacity = 0,使用构造函数vector(n, value)指定capacity 此时:capacity = nstring (basic_string<char> )默认构造函数 此时:capacity =15指定了初始字符串的,此时:capacity = 大于字符串长度且等于n*15-1basic_string<wchar_t> //不常用,默认构造函数 此时:capacity = 7
    指定了初始字符串的 此时:capacity = 大于字符串长度且等于n*8-1;。在上面,我们说到vec.reserve(n)过程是只增不减的,所以无法通过reserve()来收缩空间。因此,当我们需要收缩内存空间的时候,可以使用下面方法:首先新建一个vector/string,然后往新建的vector/string填充原容器的内容,最后将原容器的变量名指向新的容器。代码如下:
vector<int> v(10, 5);
v.reserve(20);
vector<int>(v).swap(v);
  • 用不完的内存可以请求归还:在C++11新标准中当内存用不完的时候,可以请求系统归还内存。最后,使得 vec.capacity()==vec.size()。语法如下:vec.shrink_to_fit();这里和上面的收缩空间本质是一样的,只不过这里skrink_to_fit(收缩到合适)是利用系统提供的库函数来实现。
  • 判断容器是否为空vec.empty();

1.8 其他函数

  • assign函数:将区间[first,last)的元素赋值到当前的vector容器中,或者赋n个值为x的元素到vector容器中,这个容器会清除掉vector以前的内容vec2.assign(vec1.begin(), vec1.end());或者vec.assign(n,x);。还有,该函数允许从一个不同但相容的类型赋值,或者从容器的一个子序列赋值。例如:
list<string> newstyle;
vector<const char*> oldstyle;
newstyle=oldstyle;//错误,容器类型不匹配;
newstyle.assign(oldstyle.cbegin(),oldstyle.cend());
//正确,可以将const char* 转换成string类型;

list<string> list1(1);
list1.assign(10,"hello");
//等价与list1.clear();
//后跟着list1.insert(list1.begin(),list1.end());
  • swap函数:swap操作交换两个容器内容的操作很快,因为元素本身并没有交换,swap只是交换两个容器的内部数据结构,例如:vec1.swap(vec2);。元素不会移动的事实,除了stirng外,指向容器的迭代器、引用和指针在swap操作之后都不会失效。它们仍指向swap操作之前所指向的那些元素。但是在swap操作之后,这些元素已经属于不同的容器
  • copy函数:把vec1中的从vec1.begin()(包括它)到vec1.end()(不包括它)的元素复制到vec2中,从vec2.begin()+1的位置(包括它)开始复制,覆盖掉原有元素copy(vec1.begin(),vec1.end(),vec2.begin()+1);
  • 关系运算符:每个容器都支持相等运算符(==或者!=);除了无序关联器外的所有容器都支持关系运算符(>,>=,<,<=),关系运算符左右两边的运算对象必须是相同类型,且必须保存相同类型元素。

1.9 emplace操作

  • 新标准引进了三个新成员,emplace_front,emplace,emplace_back,这些操作构造而不是拷贝元素,也就是当我们调用一个emplace成员函数时,则是将参数传递给元素类型的构造函数。例如:
//在c的末尾构造一个Sales_data独享,
//使用三个参数的Sales_data构造函数;
c.emplace_back("012",25,12.0);

//错误,没有接受三个参数的push_back版本;
c.push_back("012",25,12.0);

//正确,创建一个临时Sales_data对象传递给push_back;
c
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值