STL —— list

博主首页: 有趣的中国人
专栏首页: C++专栏
1. list简介
列表(list)是C++标准模板库(STL)中的一个容器,它是一个双向链表数据结构,用于存储元素。与vector不同,列表中的元素在内存中不是连续存储的,而是通过指针相互连接形成链表。这种设计使得列表对于插入和删除操作非常高效,但是在查找特定元素时相对较慢,因为需要按序遍历整个链表。
2. list模拟实现
2.1 list类的相关成员变量
在C++的标准库中,list的实现方式是带头双向循环链表,因此在类中,我们需要一个头指针_head。至于每个节点,我们也同样需要构造一个类,其中成员变量包含_prev, _next和数据_val。
template
struct ListNode
{
ListNode* _prev;
ListNode* _next;
T _val;
ListNode(const T& x = T())
:_prev(nullptr)
,_next(nullptr)
,_val(x)
{}
};
template
class list
{
public:
typedef ListNode Node;
list()
{
_head = new Node;
_head->_prev = _head;
_head->_next = _head;
}
private:
Node* _head;
};
2.2 尾插
尾插太简单了,直接上代码:
void push_back(const T& x)
{
Node* newnode = new Node(x);
Node* tail = _head->_prev;
tail->_next = newnode;
newnode->_prev = tail;
newnode->_next = _head;
_head->_prev = newnode;
}
2.3 迭代器
在库中,我们不管迭代器的底层是如何实现的,但是我们都要用相同的方法使用迭代器,例如之前讲过的 vector,string,在g++中的实现方法就是原生指针,来实现例如++、--、*等功能,但是这里list由于不是连续存储的,所以用原生指针正常的++、--等功能并不能达到我们的预期,因此我们可以把迭代器搞成一个类类型,并用运算符重载来改变它的功能。
下面的代码是迭代器正常的使用方法,我们需要用运算符重载来实现这些功能:void list_test1()
{
list lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);
list::iterator it = lt.begin();
while (it != lt.end())
{
cout
typedef ListNode}
};
typedef ListNode}
T& operator*()
{
return _node-_val;
}
Self& operator++()
{
_node = _node-_next;
return *this;
}
Self operator++(int)
{
Self tmp(*this);
_node = _node-_next;
return tmp;
}
Self& operator--()
{
_node = _node->_prev;
return *this;
}
Self operator--(int)
{
Self tmp(*this);
_node = _node->_prev;
return tmp;
}
bool operator!=(const Self& it)
{
return _node != it._node;
}
};
2.3.3 insert 和 erase
insert和erase传的参数就是iterator,模拟实现代码如下:
void insert(iterator pos, const T& x)
{
Node* newnode = new Node(x);
Node* cur = pos._node;
Node* prev = cur->_prev;
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = cur;
cur->_prev = newnode;
}
void erase(iterator pos)
{
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
prev->_next = next;
next->_prev = prev;
delete cur;
cur = nullptr;
}
这里需要注意,在erase的时候由于迭代器指向的空间被释放了,会导致迭代器失效的问题,之前的文章讲过相关的内容,因此我们需要更新iterator,指向被删除的位置的下一个位置即可,代码如下:
iterator erase(iterator pos)
{
Node* cur = pos._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
prev->_next = next;
next->_prev = prev;
delete cur;
cur = nullptr;
return next;
}
2.3.4 begin 和 end
begin 和 end是在迭代器中的成员函数,返回头和尾的迭代器即可:
typedef ListNodeIterator iterator;
iterator begin()
{
return iterator(_head->_next);
// 单参数类型的构造函数支持隐式类型转换,以下依法也可以:
// return _head->_next;
}
iterator end()
{
return iterator(_head);
// return _head;
}
2.3.5 insert 和 erase的复用
push_back、push_front、pop_back、pop_front都可以复用insert和erase,代码如下:
void push_back(const T& x)
{
/*Node* newnode = new Node(x);
Node* tail = _head->_prev;
tail->_next = newnode;
newnode->_prev = tail;
newnode->_next = _head;
_head->_prev = newnode;*/
insert(end(), x);
}
void pop_back()
{
erase(--end());
}
void push_front(const T& x)
{
insert(begin(), x);
}
void pop_front()
{
erase(begin());
}
测试代码:
void list_test1()
{
list lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);
list::iterator it = lt.begin();
while (it != lt.end())
{
cout
cout
cout
cout
struct A
{
int _a1;
int _a2;
A(int a1 = 0, int a2 = 0)
:_a1(a1)
,_a2(a2)
{}
};
list 5,6 });
list
// 主要看这里
cout
return &_node-_val;
}
struct A
{
int _a1;
int _a2;
A(int a1 = 0, int a2 = 0)
:_a1(a1)
,_a2(a2)
{}
};
/*A* aa;
(*aa)._a1;
aa-_a1;*/
list 5,6 });
list
cout
list
cout
list
return iterator(_head-_next);
// 单参数类型的构造函数支持隐式类型转换,以下写法也可以:
// return _head-_next;
}
iterator end() const
{
return iterator(_head);
// return _head;
}
void Print(const list
list
// 这里可以修改
*it += 10;
cout
list
return iterator(_head-_next);
// 单参数类型的构造函数支持隐式类型转换,以下写法也可以:
// return _head-_next;
}
const iterator end()
{
return iterator(_head);
// return _head;
}
typedef ListNode}
const T& operator*()
{
return _node-_val;
}
const T* operator-()
{
return &_node-_val;
}
Self& operator++()
{
_node = _node-_next;
return *this;
}
Self operator++(int)
{
Self tmp(*this);
_node = _node-_next;
return tmp;
}
Self& operator--()
{
_node = _node-_prev;
return *this;
}
Self operator--(int)
{
Self tmp(*this);
_node = _node-_prev;
return tmp;
}
bool operator!=(const Self& it)
{
return _node != it._node;
}
};
return const_iterator(_head-_next);
// 单参数类型的构造函数支持隐式类型转换,以下写法也可以:
// return _head-_next;
}
const_iterator end() const
{
return const_iterator(_head);
// return _head;
}
typedef ListNode}
Ref operator*()
{
return _node-_val;
}
Ptr operator-()
{
return &_node-_val;
}
Self& operator++()
{
_node = _node-_next;
return *this;
}
Self operator++(int)
{
Self tmp(*this);
_node = _node-_next;
return tmp;
}
Self& operator--()
{
_node = _node-_prev;
return *this;
}
Self operator--(int)
{
Self tmp(*this);
_node = _node-_prev;
return tmp;
}
bool operator!=(const Self& it)
{
return _node != it._node;
}
};
template
public:
typedef ListNode
return iterator(_head-_next);
// 单参数类型的构造函数支持隐式类型转换,以下写法也可以:
// return _head-_next;
}
iterator end()
{
return iterator(_head);
// return _head;
}
const_iterator begin() const
{
return const_iterator(_head-_next);
// 单参数类型的构造函数支持隐式类型转换,以下写法也可以:
// return _head-_next;
}
const_iterator end() const
{
return const_iterator(_head);
// return _head;
}
// ......
};
iterator it = begin();
while (it != end())
{
it = erase(it);
}
}
~list()
{
clear();
delete _head;
_head = nullptr;
}
_head = new Node;
_head-_prev = _head;
_head-_next = _head;
}
list(const list
empty_init();
for (auto& e : lt)
{
push_back(e);
}
}
std::swap(_head, lt._head);
}
list
swap(lt);
return *this;
}
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!
