分享

C 自己实现一个容器标准库

 汉无为 2023-05-17 发布于湖北

C++ 标准库提供了多种容器类型,可以满足不同的需求。以下是一些常用的容器类型。

std::vector: 动态数组,支持快速随机访问和在末尾添加元素,内部使用连续的存储空间。

std::deque: 双端队列,支持在首尾插入和删除元素,内部使用分块的存储空间。

std::list: 双向链表,支持在任意位置插入和删除元素,但无法通过下标直接访问元素。

std::set / std::multiset: 内部自动排序的集合,不可包含重复元素,multiset 可以包含重复元素。

std::map / std::multimap: 内部自动排序的键值对容器,不可包含重复的键,multimap 可以包含重复的键。

这些容器类型都具有各自的优点和适用场景,应根据具体情况进行选择。可以通过查看相关文档和示例代码了解更多细节。

Image

C++ STL库丰富了C++自己的生态。其实,这些容器我们也可以自己实现。在实现容器的时候,可以提高自己的代码能力,帮助我们对容器有一个更好的理解。

实现一个容器需要考虑以下几个方面:

  1. 容器接口设计:定义容器提供的操作接口,包括插入、删除、查找等基本操作,以及迭代器的定义。
  2. 数据结构实现:选择合适的数据结构来存储数据,如数组、链表、树等,同时要考虑数据的存储和访问效率。
  3. 内存管理:对于动态容器,需要考虑内存的分配和释放。
  4. 异常处理:处理可能发生的异常情况,如内存分配失败等。

以下是一个简单的示例,实现了一个简单的动态数组容器,支持插入、删除和查找等操作:

#include <iostream>#include <memory>#include <stdexcept>using namespace std;
template <typename T>class MyVector {public: // 构造函数 MyVector() : _capacity(10), _size(0) { _data = unique_ptr<T[]>(new T[_capacity]); }
// 带参构造函数,可指定容量的大小 MyVector(int capacity) : _capacity(capacity), _size(0) { _data = unique_ptr<T[]>(new T[_capacity]); }
// 拷贝构造函数 MyVector(const MyVector& other) : _capacity(other._capacity), _size(other._size) { _data = unique_ptr<T[]>(new T[_capacity]); for (int i = 0; i < _size; ++i) { _data[i] = other._data[i]; } }
// 移动构造函数 MyVector(MyVector&& other) noexcept : _capacity(move(other._capacity)), _size(move(other._size)) { _data = move(other._data); other._data = nullptr; }
// 析构函数 ~MyVector() { //这里采用的是智能指针,不需要手动析构 }

// 插入元素 void push_back(T value) { if (_size == _capacity) { resize(_capacity * 2); } _data[_size++] = value; }

// 删除最后一个元素 void pop_back() { if (_size == 0) { throw out_of_range('Vector is empty.'); } _data[--_size] = 0; }
// 删除指定位置的元素 void erase(int index) { if (index < 0 || index >= _size) { throw out_of_range('Index out of range.'); }
for (int i = index; i < _size - 1; ++i) { _data[i] = _data[i + 1]; } _data[--_size] = 0; }

//at 获取指定位置的元素 T& at(int index) { if (index < 0 || index >= _size) { throw out_of_range('Index out of range.'); } return _data[index]; }
//[] 获取指定位置的元素 T& operator[](size_t index) { if (index >= _size) { throw std::out_of_range('index out of range'); } return _data[index]; }
// 获取容器中元素的数量 int size() const { return _size; }
// 获取容器的容量大小 int capacity() const { return _capacity; }
// 判断容器是否为空 bool empty() const { return _size == 0; }

private: // 调整容器的大小 void resize(int newCapacity) { auto newData = unique_ptr<T[]>(new T[newCapacity]);
for (int i = 0; i < _size; ++i) { newData[i] = _data[i]; }
_data = move(newData); _capacity = newCapacity; }
private: unique_ptr<T[]> _data; // 存储数据的指针 int _capacity; // 容量大小 int _size; // 元素数量};

Image

以上是一个自实现容器的类,我们需要在主函数里面对其进行测试。在测试中,声明一个MyVector 对象,由于是模板类,需要指定其元素类型,类似于STL里面的std::vector<int>。

int main(){    //声明一个MyVector 对象,由于是模板类,需要指定其元素类型,类似于STL里面的std::vector<int>    MyVector<int> vec;
//测试push_back接口 for(int i=0;i<5;i++) vec.push_back(i);
//测试[] for(int i=0;i<vec.size();i++) std::cout<<vec[i]<<' '; std::cout<<std::endl;
//测试size接口 std::cout<<vec.size()<<std::endl; // 测试capacity接口。注意这里容量大小不等同于元素个数。 std::cout<<vec.capacity()<<std::endl;
//测试pop_back接口 vec.pop_back();
//测试erase接口 vec.erase(1);
//测试at for(int i=0;i<vec.size();i++) std::cout<<vec.at(i)<<' '; std::cout<<std::endl;
//测试enpty()接口 三目运算符 vec.empty()? std::cout<<'vec is empty'<<std::endl : std::cout<<'vec is not empty'<<std::endl;
return 0;}

总结:

这个示例中实现了一个模板类 MyVector,它是一个可变大小的数组容器。其中包含了插入、删除、获取元素等基本操作。

具体来说,可以使用 push_back() 函数向容器末尾添加元素,使用 pop_back() 函数删除最后一个元素,使用 erase() 函数删除指定位置的元素,使用 at() 函数或者下标运算符[]获取指定位置的元素,以及使用 size() 和 capacity() 函数分别获取容器中元素的数量和容量大小。

您可以根据需要对这个示例进行修改和扩展,例如添加更多的操作函数、实现迭代器、支持动态扩容、升序降序排列等等。

Image

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多