0


【STL】容器 - list的模拟实现

一.框架

list: 带头双向循环链表

//节点类
template<class T>
struct __list_node
{
    T _val;
    __list_node* _next;
    __list_node* _prev;

    __list_node(const T& x = T())
        :_val(x), _next(nullptr), _prev(nullptr)
    {}
};

//iterator类
template<class T, class Ref, class Ptr>
struct __list_iterator
{
    typedef __list_node<T> node;
    typedef __list_iterator<T, Ref, Ptr> iterator;

    typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;
    typedef Reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;    

    //属性
    node* _node;

    __list_iterator(node* x);

    iterator operator++();
    iterator operator++(int);

    iterator operator--();
    iterator operator--(int);

    Ref operator*();

    Ptr operator->();

    bool operator!=(iterator it);    
    bool operator==(iterator it);
};
//list类
template<class T>
class list
{
public:
    //正向迭代器
    typedef __list_node<T> node;
    typedef __list_iterator<T, T&, T*> iterator;
    typedef __list_iterator<T, const T&, const T*> const_iterator;
    //反向迭代器        
    typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;
    typedef Reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;
        
    iterator begin();
    iterator end();

    const_iterator begin() const;
    const_iterator end() const;

    /
    //反向迭代器
    reverse_iterator rbegin();
    reverse_iterator rend();

    const_reverse_iterator rbegin() const;
    const_reverse_iterator rend() const

    void InitializeList();
    //构造
    list();
    list(int n, const T& value = T());
    template <class Iterator>
    list(Iterator first, Iterator last);
    list(const list<T>& l);
    list<T>& operator=(const list<T> l);
    
    //其余接口
    void swap(list<T>& l);
    bool empty();

    void push_back(const T& x);
    void pop_back();

    void push_front(const T& val);
    void pop_front();

    T& front();
    const T& front()const;

    T& back();
    const T& back()const;

    size_t size() const;

    iterator insert(iterator pos, const T& val);
    iterator erase(iterator pos);

    void clear();

    ~list();
private:
    node* _head;
};

二.list迭代器

1.list迭代器的特殊之处

在string和vector中, 迭代器是原生指针T*, 具体形式: typedef T* iterator

但在list中, 节点的存储是通过指针链接起来的, 底层内存存储空间并不连续, 无法对于节点的指针进行++或者--一系列的操作, 解决这一问题, 是实现list迭代器的关键

我们可以使用操作符重载将++重载成类似于node* cur, cur = cur->next, 针对于iterator的一整套操作符方法我们全部进行重载, 所以, 我们创建了一个iterator类模板, 每次通过调用list类中begin()/end()的方式构造这个类对象it

2.iterator类的代码实现

template<class T, class Ref, class Ptr>
struct __list_iterator
{
    typedef __list_node<T> node;
    typedef __list_iterator<T, Ref, Ptr> iterator;

    node* _node;

    __list_iterator(node* x)
    {
        _node = x;
    }
    
    //前置++
    iterator& operator++()
    {
        _node = _node->_next;
        return *this;
    }
    //后置++
    iterator operator++(int)
    {
        iterator tmp = *this;
        _node = _node->_next;
        return tmp;
    }
    //前置--
    iterator& operator--()
    {
        _node = _node->_prev;
        return *this;
    }
    //后置--
    iterator operator--(int)
    {
        iterator tmp = *this;
        _node = _node->_prev;
        return tmp;
    }
    //解引用
    Ref operator*()
    {
        return _node->_val;
    }
    //如果T是一个自定义类型可以通过it->的方式访问自定义类型成员
    //但实际是it->->, 编译器做了特殊处理, 自动省略掉一个->, 所以直接写it->即可
    //it->->的意思是: it.operator->()->, it.operator->()拿到一个指针(T*/const T*), 指针->是解引用
    Ptr operator->()
    {
        return &(operator*());
    }

    bool operator!=(iterator it)
    {
        return _node != it._node;
    }        
    bool operator==(iterator it)
    {
        return _node == it._node;
    }
};

