使用C++手写简易顺序表
- 在C++的STL中最常用的数据结构可谓是std::vector了, vector弥补了数组不可以动态扩展的缺陷并且保证了储存在连续的内存块中,使访问效率很高。
- std::vector就是标准的顺序表,类似的还有Java中的ArrayList,那么他们是如何实现的呢?
这里,我们就来一起实现一个简易的顺序表。要说明的是我们的vector并不包含一些算法譬如sort,同时也不提供迭代器,前者属于算法的范畴,容易让我们关注点转移,后者需要符合STL中的迭代器的标准,涉及一些STL的高级知识,不过,两者的内容都会再以后补充。
定义Vector的接口规范
// in Vector.h
// 省略了必要的头文件保护
#define DEFAULT_CAPACITY 10 // 默认容量
template <typename _Tp>
class Vector {
private:
_Tp * _data = nullptr; // 指向_Tp类型元素的指针, 旨在借助动态数组实现Vector
std::size_t _size = 0; // 保存元素个数
std::size_t _capacity = DEFAULT_CAPACITY; // 容量, 即当前动态数组的大小
public: // 公共接口
explicit Vector(std::size_t capacity = DEFAULT_CAPACITY); // 可以指定初始大小
Vector(const Vector<_Tp> & other); // 拷贝构造
Vector(Vector<_Tp> && other); // 移动构造
Vector<_Tp>& operator= (const Vector<_Tp> & other); // 拷贝赋值
Vector<_Tp>& operator= (Vector<_Tp> && other); // 移动赋值
void push_back(const _Tp& ele); // 增
void removeAt(std::size_t index); // 删
_Tp& at(std::size_t index); // 获取下标为index的元素的引用
const _Tp& at(std::size_t index) const; // 上者的const重载
std::size_t size() const; // 获取当前元素个数
~Vector();
private: // helper-function(s)
void extend(); // 根据当前元素多少对数组进行扩展
};
依次实现
(省略了两大构造和两大赋值操作的实现)
template <typename _Tp>
Vector<_Tp>::Vector(std::size_t cap) {
_capacity = cap;
_data = new _Tp[cap];
}
template <typename _Tp>
Vector<_Tp>::~Vector() {
if (_data) delete [] _data; // _data != nullptr
}
template <typename _Tp>
void Vector<_Tp>::push_back(const _Tp& ele) {
extend(); // 检查是否需要扩展
_data[_size] = ele; // 加在_data的尾部
++_size; // 更新_size
}
template <typename _Tp>
void Vector<_Tp>::removeAt(std::size_t index) {
for (int i = index; i < _size + 1; ++i) {
_data[i] = _data[i + 1]; // 要求_Tp适当的重载了赋值运算符(或原生类型)
}
--_size; // 更新_size
}
template <typename _Tp>
_Tp& Vector<_Tp>::at(std::size_t index) {
return _data[index]; // 返回下标为index的值, 无越界检查
}
template <typename _Tp>
const _Tp& Vector<_Tp>::at(std::size_t index) const {
return _data[index]; // 返回下标为index的值, 无越界检查
}
template <typename _Tp>
std::size_t Vector<_Tp>::size() const {
return _size;
}
// 核心操作
template <typename _Tp>
void Vector<_Tp>::extend() {
if (_size < _capacity) return; // 恰好满载才扩展
_capacity <<= 1; // 两倍扩容
_Tp * oldData = _data; // 保留以赋值即释放原有内存
_data = new _Tp[_capacity]; // 获取翻倍空间
for (int i = 0; i < _size; ++i) { // copy, 不使用memset等操作是因为_Tp可能是含指针的类型
_data[i] = oldData[i];
}
delete [] oldData; // 释放原有内存空间
}
测试
- test…cpp
#include <iostream>
#include "Vector.h"
int main() {
Vector<int> v;
for (int i = 0; i < 21; ++i)
v.push_back(i);
for (int i = 0; i < v.size(); ++i)
std::cout << v.at(i) << ", ";
std::cout << "\n" << v.size() << "\n";
v.removeAt(17);
for (int i = 0; i < v.size(); ++i)
std::cout << v.at(i) << ", ";
std::cout << "\n" << v.size() << "\n";
v.removeAt(5);
for (int i = 0; i < v.size(); ++i)
std::cout << v.at(i) << ", ";
std::cout << "\n" << v.size() << "\n";
return 0;
}
- 输出
PS ~~~> g++ test.cpp -o test; ./test
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20,
20
0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20,
19
本文详细介绍如何使用C++从零开始实现一个简易的顺序表,包括动态扩展、元素增删及访问等核心操作,通过具体代码示例帮助读者深入理解vector的工作原理。

85

被折叠的 条评论
为什么被折叠?



