目录
[3.1 clear、析构函数、swap](#3.1 clear、析构函数、swap)
[② 析构函数](#② 析构函数)
[③ swap](#③ swap)
[3.3 迭代器](#3.3 迭代器)
[3.5 删除函数](#3.5 删除函数)
0.前言
我们知道,list是一个双向循环链表,所以list的每个节点中需要存在一个指向前一个节点的指针prev、一个指向下一个节点的指针next和一个数据域data
1.节点类
因为list的底层是节点,而节点的底层又是prev、next指针和数据域data,所以我们先将节点封装为一个类,然后再用list类调用节点类。节点类的代码如下:
//定义链表节点
template<class T>
struct ListNode
{
ListNode<T>* _next;
ListNode<T>* _prev;
T _data;
//链表节点构造函数
ListNode(const T& x = T())
:_next(nullptr)
, _prev(nullptr)
, _data(x)
{}
2.迭代器类
在string和vector中我们使用迭代器访问数据时需要有这样的操作:
vector<int>::iterator it = l1.begin();
while (it != l1.end())
{
cout << *it << " ";
++it;
}
cout << endl;
需要知悉的是,在C++中,为了方便和统一,无论什么类我们大多都采用此方法进行访问,string与vector都是连续的,如此访问必然不会有差错,可是list并不是连续的
我们希望++it就能找到下一个节点,而it解引用(*it)就得到节点里存的data,所以,为了使迭代器能够正常访问,我们在自定义的类中必须实现以下方法:
指针可以解引用,迭代器的类中必须重载operator*()
指针可以通过->访问其所指空间成员,迭代器类中必须重载oprator->()
指针可以++向后移动,迭代器类中必须重载operator++()与operator++(int)
迭代器需要进行是否相等的比较,因此还需要重载operator==()与operator!=()
代码如下:
①普通迭代器
//①普通迭代器 可读可写
template<class T>
struct __list_iterator
{
typedef ListNode<T> Node;
typedef __list_iterator D;
Node* _node;
//迭代器构造函数
__list_iterator(Node* x)
:_node(x)
{}
//重载++
//前置++
D& operator++()//返回迭代器的引用
{
_node = _node->_next;//指向下一个节点
return *this;
}
//后置++
D operator++(int)
{
D tmp(*this);
_node = _node->_next;
return tmp;//返回拷贝之前的值
}
//重载--
//前置--
D& operator--()
{
_node = _node->_prev;
return *this;
}
//后置--
D operator--(int)
{
D tmp(*this);
_node = _node->_prev;
return tmp;
}
//重载解引用
T& operator*()//返回数据的引用
{
return _node->_data;//返回节点里的数据
}
//重载->
T* operator->()
{
return &_node->_data;
}
//重载!=
bool operator !=(const D& s)
{
return _node != s._node;
}
//重载==
bool operator==(const D& s)
{
return _node == s._node;
}
};
②const迭代器
const迭代器的作用是只可读不可写,防止数据被修改,因此我们只需在普通迭代器的基础上对operator*()和operator->()添加const操作即可:
//②const迭代器 可读不可写
template<class T>
struct __list_const_iterator
{
typedef ListNode<T> Node;
typedef __list_const_iterator D;
Node* _node;
//迭代器构造函数
__list_const_iterator(Node* x)
:_node(x)
{}
//重载++
//前置++
D& operator++()//返回迭代器的引用
{
_node = _node->_next;//指向下一个节点
return *this;
}
//后置++
D operator++(int)
{
D tmp(*this);
_node = _node->_next;
return tmp;//返回拷贝之前的值
}
//重载--
//前置--
D& operator--()
{
_node = _node->_prev;
return *this;
}
//后置--
D operator--(int)
{
D tmp(*this);
_node = _node->_prev;
return tmp;
}
//重载解引用
const T& operator*()//返回数据的引用
{
return _node->_data;//返回节点里的数据
}
//重载->
const T* operator->()
{
return &_node->_data;
}
//重载!=
bool operator !=(const D& s)
{
return _node != s._node;
}
//重载==
bool operator==(const D& s)
{
return _node == s._node;
}
};
③模板迭代器
观察以上两个迭代器,不同之处也就在于对operator*()和operator->()的操作不同,代码相似度可以说达到了90%,那么有没有办法减少冗余,提高代码的可读性呢?
答案当然是有的,我们可以为两个迭代器提供一个共同的模板,再提供两个参数,当调用普通迭代器和const迭代器时,只需根据所传递的参数而选择不同的迭代器。
template<class T, class Ref, class Ptr>
struct __list_iterator
{
typedef ListNode<T> Node;
typedef __list_iterator<T, Ref, Ptr> D;
Node* _node;
//迭代器构造函数
__list_iterator(Node* x)
:_node(x)
{}
//重载++
//前置++
D& operator++()//返回迭代器的引用
{
_node = _node->_next;//指向下一个节点
return *this;
}
//后置++
D operator++(int)
{
D tmp(*this);
_node = _node->_next;
return tmp;//返回拷贝之前的值
}
//重载--
//前置--
D& operator--()
{
_node = _node->_prev;
return *this;
}
//后置--
D operator--(int)
{
D tmp(*this);
_node = _node->_prev;
return tmp;
}
//重载解引用
Ref operator*()//返回数据的引用
{
return _node->_data;//返回节点里的数据
}
//重载->
Ptr operator->()
{
return &_node->_data;
}
//重载!=
bool operator !=(const D& s)
{
return _node != s._node;
}
//重载==
bool operator==(const D& s)
{
return _node == s._node;
}
};
3.list类
做好了节点类和迭代器类的准备工作,终于来到了主角list类
//定义链表
template<class T>
class list
{
typedef ListNode<T> Node;
public:
/*typedef __list_iterator<T> iterator;
typedef __list_const_iterator<T> const_iterator;*/
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;
private:
Node* _head;
};
3.1 clear、析构函数、swap
①clear
//clear
void clear()
{
iterator it = begin();
while (it != end())
{
it = erase(it);
}
}
② 析构函数
//析构函数
~list()
{
clear();
delete _head;
_head = nullptr;
}
③ swap
//swap
void swap(list<T>& tmp)
{
std::swap(_head, tmp._head);
}
3.2构造函数
①无参构造
//链表构造函数
list()
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
}
②赋值构造
//operator=
list<T>& operator=(list<T> lt)
{
swap(lt);
return *this;
}
3.3 迭代器
//普通迭代器
iterator begin()
{
//return iterator(_head->_next);
return _head->_next;//单参数的构造函数支持隐式类型转换
}
iterator end()
{
return _head;
}
//const迭代器
const_iterator begin() const
{
//return iterator(_head->_next);
return _head->_next;//单参数的构造函数支持隐式类型转换
}
const_iterator end() const
{
return _head;
}
3.4插入函数
①insert插入
//insert插入
iterator insert(iterator pos, const T& x)
{
Node* cur = pos._node;//取当前节点
Node* prev = cur->_prev;//当前节点的前一个节点
Node* newnode = new Node(x);//创建并初始化新节点
prev->_next = newnode;//前一个节点的_next指针指向新节点
newnode->_prev = prev;//新节点的_prev指针指向前一个节点
newnode->_next = cur;//新节点的_next指针指向当前节点(此时相对于新节点就变成了后一个节点)
cur->_prev = newnode;//当前节点的_prev指针指向新节点(此时相对于新节点就变成了后一个节点)
//return iterator(newnode);
return newnode;
}
②头插
//push_front头插
void push_front(const T& x)
{
insert(begin(), x);
}
③尾插
原始写法
void push_back(const T& x)
{
Node* newnode = new Node(x);//开辟并初始化新节点newnode
Node* tail = _head->_prev;//定义上一个节点为tail
tail->_next = newnode;//上一个节点tail的next指针指向新节点newnode
newnode->_prev = tail;//新节点newnode的prev指针指向上一个节点tail
newnode->_next = _head;//新节点newnode的next指针指向头节点_head
_head->_prev = newnode;//头节点_head的prve指针指向新节点newnode
}
复用insert
void push_back(const T& x)
{
insert(end(), x);
}
复用尾插,写拷贝构造:
//拷贝构造
list(list<T>& lt)
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;//拷贝之前先创建一个头节点,自己指向自己
for (const auto& e : lt)
{
push_back(e);
}
}
3.5 删除函数
①erase删除
iterator erase(iterator pos)
{
assert(pos != end());//避免删除哨兵位的头节点
Node* cur = pos._node;//取当前节点
Node* prev = cur->_prev;//取前一个节点
Node* next = cur->_next;//取后一个节点
prev->_next = next;
next->_prev = prev;
//销毁当前节点
delete cur;
return next;
}
②头删
//pop_front头删
void pop_front()
{
erase(begin());
}
③尾删
//pop_back尾删
void pop_back()
{
erase(--end());
}
4.测试
void test_list()
{
//无参构造
list<int> l1;
for (auto e : l1)
{
cout << e << " ";
}
cout << endl;
//插入
//insert插入
l1.insert(l1.begin(), 1);
for (auto e : l1)
{
cout << e << " ";
}
cout << endl;
//头插
l1.push_front(0);
for (auto e : l1)
{
cout << e << " ";
}
cout << endl;
//尾插
l1.push_back(2);
l1.push_back(3);
l1.push_back(4);
for (auto e : l1)
{
cout << e << " ";
}
cout << endl;
//删除
//erase删除
l1.erase(l1.begin());
for (auto e : l1)
{
cout << e << " ";
}
cout << endl;
//头删
l1.pop_front();
for (auto e : l1)
{
cout << e << " ";
}
cout << endl;
//尾删
l1.pop_back();
for (auto e : l1)
{
cout << e << " ";
}
cout << endl;
//赋值构造
list<int> l2 = l1;
for (auto e : l1)
{
cout << e << " ";
}
cout << endl;
}
源代码(list.h)
#pragma once
#include <iostream>
#include <assert.h>
using namespace std;
#include <assert.h>
namespace xxk
{
//定义链表节点
template<class T>
struct ListNode
{
ListNode<T>* _next;
ListNode<T>* _prev;
T _data;
//链表节点构造函数
ListNode(const T& x = T())
:_next(nullptr)
, _prev(nullptr)
, _data(x)
{}
};
//定义迭代器
//在vector使用迭代器时:
/*vector<int>::iterator it = l1.begin();
while (it != l1.end())
{
cout << *it << " ";
++it;
}
cout << endl;*/
//在这段代码中我们希望++it就能找到下一个节点,而it解引用(*it)我们需要得到节点里存的data
//可是链表并不是连续的,因迭代器使用形式与指针完全相同,想要实现以上功能,我们必须要在自定义类中实现以下方法:
//1. 指针可以解引用,迭代器的类中必须重载operator*()
//2. 指针可以通过->访问其所指空间成员,迭代器类中必须重载oprator->()
//3. 指针可以++向后移动,迭代器类中必须重载operator++()与operator++(int)
// 至于operator--() / operator--(int)释放需要重载,根据具体的结构来抉择,双向链表可以向前移动,
// 所以需要重载,如果是forward_list就不需要重载--
//4. 迭代器需要进行是否相等的比较,因此还需要重载operator == ()与operator != ()
//③为减少冗余,提高代码的可读性,使用模板将两个类写到一起
template<class T, class Ref, class Ptr>
struct __list_iterator
{
typedef ListNode<T> Node;
typedef __list_iterator<T, Ref, Ptr> D;
Node* _node;
//迭代器构造函数
__list_iterator(Node* x)
:_node(x)
{}
//重载++
//前置++
D& operator++()//返回迭代器的引用
{
_node = _node->_next;//指向下一个节点
return *this;
}
//后置++
D operator++(int)
{
D tmp(*this);
_node = _node->_next;
return tmp;//返回拷贝之前的值
}
//重载--
//前置--
D& operator--()
{
_node = _node->_prev;
return *this;
}
//后置--
D operator--(int)
{
D tmp(*this);
_node = _node->_prev;
return tmp;
}
//重载解引用
Ref operator*()//返回数据的引用
{
return _node->_data;//返回节点里的数据
}
//重载->
Ptr operator->()
{
return &_node->_data;
}
//重载!=
bool operator !=(const D& s)
{
return _node != s._node;
}
//重载==
bool operator==(const D& s)
{
return _node == s._node;
}
};
//定义链表
template<class T>
class list
{
typedef ListNode<T> Node;
public:
/*typedef __list_iterator<T> iterator;
typedef __list_const_iterator<T> const_iterator;*/
typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;
//普通迭代器
iterator begin()
{
//return iterator(_head->_next);
return _head->_next;//单参数的构造函数支持隐式类型转换
}
iterator end()
{
return _head;
}
//const迭代器
const_iterator begin() const
{
//return iterator(_head->_next);
return _head->_next;//单参数的构造函数支持隐式类型转换
}
const_iterator end() const
{
return _head;
}
//链表构造函数
list()
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
}
//clear
void clear()
{
iterator it = begin();
while (it != end())
{
it = erase(it);
}
}
//析构函数
~list()
{
clear();
delete _head;
_head = nullptr;
}
//拷贝构造
list(list<T>& lt)
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;//拷贝之前先创建一个头节点,自己指向自己
for (const auto& e : lt)
{
push_back(e);
}
}
//swap
void swap(list<T>& tmp)
{
std::swap(_head, tmp._head);
}
//operator=
list<T>& operator=(list<T> lt)
{
swap(lt);
return *this;
}
//尾插
①
//void push_back(const T& x)
//{
// Node* newnode = new Node(x);//开辟并初始化新节点newnode
// Node* tail = _head->_prev;//定义上一个节点为tail
// tail->_next = newnode;//上一个节点tail的next指针指向新节点newnode
// newnode->_prev = tail;//新节点newnode的prev指针指向上一个节点tail
// newnode->_next = _head;//新节点newnode的next指针指向头节点_head
// _head->_prev = newnode;//头节点_head的prve指针指向新节点newnode
//}
//②复用insert
void push_back(const T& x)
{
insert(end(), x);
}
//insert插入
iterator insert(iterator pos, const T& x)
{
Node* cur = pos._node;//取当前节点
Node* prev = cur->_prev;//当前节点的前一个节点
Node* newnode = new Node(x);//创建并初始化新节点
prev->_next = newnode;//前一个节点的_next指针指向新节点
newnode->_prev = prev;//新节点的_prev指针指向前一个节点
newnode->_next = cur;//新节点的_next指针指向当前节点(此时相对于新节点就变成了后一个节点)
cur->_prev = newnode;//当前节点的_prev指针指向新节点(此时相对于新节点就变成了后一个节点)
//return iterator(newnode);
return newnode;
}
//push_front头插
void push_front(const T& x)
{
insert(begin(), x);
}
//erase删除函数
iterator erase(iterator pos)
{
assert(pos != end());//避免删除哨兵位的头节点
Node* cur = pos._node;//取当前节点
Node* prev = cur->_prev;//取前一个节点
Node* next = cur->_next;//取后一个节点
prev->_next = next;
next->_prev = prev;
//销毁当前节点
delete cur;
return next;
}
//pop_back尾删
void pop_back()
{
erase(--end());
}
//pop_front头删
void pop_front()
{
erase(begin());
}
private:
Node* _head;
};
void test_list()
{
//无参构造
list<int> l1;
for (auto e : l1)
{
cout << e << " ";
}
cout << endl;
//插入
//insert插入
l1.insert(l1.begin(), 1);
for (auto e : l1)
{
cout << e << " ";
}
cout << endl;
//头插
l1.push_front(0);
for (auto e : l1)
{
cout << e << " ";
}
cout << endl;
//尾插
l1.push_back(2);
l1.push_back(3);
l1.push_back(4);
for (auto e : l1)
{
cout << e << " ";
}
cout << endl;
//删除
//erase删除
l1.erase(l1.begin());
for (auto e : l1)
{
cout << e << " ";
}
cout << endl;
//头删
l1.pop_front();
for (auto e : l1)
{
cout << e << " ";
}
cout << endl;
//尾删
l1.pop_back();
for (auto e : l1)
{
cout << e << " ";
}
cout << endl;
//赋值构造
list<int> l2 = l1;
for (auto e : l1)
{
cout << e << " ";
}
cout << endl;
}
}