模板类模拟实现List

  上一篇中我模拟实现了vector,接着这个当然就是list了,首先对于list,在库函数里面,list是一个双向的,即既含有next域,也含有prev域,每个节点都含有这样的结构,我们在写的时候要把一个一个链接上,而且要保证逻辑正确,作者本人就在拷贝构造函数的时候懵逼了半天。所以一个表示节点的结构体必须有,这个当然也可以用类,但是你会感觉本质上你还是用类中结构体的性质,所以还是结构体方便一点。
  

template<class T>
struct ListNode
{
    ListNode(const T& x = T())      //构造函数,给_prev,_next,_value初始化
    : _prev(0)
    , _next(0)
    , _value(x)
    { }

    ListNode<T>* _prev;
    ListNode<T>* _next;
    T _value;
};

  这个想必大家都很熟悉,所以我就不多说了,然后为了更好、更快捷、明了的表示一个节点,或者是对这个节点做一些操作,我们最好在封装一个类,确实,我是按库里面写的,库里也包含了这个类,采用了迭代器的用法,目前,我们只当迭代器是一个指针,这样才能更直观的理解我们现在的用法。

  和库里面一样,我也把很多类型名定义成自己顺手的自定义类型。

template<class T, class Ref, class Ptr>
struct __ListIterator__
{
    typedef __ListIterator__<T, T&, T*> Iterator;
    typedef __ListIterator__<const T, const T&, const T*> ConstItrator;
    typedef __ListIterator__<T, Ref, Ptr> Self;
    typedef T ValueType;
    typedef Ref Reference;
    typedef Ptr Pointer;
    typedef ListNode<T>*  LinkType;
    typedef size_t SizeType;

    LinkType _node;
public:
    __ListIterator__(LinkType x)
        :_node(x)
    { }

    __ListIterator__()
        :_node(0)
    { }

    __ListIterator__(const Iterator& x)
        :_node(x._node)
    { }

    bool operator==(const Iterator& x)
    {
        return x._node == _node;
    }

    bool operator!=(const Iterator& x)
    {
        return x._node != _node;
    }

    Reference operator*()
    {
        return _node->_value;
    }

    Pointer operator->()
    {
        return &(*(_node->_value));
    }

    Self& operator++()
    {
        _node = _node->_next;
        return *this;
    }

    Self operator++(int)
    {
        Self temp(*this);
        _node = _node->_next;
        return temp;
    }

    Self& operator--()
    {
        _node = _node->_prev;
        return *this;
    }

    Self operator--(int)
    {
        Self temp(*this);
        _node = _node->_prev;
        return temp;
    }
};

  最后就该到list的模板类了,这才是重中之重,我也是到这里迷失了一段时间,一个函数改了好久,几近崩溃(小白吐槽而已)。不说了,对这代码再给你说说我的逻辑。


template<class T>
class List
{
public:
    typedef ListNode<T> Node;
    typedef T ValueType;
    typedef ValueType* Pointer;
    typedef const ValueType* ConstPointer;
    typedef ValueType& Reference;
    typedef const ValueType& ConstReference;
    typedef Node* LinkType;
    typedef size_t SizeType;
    typedef __ListIterator__<T, T&, T*> Iterator;
    typedef __ListIterator__<const T, const T&, const T*> ConstIterator;

   //无参的构造函数,当然一进去就要先开辟好空间
   //等着其他的函数什么调用的时候有插入、删除的空间
   //并且要构成一个环,

   这里写图片描述
  

    List<T>()
    {
       _node = new Node;
        _node->_next = _node;
        _node->_prev = _node;
        _node->_value = 0;
    }

  这个函数让我很是尴尬,我的思维逻辑很清晰,在这个函数出错的时候,我还专门找人讨论我的逻辑,绝对没毛病,但是就是有问题,索性放着美观,过了一天,早上打开又理了一次,一次就出来了。所以我get到了一个技能,有时候,歇一歇,放松一下对自己也有帮助。

