list
list支持任意位置以O(1)的时间复杂度进行插入和删除,list的底层是一个双向带头循环链表。
list与vector的比较
- list与vector都支持insert和erase,list在任意位置插入删除时间复杂度都是O(1).vector只有在尾部插入删除时间复杂度是O(1),在其他位置插入删除时间复杂度是O(N)
- list提供了push_back,push_front,pop_back,pop_front的接口,而vector提供了push_back和pop_back的接口,没有提供push_front和pop_front的接口,因为vector的pop_front和push_front时间复杂度是O(N)效率太低
- list和vector都提供了insert和erase,list的insert和erase时间复杂度是O(1),vector的insert和erase在一般位置时间复杂度是O(N).
- list底层在物理空间上是不连续的,vector底层在物理空间上是连续的。
- vector支持使用下标和
[]
进行访问,list只能使用迭代器访问,因为它的底层是一个个节点链接起来的,物理空间不连续 - vector没有提供内置的排序函数,因为vector可以直接使用algorithm里面的sort。list提供了内置的排序函数,list::sort底层是使用的归并排序的非递归,但是list::sort效率很低,一般需要排序不会使用list结构。list不能使用algorithm里面的sort,std::sort底层使用的快排,只适用于连续的物理空间,例如vector和string.
- vector的迭代器是原生指针,原生指针的功能在vector里面就够用。list的迭代器是一个自定义类型的类,类里面的成员变量是指向结点的指针,在类里面重载了
operator*,operator->,operator!=,operator==
等操作,让自定义类型的迭代器可以像指针一样进行操作。
list的迭代器
-
list的迭代器是一个自定义类型的结构体,只有一个成员变量node*,是指向结点的指针,有多个重载的成员函数,用于控制迭代器的行为,能够让迭代器像原生指针一样使用。
-
自定义类型的结构体不能直接使用运算符,但是list_iterator里面的成员变量pnode是可以直接使用运算符的。虽然list_iterator里面只有一个成员变量,但它依然是一个自定义类型,不是指针类型,不能把list_iterator和指针等价
-
由于node是一个模板,list_iterator里面的成员变量是
node<T>*
,所以list_iterator也必须是一个模板。 -
list_iterator有三个模板,
template<class T,class Ref,class Ptr>
,通过将这3个模板进行不同的实例化可以让list_iterator这个模板类实例化出不同行为的迭代器。 -
typedef list_iterator<T,const T&,const T*> const_iterator,typedef list_iterator<T,T&,T*> iterator
.const_iterator和iterator是一个类模板实例化出来的2个不同的类。它们的成员变量是一样的类型,但是成员函数不一样。 -
Ref operator*() const { return pnode->data; }
当Ref时const T&时,对应const_iterator.Ref为T&,对应iterator。普通迭代器和const迭代器都是普通属性的迭代器,可以调用普通成员函数和const成员函数。const const_iterator和const iterator是const属性的迭代器,只能调用const成员函数。
-
成员函数后面的const修饰的是*this,表示成员变量pnode不能改变,但是pnode指向的内容可以改变。在
operator*()
后面可以加const,普通属性的迭代器也可以调用,而且也能返回T&。const const_iterator和const iterator都能调用operator*()
,const const_iterator调用operator*()const
返回的是const T&,const iterator调用operator*()const
返回的是T& -
operator*()
对于const属性的迭代器和非const属性的迭代器都能调用,const属性的迭代器和非const属性的迭代器区别是它们的成员变量pnode能否被直接修改。 -
普通list对象使用普通迭代器,普通迭代器可以实现对成员变量的读写操作。
-
const修饰的list对象使用const_iterator,const_iterator也能++和–,const_iterator++和–返回的是const_iterator。iterator的++和–返回iterator,它们是2个不同的类
-
通过模板实例化能控制list_iterator的行为。让其表现出iterator和const_iterator的效果。
-
const list<int> l,l中pnode不能修改,但是pnode指向的对象可以被修改
-
const修饰
list<int> l
,l的成员变量不能直接被修改,l也不能调用普通成员函数。
模拟实现
#pragma once
#include <iostream>
#include <assert.h>
namespace slowstep
{
template <typename T>
struct list_node
{
//list_node的默认构造
list_node(const T &d = T()) : data(d), next(nullptr), prev(nullptr) {}
//成员变量
list_node<T> *next;
list_node<T> *prev;
T data;
};
template <class T, class Ref, class Ptr>
struct list_iterator
{
typedef list_node<T> node;
typedef list_iterator<T, Ref, Ptr> iterator;
//成员变量
node *pnode;
//通过节点的指针构造
list_iterator(node *p) : pnode(p) {}
//特殊构造函数
list_iterator(const list_iterator<T,T&,T*>& it):pnode(it.node){}
list_iterator(const list_iterator<T,const T&,const T*>& it):pnode(it.node){}
/*
这2个构造函数可以用普通迭代器构造const迭代器,也能用const迭代器构造普通迭代器.
*/
Ref operator*() const
{
return pnode->data;
}
//当list里面存放结构体时,可以使用迭代器+一个箭头访问就结构体成员.编译器做了特殊处理隐藏了一个箭头
Ptr operator->() const
{
return &(pnode->data);
}
bool operator==(const iterator &it) const
{
return it.pnode == pnode;
}
bool operator!=(const iterator &it) const
{
return it.pnode != pnode;
}
iterator &operator++()
{
pnode = pnode->next;
return *this;
}
iterator operator++(int)
{
iterator tmp = *this;
pnode = pnode->next;
return tmp;
}
iterator &operator--()
{
pnode = pnode->prev;
return *this;
}
iterator operator--(int)
{
iterator tmp = *this;
pnode = pnode->prev;
return tmp;
}
};
template <class T>
class list
{
typedef list_node<T> node;
public:
typedef list_iterator<T, T &, T *> iterator;//普通迭代器
typedef list_iterator<T, const T &, const T *> const_iterator;//const迭代器
list()
{
_head = new node;
_head->next = _head;
_head->prev = _head;
}
list(size_t n, const T &val = T())
{
_head = new node;
_head->next = _head;
_head->prev = _head;
while (n--)
push_back(val);
}
list(int n, const T &val = T())
{
_head = new node;
_head->next = _head;
_head->prev = _head;
while (n--)
push_back(val);
}
template <class Inputiterator>//迭代器区间的构造函数使用模板,支持泛型
list(Inputiterator first, Inputiterator last)
{
_head = new node;
_head->next = _head;
_head->prev = _head;
while (first != last)
{
push_back(*first);
first++;
}
}
list(const list<T> &l) : _head(nullptr)//拷贝构造
{
_head = new node;
_head->next = _head;
_head->prev = _head;
list<T> tmp(l.begin(), l.end());
std::swap(tmp._head, _head);
}
list<T> &operator=(const list<T> &l)
{
list<T> tmp(l);
std::swap(tmp._head, _head);
return *this;
}
iterator begin()
{
return iterator(_head->next);
}
iterator end()
{
return iterator(_head);
}
const_iterator begin() const
{
return const_iterator(_head->next);
}
const_iterator end() const
{
return const_iterator(_head);
}
iterator insert(const iterator &pos, const T &val)
{
node *prev = pos.pnode->prev;
node *newnode = new node(val);
prev->next = newnode;
newnode->prev = prev;
newnode->next = pos.pnode;
pos.pnode->prev = newnode;
return iterator(newnode);
}
iterator erase(const iterator &pos)
{
assert(pos.pnode != _head);
node *prev = pos.pnode->prev;
node *next = pos.pnode->next;
delete pos.pnode;
prev->next = next;
next->prev = prev;
return iterator(next);
}
void push_back(const T &val)
{
insert(iterator(_head), val);
}
void push_front(const T &val)
{
insert(iterator(_head->next), val);
}
void pop_back()
{
erase(iterator(_head->prev));
}
void pop_front()
{
erase(iterator(_head->next));
}
const T &front() const
{
return _head->next->data;
}
T &front()
{
return _head->next->data;
}
const T &back() const
{
return _head->prev->data;
}
T &back()
{
return _head->prev->data;
}
bool empty() const
{
return _head->next == _head;
}
size_t size() const
{
size_t ans = 0;
const_iterator it = begin();
while (it != end())
{
ans++;
it++;
}
return ans;
}
void swap(list<T> &l)
{
std::swap(_head, l._head);
}
void clear()
{
if (_head->next == _head)
return;
node *prev = _head->next;
node *cur = prev->next;
while (cur != _head)
{
delete prev;
prev = cur;
cur = cur->next;
}
delete prev;
_head->next = _head;
_head->prev = _head;
}
void reverse()
{
node *l = _head->next;
node *r = _head->prev;
while (l != r && l->next != r)
{
std::swap(l->data, r->data);
l = l->next;
r = r->prev;
}
if (l->next == r)
std::swap(l->data, r->data);
}
void remove(const T &val)
{
iterator it = begin();
while (it != end())
{
if (*it == val)
it = erase(it);
else
it++;
}
}
~list()
{
clear();
delete _head;
_head = nullptr;
}
private:
node *_head;
};
}