STL容器的代码设计中,模板编程和代码复用的思想贯穿始终,代码复用可以将各个成员接口统一起来从而大大增加程序的可读性和可维护性,模板编程使得容器类可以根据需要用于存储各种不同类型的数据.
C++STL标准库中的list使用的数据结构是带头双向循环链表;
- 链表的头结点不用于存储有效数据
- 以图示中的方式设计出来的循环链表,在链表中的任意位置的插入和删除结点操作的代码逻辑都是一样的,而且无须区分空表和非空表的情形,代码实现起来非常方便
template<class DataType>
struct ListNode
{
ListNode(const DataType& val = DataType())
:_prev(nullptr)
,_next(nullptr)
,_data(val)
{}
ListNode<DataType>* _prev;
ListNode<DataType>* _next;
DataType _data;
};
STL容器的迭代器是用于访问容器中数据元素的工具,其本质上是将数据元素指针封装成类(或类模板),该类(或类模板)会对外提供成员接口(一般是运算符重载),使得迭代器对象可以像指向数组元素的普通指针一样被使用(通常支持++,- -,比较(= =,! =),解引用(*,->)等等操作)(于是遍历容器中数据元素的代码形式也变得和遍历数组元素的代码形式一致) ,从而实现容器元素遍历访问方式的高级抽象
template <class Datatype, class Ref, class Ptr>
class ListIterator
{
public:
//告诉编译器Ptr和Ref是类型名,而不是全局变量,为实现反向迭代器做准备
typedef Ref Ref;
typedef Ptr Ptr;
//简化迭代器命名,方便代码编写
typedef ListIterator<Datatype, Ref, Ptr> Self;
//在迭代器中实例化结点模板
typedef ListNode<Datatype> Node;
//构造函数
ListIterator(Node* ptr = nullptr)
{
_PtrNode = ptr;
}
//ListIterator(const Node* ptr)
//{
// _PtrNode = ptr;
//}
//重载*运算符,返回结点数据的引用
Ref operator*() const
{
return _PtrNode->_data;
}
//重载->,函数返回值是结点数据的地址
//当结点数据类型仍然为自定义结构时会用到,
Ptr operator->() const
{
return &(_PtrNode->_data);
}
//重载前置++,函数返回值是迭代器的自引用
Self& operator++()
{
_PtrNode = _PtrNode->_next;
return (*this);
}
//重载后置++,函数返回值是迭代器的自引用
Self operator++(int)
{
Self tem(*this);
_PtrNode = _PtrNode->next;
return tem;
}
//重载前置--,函数返回值是迭代器的自引用
Self& operator--()
{
_PtrNode = _PtrNode->_prev;
return (*this);
}
//重载后置--,函数返回值是迭代器的自引用
Self operator--(int)
{
Self tem(*this);
_PtrNode = _PtrNode->_prev;
return tem;
}
//重载比较运算符==
bool operator==(const Self It) const
{
return _PtrNode == It._PtrNode;
}
//重载比较运算符!=
bool operator!= (const Self It) const
{
return !((*this) == It);
}
//提供获取节点指针的接口
Node* GetPtr()
{
return _PtrNode;
}
const Node* GetPtr()const
{
return _PtrNode;
}
//成员指针
Node* _PtrNode;
};
在迭代器中需要通过typedef对结点模板进行实例化:
正向迭代器模板之所以要设计三个模板参数是为了能够利用同一个迭代器模板去实例化出普通迭代器和const迭代器:
const迭代器是只能访问数据元素而不能修改数据元素的迭代器(一般供const对象使用)
template<class Iterator>
class ReverseListIterator
{
public:
//告诉编译器Ref和Ptr是Iterator类域中的类型名称
typedef typename Iterator::Ref Ref;
typedef typename Iterator::Ptr Ptr;
typedef ReverseListIterator<Iterator> Self;
//构造函数
ReverseListIterator(const Iterator& Rit = Iterator())
:_Rit(Rit)
{}
//重载*运算符,返回结点数据的引用
Ref operator*() const
{
return *_Rit;
}
//重载->,函数返回值是结点数据的地址
//当结点数据类型仍然为自定义结构时会用到,
Ptr operator->() const
{
return &(*_Rit);
}
//重载前置++,函数返回值是迭代器的自引用
Self& operator++()
{
--_Rit;
return (*this);
}
//重载后置++,函数返回值是迭代器的自引用
Self operator++(int)
{
Self tem(*this);
--_Rit;
return tem;
}
//重载前置--,函数返回值是迭代器的自引用
Self& operator--()
{
++_Rit;
return (*this);
}
//重载后置--,函数返回值是迭代器的自引用
Self operator--(int)
{
Self tem(*this);
++_Rit;
return tem;
}
//重载比较运算符==
bool operator==(const Self It) const
{
return It._Rit== _Rit;
}
//重载比较运算符!=
bool operator!= (const Self It) const
{
return !((*this) == It);
}
Iterator _Rit;
};
template<class T>
class List
{
public:
//实例化并重命名链表结点模板
typedef ListNode<T> Node;
//实例化并重命名正向迭代器模板
typedef ListIterator<T, T&, T*> iterator;
typedef ListIterator<T, const T&, const T*> const_iterator;
//实例化并重命名反向迭代器模板
typedef ReverseListIterator<iterator> reverse_iterator;
typedef ReverseListIterator<const_iterator> const_reverse_iterator;
//获取迭代器的成员接口
iterator begin()
{
return iterator(_Node->_next);
}
const_iterator begin() const
{
return const_iterator(_Node->_next);
}
iterator end()
{
return iterator(_Node);
}
const_iterator end() const
{
return const_iterator (_Node);
}
reverse_iterator rbegin()
{
return reverse_iterator(--end());
}
reverse_iterator rbegin() const
{
return reverse_iterator(--end());
}
reverse_iterator rend()
{
return reverse_iterator(--begin());
}
const_reverse_iterator rend() const
{
return const_reverse_iterator(--begin());
}
//基本功能的成员接口
//申请链表结点的接口
Node* BuyListNode(const T& val = T());
//清空List
//采用头删删除(寻址比较方便)
void clear();
//交换两个list对象的内容
void swap(List<T>& list);
private:
//创建头节点的私有成员接口
void Creathead();
public:
//List容器的数据进出接口
// 在pos位置前插入值为val的节点
iterator insert(iterator pos, const T& val);
// 删除pos位置的节点,返回该节点的下一个位置
iterator erase(iterator pos);
//链表尾插接口
void push_back(const T& val);
//链表尾删接口
void pop_back();
//链表头插接口
void push_front(const T& val);
//链表头删接口
void pop_front();
//List的构造函数
//默认构造函数
List();
//构造函数模板
//(用迭代器区间构造List对象,迭代器可以是其他类型容器的迭代器)
template <class Iterator>
List(Iterator first, Iterator last);
//拷贝构造函数
List(const List<T>& list);
//创建n个T值节点的构造函数
List(int n, const T& value = T());
//List的赋值运算符重载
List<T>& operator=(List<T> templist);
//访问List各种存储信息的接口
size_t size()const;
//链表判空接口
bool empty() const;
//重新设置链表节点个数的接口
void resize(size_t newsize, const T& data = T());
//返回首数据元素
T& front();
//const重载(const修饰this指针使得const对象可以调用该接口)
const T& front()const;
//返回尾数据元素
T& back();
//const重载(const修饰this指针使得const对象可以调用该接口)
const T& back()const;
//List的析构函数
~List();
private:
Node* _Node;
};
};
void Creathead();
创建链表头节点时注意修改头节点的指针域使其指向头节点自身: void Creathead()
{
_Node = new Node;
_Node->_next = _Node;
_Node->_prev = _Node;
}
void clear();
清空链表的接口 //清空List
//采用头删删除(寻址比较方便)
void clear()
{
Node* cur = _Node->_next;
while (cur != _Node)
{
Node *tem = cur->_next;
delete cur;
cur = tem;
}
//注意恢复空表的指针状态
_Node->_next = _Node;
_Node->_prev = _Node;
}
void swap(List& list)
交换两个链表的所有内容:实质上就是交换头节点指针的指向 //交换两个list对象的内容
void swap(List<T>& list)
{
std::swap(_Node, list._Node);
}
//List的构造函数
//默认构造函数
List()
{
Creathead();
}
//用容器迭代器区间去初始化List对象
template <class Iterator>
List(Iterator first, Iterator last)
{
Creathead();
while (first != last)
{
push_back(*first);
++first;
}
}
//拷贝构造函数(复用迭代器构造函数实现)
List(const List<T>& list)
{
//创建空表
Creathead();
List<T> tem(list.begin(), list.end());
this->swap(tem);
}
//构造n个节点的链表的构造函数(复用尾插接口实现)
List(int n, const T& value = T())
{
Creathead();
while (n--)
{
push_back(value);
}
}
//List的赋值运算符重载(复用交换函数和拷贝构造函数实现)
List<T>& operator=(List<T> templist)
{
this->swap(templist);
return (*this);
}
// 在pos位置前插入值为val的节点
iterator insert(iterator pos, const T& val)
{
Node* temprve = pos._PtrNode->_prev;
Node * NodenewNode = BuyListNode(val);
temprve->_next = NodenewNode;
pos._PtrNode->_prev = NodenewNode;
NodenewNode->_next = pos._PtrNode;
NodenewNode->_prev = temprve;
--pos;
return pos;
}
// 删除pos位置的节点,返回该节点的下一个位置
iterator erase(iterator pos)
{
assert(!empty());
Node* temprev = pos.GetPtr()->_prev;
Node* tempnext = pos.GetPtr()->_next;
iterator tem = pos;
++tem;
temprev->_next = tempnext;
tempnext->_prev = temprev;
delete pos.GetPtr();
return tem;
}
//链表尾插接口
void push_back(const T& val)
{
insert(end(), val);
}
//链表尾删接口
void pop_back()
{
assert(!empty());
erase(--end());
}
//链表头插接口
void push_front(const T& val)
{
insert(begin(), val);
}
//链表头删接口
void pop_front()
{
assert(!empty());
erase(begin());
}
//获取节点个数
size_t size()const
{
int count = 0;
for (auto it : (*this))
{
count++;
}
return count;
}
//链表判空
bool empty() const
{
return (begin() == end());
}
//调整链表节点个数(复用尾插尾删接口实现)
void resize(size_t newsize, const T& data = T())
{
int Size = size();
if (Size > newsize)
{
int Erase = Size - newsize;
while (Erase--)
{
pop_back();
}
}
else
{
int create = newsize - Size;
while (create--)
{
push_back(T);
}
}
}
//获取表头数据
T& front()
{
assert(!empty());
return *begin();
}
const T& front()const
{
assert(!empty());
return *begin();
}
//获取表尾数据
T& back()
{
assert(!empty());
return *(--end());
}
const T& back()const
{
assert(!empty());
return *(--end());
}
~List()
{
clear();
delete _Node;
_Node = nullptr;
}