当前位置: 首页 > article >正文

9,STL——vector类

一、vector类的介绍和使用

1,了解vector

vector类的官方介绍https://cplusplus.com/reference/vector/vector/

使用STL的三个境界:能用,明理,能扩展

1). vector是表示可变大小数组的序列容器。

2). 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。

3.) 本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。

4. )vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。

5. )因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。

6. )与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list和forward_list统一的迭代器和引用更好。

2,vector的使用

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

namespace std
{
	void test1()
	{
		//初始化
		vector<int> v1;
		vector<int> v2(10, 1);
		vector<int> v3(v2);

		//尾插
		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)
		{
			v1[i]++;
		}
		for (size_t i = 0; i < v1.size(); ++i)
		{
			cout << v1[i] << " ";
		}
		cout << endl;

		//迭代器遍历
		vector<int>::iterator it = v1.begin();
		while (it != v1.end())
		{
			//可以修改数据
			(*it)--;

			cout << *it << " ";
			++it;
		}
		cout << endl;

		//范围for遍历
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;
	}
	void test2()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);

		cout << v1.max_size() << endl;
	}
	void test3()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
	
		//find算法,引用头文件 <algorithm>
		vector<int>::iterator pos = find(v1.begin(), v1.end(), 3);
		if (pos != v1.end())
		{
			//插入
			v1.insert(pos, 88);
		}
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

		pos = find(v1.begin(), v1.end(), 1);
		if (pos != v1.end())
		{
			//删除
			v1.erase(pos);
		}
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;
	}
	void test4() 
	{
		vector<int> v1;
		v1.push_back(8);
		v1.push_back(7);
		v1.push_back(2);
		v1.push_back(5);
		v1.push_back(9);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(1);
		v1.push_back(6);
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

		//快排
		sort(v1.begin(), v1.end());
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl;

		//less<int> ls;
		//greater<int> gt;逆置函数
		//sort(v1.begin(), v1.end(), gt);
		//直接传名命对象,可以少写两行
		sort(v1.begin(), v1.end(), greater<int> ());

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

		string s("hello26138912634");
		sort(s.begin(), s.end(), greater<char>());
		cout << s << endl;

		//136 
	}

}

int main()
{
	//std::test1();
	//std::test2();
	//std::test3();
	std::test4();

	return 0;
}

二、vector类的模拟实现

#pragma once
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#include <assert.h>
using namespace std;

//csy名命空间
namespace csy
{
	//vector模板类,类型为T,可替换
	template<class T>
	class vector
	{
	public:
		//iterator重定义成T*,可以简化一下,
		//在reserve里的tmp使用
		//在Func里的const_iterator使用
		typedef T* 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)
			, _end_of_storag(nullptr)
		{}

		//拷贝构造传统写法
		//vector(const vector<T>& v)
		//	:_start(nullptr)
		//	, _finish(nullptr)
		//	, _end_of_storag(nullptr)
		//{
		//	//开空间
		//	reserve(v.size());
		//	//拷贝数据
		//	for (auto e : v)
		//	{
		//		push_back(e);
		//	}
		//}

		//同值构造
		vector(size_t n, const T& val = T())
		{
			reserve(n);
			for (size_t i = 0; i < i; ++i)
			{
				push_back(val);
			}
		}

