赞
踩
目录
4,vector(int n, const T& value = T())
6,vector(InputIterator first, InputIterator last)
13,resize(size_t n, const T& value = T())
16,insert(iterator pos, const T& x)
上面我们认识了 vector 类,有了一个大概的理解,下面我们来实现一下 vector 类的框架,来更好的熟悉 vector 类,也让我们对其有着更深的理解;
我们先写一个 vector 类的基本框架;
- namespace newVector
- {
- template<class T>
- class vector
- {
- public:
-
- // Vector的迭代器是一个原生指针
- typedef T* iterator;
-
- private:
-
- iterator _start = nullptr; // 指向数据块的开始
-
- iterator _finish = nullptr; // 指向有效数据的尾
-
- iterator _endOfStorage = nullptr; // 指向存储容量的尾
-
- };
- }
vector 类里面是可以包含很多类型的,所以我们用模板来表示,以应用各种场景,vector 类里面多用迭代器的方式来表示,vector 的迭代器其实就是一个原生指针;
_start 指向数据块的开始,_finish 指向有效数据的尾,_endOfStorage 指向存储容量的尾;
- vector()
- {}
因为我们在构造框架的时候已经给了缺省值,所以可以不用在写了;
可以看到这里已经初始化了;
就是打印输出嘛,方便后续测试;
- void pinrt()
- {
- for (size_t i = 0; i < size(); i++)
- {
- cout << _start[i] << " ";
- }
- }
我们都会用,初始化 n 个 value;
- vector(int n, const T& value = T())
- {
- reserve(n);
- for (size_t i = 0; i < n; i++)
- {
- push_back(value);
- }
- }
有人不知道缺省值给个 T()是什么意思,首先 T()是匿名对象,默认就是编译器对内置类型的初始化;
测试一下:
- int main()
- {
- newVector::vector<int> v1(5, 8);
- v1.pinrt();
- return 0;
- }
现在我们不给初始化的值试试:
- int main()
- {
- newVector::vector<int> v1(5);
- v1.pinrt();
- return 0;
- }
默认初始化为0;
拷贝构造(深拷贝)
- vector(const vector<T>& v)
- {
- reserve(v.capacity());
- //memcpy(_start, v._start, sizeof(T)*v.size());
- for (size_t i = 0; i < v.size(); i++)
- {
- _start[i] = v._start[i];
- }
- _finish = _start + v.size();
- }
为什么不用 memcpy 呢,上面那个明显要便捷一点,因为 memcpy 是浅拷贝,如果遇到 T是string类的时候就会因为析构函数多次析构同一块空间而报错,而下面这个挨个赋值是深拷贝,他们两个 _start 不会指向同一块空间;
- int main()
- {
- newVector::vector<int> v1(5,8);
- newVector::vector<int> v2(v1);
- v2.pinrt();
- return 0;
- }
可以看到也是 OK 的;
这个要配合模板使用,这代表一个范围,只要是同类型的都可以;
- template<class InputIterator>
-
- vector(InputIterator first, InputIterator last)
- {
- reserve(last - first + 1);
- while (first != last)
- {
- push_back(*first);
- first++;
- }
- }
先扩容嘛,像这种区间都是左闭右开的,然后再挨个尾插即可;
- int main()
- {
- int arr[5] = { 1,2,3,4,5 };
- newVector::vector<int> v1(arr,arr+5);
- v1.pinrt();
- return 0;
- }
只要是同类型的都可以,像这种的数组都行;
析构函数
- ~vector()
- {
- delete[] _start;
- _start = _finish = _endOfStorage = nullptr;
- }
delete 后面一定要带 [ ] ,因为析构的是一段连续的空间,就看做是数组即可,然后再将各个迭代器置空即可;
- int main()
- {
- newVector::vector<int> v1(5,8);
- v1.~vector();
- v1.pinrt();
- return 0;
- }
指向第一个元素的迭代器
- iterator begin()
- {
- return _start;
- }
直接返回 _start 即可;
- int main()
- {
- int arr[5] = { 1,2,3,4,5 };
- newVector::vector<int> v1(arr,arr+5);
- cout << *v1.begin();
- return 0;
- }
指向最后一个元素下一个元素的迭代器
- iterator end()
- {
- return _finish;
- }
直接返回 _finish 即可;
- int main()
- {
- int arr[5] = { 1,2,3,4,5 };
- newVector::vector<int> v1(arr,arr+5);
- cout << *v1.end();
- return 0;
- }
直接随机数了;
换个思路,试一下:
- int main()
- {
- int arr[5] = { 1,2,3,4,5 };
- newVector::vector<int> v1(arr,arr+5);
- cout << *(v1.end()-1);
- return 0;
- }
我们找他前一个迭代器,果然是最后一个数;
返回有效数据个数
- size_t size() const
- {
- return _finish - _start;
- }
直接迭代器相减即可;
- int main()
- {
- int arr[5] = { 1,2,3,4,5 };
- newVector::vector<int> v1(arr,arr+5);
- cout << v1.size();
- return 0;
- }
返回容量大小
- size_t capacity() const
- {
- return _endOfStorage - _start;
- }
直接迭代器相减即可,差值就是容量大小;
- int main()
- {
- int arr[5] = { 1,2,3,4,5 };
- newVector::vector<int> v1(arr,arr+5);
- cout << v1.capacity();
- return 0;
- }
扩容
- void reserve(size_t n)
- {
- if (n > capacity())
- {
- T* tmp = new T[n];
- size_t old = size();
- if (_start)
- {
- //memcpy(tmp, _start, old * sizeof(T));
- for (size_t i = 0; i < old; i++)
- {
- tmp[i] = _start[i];
- }
- delete[] _start;
- }
- _start = tmp;
- _finish = _start + old;
- _endOfStorage = _start + n;
- }
- }
当要扩容时才用的着,先判断,然后开辟一段需要的空间,之后就是拷贝赋值了,这里我们还是没有用 memcpy 因为是浅拷贝,然后再释放原空间,再将迭代器重新赋值即可;
- int main()
- {
- int arr[5] = { 1,2,3,4,5 };
- newVector::vector<int> v1(arr,arr+5);
- cout << v1.capacity() << endl;
-
- v1.reserve(20);
- cout << v1.capacity() << endl;
- return 0;
- }
一目了然;
更改有效数据个数,不够则填充,可以指定填充数据;
- void resize(size_t n, const T& value = T())
- {
- if (n < size())
- {
- _finish = _start + n;
- }
- else
- {
- if (n > capacity())
- {
- reserve(n);
- }
- while (_finish!=_start+n)
- {
- push_back(value);
- }
- }
- }
当缩减数据时直接把 _finish 往前移即可,当扩容时先扩容,然后进行填充;
- int main()
- {
- int arr[5] = { 1,2,3,4,5 };
- newVector::vector<int> v1(arr,arr+5);
- cout << v1.size() << endl;
-
- v1.resize(10);
- cout << v1.size() << endl;
-
- v1.resize(15, 6);
- cout << v1.size() << endl;
- v1.pinrt();
- return 0;
- }
可以看到,当我们不指定填充时默认填充0;
尾插
- void push_back(const T& x)
- {
- if (_finish == _endOfStorage)
- {
- size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
- reserve(newcapacity);
- }
- *_finish = x;
- _finish++;
- }
首先要检查是否需要扩容,然后赋值,将 _finish 往后移一位即可;
- int main()
- {
- int arr[5] = { 1,2,3,4,5 };
- newVector::vector<int> v1(arr, arr + 5);
-
- v1.push_back(6);
- v1.push_back(7);
- v1.pinrt();
- return 0;
- }
插入十分成功;
尾删
- void pop_back()
- {
- assert(size() > 0);
- _finish--;
- }
像这种数组类型的,直接对其迭代器动手就行,直接 _finish 往前移一位即可;
- int main()
- {
- int arr[5] = { 1,2,3,4,5 };
- newVector::vector<int> v1(arr, arr + 5);
-
- v1.pop_back();
- v1.pop_back();
- v1.pinrt();
- return 0;
- }
删除非常顺利;
指定位置插入
- iterator insert(iterator pos, const T& x)
- {
- assert(pos >= _start && pos <= _finish);
- size_t old = pos - _start;
- if (_finish == _endOfStorage)
- {
- size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
- reserve(newcapacity);
- }
- pos = _start + old;
- memcpy(pos + 1, pos, (_finish - pos) * sizeof(T));
- *pos = x;
- _finish++;
- return pos;
- }
这里会面临一个迭代器失效的问题,当扩容后,原本的 pos 还是指向旧空间就失效了,所以我们要更新 pos ;
- int main()
- {
- int arr[5] = { 1,2,3,4,5 };
- newVector::vector<int> v1(arr, arr + 5);
-
- auto pos = find(v1.begin(), v1.end(), 1);
- v1.insert(pos, 9);
-
- pos= find(v1.begin(), v1.end(), 5);
- v1.insert(pos, 9);
- v1.pinrt();
- return 0;
- }
完美插入;
擦除指定位置
- iterator erase(iterator pos)
- {
- assert(pos >= 0 && pos <= _finish);
- memcpy(pos, pos + 1, sizeof(T)*(_finish - pos));
- _finish--;
- return pos;
- }
先断言判断,然后直接往前移一位覆盖即可,再更新一下 _finish ;
- int main()
- {
- int arr[5] = { 1,2,3,4,5 };
- newVector::vector<int> v1(arr, arr + 5);
-
- auto pos = find(v1.begin(), v1.end(), 1);
- v1.erase(pos);
-
- pos = find(v1.begin(), v1.end(), 5);
- v1.erase(pos);
- v1.pinrt();
- return 0;
- }
也是成功擦除了;
判空
- bool empty()
- {
- return _start == _finish;
- }
当为空时返回真,反之亦然;
- int main()
- {
- int arr[5] = { 1,2,3,4,5 };
- newVector::vector<int> v1(arr, arr + 5);
- cout << v1.empty() << endl;
-
- newVector::vector<int> v2;
- cout << v2.empty();
- return 0;
- }
返回下标对应的值;
- T& operator[](size_t pos)
- {
- assert(pos >= 0 && pos <= size());
- return _start[pos];
- }
直接像数组一样取值返回即可;
- int main()
- {
- int arr[5] = { 1,2,3,4,5 };
- newVector::vector<int> v1(arr, arr + 5);
-
- cout << v1[0] << " " << v1[4];
- return 0;
- }
写法也是跟数组一样简单;
赋值,深拷贝
- void swap(vector<T>& v)
- {
- std::swap(_start, v._start);
- std::swap(_finish, v._finish);
- std::swap(_endOfStorage, v._endOfStorage);
- }
-
- vector<T>& operator= (vector<T> v)
- {
- swap(v);
- return *this;
- }
直接一手交换即可;
- int main()
- {
- int arr[5] = { 1,2,3,4,5 };
- newVector::vector<int> v1(arr, arr + 5);
-
- newVector::vector<int> v2 = v1;
- v2.pinrt();
- return 0;
- }
我们就先搞一个大概的,其中还有很多分支,比如我们写的是擦除某个数据,其实也可以擦除某个范围,这些就靠大家去摸索,查阅文档了;
vector类的实现就到这里了;
加油!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。