各位小伙伴们,大家好!我是bug。今天我们继续学习STL容器中的list:
(代码可能会有一点问题,请各位老铁指正 )
list:在C++中list容器是双向带头循环链表,这种结构在数据的插入删除上相比于vector有着极大的优势,其时间复杂度为O(1)。它唯一的缺点就是不支持随机访问,去查找数据只能够通过遍历的方式,而vector可以通过下标进行访问。
list的常用接口:
construct(构造函数) | 用法 |
---|---|
list() | 构造空list |
list (size_type n, const value_type& val = value_type()) | 构造包含n个数据为val的list |
list (const list& x) | 拷贝构造函数 |
list (InputIterator first, InputIterator last) | 用[first, last)区间中的元素构造list |
遍历操作 | 用法 |
---|---|
begin | 返回第一个元素的iterator |
end | 返回最后一个元素下一个位置的iterator |
rbegin | 返回第一个元素的reverse_iterator,即end位置 |
rend | 返回最后一个元素下一个位置的reverse_iterator,即begin位置 |
操作空间/容量 | 用法 |
---|---|
empty | 检测list是否为空,是返回true,否则返回false |
size | 返回list中有效节点的个数 |
获得数据 | 用法 |
---|---|
front | 返回list的第一个节点中值的引用 |
back | 返回list的最后一个节点中值的引用 |
修改操作 | 用法 |
---|---|
push_front | 在list首元素前插入值为val的元素 |
pop_front | 删除list中第一个元素 |
push_back | 在list尾部插入值为val的元素 |
pop_back | 删除list中最后一个元素 |
insert | 在list position 位置中插入值为val的元素 |
erase | 删除list position位置的元素 |
swap | 交换两个list中的元素 |
clear | 清空list中的有效元素 |
list创建对象的方式有很多,比如:
使用默认构造函数
使用带参构造函数
使用拷贝构造函数
使用赋值运算符重载
使用迭代器区间进行构造
创建匿名对象
代码⬇️ ⬇️:
//无参构造
list<int> lt1;
//有参数构造
list<int> lt2(4, 5);
//迭代器区间进行构造
llist<int> lt3(lt2.begin(), lt2.end());
//拷贝构造
list<int> lt4(lt3);
//赋值运算符重载
list<int> lt5 = lt4;
与vector、string不同,list由于空间不连续,不支持用[]进行访问数据。所以list的遍历方式只有迭代器和范围for两种。
代码⬇️ ⬇️:
list<int> lt1(4,5);
//迭代器进行遍历
list<int>::iterator it = lt1.begin();
while (it != lt1.end())
{
cout << *it << " ";
it++;
}
cout << endl;
//范围for进行遍历
for (auto e : lt1)
{
cout << e << " ";
}
cout << endl;
在list中插入并不存在迭代器失效的问题,因为list的插入不会改变它原有的空间。但是list的删除会造成迭代器失效,而且失效的部分是指向了被删除的空间迭代器,其他部分的迭代器不会有所影响。
和vector一样,erase使用了返回新迭代器的方式来避免失效。
注意❗️ ❗️
迭代器有两种实现方式,具体应根据容器底层数据结构实现:
1. 原生态指针,比如:vector的迭代器就是原生态指针
2. 将原生态指针进行封装,因迭代器使用形式与指针完全相同,因此在自定义的类中必须实现以下方法:
1、指针解引用,重载operator*()
2、 指针->访问其所指空间成员,重载oprator->()
3.、指针可以++向后移动,迭代器类中必须重载operator++()与operator++(int)至于operator–()/operator–(int)释放需要重载,根据具体的结构来抉择,双向链表可以以向前 移动,所以需要重载,如果是forward_list就不需要重载。
4、 迭代器需要进行是否相等的比较,因此还需要重载operator==()与operator!=()
这里我们来实现一个简易的vector⬇️ ⬇️:
//结点
_Tp _data;
_list_node<_Tp>* _next;
_list_node<_Tp>* _prev;
//构造函数
_list_node(const _Tp& val = _Tp())
//迭代器
typedef _list_node<_Tp> Link_type;
typedef _list_iterator<_Tp, Ref,Ptr> self;
//引用
typedef Ref reference;
typedef const Ref const_reference;
//指针
typedef Ptr pointer;
typedef const Ptr const_pointer;
//构造函数
_list_iterator(Link_type* pnode = nullptr)
_list_iterator(const self& lt)
//重载
reference operator*()
pointer operator->()
const_reference operator*()const
const_pointer operator->()const
bool operator!=(const self& x)const
bool operator==(const self& x)const
self& operator++()
self operator++(_Tp)
self& operator--()
self operator--(_Tp)
//list
typedef _list_node<_Tp> Link_type;
typedef _list_iterator<_Tp,_Tp&,_Tp*> iterator;
typedef _list_iterator<_Tp,const _Tp&,const _Tp*> const_iterator;
private:
Link_type* _head;
void Creatphead()
public:
//迭代器
iterator begin()
iterator end()
const_iterator cbegin()const
const_iterator cend()const
//构造函数
_list()
template<class InputIterator>
_list(InputIterator first, InputIterator last)
_list(int n, const _Tp& val = _Tp())
_list(const _list<_Tp>& lt)
_list& operator=(const _list<_Tp>& lt)
//插入删除修改
void push_back(const _Tp& val)
void push_front(const _Tp& val)
void pop_back()
void pop_front()
iterator insert(iterator pos, const _Tp& val = _Tp())
void insert(iterator pos,int n, const _Tp& val )
template<class InputIterator>
void insert(iterator pos,InputIterator first, InputIterator last)
iterator erase(iterator pos)
iterator erase(iterator first, iterator last)
//其他接口
bool empty()
size_t size()const
void clear()
void swap(_list<_Tp>& lt)
完整代码⬇️ ⬇️:
#include
#include
using std::cin;
using std::cout;
using std::endl;
namespace lz
{
//封装结点
template<class _Tp>
struct _list_node
{
public:
_Tp _data;
_list_node<_Tp>* _next;
_list_node<_Tp>* _prev;
_list_node(const _Tp& val = _Tp())
:_data(val)
,_next(nullptr)
, _prev(nullptr)
{}
};
//封装迭代器
template<class _Tp,class Ref,class Ptr>
struct _list_iterator
{
typedef _list_node<_Tp> Link_type;
typedef _list_iterator<_Tp, Ref,Ptr> self;
//引用
typedef Ref reference;
typedef const Ref const_reference;
//指针
typedef Ptr pointer;
typedef const Ptr const_pointer;
Link_type* _pnode;
_list_iterator(Link_type* pnode = nullptr)
:_pnode(pnode)
{}
_list_iterator(const self& lt)
:_pnode(lt._pnode)
{}
reference operator*() { return _pnode->_data; }
pointer operator->() { return &(operator*()); }
const_reference operator*()const { return _pnode->_data; }
const_pointer operator->()const { return &(operator*()); }
bool
operator!=(const self& x)const { return _pnode != x._pnode; }
bool
operator==(const self& x)const { return _pnode == x._pnode; }
//前置自增
self& operator++()
{
_pnode = _pnode->_next;
return *this;
}
//后置自增
self operator++(_Tp)
{
Link_type* tmp = _pnode;
_pnode = _pnode->_next;
return tmp;
}
//前置自减
self& operator--()
{
_pnode = _pnode->_prev;
return *this;
}
//后置自减
self operator--(_Tp)
{
Link_type* tmp = _pnode;
_pnode = _pnode->_prev;
return tmp;
}
};
//封装结点和迭代器
template<class _Tp>
struct _list
{
typedef _list_node<_Tp> Link_type;
typedef _list_iterator<_Tp,_Tp&,_Tp*> iterator;
typedef _list_iterator<_Tp,const _Tp&,const _Tp*> const_iterator;
private:
Link_type* _head;
void Creatphead()//创建头指针
{
_head = new Link_type;
_head->_next = _head;
_head->_prev = _head;
}
public:
//迭代器
iterator begin() { return _head->_next; }
iterator end() { return _head; }
const_iterator cbegin()const{ return _head->_next; }
const_iterator cend()const { return _head; }
//无参构造
_list()
{
Creatphead();
}
//迭代器区间构造
template<class InputIterator>
_list(InputIterator first, InputIterator last)
{
Creatphead();
while (first != last)
{
push_back(*first);
first++;
}
}
//int 不能用size_t,否则会撞!!!???
//类型不一致,会调用上面的模板迭代器区间
_list(int n, const _Tp& val = _Tp())
{
Creatphead();
while (n)
{
push_back(val);
n--;
}
}
//拷贝构造函数
_list(const _list<_Tp>& lt)
{
Creatphead();
/*const_iterator it = lt.cbegin();
while (it != lt.cend())
{
push_back(*it);
it++;
}*/
//现代写法
_list tmp(lt.cbegin(), lt.cend());
swap(tmp);
}
//析构函数
~_list()
{
clear();
delete _head;
_head = nullptr;
}
//赋值运算符重载
_list<_Tp>& operator=(const _list<_Tp>& lt)
{
_list<_Tp> tmp(lt);
swap(tmp);
}
//尾插
void push_back(const _Tp& val)
{
//Link_type* new_node = new Link_type;
//new_node->_data = val;
之前的尾
//Link_type* tail = _head->_prev;
//tail->_next = new_node;
//new_node->_prev = tail;
//new_node->_next = _head;
//_head->_prev = new_node;
//代码复用
insert(end(), val);
}
//头插
void push_front(const _Tp& val)
{
//Link_type* new_node = new Link_type;
//new_node->_data = val;
//Link_type* pnext = _head->_next;
连接结点
//_head->_next = new_node;
//new_node->_prev = _head;
//new_node->_next = pnext;
//pnext->_prev = new_node;
//代码复用
insert(begin(), val);
}
//尾删
void pop_back()
{
/*
if (!empty())
{
Link_type* last = _head->_prev;
Link_type* prev = last->_prev;
prev->_next = _head;
_head->_prev = prev;
delete last;
}*/
//代码复用
erase(--end());
}
//头删
void pop_front()
{
/* if (!empty())
{
Link_type* first = _head->_next;
Link_type* second = first->_next;
_head->_next = second;
second->_prev = _head;
delete first;
}*/
//代码复用
erase(begin());
}
//任意位置插入一个数据
iterator insert(iterator pos, const _Tp& val = _Tp())
{
Link_type* new_node = new Link_type;
new_node->_data = val;
Link_type* pprev = pos._pnode->_prev;
//插入新节点
pprev->_next = new_node;
new_node->_prev = pprev;
new_node->_next = pos._pnode;
pos._pnode->_prev = new_node;
return pos++;
}
//int 不能用size_t,否则会撞!!!???
//类型不一致,会调用上面的模板迭代器区间
//任意位置插入多个数据
void insert(iterator pos,int n, const _Tp& val )
{
iterator it = pos;
while (n)
{
it = insert(it, val);
n--;
}
}
//任意位置插入一个迭代器区间的数据
template<class InputIterator>
void insert(iterator pos,InputIterator first, InputIterator last)
{
iterator it = pos;
while (first != last)
{
it = insert(it,*first);
first++;
}
}
//任意位置删除一个数据***
iterator erase(iterator pos)
{
Link_type* pdel = pos._pnode;
Link_type* pnext = pdel->_next;
Link_type* pprev = pdel->_prev;
//如果为空就不用进行删除操作,同时不能删除头结点
if (!empty() && pdel != _head)
{
pprev->_next = pnext;
pnext->_prev = pprev;
delete pdel;
}
return pnext;
}
//删除一个迭代器区间的数据[first, last)
iterator erase(iterator first, iterator last)
{
iterator it = first;
while (it != last)
{
it = erase(it);
}
return last++;
}
//判空
bool empty()
{
return _head->_next == _head;
}
//计算个数
size_t size()const
{
size_t count = 0;
iterator it = begin();
while (it != end())
{
count++;
it++;
}
return count;
}
//清除
void clear()
{
erase(begin(), end());
}
//交换
void swap(_list<_Tp>& lt)
{
std::swap(_head,lt._head);
}
};
}
//打印函数
template<class T>
void PrintCon(const lz::_list<T>& con)
{
auto it = con.cbegin();
while (it != con.cend())
{
cout << *it << " ";
it++;
}
cout << endl;
}
void Test1()//构造函数
{
//无参构造
lz::_list<int> lt1;
PrintCon(lt1);
//存入多个数据
lz::_list<int> lt2(4, 5);
PrintCon(lt2);
//迭代器区间
lz::_list<int> lt3(lt2.begin(), lt2.end());
PrintCon(lt3);
//拷贝构造
lz::_list<int> lt4(lt3);
PrintCon(lt4);
//=重载
lz::_list<int> lt5 = lt4;
PrintCon(lt5);
}
void Test2()//insert+erase(避免迭代器失效)
{
lz::_list<int> lt1(4, 5);
lz::_list<int> lt2(4, 1);
//找到尾,插入数据
lz::_list_iterator<int, int&, int*> it1 = lt1.end();
//插入单个数据
it1 = lt1.insert(it1, '!');
it1 = lt1.insert(it1, 'a');
PrintCon(lt1);
//插入多个数据
lt1.insert(lt1.begin(), 4, 6);
PrintCon(lt1);
//将lt2中的数据插入lt1中
lt1.insert(it1,lt2.begin(),lt2.end());
PrintCon(lt1);
;
//删除任意位置数据
it1 = lt1.erase(it1);//此时的位置是头结点,不能删除
it1 = lt1.erase(it1);
PrintCon(lt1);
//删除迭代器区间的数据[first, last)
lt1.erase(lt1.begin(),lt1.end());
PrintCon(lt1);
}
void Test3()//push_back+push_front+pop_back+pop_front
{
lz::_list<int> lt1;
PrintCon(lt1);//无数据打印
lt1.push_back(2);
lt1.push_back(1);
lt1.push_front(3);
lt1.push_front(4);
PrintCon(lt1);
//测试删完后的处理
lt1.pop_back();
//lt1.pop_back();
//lt1.pop_back();
lt1.pop_front();
//lt1.pop_front();
//lt1.pop_front();
PrintCon(lt1);
}
int main()
{
Test3();
return 0;
}