您的位置:首页 > 其它

模板类模拟实现List

2017-03-16 09:57 239 查看
  上一篇中我模拟实现了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;
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: