目录
一、简介
二、接口
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是0vector<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而不是capacitywhile (_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;
}
完结撒花~~~~(✿╹◡╹)