C++ STL容器之vector和常用接口的实现

6 篇文章 0 订阅

目录

vector的常用接口

vector常用接口实现


简介

1. vector是表示可变大小数组的序列容器。
2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
3. 本质上来说,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要为新元素重新开辟空间。其做法是,分配一个新的数组(比原来数组大的数组),然后将全部元素拷贝(深拷贝)到这个数组。就效率而言,这是一个低效率的工作
4. 实际上 , 每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小, 因为存储空间比实际需要的存储空间更大, vector的存储空间并不是一个一个增加, (不同的库采用不同的策略权衡空间, vs中是1.5倍增加,gcc是2倍), 这可能会造成空间浪费, 但不用每次增加新元素都要重新分配内存(是一种空间换时间的做法)
5. 与其它动态序列容器相比(deque, list , forward_list) , vector在访问元素的时候更加高效, 在末尾添加和删除元素相对高效。对于不在末尾的删除和插入操作,效率更低。并且与list和forward_list相比,迭代器和引用的一致性更差。

vector的常用接口

1.常见构造

函数名称函数功能
vector()构造空的vector
vector(size_type n, const value_type& val = value_type()) 构造并初始化n个val
vector (const vector& x)拷贝构造
template <class InputIterator>                  
vector (InputIterator first, InputIterator last)
使用迭代器进行初始化构造

来看具体应用 :

#include<iostream>
#include<vector>
using namespace std;
class Solution {
public:
	void Print_vector_int(const vector<int>& v) {
		for (auto i : v) {
			cout << i << ' ';
		}
		cout << endl;
	}
};
int main() {
	vector<int> arr;
	vector<int> arr1(10, -1);
	vector<vector<int>>arr2;//二维数组
	for (int i = 0; i < 10; ++i) {
		arr.push_back(i + 1); 
	}
	vector<int> arr3(arr);
	vector<int> arr4(arr.begin() + 2, arr.begin() + 5);
	Solution p;
	cout << "arr :";
	p.Print_vector_int(arr);
	cout << "arr1:";
	p.Print_vector_int(arr1);
	cout << "arr3:";
	p.Print_vector_int(arr3);
	cout << "arr4:";
	p.Print_vector_int(arr4);
	system("pause");
	return 0;
}

2. vector iterator(迭代器)的使用

函数名称函数功能
iterator begin() 
const_iterator begin() const 
返回第一个元素位置的iterator
返回第一个元素位置的const_iterator
iterator end()
const_iterator end() const 
返回最后一个元素后一个位置的iterator
返回最后一个元素后一个位置的const_iterator
reverse_iterator rbegin()
const reverse_iterator rbegin() const 
返回最后一个元素的位置的reverse_iterator
返回最后一个元素的位置的const_reverse_iterator
reverse_iterator rend() 
const reverse_iterator rend() const
返回第一个元素前一个位置的reverse_iterator
返回第一个元素前一个位置的const_reverse_iterator
const_iterator cbegin() const (C++11)返回第一个元素位置的const_iterator
const_iterator cend() const (C++11)返回最后一个元素下一个位置的const_iterator
const_reverse_iterator crbegin() const (C++11)返回最后一个元素的位置的const_reverse_iterator
const_reverse_iterator crend() const (C++11)返回第一个元素前一个位置的const_reverse_iterator
#include<iostream>
#include<vector>
using namespace std;
class Solution {
public:
	void Print_vector_int(const vector<int>& v) {
		for (auto i : v) {
			cout << i << ' ';
		}
		cout << endl;
	}
};
int main() {
	vector<int> arr;
	vector<int> arr1(10, -1);
	vector<vector<int>>arr2;//二维数组
	for (int i = 0; i < 10; ++i) {
		arr.push_back(i + 1);
	}
	vector<int> arr3(arr);
	vector<int> arr4(arr.begin() + 2, arr.begin() + 5);
	Solution p;
	cout << "arr :";
	for (auto i = arr.begin(); i < arr.end(); ++i) {
		cout << *i << " ";
	}
	cout << endl;
	cout << "arr1:";
	for (vector<int>::iterator i = arr1.begin(); i < arr1.end(); ++i) {
		cout << *i << " ";
	}
	cout << endl;
	cout << "arr3:";
	for (auto i = arr3.begin(); i < arr3.end(); ++i) {
		*i += 1;
	}
	p.Print_vector_int(arr3);
	cout << "arr4:";
	for (auto i = arr4.rbegin(); i < arr4.rend(); ++i) {
		cout << *i << " ";
	}
	cout << endl;
	system("pause");
	return 0;
}

3.容量操作

