C++——vector

目录

一、简介

二、接口

  1.构造

2.空间变化

3.增删查改

 三、vector与string的区别

四、模拟实现 

vector.h

test.cpp


一、简介

        vector,其实就是我们C语言学过的动态顺序表,一个可以存储任何数据类型,可以动态增长的数组。C++的STL将其收录,我们再想使用顺序表的时候就不用再自己去造轮子了,可以直接调用库中的顺序表帮我们完成各种需求。

        本博客主要还是介绍vector的各种接口以及部分常用接口的模拟实现

二、接口

        纵览所有接口,我们可以发现vector的接口比string简洁多了,这是因为vector吸取了很多string的经验,减少了冗余。

        我会把比较重要的接口调用的演示代码给出,并配上注释,各位有string的经验应该很容易明白,各个容器之间的很多知识是互通的。

  1.构造

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

void test_vector1()
{
	// 默认构造,啥也没有,capacity是0
	vector<int> v1;
	// 10个1构造并初始化
	vector<int> v2(10, 1);
	// 迭代器区间构造,这个迭代器不仅可以是vector的,其实也可以是其它容器的
	vector<int> v3(++v2.begin(), --v2.end());
	// 拷贝构造
	vector<int> v4(v3);

	// 普通遍历
	for (size_t i = 0; i < v4.size(); i++)
	{
		cout << v4[i] << " ";
	}
	cout << endl;

	// 迭代器遍历
	vector<int>::iterator it = v4.begin();
	while (it != v4.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	// 范围for遍历
	for (auto e : v3)
	{
		cout << e << " ";
	}
	cout << endl;
}

int main()
{
	test_vector1();

	return 0;
}

2.空间变化

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

void TestVectorExpand()
{
	// vector在vs环境下,底层是刚开始开辟一个buff数组,等数组满了之后再开始1.5倍扩容
	// 如果是gcc条件下,就不会有buff数组,初始就是2倍扩容
	size_t sz;
	vector<int> v;
	v.reserve(100);

	sz = v.capacity();
	cout << "capacity changed: " << sz << '\n';

	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();

	// reserve接口的作用和在string中的类似
	vector<int> v(10, 1);
	v.reserve(20);
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	v.reserve(15);
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	v.reserve(5);
	cout << v.size() << endl;
	cout << v.capacity() << endl;
}

void test_vector3()
{
	//TestVectorExpand();

	// resize的作用与string中的resize类似
	vector<int> v(10, 1);
	v.reserve(20);
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	v.resize(15, 2);
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	v.resize(25, 3);
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	v.resize(5);
	cout << v.size() << endl;
	cout << v.capacity() << endl;
}
int main()
{
	test_vector1();
    test_vector2();

	return 0;
}

3.增删查改

 跟string很类似,看演示就好

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

void test_vector4()
{
	vector<int> v(10, 1);
	v.push_back(2);
	v.insert(v.begin(), 0);

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

	v.insert(v.begin() + 3, 10);

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

	vector<int> v1(5, 0);
	for (size_t i = 0; i < 5; i++)
	{
		cin >> v1[i];
	}

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

}

void test_vector5()
{
	vector<string> v1;
	string s1("xxxx");
	v1.push_back(s1);

	v1.push_back("yyyyy");
	for (const auto& e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
}

int main()
{
	test_vector4();
    test_vector5();

	return 0;
}

 三、vector<char>与string的区别

        string存储的字符串是以/0结尾的,而vector<char>如果不手动添加,结尾就不是\0,另外,string有许多vector<char>没有的接口,更能有效地对字符串进行操作。 

四、模拟实现 

由于vector需要存储不同的数据类型,所以实现需要用到模板,而模板的声明和定义如果分离的话在运行的时候会发生链接错误,所以只需要一个头文件和一个测试文件

vector.h

实现过程要尤其注意迭代器失效的问题

插入的实现中,如果插入发生了扩容,那么原来传入的pos位置的迭代器就会失效,因为vector已经转移了空间位置,而pos仍在原位,为了得到之后相应的位置,可以把之后的pos位置作为返回值返回

reverse中,如果发生了扩容,则原来的start和finish指针也会失效,则其size()接口也会失效,所以需要在开始就记录下来old_size,方便后续的使用

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

namespace muss
{
	// 使用模板的时候不要声明和定义分离,会发生链接错误
	template<typename T>
	class vector
	{
		typedef T* iterator;
		typedef const T* const_iterator;

	public:
		vector() :_start(nullptr), _finish(nullptr), _end_of_storage(nullptr) { }
		vector(const vector<T>& v)
		{
			reserve(v.size());	
			for (const auto& e : v)
			{
				push_back(e);
			}
		}
		// 缺省值是类似于int()即整型的默认构造,默认是0
		// 必须加const才能接收T()
		vector(size_t n, const T& value = T())
		{
			// 提前开空间提高效率
			reserve(n);
			while (n--) push_back(value);
		}

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

		// 可以用任何容器的迭代器区间初始化
		template<typename InputIterator>
		vector(InputIterator begin, InputIterator end)
		{
			while (begin != end)
			{
				push_back(*begin);
				++begin;
			}
		}

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

		size_t size() const { return _finish - _start; }
		size_t capacity() const { return _end_of_storage - _start; }
		
		iterator begin() { return _start; }
		iterator end() { return _finish; }
		const_iterator begin() const { return _start; }
		const_iterator end() const { return _finish; }

		void swap(vector<T>& v)
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_end_of_storage, v._end_of_storage);
		}

		void reserve(size_t n)
		{
			size_t old_size = size();
			if (capacity() < n)
			{
				T* tmp = new T[n];
				// 不能是memcpy,浅拷贝申请空间的自定义类型会出现错误
				for (int i = 0; i < size(); ++i)
				{
					tmp[i] = _start[i];
				}
				delete[] _start;
				_start = tmp;
				// 这里的_start已经不能减_finish了,也就是说size求不出来了
				// 把两行换换位置可以,不过写代码的过程中为了保险起见可以用old_size
				//_finish = _start + size();
				_finish = _start + old_size;
				_end_of_storage = _start + n;
			}
		}

		void resize(size_t n, const T& value = T())
		{
			if (n < size())
				_finish = _start + n;
			else
			{
				reserve(n);
				// 填充到size而不是capacity
				while (_finish < _start + n)
					push_back(value);
			}
		}

		void clear()
		{
			_finish = _start;
		}

		bool empty()
		{
			return _finish == _start;
		}

		// 擦除指定位置元素
		void erase(iterator pos)
		{
			assert(pos >= _start && pos < _finish);

			for (iterator i = pos; i < _finish - 1; ++i)
			{
				*i = *(i + 1);
			}
			--_finish;
		}

		// 一旦发生扩容,pos会失效(pos在原来位置,但是_start和_finish等等都已经转移)
		//void insert(iterator pos, const T& value)
		//{
		//	assert(pos >= _start && pos <= _finish);
		//	if(size() == capacity())
		//		reserve(capacity() == 0 ? 4 : 2 * capacity());
		//	for (iterator i = _finish; i > pos; --i)
		//	{
		//		*i = *(i - 1);
		//	}
		//	++_finish;
		//	*pos = value;
		//}

		// 所以我们需要在扩容结束时更新pos,并且如果想在函数外继续使用pos,我们需要给返回值
		iterator insert(iterator pos, const T& value)
		{
			assert(pos >= _start && pos <= _finish);
			if (size() == capacity())
			{
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : 2 * capacity());
				pos = _start + len;
			}

			for (iterator i = _finish; i > pos; --i)
			{
				*i = *(i - 1);
			}
			++_finish;
			*pos = value;
			return pos;
		}

		void push_back(const T& value)
		{
			if (size() == capacity())
			{
				reserve(capacity() == 0 ? 4 : 2 * capacity());
			}
			*_finish = value;
			++_finish;
		}

		void pop_back()
		{
			erase(end() - 1);
		}

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

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

		vector<T>& operator=(const vector<T>& v)
		{
			clear();
			reserve(v.size());

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

			return *this;
		}

	private:
		iterator _start = nullptr; // 首元素位置
		iterator _finish = nullptr;// 尾元素位置的下一个位置
		iterator _end_of_storage = nullptr;// 超出容量的下一个位置
	};

	// 可以打印所有容器
	template<typename Container>
	void print_container(const Container& c)
	{
		for (const auto& e : c)
		{
			cout << e << " ";
		}
		cout << endl;
	}

	void vector_test1()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);
		print_container(v1);

		vector<int> v2(v1);
		print_container(v2);

		vector<int> v3(v2.begin() + 1, v2.end() - 1);
		print_container(v3);

		vector<int> v4(10);
		// ???????????????
		vector<int> v5(9, 12);
		print_container(v4);
		print_container(v5);
		
	}

	void vector_test2()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);
		print_container(v1);

		v1.insert(v1.begin() + 1, 22);
		print_container(v1);
		v1.insert(v1.begin(), 123);
		print_container(v1);
		v1.insert(v1.end(), 999);
		print_container(v1);

		vector<int> v2;
		v2.push_back(1);
		v2.push_back(2);
		v2.push_back(3);
		v2.push_back(4);
		v2.push_back(5);
		print_container(v2);
		v2.resize(3);
		print_container(v2);
		v2.resize(7, 8);
		print_container(v2);
		v2.resize(12, 13);
		print_container(v2);

	}

	void vector_test3()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);
		print_container(v1);
		cout << v1[2] << endl;
		cout << v1[0] << endl;
		cout << v1[4] << endl;
		v1.clear();
		print_container(v1);
		cout << v1.empty() << endl;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);
		cout << v1.empty() << endl;
		print_container(v1);

		v1.erase(v1.begin() + 1);
		print_container(v1);
		v1.erase(v1.begin());
		print_container(v1);
		// 要注意尾删得用end()-1,不然会越界
		v1.erase(v1.end() - 1);
		print_container(v1);
		v1.pop_back();
		print_container(v1);
	}

	void vector_test4()
	{
		vector<int> v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);
		print_container(v1);

		vector<int> v2;
		vector<int> v3;
		v2 = v3 = v1;
		print_container(v2);
		print_container(v3);
		vector<int> v4;
		v4.push_back(11);
		v4.push_back(22);
		v4.push_back(33);
		swap(v4, v1);
		print_container(v1);
		print_container(v4);

	}

	void vector_test5()
	{
		vector<string> v;
		v.push_back("111111");
		v.push_back("111111");
		v.push_back("111111");
		v.push_back("111111");
		v.push_back("111111");
		v.push_back("111111");
		v.push_back("111111");
		print_container(v);
	}
}

test.cpp

#include "vector.h"
#include <vector>
//using namespace std;

int main()
{
	//vector<int> v1 = { 1,2,3,4,5,7,8,5,13,54 };
	//cout << v1.capacity() << endl;
	//vector<int> v2(v1);
	//cout << v2.capacity() << endl;

	muss::vector_test5();

	//cout << int() << endl;


	return 0;
}

完结撒花~~~~(✿╹◡╹)

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值