个人主页:点我进入主页
专栏分类:C语言初阶 C语言进阶 数据结构初阶 Linux C++初阶 算法
欢迎大家点赞,评论,收藏。
一起努力,一起奔赴大厂
一.list简介
list是一个带头双向链表,在数据结构的时候,我写过关于带头双向循环链表的实现,可以看博客https://yangking.blog.csdn.net/article/details/134495668,我们可以看下面的图,是list的存储结构,
本次的内容包括list的使用,list的模拟实现,list的迭代器以及反向迭代器的原理,模拟实现和使用,最重要的是迭代器和反向迭代器的内容,在前面string和vector中迭代器是原生的指针,但是在这里不是,具体是什么样子的我们可以看后面的内容。
二.一个简易的list
2.1.单个节点
template<class T>
struct ListNode
{
typedef ListNode<T> Node;
Node* _next;
Node* _prev;
T _data;
ListNode(const T& val = T())
: _next(nullptr)
, _prev(nullptr)
, _data(val)
{}
};
在这里我们可以使用strcut结构体来创建一个节点
2.2.默认构造
void empty_init()
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
_size = 0;
}
list()
{
empty_init();
}
我们创建一个头节点, 让它指向自己。
2.3push_back
void push_back(const T& val)
{
Node* newnode = new Node(val);
Node* prev = _head._node->_prev;
Node* cur = _head._node;
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = cur;
cur->_prev = newnode;
_size++;
}
在这里我们就是简单的插入操作,不给具体的解释。到这里我们简易的list就完成了,我们依次插入1234可以看到
void test()
{
list<int> l;
l.push_back(1);
l.push_back(2);
l.push_back(3);
l.push_back(4);
}
三.迭代器
我们封装一个迭代器的类,我们的迭代器需要支持
list<int>::iterator it = lt1.begin();
while (it != lt1.end())
{
cout << *it << " ";
++it;
}
cout << endl;
所以我们里面需要包括!=,*it,++it,以及begin和end这些内容,我们需要知道迭代器模仿的是Node*这个行为,我们看一下模拟代码:
template <class T>
struct ListIterator
{
typedef ListNode<T> Node;
typedef ListIterator<T> Self;
Node* _node;
ListIterator(Node* node)
:_node(node)
{}
bool operator==(const Self& it)
{
return _node == it._node;
}
bool operator!=(const Self& it)
{
return _node != it._node;
}
Self& operator--()
{
_node = _node->_prev;
return *this;
}
Self operator--(int)
{
Self tmp(_node);
_node = _node->_prev;
return *tmp;
}
Self& operator++()
{
_node = _node->_next;
return *this;
}
Self operator++(int)
{
Self tmp(_node);
_node = _node->_next;
return tmp;
}
T& operator*()
{
return _node->_data;
}
};
我们在list类里面加入
iterator begin()
{
return _head->_next;
}
iterator end()
{
return _head;
}
我们运行测试代码
void test()
{
list<int> l;
l.push_back(1);
l.push_back(2);
l.push_back(3);
l.push_back(4);
list<int>::iterator it = l.begin();
while (it != l.end())
{
cout << *it << " ";
it++;
}
cout << endl;
}
运行结果为
四.insert和erase以及复用
4.1insert
在这里我们的insert用迭代器进行插入,给以个位置,插入它的前面,
我们的代码如下:
void insert(iterator pos, const T& val)
{
Node* newnode = new Node(val);
Node* prev = pos._node->_prev;
Node* cur = pos._node;
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = cur;
cur->_prev = newnode;
_size++;
}
有了我们的insert我们的push_back可以复用我们的insert,可以改为
void push_back(const T& val)
{
insert(end(), val);
}
在这里我们的insert不会造成迭代器失效,因为指针指向的位置不会发生改变,它是插入到pos位置的前面。
4.2erase以及迭代器失效
对于返回值为什么是iterator,这和我们的迭代器失效有关,我们先用void来展示其中的问题。
void erase(iterator pos)
{
Node* prev = pos._node->_prev;
Node* next = pos._node->_next;
delete pos._node;
prev->_next = next;
next->_prev = prev;
_size--;
}
我们的测试代码如下:
void test()
{
list<int> l;
l.push_back(1);
l.push_back(2);
l.push_back(3);
l.push_back(4);
list<int>::iterator it = l.begin();
while (it != l.end())
{
if (*it % 2 == 0) l.erase(it);
else it++;
}
it = l.begin();
while (it != l.end())
{
cout << *it << " ";
it++;
}
cout << endl;
}
在这里会出现错误,原因是迭代器失效,野指针的引用,所以我们需要对迭代器进行维护,所以有了返回值,我们改为
iterator erase(iterator pos)
{
Node* prev = pos._node->_prev;
Node* next = pos._node->_next;
delete pos._node;
prev->_next = next;
next->_prev = prev;
_size--;
return next;
}
4.3复用
有了这两个,我们的pop_back,pop_front,push_front就可以有了
void pop_back()
{
erase(--end());
}
void pop_front()
{
erase(begin());
}
void push_front(const T& val)
{
insert(begin(), val);
}
五.operator->()
我们的T是一个结构体
struct A
{
int a = 1;
int b = 2;
};
void test()
{
list<A> l;
l.push_back({ 1,2 });
l.push_back({ 2,3 });
l.push_back({ 3,4 });
l.push_back({ 4,5 });
list<A>::iterator it = l.begin();
while (it != l.end())
{
/* cout << (*it).a << " " << (*it).b << endl;*/
cout << it._node->_data.a << " " << it._node->_data.b << endl;
it++;
}
}
我们的解引用是不是看的非常难受,所有我们需要operator一下,
T* operator->()
{
return &_node->_data;
}
我们改为
cout << it->a << " " << it->b << endl;
六.const迭代器
有了我们的非const版本的,那么我们就需要我们的const版本的,const版本就是将所有的都复制一份,然后operator*返回const的
template <class T>
struct ListConstIterator
{
typedef ListNode<T> Node;
typedef ListConstIterator<T> Self;
Node* _node;
ListConstIterator(Node* node)
:_node(node)
{}
bool operator==(const Self& it)
{
return _node == it._node;
}
bool operator!=(const Self& it)
{
return _node != it._node;
}
Self& operator--()
{
_node = _node->_prev;
return *this;
}
Self operator--(int)
{
Self tmp(_node);
_node = _node->_prev;
return *tmp;
}
Self& operator++()
{
_node = _node->_next;
return *this;
}
Self operator++(int)
{
Self tmp(_node);
_node = _node->_next;
return tmp;
}
const T& operator*()
{
return _node->_data;
}
const T* operator->()
{
return &_node->_data;
}
};
由于这个会和非fonst很多内容一样,会造成代码冗余,所以我们可以利用模板来简化我们的代码,我们非const的代码函数的返回值为Self,T&,T*,const版本的是Self,const T&,const T*,所以我们可以写成模板
template <class T,class Ref,class Ptr>
struct ListIterator
{
typedef ListNode<T> Node;
typedef ListIterator< T, Ref, Ptr> Self;
Node* _node;
ListIterator(Node* node)
:_node(node)
{}
bool operator==(const Self& it)
{
return _node == it._node;
}
bool operator!=(const Self& it)
{
return _node != it._node;
}
Self& operator--()
{
_node = _node->_prev;
return *this;
}
Self operator--(int)
{
Self tmp(_node);
_node = _node->_prev;
return *tmp;
}
Self& operator++()
{
_node = _node->_next;
return *this;
}
Self operator++(int)
{
Self tmp(_node);
_node = _node->_next;
return tmp;
}
Ref operator*()
{
return _node->_data;
}
Ptr operator->()
{
return &_node->_data;
}
};
我们在list类里面写入
typedef ListIterator<T,T&,T*> iterator;
typedef ListIterator<T,const T&,const T*> const_iterator;
这样我们由我们自己写改为了编译器去写。
七.反向迭代器
我们的反向得带起是使用正向迭代器进行写的,它的rbegin是正向迭代器的end,rend是正向迭代器的begin,所以它的operator*是解引用前一个的。
template <class Iterator, class Ref, class Ptr>
struct ReverseIterator
{
typedef ReverseIterator<Iterator, Ref, Ptr> Self;
Iterator _it;
ReverseIterator(Iterator it)
:_it(it)
{}
Ref operator*()
{
Iterator tmp = _it;
--tmp;
return *tmp;
}
Ptr operator->()
{
return _it.operator->();
}
Self rbegin()
{
return ReverseIterator(_it.end());
}
Self rend()
{
return ReverseIterator(_it.begin());
}
Self operator++()
{
--_it;
return *this;
}
Self operator++(int)
{
Iterator tmp = _it;
--_it;
return tmp;
}
Self operator--()
{
++_it;
return *this;
}
Self operator--(int)
{
Iterator tmp = _it;
tmp = _it;
++_it;
return tmp;
}
bool operator!=(Self it)
{
return _it != it._it;
}
};
到这里我们的内容结束了。