函数名称函数功能
size_t size() const返回元素个数
size_t capacity() const返回容量大小
bool empty() const判空
void clear()清空
void reserve(size_t n)为vector预留空间(扩容, 改变的是容量的大小) (注意, 扩容只会增加, 如传入比原容量小的值则不作操作)
void resize(size_t n )将有效元素的个数改成n个,多出的空间元素用默认构造函数构造的数据填充(注意, 字符个数只会增加, 如传入比有效长度小的值则不作操作)
void resize(size_t n ,  const value_type& val)将有效元素的个数改成n个,多出的空间元素用val填充(注意, 字符个数只会增加, 如传入比有效长度小的值则不作操作)
#include<iostream>
#include<vector>
using namespace std;
class Solution {
public:
	void Print_vector_int(const vector<int>& v) {
		for (auto i : v) {
			cout << i << ' ';
		}
		cout << endl;
	}
};
int main() {
	vector<int> arr;
	for (int i = 0; i < 10; ++i) {
		arr.push_back(i + 1);
	}
	Solution p;
	cout << arr.size() << endl;
	cout << arr.capacity() << endl;
	arr.reserve(15);
	cout << arr.size() << endl;
	cout << arr.capacity() << endl;
	arr.resize(20, -1);
	cout << arr.size() << endl;
	cout << arr.capacity() << endl;
	p.Print_vector_int(arr);
	arr.empty() ? cout << "空\n" : cout << "不为空\n";
	arr.clear();
	arr.empty() ? cout << "空\n" : cout << "不为空\n";
	system("pause");
	return 0;
}

 4.vector 修改操作

函数名称重载函数函数功能
void push_back(const value_type& val)/尾插val
void pop_back()/尾删
insert

iterator insert (iterator position,

                         const value_type& val);  

iterator insert (iterator position, size_type n, 

const value_type& val);

template <class InputIterator>    

iterator insert (iterator position, InputIterator first, 

InputIterator last);

在position位置之前插入val

在position位置之前n个插入val

在position位置之前插入

[first, last) 范围内所有的数据

erase

iterator erase (const_iterator position);

iterator erase (const_iterator first, const_iterator last);

删除position位置处的元素
删除 [first, last) 范围内的所有元素
 
operator[]

reference operator[] (size_type n);

const_reference operator[] (size_type n) const;

像数组一样操作
const类型vector则调用此函数
void swap (vector& x)(成员函数)/交换x与 *this

template <class T, class Alloc>  

void swap (vector<T, Alloc>& x, 

vector<T, Alloc>& y);(友元函数)

/交换x与y

template <class InputIterator, class T>

InputIterator find (InputIterator first, InputIterator last, const T& val);(非vector接口函数)

/vector中并未提供有关查找的成员函数或者友元函数, 这个find函数时C++库所提供, 查找范围是[first, last)
#include<iostream>
#include<vector>
using namespace std;
class Solution {
public:
	void Print_vector_int(const vector<int>& v) {
		for (auto i : v) {
			cout << i << ' ';
		}
		cout << endl;
	}
};
int main() {
	vector<int> arr;
	for (int i = 0; i < 10; ++i) {
		arr.push_back(i + 1);
	}
	vector<int> arr1(arr);
	Solution p;
	cout << arr.size() << endl;
	cout << arr.capacity() << endl;
	arr.push_back(11);
	p.Print_vector_int(arr);
	cout << arr.size() << endl;
	cout << arr.capacity() << endl;
	arr.pop_back();
	p.Print_vector_int(arr);
	cout << arr.size() << endl;
	cout << arr.capacity() << endl;
	arr.resize(11);
	arr[10] = 11;
	p.Print_vector_int(arr);
	arr.insert(arr.begin() + 2, -10);
	arr.insert(arr.begin() + 6, 3, -11);
	arr.insert(arr.begin() + 9, arr1.begin(), arr1.begin() + 5);
	p.Print_vector_int(arr);
	arr.erase(arr.begin() + 2);
	arr.erase(arr.begin() + 5, arr.begin() + 13);
	p.Print_vector_int(arr);
	vector<int>::iterator i = find(arr.begin(), arr.end(), 12);
	i >= arr.begin() && i < arr.end() ? cout << "找到了!" << *i << endl : cout << "没找到\n";
	i = find(arr.begin(), arr.end(), 10);
	i >= arr.begin() && i < arr.end() ? cout << "找到了!" << *i << endl : cout << "没找到\n";
	system("pause");
	return 0;
}

 vector 迭代器失效问题

test1.cpp

#include<iostream>
#include<vector>
using namespace std;
int main() {
	vector<int> arr;
	for (int i = 0; i < 10; ++i) {
		arr.push_back(i + 1);
	}
	vector<int>::iterator i = arr.begin() + 3;
	cout << *i << endl;
	arr.erase(i);
	cout << *i << endl;
	system("pause");
	return 0;
}

