C++容器--vector

vector

vector可表示可变大小数组的序列容器。
vector采用和数组相同的连续存储空间来存储元素。可采用下表对vector的元素进行访问,与数组一样高效。
与数组的不同点:vector的大小可以动态改变,它的大小会被容器自动处理,而数组是定长的。
vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大,为保证vector在末尾进行插入的时候是在常数时间的复杂度中完成。
与其他动态序列容器相比(deque,list),vector在随机访问元素时更加高效,尾插和尾删相对高效;但是不在末尾进行插入和删除的操作,效率更低。

接口

构造

vector();	// 无参构造
vector(size_type n, const value_type& val = value_type());	// 构造并初始化n个val
vector(const vector& v);	// 拷贝构造
vector(InputIterator first, InputIterator last);	// 使用迭代器进行初始化构造

迭代器

// 容器迭代器接口统一
begin();	// vector的起始位置
end();		// vector结束位置的下一个位置
rbegin();	// vector结束位置
rend();		// vector起始位置的前一个位置
cbegin();	// const接口
cend();

容量

size();	// 数据个数
capacity();	// 容量大小
empty();	// 判空
void resize(size_type n, value_type val = value_type());	// 改变有效数据容量
void reserve(size_type n);	// 改变空间大小

capacity的增长在vs下是1.5倍增长,g++是2倍增长,不同版本的STL顺序表的增容可能不同
reserve只负责开辟空间,如果知道需要用多少空间,reserve可以缓解vector的增容缺陷,reserve小于当前容量,reserve什么都不做
resize开辟空间的时候还会初始化,影响size;包括缩小size也是可行的

增删改查

void push_back(const value_type& val);	// 尾插
void pop_back();	// 尾删
InputIterator find(InputIterator first, InputIterator last, const T& val);	// 查找,非成员函数
iterator insert(iterator position, const value_type& val);	// 在pos之前插入
iterator erase(iterator position);	// 删除pos位置的元素
void swap(vector& v);	// 交换两个vector的数据空间
reference operator[](size_type n);	// []的重载,与数组相同

find是算法实现,不是成员函数,迭代器进行了重新封装,不同容器的迭代器都可以使用
reference是T&的别名,typedef了而已,在STL的源码中引用都定义reference为了保持接口统一
不提供pop_front接口,效率感人,所以在后边实现队列queue的底层结构不可以使用vector
iterator为迭代器

使用中的问题

迭代器失效

迭代器失效的场景:删除
原因:当前节点已经释放,对释放节点执行++操作,相当于对空指针进行解引用
解决方式:删除函数的返回值会返回下一个迭代器的位置,删除后需要重新获取迭代器
容器中失效的原因都是这个,解决方式也相同,返回下一个迭代器的位置,重新获取

#include <iostream> 
#include <algorithm> 
#include <vector> 

int main() {
	int a[] = { 1, 2, 3, 4 };
	std::vector<int> v(a, a + sizeof(a) / sizeof(int));

	// 使用find查找3所在位置的iterator    
	std::vector<int>::iterator pos = find(v.begin(), v.end(), 3);

	// 删除pos位置的数据,导致pos迭代器失效。   
	pos = v.erase(pos);
	std::cout << *pos << std::endl; // 此处会导致非法访问

	// 在pos位置插入数据,导致pos迭代器失效。   
	// insert会导致迭代器失效,是因为insert可    
	// 能会导致增容,增容后pos还指向原来的空间,而原来的空间已经释放了。   
	pos = find(v.begin(), v.end(), 3);
	pos = v.insert(pos, 30);
	std::cout << *pos << std::endl;	// 此处会导致非法访问

	return 0;
}

实现

使用三个指针控制,start(有效元素的开始),finish(有效元素的结束),end_of_storage(容量的结束)
vector的实现较为简单,找到具体代码分析

源码

#include <iostream>
#include <assert.h>
#include <algorithm>
template <class T>

class Vector {
public:
	typedef T* iterator;
	typedef const T* const_iterator;

	iterator begin() {
		return _start;
	}
	iterator end() {
		return _finish;
	}

	const_iterator cbegin() const {
		return _start;
	}
	const_iterator cend() const {
		return _finish;
	}

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

public:
	Vector()
		: _start(nullptr)
		, _finish(nullptr)
		, _endofStorage(nullptr) {}
	Vector(size_t n, const T& val = T()) 
		: _start(nullptr)
		, _finish(nullptr)
		, _endofStorage(nullptr) {
		reserve(n);
		while (n--)
		{
			push_back(val);
		}
	}

	// 这里如果使用Iterator做迭代器,就会导致初始化的迭代器区间[first,last]只能是Vector的迭代器       
	// 这里重新声明迭代器,迭代器区间[first,last]可以是任意容器的迭代器区间
	template <class InputIterator>
	Vector(InputIterator first, InputIterator last) {
		reserve(last - first);
		while (first != last)
		{
			push_back(*first);
			++first;
		}
	}

	Vector(const Vector<T>& vec) 
		: _start(nullptr)
		, _finish(nullptr)
		, _endofStorage(nullptr) {

		reserve(vec.capacity());
		iterator it = begin();
		const_iterator vit = vec.cbegin();
		while (vit != vec.cend())
		{
			*it++ = *vit++;
		}
		_finish = _start + vec.size();
		_endofStorage = _start + vec.capacity();	
	}
	Vector<T>& operator= (Vector<T> vec) {
		Swap(vec);
		return *this;
	}
	void reserve(size_t n) {
		if (n > capacity())
		{
			size_t Size = size();
			T* tmp = new T[n];

			// 不可以直接进行memcpy
			if (_start)
			{
				for (size_t i = 0; i < Size; ++i)
					tmp[i] = _start[i];
			}
			// delete[] _start;
			_start = tmp;
			_finish = _start + Size;
			_endofStorage = _start + n;
		}
	}
	void resize(size_t n, const T& val = T()) {
		if (n < size())
		{
			_finish = _start + n;
		}
		if (n > capacity())
		{
			reserve(n);
		}
		iterator it = _finish;
		_finish = _start + n;
		while (it != _finish)
		{
			*it = val;
			++it;
		}
	}
	void Swap(Vector<T>& vec) {
		std::swap(_start, vec._start);
		std::swap(_finish, vec._finish);
		std::swap(_endofStorage, vec._endofStorage);	
	}

	void push_back(const T& val) {
		insert(end(), val);
	}
	void pop_back() {
		erase(end());
	}
	iterator insert(iterator pos, const T& val) {
		assert(pos <= _endofStorage);
		if (_finish == _endofStorage) {
			size_t Size = size();
			size_t new_capacity = capacity() == 0 ? 1 : capacity() * 2;
			reserve(new_capacity);
			pos = _start + Size;
		}
		iterator end = _finish - 1;
		while (end >= pos)
		{
			*(end + 1) = *end;
			--end;
		}
		*pos = val;
		++_finish;
		return pos;
	}

	// 返回删除元素的下一个位置,解决一边删除一边遍历迭代器失效的问题
	iterator erase(iterator pos) {
		iterator begin = pos + 1;
		while (begin != _finish)
		{
			*(begin - 1) = *begin;
			++begin;
		}
		--_finish;
		return pos;
	}

	T& operator[](size_t pos) {
		return _start[pos];
	}

	void print() {
		for (auto& e : *this)
		{
			std::cout << e << " ";
		}
		std::cout << std::endl;
	}


private:
	iterator _start;
	iterator _finish;
	iterator _endofStorage;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值