//list类
template<class T>
class list
{
public:
    typedef __list_node<T> node;
    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;

3.const迭代器复用普通迭代器

为什么iterator这个类模板的模板参数是template<class T, class Ref, class Ptr>, 直接写一个class T不就可以了吗?Ref, Ptr是用来做什么的?

这块整体是一个复用的思想,** 让const_iterator(const迭代器)复用到iterator(普通迭代器)**

如果我要构造一个普通迭代器, 传入T, T&, T* 分别对应iterator类模板的模板参数T, Ref, Ptr

如果我要构造一个const迭代器, 传入T, const T&, T* 分别对应iterator类模板的模板参数T, Ref, Ptr

这样完美的让一份iterator类模板同时可以支持普通迭代器与const迭代器, 如果只写template<class T>, 还需要再实现一个const_iterator的类模板

三.反向迭代器

1.反向迭代器也称迭代器适配器(复用的思想)

反向迭代器是迭代器适配器

stack&&queue&&priority_queue是容器适配器, 在后面的篇章会详细讲解

反向迭代器的精髓就在于, 只需要实现一份reverse_iterator便可以适配出绝大多数的容器的反向迭代器

注意这里是绝大多数容器! 绝大多数可以定义为, 这些容器的迭代器需要支持++与--操作

换句话说, 只要是能够支持迭代器++与--的容器, 就可以使用反向迭代器reverse_iterator适配出该容器自己的反向迭代器

例如forward_list, unordered_map, unordered_set这三种容器便不支持反向迭代器, 也就是不能适配

2.反向迭代器的使用

list<int> l;
l.push_back(1);
l.push_back(2);
l.push_back(3);
l.push_back(4);
l.push_back(5);
list<int>::reverse_iterator it = l.rbegin();
while (it != l.rend())
{
    cout << *it << ' ';
    ++it;
}
cout << endl;

3.反向迭代器操作原理详解

反向迭代器, 从名字上来理解, 他其实就是一个反着的正向迭代器

list: 1,2,3,4,5

正向迭代器: [begin, end]

begin --> end, it++

结果: 1,2,3,4,5

反向迭代器: [rend, rbegin]

rbegin-> rend, it++

结果: 5,4,3,2,1

反向迭代器的++操作, 在底层上是正向迭代器的--操作

rbegin()的位置是原end()的位置

rend()的位置是原begin()的位置

reverse_iterator rbegin()的实现必须是要 return iterator(begin()) 以这种形式, 才可以适配多种容器让reverse_iteartor复用iterator, rend()同理

所以在解引用时, 如上图, 是一定要先拷贝一份后(*不能改变迭代器的位置), 先--再return的

4.反向迭代器的代码实现

//迭代器适配器, 复用思想
template<class Iterator, class Ref, class Ptr>
struct Reverse_iterator
{
    typedef Reverse_iterator<Iterator, Ref, Ptr> rIt;
    Iterator _it;
        
    //构造
    Reverse_iterator(Iterator it)
        :_it(it)//使用初始化列表, 如果不在这里定义的化需要在__list_iterator实现默认构造
    {}

    //其余接口
    //前置++
    rIt& operator++()
    {
        _it--;
        return *this;
    }
    //后置++
    rIt operator++(int)
    {
        rIt tmp(_it);
        _it--;
        return tmp;
    }
    //前置--
    rIt& operator--()
    {
        _it++;
        return *this;
    }
    //后置--
    rIt operator--(int)
    {
        rIt tmp(_it);
        _it++;
        return tmp;
    }
    //解引用
    Ref operator*()
    {
        Iterator tmp(_it);
        return *(--tmp);
    }
    //如果*_node是一个自定义类型可以通过it->的方式访问自定义类型成员
    //但实际是it->->, 编译器做了特殊处理, 自动省略掉一个->, 所以直接写it->即可
    //it->->的意思是: it.operator->()->, it.operator->()拿到一个指针(T*/const T*), 指针->是解引用
    Ptr operator->()
    {    
        //调用上面的operator*(), 底层逻辑又会去调用__list_iterator类中的operator*()
        //最终会拿到_node->_val
        //最后再取地址, 拿到_val的地址
        return &(operator*());
    }

    bool operator!=(rIt s)
    {
        return _it != s._it;
    }
    bool operator==(rIt s)
    {
        return _it == s._it;
    }
};

//list类
template<class T>
class list
{
public:
    typedef __list_node<T> node;
    typedef __list_iterator<T, T&, T*> iterator;
    typedef __list_iterator<T, const T&, const T*> const_iterator;
        
    typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;
    typedef Reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;

    //......
    //......

