目录
一,list
1, list 的节点与迭代器
2,list 的数据结构、一些简单的功能、构造函数
3,list 的对元素操作
4,C++ 11 的一些功能
5,完整代码:
二,queue
一,list
std::list 是 C++ 标准模板库 (STL) 中提供的一个容器模板,它被实现为环状双向链表。list 和 vector 是两个最常被使用的容器。相较于 vector 的连续线性空间,list 的非连续存储就显得复杂许多,它的好处是每次插人或删除一个元素,就配置或释放一个元素空间。因此,list 对空间的使用一点也不浪费。而且,对于任何位置的插入或移除元素,list 永远是常数时间。
关于 list 的各种接口的用法这里就不介绍了,此文主要是模拟实现。
1, list 的节点与迭代器
list 本身和 list 的节点是不同的结构,是需要分开设计的。list 中会包含 list 节点结构。节点结构:
template<class T>
struct list_node {list_node<T>* next, * pre; // next 指向下一个节点,pre 指向前一个节点T data;list_node(const T& data_ = T()):next(nullptr),pre(nullptr),data(data_){}
};
如果不清楚迭代器是什么或者是不清楚要怎么设计一个容器专属的迭代器可以看看这个:C++ 迭代器与反向迭代器-CSDN博客
如果对 vector 的实现细节感兴趣可以看看这个:C++ 简单模拟实现 STL 中的 vector 与 stack-CSDN博客
list 不再能够像 vector 一样以普通指针作为迭代器,因为其节点不保证在储存空间中连续存在。所以 list 迭代器必须有能力指向 list 的节点,并且能够进行正确的递增(++)、递减(--)、取值(*)、成员存取(->)等操作。这里要注意,取值时取的是节点的数据值,不是节点本身,成员取用时取用的是节点的成员。例如:
mySTL::list<int> lt = { 1,2,3,4,5 };
for (auto it = lt.begin();it != lt.end();++it) {cout << *it << " "; // 输出的是 1 2 3 4 5;
}
mySTL::list<pair<int, int>> lt2 = { {1,2},{3,4},{5,6} };
for (auto it = lt2.begin();it != lt2.end();++it) {cout << it->first << "," << it->second << " # "; // 输出的是 1,2 # 3,4 # 5,6 #
}
list 迭代器的设计:
template<class T,class Ref,class Ptr>
struct list_iterator {typedef list_node<T> Node;typedef list_iterator<T, Ref, Ptr> self;typedef list_iterator<T, T&, T*> iterator;// 迭代器内部的一个普通指针类型,指向对应的 list 节点Node* _node;// 迭代器相应类型的定义typedef T value_type;typedef Ref reference;typedef Ptr pointer;// 迭代器的构造list_iterator(Node* node):_node(node){} // 用节点构造当前迭代器list_iterator(const iterator& iter):_node(iter._node){} // 用普通迭代器构造当前迭代器// 注意, 对迭代器解引用, 取出来的是节点里面的数据值reference operator*()const { return _node->data; }// &(operator*()), 这是一个标准的做法pointer operator->()const { return &(operator*()); }self& operator++() { _node = _node->next; return *this;}self operator++(int){Node* tmp = _node;_node = _node->next;return tmp;}self& operator--() { _node = _node->pre; return *this;}self operator--(int) {Node* tmp = _node;_node = _node->pre;return tmp;}bool operator==(const self& iter)const { return _node == iter._node; }bool operator!=(const self& iter)const { return not operator==(iter); }};
2,list 的数据结构、一些简单的功能、构造函数
list 是一个带有头节点的环状双向链表,它只需要一个指针就可以完整的表示整个链表,为了方便操作,我们也可以来额外来维护一个 size 变量来表示节点的个数(不包括头节点)。
template<class T>
class list {// ...
private:typedef list_node<T> Node;typedef list<T> self;private:Node* _head = nullptr; //头节点size_t _size = 0;void initialize() { //初始化头节点_head = new Node;_head->pre = _head->next = _head;}// ...
};
list 中有关迭代器的操作与一些简单的基础功能:
template<class T>
class list {// ...
public://迭代器/*正向迭代器*/typedef list_iterator<T, T&, T*> iterator;typedef list_iterator<T, const T&, const T*> const_iterator;iterator begin() { return _head->next; }iterator end() { return _head; }const_iterator begin()const { return _head->next; }const_iterator end()const { return _head; }/*反向迭代器*/typedef Reverse_Iterator<iterator> reverse_iterator;typedef Reverse_Iterator<const_iterator> const_reverse_iterator;reverse_iterator rbegin() { return end(); }reverse_iterator rend() { return begin(); }const_reverse_iterator rbegin()const { return end(); }const_reverse_iterator rend()const { return begin(); }public:// 简单的基础功能size_t size() { return _size; }bool empty() { return _size == 0; }void clear() {while (not empty()) pop_back();}void swap(list& lt) {std::swap(_head, lt._head);std::swap(_size, lt._size);}// 对首尾元素的访问T& back() { return *(--end()); }const T& back()const { return *(--end()); }T& front() { return *begin(); }const T& front()const { return *begin(); }// ...
};
list 的构造函数:
template<class T>
class list {// ...
public://构造list() { initialize(); }list(size_t n, const T& data = T()) {initialize();while (n--) { push_back(data); }}list(int n, const T& data = T()) {initialize();while (n--) { push_back(data); }}/*使用迭代器构造*/template<class input_iterator> list(input_iterator begin, input_iterator end) {initialize();while (begin != end) {push_back(*(begin++));}}//拷贝list(const list& lt) {initialize();for (const auto& data : lt) {push_back(data);}}self& operator=(list lt) {swap(lt);return *this;}//析构~list() {clear();delete _head;_head = nullptr;_size = 0;}// ...
};
3,list 的对元素操作
std::list 里面提供的元素操作有很多,这里就只挑几种重要的函数来实现。我们把 insert 与 erase 操作实现之后就可以很轻松的实现 push_back()、push_front()(尾插,头插) 与 pop_back() 、pop_front() (尾删,头删)操作了。
template<class T>
class list {// ...
public://增void push_front(const T& data) { insert(begin(), data); } // 头插新节点void push_back(const T& data) { insert(end(), data); } // 尾插新节点// 在 pos 位置的前面插入一个值为 data 的新节点, 返回新插入的节点的迭代器iterator insert(iterator pos, const T& data) {Node* node = pos._node;Node* newNode = new Node(data);newNode->next = node;newNode->pre = node->pre;node->pre->next = newNode;node->pre = newNode;++_size;return newNode;}//删void pop_front() { erase(begin()); } // 头删void pop_back() { erase(--end()); } // 尾删// 删掉迭代器 pos 所指向的节点, 返回删掉的节点的位置的新节点迭代器iterator erase(iterator pos) {assert(pos != end());Node* tmp = pos._node;tmp->pre->next = tmp->next;tmp->next->pre = tmp->pre;Node* res = tmp->next;delete tmp;--_size;return res;}// ...
};
4,C++ 11 的一些功能
这里主要实现的功能是 initializer_list 初始化 与 右值引用,如果对这两个东西不了解的话可以看看这两篇博客:
C++11 一些常用的功能-CSDN博客
C++ 左值引用与右值引用-CSDN博客
template<class T>
class list {// ...
public://C++ 11 //initializer_list构造list(const std::initializer_list<T>& lt) {initialize();for (const T& data : lt) {push_back(data);}}//右值引用相关//移动构造与移动赋值list(list&& lt) :_head(lt._head), _size(lt._size) {initialize();lt._head = nullptr;lt._size = 0;}self& operator=(list&& lt) {delete* this;std::swap(_head, lt._head);std::swap(_size, lt._size);}//插入void push_front(T&& data) { insert(begin(), std::forward<T>(data)); }void push_back(T&& data) { insert(end(), std::forward<T>(data)); }iterator insert(iterator pos, T&& data) {Node* node = pos._node;Node* newNode = new Node(std::forward<T>(data));newNode->next = node;newNode->pre = node->pre;node->pre->next = newNode;node->pre = newNode;++_size;return newNode;}// ...
};
5,完整代码:
namespace mySTL {// list 节点类template<class T>struct list_node {list_node<T>* next, * pre; // next 指向下一个节点,pre指向前一个节点T data;list_node(const T& data_ = T()):next(nullptr),pre(nullptr),data(data_){}};// list 迭代器类template<class T,class Ref,class Ptr>struct list_iterator {typedef list_node<T> Node;typedef list_iterator<T, Ref, Ptr> self;typedef list_iterator<T, T&, T*> iterator;// 迭代器内部的一个普通指针类型,指向对应的 list 节点Node* _node;// 迭代器相应类型的定义typedef T value_type;typedef Ref reference;typedef Ptr pointer;// 迭代器的构造list_iterator(Node* node):_node(node){} // 用节点构造当前迭代器list_iterator(const iterator& iter):_node(iter._node){} // 用普通迭代器构造当前迭代器// 注意, 对迭代器解引用, 取出来的是节点里面的数据值reference operator*()const { return _node->data; }// &(operator*()), 这是一个标准的做法pointer operator->()const { return &(operator*()); }self& operator++() { _node = _node->next; return *this;}self operator++(int){Node* tmp = _node;_node = _node->next;return tmp;}self& operator--() { _node = _node->pre; return *this;}self operator--(int) {Node* tmp = _node;_node = _node->pre;return tmp;}bool operator==(const self& iter)const { return _node == iter._node; }bool operator!=(const self& iter)const { return not operator==(iter); }};// list 类template<class T>class list {private:typedef list_node<T> Node;typedef list<T> self;private:Node* _head = nullptr; //头节点size_t _size = 0;void initialize() { //初始化头节点_head = new Node;_head->pre = _head->next = _head;}public://迭代器/*正向迭代器*/typedef list_iterator<T, T&, T*> iterator; typedef list_iterator<T, const T&, const T*> const_iterator;iterator begin() { return _head->next; }iterator end() { return _head; }const_iterator begin()const { return _head->next; }const_iterator end()const { return _head; }/*反向迭代器*/typedef Reverse_Iterator<iterator> reverse_iterator; typedef Reverse_Iterator<const_iterator> const_reverse_iterator;reverse_iterator rbegin() { return end(); }reverse_iterator rend() { return begin(); }const_reverse_iterator rbegin()const { return end(); }const_reverse_iterator rend()const { return begin(); }public:// 简单的基础功能size_t size() { return _size; }bool empty() { return _size == 0; }void clear() { while (not empty()) pop_back();}void swap(list& lt) {std::swap(_head, lt._head);std::swap(_size, lt._size);}// 对首尾元素的访问T& back() { return *(--end()); }const T& back()const { return *(--end()); }T& front() { return *begin(); }const T& front()const { return *begin(); }// 在迭代器 start 与 finish 构成的范围内查找值为 target 的节点iterator find(const iterator& start, const iterator& finish, const T& target) {for (iterator it = start;it != finish;++it) {if (*it == target) return it;}return finish;}public://构造list() { initialize(); }list(size_t n, const T& data = T()) {initialize();while (n--) { push_back(data); }}list(int n, const T& data = T()) {initialize();while (n--) { push_back(data); }}template<class input_iterator> /*使用迭代器构造*/list(input_iterator begin, input_iterator end) {initialize();while (begin != end) {push_back(*(begin++));}}//拷贝list(const list& lt) {initialize();for (const auto& data : lt) {push_back(data);}}self& operator=(list lt) {swap(lt);return *this;}//析构~list() {clear();delete _head;_head = nullptr;_size = 0;}public://增void push_front(const T& data) { insert(begin(), data); } // 头插新节点void push_back(const T& data) { insert(end(), data); } // 尾插新节点// 在 pos 位置的前面插入一个值为 data 的新节点, 返回新插入的节点的迭代器iterator insert(iterator pos,const T& data) {Node* node = pos._node;Node* newNode = new Node(data);newNode->next = node;newNode->pre = node->pre;node->pre->next = newNode;node->pre = newNode;++_size;return newNode;}//删void pop_front() { erase(begin()); } // 头删void pop_back() { erase(--end()); } // 尾删// 删掉迭代器 pos 所指向的节点, 返回删掉的节点的位置的新节点迭代器iterator erase(iterator pos) {assert(pos != end());Node* tmp = pos._node;tmp->pre->next = tmp->next;tmp->next->pre = tmp->pre;Node* res = tmp->next;delete tmp;--_size;return res;}public://C++ 11 //initializer_list构造list(const std::initializer_list<T>& lt) {initialize();for (const T& data : lt) {push_back(data);}}//右值引用相关//移动构造与移动赋值list(list&& lt) :_head(lt._head), _size(lt._size) {initialize();lt._head = nullptr;lt._size = 0;}self& operator=(list&& lt) {delete *this;std::swap(_head, lt._head);std::swap(_size, lt._size);}//插入void push_front(T&& data) { insert(begin(), std::forward<T>(data)); }void push_back(T&& data) { insert(end(), std::forward<T>(data)); }iterator insert(iterator pos, T&& data) {Node* node = pos._node;Node* newNode = new Node(std::forward<T>(data));newNode->next = node;newNode->pre = node->pre;node->pre->next = newNode;node->pre = newNode;++_size;return newNode;}};}
二,queue
queue 是一种先进先出(First In First Out,FIFO)的数据结构,它有两个出口。queue 允许新增元素、移除元素、从最底端加人元素取得最顶端元素。但除了最底端可以加入、最顶端可以取出外,没有任何其它方法可以存取 queue 的其它元素。也就是说,queue 不允许有遍历行为。将元素推人queue 的操作称为 push,将元素推出 queue 的操作称为 pop。
queue 与 stack 一样,都是容器适配器(container adapters),他们的底层都是其他的容器,STL 中的 stack 与 queue 实际上都是对其他容器的封装,其都不支持迭代器。
我们可以选择用 list 也可以选择用 deque 来当作 queue 的底层容器。
namespace mySTL {template<class T, class Container = list<T>>class queue {private:Container _cont; // 底层使用的容器public:void push(const T& data) { _cont.push_back(data); }void push(T&& data) { _cont.push_back(std::forward<T>(data)); }void pop() { _cont.pop_front(); }T& back() { return _cont.back(); }const T& back()const { return _cont.back(); }T& front() { return _cont.front(); }const T& front()const { return _cont.front(); }size_t size() { return _cont.size(); }bool empty() { return _cont.empty(); }};}