test2,cpp

#include<iostream>
#include<vector>
using namespace std;
int main() {
	vector<int> arr;
	for (int i = 0; i < 10; ++i) {
		arr.push_back(i + 1);
	}
	vector<int> arr1(arr);
	vector<int>::iterator i = arr.begin() + 3;
	cout << *i << endl;
	arr.insert(i, 20, 0);
	cout << *i << endl;
	system("pause");
	return 0;
}

 test1.cpp和test2.cpp都会出现访问非法内存的错误, 如下:

说明: 

1. 当insert函数执行时, 可能会因为原来的容量不够而进行扩容, 这样就会动态分配新的内存空间, 将原来的数据拷贝到新空间,再释放掉旧的内存空间, 这样指向旧空间元素位置的迭代器肯定就不能继续使用了, 为了规范迭代器使用, 索性insert函数不管有没有扩容的情况, 都会强制让插入位置处的迭代器失效

2. erase函数是用需要删除部分元素之后的所有元素往前平移覆盖删除部分的元素, 讲道理并没有出现像insert函数一样内存空间变化的情况, 但写STL库的大佬就这么写了, 让删除位置处的迭代器强制失效. 我们来看一下erase的原码

其中destroy就是用来让迭代器强行失效的

迭代器失效搞的人很烦啊, 不过erase和insert的返回值就是解决迭代器失效的问题, 果然, 大佬还是考虑的周到, 我们只需要在删除或插入之后在让迭代器变量接收一下函数的返回值就可以了, 例如:

#include<iostream>
#include<vector>
using namespace std;
int main() {
	vector<int> arr;
	for (int i = 0; i < 10; ++i) {
		arr.push_back(i + 1);
	}
	vector<int> arr1(arr);
	vector<int>::iterator i = arr.begin() + 3;
	cout << *i << endl;
	i = arr.insert(i, 20, 0);
	cout << *i << endl;
	system("pause");
	return 0;
}

 vector常用接口实现

Vector.h

#pragma once
#include<iostream>
using namespace std;
template<class T>
class Vector {
	size_t m_size;
	size_t m_capacity;
	T* m_data;
public:
	typedef T* Iterator;
	Vector();
	Vector(size_t n, const T& val);
	Vector(size_t n);
	Vector(const Vector<T>& x);
	Vector(initializer_list<T> l);//C++11新增
	~Vector();
	Vector<T>& operator=(const Vector<T>& x);
	Vector<T>& operator=(initializer_list<T> l);//C++11新增
	size_t size();
	size_t capacity();
	void swap(Vector<T>& x);
	friend void swap(Vector<T>& a, Vector<T>& b) {
		Vector<T> tmp = a;
		a = b;
		b = tmp;
	}
	bool empty();
	void clear();
	void resize(size_t n, const T& val = T()) {
			if (n >= m_capacity) {
				size_t m = m_size;
				m_size = n;
				reserve(n);
				for (size_t i = 0; i < m_size; memcpy(m_data + i, &val, sizeof(T)), ++i);
			}
		
	}
	void reserve(size_t n);
	void push_back(const T& x);
	void pop_back();
	Iterator begin() {
		return m_data;
	}
	Iterator end() {
		return m_data + m_size;
	}
	Iterator erase(Iterator position) {
		memcpy(position, position + 1, (end() - position - 1)*sizeof(T));//不需要深拷贝
		--m_size;
		return position;
	}
	Iterator erase(Iterator first, Iterator last) {
		memcpy(first, last, (end() - last) * sizeof(T));//不需要深拷贝
		m_size -= (last - first);
		return first;
	}
	Iterator insert(Iterator position, const T& val) {
		reserve(++m_size);
		for (Iterator i = end(); i >= position; --i) {
			*i = *(i - 1);
		}
		*position = val;
		return position;
	}
	Iterator insert(Iterator position, size_t n = 1, const T& val = T()) {
		m_size += n;
		reserve(m_size);
		for (Iterator i = end(); i >= position + n; --i) {
			*i = *(i - n);
		}
		for (Iterator i = position; i < position + n; ++i) {
			*i = val;
		}
		return position;
	}

