C++Vector使用方法

C++内置的数组支持容器的机制,可是它不支持容器抽象的语义。要解决此问题我们自己实现这种类。在标准C++中,用容器向量(vector)实现。容器向量也是一个类模板。
标准库vector类型使用须要的头文件:#include <vector>。vector 是一个类模板。不是一种数据类型,vector<int>是一种数据类型。Vector的存储空间是连续的,list不是连续存储的。

一、 定义和初始化
vector< typeName > v1;       //默认v1为空,故以下的赋值是错误的v1[0]=5;
vector<typeName>v2(v1); 或v2=v1;或vector<typeName> v2(v1.begin(), v1.end());//v2是v1的一个副本,若v1.size()>v2.size()则赋值后v2.size()被扩充为v1.size()。
vector< typeName > v3(n,i);//v3包括n个值为i的typeName类型元素
vector< typeName > v4(n); //v4含有n个值为0的元素
int a[4]={0,1,2,3,3}; vector<int> v5(a,a+5);//v5的size为5,v5被初始化为a的5个值。后一个指针要指向将被拷贝的末元素的下一位置。
vector<int> v6(v5);//v6是v5的拷贝
vector< 类型 > 标识符(最大容量,初始全部值);

 

二、 值初始化
1>     假设没有指定元素初始化式,标准库自行提供一个初始化值进行值初始化。
2>     假设保存的式含有构造函数的类类型的元素,标准库使用该类型的构造函数初始化。
3>     假设保存的式没有构造函数的类类型的元素,标准库产生一个带初始值的对象,使用这个对象进行值初始化。


三、vector对象最重要的几种操作
1. v.push_back(t)    在容器的最后加入一个值为t的数据,容器的size变大。
    另外list有push_front()函数,在前端插入,后面的元素下标依次增大。
2. v.size()        返回容器中数据的个数,size返回对应vector类定义的size_type的值。v.resize(2*v.size)或                  

v.resize(2*v.size, 99) 将v的容量翻倍(并把新元素的值初始化为99)
3. v.empty()     推断vector是否为空
4. v[n]           返回v中位置为n的元素
5. v.insert(pointer,number, content)    向v中pointer指向的位置插入number个content的内容。
    还有v. insert(pointer, content),v.insert(pointer,a[2],a[4])将a[2]到a[4]三个元素插入。
6. v.pop_back()    删除容器的末元素,并不返回该元素。
7.v.erase(pointer1,pointer2) 删除pointer1到pointer2中间(包含pointer1所指)的元素。
   vector中删除一个元素后,此位置以后的元素都须要往前移动一个位置,尽管当前迭代器位置没有自己主动加1,
   可是因为兴许元素的顺次前移,也就相当于迭代器的自己主动指向下一个位置一样。
8. v1==v2          推断v1与v2是否相等。
9. !=、<、<=、>、>=      保持这些操作符惯有含义。
10. vector<typeName>::iterator p=v1.begin( ); p初始值指向v1的第一个元素。*p取所指向元素的值。
      对于const vector<typeName>仅仅能用vector<typeName>::const_iterator类型的指针訪问。
11.   p=v1.end( ); p指向v1的最后一个元素的下一位置。
12.v.clear()      删除容器中的全部元素。12.v.clear()      删除容器中的全部元素。

#include<algorithm>中的泛函算法
搜索算法:find() 、search() 、count() 、find_if() 、search_if() 、count_if()
分类排序:sort() 、merge()
删除算法:unique() 、remove()
生成和变异:generate() 、fill() 、transformation() 、copy()
关系算法:equal() 、min() 、max()
sort(v1.begin(),vi.begin()+v1.size/2); 对v1的前半段元素排序
list<char>::iterator pMiddle =find(cList.begin(),cList.end(),'A');找到则返回被查内容第一次出现处指针,否则返回end()。
vector< typeName >::size_type x ; vector< typeName >类型的计数,可用于循环如同for(int i)


初学C++的程序猿可能会觉得vector的下标操作能够加入元素,事实上不然:

vector<int> ivec;   // empty vector

for (vector<int>::size_type ix = 0; ix != 10; ++ix)

     ivec[ix] = ix; // disaster: ivec has no elements

