双链表迭代器实现方法

时间:2015-05-22 15:19:37

标签: c++ visual-studio iterator doubly-linked-list

我已经用迭代器(常规和常量)实现了一个双向链表,看起来工作正常,但我无法理解几件事:

1)据我所知,实现迭代器的方法之一是继承std::iterator< ... >在模板参数中提及所有必需的类型,然后在类中键入它们...但为什么我们需要difference_type两个迭代器?双向迭代器不能在内部重载operator - ()所以可以不删除差异类型吗?

2)我知道它不是复制类似事物逻辑的最佳方法(在我的情况下,常规迭代器和const_iterator是两个不同的类)但是那是我现在做的,因为我对c ++模板的基本知识。我将const_iterator作为iterator的朋友,并使用特殊构造函数Tconst T(节点值类型)到const_iterator(iterator &other)进行了隐式转换,因此在返回引用时来自operator *()它和operator->()的指针会自动将内部ptr->_node_value(列表节点数据)转换为const版本。这种方法还不错吗?

template <typename T>
struct DLList_node
{
    T _node_value;
    DLList_node<T> *_next, *_prev;
    DLList_node<T>(const T& = T(), DLList_node<T> * = NULL, DLList_node<T> * = NULL);   
};

template <typename T>
class DLList;

//non-const regular iterator
template<typename T>
class DLList_iterator;

//const iterator
template<typename T>
class DLList_const_iterator;

template<typename T>
class DLList_iterator :
    public std::iterator< std::bidirectional_iterator_tag, T, T*, T& >
{
    public:
        friend class DLList<T>;
        //const iterator must have access to node pointer
        friend class DLList_const_iterator<T>;  
        typedef T                               value_type;
        typedef ptrdiff_t                       difference_type;
        typedef T*                              pointer;
        typedef T&                              reference;
        typedef std::bidirectional_iterator_tag iterator_category;
        typedef DLList_node<T>*                 node_ptr;           

        DLList_iterator()
        : ptr(NULL)
        {}

        DLList_iterator(node_ptr _ptr): ptr(_ptr)
        {}

        reference operator*() const
        {
            assert(ptr != NULL && "list iterator not dereferencable!");
            return ptr->_node_value;
        }

        pointer operator->() const
        {
            assert(ptr != NULL && "list iterator not dereferencable!");
            return &(ptr->_node_value);
        }

        bool operator == (const DLList_iterator& other) const
        {
            return ptr == other.ptr;
        }

        bool operator != (const DLList_iterator& other) const
        {
            return ptr != other.ptr;
        }

        //pre incerement
        DLList_iterator& operator++()
        {
            assert(ptr != NULL && "list iterator not incrementable!");
            ptr = ptr->_next;
            return *this;
        }

        //post increment
        DLList_iterator operator++(int) 
        {
            assert(ptr != NULL && "list iterator not incrementable!");
            DLList_iterator tmp(*this);
            ptr = ptr->_next;
            return tmp; 
        }

        DLList_iterator& operator--() 
        {
            assert(ptr != NULL && "list iterator not decrementable!");
            ptr = ptr->_prev;
            return *this;
        }

        DLList_iterator operator--(int) 
        {
            assert(ptr != NULL && "list iterator not decrementable!");
            DLList_iterator tmp(*this);
            ptr = ptr->_prev;
            return tmp; 
        }

    private:
        node_ptr ptr;
};


//const iterator
template<typename T>
class DLList_const_iterator :
    public std::iterator< std::bidirectional_iterator_tag, const T, const T*, const T& >
{
    public:
        friend class DLList<T>; 
        typedef const T                         value_type;
        typedef ptrdiff_t                       difference_type;
        typedef const T*                        const_pointer;
        typedef const T&                        const_reference;
        typedef std::bidirectional_iterator_tag iterator_category;      
        typedef DLList_node<T>*                 node_ptr;   

        DLList_const_iterator()
        : cptr(NULL)
        {}

        DLList_const_iterator(DLList_iterator<T>& _iter): cptr(_iter.ptr)
        {}

        DLList_const_iterator(node_ptr _ptr): cptr(_ptr)
        {}

        const_reference operator*() const
        {
            assert(cptr != NULL && "list iterator not dereferencable!");
            return cptr->_node_value;
        }

        const_pointer operator->() const
        {
            assert(cptr != NULL && "list iterator not dereferencable!");
            return &(cptr->_node_value);
        }

        bool operator == (const DLList_const_iterator & other) const
        {
            return cptr == other.cptr;
        }

        bool operator != (const DLList_const_iterator & other) const
        {
            return cptr != other.cptr;
        }

        //pre incerement
        DLList_const_iterator & operator++()
        {
            assert(cptr != NULL && "list iterator not incrementable!");
            cptr = cptr->_next;
            return *this;
        }

        //post increment
        DLList_const_iterator operator++(int) 
        {
            assert(cptr != NULL && "list iterator not incrementable!");
            DLList_const_iterator tmp(*this);
            cptr = cptr->_next;
            return tmp; 
        }

        DLList_const_iterator & operator--() 
        {
            assert(cptr != NULL && "list iterator not decrementable!");
            cptr = cptr->_prev;
            return *this;
        }

        DLList_const_iterator operator--(int) 
        {
            assert(cptr != NULL && "list iterator not decrementable!");
            DLList_iterator tmp(*this);
            cptr = cptr->_prev;
            return tmp; 
        }       

    private:
        node_ptr cptr;
};

template <typename T>
class DLList
{
    private:
         node_ptr _begin, _tail;
    public:
        typedef DLList_iterator<T> iterator;
        typedef DLList_const_iterator<T> const_iterator;
        typedef DLList_node<T>* node_ptr;           
        typedef DLList_node<T> node;

        typedef typename DLList_iterator<T>::value_type         value_type;
        typedef typename DLList_iterator<T>::difference_type    difference_type;
        typedef typename DLList_iterator<T>::pointer            pointer;
        typedef typename DLList_iterator<T>::reference          reference;

        typedef typename DLList_const_iterator<T>::const_pointer    const_pointer;
        typedef typename DLList_const_iterator<T>::const_reference  const_reference;

    //member functions and constructors here        
    //...
};

1 个答案:

答案 0 :(得分:0)

  

1)据我所知,实现迭代器的方法之一是继承自std :: iterator&lt; ...&gt;在模板参数中提到所有必要的类型,

  

然后在你的班级中输入它们......

没有。这就是你继承std::iterator的原因,所以你不必费心去做。

  

但为什么我们需要两个迭代器的difference_type?

请注意,std::iterator默认大多数标准类型。如果您正在做一些时髦且没有标准的事情,您只需要指定差异类型。

  

双向迭代器不能重载operator - (),所以可以不删除差异类型吗?

您不需要提及任何类型。 std::iterator可以帮助您完成所有工作。

  

2)我知道它不是复制类似事物逻辑的最佳方法(在我的情况下,常规迭代器和const_iterator是两个不同的类)但是那是我现在做的,因为我对c ++模板的基本知识。

除了检索上的一些差异之外,看看你的课程基本相同。为什么不将所有相同的代码移动到基类中。

template<typename T>
class DLList_Base_iterator :
    public std::iterator< std::bidirectional_iterator_tag, T, T*, T& >
{
      // Common code
      protected:  // allow all concrete iterators to see pointer.
          node_ptr ptr;
};
template<typename T>
class DLList_iterator : public DLList_Base_iterator<T>
{
    DLList_iterator():              public DLList_Base_iterator<T>(NULL) {}
    DLList_iterator(node_ptr _ptr): public DLList_Base_iterator<T>(_ptr) {}

    reference operator*()        const  {return cptr->_node_value;}
    pointer   operator->()       const  {return &(cptr->_node_value);}
};
template<typename T>
class DLList_const_iterator : public DLList_Base_iterator<T>
{
    DLList_const_iterator():              public DLList_Base_iterator<T>(NULL) {}
    DLList_const_iterator(node_ptr _ptr): public DLList_Base_iterator<T>(_ptr) {}
    const_reference operator*()  const {return cptr->_node_value;}
    const_pointer   operator->() const {return &(cptr->_node_value);}
};
  

我使const_iterator成为迭代器的朋友,并使用特殊的构造函数const_iterator(iterator&amp; other)从T(节点值类型)到const T进行隐式转换,所以当从operator *()返回引用和指针时,它和operator- &gt;()它自动将内部ptr-> _node_value(列表节点数据)转换为const版本。这种方法还不错吗?

我只想在非const迭代器中添加一个转换运算符,允许你将它转换为const版本。

template<typename T>
class DLList_iterator : public DLList_Base_iterator<T>
{
    operator DLList_const_iterator<T> {
        return DLList_const_iterator<T>(cptr);
    }
};