		//拷贝构造的现代写法,区间构造,swap写入
		template <class InputIterator>
		vector(InputIterator first, InputIterator last)
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storag(nullptr)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}
		void swap(vector<T>& v)
		{
			std::swap(_start,v._start);
			std::swap(_finish,v._finish);
			std::swap(_end_of_storag,v._end_of_storag);
		}
		vector(const vector<T>& v)
		{
			//开空间
			vector<T> tmp(v.begin(),v.end());
			//拷贝数据
			swap(tmp);
		}

		~vector()
		{
			delete[] _start;
			_start = _finish = _end_of_storag = nullptr;
		}

		//提供capacity和size和reserve和v[i]
		size_t capacity() const
		{
			return _end_of_storag - _start;
		}
		size_t size() const
		{
			return _finish - _start;
		}
		void reserve(size_t n)
		{
			if (n > capacity())
			{
				//开辟n大小的空间
				T* tmp = new T[n];
				//拷贝
				if (_start)
				{
					memcpy(tmp, _start, sizeof(T)*size());
					delete[] _start;
				}
				//替换size(),避免_start改变导致size()改变
				size_t sz = size();
				//类成员变量赋值更新
				_start = tmp;
				_finish = _start + sz;
				_end_of_storag = _start + n;
			}
		}
		T& operator [](size_t pos)
		{
			assert(pos < size());
			return _start[pos];
		}
		const T& operator [](size_t pos) const
		{
			assert(pos < size());
			return _start[pos];
		}
		
		//假设原始size为8个元素,12345678,size要重置成长度n
		//1,如果n > 15 需要扩容 + 初始化
		//2,如果n > 8 && n <= 15 初始化
		//3,如果n < 8 删除数据
		void resize(size_t n, const T& val = T())
		{
			if (n > capacity())
			{
				reserve(n);
			}
		
			if (n > size())
			{
				//初始化填值
				while (_finish < _start + n)
				{
					*_finish = val;
					++_finish;
				}
			}
			else
			{
				_finish = _start + n;
			}
		}

		//加const避免引用临时变量
		void push_back(const T& x)
		{
			if (_finish == _end_of_storag)
			{
				reserve(capacity() == 0 ? 4 : capacity() * 2);
			}

			*_finish = x;
			++_finish;
		}

		void pop_back()
		{
			assert(_finish > _start);
			--_finish;
		}

		//v.insert(v.begin(), 1);
		//pos不要传引用,不能修改引用值
		iterator insert(iterator pos, const T& x)
		{
			assert(pos >= _start);
			assert(pos <= _finish);
			//扩容
			if (_finish == _end_of_storag)
			{
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				pos = _start + len;
			}
			//挪动后半段数据
			//扩容后,pos还指向旧空间,pos变成野指针,也叫做迭代器的失效
			//所以扩容后要重置pos
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}
			//插入
			*pos = x;
			++_finish;
			return pos;
		}
		
		//结论:insert/erase pos位置,不要直接访问pos
		//一定要更新,直接访问,可能各种出乎意料的结果
		//认为pos失效,不要访问
		iterator erase(iterator pos)
		{
			assert(pos >= _start);
			assert(pos < _finish);

			//挪动后面的往前一个位置覆盖
			iterator begin = pos + 1;
			while (begin < _finish)
			{
				*(begin - 1) = *begin;
				++begin;
			}
			--_finish;
			return pos;
		}

		T& front()
		{
			assert(size() > 0);
			return *_start;
		}

		T& back()
		{
			assert(size() > 0);
			return *(_finish - 1);
		}

	private:
		iterator _start;
		iterator _finish;
		iterator _end_of_storag;
	};

	void Func(const vector<int>& v)
	{
		//注意使用const迭代器
		vector<int>::iterator it = v.begin();
		while (it != v.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;
		
		for (auto e : v)
		{
			cout << e << " ";
		}
		cout << endl;
	}

	void test_vector1()
	{
		double d = 2.2;
		//int& i = d;
		const int& i = d;

		vector<string> v;
		v.push_back("xxxxx");

		for (size_t i = 0; i < v.size(); ++i)
		{
			cout << v[i] << " ";
		}
		cout << endl << endl;;
	}

	void test_vector2()
	{
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		v.push_back(5);

		for (size_t i = 0; i < v.size(); ++i)
		{
			cout << v[i] << " ";
		}
		cout << endl << endl;
	}

	void test_vector3()
	{
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		v.push_back(5);

		vector<int>::iterator it = v.begin();
		while (it != v.end())
		{
			cout << *it << " ";
			++it;
		}
		cout << endl;

		v.pop_back();
		v.pop_back();

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

	void test_vector4()
	{
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		v.push_back(5);

		for (size_t i = 0; i < v.size(); ++i)
		{
			cout << v[i] << " ";
		}
		cout << endl << endl;

		auto p = find(v.begin(), v.end(), 3);
		if (p != v.end())
		{
			//p不要再次使用,可能失效了
			v.insert(p, 30);

			//cout << *p << endl;
			//v.insert(p, 40);
		}

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

	void test_vector5()
	{
		vector<int> v;
		v.push_back(1);
		v.push_back(2);
		v.push_back(4);
		v.push_back(3);
		v.push_back(4);
		v.push_back(5);
	
		//删除所有的偶数
		auto it = v.begin();
		while (it != v.end())
		{	
			//错误用法
			//if (*it % 2 == 0)
			//{
			//	v.erase(it);
			//}
			//++it;
			
			//正确用法
			if (*it % 2 == 0)
			{
				it = v.erase(it);
			}
			else
			{
				++it;
			}
		}

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

	void test_vector6()
	{
		std::vector<int> v;
		v.reserve(10);
		v.push_back(1);
		v.push_back(2);
		v.push_back(3);
		v.push_back(4);
		v.push_back(5);

		//在所有的偶数前面插入偶数的2倍
		auto it = v.begin();
		while (it != v.end())
		{
			if (*it % 2 == 0)
			{
				it = v.insert(it, *it * 2);
				++it;
				++it;
			}
			else
			{
				++it;
			}
		}

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

	//浅拷贝,析构两次,指向同一空间,一个对象修改影响两个对象
	//深拷贝,开辟新空间,指向新空间
	void test_vector7() 
	{
		//普通构造
		vector<int> v1;
		v1.push_back(1);
		for (auto e : v1)
		{
			cout << e << " ";
		}
		//拷贝构造
		vector<int> v2(v1);
		for (auto e : v2)
		{
			cout << e << " ";
		}
		cout << endl;
		//内置类型也有构造
		int i = 6;
		int j = int();
		int k = int(22);
		cout << i << " " << j << " " << k << endl;
	}

	void test_vector8()
	{
		vector<int> v1;
		v1.resize(10, 0);
		for (auto e : v1)
		{
			cout << e << " ";
		}
		cout << endl << endl;

		vector<int> v2;
		v2.reserve(10);
		v2.push_back(1);
		v2.push_back(2);
		v2.push_back(3);
		v2.push_back(4);
		v2.push_back(5);

		v2.resize(8, 8);
		for (auto e : v2)
		{
			cout << e << " ";
		}
		cout << endl << endl;
		
		v2.resize(20, 20);
		for (auto e : v2)
		{
			cout << e << " ";
		}
		cout << endl << endl;
	}
}

http://www.kler.cn/a/488639.html

相关文章:

  • krpano 实现文字热点中的三角形和竖杆
  • 微信小程序——创建滑动颜色条
  • Springboot——钉钉(站内)实现登录第三方应用
  • Linux内核TTY子系统有什么(6)
  • 2025年第三届“华数杯”国际赛B题解题思路与代码(Matlab版)
  • MMDetection框架下的常见目标检测与分割模型综述与实践指南
  • 机器学习实战——K-均值聚类算法:原理与应用
  • 软考 高级 架构师 第十一章 面向对象分析 设计模式
  • 天童美语:如何培养孩子的音乐细胞
  • 测试开发之面试宝典
  • mysql中查询json的技巧
  • 【大模型入门指南 07】量化技术浅析
  • Redis高频知识点
  • 【硬件测试】基于FPGA的BPSK+帧同步系统开发与硬件片内测试,包含高斯信道,误码统计,可设置SNR
  • GaussDB事务和并发控制机制
  • Unity Burst详解
  • Zustand selector 发生 infinate loops的原因以及解决
  • Unity Android AAB包GooglePlay上线备忘
  • vmware-ubuntu22.04配置虚拟机win10,重新上网成功
  • pyTorch笔记
  • 【网络】计算机网络的分类 局域网 (LAN) 广域网 (WAN) 城域网 (MAN)个域网(PAN)
  • 英伟达多维进击汽车业务:自动驾驶时代已至
  • 02-51单片机数码管与矩阵键盘
  • 分布式Id方案选择
  • NLP三大特征抽取器:CNN、RNN与Transformer全面解析
  • vue video重复视频 设置 srcObject 视频流不占用资源 减少资源浪费