ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【C++ 初阶】List底层框架模拟实现

2021-11-21 23:05:17  阅读:129  来源: 互联网

标签:node head 初阶 iterator List list C++ next operator


目录

一、List框架搭建

1. List简介


  1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代
  2. list的底层是带头双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。而forward_list是单链表,只能朝前迭代
  3. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率高。
  4. 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,如访问中间的某个元素需要从头部或者未卜迭代到该位置,时间复杂度是O(N),list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)

2. List的使用

在这里插入图片描述

3. List构造

3.1 构造一个空的list

list(){
    //带头双向循环
    _head = new Node(T()); //这里的构造不能传0,因此这里不一定是int类型的,这里T可能是vector,也可能是string对象
    _head->_next = _head;
    _head->_prev = _head;
}

3.2 拷贝构造

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

3.3 用区间元素构造list

template<class InputIterator>
list(InputIterator first,InputIterator last){ //这里不仅仅支持链表的初始化,而且还支持string或者vector的迭代器
    _head = new Node;
    _head->_next = _head;
    _head->_prev = _head;
    while(first != last){
        push_back(*first);
        ++first;
    }
}

请添加图片描述

4. List节点

template<class T>
struct __list_node{
    __list_node<T>* _next;
    __list_node<T>* _prev;
    T _data;
    
    __list_node(const T& x = T()) //给个匿名对象去初始化
        :_next(nullptr)
        , _prev(nullptr)
        ,_data(x)
    {}
    };

5. 迭代器框架实现

List 的迭代器
迭代器有两种实现方式,具体应根据容器底层数据结构实现:

  1. 原生态指针,比如:vector
  2. 将原生态指针进行封装,因迭代器使用形式与指针完全相同,因此在自定义的类中必须实现以下

方法:

  1. 指针可以解引用,迭代器的类中必须重载operator*()
  2. 指针可以通过->访问其所指空间成员,迭代器类中必须重载oprator->()
  3. 指针可以++向后移动,迭代器类中必须重载operator++()与operator++(int)
    至于operator–()/operator–(int)释放需要重载,根据具体的结构来抉择,双向链表可以向前 移动,所以需要重载,如果是forward_list就不需要重载–
  4. 迭代器需要进行是否相等的比较,因此还需要重载operator==()与operator!=()

这里typdef的__list_iterator里带了三个参,其中第二和第三个类模版分别用于决定operator*()返回什么样类型的的对象 和 用于operator->()返回当前节点的数据

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. 赋值重载

//解引用
Ref operator*(){
    return _node->_data;
}
    
Ptr operator->(){
    return &_node->_data;
}
    
// ++it
self& operator++(){
    _node = _node->_next;
    return *this;
}
    
// it++
self operator++(int){ //后置++
    self tmp(*this);
    _node = _node->_next;
    return tmp;
}
    
// --it
self& operator--(){
    _node = _node->_prev;
    return *this;
}
    
// it--
self operator--(int){ //后置--
    self tmp(*this);
    _node = _node->_prev;
    return tmp;
}

//比较是否相等
bool operator!=(const self& it){
    return _node != it._node;
}
    
bool operator==(const self& it){
    return _node == it._node;
}

7. 关于List的容量

遍历一遍,直到遇到带头后结束

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

8. List添加新节点

iterator insert(iterator pos, const T& x){
    Node* cur = pos._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); //反回新插入节点
}

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

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

9. 删除一个节点

由于list数据结构的特点决定了不能像数组一样实现O(1)访问任意节点,所以标准库里只提供了头删和尾删

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. 清空链表和析构

这里需要注意的是只有当实例化对象开辟了空间后才析构,否则进入clear函数后会报错

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

二、完整代码

Gitee链接

标签:node,head,初阶,iterator,List,list,C++,next,operator
来源: https://blog.csdn.net/sinat_44182212/article/details/121362882

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有