overview
List Container Framework
List simulation implementation
ListNode node class
MyList structure
No parameter construction
List iterator
Complete MyList class definition
Insert to insert data
Erase delete data
Push to insert data
Pop delete data
other functions
ClearClear data
destructor
Test code MyList.cpp
Complete code MyList.hpp
Overview
Learned from the blogger: (84 messages) [C + +] teach you how to write your own list class_Ornamrr’s Blog-CSDN Blog
List container frame
The underlying data structure of the List container is actually a leading two-way circular linked list. The frame structure is shown in the figure:
List simulation implementation
ListNode node class
In the underlying structure, the node is the basic unit, first we need to define the template of the node class:
node template template<class T> class ListNode { public: ListNode<T>* _prev; T_val; ListNode<T>* _next; ListNode(const T & val) : _prev(nullptr), _val(val), _next(nullptr){} };
MyList structure
After defining the node class, we need to clarify the implementation logic of the List container: the List container mainly maintains a head node pointer to access the entire linked list:
No parameter construction
From the above structure, the MyList class can be designed and initialized:
///The implementation of the list template class maintains a head node pointer, and the head is only used for connection and does not store data template<class T> class MyList { typedef ListNode<T> Node; private: Node* _head; public: // no parameter construction MyList() {//leading node, not practical _head = new Node(0); _head->_next = _head; _head->_prev = _head; } }
List Iterator
In the standard template library STL, each container has its unique iterator, and the iterator of the List container is essentially a node pointer, and because the List iterator is more complicated than the vector container , it is encapsulated here, and the operators that may be used are overloaded:
The definition of
/list iterator is not just a simple type pointer, its next position is _next template<class T> struct _list_iterator//parameter template Ref, pointer template Ptr { typedef _list_iterator<T> self; typedef ListNode<T> Node; Node* _node; \t//Constructor _list_iterator(Node* node) :_node(node) {} //overload dereference T operator*() { return _node->_val; } // Overload ++ and -- self operator + + () { this->_node = this->_node->_next; return *this; } self operator--() { this->_node = this->_node->_prev; return *this; } // Overload == and ! = bool operator==(const self & amp; it) const { return _node == it._node; } bool operator!=(const self & amp; it) const { return _node != it._node; } };
Complete MyList class definition
///The implementation of the list template class maintains a head node pointer, and the head is only used for connection and does not store data template<class T> class MyList { typedef ListNode<T> Node; typedef _list_iterator<T> list_iterator; private: Node* _head; public: // no parameter construction MyList() {//leading node, not practical _head = new Node(0); _head->_next = _head; _head->_prev = _head; } // copy construction MyList(MyList<T> & Lt) { _head = new Node(0); _head->_next = _head; _head->_prev = _head; Node* cur = Lt._head->_next; while (cur != Lt._head) { this->push_back(cur->_val); cur = cur->_next; } } // overload assignment MyList<T> & amp; operator=(MyList<T> & amp; Lt) { this->_head = Lt._head; return *this; } \t //member function void push_back(T val); void push_front(T val); void pop_back(); void pop_front(); void insert(list_iterator pos, T val); void erase(list_iterator pos); int size(); bool empty(); T front();//Get the head element T back();//Get the tail element void clear();//Clear all nodes except the head node //Simulation of iterator iterator head and tail iterator list_iterator begin() {//Insert the node at the previous position insert header and tail insert return _head->_next;//The actual head position } list_iterator end() { return _head;//The next position of the tail is the head } //destructor ~MyList() { this->clear();//Release other nodes delete _head;//Release the head node _head = NULL; } };
Insert insert data
The insertion here is to insert the node at the previous position of pos position, head insertion and tail insertion are also applicable, and the operation logic is as shown in the figure:
template<class T> void MyList<T>::insert(list_iterator pos, T val) { Node* prev = pos._node->_prev; Node* new_node = new Node(val); prev->_next = new_node; new_node->_prev = prev; new_node->_next = pos._node; pos._node->_prev = new_node; }
Erase delete data
Note the position of the head node:
template<class T> void MyList<T>::erase(list_iterator pos) { if (_head->_next == _head) { cout << "The deletion has been completed and cannot be deleted again!!" << endl; return; } if (pos._node == _head) {//Prevent deleting the head Node* prev = pos._node->_prev; Node* pprev = prev->_prev; pprev->_next = _head; _head->_prev = pprev; return; } Node* prev = pos._node->_prev; Node* next = pos._node->_next; prev->_next = next; next->_prev = prev; delete pos._node; }
Push insert data
It can be realized by analysis, or directly by using Insert:
template<class T> void MyList<T>::push_back(T val) { //Node* tail = _head->_prev; //Node* new_node = new Node(val); //tail->_next = new_node; //new_node->_prev = tail; //new_node->_next = _head; //_head->_prev = new_node; this->insert(this->end(), val); } template<class T> void MyList<T>::push_front(T val) { //Node* next = _head->_next; //Node* new_node = new Node(val); //new_node->_next = next; //next->_prev = new_node; //new_node->_prev = _head; //_head->_next = new_node; this->insert(this->begin(), val); }
Pop delete data
It can be achieved by analysis, or directly by using Erase:
template<class T> void MyList<T>::pop_back() { /*if (_head->_next == _head) { cout << "The deletion has been completed and cannot be deleted again!!" << endl; return; } Node* tail = _head->_prev; Node* tailprev = tail->_prev; delete tail; tail = NULL; tailprev->_next = _head; _head->_prev = tailprev;*/ this->erase(this->end()); } template<class T> void MyList<T>::pop_front() { /*if (_head->_next == _head) { cout << "The deletion has been completed and cannot be deleted again!!" << endl; return; } Node* front = _head->_next; Node* next = front->_next; delete front; _head->_next = next; next->_prev = _head;*/ this->erase(this->begin()); }
Other functions
template<class T> int MyList<T>::size() { int count = 0; Node* cur = _head->_next; while (cur != _head) { count + + ; cur = cur->_next; } return count; } template<class T> bool MyList<T>::empty() { return this->size() == 0; } template<class T> T MyList<T>::front() { return _head->_next->_val; } template<class T> T MyList<T>::back() { return _head->_prev->_val; }
Clear clear data
Clear data, freeing all nodes except the head node:
template<class T> void MyList<T>::clear() { //Release all nodes except the head node while (_head->_next != _head) { this->erase(this->begin()); } }
Destructor
Release all nodes:
//destructor template<class T> MyList<T>::~MyList() { this->clear();//Release other nodes delete _head;//Release the head node _head = NULL; }
Test code MyList.cpp
#define _CRT_SECURE_NO_WARNINGS 1 #include "MyList.hpp" int main() { MyList<int> lt;//No parameter construction lt.push_back(1);//tail plug lt. push_back(2); lt.push_back(3); lt. push_back(4); lt. push_back(5); lt.push_front(6);//head plug lt.push_front(7); lt.push_front(8); lt.pop_back();//tail deletion lt. pop_back(); lt.pop_front();//head delete lt. pop_front(); MyList<int> lt1(lt);//copy construction MyList<int> lt2 = lt;//Assignment operation lt.insert(lt.begin(), 9);//insert test lt.insert(lt.end(), 10); cout << "size = " << lt. size() << endl; cout << "front = " << lt. front() << endl; cout << "back = " << lt.back() << endl; cout << "empty = " << lt.empty() << endl; for (_list_iterator<int> it = lt.begin(); it != lt.end(); + + it) { cout << *it << " "; } cout << endl; cout << endl; lt.erase(lt.begin());//delete test lt.erase(lt.end()); lt.clear();//clear test cout << "After cleaning: " << endl; cout << "empty = " << lt.empty() << endl; return 0; }
Complete code MyList.hpp
#pragma once #includeusing namespace std; //The use of class templates requires the function declaration and implementation to be written in a file, //And the file suffix is changed to .hpp, and the header file is included when used. /C ++ implements list with a headed doubly linked list node template template class ListNode { public: ListNode * _prev; T_val; ListNode * _next; ListNode(const T & val) : _prev(nullptr), _val(val), _next(nullptr){} }; The definition of /list iterator is not just a simple type pointer, its next position is _next template<class T> struct _list_iterator//parameter template Ref, pointer template Ptr { typedef _list_iterator<T> self; typedef ListNode<T> Node; Node* _node; \t//Constructor _list_iterator(Node* node) :_node(node) {} //overload dereference T operator*() { return _node->_val; } // Overload ++ and -- self operator + + () { this->_node = this->_node->_next; return *this; } self operator--() { this->_node = this->_node->_prev; return *this; } // Overload == and ! = bool operator==(const self & amp; it) const { return _node == it._node; } bool operator!=(const self & amp; it) const { return _node != it._node; } }; ///The implementation of the list template class maintains a head node pointer, and the head is only used for connection and does not store data template<class T> class MyList { typedef ListNode<T> Node; typedef _list_iterator<T> list_iterator; private: Node* _head; public: // no parameter construction MyList() {//leading node, not practical _head = new Node(0); _head->_next = _head; _head->_prev = _head; } // copy construction MyList(MyList<T> & Lt) { _head = new Node(0); _head->_next = _head; _head->_prev = _head; Node* cur = Lt._head->_next; while (cur != Lt._head) { this->push_back(cur->_val); cur = cur->_next; } } // overload assignment MyList<T> & amp; operator=(MyList<T> & amp; Lt) { this->_head = Lt._head; return *this; } \t //member function void push_back(T val); void push_front(T val); void pop_back(); void pop_front(); void insert(list_iterator pos, T val); void erase(list_iterator pos); int size(); bool empty(); T front();//Get the head element T back();//Get the tail element void clear();//Clear all nodes except the head node //Simulation of iterator iterator head and tail iterator list_iterator begin() {//Insert the node at the previous position insert header and tail insert return _head->_next;//The actual head position } list_iterator end() { return _head;//The next position of the tail is the head } //destructor ~MyList() { this->clear();//Release other nodes delete _head;//Release the head node _head = NULL; } }; template<class T> void MyList<T>::push_back(T val) { //Node* tail = _head->_prev; //Node* new_node = new Node(val); //tail->_next = new_node; //new_node->_prev = tail; //new_node->_next = _head; //_head->_prev = new_node; this->insert(this->end(), val); } template<class T> void MyList<T>::push_front(T val) { //Node* next = _head->_next; //Node* new_node = new Node(val); //new_node->_next = next; //next->_prev = new_node; //new_node->_prev = _head; //_head->_next = new_node; this->insert(this->begin(), val); } template<class T> void MyList<T>::pop_back() { /*if (_head->_next == _head) { cout << "The deletion has been completed and cannot be deleted again!!" << endl; return; } Node* tail = _head->_prev; Node* tailprev = tail->_prev; delete tail; tail = NULL; tailprev->_next = _head; _head->_prev = tailprev;*/ this->erase(this->end()); } template<class T> void MyList<T>::pop_front() { /*if (_head->_next == _head) { cout << "The deletion has been completed and cannot be deleted again!!" << endl; return; } Node* front = _head->_next; Node* next = front->_next; delete front; _head->_next = next; next->_prev = _head;*/ this->erase(this->begin()); } template<class T> void MyList<T>::insert(list_iterator pos, T val) { Node* prev = pos._node->_prev; Node* new_node = new Node(val); prev->_next = new_node; new_node->_prev = prev; new_node->_next = pos._node; pos._node->_prev = new_node; } template<class T> void MyList<T>::erase(list_iterator pos) { if (_head->_next == _head) { cout << "The deletion has been completed and cannot be deleted again!!" << endl; return; } if (pos._node == _head) {//Prevent deleting the head Node* prev = pos._node->_prev; Node* pprev = prev->_prev; pprev->_next = _head; _head->_prev = pprev; return; } Node* prev = pos._node->_prev; Node* next = pos._node->_next; prev->_next = next; next->_prev = prev; delete pos._node; } template<class T> int MyList<T>::size() { int count = 0; Node* cur = _head->_next; while (cur != _head) { count + + ; cur = cur->_next; } return count; } template<class T> bool MyList<T>::empty() { return this->size() == 0; } template<class T> T MyList<T>::front() { return _head->_next->_val; } template<class T> T MyList<T>::back() { return _head->_prev->_val; } template<class T> void MyList<T>::clear() { //Release all nodes except the head node while (_head->_next != _head) { this->erase(this->begin()); } }