目录
前言
list是链表的意思
它属于链表中的带头双向循环链表
建议先掌握数据结构中的链表
C数据结构:双向链表(带头循环)_c带头双向循环链表-优快云博客
数据结构
首先我们需要一个链表的节点
template<class T>
struct ListNode
{
T _data;
ListNode* _next;
ListNode* _prev;
ListNode(const T& data = T())
:_data(data)
,_next(nullptr)
,_prev(nullptr)
{}
};
因为这个ListNode类节点里面的内容可以是公开的,所以使用了struct默认即为public,当然也可以使用class来定义类,只需注意使用访问限定符即可
双向链表当然需要next和prev两个指针来指向后面和前面
类中还定义了一个默认构造函数用来构造节点
成员变量和成员函数放置的顺序前后都是可以的,但通常会把成员变量放到最下面
template<class T>
class list
{
typedef ListNode<T> Node;
public:
private:
Node* _head;
size_t _size = 0;
};
Node*指针指向链表头节点,我们还可以定义一个size成员函数,这样可以在计算链表大小的时候减少遍历节点次数
push_back
void push_back(const T& data)
{
Node* newnode = new Node(data);
Node* tail = _head->prev;
tail->_next = newnode;
newnode->_next = _head;
newnode->_prev = tail;
_head->_prev = newnode;
_size++;
}
生成新节点,将它插入到最后面即可
push_front
void push_front(const T& data)
{
Node* newnode = new Node;
Node* next = _head->_next;
_head->_next = newnode;
newnode->_prev = _head;
newnode->_next = next;
next->_prev = newnode;
insert(begin(), data);
}
生成新节点,插入到_head的下一个位置即可
默认构造函数
list()
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
_size = 0;
}
构造出我们的哨兵位头节点,并初始化next和prev指针和size大小
因为这段默认构造函数在其他的成员函数内部也可能会使用,并且默认构造函数不方便显示调用,所以我们可以把这段代码用一个函数来封装起来,方便其他成员函数使用
void EmptyInit()
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
_size = 0;
}
list()
{
EmptyInit();
}
这样我们把空初始化的逻辑放到EmptyInit函数中即可
拷贝构造函数
list(const list<T>& lt)
:_head(lt._head)
,_size(lt._size)
{}
这是经典的错误写法!
这里只是将lt里面的_head按字节拷贝给了this的_head(浅拷贝)
所以最终是两个_head用同一个链表,同一块空间
为了避免这个问题,我们需要重新生成一段空间来完成深拷贝
list(const list<T>& lt)
{
EmptyInit();
for (auto& x : lt)
{
push_back(x);
}
}
复用EmptyInit和push_back的逻辑
因为EmptyInit会初始化出一个哨兵位头节点,我们只需要在这个头节点后面依次插入lt里面的元素即可,因为push_back也是会开新空间的
但是这里的遍历是还完不成的,因为范围for需要有begin,end,重载!=函数,这些函数又需要我们的迭代器,但是我们类中目前是还没有实现的,所以我们还需要先实现完成迭代器和这些成员函数才能完成这个拷贝构造
list迭代器
这里迭代器的实现就没有前面vector和string的那么简单了,因为它们两个的迭代器都可以通过指针的+-来遍历整个容器,但是list由于空间的不连续,所以不能简单的只是使用指针进行+-运算,而是需要我们手动完成对++,--这些运算符的重载操作
结构
template<class T, class Ref, class Ptr>
struct list_iterator
{
typedef ListNode<T> Node;
typedef list_iterator<T, Ref, Ptr> Self;
Node* _node;
};
这里需要有三个模板的支撑&#x