vector(2)
vector(2)
vector的使用
构造
代码如下:
vector<int> v1 = { 1,2,3,4,5,6 };//隐式类型转换
vector<int> v2({ 1,2,3,4,5,6 });//直接构造
依据如下:
类似于C语言中初始化数组:
int a[]={1,2,3,4,5,6};
对于a这个数组来说,空间大小是未知的,但是我们这里是拿后面的内容拷贝赋值到a这个数组里面
vector 空间增长问题
像动态开辟的空间,如果不满,不会从中间砍掉,举个例子:
这里面空间大小(capacity)为20,有效个数(size)为10,剩下的空间不会被砍掉,而是会重新开一块空间进行拷贝,也就是要进行缩容操作并不是本地缩容,而是异地缩容。
capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2 倍增长的。这个问题经常会考察,不要固化的认为,vector增容都是2倍,具体增长多少是 根据具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。
reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代 价缺陷问题。
resize在开空间的同时还会进行初始化,影响size。
// 测试vector的默认扩容机制
void TestVectorExpand()
{
size_t sz;
vector<int> v;
sz = v.capacity();
cout << "making v grow:\n";
for (int i = 0; i < 100; ++i)
{
v.push_back(i);
if (sz != v.capacity())
{
sz = v.capacity();
cout << "capacity changed: " << sz << '\n';
}
}
}
vs:运行结果:vs下使用的STL基本是按照1.5倍方式扩容
making foo grow:
capacity changed: 1
capacity changed: 2
capacity changed: 3
capacity changed: 4
capacity changed: 6
capacity changed: 9
capacity changed: 13
capacity changed: 19
capacity changed: 28
capacity changed: 42
capacity changed: 63
capacity changed: 94
capacity changed: 141
g++运行结果:linux下使用的STL基本是按照2倍方式扩容
making foo grow:
capacity changed: 1
capacity changed: 2
capacity changed: 4
capacity changed: 8
capacity changed: 16
capacity changed: 32
capacity changed: 64
capacity changed: 128
// 如果已经确定vector中要存储元素大概个数,可以提前将空间设置足够
// 就可以避免边插入边扩容导致效率低下的问题了
void TestVectorExpandOP()
{
vector<int> v;
size_t sz = v.capacity();
v.reserve(100); // 提前将容量设置好,可以避免一遍插入一遍扩容
cout << "making bar grow:\n";
for (int i = 0; i < 100; ++i)
{
v.push_back(i);
if (sz != v.capacity())
{
sz = v.capacity();
cout << "capacity changed: " << sz << '\n';
}
}
}
vector 增删查改
insert:在position之前插入val
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
//插入
v1.insert(v1.begin(), 9);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
虽然vector不支持下标访问,但是可以间接访问:
v1.insert(v1.begin() + 2, 200);
for(auto e:v1)
{
cout << e << " ";
}
cout << endl;
同理,erase也是差不多的
//删除
v1.erase(v1.begin() + 2);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
insert和erase不推荐多用,因为对程序的效率影响很大
operator[]:像数组一样访问
**at()**作用也是差不多,但是在处理异常的方式上不同,operator[]遇到越界是直接断言处理,at()会选择抛异常
稍微提一嘴,assign也就是赋值操作:
代码如下:
v1.assign=({10,20,30});
一道OJ题–只出现一次的数字
给你一个 非空 整数数组 nums
,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。
示例 1 :
输入:nums = [2,2,1]
输出:1
示例 2 :
输入:nums = [4,1,2,1,2]
输出:4
示例 3 :
输入:nums = [1]
输出:1
提示:
1 <= nums.length <= 3 * 104
-3 * 104 <= nums[i] <= 3 * 104
- 除了某个元素只出现一次以外,其余每个元素均出现两次。
class Solution {
public:
int singleNumber(vector<int>& nums) {
int value=0;
for(auto e:nums)
{
value ^=e;
}
return value;
}
};
一道OJ题–杨辉三角
给定一个非负整数 *numRows
,*生成「杨辉三角」的前 numRows
行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。
示例 1:
输入: numRows = 5
输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]
示例 2:
输入: numRows = 1
输出: [[1]]
提示:
1 <= numRows <= 30
代码如下:
// 涉及resize / operator[]
// 核心思想:找出杨辉三角的规律,发现每一行头尾都是1,中间第[j]个数等于上一行[j-1]+[j]
class Solution {
public:
vector<vector<int>> generate(int numRows) {
vector<vector<int>> vv(numRows,vector<int>());
for(size_t i=0;i<numRows;++i)//开辟空间
{
vv[i].resize(i+1,1);
}
for(size_t i=0;i<vv.size();++i)
{
for(size_t j=1;j<vv[i].size()-1;++j)
{
vv[i][j]=vv[i-1][j]+vv[i-1][j-1];
}
}
return vv;
}
};
这里有一个重点核心:vector<vector < int> >
结论是这里相当于二维数组
二维数组的本质是一维数组
动态开辟空间的过程如下:
动态二维数组理解
// 以杨慧三角的前n行为例:假设n为5
void test2vector(size_t n)
{
// 使用vector定义二维数组vv,vv中的每个元素都是vector<int>
soobin::vector<soobin::vector<int>> vv(n);
// 将二维数组每一行中的vecotr<int>中的元素全部设置为1
for (size_t i = 0; i < n; ++i)
vv[i].resize(i + 1, 1);
// 给杨慧三角出第一列和对角线的所有元素赋值
for (int i = 2; i < n; ++i)
{
for (int j = 1; j < i; ++j)
{
vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];
}
}
}
soobin: :vector<soobin: : vector< int >> vv(n); 构造一个vv动态二维数组,vv中总共有n个元素,每个元素 都是vector类型的,每行没有包含任何元素
vector的模拟实现:
vector.h
#pragma once
#include <assert.h>
#include <string.h>
namespace soobin
{
template<class T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
vector()
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{}
vector(initializer_list<T> i1)
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{
reserve(il.size());
for (auto& e : i1)
{
push_back(e);
}
}
//private:
//iterator _start;
//iterator _finish;
//iterator _endofstorage;
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator begin() const
{
return _start;
}
const_iterator end() const
{
return _finish;
}
~vector()
{
if (_start)
{
delect[]_start;
_start = _finish = _endofstorage = nullptr;
}
}
T& operator[](size_t i)
{
assert(i < size());
return _start[i];
}
size_t size() const
{
return _finish - _start;
}
size_t capacity() const
{
return _endofstorage - _start;
}
void reserve(size_t n)
{
if (n > capacity())
{
T* tmp = new T[n];
if (_start)
{
size_t oldSize = size();//这里需要注意记录原先的size,因为被const修饰了不可以被修改,这样拿到的不是最新的
memcpy(tmp, _start, sizeof(T) * oldSize);
delete[]_start;
}
_start = tmp;
_finish = _start + oldSize;
_endofstorage = _start + n;
}
}
void push_back(const T& x)
{
if (_finish == _endofstorage)
{
reserve(capacity() == 0 ? 4 : capacity() * 2);
}
*_finish = x;
++_finish;
}
bool empty()
{
return _start == _empty;
}
void pop_back()
{
assert(!empty());
--_finish;
}
void insert(iterator pos, const T& x)
{
assert(pos >= _start && pos <= _finish);
if (_finish == _endofstorage)
{
size_t len = pos - _start;//涉及到迭代器失效的问题
reserve(capacity() == 0 ? 4 : capacity() * 2);
pos = _start + len;
}
iterator i = _finish - 1;//这里是下标
while (i >= pos)
{
*(i + 1) = *i;
--i;
}
*pos = x;
++_finish;
}
void erase(iterator pos);
};
void test_vector1()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(4);
v1.push_back(4);
for (size_t i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
vector<int>::iterator it1 = v1.begin();
while (it1 != v1.end())
{
cout << *it1 << " ";
}
cout << endl;
}
}
Test.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <vector>
#include "vector.h"
using namespace std;
void test_vector1()
{
vector<int> v1 = { 1,2,3,4,5,6 };//隐式类型转换
vector<int> v2({ 1,2,3,4,5,6 });//直接构造
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
//插入
v1.insert(v1.begin(), 9);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
v1.insert(v1.begin() + 2, 200);
for(auto e:v1)
{
cout << e << " ";
}
cout << endl;
//删除
v1.erase(v1.begin() + 2);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
}
int main()
{
soobin::test_vector1();
return 0;
}
这里需要来浅浅讨论一个迭代器失效的问题:
当我们用迭代器在指定位置插入数据的时候,可能会进行扩容操作,但是扩容操作可能pos指向的位置还是原先的位置,这样子在尾插的时候,会发生越界的情况
if (_finish == _endofstorage)
{
size_t len = pos - _start;//len用来记录pos和_start的距离
reserve(capacity() == 0 ? 4 : capacity() * 2);
pos = _start + len;//当遇到扩容的时候,加上这样的距离
}
原文地址:https://blog.csdn.net/Mr_Xuhhh/article/details/142825132
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!