上述程序试图在ivec中插入10个新元素,元素值依次为0到9的整数。可是,这里ivec是空的vector对象,并且下标仅仅能用于获取已存在的元素。

这个循环的正确写法应该是:

for (vector<int>::size_type ix = 0; ix != 10; ++ix)

     ivec.push_back(ix); // ok: adds new element with value ix


警告:必须是已存在的元素才干用下标操作符进行索引。通过下标操作进行赋值时,不会加入不论什么元素。仅能对确知已存在的元素进行下标操作 

  

四、内存管理与效率

      1.使用reserve()函数提前设定容量大小,避免多次容量扩充操作导致效率低下。

      关于STL容器,最令人称赞的特性之中的一个就是是仅仅要不超过它们的最大大小,它们就能够自己主动增长到足以容纳你放进去的数据。(要知道这个最大值,仅仅要调用名叫max_size的成员函数。)对于vector和string,假设须要很多其它空间,就以相似realloc的思想来增长大小。vector容器支持随机訪问,因此为了提高效率,它内部使用动态数组的方式实现的。在通过 reserve() 来申请特定大小的时候总是按指数边界来增大其内部缓冲区。当进行insert或push_back等添加元素的操作时,假设此时动态数组的内存不够用,就要动态的又一次分配当前大小的1.5~2倍的新内存区,再把原数组的内容复制过去。所以,在普通情况下,其訪问速度同一般数组,仅仅有在又一次分配发生时,其性能才会下降。正如上面的代码告诉你的那样。而进行pop_back操作时,capacity并不会由于vector容器里的元素降低而有所下降,还会维持操作之前的大小。对于vector容器来说,假设有大量的数据须要进行push_back,应当使用reserve()函数提前设定其容量大小,否则会出现很多次容量扩充操作,导致效率低下。

      reserve成员函数同意你最小化必须进行的又一次分配的次数,因而能够避免真分配的开销和迭代器/指针/引用失效。但在我解释reserve为什么能够那么做之前,让我简要介绍有时候令人困惑的四个相关成员函数。在标准容器中,仅仅有vector和string提供了全部这些函数。

(1) size()告诉你容器中有多少元素。它没有告诉你容器为它容纳的元素分配了多少内存。
(2) capacity()告诉你容器在它已经分配的内存中能够容纳多少元素。那是容器在那块内存中总共能够容纳多少元素,而不是还能够容纳多少元素。假设你想知道一个vector或string中有多少没有被占用的内存,你必须从capacity()中减去size()。假设size和capacity返回相同的值,容器中就没有剩余空间了,而下一次插入(通过insert或push_back等)会引发上面的又一次分配步骤。
(3) resize(Container::size_type n)强制把容器改为容纳n个元素。调用resize之后,size将会返回n。假设n小于当前大小,容器尾部的元素会被销毁。假设n大于当前大小,新默认构造的元素会加入到容器尾部。假设n大于当前容量,在元素加入之前会发生又一次分配。
(4) reserve(Container::size_type n)强制容器把它的容量改为至少n,提供的n不小于当前大小。这一般强迫进行一次又一次分配,由于容量须要添加。(假设n小于当前容量,vector忽略它,这个调用什么都不做,string可能把它的容量降低为size()和n中大的数,但string的大小没有改变。在我的经验中,使用reserve来从一个string中修整多余容量一般不如使用“交换技巧”,那是条款17的主题。)

     这个简单介绍表示了仅仅要有元素须要插入并且容器的容量不足时就会发生又一次分配(包含它们维护的原始内存分配和回收,对象的拷贝和析构和迭代器、指针和引用的失效)。所以,避免又一次分配的关键是使用reserve尽快把容器的容量设置为足够大,最好在容器被构造之后立马进行。

比如,假定你想建立一个容纳1-1000值的vector<int>。没有使用reserve,你能够像这样来做:

vector<int> v;
for (int i = 1; i <= 1000; ++i) v.push_back(i);
在大多数STL实现中,这段代码在循环过程中将会导致2到10次又一次分配。(10这个数没什么奇怪的。记住vector在又一次分配发生时一般把容量翻倍,而1000约等于210。)

把代码改为使用reserve,我们得到这个:

vector<int> v;
v.reserve(1000);
for (int i = 1; i <= 1000; ++i) v.push_back(i);
这在循环中不会发生又一次分配。

在大小和容量之间的关系让我们能够预言什么时候插入将引起vector或string运行又一次分配,并且,能够预言什么时候插入会使指向容器中的迭代器、指针和引用失效。比如,给出这段代码,

string s;
...
if (s.size() < s.capacity()) {
s.push_back('x');
}
push_back的调用不会使指向这个string中的迭代器、指针或引用失效,由于string的容量保证大于它的大小。假设不是运行push_back,代码在string的任何位置进行一个insert,我们仍然能够保证在插入期间没有发生又一次分配,可是,与伴随string插入时迭代器失效的一般规则一致,全部从插入位置到string结尾的迭代器/指针/引用将失效。

回到本条款的主旨,通常有两情况使用reserve来避免不必要的又一次分配。第一个可用的情况是当你确切或者大约知道有多少元素将最后出如今容器中。那样的话,就像上面的vector代码,你仅仅是提前reserve适当数量的空间。另外一种情况是保留你可能须要的最大的空间,然后,一旦你加入完所有数据,修整掉不论什么多余的容量。

       2.使用“交换技巧”来修整vector过剩空间/内存

      有一种方法来把它从以前最大的容量降低到它如今须要的容量。这样降低容量的方法经常被称为“收缩到合适(shrink to fit)”。该方法仅仅需一条语句:vector<int>(ivec).swap(ivec);
表达式vector<int>(ivec)建立一个暂时vector,它是ivec的一份拷贝:vector的拷贝构造函数做了这个工作。可是,vector的拷贝构造函数仅仅分配拷贝的元素须要的内存,所以这个暂时vector没有多余的容量。然后我们让暂时vector和ivec交换数据,这时我们完毕了,ivec仅仅有暂时变量的修整过的容量,而这个暂时变量则持有了以前在ivec中的没用到的过剩容量。在这里(这个语句结尾),暂时vector被销毁,因此释放了以前ivec使用的内存,收缩到合适。

     3.用swap方法强行释放STL Vector所占内存

template < class T> void ClearVector( vector<T>& v )
{
    vector<T>vtTemp;
    vtTemp.swap( v );
}

    vector<int> v ;
    nums.push_back(1);
    nums.push_back(3);
    nums.push_back(2);
    nums.push_back(4);
    vector<int>().swap(v);

/* 或者v.swap(vector<int>()); */

/*或者{ std::vector<int> tmp = v;   v.swap(tmp);   }; //加大括号{ }是让tmp退出{ }时自己主动析构*/

 

五、Vector 内存管理成员函数的行为測试
C++ STL的vector使用很广泛,可是对其内存的管理模型一直有多种推測,以下用实例代码測试来了解其内存管理方式,測试代码例如以下:

#include <iostream>
#include <vector>
using namespace std;

int main()
{
vector<int> iVec;
cout << "容器 大小为: " << iVec.size() << endl;
cout << "容器 容量为: " << iVec.capacity() << endl; //1个元素, 容器容量为1

iVec.push_back(1);
cout << "容器 大小为: " << iVec.size() << endl;
cout << "容器 容量为: " << iVec.capacity() << endl; //2个元素, 容器容量为2

iVec.push_back(2);
cout << "容器 大小为: " << iVec.size() << endl;
cout << "容器 容量为: " << iVec.capacity() << endl; //3个元素, 容器容量为4

iVec.push_back(3);
cout << "容器 大小为: " << iVec.size() << endl;
cout << "容器 容量为: " << iVec.capacity() << endl; //4个元素, 容器容量为4

iVec.push_back(4);
iVec.push_back(5);
cout << "容器 大小为: " << iVec.size() << endl;
cout << "容器 容量为: " << iVec.capacity() << endl; //5个元素, 容器容量为8

iVec.push_back(6);
cout << "容器 大小为: " << iVec.size() << endl;
cout << "容器 容量为: " << iVec.capacity() << endl; //6个元素, 容器容量为8

iVec.push_back(7);
cout << "容器 大小为: " << iVec.size() << endl;
cout << "容器 容量为: " << iVec.capacity() << endl; //7个元素, 容器容量为8

iVec.push_back(8);
cout << "容器 大小为: " << iVec.size() << endl;
cout << "容器 容量为: " << iVec.capacity() << endl; //8个元素, 容器容量为8

iVec.push_back(9);
cout << "容器 大小为: " << iVec.size() << endl;
cout << "容器 容量为: " << iVec.capacity() << endl; //9个元素, 容器容量为16
/* vs2005/8 容量增长不是翻倍的,如
    9个元素   容量9
    10个元素 容量13 */

/* 測试effective stl中的特殊的交换 swap() */
cout << "当前vector 的大小为: " << iVec.size() << endl;
cout << "当前vector 的容量为: " << iVec.capacity() << endl;
vector<int>(iVec).swap(iVec);

cout << "暂时的vector<int>对象 的大小为: " << (vector<int>(iVec)).size() << endl;
cout << "暂时的vector<int>对象 的容量为: " << (vector<int>(iVec)).capacity() << endl;
cout << "交换后,当前vector 的大小为: " << iVec.size() << endl;
cout << "交换后,当前vector 的容量为: " << iVec.capacity() << endl;

return 0;
}

 

 六、vector的其它成员函数

