[C + + primary] List bottom framework Simulation Implementation

Posted by marcela1637 on Sun, 21 Nov 2021 21:02:29 +0100

1, List frame construction

1. Introduction

  1. list is a sequential container that can be inserted and deleted at any position within the constant range, and the container can iterate back and forth.
  2. The bottom layer of list is the leading two-way linked list structure. Each element in the two-way linked list is stored in independent nodes that are not related to each other. In the node, the pointer points to its previous element and the latter element. And forward_list is a single linked list and can only iterate forward
  3. Compared with other sequential containers (array, vector, deque), list usually inserts and removes elements at any position, which is efficient.
  4. Compared with other sequential containers, list and forward_ The biggest drawback of the list is that it does not support random access to any location. For example, to access an element in the middle, it needs to iterate from the head or unknown to that location. The time complexity is O(N). The list also needs some additional space to save the associated information of each node (this may be an important factor for a large list with small storage types)

2. Use of list

3. List structure

3.1 construct an empty list

list(){
    //Lead two-way cycle
    _head = new Node(T()); //The construction here cannot pass 0, so it is not necessarily of type int. here T may be a vector or a string object
    _head->_next = _head;
    _head->_prev = _head;
}

3.2 copy structure

list(const list<T>& lt){
    //Deep copy
    _head = new Node;
    _head->_next = _head;
    _head->_prev = _head;
    for(const auto& e : lt){
        push_back(e);
    }
}

3.3 constructing a list with interval elements

template<class InputIterator>
list(InputIterator first,InputIterator last){ //This supports not only the initialization of linked lists, but also the iterators of string s or vector s
    _head = new Node;
    _head->_next = _head;
    _head->_prev = _head;
    while(first != last){
        push_back(*first);
        ++first;
    }
}

4. List node

template<class T>
struct __list_node{
    __list_node<T>* _next;
    __list_node<T>* _prev;
    T _data;
    
    __list_node(const T& x = T()) //Initialize an anonymous object
        :_next(nullptr)
        , _prev(nullptr)
        ,_data(x)
    {}
    };

5. Iterator framework implementation

Iterator for List
Iterators can be implemented in two ways, which should be implemented according to the underlying data structure of the container:

  1. Original ecological pointer, such as vector
  2. Encapsulate the original pointer. Because the use form of iterator is exactly the same as that of pointer, the following must be implemented in the custom class

method:

  1. The pointer can be dereferenced, and the iterator class must be overloaded with operator * ()
  2. The pointer can access the space member it refers to through - > and the iterator class must be overloaded with oprator - > ()
  3. The pointer can move backwards in + +, and the iterator class must overload operator + + () and operator++(int)
    As for the operator – () / operator – (int) release, it needs to be overloaded. It depends on the specific structure. The two-way linked list can move forward, so it needs to be overloaded. If it is forward_list does not need to be overloaded –
  4. The iterator needs to compare whether it is equal, so it also needs to overload operator = = () and operator= ()

Here typdef's__ list_ The iterator takes three parameters. The second and third class templates are used to determine what type of object operator * () returns and operator - > () returns the data of the current node, respectively

template<class T>
    class list
    {
        typedef __list_node<T> Node;
    public:
        typedef __list_iterator<T, T&, T*> iterator;
        typedef __list_iterator<T, const T&, const T*> const_iterator;
        
        iterator begin(){
            return iterator(_head->_next);
        }
        
        iterator end(){
            return iterator(_head);
        }
        
        const_iterator begin() const{
            return const_iterator(_head->_next);
        }
        
        
        const_iterator end() const {
            return const_iterator(_head);
        }
        
	private:
	   Node* _head;
 };

6. Assignment overload

//Dereference
Ref operator*(){
    return _node->_data;
}
    
Ptr operator->(){
    return &_node->_data;
}
    
// ++it
self& operator++(){
    _node = _node->_next;
    return *this;
}
    
// it++
self operator++(int){ //Post++
    self tmp(*this);
    _node = _node->_next;
    return tmp;
}
    
// --it
self& operator--(){
    _node = _node->_prev;
    return *this;
}
    
// it--
self operator--(int){ //Post--
    self tmp(*this);
    _node = _node->_prev;
    return tmp;
}

//Compare for equality
bool operator!=(const self& it){
    return _node != it._node;
}
    
bool operator==(const self& it){
    return _node == it._node;
}

7. About the capacity of the List

Go through it until you meet the leader

size_t size(){
    size_t n = 0;
    iterator it = begin();
    while(it != end()){
        ++it;
        ++n;
    }
    return n;
}
        
bool empty(){
    return begin() == end();
}

8. Add a new node to the list

iterator insert(iterator pos, const T& x){
    Node* cur = pos._node; //Current node
    Node* prev = cur->_prev;
    
    Node* newnode = new Node(x);
    prev->_next = newnode;
    newnode->_prev = prev;
    
    newnode->_next = cur;
    cur->_prev = newnode;
    
    return iterator(newnode); //Reverses the newly inserted node
}

void push_back(const T& x){
	insert(end(), x)
}

void push_front(const T& x){
    insert(begin(), x);
}

9. Delete a node

Because of the characteristics of list data structure, O(1) can not access any node like array, so only header deletion and tail deletion are provided in the standard library

iterator erase(iterator pos){
    assert(pos != end());
    
    Node* cur = pos._node;
    Node* pre = cur->_prev;
    Node* next = cur->_next;
    
    delete cur;
    pre->_next = next;
    next->_prev = prev;
    
    return iterator(next);
}

void pop_back(){
    erase(--end());
}

void pop_front(){
    erase(begin());
}

10. Empty the linked list and destruct

It should be noted here that destruct only after the instantiated object has opened up space, otherwise an error will be reported after entering the clear function

void clear(){
	iterator it = begin();
	while(it != end()){
	it = erase(it);
}
~list(){
    clear();
    delete _head;
    _head = nullptr;
}

2, Complete code

Gitee link 🔗 🔗 🔗

👉 👉 👉 List simulation 👈 👈 👈

It's not easy to create. If the article helps you, please like it for three times:)

Topics: C++ Algorithm data structure