    /
    //反向迭代器
    reverse_iterator rbegin()
    {
        return reverse_iterator(end());
    }
    reverse_iterator rend()
    {
        return reverse_iterator(begin());
    }
    const_reverse_iterator rbegin() const
    {
        return const_reverse_iterator(end());
    }
    const_reverse_iterator rend() const
    {
        return const_reverse_iterator(begin());
    }

    //......
    //......
private:
    node* _head;

这里的const_reverse_iterator复用reverse_iterator与上面const_iterator复用iterator是一个道理滴!!!

5.迭代器的分类


单向迭代器(forward_iterator) 支持++

例如: forward_list, unordered_map, unordered_set


双向迭代器(bidirectional_iterator) 支持 ++ / --

例如: list, map, set


随机迭代器(random_access_iterator) 支持 ++ / -- / + / -

例如: vector, deque, string


随机迭代器是特殊的双向迭代器

可以说, 如果该容器可以适配反向迭代器, 那么该容器的迭代器就是双向迭代器


四.常用接口

以下涉及到的深拷贝与迭代器失效详解, 具体可以参考我之前写的vector模拟实现

详解入口: http://t.csdn.cn/B8cpI

1.构造函数

void InitializeList()
{
    _head = new node;
    _head->_next = _head;
    _head->_prev = _head;
}

list()
{
    InitializeList();
}

list(int n, const T& value = T())
{
    InitializeList();
    while (n--)
    {
        push_back(value);
    }
}

template <class Iterator>
list(Iterator first, Iterator last)
{
    InitializeList();
    while (first != last)
    {
        push_back(*first);
        ++first;
    }
}

list(const list<T>& l)
{
    InitializeList();
    list<T> tmp(l.begin(), l.end());
    swap(tmp);
}

2.insert与erase

在list中

insert不会发生迭代器失效

erase必定会发生迭代器失效

注意: stl中实现的insert插入之后, 返回的是插入的节点的迭代器, 返回值更新了原迭代器位置为新插入的

erase返回值是删除节点的下一个节点的迭代器

iterator insert(iterator pos, const T& val)
{
    node* cur = pos._node;
    node* newnode = new node(val);
    node* pprev = cur->_prev;
            
    pprev->_next = newnode;
    cur->_prev = newnode;
    newnode->_next = cur;
    newnode->_prev = pprev;

    return iterator(newnode);
}

iterator erase(iterator pos)
{
    node* cur = pos._node;
    node* pprev = cur->_prev;
    node* pnext = cur->_next;

    delete cur;
    cur = nullptr;

    pprev->_next = pnext;
    pnext->_prev = pprev;

    return iterator(pnext);
}

3.其余接口

list<T>& operator=(const list<T> l)
{
    list<T> tmp(l);
    swap(tmp);
    return *this;
}
        
void swap(list<T>& l)
{
    ::swap(_head, l._head);
}

bool empty()
{
    return _head->_next == _head;
}

void push_back(const T& x)
{
    //new节点
    node* newnode = new node(x);
    //尾插
    node* tail = _head->_prev;
    newnode->_next = _head;
    newnode->_prev = tail;
    tail->_next = newnode;
    _head->_prev = newnode;
}
void pop_back()
{
    node* tail = _head->_prev;
    node* tprev = tail->_prev;
    node* tnext = tail->_next;
    delete tail;
    tail = nullptr;
    tprev->_next = tnext;
    tnext->_prev = tprev;
}

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

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

T& front()
{
    return _head->_next->_val;
}        
const T& front()const
{
    return _head->_next->_val;
}
T& back()
{
    return _head->_prev->_val;
}
const T& back()const
{
    return _head->_prev->_val;
}

size_t size() const
{
    node* cur = _head;
    int count = 0;
    while (cur->_next != _head)
    {
        count++;
        cur = cur->_next;
    }
    return count;
}

//清理, 保留头节点
void clear()
{
    node* cur = _head->_next;
    while (cur != _head)
    {
        node* next = cur->_next;
        delete cur;
        cur = next;
    }
    _head->_next = _head;
    _head->_prev = _head;
}

//析构, 全部清理包括头节点在内
~list() 
{ 
    node* cur = _head->_next;
    while (cur != _head)
    {
        node* next = cur->_next;
        delete cur;
        cur = next;
    }
    delete _head;
    _head = nullptr;
}
标签: c++ list java

本文转载自: https://blog.csdn.net/Hello_World_213/article/details/127151383
版权归原作者 Hello_World_213 所有, 如有侵权,请联系我们删除。

“【STL】容器 - list的模拟实现”的评论:

还没有评论