c.assign(beg,end)
将[beg; end)区间中的数据赋值给c。
c.assign(n,elem)
将n个elem的拷贝赋值给c。
c.at(idx)
传回索引idx所指的数据,假设idx越界,抛出out_of_range。
c.back()
传回最后一个数据,不检查这个数据是否存在。
c.front()
传回地一个数据。
get_allocator
使用构造函数返回一个拷贝。
c.rbegin()
传回一个逆向队列的第一个数据。
c.rend()
传回一个逆向队列的最后一个数据的下一个位置。
c.~ vector <Elem>()
销毁全部数据,释放内存。  

转载于:https://www.cnblogs.com/mengfanrong/p/3770971.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/293656.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

岛国人气美少女竟然每晚跟 3 个人通宵打麻将?

1 桥本怕不是四川人?▼2 借口总比困难多▼3 突然觉得自己是大厨▼4 连自己都不放过▼5 这就是纹身的烦恼▼6 这又是什么黑暗料理&#xff08;via.坏蛋王师傅&#xff09;▼7 哦吼&#xff0c;是在下输了▼7 哦吼&#xff0c;是在下输了▼你点的每个赞&#xff0c;我都认…

java获取ResultSet长度

2019独角兽企业重金招聘Python工程师标准>>> public class Test { public static void main(String[] args) throws SQLException { Connection conn WLMGlobal.connMgr_stat_instance().getConnection(); Statement stmt conn.createStatement(Result…

浅谈协同过滤推荐算法

在现今的推荐技术和算法中&#xff0c;最被大家广泛认可和采用的就是基于协同过滤的推荐方法。本文将带你深入了解协同过滤的秘密。 1 什么是协同过滤 协同过滤是利用集体智慧的一个典型方法。要理解什么是协同过滤 (Collaborative Filtering, 简称 CF)&#xff0c;首先想一个简…

C# wpf编程CM框架快速入门项目实例

01—事件连接这会自动将控件上的事件关联到ViewModel上的方法。常规约定&#xff1a;<Button x:Name"Save">这将导致按钮的单击事件调用ViewModel上的“Save”方法。简短语法&#xff1a;<Button cal:Message.Attach"Save">这将再次导致按钮的…

Android之两个应用之间的通信与调用

Android 里面的两个APK通信的方式有哪些&#xff1f; 自己网上查了查&#xff0c;总结了一下&#xff1a; 1. 广播&#xff0c;最简单的方法&#xff0c;这个实现起来比较简单 2. AIDL&#xff0c;功能强大&#xff0c;支持一对多并发通信&#xff0c;支持实时通信。 3. 网…

NSString 字符串 操作 常用

//将NSData转化为NSString NSString* str [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];//将NSString 转化为NSData (NSString.h)- (NSData *)dataUsingEncoding:(NSStringEncoding)encoding; //载一个字符串中删除一个字符或字符串[_di…

[HTML5]3D标签云

index.html <html> <head> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <title>3D标签云</title> <link rel"stylesheet" type"text/css" href"http://webapplee-word…

正则表达式匹配字符串的问题

如何用正则表达式做模糊查询&#xff1f;&#xff1f; 是可以的比如“.*?name.*?”就可以匹配找出所有含有"name"的字符串&#xff0c;就像mysql查询用"where .. like %name%"一样的。并且正则可以更灵活&#xff0c;如果你写的".*?name\d{2}.*?&…

java.lang.IllegalStateException: attempt to re-open an already-closed object

这个错误出现的原因是因为我在一个数据库操作的时候&#xff0c;在循环读取数据的时候&#xff0c;把datebase给close了&#xff0c;会出现这样的错误&#xff0c;还有一直情况就是我们在写数据库操作的时候&#xff0c;需要调用到其它函数的相关操作&#xff0c;当其它函数操作…

sas常用选项

System options&#xff1a; obs&#xff1a;表示需要处理的最后一行observation&#xff0c;如果指定其为max&#xff0c;就表示处理到最后一条observation firstobs&#xff1a;表示需要从第几行observation开始处理&#xff0c;默认是1observation msglevel&#xff1a;默认…

我的2021年终总结:初为人父,从头再来

【年终总结】| 作者/Edison最近公司开始一股年终总结浪潮&#xff0c;看着同事们写大作文式的“内卷”总结&#xff0c;我不禁在想我这一年做了什么&#xff0c;那么也就有了这篇总结推文&#xff0c;当然它也是我每年的习惯。传送门&#xff1a;Edison的2020年终总结1也谈2021…

Java 基础【09】你的多继承纳?

Java省略了许多很少用到&#xff0c;缺乏了解&#xff0c;混淆功能的C &#xff0c;在我们的经验中带来更多的悲伤大于收益 。 -----James Gosling James Gosling 这个人大家应该很熟悉&#xff0c;就是最初设计Java 语言的的程序…

开源项目导入eclipse的一般步骤[转]

下载到开源项目后&#xff0c;我们还是希望导入到eclipse中还看&#xff0c;这样要方便点&#xff0c;一般的步骤是这样的 打开源代码目录&#xff0c; 如果看到里面有.calsspath .project文件&#xff0c;那么说明这个项目本来就是eclipse开发的&#xff0c;那么在eclipse中-&…

死锁活锁

死锁&#xff1a; 是指两个或两个以上的进程在执行过程中&#xff0c;因争夺资源而造成的一种互相等待的现象&#xff0c;若无外力作用&#xff0c;它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁&#xff0c;这些永远在互相等待的进程称为死锁进程。 由于资源…

说说可重复函数(Reentrant) 和线程安全(thread-safe)的区别与联系

在讲可重复函数与线程安全之前先来了解什么是可重复函数和线程安全。可重复函数&#xff1a;在多线程或有异常控制流的情况下,当某个函数运行到中途时,控制流(也就是当前指令序列)就有可能被打断而去执行另一个函数.而"另一个函数"很有可能是它本身.&#xff0c;如果…

inputn函数与input函数的区别

inputn函数与input函数的区别(这里的比较类似于前面的inputc函数) ①input函数可以将字符型变量转换为字符型或数值型&#xff0c;这取决于指定的输入格式informat&#xff1b;而inputn函数只能将字符型变量转换为数值型。从这个角度上看&#xff0c;跟inputc函数一样&#xff…

Blazor中的无状态组件

声明&#xff1a;本文将RenderFragment称之为组件DOM树或者是组件DOM节点&#xff0c;将*.razor称之为组件。1. 什么是无状态组件如果了解React&#xff0c;那就应该清楚&#xff0c;React中存在着一种组件&#xff0c;它只接收属性&#xff0c;并进行渲染&#xff0c;没有自己…

一次性撤稿70篇!中国学者论文再现大规模撤稿 | 附全名单

全世界只有3.14 % 的人关注了爆炸吧知识2021年1月20日&#xff0c;英国皇家化学学会&#xff08;Royal Society of Chemistry&#xff0c;简称RSC&#xff09;表示&#xff0c;他们正在考虑撤回68篇可能出自“论文工厂”的文章&#xff0c;但当时并没有公布这68篇文章的详情。近…