c++之stl_list
文章目录
一、list的内存结构
在cpp中,list容器是双向链表,对应c#中的LinkedList。链表的内存是不连续的,通过节点(node)串起来。
- 优点:
- 高效插入删除。只需对指针进行操作,不需要拷贝元素。
- 不需要连续内存,就可以完成动态操作。增加元素,即增加节点。
- 缺点:
- 不支持随机访问,即索引器,[]操作符。
- 需要额外内存来维护node节点。
接下来看看list是怎样设计的。
从图中可以看出,list不仅是双向的,还是环状的。整个list是由node串起来的,node里有两根指针,prev、next,以及一个data。prev指向前一个node,next指向后一个node。end()里没有data,这是为了遵循前闭后开原则,stl里其他容器也是一样。
二、具体实现
1. list的node
template <typename T>
struct list_node
{
typedef list_node<T> *node_ptr;
typedef T value_type;
value_type data;
node_ptr prev;
node_ptr next;
list_node(const value_type &val) : data(val), prev(NULL), next(NULL) {
}
};
2. list的迭代器
template <typename T>
struct list_iterator {
list_node<T> node;
//......
ref operator*() const {
return node->data;}
ptr operator->() const {
return &(operator*());}
self &operator++(){
node = node->next; return *this;}
self &operator--(){
node = node->prev; return *this}
bool &operator==(cosnt self &ths){
return node == ths.node};
//......
};
struct reverse_list_iterator {
/* ..... */};
由于list的内存空间不连续,无法直接使用指针操作,所以必须重载++、--操作符,且不提供[]操作符。++操作其实就是将迭代器中的node指向下一个node,很容易理解。为了让迭代器能像指针一样使用,需要对*、->操作符进行重载,使其能够轻松获取到node中的data。操作符重载是cpp重要的一部分,虽然设计起来比较麻烦,但是能够让使用者用得很舒服。
3. list的常用方法
void push_back(const value_type &val);//后端插入
void push_front(const value_type &val);//前端插入
void insert(iterator positon, const value_type &val);//任意一个位置插入
void pop_front();//前端删除
void pop_back();//后端删除
void remove(const value_type &val);//删除所有指定元素
iterator earse(iterator position);//删除任意一个节点
void clear();//清空容器
list只需要一根node指针,一般称作为head(里面不装data,仅作为标记使用,为了遵循前闭后开区间的原则),配合iterator,就可以管理整个链表。操作list、iterator中的node指针,可以很快、很轻松的完成插入删除、操作。
4. 完整代码
为了保证简洁,可以忽略reverse iterator部分,本文reverse iterator的实现不妥,应采用迭代器适配器(iterator adaptor)来实现。
#if !defined(_M_LIST_)
#define _M_LIST_
#include <memory>
namespace learnCpp
{
template <typename T>
struct list_node
{
typedef list_node<T> *node_ptr;
typedef T value_type;
public:
value_type data;
node_ptr prev;
node_ptr next;
list_node() : prev(NULL), next(NULL) {
}
list_node(const value_type &val) : data(val), prev(NULL), next(NULL) {
}
};
template <typename T>
struct list_iterator
{
protected:
typedef T value_type;
typedef T *ptr;
typedef T &ref;
typedef list_iterator<T> self;
typedef list_node<T> *link_type;
public:
link_type node;
list_iterator(link_type node