vector(沉淀)

文章目录

1.vector的介绍及使用(顺序表)

1.1 vector的介绍vector参考文献

三种遍历方式

(1)遍历第一种下标
(2)第二种迭代器
(3)范围for 支持迭代器就支持范围for

具体代码实现如下图:

cpp 复制代码
vector<int> v1;
vector<int> v2(10, 1);
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
//遍历第一种下标
for (size_t i = 0; i < v1.size(); i++)
{
	cout << v1[i] << " ";
}
cout << endl;
//第二种迭代器
vector<int>::iterator it1 = v1.begin();//像指针一样的东西,在指定类域里操作
while (it1!=v1.end())
{
	cout << *it1 << " ";
	++it1;
}
cout << endl;
//范围for 支持迭代器就支持范围for
for (auto e : v1)
{
	cout << e<< " ";
}
cout << endl;

1.2 vector的使用

Member functions

(1) (constructor) std::vector::vector构造
cpp 复制代码
vector<int> v1;
vector<int> v2(10, 1);
cpp 复制代码
vector<int> v1 = { 1,2,3,4,5,6 };

上面的代码调用了下面这个:

cpp 复制代码
void test_vector1()
{
	vector<int> v1 = { 1,2,3,4,5,6 };
	vector<int> v2  ({ 1,2,3,4,5,6 });
	auto il1 = { 1,2,3,4,5,6 };
	initializer_list<int> il2 = { 1,2,3,4,5,6 };
	//int a[] = { 1,2,3,4,5,6 };

 }

initializer_list底层有两个指针,如下图:

Iterators(迭代器):

(1)正向迭代器std::vector::begin
(2)正向迭代器std::vector::end
(3)反向向迭代器std::vector::rbegin
(4)反向向迭代器 std::vector::rend

Capacity:


一般最好不要使用shrink_to_fit接口,因为平常都是删除数据,不会改变空间大小(如下图)

Element access:

Modifiers:

####(1) push_back

具体使用在三种遍历方式那;

(2)assign
cpp 复制代码
v1.assign({ 10,20,30 });
for (auto e : v1)
{
	cout << e << " ";
}
cout << endl;
(3)std::vector::pop_back
(4)std::vector::insert(不能像string那样用下标插入了)头插
cpp 复制代码
v1.insert(v1.begin(),10);
for (auto e : v1)
{
	cout << e << " ";
}
cout << endl;
v1.insert(v1.begin()+2, 1000);
for (auto e : v1)
{
	cout << e << " ";
}
cout << endl;
(5)erase 删
cpp 复制代码
v1.erase(v1.begin() + 2);
for (auto e : v1)
{
	cout << e << " ";
}
cout << endl;
}
(6)emplace

Allocator:

Non-member function overloads

Template specializations

拓展

1.sting,vector区别

1.类型不同

cpp 复制代码
string s1;
vector<char> v3;


2、string定义的s1是有/0的,vector定义v3没有/0;
3.string能串,vector不行,string又operator[]+=...;vector 没有#

用string实例化一个vector,使用范围for

用string实例化一个vector底层原理 (如下图)

vstr.push_back("李四");//隐式类型转换 在调用string(const char* str);
for (const auto& e : vstr)//v1不是int类型加const auto& ;不然消耗太大这两个很重要

cpp 复制代码
vector<string> vstr;//用string实例化一个vector
string s1 = "张三";
vstr.push_back(s1);
vstr.push_back("李四");//隐式类型转换 在调用string(const char* str);
for (const auto& e : vstr)//v1不是int类型加const auto& ;不然消耗太大
{
	cout << e << " ";
}
cout << endl;

vstr[][]和vstr.operator<>.operator<>++两者等价

过程如下:

vstr[0][1]++;//变同音词
vstr[0][1]++;
vstr.operator.operator++;//与上方代码等价

cpp 复制代码
//vstr[0][0]++;
vstr[0][1]++;//变同音词
vstr[0][1]++;
vstr.operator[](0).operator[](1)++;//与上方代码等价
for (const auto& e : vstr)//v1不是int类型加const auto& ;不然消耗太大
{
	cout << e << " ";
}
cout << endl;
扩容问题

capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2
倍增长的。

cpp 复制代码
// 测试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';
		}
	}
}

// 如果已经确定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';
		}
	}
}
int main()
{
	//test_vector1();
	TestVectorExpand();
	TestVectorExpandOP();
	return 0;
}
练习
1
cpp 复制代码
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int value = 0;
        for(auto e:nums)
        {
            value ^= e;
        }
        return value;
    }
};
2.杨辉三角
在c语言上的逻辑


how 开辟空间的:

cpp 复制代码
int row =0;
int *colArr = NULL;
ptr = generate(10,&row,&colArr);//int**  colArr为指针,再取地址;
int**ptr =(int**)malloc(sizeof(int*)*N);
for(int i  = 0;i<N ;i++)
{
ptr[i] =(int*)malloc(sizeof(int)*(i+1));
}
c++
cpp 复制代码
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);//全是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<vector>区别和动态二维数组理解

本质实例化出两个类型
vector
vector<vector>

cpp 复制代码
//vector
template<class T>
class vector
{
public:
    T& operator[](size_t i)
    {
        assert(i < _size);
            return _a[i];
    }
private:
    T* _a;
    size_t _size;
    size_t _capacity;
};

详细分解如下图:



2.vector深度剖析及模拟实现

2.1 std::vector的核心框架接口的模拟实现st::vector

