【落羽的落羽 C++】vector

文章目录

一、vector类介绍

vector是STL中的一种容器,本质上是顺序表。它和string类的结构很相似,其也有size、capacity、数组等,不同的是string底层只是字符数组,而vector类的底层是可以存储所有数据类型的数组。有了string的经验,我们理解vector就更轻松了。

vector实际上是一个类模板,在使用时,我们需要根据实际要存储的数据类型用<>表明,如vector<int> v1; vector<char> v2; vector<string> v3;等等

tip:vector<char>string看起来似乎没什么区别,但是string会在字符串后自动加\0,而前者不会,同时string中也有一些针对字符串的特殊操作也是vector中没有的。实际中根据我们的需求来选择使用。

二、vector中的常用接口

vector的接口和string中几乎完全一样,使用方法也类似,就简单介绍一下:

vector成员 接口说明
size 获取数据个数
capacity 获取空间容量大小
resize 改变vector的size
reserve 改变vector的capacity
begin 获取第一个数据的迭代器iterator/const_iterator
end 获取最后一个数据的下一个位置的迭代器iterator/const_iterator
push_back 尾部插入数据
pop_back 尾部删除数据
insert 插入数据
erase 删除数据
swap 交换两个vector的数据空间
operator[] 使能像数组一样访问vector存储的数据

简单演示:

三、迭代器失效问题

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际上就是一个指针,或者是对指针进行了封装,比如vector<T>的迭代器就是原生态指针T*。因此迭代器失效就是迭代器底层对应指针所指向的空间被销毁了,类似野指针的道理,使用可能会造成程序崩溃。对于vector,可能会导致其迭代器失效的操作有:resize、reserve、insert、assign、push_back,这些操作可能会进行扩容操作,vector底层旧空间被释放而开辟了一块新空间,则指向旧空间的迭代器就失效了。因此,在以上操作完成之后,如果还想要通过迭代器操作vector中的元素,需要给迭代器重新赋值。举个例子:

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;
int main()
{
    vector<int> v = { 1, 2, 3, 4, 5 };
    vector<int>::iterator it = v.begin();

    //将有效元素个数调整至10个,多出的位置用0填充,这个操作底层会进行扩容
    v.resize(10, 0);
    //此时原来的迭代器it失效,使用程序会崩溃
    cout << *it;

    return 0;
}
cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;
int main()
{
    vector<int> v = { 1, 2, 3, 4, 5 };
    vector<int>::iterator it = v.begin();

    //将有效元素个数调整至10个,多出的位置用0填充,这个操作底层会进行扩容
    v.resize(10, 0);
    
    //此时原来的迭代器it失效,使用程序会崩溃
    //cout << *it;

    //给it重新赋值就能解决
    it = v.begin();
    while(it != v.end())
    {
        cout << *it << ' ';
        it++;
    }
    cout << endl;
    
    return 0;
}

除此之外,erase操作也会导致迭代器失效,erase删除pos位置数据后,pos位置之后的元素会往前挪动,没有造成底层空间的改变,理论上迭代器不会失效。但是如果pos位置刚好是最后一个数据,删完之后pos刚好是end的位置,而end位置是没有数据的,那么pos就失效了。因此在VS下,只要使用erase操作后,VS就认为该位置迭代器失效了。解决办法也是一样,重新赋值。

VS对迭代器失效的检查比较严格,程序会直接崩溃。而Linux下g++编译器对迭代器失效的检测较为宽松,程序可能可以运行,但是结果也会出错。

四、vector的使用实例

力扣题目:杨辉三角

杨辉三角想必大家都不陌生,如果想要生成杨慧三角的前numRows行,用vector来实现就很方便了,我们可以定义出vector<vector<int>>的结构,表示它存储的数据类型是vector<int>,模拟出杨辉三角的结构:

cpp 复制代码
vector<vector<int>> generate(int numRows) 
{
    vector<vector<int>> vv;
    vv.resize(numRows);

    //将每一个元素都初始化成1
    for(int i = 0; i < vv.size(); i++)
    {
        vv[i].resize(i+1, 1);
    }
    
    //遍历赋值
    for(int i = 2; i < numRows; i++)
    {
        for(int j = 1; j < i; j++)
        {
            vv[i][j] = vv[i-1][j] + vv[i-1][j-1];
        }
    }
    return vv;
}

结果没有问题

五、vector模拟实现

在我的vector.h中:

cpp 复制代码
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
namespace lydly
{
	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()
		{

		}

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

		//利用迭代器区间构造
		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push_back(*first);
				first++;
			}
		}

		//使我们可以用{}初始化
		vector(initializer_list<T> il)
		{
			reserve(il.size());
			for (auto& e : il)
			{
				push_back(e);
			}
		}

		vector(const vector<T>& v)
		{
			reserve(v.capacity());
			for (auto& e : v)
			{
				push_back(e);
			}
		}

		//利用std库中的swap算法
		void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_end_of_storage, v._end_of_storage);
		}

		vector<T>& operator=(vector<T> v)
		{
			swap(v);
			return *this;
		}

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

		size_t capacity() const
		{
			return _end_of_storage - _start;
		}

		size_t size() const
		{
			return _finish - _start;
		}

		T& operator[](size_t i)
		{
			assert(i < size());
			return _start[i];
		}

		void resize(size_t n, T val = T())
		{
			if (n > size())
			{
				reserve(n);
			}
			while (_finish != _start + n)
			{
				*_finish = val;
				_finish++;
			}
		}

		void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t old_size = size();
				T* tmp = new T[n];
				if (_start)
				{
					//深拷贝
					for (size_t i = 0; i < old_size; i++)
					{
						tmp[i] = _start[i];
					}
					delete[] _start;
				}
				_start = tmp;
				_finish = _start + old_size;
				_end_of_storage = _start + n;
			}
		}

		void push_back(const T& x)
		{
			if (_finish == _end_of_storage)
			{
				size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newcapacity);
			}
			*_finish = x;
			_finish++;
		}

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

		iterator insert(iterator pos, const T& x)
		{
			assert(pos >= _start && pos <= _finish);
			if (_finish == _end_of_storage)
			{
				size_t len = pos - _start;
				size_t newcapacity = capacity() == 0 ? 4 : capacity * 2;
				reserve(newcapacity);
				pos = _start + pos;
			}

			//pos后的数据往后挪一个位置
			iterator it = _finish - 1;
			while (it >= pos)
			{
				*(it + 1) = *it;
				it--;
			}

			*pos = x;
			_finish++;
			return pos;
		}

		iterator erase(iterator pos)
		{
			assert(pos >= _start && pos < _finish);
			//pos后的数据往前挪一个位置
			iterator it = pos + 1;
			while (it < _finish)
			{
				*(it - 1) = *it;
				it++;
			}
			_finish--;
			return pos;
		}
	private:
		iterator _start = nullptr;
		iterator _finish = nullptr;
		iterator _end_of_storage = nullptr;
	};
}

简单测试:

本篇完,感谢阅读。

相关推荐
Ethon_王1 小时前
走进Qt--工程文件解析与构建系统
c++·qt
工藤新一¹2 小时前
C++/SDL进阶游戏开发 —— 双人塔防游戏(代号:村庄保卫战 13)
c++·游戏·游戏引擎·毕业设计·sdl·c++游戏开发·渲染库
让我们一起加油好吗2 小时前
【C++】类和对象(上)
开发语言·c++·visualstudio·面向对象
好想有猫猫3 小时前
【Redis】服务端高并发分布式结构演进之路
数据库·c++·redis·分布式·缓存
不是杠杠3 小时前
驼峰命名法(Camel Case)与匈牙利命名法(Hungarian Notation)详解
c++
Epiphany.5563 小时前
基于c++的LCA倍增法实现
c++·算法·深度优先
newki3 小时前
学习笔记,Linux虚拟机中C/C++的编译相关流程步骤
c语言·c++
jerry6094 小时前
c++流对象
开发语言·c++·算法
虾球xz4 小时前
游戏引擎学习第247天:简化DEBUG_VALUE
c++·学习·游戏引擎