list的实现最主要的点就是迭代器的实现,不能在使用原生指针,因为链表的结点并不是连续的。于是使用类来实现迭代器,具体代码如下:
namespace QBL
{
template<class T>//结点的数据类型
struct ListNode
{
ListNode(const T& x = T())//结点初始化的时候数据给默认值,默认值是数据类型的匿名对象,匿名对象执行无参构造
:_next(nullptr)
, _prev(nullptr)
, _Data(x)//当结点数据类型是自定义类的时候会去执行拷贝构造,所以无需担心浅拷贝的问题
{
}
ListNode* _next;
ListNode* _prev;
T _Data;
};
template<class T>
struct ListIterator
{//因为原生指针node* 无法直接进行类似指针++或者--或者解引用的操作,于是写一个类,专门用来控制迭代器的行为
typedef ListNode<T> Node;
typedef ListIterator<T> Self;
Node* pnode;//定义的迭代器类其实还是指针,只不过我们可以重载迭代器的行为了
ListIterator(Node* p)
:pnode(p)
{}
Self& operator++()//我们定义一个迭代器对象,对象++其实就是指针指向下一个
{
pnode = pnode->_next;
return *this;//返回一个迭代器,即此类
}
Self operator++(int)//后置++
{
Self tmp(*this);//因为是指针,目的就是指向同一个位置,所以浅拷贝没问题
pnode = pnode->_next;
return tmp;
}
Self& operator--()
{
pnode = pnode->_prev;
return *this;
}
Self operator--(int)
{
Self tmp(*this);
pnode = pnode->_prev;
return tmp;
}
T& operator*()
{
return pnode->_Data;
}
T* operator->()
{
return &(pnode->_Data);
}
bool operator!=(Self get_pnode)
{
return pnode != get_pnode.pnode;
}
bool operator==(Self get_pnode)
{
return pnode == get_pnode.pnode;
}
};
template<class T>
struct ListConstIterator//重新写一个类,专门用来访问const修饰是的链表,这个类的迭代器解引用的数据无法修改
{//const迭代器就是普通的迭代器的赋值,但是修改了解引用和->
typedef ListNode<T> Node;
typedef ListConstIterator<T> Self;
Node* pnode;
ListConstIterator(Node* p)
:pnode(p)
{}
Self& operator++()
{
pnode = pnode->_next;
return *this;
}
Self operator++(int)
{
Self tmp(*this);
pnode = pnode->_next;
return tmp;
}
Self& operator--()
{
pnode = pnode->_prev;
return *this;
}
Self operator--(int)
{
Self tmp(*this);
pnode = pnode->_prev;
return tmp;
}
const T& operator*()//此类的解引用无法修改结点数据
{
return pnode->_Data;
}
const T* operator->()
{
return &(pnode->_Data);
}
bool operator!=(Self get_pnode)
{
return pnode != get_pnode.pnode;
}
bool operator==(Self get_pnode)
{
return pnode == get_pnode.pnode;
}
};
template <class T>
class list
{
typedef ListNode<T> node;
public:
typedef ListIterator<T> iterator;
typedef ListIterator<T> const_iterator;
list()
{
_head = new node;//初始化开辟的是哨兵位
_head->_next = _head;//哨兵位的next和prev都指向自己
_head->_prev = _head;
_size = 0;
}
/*void push_back(const T& x)
{
node* tmp = new node(x);
node* tail = _head->_prev;
tmp->_next = _head;
tmp->_prev = tail;
_head->_prev = tmp;
tail->_next = tmp;
}*/
iterator begin()//begin和end返回的都是迭代器类型,这样才能对迭代器进行操作访问其他结点
{
return iterator(_head->_next);//返回匿名对象,虽然是传值返回,但是返回的是迭代器,所以没问题
}
iterator end()
{
return iterator(_head);//end是指向哨兵位的,并不是最有一个结点
}
const_iterator begin()const//不能使用const修饰iterator,因为const修饰的是迭代器对象,而我们需要的是结点的数据无法修改
{//const_iterator属于一个新的类,专门用来解决const修饰的list
return const_iterator(_head->_next);
}
const_iterator end()const
{
return const_iterator(_head);
}
void insert(iterator pos, const T& val)//在某个结点前面插入
{
node* cur = pos.pnode;
node* tmp = new node(val);
node* prev = cur->_prev;
tmp->_next = cur;
tmp->_prev = prev;
prev->_next = tmp;
cur->_prev = tmp;
++_size;
}
iterator erase(iterator pos)//erase后,pos失效,所以返回下一个结点的迭代器
{
node* prev = pos.pnode->_prev;
node* next = pos.pnode->_next;
prev->_next = next;
next->_prev = prev;
delete pos.pnode;
--_size;
return iterator(next);
}
void push_back(const T& val)
{
insert(end(), val);
}
void push_front(const T& val)
{
insert(begin(), val);
}
void pop_back()
{
erase(--end());
}
void pop_front()
{
erase(begin());
}
size_t size()const
{
return _size;
}
bool empty()
{
return _size == 0;
}
private:
node* _head;//链表只有一个成员变量指向哨兵位
size_t _size;
};
void test1()
{
list<int> lt;
lt.push_back(5);
lt.push_back(5);
lt.push_back(4);
lt.push_back(3);
lt.push_back(2);
lt.push_back(1);
list<int>::iterator it = lt.begin();//定义一个迭代器对象去访问链表的结点
while(it != lt.end())
{
cout << *it << " ";
++it;
}
cout << endl;
lt.push_front(103);
lt.push_front(13);
lt.push_front(03);
lt.pop_back();
lt.pop_back();
lt.pop_front();
lt.pop_front();
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
}
void test2()
{
struct A
{
int a1;
int a2;
A(int aa1 = 0, int aa2 = 0)
:a1(aa1)
,a2(aa2)
{
}
};
A A1(1, 1);
list<A> lt;
lt.push_back(A1);
lt.push_back({2, 2});
lt.push_back(A(3, 3));
list<A>::iterator it = lt.begin();//当为模板为自定义类型的时候,解引用重载就无法使用了,因为无法解引用自定义类型
while (it != lt.end())
{
cout << it->a1 << " " << it->a2 << " ";//下面一行代码和这一行一样的意思,编译器优化掉了一个->
///cout << it.operator->()->a1 << " " << it.operator->()->a2 << " ";
it++;
cout << endl;
}
cout << endl;
}
}
可以发现上述代码中为了解决const修饰的链表仍然可以通过迭代器修改结点的值的问题,重新写了一个类,但是这个类中只要解引用和->访问被const修饰了。其他成员函数都是一样的。于是可以通过模板解决这个冗余的问题。讲解引用和->的重载返回值改用模板参数。然后通过list中的两个宏去定义二者。这样就有了两个类,且功能和上面的代码一样。
namespace QBL
{
template<class T>//结点的数据类型
struct ListNode
{
ListNode(const T& x = T())//结点初始化的时候数据给默认值,默认值是数据类型的匿名对象,匿名对象执行无参构造
:_next(nullptr)
, _prev(nullptr)
, _Data(x)//当结点数据类型是自定义类的时候会去执行拷贝构造,所以无需担心浅拷贝的问题
{
}
ListNode* _next;
ListNode* _prev;
T _Data;
};
template<class T, class Ref, class Ptr>//与上面相比,只要解引用和->不一样,写成模板,让编译器生成一个带const和一个不带const的就行
struct ListIterator
{//因为原生指针node* 无法直接进行类似指针++或者--或者解引用的操作,于是写一个类,专门用来控制迭代器的行为
typedef ListNode<T> Node;
typedef ListIterator<T, Ref, Ptr> Self;
Node* pnode;//定义的迭代器类其实还是指针,只不过我们可以重载迭代器的行为了
ListIterator(Node* p)
:pnode(p)
{}
Self& operator++()//我们定义一个迭代器对象,对象++其实就是指针指向下一个
{
pnode = pnode->_next;
return *this;//返回一个迭代器,即此类
}
Self operator++(int)//后置++
{
Self tmp(*this);//因为是指针,目的就是指向同一个位置,所以浅拷贝没问题
pnode = pnode->_next;
return tmp;
}
Self& operator--()
{
pnode = pnode->_prev;
return *this;
}
Self operator--(int)
{
Self tmp(*this);
pnode = pnode->_prev;
return tmp;
}
Ref operator*()
{
return pnode->_Data;
}
Ptr operator->()
{
return &(pnode->_Data);
}
bool operator!=(Self get_pnode)
{
return pnode != get_pnode.pnode;
}
bool operator==(Self get_pnode)
{
return pnode == get_pnode.pnode;
}
};
template <class T>
class list
{
typedef ListNode<T> node;
public:
typedef ListIterator<T, T&, T*> iterator;//通过定义两个不同的宏再通过模板来实现两种类
typedef ListIterator<T, const T&, const T*> const_iterator;
void empty_init()
{
_head = new node;//初始化开辟的是哨兵位
_head->_next = _head;//哨兵位的next和prev都指向自己
_head->_prev = _head;
_size = 0;
}
list()
{
empty_init();
}
list(const list<T>& lt)//拷贝构造
{
empty_init();//有一个头节点以后,在进行尾插就很方便
for (auto& e : lt)
{
push_back(e);
}
}
void swap(list& lt)
{
std::swap(_head, lt._head);
std::swap(_size, lt._size);
}
list<T>& operator=(list lt)
{
swap(lt);//因为是和临时对象交换的,交换过后出函数,函数执行析构,原来的结点也会被释放掉
return *this;
}
/*void push_back(const T& x)
{
node* tmp = new node(x);
node* tail = _head->_prev;
tmp->_next = _head;
tmp->_prev = tail;
_head->_prev = tmp;
tail->_next = tmp;
}*/
iterator begin()//begin和end返回的都是迭代器类型,这样才能对迭代器进行操作访问其他结点
{
return iterator(_head->_next);//返回匿名对象,虽然是传值返回,但是返回的是迭代器,所以没问题
}
iterator end()
{
return iterator(_head);//end是指向哨兵位的,并不是最有一个结点
}
const_iterator begin()const//不能使用const修饰iterator,因为const修饰的是迭代器对象,而我们需要的是结点的数据无法修改
{//const_iterator属于一个新的类,专门用来解决const修饰的list
return const_iterator(_head->_next);
}
const_iterator end()const
{
return const_iterator(_head);
}
void insert(iterator pos, const T& val)//在某个结点前面插入
{
node* cur = pos.pnode;
node* tmp = new node(val);
node* prev = cur->_prev;
tmp->_next = cur;
tmp->_prev = prev;
prev->_next = tmp;
cur->_prev = tmp;
++_size;
}
iterator erase(iterator pos)//erase后,pos失效,所以返回下一个结点的迭代器
{
node* prev = pos.pnode->_prev;
node* next = pos.pnode->_next;
prev->_next = next;
next->_prev = prev;
delete pos.pnode;
--_size;
return iterator(next);
}
void push_back(const T& val)
{
insert(end(), val);
}
void push_front(const T& val)
{
insert(begin(), val);
}
void pop_back()
{
erase(--end());
}
void pop_front()
{
erase(begin());
}
size_t size()const
{
return _size;
}
bool empty()
{
return _size == 0;
}
void clear()//没有清除头节点,只清除所有数据
{
iterator it = begin();
while (it != end())
{
it = erase(it);//erase返回下一个位置的迭代器
}
}
~list()
{
clear();
delete _head;
_head = nullptr;
}
private:
node* _head;//链表只有一个成员变量指向哨兵位
size_t _size;
};
void PrintList(const list<int>& clt)
{
list<int>::const_iterator it = clt.begin();
for (auto e : clt)
{
cout << e << " ";
}
cout << endl;
}
void test1()
{
list<int> lt;
lt.push_back(5);
lt.push_back(5);
lt.push_back(4);
lt.push_back(3);
lt.push_back(2);
lt.push_back(1);
list<int>::iterator it = lt.begin();//定义一个迭代器对象去访问链表的结点
while (it != lt.end())
{
cout << *it << " ";
++it;
}
cout << endl;
lt.push_front(103);
lt.push_front(13);
lt.push_front(03);
lt.pop_back();
lt.pop_back();
lt.pop_front();
lt.pop_front();
for (auto e : lt)
{
cout << e << " ";
}
cout << endl;
}
void test2()
{
struct A
{
int a1;
int a2;
A(int aa1 = 0, int aa2 = 0)
:a1(aa1)
, a2(aa2)
{
}
};
A A1(1, 1);
list<A> lt;
lt.push_back(A1);
lt.push_back({ 2, 2 });
lt.push_back(A(3, 3));
list<A>::iterator it = lt.begin();//当为模板为自定义类型的时候,解引用重载就无法使用了,因为无法解引用自定义类型
while (it != lt.end())
{
cout << it->a1 << " " << it->a2 << " ";//下面一行代码和这一行一样的意思,编译器优化掉了一个->
///cout << it.operator->()->a1 << " " << it.operator->()->a2 << " ";
it++;
cout << endl;
}
cout << endl;
}
void test3()
{
list<int> lt1;
lt1.push_back(11);
lt1.push_back(12);
lt1.push_back(13);
lt1.push_back(14);
lt1.push_back(15);
lt1.push_back(16);
PrintList(lt1);
list<int> lt2 = lt1;
PrintList(lt2);
list<int> lt3(lt2);
PrintList(lt3);
}
}