vector.h

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
namespace st
{
	template <class T>
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;
		iterator begin()
		{
			return _start;
		}
		iterator end()
		{
			return _finish;
		}
		const_iterator begin() const
		{
			return _start;
		}
		const_iterator end() const
		{
			return _finish;
		}
		vector()
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{}
		vector(initializer_list<T> il)
			:_start(nullptr)
			, _finish(nullptr)
			, _endofstorage(nullptr)
		{
			reserve(il.size());
			for (auto& e : il)//加引用,万一类型不是整形
			{
				push_back(e);
			}
		}
		~vector()
		{
			delete[]_start;
			_start = _finish = _endofstorage = nullptr;
		}
		T& operator[](size_t i)
		{
			assert(i < size());
			return _start[i];
		}
		const T& operator[](size_t i) const
		{
			assert(i < size());
			return _start[i];
		}
		size_t size() const
		{
			return _finish - _start;
		}
		size_t capacity() const
		{
			return _endofstorage - _start;
		}
		void resize(size_t n, T val = T())//匿名对象缺省值
		{
			if (n <= size())
			{
				_finish = _start + n;
			}
			else
			{
				reserve(n);
				while (_finish < _start + n)
				{
					*_finish = val;
					++_finish;
				}
			}
		}
		void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t Oldsize = size();
				T* tmp = new T[n];
				if (_start)
				{
					memcpy(tmp, _start, sizeof(T) * Oldsize);//拷贝
					delete[] _start;
				}
				_start = tmp;
				_finish = _start + Oldsize;
				_endofstorage = _start + n;
			}
		}
		void push_back(const T& x)
		{
			//复用
			//insert(_finish, x);//在finish这个位置插入x

			if (_finish == _endofstorage)
			{
				reserve(capacity() == 0 ? 4 : capacity() * 2);
			}
			*_finish = x;
			++_finish;
		}
		bool empty()
		{
			return _start == _finish;
		}
		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;
		//}
		//修改
		iterator 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;
			return pos;
		}
		iterator erase(iterator pos)
		{
			assert(pos >= _start);
			assert(pos < _finish);
			iterator i = pos + 1;
			while (i < _finish)
			{
				*(i - 1) = *i;//覆盖往后挪
				i++;
			}
			_finish --;
			return pos;
		}
	private:
		iterator _start;//头  _a
		iterator _finish;//尾  _finsh-_start ==_size
		iterator _endofstorage;//末  _endofstorage-_start ==_capacity;

	};
	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(5);
		v1.push_back(6);
		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 << " ";
			++it1;
		}
		cout << endl;
		v1.pop_back();
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

	}
	void test_vector2()
	{
		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 << " ";
		}
		cout << endl;
		v1.insert(v1.begin() + 2, 30);
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

		vector<int> v2 = { 1,2,3,4,5,6,7 };
		for (auto e : v2)
		{
			cout << e << " ";
		}
		cout << endl;

	}

	void test_vector3()
	{
		std::vector<int> v1;
		//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 << " ";
		}
		cout << endl;

		int x;
		cin >> x;
		auto it = find(v1.begin(), v1.end(), x);
		//if(it != v1.end())
		//{
		//	//it是否失效? 失效了,不能访问
		//	it = v1.insert(it, 10 * x);
		//	cout <<*it << endl;//失效了
		//}
		if (it != v1.end())
		{
			
			it  = v1.insert(it, 10 * x);
			cout << *it << endl;//失效了
		}
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

	}

	void test_vector4()
	{
		std::vector<int> v1;
		/*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 << " ";
		}
		cout << endl;

		int x;
		cin >> x;
		auto it = find(v1.begin(), v1.end(), x);
		if (it != v1.end())
		{
			//it是否失效? 失效了,不能访问
			v1.erase(it);
			cout << *it << endl;

		}
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

	}
	void test_vector5()
	{
		std::vector<int> v1;
		/*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 << " ";
		}
		cout << endl;
		//要求删除所有的偶数
		auto it = v1.begin();
		while (it != v1.end())
		{
			if (*it % 2 == 0)
			{
				//erase 返回删除位置下一个位置。
				it = v1.erase(it);
			}
			else ++it;
		}
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

	}

	void test_vector6()
	{
		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 << " ";
		}
		cout << endl;
		v1.resize(10);
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

		v1.resize(15,1);
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;
	}

}

test.cpp

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;
void test_vector1()
{
	vector<int> v1{ 1,2,3,4,5,6 };
	vector<int> v2({ 1,2,3,4,5,6 });
	//auto il1 = { 1,2,3,4,5,6 };
	//initializer_list<int> il2 = {1,2,3,4,5,6};
	//int a[] = {1,2,3,4,5,6,7};
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
	//v1[10]
	v1.assign({ 10,20,30 });
	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;
}
void TestVectorExpand()
{
	size_t sz;
	vector<int> v;
	cout << typeid(vector<int>::iterator).name() << endl;//查看类型
		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';

			}
		}

}

void test_vector2()
{
	
	TestVectorExpand();
}
#include"vector.h"
int main()
{
	//test_vector1();
	//st::test_vector2();
	/*st::test_vector3();*/
	/*st::test_vector4();*/
	/*st::test_vector5();
	int i = int();
	int i = int(1);
	int k(2);*/
	st::test_vector6();
	return 0;
}

2.2 使用memcpy拷贝问题

2.2.1.浅拷贝

2.2.2深拷贝

vector.h

cpp 复制代码
//深拷贝 拷贝构造 v2(v1)
vector(const vector<T>& v)
{
	reserve(v.capacity());
	for (auto& e : v)
	{
		push_back(e);
	}
}
void swap(vector<T>& tmp)
{
	std::swap(_start, tmp._start);
	std::swap(_finish, tmp._finish);
	std::swap(_endofstorage, tmp._endofstorage);
}
// v1 = v3 现代写法
vector <T>& operator = (vector<T> v)
{
	swap(v);    //v3是v想要的,v是v1想要的直接交换
	return *this;
}
~vector()
......................................................................................
void test_vector7()
{
	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 << " ";
	}
	cout << endl;
	//值拷贝,浅拷贝
	vector<int> v2(v1);
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	vector<int>v3 = { 10,20,30,40 };
	v1 = v3;
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
}

深层次深浅拷贝问题

下方是浅拷贝的代码段和过程,问题是出在memcpy,string中,_str指针指向的内容会析构两次,乱码。

下面是深拷贝过程及修改

