Reference:
一.vector 的构造函数形式
-
(1)vector():创建一个空vector
-
(2)vector(int nSize): 创建一个vector,元素个数为nSize,每个值默认初始化为0;
vector(int nSize,const t& t): 创建一个vector,元素个数为nSize,且值均为t -
(3)vector(begin,end):复制[begin,end)区间内另一个数组的元素到vector中.
-
(4)vector(const vector&):复制构造函数
1、vector( const Allocator& = Allocator() );
2、vector( size_type n,constT& value = T(), const Allocator& = Allocator() );
3、template vector ( InputIterator first, InputIterator last, const Allocator& = Allocator() );
4、vector ( const vector<T,Allocator>& x );
除了第4个构造函数,其他的几个构造函数都有一个缺省参数Allocator,它是用于指定要使用的空间配置器的,STL提供的默认的空间配置器,我们基本不用管这个参数,除非是我们自己实现了一个空间配置器,然后希望使用我们自己写的空间配置器。
各个构造函数的使用:
-
Ⅰ.vector( size_type n,constT& value = T(), const Allocator& = Allocator() );
-
Ⅱ.vector()
-
Ⅲ.vector(begin,end)
-
Ⅳ. vector ( const vector<T,Allocator>& x );
拷贝构造函数,根据一个vector对象构建一个新的vector对象
注意,拷贝有深拷贝和浅拷贝两种方式。 一般在创建一个新的对象时使用的就是深拷贝,即元素值相同,地址空间不同,而在使用一个vector对象进行值传递传参时,使用的就是浅拷贝,即形参是实参的一份临时拷贝。这往往是会出问题的,所以建议在使用vector作为参数时,尽量传引用。
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector<int>::iterator v1_iter,v2_iter,v3_iter,v4_iter;
//创建一个长度为3,初始值为0的int型向量--------------------------
vector<int> v1(3);
cout<<"v1 = :";
for(v1_iter = v1.begin(); v1_iter != v1.end();v1_iter ++)
cout<<" "<<*v1_iter;
cout<<endl;
//创建一个长度为5,初始值为2的int型向量---------------------------------
vector<int> v2(5,2);
cout<<"v2 = :";
for(v2_iter = v2.begin(); v2_iter != v2.end();v2_iter ++)
cout<<" "<<*v2_iter;
cout<<endl;
//创建一个int型向量,并用v2初始化它--------------===----------------------
vector<int> v3(v2);
cout<<"v3 = :";
for(v1_iter = v3.begin(); v1_iter != v3.end();v1_iter ++)
cout<<" "<<*v1_iter;
cout<<endl;
//创建一个nt型向量,并用v2部分元素初始化它------------------------------------
vector<int> v4(v2.begin()+1,v2.begin()+3);
cout<<"v4 = :";
for(v4_iter = v4.begin(); v4_iter != v4.end();v4_iter ++)
cout<<" "<<*v4_iter;
cout<<endl;
system("pause");
return 0;
}
二. vector的大小和容量
vector<T> ::size_type size() const:返回向量中元素的个数
vector<T> ::size_type capacity() const:返回当前向量张红所能容纳的最大元素值
vector<T> ::size_type max_size() const:返回最大可允许的vector元素数量值
容器对象调用**size()**可以知道当前容器里面有多少个元素,对vector向量对象来说,就是当前存放的元素的个数。
容器对象调用**capacity()**函数,可以知道容器的大小,也就是当前容器对象可用容纳的元素个数。Capacity随着向量的元素的增加而增加,当size() ==capacity()时,容器会自动重新alloc内存,增加一倍的内存。
当创建空容器时, 容量(capacity)为 0;当用完时,增加原容量的 1/2 (各编译器 可能存在差异 vs2013是这样的,mingw则 增加原容量 )–适用如 vector这种 元素连续存储的容器, 如为list则不同。
capacity 一般大于size的原因是为了避免 每次增加数据时都要重新分配内存,所以一般会 生成一个较大的空间,以便随后的数据插入。
vector 的reserve增加了vector的capacity,但是它的size没有改变!而resize改变了vector的capacity同时也增加了它的size!
原因如下:
reserve是容器预留空间,但在空间内不真正创建元素对象,所以在没有添加新的对象之前,不能引用容器内的元素。加入新的元素时,要调用push_back()/insert()函数。
resize是改变容器的大小,且在创建对象,因此,调用这个函数之后,就可以引用容器内的对象了,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。此时再调用push_back()函数,是加在这个新的空间后面的。
两个函数的参数形式也有区别的,reserve函数之后一个参数,即需要预留的容器的空间;resize函数可以有两个参数,第一个参数是容器新的大小,第二个参数是要加入容器中的新元素,如果这个参数被省略,那么就调用元素对象的默认构造函数。下面是这两个函数使用例子:
三. vetor 对象上的操作
1.插入元素:push_back()
(1)**push_back()**添加到末尾
void push_back (const value_type& val);
a.push_back( val); //a是vector向量
如果vector的容器已满,在末尾添加元素时会alloc申请更大的内存,并拷贝之前的元素到新内存,再把元素添加到vector容器末尾
(2)insert()插入一个元素
1) insert (iterator position, const value_type& val)
传入的参数是迭代器的位置和需要插入的元素val。
Position可以是a.begin(),也可以是a.end(),或者这两者中间的一个迭代器位置
2)void insert (iterator position, size_type n, const value_type& val);
在position位置开始,插入n个值为val的元素
3)void insert (iterator position, InputIterator first, InputIterator last);
在position位置插入first(比如数组首地址)到last(比如数组首地址+n)之间的元素。
最常用的是insert (iterator position, const value_type& val);
总结
insert() 函数有以下三种用法:
1、在指定位置loc前插入值为val的元素,返回指向这个元素的迭代器
2、在指定位置loc前插入num个值为val的元素
3、在指定位置loc前插入区间[start, end)的所有元素
//创建一个vector,置入字母表的前十个字符
vector <char> Avector;
for( int i=0; i < 10; i++ )
Avector.push_back( i + 65 );
//插入四个C到vector中
vector <char>::iterator theIterator = Avector.begin();
Avector.insert( theIterator, 4, 'C' );
//显示vector的内容
for( theIterator = Avector.begin(); theIterator != Avector.end(); theIterator++ )
cout < < *theIterator;
2.查找:find()
调用find方法(需要include)
template <class InputIterator, class T>
InputIterator find (InputIterator first, InputIterator last, const T& val)
//如查找元素为value,找到则返回迭代器的位置,否则迭代器将指向end()
std::vector < Type >:: iterator iVector;
iVector = std::find(a.begin(), a.end() , value);
if( iVector != a.end()){
找到了
}
else{
没找到
}
3.删除末尾元素或者删除全部元素:pop_back()/erase()/clear()
iterator erase(iterator it):删除向量中迭代器指向元素
iterator erase(iterator first,iterator last):删除向量中[first,last)中元素
void pop_back():删除向量中最后一个元素
void clear():清空向量中所有元素
(1)删除一个末尾元素
a.pop_back();
//删除操作避免大量移动的方法,如果元素有申请堆栈的内存,需要换另外一种方法删除,因为需要先获取元素,释放元素指向的申请内存后,才能做删除操作,不然会造成内存泄漏。
(2)删除全部元素
while(pVector->size() != 0)
{
//pop_back方法无返回值
pVector->pop_back();
//删除操作避免大量移动的方法,如果元素有申请堆栈的内存,不可用此方法
}
(3)调用clear函数删除全部元素
a.clear()
(4)另外一种删除全部元素的方法:erase()
//这种方法针对元素有另外申请内存的情况下比较有用,比如元素是一个结构体或者对象,有成员p申请了堆内存,删除元素前要释放内存。
VectorT::iterator iVector = a.begin();
while(iVector != a.end())
{
delete (*iVector)->p;
iVector = a.erase(iVector);
//执行erase后,iVector将指向删除的元素的下一个元素
}
(5).删除一个不一定是末尾的元素
//先执行find查找value的值,在vector容器里面就删除
VectorType::iterator iVector = std::find(a.begin(), a.end(), value);
if(iVector != a.end()){
a.erase(iVector); //参数只能是迭代器
//std::cout<<" erase success "<< m<<std::endl;
}
4.遍历
reference at(int pos):返回pos位置元素的引用
reference front():返回首元素的引用
reference back():返回尾元素的引用
iterator begin():返回向量头指针,指向第一个元素
iterator end():返回向量尾指针,指向向量最后一个元素的下一个位置
reverse_iterator rbegin():反向迭代器,指向最后一个元素
reverse_iterator rend():反向迭代器,指向第一个元素之前的位置
//利用迭代器,一开始迭代器iVector指向begin,只要不等于end,就继续遍历下去
typedef std::vector < Type > VectorT;
VectorT a;
VectorT::iterator iVector = a.begin();
while(iVector != a.end()){
std::cout<<" dump "<< (*iVector)<<std::endl;
++iVector;
}
5.排序:sort()
std::sort( a.begin() , a.end() );
也可以是
std::sort( a.begin() , a.begin() + 4 );
反正就是传入排序的位置范围。默认是升序
另外可以实现自己的排序函数Compare comp
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);
6.判断函数:empty()
bool empty() const:判断向量是否为空,若为空,则向量中无元素
7.反向迭代器(rbegin,rend)
c.begin() 返回一个迭代器,它指向容器c的第一个元素
c.end() 返回一个迭代器,它指向容器c的最后一个元素的下一个位置
c.rbegin() 返回一个逆序迭代器,它指向容器c的最后一个元素
c.rend() 返回一个逆序迭代器,它指向容器c的第一个元素前面的位置
上述每个操作都有两个不同的版本:一个是const成员,另一个是非const成员。这些操作返回什么类型取决于容器是否为const。如果容器不是const,则这些操作返回iterator或reverse_iterator类型。如果容器是const,则其返回类型要加上const_前缀,也就是const_iterator和const_reverse_iterator类型。
8.:assign()
函数原型:
void assign(const_iterator first,const_iterator last);
void assign(size_type n,const T& x = T());
功能:
将区间[first,last)的元素赋值到当前的vector容器中,或者赋n个值为x的元素到vector容器中,这个容器会清除掉vector容器中以前的内容。
举例
#include <vector>
#include <iostream>
int main( )
{
using namespace std;
vector<int> v1, v2, v3;
vector<int>::iterator iter;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(50);
v2.push_back(1);
v2.push_back(2);
cout << "v1 = " ;
for (iter = v1.begin(); iter != v1.end(); iter++)
cout << *iter << " ";
cout << endl;
cout << "v2 = ";
for (iter = v2.begin(); iter != v2.end(); iter++)
cout << *iter << " ";
cout << endl;
v2 = v1;
cout << "v2 = ";
for (iter = v2.begin(); iter != v2.end(); iter++)
cout << *iter << " ";
cout << endl;
v2.assign(v1.begin(), v1.end());
cout << "v2 = ";
for (iter = v2.begin(); iter != v2.end(); iter++)
cout << *iter << " ";
cout << endl;
v3.assign(7, 3) ;
cout << "v3 = ";
for (iter = v3.begin(); iter != v3.end(); iter++)
cout << *iter << " ";
cout << endl;
return 0;
}
四.vector 操作总结
(1)a.assign(b.begin(), b.begin()+3);//b为向量,将b的0~2个元素构成的向量赋给a
(2)a.assign(4,2);//是a只含4个元素,且每个元素为2
(3)a.back();//返回a的最后一个元素
(4)a.front();//返回a的第一个元素
(5)a[i]; //返回a的第i个元素,当且仅当a[i]存在2013-12-07
(6)a.clear();//清空a中的元素
(7)a.empty();//判断a是否为空,空则返回ture,不空则返回false
(8)a.pop_back();//删除a向量的最后一个元素
(9)a.erase(a.begin()+1,a.begin()+3);//删除a中第1个(从第0个算起)到第2个元素,也就是说删除的元素从a.begin()+1算起(包括它)一直到a.begin()+3(不包括它)
(10)a.push_back(5);//在a的最后一个向量后插入一个元素,其值为5
(11)a.insert(a.begin()+1,5);//在a的第1个元素(从第0个算起)的位置插入数值5,如a为1,2,3,4,插入元素后为1,5,2,3,4
(12)a.insert(a.begin()+1,3,5);//在a的第1个元素(从第0个算起)的位置插入3个数,其值都为5
(13)a.insert(a.begin()+1,b+3,b+6);//b为数组,在a的第1个元素(从第0个算起)的位置插入b的第3个元素到第5个元素(不包括b+6),如b为1,2,3,4,5,9,8,插入元素后为1,4,5,9,2,3,4,5,9,8
(14)a.size();//返回a中元素的个数;
(15)a.capacity();//返回a在内存中总共可以容纳的元素个数
(16)a.rezize(10);//将a的现有元素个数调至10个,多则删,少则补,其值随机
(17)a.rezize(10,2);//将a的现有元素个数调至10个,多则删,少则补,其值为2
(18)a.reserve(100);//将a的容量(capacity)扩充至100,也就是说现在测试a.capacity();的时候返回值是100.这种操作只有在需要给a添加大量数据的时候才 显得有意义,因为这将避免内存多次容量扩充操作(当a的容量不足时电脑会自动扩容,当然这必然降低性能)
(19)a.swap(b);//b为向量,将a中的元素和b中的元素进行整体性交换
(20)a==b; //b为向量,向量的比较操作还有!=,>=,<=,>,<
五.几种重要的算法
使用时需要包含头文件:
#include <algorithm>
(1)sort(a.begin(),a.end());
//对a中的从a.begin()(包括它)到a.end()(不包括它)的元素进行从小到大排列
(2)reverse(a.begin(),a.end());
//对a中的从a.begin()(包括它)到a.end()(不包括它)的元素倒置,但不排列,如a中元素为1,3,2,4,倒置后为4,2,3,1
(3)copy(a.begin(),a.end(),b.begin()+1);
//把a中的从a.begin()(包括它)到a.end()(不包括它)的元素复制到b中,从b.begin()+1的位置(包括它)开始复制,覆盖掉原有元素
(4)find(a.begin(),a.end(),10);
//在a中的从a.begin()(包括它)到a.end()(不包括它)的元素中查找10,若存在返回其在向量中的位置
六.选用vector与 deque
- Vector:
动态数组,内存中一整块连续区域。支持.reserve()和.capacity()。为提高效率,最好在添加元素之前用.reserve()分配好容量。插入删除操作越靠近数组首部效率越低。
- deque(double ended queue):
动态数组,内存中多段连续区域拼凑。不支持reserve()和capacity()函数。首尾插入删除操作相对效率高。
总结:
vector和deque都是动态数组类型的,都可通过[]访问。一般选择vector, 但当需要从首尾两端进行插入或删除元素操作时,应该选择deque.
七.二维vector初始化
//二维vector初始化
vector< vector<int> > vt;//初始化一个 二维vector
vector<vector<int> > vect(vt);//使用另一个 二维 vector 初始化当前二维vector
vector< vector<int> > vec(row,vector<int>(column));//初始化一个 二维的vector 行row,列column,且值为0
vector<vector<int> > visited(row,vector<int>(column,6));//初始化一个 二维vector 行row,列column ,且 值为data=6 自定义data;
vector<vector<int> > vecto(row,vector<int>(vt[0].begin()+1,vt[0].begin()+3));初始化一个 二维vector 行row,第二个参数为一维vector;
八. C++数组初始化
参考:C++数组初始化方法
定义
int *pia = new int[10];
此 new 表达式分配了一个含有 10 个 int 型元素的数组,并返回指向该数组第一个元素的指针,此返回值初始化了指针 pia。
typedef int arrT[10];
//arrT表示10个int的数组类型
int *pi1 = new arrT
; //10个未初始化的int
int *pi2 = new arrT()
; //10个初始化为0的int
int *pi3 = new arrT{0,1,2,3,4,5,6,7,8,9}
; //VS2010不支持
在自由存储区中创建的数组对象是没有名字的,只能通过其地址间接地访问堆中的对象。
注意:C++使用new和delete在堆(自由存储区)上分配和释放动态数组。
动态数组初始化
-
元素只能初始化为元素类型的默认值,而不能像数组变量一样,用初始化列表为数组元素提供各不相同的初值。
-
对于内置数据类型元素的数组,必须使用()来显示指定程序执行初始化操作,否则程序不执行初始化操作:
int *pia = new int[10]; // 每个元素都没有初始化
int *pia2 = new int[10] (); // 每个元素初始化为0,括号内不能写其他值,只能初始化为0
3.类类型元素的数组,则无论是否使用(),都会自动调用其默认构造函数来初始化:
string *psa = new string[10]; // 每个元素调用默认构造函数初始化
string *psa = new string[10](); // 每个元素调用默认构造函数初始化
动态分配空数组
char *cp = new char[0]
;之后,可以动态改变cp的维数。
动态释放
delete [] pia;
示例
const char *pc = "a very long literal string"; // 处理C风格字符串时使用const指针
const size_t len = strlen(pc) +1; // size_t用于数组的大小和下标
for (size_t ix = 0; ix != 1000000; ++ix) {
char *pc2 = new char[len]; // pc2指向的存储空间的内容会动态改变,因此不使用const
strncpy (pc2, pc, len); // 使用strncpy比使用strcpy安全
// do something;
delete [] pc2;
}
九.范围for循环
vector<int> v(10, 2);
for (auto &r : v) {
r *= 2;
}
==============================================>>>>>>>>>>>>>
for (auto beg = v.begin(), end = v.end(); beg != end; ++beg) {
auto &r = *beg;
r *= 2;
}