当前位置: 首页 > wzjs >正文

建设部网站安全考核证书查询北京公司注册查询

建设部网站安全考核证书查询,北京公司注册查询,如何看网站做打好坏,南软科技网站开发目录 默认成员函数 迭代器 vector的扩容: reserve: resize: at: 增删: push_back和pop_back insert和erase 查改: find: ​编辑 sort: 在C语言中,想要存储非连续的数据,通常会用数组(array),例如…

目录

默认成员函数

迭代器

 vector的扩容:

reserve:

resize:

at:

 增删:

push_back和pop_back

 insert和erase

查改:

find:

​编辑

sort: 


在C语言中,想要存储非连续的数据,通常会用数组(array),例如int arr[20],arr中就可以存储20个int类型数据,但arr这个数组它的上限就永远是20,不会动态增长

在C++中,STL中的vector容器就很好的弥补了这点,它是一个可以动态增长的顺序表容器,本篇文章会说明vector最常用的十几种接口函数

默认成员函数

vector的默认成员函数有4个,分别是构造函数,拷贝构造函数,析构函数和赋值运算符重载函数

vector<int> v1;//默认构造函数
vector<int> v2(114, 514);//将114个514存入v2(不常用,了解即可)vector<int> v3(v2);//拷贝构造函数vector<int> v4;
v4 = v3;//赋值运算符重载

和string的默认成员函数大差不差

那么string和vector<char>有什么区别呢?

他们两者都是用来存储字符的数组,但string一般是用来存储一串连续的数据,而vector一般用来存储不连续的多个数据

例如,当你想要存储40个人的身份证号时,可以用40个string对象分别存储,而存储40个人的年龄时,就可以用一个vector来存储

这也说明了为什么vector里没有<<和>>,append这种运算符重载函数,因为vector不需要,能用到这两种运算符重载的数据都会去选择string

和string一样,vector也可以尾插

vector<int> v1;//默认构造函数
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);

 上述代码就是将1,2,3,4依次尾插到v1中

迭代器

对于vector,有3种方法可以输出其中的数据

1.operator[]+size()

vector也是支持[]重载的

再加上size()函数用来读取vector中的数据总个数

vector<int> v1;//默认构造函数
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
for (int i = 0; i < v1.size(); i++)
{cout << v1[i] << " ";
}

输出结果:

2.迭代器

对于每个STL中的容器都有迭代器,vector当然也不例外

迭代器一共有三种类型,分别是普通迭代器,反向迭代器和只读(const)迭代器

普通迭代器:

vector<int> v1;//默认构造函数
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
vector<int>::iterator it = v1.begin();
while(it != v1.end())
{cout << *it << " ";it++;
}

输出结果和上面的一样 

vector<int>::iterator 就是int类型的vector的迭代器类型

begin和end分别返回的是该对象起始位置结束位置的迭代器

3.范围for

vector<int> v1;//默认构造函数
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
for(auto e : v1)
{cout << e << " ";
}

 输出和上面的一样

范围for本质上还是迭代器,auto e中的auto就会被替换成后面v1的迭代器类型,即vector<int>::iterator,并赋值成v1.begin(),它会自动加加,直到==v1.end()。

迭代器不仅可以正向遍历,还可以反向遍历

反向迭代器:

rbegin和rend也就是reverse_begin和reverse_end的意思,即翻转之后的begin和end

但可以看到,他们的返回值类型都是reverse_iterator,即翻转后的迭代器类型

所以直接将一个普通的迭代器变量复制成rbegin会报错

这时候就要用到上面提到的reverse_iterator

vector<int> v1;//默认构造函数
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
vector<int>::reverse_iterator rit = v1.rbegin();//反向迭代器
while(rit != v1.rend())
{cout << *rit << " ";rit++;
}

输出结果:

 只读(const)迭代器:

void printv(const vector<int>& v)
{vector<int>::const_iterator cit = v.begin();while(cit != v.end()){cout << *cit << " ";cit++;}
}
int main()
{vector<int> v1;//默认构造函数v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);printv(v1);}

就好比上面这个程序,我的printv函数的参数是const vector<int>&类型,这是因为一般来说传参都喜欢用&用来提高效率,而为了防止改变原数据,又会在前面加上const,在这种情况下, 想要用普通迭代器的话会报错,因为这就属于权限放大了,由const变成了非const(具体可以去搜权限放大缩小问题)。

对于这种情况,就需要用到const_iterator

除此之外,迭代器的反向和只读特性还可以同时拥有,即const_reverse_iterator,只读反向迭代器

 假设有个vector对象是vec:

 vector的扩容:

和string一样,vector也有size和capacity接口,分别用来调用该对象所存储的数据个数和容量

vector<int> v1;//默认构造函数
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
cout << v1.size() << endl << v1.capacity() << endl;

输出结果: 

 也就是说size是5,capacity是8,那么vector的capacity增长策略是怎么样的呢?

void Test()
{size_t sz;vector<int> v;sz = v.capacity();cout << "capacity的变化:\n";for (int i = 0; i < 100; ++i){v.push_back(i);if (sz != v.capacity()){sz = v.capacity();cout << "capacity changed: " << sz << '\n';}}
}

该函数用于测试逐个插入数据直到100,capacity的变化

输出结果(VS环境):

 

可以看到规律大概是1.5倍,只不过会向下取整

但如果换到别的环境下测试,例如Linux和GCC编译器:

现在的增长策略又是2倍了

不同环境下的增长策略不一样,那么到底是1.5倍的策略更好还是2倍的策略更好? 

如果把插入的数据从100改到1067,就会发现2倍的扩容会浪费更多的空间

 但是2倍的又比1.5倍的扩容次数要少,所以说各有千秋

1.5倍不浪费空间,但浪费时间

2倍不浪费时间,但浪费空间

reserve:

前面说到不断的开辟更大的空间会消耗很多时间,那有没有什么办法可以提高效率呢?

void Test()
{size_t sz;vector<int> v;v.reserve(1066);//在插入数据之前开辟好1066个空间sz = v.capacity();cout << "capacity的变化:\n";for (int i = 0; i < 1066; ++i){v.push_back(i);if (sz != v.capacity()){sz = v.capacity();cout << "capacity changed: " << sz << '\n';}}
}

输出结果:

可以看到,这次capacity就没有变化了

这是因为上面代码在原来的基础上加了一行v.reserve(1066),就直接把对象v的容量一次性扩到了1066,自然就不需要再额外扩容了 

resize:

reserve是可以开辟到更大的容量,而resize是将值增长或减少到一个值,也就是val,如果不给,默认就是0

若n比原本的size大:

void print(const vector<int>& v)
{for (int i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;
}
int main()
{vector<int> v;for (int i = 0; i < 5; i++){v.push_back(i);}v.resize(10);print(v);cout << v.capacity() << endl;v.resize(15,114);print(v);cout << v.capacity() << endl;return 0;
}

输出结果:

一开始v有5个数据,后面resize到了10个,而且没有指定val的值,所以默认就是0,第一行的后面就多了5个0,第二行输出的是当前capacity,可以看到是10

后面就resize成了15,但这次指定了val是114,所以第三行输出后面就又跟了5个114,第四行输出的是当前capacity,可以看到是20。即:若capacity超出,也会自动扩容capacity

若n比原来的size小:

void print(const vector<int>& v)
{for (int i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;
}
int main()
{vector<int> v;for (int i = 0; i < 15; i++){v.push_back(i);}v.resize(10);print(v);cout << v.capacity() << endl;v.resize(5);print(v);cout << v.capacity() << endl;return 0;
}

输出结果:

可以看到,当n小于当前size时,会直接删除n后面的数据,但capacity不会缩小

at:

vector<int> v;
for (int i = 0; i < 10; i++)v.push_back(i);
v[10] = 2;

上面所示代码中,v有10个元素,下标到9,但我调用了v[10],这里就非法访问

但如果用at接口呢

vector<int> v;
for (int i = 0; i < 10; i++)v.push_back(i);
v.at(10) = 2;

可以看到,虽然也报了错,但这是报的异常,只要补异常就不会报错了

 增删:

push_back和pop_back

push_back一开始已经讲过,就是尾插数据

pop_back是尾删数据

void print(const vector<int>& v)
{for (int i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;
}
int main()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.pop_back();print(v);return 0;
}

输出结果:

 insert和erase

 可以发现vector的insert和string的不一样,vector的第一个参数是传的迭代器

void print(const vector<int>& v)
{for (int i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;
}
int main()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.insert(v.begin(), 0);//头插一个元素v.insert(v.begin(),-1);//头插一个元素v.insert(v.end(), 5);//尾插一个元素print(v);return 0;
}

输出结果:

 可以看到,erase传的也是迭代器

因为没有缺省值,所以就不能再像string一样直接传无参了 

void print(const vector<int>& v)
{for (int i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;
}
int main()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.insert(v.begin(), 0);//头插一个元素v.insert(v.begin(),-1);//头插一个元素v.insert(v.end(), 5);//尾插一个元素v.erase(v.begin());//头删v.erase(v.end());//尾删print(v);return 0;
}

可以看到先头删再尾删,看着没有问题

但实际上会出现内存错误

这是因为end()迭代器是返回的最后一个数+1的位置,这个位置是没有元素的

所以要尾删的话,需要传end()-1

void print(const vector<int>& v)
{for (int i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;
}
int main()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.insert(v.begin(), 0);//头插一个元素v.insert(v.begin(),-1);//头插一个元素v.insert(v.end(), 5);//尾插一个元素v.erase(v.begin());//头删v.erase(v.end()-1);//尾删print(v);return 0;
}

输出结果: 

查改:

find:

虽然vector里没有find函数(string里有),但std,即全局中,有find函数,这是算法里的,包含于<algorithm>头文件(这个单词翻译过来就是算法的意思)

可以看到三个形参中,前两个形参是迭代器类型,分别表示起始位置和结束位置,需要特别注意的是,只要是这种传迭代器区间的形参,都传的是左闭右开区间(包括下面要讲到的sort函数),第三个形参则是要找的数据

void print(const vector<int>& v)
{for (int i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;
}int main()
{vector<int> v;for (int i = 0; i < 10; i++){v.push_back(i);}vector<int>::iterator pos = find(v.begin(), v.end(), 5);//左闭右开区间if(pos != v.end())//用来判断是否找到{v.erase(pos);}print(v);return 0;
}

输出结果:

那么代码中下面的if判断是怎么来判断是否找到的呢?

这是find函数的具体实现,可以发现,若这个左闭右开区间内没有找到,最后返回是last,也就是第二个参数(开区间的迭代器),所以pos只要不等于开区间的迭代器,就代表找到了

sort: 

本篇就先只介绍第一行的sort,两个形参也是左闭右开的迭代器类型(sort函数底层是用快排实现的)

void print(const vector<int>& v)
{for (int i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;
}int main()
{vector<int> v;v.push_back(3);v.push_back(1);v.push_back(6);v.push_back(8);v.push_back(7);v.push_back(9);v.push_back(4);v.push_back(6);sort(v.begin(), v.end());//传左闭右开区间print(v);return 0;
}

输出结果:


文章转载自:

http://PBrrdoi0.qhfdL.cn
http://WA8G0ihu.qhfdL.cn
http://ZPwQXPso.qhfdL.cn
http://oz4OjaQr.qhfdL.cn
http://oYPEBqZG.qhfdL.cn
http://XsatZuB8.qhfdL.cn
http://7SejpA07.qhfdL.cn
http://KSnWCis3.qhfdL.cn
http://vzmy5NiX.qhfdL.cn
http://fsQZDNWY.qhfdL.cn
http://ZWdWEvI7.qhfdL.cn
http://exZLs8gi.qhfdL.cn
http://Z0MaSZOu.qhfdL.cn
http://dm4Hf2ta.qhfdL.cn
http://xiKZ4qRE.qhfdL.cn
http://Ew1YPUbh.qhfdL.cn
http://WG9Jnsiw.qhfdL.cn
http://FOvt5iUd.qhfdL.cn
http://a0BLtqCV.qhfdL.cn
http://ndSRlfzy.qhfdL.cn
http://QWaZT7WY.qhfdL.cn
http://VgfmlRk5.qhfdL.cn
http://YmIZK1cp.qhfdL.cn
http://zeo34Dy9.qhfdL.cn
http://dqb2wRWe.qhfdL.cn
http://4hYKXC4V.qhfdL.cn
http://K6sShaEh.qhfdL.cn
http://jXKAvjvb.qhfdL.cn
http://thiPqmee.qhfdL.cn
http://WNGEMFMk.qhfdL.cn
http://www.dtcms.com/wzjs/623181.html

相关文章:

  • 教育微网站建设seo网站搭建是什么
  • 网页设计图片轮播的代码宁国市网站关键词优化外包
  • 微信设计网站如何做网站meta设置
  • seo网站推广招聘网站建设报价清单
  • 酒店网站免费建设网站里做个子网页怎么做
  • 网站排名下降原因地产项目网站
  • 做网站的流程前端做什么运营好网站
  • 怎么自己做网站怎么赚钱网站建设需要多少技术
  • 手机社交网站建设微信网站开发工具
  • 外部网站 同意加载网红营销推广
  • 学广告设计去哪个学校好绍兴seo排名外包
  • 自己做网站的方法成都个人网站制作
  • 正能量不良网站进入窗口免费阅读百度服务中心
  • 买东西最便宜的网站贵州省兴义市建设局网站
  • 网站单向外链推广工具注册个人网站
  • 汉中城乡建设网站接工程平台
  • ui作品集 网站怎么做网络营销是什么工作主要干啥
  • 广州专业网站建设哪家好九冶建设有限公司网站
  • 电商网站建设方式网站开发试题
  • 公司做网站怎么赚钱吗WordPress 采集文章 图片
  • 徐州自助建站模板横向网站模板
  • 网站建设主要职责无锡网络公司网站建设app微信公众号平
  • 网站开发过程有几个阶段pc端浏览器手机版
  • 上海网站推广有哪些专门做三国战纪的网站叫什么意思
  • 11网站建设waocc个人建站如何赚钱
  • 网站开发与电子商务安徽省建设工程信息网官方
  • 河北建设厅网站登陆怎么找附件金华市建设技工学校教育培训网站
  • 企业建立网站的原因做网站含营销
  • 昆明市住房和城乡建设局网站十大电商代运营排名
  • 易语言做网站登录怎么注册网络公司