	template <class InputIterator>
	Iterator insert(Iterator position, InputIterator first, InputIterator last) {
		int tmp = position - begin();
		int n = last - first;
		if (n <= 0) {
			return position;
		}
		m_size += n;
		reserve(m_size);
		position = m_data + tmp;//迭代器的值可能会发生变化, 因为reserve可能会重新分配内存, 释放掉原来的内存
		//迭代器可能失效
		for (Iterator i = end(); i >= position + n; --i) {
			*i = *(i - n);
		}
		//memcpy(m_data + tmp, first, n * sizeof(T));
		//可能会出现深拷贝
		for (Iterator i = position; i < position + n; ++i, ++first) {
			*i = *first;
		}
		return position;
	}
	Iterator insert(Iterator position, T&& val) {
		reserve(++m_size);
		for (Iterator i = end(); i >= position; --i) {
			*i = *(i - 1);
		}
		*position = val;
		return position;
	}
	T& operator[](const size_t n);
	T& operator[](const size_t n) const;
};
template <class T>
Vector<T>::Vector():m_size(0),
m_capacity(0),
m_data(nullptr)
{
}
template <class T>
Vector<T>::Vector(size_t n, const T& val) :m_size(n),
m_capacity(n),
m_data(new T[n])
{
	for (size_t i = 0; i < m_size; m_data[i] = val, ++i);
}
template <class T>
Vector<T>::Vector(size_t n) :m_size(0),
		m_capacity(n),
		m_data(new T[n])
	{
		for (size_t i = 0; i < m_capacity; m_data[i] = 0, ++i);
	}
template <class T>
Vector<T>::Vector(initializer_list<T> l):
	m_capacity(l.size()),
	m_size(0),
	m_data(new T[l.size()])
{
	for (auto& e : l) {
		m_data[m_size++] = e;
	}
}//C++11新增
template <class T>
Vector<T>::Vector(const Vector<T>& x) :m_size(x.m_size),
m_capacity(x.m_capacity),
m_data(new T[x.m_capacity])
{
	memcpy(m_data, x.m_data, m_capacity * sizeof(T));
}
template <class T>
Vector<T>::~Vector() {
	if (m_data) {
		delete[]m_data;
	}
	m_capacity = m_size = 0;
}
template <class T>
void Vector<T>::swap(Vector<T>& x) {
	Vector<T> tmp = *this;
	*this = x;
	x = tmp;
}
template <class T>
Vector<T>& Vector<T>::operator=(const Vector<T>& x) {
	m_size = x.m_size;
	m_capacity = x.m_capacity;
	m_data = new T[x.m_capacity];
	memcpy(m_data, x.m_data, m_capacity * sizeof(T));
	return *this;
}
template <class T>
Vector<T>& Vector<T>::operator=(initializer_list<T> l) {
	m_capacity = l.size();
	m_size = 0;
	m_data = new T[m_capacity];
	for (auto& e : l) {
		m_data[m_size++] = e;
	}
	return *this;
}//C++11新增
template <class T>
void Vector<T>::push_back(const T& x) {
	++m_size;
	reserve(m_size);
	memcpy(m_data + m_size - 1, &x, sizeof(T));
}
template <class T>
void Vector<T>::reserve(size_t n) {
	if (n >= m_capacity) {
		m_capacity != 0 ? m_capacity = n + (m_capacity / 2) : m_capacity = 10;
		m_data = (T*)realloc(m_data, sizeof(T)*m_capacity);
	}
}
template <class T>
size_t Vector<T>::size() {
	return m_size;
}
template <class T>
size_t Vector<T>::capacity() {
	return m_capacity;
}
template <class T>
bool Vector<T>::empty() {
	return m_size == 0;
}
template <class T>
void Vector<T>::clear() {
	m_size = 0;
}
template <class T>
T& Vector<T>::operator[](const size_t n) {
	return m_data[n];
}
template <class T>
T& Vector<T>::operator[](const size_t n)const { 
	return m_data[n];
}
template <class T>
void Vector<T>::pop_back() {
	if (m_size > 0) {
		--m_size;
	}
}

测试文件main.cpp 

#include<iostream>
#include"vector.h"
using namespace std;
class Solution {
public:
	void Print_vector_int(Vector<int>& v) {
		for (auto i : v) {
			cout << i << ' ';
		}
	cout << endl;
	}
};
int main() {
	Vector<int> arr;
	for (int i = 0; i < 11; ++i) {
		arr.push_back(i + 1);
	}
	Vector<int>arr2(arr);
	Solution p;
	arr.swap(arr2);
	swap(arr, arr2);
	arr.erase(arr.begin() + 4);
	arr2.erase(arr2.begin() + 4, arr2.begin() + 7);
	Vector<int>::Iterator h = arr.begin() + 2;
	arr.insert(h, 100);
	for (size_t i = 0; i < arr.size(); ++i) {
		cout << arr[i] << " ";
	}
	cout << endl;
	p.Print_vector_int(arr2);
	Vector<int> test{ 1,2,3,4,5 };
	p.Print_vector_int(test);
	Vector<int>test2;
	test2 = { 1,2,3,4,5,6,7 };
	p.Print_vector_int(test2);
	system("pause");
	return 0;
}

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值