进阶链表——C++list
之前我们了解了C++的顺序表vector容器,今天我们来了解C++的链表容器list(带头双向循环链表)。
一些基础工作
在模拟实现list之前,我们先来看看文档:
我们重点来看看它的成员有哪些:
我们重点实现增删查改和const和非const迭代器。
具体的文档:
结点类的定义
我们的链表是由一个一个相互孤立的结点,连接起来形成的链表,在C++里我们也要像在C语言那里一样,定义结点类:
首先我们在头文件里,用命名空间跟库里的list分隔开来:
namespace My_list
{
template<class T> //泛型编程
//结点类定义
struct _list_Node
{
};
class list //双向循环链表
{
};
}
由于结点的内容我们要经常访问我们用struct,因为struct的默认成员是公有的。
namespace My_list
{
template<class T> //泛型编程
//结点类定义
struct _list_Node
{
T _data; //数据
_list_Node<T>* _next; //下一个结点地址
_list_Node<T>* _prve; //前一个结点地址
//构造函数初始化
_list_Node(const T& val = T())//隐式类型转换
:_data(val)
, _next(nullptr)
, _prve(nullptr)
{
}
};
class list //双向循环链表
{
};
}
namespace My_list
{
template<class T> //泛型编程
//结点类定义
struct _list_Node
{
T _data; //数据
_list_Node<T>* _next; //下一个结点地址
_list_Node<T>* _prve; //前一个结点地址
//构造函数初始化
_list_Node(const T& val = T())//隐式类型转换
:_data(val)
, _next(nullptr)
, _prve(nullptr)
{
}
};
template<class T> //泛型编程
class list //双向循环链表
{
typedef _list_Node<T> _Node; //typedef _list_Node<T>
private:
//定义私有成员
_Node* _head;
size_t _size;
};
}
把list的构造函数实现一下(初始化头结点):
写一个empty_list () 初始化头结点:
namespace My_list
{
template<class T> //泛型编程
//结点类定义
struct _list_Node
{
T _data; //数据
_list_Node<T>* _next; //下一个结点地址
_list_Node<T>* _prve; //前一个结点地址
//构造函数初始化
_list_Node(const T& val = T())//隐式类型转换
:_data(val)
, _next(nullptr)
, _prve(nullptr)
{
}
};
template<class T> //泛型编程
class list //双向循环链表
{
typedef _list_Node<T> _Node; //typedef _list_Node<T>
public:
//初始化头结点
void empty_list()
{
_head = new _Node;
_head->_next = _head;
_head->_prve = _head;
_size = 0;
}
//构造函数
list()
{
empty_list();
}
private:
//定义私有成员
_Node* _head;
size_t _size;
};
}
顺便实现一下析构函数,为了实现这个功能我们要写一个函数清理链表的所有的数据。为了实现这个功能更方便,还记得我们之前学过的迭代器吗?我们先来实现一个非const迭代器。
非const迭代器
首先list的迭代器和vector的迭代器很不一样,vector的迭代器的底层是连续的指针,所以我们直接可以对vector的迭代器直接加减,但是list是链表,list的指针是不连续的,无法直接加减(否则可能会访问到未开辟的地址。) 所以list的迭代器我们又要用自己封装一下:
我们也用struct来封装list的迭代器:
template<class T>
struct __list_itreator
{
typedef _list_Node<T> _Node; //typedef _list_Node<T>
//成员
_Node* Node;
//构造函数
__list_itreator(_Node* head)
:Node(head)
{
}
};
template<class T>
struct __list_itreator
{
typedef _list_Node<T> _Node; //typedef _list_Node<T>
typedef __list_itreator<T> self; //typedef __list_itreator
//成员
_Node* Node;
//构造函数
__list_itreator(_Node* head)
:Node(head)
{
}
//实现后置++
//前置++返回值也是一个迭代器,我们也可以typedef
self& operator++()
{
Node = Node->_next;
return *this;
}
//后置++
self operator++(int)
{
self tmp(Node);
Node = Node->_next;
return tmp;
}
//前置--
self& operator--()
{
Node = Node->_prve;
return *this;
}
//后置--
self operator--(int)
{
self tmp(Node);
Node = Node->_prve;
return tmp;
}
//解引用
T& operator*()
{
return Node->_data;
}
//重载->
T* operator->()
{
return &Node->_data;
}
//!=
bool operator!=(const self& N)
{
return Node != N.Node;
}
//==
bool operator==(const self& N)
{
return Node == N.Node;
}
};
现在我们写好了迭代器,现在我们来写我们最常写的begin( ) 和 end ( )
typedef __list_itreator<T> iterator; //非const迭代器
//返回第一个结点
iterator begin()
{
return _head->_next;
}
//返回头结点
iterator end()
{
return _head;
}
clear ( )
现在我们来看看clear ( )函数的文档:
我们来实现一下:
//clear()
void clear()
{
iterator it = begin();
while (it != end())
{
}
}
我们while循环里面要写一个删除结点的函数:
erase ( )
我们来实现一下:
iterator erase(iterator pos)
{
_Node* cur = pos.Node;
_Node* prve = cur->_prve;//保存cur之前的结点
_Node* next = cur->_next;//保存cur之后的结点
delete cur;
prve->_next = next;
next->_prve = prve;
--_size;
return iterator(next);//防止迭代器失效
}
我们来完善clear ( ):
void clear()
{
iterator it = begin();
while (it != end())
{
it = erase(it);
}
}
list析构函数
现在做好准备工作后,我们可以实现list的析构函数:
//析构函数
~list()
{
clear();
delete _head;
_head = nullptr;
}
现在给大家看看我们实现的功能:
namespace My_list
{
template<class T> //泛型编程
//结点类定义
struct _list_Node
{
T _data; //数据
_list_Node<T>* _next; //下一个结点地址
_list_Node<T>* _prve; //前一个结点地址
//构造函数初始化
_list_Node(const T& val = T())//隐式类型转换
:_data(val)
, _next(nullptr)
, _prve(nullptr)
{
}
};
template<class T>
struct __list_itreator
{
typedef _list_Node<T> _Node; //typedef _list_Node<T>
typedef __list_itreator<T> self; //typedef __list_itreator
//成员
_Node* Node;
//构造函数
__list_itreator(_Node* head)
:Node(head)
{
}
//实现后置++
//前置++返回值也是一个迭代器,我们也可以typedef
self& operator++()
{
Node = Node->_next;
return *this;
}
//后置++
self operator++(int)
{
self tmp(Node);
Node = Node->_next;
return tmp;
}
//前置--
self& operator--()
{
Node = Node->_prve;
return *this;
}
//后置--
self operator--(int)
{
self tmp(Node);
Node = Node->_prve;
return tmp;
}
//解引用
T& operator*()
{
return Node->_data;
}
//重载->
T* operator->()
{
return &Node->_data;
}
//!=
bool operator!=(const self& N)
{
return Node != N.Node;
}
//==
bool operator==(const self& N)
{
return Node == N.Node;
}
};
template<class T> //泛型编程
class list //双向循环链表
{
typedef _list_Node<T> _Node; //typedef _list_Node<T>
public:
typedef __list_itreator<T> iterator; //非const迭代器
//返回第一个结点
iterator begin()
{
return _head->_next;
}
//返回头结点
iterator end()
{
return _head;
}
//初始化头结点
void empty_list()
{
_head = new _Node;
_head->_next = _head;
_head->_prve = _head;
_size = 0;
}
//构造函数
list()
{
empty_list();
}
//析构函数
~list()
{
clear();
delete _head;
_head = nullptr;
}
//clear()
void clear()
{
iterator it = begin();
while (it != end())
{
it = erase(it);
}
}
iterator erase(iterator pos)
{
_Node* cur = pos.Node;
_Node* prve = cur->_prve;//保存cur之前的结点
_Node* next = cur->_next;//保存cur之后的结点
delete cur;
prve->_next = next;
next->_prve = prve;
--_size;
return iterator(next);//防止迭代器失效
}
private:
//定义私有成员
_Node* _head;
size_t _size;
};
}
现在我们来测试一下:
void test1()
{
list<int> l;
}
编译器正常运行,说明运行成功了。
push_back ( )
我们push_back ( )写起来不难但是,我们可以写好了insert直接复用:
insert ( )
我们用迭代器来完成插入动作:
//插入
iterator insert(iterator pos,const T& val)
{
_Node* cur = pos.Node;
//保存之前的结点
_Node* prve = cur->_prve;
//开辟结点
_Node* newnode = new _Node(val);
//改变指向
newnode->_prve = prve;
prve->_next = newnode;
newnode->_next = cur;
cur->_prve = newnode;
++_size;
return iterator(newnode); //返回插入的位置
}
现在我们来实现push_back()
void push_back(const T& val)
{
insert(end(), val);
}
我们来测试一下:
void test1()
{
list<int> l;
l.push_back(90);
l.push_back(90);
l.push_back(90);
l.push_back(90);
l.push_back(90);
l.push_back(90);
auto it = l.begin();
while (it != l.end())
{
if (it != -- l.end())
{
cout << *it << "<=>";
it++;
}
else
{
cout << *it ;
it++;
}
}
cout << endl;
}
同时我们还有一个函数:push_front:
push_front ( )
我们也用insert复用:
void push_front(const T& val)
{
insert(begin(), val);
}
我们来测试一下:
void test1()
{
list<int> l;
l.push_back(90);
l.push_back(190);
l.push_back(290);
l.push_back(390);
l.push_back(490);
l.push_back(590);
l.push_front(1234);
auto it = l.begin();
while (it != l.end())
{
if (it != -- l.end())
{
cout << *it << "<=>";
it++;
}
else
{
cout << *it ;
it++;
}
}
cout << endl;
}
pop_back()和 pop_front()
这两个函数我们直接复用erase:
void pop_back()
{
erase(--end());//最后一个节点
}
void pop_front()
{
erase(begin());
}
测试一下:
void test1()
{
list<int> l;
l.push_back(90);
l.push_back(190);
l.push_back(290);
l.push_back(390);
l.push_back(490);
l.push_back(590);
l.push_front(1234);
l.pop_back();
l.pop_front();
auto it = l.begin();
while (it != l.end())
{
if (it != -- l.end())
{
cout << *it << "<=>";
it++;
}
else
{
cout << *it ;
it++;
}
}
cout << endl;
}
const迭代器
到现在我们还没有实现const迭代器,我们来实现const迭代器(注意const迭代器是指被指向的内容无法被修改,不是指针本身不能被改。)
大家可以这样理解,非const迭代器和const迭代器本质就是两个不同的迭代器,只不过一个的对象是非const对象,另一个的对象是const对象:
所以我们写const迭代器就是重新写一个对象是const的迭代器:
//const迭代器
template<class T>
struct __list_const_itreator
{
typedef _list_Node<T> _Node; //typedef _list_Node<T>
typedef __list_const_itreator<T> self; //typedef __list_itreator
//成员
_Node* Node;
//构造函数
__list_const_itreator(_Node* head)
:Node(head)
{
}
//实现后置++
//前置++返回值也是一个迭代器,我们也可以typedef
self& operator++()
{
Node = Node->_next;
return *this;
}
//后置++
self operator++(int)
{
self tmp(Node);
Node = Node->_next;
return tmp;
}
//前置--
self& operator--()
{
Node = Node->_prve;
return *this;
}
//后置--
self operator--(int)
{
self tmp(Node);
Node = Node->_prve;
return tmp;
}
//解引用
const T& operator*()
{
return Node->_data;
}
//重载->
const T* operator->()
{
return &Node->_data;
}
//!=
bool operator!=(const self& N)
{
return Node != N.Node;
}
//==
bool operator==(const self& N)
{
return Node == N.Node;
}
};
但大家发现除了“ * ” 和 “ -> ”运算符的返回值不同,其他的都一样,再重复写,代码有点冗余,这个时候我们可以又用模板:
//定义T&返回值为Ref,定义T*返回值Ptr
template<class T, class Ref, class Ptr>
struct __list_itreator
{
typedef _list_Node<T> _Node; //typedef _list_Node<T>
typedef __list_itreator<T,Ref,Ptr> self; //typedef __list_itreator
//成员
_Node* Node;
//构造函数
__list_itreator(_Node* head)
:Node(head)
{
}
//实现后置++
//前置++返回值也是一个迭代器,我们也可以typedef
self& operator++()
{
Node = Node->_next;
return *this;
}
//后置++
self operator++(int)
{
self tmp(Node);
Node = Node->_next;
return tmp;
}
//前置--
self& operator--()
{
Node = Node->_prve;
return *this;
}
//后置--
self operator--(int)
{
self tmp(Node);
Node = Node->_prve;
return tmp;
}
//解引用
Ref operator*()
{
return Node->_data;
}
//重载->
Ptr operator->()
{
return &Node->_data;
}
//!=
bool operator!=(const self& N)
{
return Node != N.Node;
}
//==
bool operator==(const self& N)
{
return Node == N.Node;
}
};
这时候我们就很简单了:
typedef __list_itreator<T, T&, T*> iterator; //非const迭代器
typedef __list_itreator<T, const T&, const T*>
const_iterator; //const迭代器
拷贝构造函数list(const list& It)
有了const迭代器,我们就可以实现拷贝构造函数list(const list& It)
//拷贝构造
list(const list<T>& lt)
{
empty_list();
for (auto e : lt)
{
push_back(e);
}
}
void test2()
{
list<int> l;
l.push_back(90);
l.push_back(190);
l.push_back(290);
l.push_back(390);
l.push_back(490);
l.push_back(590);
list<int> lt(l);
}
附上源码:
#pragma once
#include<iostream>
using namespace std;
namespace My_list
{
template<class T> //泛型编程
//结点类定义
struct _list_Node
{
T _data; //数据
_list_Node<T>* _next; //下一个结点地址
_list_Node<T>* _prve; //前一个结点地址
//构造函数初始化
_list_Node(const T& val = T())//隐式类型转换
:_data(val)
, _next(nullptr)
, _prve(nullptr)
{
}
};
//定义T&返回值为Ref,定义T*返回值Ptr
template<class T, class Ref, class Ptr>
struct __list_itreator
{
typedef _list_Node<T> _Node; //typedef _list_Node<T>
typedef __list_itreator<T,Ref,Ptr> self; //typedef __list_itreator
//成员
_Node* Node;
//构造函数
__list_itreator(_Node* head)
:Node(head)
{
}
//实现后置++
//前置++返回值也是一个迭代器,我们也可以typedef
self& operator++()
{
Node = Node->_next;
return *this;
}
//后置++
self operator++(int)
{
self tmp(Node);
Node = Node->_next;
return tmp;
}
//前置--
self& operator--()
{
Node = Node->_prve;
return *this;
}
//后置--
self operator--(int)
{
self tmp(Node);
Node = Node->_prve;
return tmp;
}
//解引用
Ref operator*()
{
return Node->_data;
}
//重载->
Ptr operator->()
{
return &Node->_data;
}
//!=
bool operator!=(const self& N)
{
return Node != N.Node;
}
//==
bool operator==(const self& N)
{
return Node == N.Node;
}
};
const迭代器
//template<class T>
//struct __list_const_itreator
//{
// typedef _list_Node<T> _Node; //typedef _list_Node<T>
// typedef __list_const_itreator<T> self; //typedef __list_itreator
// //成员
// _Node* Node;
// //构造函数
// __list_const_itreator(_Node* head)
// :Node(head)
// {
// }
// //实现后置++
// //前置++返回值也是一个迭代器,我们也可以typedef
// self& operator++()
// {
// Node = Node->_next;
// return *this;
// }
// //后置++
// self operator++(int)
// {
// self tmp(Node);
// Node = Node->_next;
// return tmp;
// }
// //前置--
// self& operator--()
// {
// Node = Node->_prve;
// return *this;
// }
// //后置--
// self operator--(int)
// {
// self tmp(Node);
// Node = Node->_prve;
// return tmp;
// }
// //解引用
// const T& operator*()
// {
// return Node->_data;
// }
// //重载->
// const T* operator->()
// {
// return &Node->_data;
// }
// //!=
// bool operator!=(const self& N)
// {
// return Node != N.Node;
// }
// //==
// bool operator==(const self& N)
// {
// return Node == N.Node;
// }
//};
template<class T> //泛型编程
class list //双向循环链表
{
typedef _list_Node<T> _Node; //typedef _list_Node<T>
public:
typedef __list_itreator<T, T&, T*> iterator; //非const迭代器
typedef __list_itreator<T, const T&, const T*>
const_iterator; //const迭代器
//返回第一个结点
const_iterator begin() const
{
return _head->_next;
}
//返回头结点
const_iterator end() const
{
return _head;
}
//返回第一个结点
iterator begin()
{
return _head->_next;
}
//返回头结点
iterator end()
{
return _head;
}
//初始化头结点
void empty_list()
{
_head = new _Node;
_head->_next = _head;
_head->_prve = _head;
_size = 0;
}
//拷贝构造
list(const list<T>& lt)
{
empty_list();
for (auto e : lt)
{
push_back(e);
}
}
//构造函数
list()
{
empty_list();
}
//析构函数
~list()
{
clear();
delete _head;
_head = nullptr;
}
//clear()
void clear()
{
iterator it = begin();
while (it != end())
{
it = erase(it);
}
}
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());
}
//插入
iterator insert(iterator pos,const T& val)
{
_Node* cur = pos.Node;
//保存之前的结点
_Node* prve = cur->_prve;
//开辟结点
_Node* newnode = new _Node(val);
//改变指向
newnode->_prve = prve;
prve->_next = newnode;
newnode->_next = cur;
cur->_prve = newnode;
++_size;
return iterator(newnode); //返回插入的位置
}
iterator erase(iterator pos)
{
_Node* cur = pos.Node;
_Node* prve = cur->_prve;//保存cur之前的结点
_Node* next = cur->_next;//保存cur之后的结点
delete cur;
prve->_next = next;
next->_prve = prve;
--_size;
return iterator(next);//防止迭代器失效
}
private:
//定义私有成员
_Node* _head;
size_t _size;
};
void test1()
{
list<int> l;
l.push_back(90);
l.push_back(190);
l.push_back(290);
l.push_back(390);
l.push_back(490);
l.push_back(590);
l.push_front(1234);
l.pop_back();
l.pop_front();
auto it = l.begin();
while (it != l.end())
{
if (it != -- l.end())
{
cout << *it << "<=>";
it++;
}
else
{
cout << *it ;
it++;
}
}
cout << endl;
}
void test2()
{
list<int> l;
l.push_back(90);
l.push_back(190);
l.push_back(290);
l.push_back(390);
l.push_back(490);
l.push_back(590);
list<int> lt(l);
}
}