cpp 复制代码
void reserve(size_t n)
{
	if (n > capacity())
	{
		size_t Oldsize = size();
		T* tmp = new T[n];
		if (_start)
		{
			//memcpy(tmp, _start, sizeof(T) * Oldsize);//拷贝
			for (size_t i = 0; i < Oldsize; i++)
			{
				tmp[i] = _start[i];//赋值 是深拷贝
			}
			delete[] _start;
		}
		_start = tmp;
		_finish = _start + Oldsize;
		_endofstorage = _start + n;
	}
}

补充

迭代器失效问题(insert和erase)

由于扩容引起野指针问题


cpp 复制代码
	void test_vector3()
	{
		std::vector<int> v1;
		//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 << " ";
		}
		cout << endl;

		int x;
		cin >> x;
		auto it = find(v1.begin(), v1.end(), x);
		//if(it != v1.end())
		//{
		//	//it是否失效? 失效了,不能访问
		//	it = v1.insert(it, 10 * x);
		//	cout <<*it << endl;//失效了
		//}
		if (it != v1.end())
		{
			
			it  = v1.insert(it, 10 * x);
			cout << *it << endl;//失效了
		}
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

	}
}

迭代器失效问题(erase)

任何场景下,迭代器都会失效,要更新后再去访问。eg:修改后的代码段//erase 返回删除位置下一个位置。

删除数据,导致数据挪动,it已经不是指向之前位置了。it也失效了,因为it已经不是指向之前的位置,可能会导致逻辑问题。

erase模拟实现的过程如下:

vs报错的原因:强制的检查,失效迭代器不让你访问。

cpp 复制代码
void test_vector4()
{
	std::vector<int> v1;
	/*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 << " ";
	}
	cout << endl;

	int x;
	cin >> x;
	auto it = find(v1.begin(), v1.end(), x);
	if (it != v1.end())
	{
		//it是否失效? 失效了,不能访问
		v1.erase(it);
		cout << *it << endl;

	}
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

}
erase迭代器失效的复杂场景(要求删除所有的偶数)
cpp 复制代码
void test_vector5()
{
	std::vector<int> v1;
	/*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 << " ";
	}
	cout << endl;
	//要求删除所有的偶数
	auto it = v1.begin();
	while (it != v1.end())
	{
		if (*it % 2 == 0)
		{
			v1.erase(it);
		}
		++it;
	}
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

}


修改后

cpp 复制代码
//要求删除所有的偶数
auto it = v1.begin();
while (it != v1.end())
{
	if (*it % 2 == 0)
	{
		//erase 返回删除位置下一个位置。
		it = v1.erase(it);
	}
	else ++it;
}
极端情况,erase下缩容

总结

以上就是vector的全部内容了,写了好多天,一次没看懂,可多次阅读文章。喜欢博主写的内容,可以一键三连支持博主。

相关推荐
Bczheng19 分钟前
C++ 语法之函数和函数指针
开发语言·c++
C语言小火车13 分钟前
Redis 10大核心场景实战手册:从缓存加速到分布式锁的全面解析
c语言·开发语言·数据库·c++·redis
xiecoding.cn2 小时前
C语言和C++到底有什么关系?
c语言·开发语言·c++·c/c++·c语言入门
c7_ln2 小时前
C++输入输出流第一弹:标准输入输出流 详解(带测试代码)
c++·g++·标准输入输出
Aomnitrix3 小时前
Qt 实操记录:打造自己的“ QQ 音乐播放器”
开发语言·c++·qt·ui·音视频
wzysyrda3 小时前
CRTP奇异递归模板模式
c++
f狐0狸x3 小时前
【蓝桥杯每日一题】3.17
c语言·c++·算法·蓝桥杯·二进制枚举
Elnaij5 小时前
从C语言开始的C++编程生活(1)
c语言·c++
此刻我在家里喂猪呢5 小时前
C++ 介绍STL底层一些数据结构
c++
PingdiGuo_guo5 小时前
C++前缀和
开发语言·c++