C++list类及常用接口实现

list

因为list时双向链表,其内部存的不只有数据,还有前后指针,直接解引用会出错
还有它的物理存储空间不是连续的,++,–操作是向前/后偏移一定的大小,而下一个紧挨的物理空间可能是没有申请的
所以将原生态指针进行封装,因迭代器使用形式与指针完全相同,因此在自定义的类中必须实现以下方法:

  1. 指针可以解引用,迭代器的类中必须重载operator * ()
  2. 指针可以通过->访问其所指空间成员,迭代器类中必须重载oprator->()
  3. 指针可以++向后移动,迭代器类中必须重载operator++()与operator++(int)
    至于operator–() / operator–(int)释放需要重载,根据具体的结构来抉择,双向链表可
    以向前 移动,所以需要重载,如果是forward_list就不需要重载–
  4. 迭代器需要进行是否相等的比较,因此还需要重载operator == ()与operator != ()
#include<iostream>
using namespace std;
//双向带头循环链表
template <class T>
struct ListNode
{
 T _value;
 ListNode<T>* _next;
 ListNode<T>* _prev;
 ListNode(const T& val = T())
  :_value(val)
  , _next(nullptr)
  , _prev(nullptr)
 {}
};


/*因为list时双向链表,其内部存的不只有数据,还有前后指针,直接解引用会出错
还有它的物理存储空间不是连续的,++,--操作是向前/后偏移一定的大小,而下一个紧挨的物理空间可能是没有申请的
所以将原生态指针进行封装,因迭代器使用形式与指针完全相同,因此在自定义的类中必须实现以下方法:
1. 指针可以解引用,迭代器的类中必须重载operator * ()
2. 指针可以通过->访问其所指空间成员,迭代器类中必须重载oprator->()
3. 指针可以++向后移动,迭代器类中必须重载operator++()与operator++(int)
至于operator--() / operator--(int)释放需要重载,根据具体的结构来抉择,双向链表可
以向前 移动,所以需要重载,如果是forward_list就不需要重载--
4. 迭代器需要进行是否相等的比较,因此还需要重载operator == ()与operator != ()*/

template <class T, class Ref, class Ptr>
struct ListIterator
{
 typedef ListNode<T> Node;
 typedef ListIterator<T, Ref, Ptr> Self;
 ListIterator(Node* node)
  :_node(node)
 {}
//解引用: *iterator --->  获取节点value
 Ref operator*()
 {
  return _node->_value;
 }
// 指针->成员,一般list元素为自定义类型时用
 Ptr operator->()
 {
  return &_node->_value;
 }
// ++: 移动到下一个元素的位置
 Self& operator++()
 {
  _node = _node->_next;
  return *this;
 }
Self& operator--()
 {
  _node = _node->_prev;
  return *this;
 }
bool operator!=(const Self& it)
 {
  return _node != it._node;
 }
bool operator==(const Self& it)
 {
  return _node != it._node;
 }
Node* _node;
};

template <class T>
class List
{
public:
 typedef ListNode<T> Node;
 typedef ListIterator<T, T&, T*> iterator;
 //不能通过添加const修饰符定义const迭代器
 typedef ListIterator<T, const T&, const T*> const_iterator;

 iterator begin() 
 {
  //第一个元素的位置
  return iterator(_header->_next);
 }
 
 iterator end()
 {
  //最后一个元素的下一个位置
  return iterator(_header);
 }
 
const_iterator begin() const
 {
  //第一个元素的位置
  return const_iterator(_header->_next);
 }
 
 const_iterator end() const
 {
  //最后一个元素的下一个位置
  return const_iterator(_header);
 }

//构造函数
 List()
  :_header(new Node)
 {
  //构建循环结构
  _header->_next = _header->_prev = _header;
 }

//插入函数insert
 void insert(iterator pos, const T& val)
 {
  Node* cur = new Node(val);
  //pos前插入
  Node* node = pos._node;
  Node* prev = node->_prev;
  prev->_next = cur;
  cur->_prev = prev;
  cur->_next = node;
  node->_prev = cur;
 }

//删除会导致迭代器失效
 //返回值: 被删除掉的元素的下一个元素位置
 iterator erase(iterator pos)
 {
  //不能删除头结点(_header)
  if (pos != end())
  {
   Node* node = pos._node;
   Node* prev = node->_prev;
   Node* next = node->_next;
   delete node;
   prev->_next = next;
   next->_prev = prev;
   return iterator(next);
  }
  return pos;
 }
 
void pushBack(const T& val)
 {
  insert(end(), val);
 }
 
 void pushFront(const T& val)
 {
  insert(begin(), val);
 }
 
 void popBack()
 {
  erase(--end());
 }
 
 void popFront()
 {
  erase(begin());
 }
 
//获得链表元素个数
 size_t size() const
 {
  size_t count = 0;
  for (const auto& e : *this)
   ++count;
  return count;
 }
 
//析构
 ~List()
 {
  if (_header)
  {
   clear();
   delete _header;
   _header = nullptr;
  }
 }

//清空所有非头结点函数
 void clear()
 {
  Node* cur = _header->_next;
  while (cur != _header)
  {
   Node* next = cur->_next;
   delete cur;
   cur = next;
  }
  //重新构建循环结构
  _header->_next = _header->_prev = _header;
 }

List(const List<T>& lst)
  :_header(new Node)
 {
  _header->_next = _header->_prev = _header;
  //深拷贝,插入元素
  for (const auto& e : lst)
   pushBack(e);
 }
 
 //现代写法
 List<T>& operator=(List<T> lst)
 {
  swap(_header, lst._header);
  return *this;
 }
private:
 Node* _header;
};




//范围for遍历链表元素
template <class T>
void printListFor(const List<T>& lst)
{
 for (const auto& e : lst)
 {
  cout << e << " ";
 }
 cout << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值