    List<T>(const List<T>& l)
    {
        _node = new Node;//给this的_node先开辟好空间
        LinkType MoveNode = _node;//然后新定义一个节点,表示尾节点
        LinkType srcNode = new Node;
        srcNode = l._node;//创建一个节点,表示被拷贝对象的头结点
        LinkType destNode = new Node;//创建新节点,用来储存拷贝节点的数据,再链接到尾节点上
        while (srcNode->_next != l._node)//当l的最后一个节点被拷贝完后,停止拷贝
        {
            destNode = new Node;//每次进去:开辟空间->储存数具->链接上尾节点

            MoveNode->_next = destNode;
            destNode->_prev = MoveNode;
            destNode->_next = _node;
            _node->_prev = destNode;

            srcNode = srcNode->_next;
            MoveNode = MoveNode->_next;
        }
    }

示意图:
插入一个节点
这里写图片描述
插入两个节点
这里写图片描述
以此类推,每次进来先和尾节点的next域相连,然后把新节点的prev域指向尾节点,还要记得的是,一定要和头结点相连,即上述操作完成之后,将新节点的next域指向头结点,将头结点的prev域指向尾节点,这样才是一个循环的双向链表,假如你本意不循环的话,让我没说,但是记得你的节点的netx域要指空。

赋值运算符的操作没啥说的,和拷贝构造的一样,多加个返回值而已,最起码这个函数是这样。逻辑都是一样的。


    List<T>& operator=(const List& l)
    {
        _node = new Node;
        LinkType MoveNode = _node;
        LinkType srcNode = new Node;
        srcNode = l._node;
        LinkType destNode = new Node;
        while (srcNode->_next != l._node)
        {
            destNode = new Node;
            destNode->_value = srcNode->_next->_value;
            MoveNode->_next = destNode;
            destNode->_prev = MoveNode;
            destNode->_next = _node;
            _node->_prev = destNode;
            srcNode = srcNode->_next;
            MoveNode = MoveNode->_next;
        }
        return *this;
    }

这里写代码片

    Iterator Insert(Iterator pos, const T& x)
    //插入函数,在pos位置的前面插入
    {
        LinkType temp = new Node(x);
        pos._node->_prev->_next = temp;
        temp->_prev = pos._node->_prev;
        temp->_next = pos._node;
        pos._node->_prev = temp;
        return temp;
    }

删除节点的图解:
这里写代码片

    Iterator Erase(const T& value)
    {
        Iterator pos = Find(value);
        Iterator temp = pos;
        temp++;
        pos._node->_prev->_next = pos._node->_next;
        pos._node->_next->_prev = pos._node->_prev;
        delete pos._node;
        return temp;
    }


    Iterator Begin()
    {
        return _node->_next;
    }

    ConstIterator Begin()const
    {
        return _node->_next;
    }

    Iterator End()
    {
        return _node;
    }

    ConstIterator End()const
    {
        return _node;
    }

    bool Empty()const
    {
        return Begin() == End();
    }

    SizeType Size()
    {
        SizeType size = 0;
        Iterator temp = Begin();
        while (temp._node != _node)
        {
            temp._node = temp._node->_next;
            size++;
        }
        return size;
    }

    Reference Front()
    {
        return _node->_next->_value;
    }

    ConstReference Front()const
    {
        return _node->_next->_value;
    }

    Reference Back()
    {
        return _node->_prev->_value;
    }

    ConstReference Back()const
    {
        return _node->_prev->_value;
    }

    void PushFront(const T& x)
    {
        Insert(Begin(), x);
    }

    void PushBack(const T& x)
    {
        Insert(End(), x);
    }


    void PopFront()
    {
        Delete(_node->_next);
    }

    void PopBack()
    {
        Delete(_node->_prev);
    }

    void Delete(Iterator pos)
    {
        Iterator temp = pos;
        temp._node->_prev->_next = temp._node->_next;
        temp._node->_next->_prev = temp._node->_prev;
        delete temp._node;

    }
    void Clear()
    {
        while (Begin() != End())
        {
            Delete(Begin());
        }
        _node->_next = _node;
        _node->_prev = _node;
        _node->_value = 0;
    }

    ~List()
    {
        Iterator temp;
        Clear();
    }

    friend ostream& operator<<(ostream& os, List<T>& L)
    {
        Iterator temp = L.Begin();
        Iterator END = L.End();
        while (temp._node != END._node)
        {
            cout << temp._node->_value << " ";
            temp._node = temp._node->_next;
        }
        return os;
    }

protected:
    Iterator Find(const T& value)
    {
        Iterator temp = _node;
        while (temp._node->_value != value)
        {
            temp._node = temp._node->_next;
        }
        return temp;
    }

private:
    LinkType _node;
};
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值