1.vector 的数据结构
vector采用简单的线性连续空间,以两个迭代器start和end分别指向头尾,并以迭代器end_of_storage指向容量尾端。容量可能比(尾-头)还大,多余即备用空间。简单来说就是,每个动态数组都分配有一定容量,当存储的数据达到容量的上限的时候,就重新分配内存
以两个迭代器start和end分别指向头尾,并以迭代器end_of_storage指向容量尾端。容量可能比(尾-头)还大,多余即备用空间。
以前一直以为在原来数组开辟的空间后面再增加,结果怎么想都没想明白。因为一般来说后面的内存已经被占用了,在后面增加是不可能的。结果是重新开辟了一个数组,把之前的值放到复制到新开辟的数组中来。
关于vector简单的说就是一个动态增长的数组,里面有一个指针指向一片连续的内存空间,当空间装不下要容纳的数据的时候会自动申请一片更大的空间(空间配置器)将原来的数据拷贝到新的空间,然后就会释放旧的空间。当删除的时候空间并不会释放只是清空了里面的数据。
使用start、finish、end_of_storage三个迭代器,便可轻易地提供首尾标示、大小、容量、空容器判断、中括号运算符value计算、首元素值、尾元素值等。
两个关键大小:
大小:size=_Mylast - _Myfirst;
容量:capacity=_Myend - _Myfirst;
分别对应于resize()、reserve()两个函数。
size表示vector中已有元素的个数,容量表示vector最多可存储的元素的个数;为了降低二次分配时的成本,vector实际配置的大小可能比客户需求的更大一些,以备将来扩充,这就是容量的概念。即capacity>=size,当等于时,容器此时已满,若再要加入新的元素时,就要重新进行内存分配,整个vector的数据都要移动到新内存。二次分配成本较高,在实际操作时,应尽量预留一定空间,避免二次分配。
2.下面是STL库中Vector 所对应的库函数
3.模拟实现vector
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#pragma once
//vector:动态的顺序表
namespace bite{
template<class T>
class vector{
public:
typedef T* iterator;
typedef T* reverse_iterator;
public:
//construct构造
vector()
:_start(nullptr)
, _finish(nullptr)
, _endofStorage(nullptr){}
vector(size_t n, const T& value){
_start = new T[n];
//向空间中存放n个值为value的元素
for (size_t i = 0; i < n; ++i)
_start[i] = value;
_finish = _endofStorage = _start + n;
}
vector(T* first, T* last){
size_t n = last - first;
_start = new T[n];
while (fiwst != last){
*_finish++ = *first++;
}
_endofStorage = _finish;
}
//注意浅拷贝
vector(const vector<T>& v);
vector<T>& operator=(const vector<T>& v);
~vector(){
if (_start){
delete[]_start;
_start = _finish = _endofStorage = nullptr;
}
}
//iterator迭代器
//迭代器类似指针
//第一个有效元素的位置
iterator begin(){
return _start;
}
//最后一个有效元素的位置
iterator end(){
return _finish;
}
reverse_iterator rbegin(){
return end();
}
reverse_iterator rend(){
return begin();
}
//capacity
size_t size()const{
return _finish - _start;
}
size_t capacity()const{
return _endofStorage - _start;
}
bool empty()const{
return _start == _finish;
}
//T():创建一个无名的对象
//T是内置类型,T()----->0
//T是自定义类型,T()--->调用该类无参的构造函数创建对象
void resize(size_t newSize, const & val = T()){
size_t oldSize = size();
if (newSize <= oldSize){
_finish = _start + newSize;
}
else{
//考虑是否需要扩容
if (newSize > capacity())
reserve(newSize);
//填充元素
for (size_t i = oldSize; i < oldSize; ++i)
*_finish++ = val;
}
}
void reserve(size_t newCapacity){
size_t oldCapacity = capacity();
if (newCapacity>oldCapacity){
//申请新空间
T* pTemp = new T[newCapacity];
//拷贝元素
size_t n = size();
if (_start){
for (size_t i = 0; i < size(); ++i)
pTemp[i] = _start[i];
//释放旧空间
free(_start);
}
_start = pTemp;
_finish = _start + n;
_endofStorage = _start + oldCapacity;
}
}
//access
//访问任意位置的元素,index不能大于元素的个数
T& operator[](size_t index){
assert(index < size());
return _start[index];
}
const T& operator[](size_t index)const{
assert(index < size());
return _start[index];
}
T& front(){
return *_start;
}
const T& front()const{
return *_start;
}
T& back()const{
return *(_finish - 1);
}
void push_back(const T& value){
checkcapacity();
*_finish++ = value;
}
void pop_back(){
if (empty())
return;
--_finsih;
}
iterator insert(iterator pos, const T& value){
checkcapacity();
//搬移元素
for (size_t i = size(); i >= pos - _start; i--){
_start[i] = _start[i - 1];
}
//插入元素
*pos = value;
++_finish;
return pos;
}
iterator erase(iterator pos){
if (pos == end())
return pos;
for (size_t i = pos - _start; i < size(); ++i){
_start[i] = _start[i + 1];
}
--_finish;
return pos;
}
void swap(vector<T>& v){
swap(_start, v._start);
swap(_finish, v._finish);
swap(_endofStorage, v._endofStorage);
}
void clear(){
_finish = _start;
}
protected:
void checkcapacity(){
if (_finish == _endofStorage)
reserve(capacity() * 2);
}
protected:
T* _start;
T* _finish;
T* _endofStorage;
};
}
#include<iostream>
using namespace std;
void TestVector1(){
bite::vector<int> v1;
bite::vector<int> v2(10, 6);
cout << v2.sie() << endl;
cout << v2.capacity() << endl;
for (auto e : v2)
cout << e << " ";
cout << endl;
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
bite::vector<int> v3(array, array + sizeof(array) / sizeof(array[0]));
for (auto e : v3)
cout << e << " ";
cout << endl;
}
void Testvector2(){
bite:vector<int>v;
v.reserve(10);
cout << v.size() << endl;
cout << v.capacity() << endl;
v.reserve(5);
cout << v.size() << endl;
cout << v.capacity() << endl;
v.push_back(1);
v.push_back(2);
v.push_back(3);
cout << v.size() << endl;
cout << v.front() << endl;
cout << v.back() << endl;
cout << v[1] << endl;
for (auto e : v)
cout << e << " ";
cout << endl;
v.pop_back();
cout << v.size() << endl;
for (auto e : v)
cout << e << " ";
cout << endl;
v.pop_back();
cout << v.back() << endl;
v.insert(v.begin(), 0);
cout << v.front() << endl;
v.erase(v.begin());
cout << v.front << endl;
v.resize(5, 8);
cout << v.size() << endl;
cout << v.capacity() << endl;
for (auto e : v)
cout << e << " ";
cout << endl;
v.resize(20);
cout << v.size() << endl;
cout << v.capacity() << endl;
for (auto e : v)
cout << e << " ";
cout << endl;
v.resize(10);
cout << v.size() << endl;
cout << v.capacity() << endl;
for (auto e : v)
cout << e << " ";
cout << endl;
v.clear();
cout << v.size() << endl;
cout << v.capacity() << endl;
}
#include<iostream>
using namespace std;
#include "Vector.h"
int main(){
TestVector1();
Testvector2();
return 0;
}
4.使用STL进行操作
4.1 向量的初始化操作
vector<int> a ; //声明一个int型向量a
vector<int> a(10) ; //声明一个初始大小为10的向量
vector<int> a(10, 1) ; //声明一个初始大小为10且初始值都为1的向量
vector<int> b(a) ; //声明并用向量a初始化向量b
vector<int> b(a.begin(), a.begin()+3) ; //将a向量中从第0个到第2个(共3个)作为向量b的初始值
int n[] = {1, 2, 3, 4, 5} ;
vector<int> a(n, n+5) ; //将数组n的前5个元素作为向量a的初值
vector<int> a(&n[1], &n[4]) ; //将n[1] - n[4]范围内的元素作为向量a的初值
4.2 元素的输入与访问‘’
/*************************************************
Copyright © ZJL 1998-2019. All rights reserved.
File name: STL_ Vector的常见用法总结
Author: ZJL
Version: V1.0
Description: Vecto本身是可以作为数组使用的,而且在一些元素不确定的场合可以很好地节省空间
Others: // 其它内容的说明
Log: 元素的初始化操作与输出操作
*************************************************/
#include <iostream>
#include <vector>
#include <iterator>
using namespace std;
int main(int argc, char *argv[])
{
/* vector<int> a(10,0); //定义10个元素的大小为0的向量
cin>>a[2];
cin>>a[8];
cin>>a[6];*/
int n[]={1,3,4,5,6};
// vector<int> a(n,n+5);
vector<int> a(&n[1], &n[4]) ;//将n[1] - n[4]范围内的元素作为向量a的初值
/**输出向量中的元素**/
int i;
cout<<"向量的大小:="<<a.size()<<endl;
/**采用遍历数组的方法**/
cout<<"---------采用遍历数组的方法---------------"<<endl;
for(i=0;i<a.size();i++)
cout<<a[i]<<endl;
cout<<"---------采用迭代器---------------"<<endl;;
vector<int>::iterator it;
for(it=a.begin();it!=a.end();it++)
cout<<*it<<" ";
return 0;
}
4.3 容量函数
/*************************************************
Copyright © ZJL 1998-2019. All rights reserved.
File name: Vector ---容量函数
Author: ZJL
Version: V1.0
Description: 容器大小:vec.size();
容器容量:vec.capacity(); // 指在发生 realloc 前能允许的最大元素数,即预分配的内存空间,与 size() 不同
容器最大容量:vec.max_size();
更改容器大小:vec.resize();
容器判空:vec.empty();
Others: // 其它内容的说明
Log: 元素的初始化操作与输出操作
*************************************************/
#include <iostream>
#include <vector>
#include <iterator>
using namespace std;
int main(int argc, char *argv[])
{
vector<int> vec;
for(int i=0;i<16;i++)
{
vec.push_back(i);
}
cout<<"size():"<<vec.size()<<endl;
cout<<"capacity"<<vec.capacity()<<endl;
cout<<"max_size:"<<vec.max_size()<<endl;
vec.resize(10);
cout<<"vec.size()"<<vec.size()<<endl;
if(vec.empty())
cout<<"元素为空"<<endl; //输出元素为空
return 0;
}
4.4 添加函数
/*************************************************
Copyright © ZJL 1998-2019. All rights reserved.
File name: Vector ---容量函数
Author: ZJL
Version: V1.0
Description:
末尾添加元素:vec.push_back(const T& x);
任意位置插入一个元素:vec.insert(iterator it, const T& x);
任意位置插入 n 个相同元素:vec.insert(iterator it, int n, const T& x);
插入另一个向量的 [first,last] 间的数据:vec.insert(iterator it, iterator first, iterator last);
Log: 元素的初始化操作与输出操作
*************************************************/
#include <iostream>
#include <vector>
#include <iterator>
using namespace std;
int main(int argc, char *argv[])
{
vector<int> vec;
vec.push_back(2);
/**在人任意位置插入一个元素**/
vector<int>::iterator it=vec.begin();
vec.insert(it,2);
//任意位置插入n个相同的像素
it=vec.begin();
vec.insert(it,3,9); //从0 1 2 分别插入数据3个相同的数 9
//插入另一个向量的[first,last] 间的数据
vector<int> vec2(2,4); //定义一个int 类型的向量vecto,设置size 为2 初始化值均为4
cout<<"vec2.size()"<<vec2.size()<<endl;
it=vec.begin();
vec.insert(it,vec2.end()-2,vec2.end());
//遍历显示数据
for(it=vec.begin();it!=vec.end();it++)
cout<<*it<<" ";
cout<<endl;
return 0;
}
4.5 删除函数
/*************************************************
Copyright © ZJL 1998-2019. All rights reserved.
File name: Vector ---容量函数
Author: ZJL
Version: V1.0
Description:
末尾删除元素:vec.pop_back();
任意位置删除一个元素:vec.erase(iterator it);
删除 [first,last] 之间的元素:vec.erase(iterator first, iterator last);
清空所有元素:vec.clear();
Log: 建议采用debug 打断点的方式观察数组中的元素
*************************************************/
#include <iostream>
#include <vector>
#include <iterator>
using namespace std;
int main(int argc, char *argv[])
{
vector<int> vec;
for(int i=0;i<8;i++)
vec.push_back(i);
//末尾删除,,末尾删除元素
vec.pop_back();
//在任意一个位置删除元素
vector<int>::iterator it;
it=vec.begin();
vec.erase(it);
//删除【first,last】之间的任意一个元素
vec.erase(vec.begin(),vec.begin()+1);
//删除完元素之后再次观察删除玩的数组
for(it=vec.begin();it!=vec.end();it++)
cout<<*it<<" ";
cout<<endl;
//清空所有元素
vec.clear();
//再次遍历数组中得元素
for(it=vec.begin();it!=vec.end();it++)
cout<<*it<<endl;
return 0;
}
4.6 访问函数
4.7 多个元素赋值
4.8 迭代器与算法
4.9 利用Vector 实现二维数组
/*************************************************
Copyright © ZJL 1998-2019. All rights reserved.
File name: Vector ---容量函数
Author: ZJL
Version: V1.0
Description:
实现二维数组
Log: 建议采用debug 打断点的方式观察数组中的元素
*************************************************/
#include <iostream>
#include <vector>
#include <iterator>
using namespace std;
int main(int argc, char *argv[])
{
const int count=3; //定义列
vector<vector<int>> vec1(count);//定义一个二维数组
for(int i=0;i<vec1.size();++i) { //定义行
for(int j=0;j<count;++j){
vec1[i].push_back(333);
}
}
//增加一行
vector<int> temp;
vec1.push_back(temp);
int pos=vec1.size()-1;
//因为这里是三列
vec1[pos].push_back(22);
vec1[pos].push_back(22);
vec1[pos].push_back(22);
//增加一列
pos=vec1.size();
for(int i=0;i<pos;++i)
vec1[i].push_back(555);
//打印二维数组
for(int i=0;i<vec1.size();++i){
for(int j=0;j<vec1[0].size();++j){
cout<<vec1[i][j]<<" ";}
cout<<endl;
}
cout<<endl;
}