目录
-
list相较于vector连续的线性空间就显得很复杂,他的存储空间是不连续的,好处是每次插入和删除一个元素的时候,只需要配置或者释放一个元素的空间
- 插入和删除十分的方便
list的节点(node)
- list 本身和list的节点是不同的结构,需要分开设计
- list节点结构是一个双向的链表
template <class T>
struct __list_node{
typedef void* void_pointer;
void_pointer prev; //指针的类型是void*,其实可以将其设定为 __list_node<T>
void_pointer next;
T data;
};
list迭代器
- list迭代器不能像vector一样使用普通的指针,因为考虑到内存分配的不连续性,list的迭代器必须有能力指向list的的节点,并正确的进行递增、递减、取值(获取成员节点的数据值)、成员的存取(取用的是节点的成员)等操作
- 因为list的迭代器具备前移和后移的能力,所以使用Bidirectional iterators
- list的插入和接合操作(splice)都不会造成原有的list迭代器失效,vector不可以,因为vector插入操作可能造成记忆体的重新配置,会导致原有的迭代器失效
- list删除元素(erase)也只有指向被删除元素的那个迭代器会失效,其余的迭代器不会受到任何的影响
- list迭代器设计如下
//list的迭代器设计
template <class T,class Ref,class Ptr>
struct __list_iterator{
typedef __list_iterator<T,T&,T*> iterator;
typedef __list_iterator<T,Ref,Ptr> self;
typedef std::bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef __list_node<T>* link_type;
typedef std::size_t size_type;
typedef ptrdiff_t difference_type;
link_type node;//迭代器内部需要一个普通的指针,指向list节点
//constructor
__list_iterator(){}
__list_iterator(link_type x):node(x){}
__list_iterator(const iterator& x):node(x.node){}
bool operator==(const self& x) const{return (node == x.node);}
bool operator!=(const self& x) const{return (node != x.node);}
//以下对迭代器取值 取得的是节点的数据值
reference operator*() const {return (*node).data;}
//以下是对迭代器的成员进行存取 (member access) 运算子的标准做法
pointer operator->() const {return &(operator*());}
//对迭代器进行加一 前进一个节点
self& operator++(){
node = (link_type)((*node).next);
}
self operator++(int){
self tmp = *this;
++*this;
return tmp;
}
//对迭代器进行减一 后退一个节点
self& operator--(){
node = (link_type)((*node).prev);
}
self operator--(int){
self tmp = *this;
--*this;
return tmp;
}
};
list的数据结构
- SGI list不仅仅是双向链表 还是一个环状双向链表,只需要一个指针就可以完成整个链表的遍历
//list的迭代器设计
template <class T,class Ref,class Ptr>
struct __list_iterator{
typedef __list_iterator<T,T&,T*> iterator;
typedef __list_iterator<T,Ref,Ptr> self;
typedef std::bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef __list_node<T>* link_type;
typedef std::size_t size_type;
typedef ptrdiff_t difference_type;
link_type node;//迭代器内部需要一个普通的指针,指向list节点
//constructor
__list_iterator(){}
__list_iterator(link_type x):node(x){}
__list_iterator(const iterator& x):node(x.node){}
bool operator==(const self& x) const{return (node == x.node);}
bool operator!=(const self& x) const{return (node != x.node);}
//以下对迭代器取值 取得的是节点的数据值
reference operator*() const {return (*node).data;}
//以下是对迭代器的成员进行存取 (member access) 运算子的标准做法
pointer operator->() const {return &(operator*());}
//对迭代器进行加一 前进一个节点
self& operator++(){
node = (link_type)((*node).next);
}
self operator++(int){
self tmp = *this;
++*this;
return tmp;
}
//对迭代器进行减一 后退一个节点
self& operator--(){
node = (link_type)((*node).prev);
}
self operator--(int){
self tmp = *this;
--*this;
return tmp;
}
//让指针node刻意指向尾端的一个空白节点,node节点便会符合STL对于前开后闭区间的要求,成为list迭代器
iterator begin(){return (link_type)(*node->next);}
iterator end(){return node;}
bool empty()const{return node->next == node;}
size_type size()const{
size_type result = 0;
std::distance(begin(),end(),result);
return result;
}
//取头部节点的内容(元素数值)
reference front(){
return *begin();
}
//取尾节点的内容(元素数值)
reference back(){
return *(--end());
}
};
//list 环状双向链表设计如下
template <class T,class Alloc> //缺省使用alloc作为配置器
class list{
protected:
typedef __list_node<T> list_node;
public:
typedef list_node* link_type;
protected:
link_type node; //只需要一个指针,便可以循环遍历整个环状的双向链表
};
list 的构造和内存管理
- 具体内容见代码注释
//list 环状双向链表设计如下
template <class T,class Alloc> //缺省使用alloc作为配置器
class list{
protected:
typedef __list_node<T> list_node;
//专属空间配置器 每次配置一个节点的大小
public:
typedef list_node* link_type;
typedef simple_alloc<list_node,Alloc>list_node_allocator;
//list_node_allocator(n) 表示分配n个节点空间,以下四个函数分别用来配置、释放、构造、销毁一个节点
protected:
//配置一个节点并返回
link_type get_node(){return list_node_allocator::allocate();}
//释放一个节点
link_type put_node(){return list_node_allocator::deallocate();}
//产生(配置并构造)一个节点 带有元素数值
link_type create_node(const T& x){
link_type p = get_node();
Chy::allocator<T>::construct(p->data,x); //全局函数 构造/析构基本工具
return p;
}
//销毁 (析构并释放) 一个节点
void destroy_node(link_type p){
Chy::allocator<T>::destroy(&p->data); //全局函数 构造/析构基本工具
}
public:
//构造函数
//产生一个空的链表
list(){empty_initialize();} //产生一个空的链表
protected:
link_type node; //只需要一个指针,便可以循环遍历整个环状的双向链表
void empty_initialize(){
node = get_node(); //配置一个节点空间,令node指向它
node->next = node; //令node头尾指向自己 不设置元素值
node->prev = node;
}
};
- 当使用push_back()将新的元素插入到list的尾端的时候 ,这个函数内部调用的是insert();
list 的元素操作
//清除所有的节点(整个链表)
template <class T,class Alloc>
void list<T,Alloc>::clear() {
link_type cur = (link_type)node->next; //begin()
while (cur != node){ //遍历每一个节点
link_type tmp = cur;
cur = (link_type)cur->next;
destroy_node(tmp); //销毁、析构释放一个节点
}
//恢复node的原始状态
node->next = node;
node->prev = node;
}
//清除数值为value的所有元素
template<class T,class Alloc>
void list<T,Alloc>::remove(const T &value) {
typedef typename __list_iterator<T,T&,T*>::iterator iterator;
iterator first = __list_iterator<T,T&,T*>::begin();
iterator last = __list_iterator<T,T&,T*>::end();
while (first != last){
iterator next = first;
++next;
if (*first == value){
__list_iterator<T,T&,T*>::erase(value);
first = next;
}
}
}
//移除数值相同的连续元素,注意:只有"连续并且相同的元素",才会被删除只剩一个
template <class T,class Alloc>
void list<T,Alloc>::unique() {
typedef typename __list_iterator<T,T&,T*>::iterator iterator;
iterator first = __list_iterator<T,T&,T*>::begin();
iterator last = __list_iterator<T,T&,T*>::end();
if (first == last){
return; //空的链表 什么都不做
}
iterator next = first;
while(++next != last){ //遍历每一个节点
if (*first == *next){ //如果这个区段中存在相同的元素
__list_iterator<T,T&,T*>::erase(next); //移除之
} else{
first = next; //调整指针
}
next = first; //修正区段范围
}
}
- list是一个双向的环状链表,只需要处理边界条件,在头部和尾部插入和删除的操作几乎是一样的
- 移除(erase) 某个迭代器所指向的元素,只是进行指针移动操作
- list提供了一个迁移操作(transfer),将连续范围的元素迁移到某个特定位置之前,技术角度上讲是节点之间的指针移动
- transfer迁移操作 是 其余操作(splice 、 sort 、 merge)的基础
- transfer的源代码
- transfer接收的[first , last)区间可以在同一个list中
- transfer不是公开的接口,list提供的是所谓的接合操作(splice) ,将某联系范围的元素从一个list移动到另一个(或者同一个)list的某个定点
//将[first , last) 内的所有元素 移动到 position之前
void transfer(iterator position,iterator first,iterator last){
if (last != position){
(*(link_type((*last.node).prev))).next = position.node; //1
(*(link_type((*first.node).prev))).next = last.node; //2
(*(link_type((*position.node).prev))).next = first.node;//3
link_type tmp = link_type ((*position.node).prev); //4
(*position.node).prev = (*last.node).prev; //5
(*last.node).prev = (*first.node).prev; //6
(*first.node).prev = tmp; //7
}
}
- 本质上是节点之间的指针移动,上述splice、reverse、sort函数本身依靠的是transfer函数
- 完整代码 不一定对
#include <iostream>
#include <list>
template<class T,class Alloc>
class simple_alloc{
public:
static T* allocate(std::size_t n){
return 0==n?0:(T*)Alloc::allocate(n * sizeof(T));
}
static T* allocate(void){
return (T*)Alloc::allocate(sizeof (T));
}
static void deallocate(T* p,size_t n){
if (n!=0){
Alloc::deallocate(p,n * sizeof(T));
}
}
static void deallocate(T* p){
Alloc::deallocate(p,sizeof(T));
}
};
namespace Chy{
template <class T>
inline T* _allocate(ptrdiff_t size,T*){
std::set_new_handler(0);
T* tmp = (T*)(::operator new((std::size_t)(size * sizeof (T))));
if (tmp == 0){
std::cerr << "out of memory" << std::endl;
exit(1);
}
return tmp;
}
template<class T>
inline void _deallocate(T* buffer){
::operator delete (buffer);
}
template<class T1,class T2>
inline void _construct(T1 *p,const T2& value){
new(p) T1 (value); //没看懂
}
template <class T>
inline void _destroy(T* ptr){
ptr->~T();
}
template <class T>
class allocator{
public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef std::size_t size_type;
typedef ptrdiff_t difference_type;
template<class U>
struct rebind{
typedef allocator<U>other;
};
pointer allocate(size_type n,const void * hint = 0){
return _allocate((difference_type)n,(pointer)0);
}
void deallocate(pointer p,size_type n){
_deallocate(p);
}
void construct(pointer p,const T& value){
_construct(p,value);
}
void destroy(pointer p){
_destroy(p);
}
pointer address(reference x){
return (pointer)&x;
}
const_pointer const_address(const_reference x){
return (const_pointer)&x;
}
size_type max_size()const{
return size_type(UINT_MAX/sizeof (T));
}
};
}
//如果是copy construction 等同于assignment而且destructor 是 trivial以下就会有效
//如果是POD型别 执行的流程就会跳转到以下函数,这个是通过function template的参数推导机制得到的
template<class ForwardIterator,class Size,class T>
inline ForwardIterator __uninitizlized_fill_n_aux(ForwardIterator first,Size n,const T&x){
return fill_n(first,n,x); //交给高阶函数执行
}
struct __true_type{};
struct __false_type{};
template<class T>
struct __type_traits {
typedef __true_type this_dummy_member_must_be_first;
typedef __false_type has_trivial_default_constructor;
typedef __false_type has_trivial_copy_constructor;
typedef __false_type has_trivial_assignment_constructor;
typedef __false_type has_trivial_destructor;
typedef __false_type is_POD_type;
};
//函数的逻辑是
//首先萃取出 迭代器first的value type,然后判断这个型别是否是POD类型
template<class ForwardIterator,class Size,class T,class T1>
inline ForwardIterator __uninitizlized_fill_n(ForwardIterator first,Size n,const T&x,T1*){
//以下使用的是__type_traits<T1>::is_POD_type is _POD
typedef typename __type_traits<T1>::is_POD_type is_POD;
return __uninitizlized_fill_n_aux(first,n,x,is_POD());
}
template<class ForwardIterator,class Size,class T>
ForwardIterator uninitialized_fill_n(ForwardIterator first,Size n,const T&x){
return __uninitizlized_fill_n(first,n,x,value_type(first));
//使用value_type()判断first的value type
}
//list的节点结构设计
template <class T>
struct __list_node{
typedef void* void_pointer;
void_pointer prev; //指针的类型是void*,其实可以将其设定为 __list_node<T>
void_pointer next;
T data;
};
//list的迭代器设计
template <class T,class Ref,class Ptr>
struct __list_iterator{
typedef __list_iterator<T,T&,T*> iterator;
typedef __list_iterator<T,Ref,Ptr> self;
typedef std::bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef __list_node<T>* link_type;
typedef std::size_t size_type;
typedef ptrdiff_t difference_type;
link_type node;//迭代器内部需要一个普通的指针,指向list节点
//constructor
__list_iterator(){}
__list_iterator(link_type x):node(x){}
__list_iterator(const iterator& x):node(x.node){}
bool operator==(const self& x) const{return (node == x.node);}
bool operator!=(const self& x) const{return (node != x.node);}
//以下对迭代器取值 取得的是节点的数据值
reference operator*() const {return (*node).data;}
//以下是对迭代器的成员进行存取 (member access) 运算子的标准做法
pointer operator->() const {return &(operator*());}
//对迭代器进行加一 前进一个节点
self& operator++(){
node = (link_type)((*node).next);
}
self operator++(int){
self tmp = *this;
++*this;
return tmp;
}
//对迭代器进行减一 后退一个节点
self& operator--(){
node = (link_type)((*node).prev);
}
self operator--(int){
self tmp = *this;
--*this;
return tmp;
}
};
//list 环状双向链表设计如下
template <class T,class Alloc> //缺省使用alloc作为配置器
class list{
protected:
typedef typename __list_iterator<T,T&,T*>::iterator iterator;
typedef typename __list_iterator<T,T&,T*>::value_type value_type;
typedef typename __list_iterator<T,T&,T*>::reference reference;
typedef typename __list_iterator<T,T&,T*>::size_type size_type;
typedef __list_node<T> list_node;
//专属空间配置器 每次配置一个节点的大小
public:
typedef list_node* link_type;
typedef simple_alloc<list_node,Alloc>list_node_allocator;
//list_node_allocator(n) 表示分配n个节点空间,以下四个函数分别用来配置、释放、构造、销毁一个节点
protected:
//配置一个节点并返回
link_type get_node(){return list_node_allocator::allocate();}
//释放一个节点
link_type put_node(){return list_node_allocator::deallocate();}
//产生(配置并构造)一个节点 带有元素数值
link_type create_node(const T& x){
link_type p = get_node();
Chy::allocator<T>::construct(p->data,x); //全局函数 构造/析构基本工具
return p;
}
//销毁 (析构并释放) 一个节点
void destroy_node(link_type p){
Chy::allocator<T>::destroy(&p->data); //全局函数 构造/析构基本工具
}
public:
//让指针node刻意指向尾端的一个空白节点,node节点便会符合STL对于前开后闭区间的要求,成为list迭代器
iterator begin(){return (link_type)(*node->next);}
iterator end(){return node;}
bool empty()const{return node->next == node;}
size_type size()const{
size_type result = 0;
std::distance(begin(),end(),result);
return result;
}
//取头部节点的内容(元素数值)
reference front(){
return *begin();
}
//取尾节点的内容(元素数值)
reference back(){
return *(--end());
}
//插入元素 供push_back()函数调用
//insert函数 需要配置并构造一个节点,然后在尾端进行指针操作,将新的节点插入进去
//函数的目的是为了在迭代器指定的位置插入一个节点,内容为x
iterator insert(iterator position,const T&x){ //产生一个节点,默认初始化元素数值为x
link_type tmp = create_node(x);
//调整双指针 将tmp插入进去
tmp->next = position.node;
tmp->prev = position.node->prev;
(link_type(position.node->prev))->next = tmp;
position.node->prev = tmp;
return tmp;
}
//插入一个节点 作为头部节点
void push_front(const T& x){
insert(begin(),x);
}
//插入一个节点 作为尾节点
void push_back(const T& x){
insert(end(),x);
}
//移除迭代器position指向的节点
iterator erase(iterator position){
link_type next_node = link_type (position.node->next);
link_type prev_node = link_type (position.node->prev);
prev_node->next = next_node;
next_node->prev = prev_node;
destroy_node(position.node);
return iterator (next_node);
}
//移除头部节点
void pop_front(){
erase(begin());
}
//移除尾部节点
void pop_back(){
iterator tmp = end();
erase(--tmp);
}
//将[first , last) 内的所有元素 移动到 position之前
void transfer(iterator position,iterator first,iterator last){
if (last != position){
(*(link_type((*last.node).prev))).next = position.node; //1
(*(link_type((*first.node).prev))).next = last.node; //2
(*(link_type((*position.node).prev))).next = first.node;//3
link_type tmp = link_type ((*position.node).prev); //4
(*position.node).prev = (*last.node).prev; //5
(*last.node).prev = (*first.node).prev; //6
(*first.node).prev = tmp; //7
}
}
public:
//构造函数
//产生一个空的链表
list(){empty_initialize();} //产生一个空的链表
void clear();
void remove(const T& value);
void unique();
protected:
link_type node; //只需要一个指针,便可以循环遍历整个环状的双向链表
//空初始化
void empty_initialize(){
node = get_node(); //配置一个节点空间,令node指向它
node->next = node; //令node头尾指向自己 不设置元素值
node->prev = node;
}
public:
//将x结合于position所指定位置之前 x必须不同于*this
void splice(__list_iterator<T, T &, T *>, list &x);
//将i指向的元素结合于position所指定的位置之前。position和i可以指向同一个list
void splice(iterator position,list& ,iterator i){
iterator j = i;
++j;
if (position == i || position == j){
return;
}
transfer(position,i,j);
}
//将[first,last)内的元素接合于position指定的位置之前
//position 和 [first,last)内可能指向的是同一个list
//但是position 不能位于 [first,last)内部
void splice(iterator position,list &,iterator first,iterator last){
if (first != last){
transfer(position,first,last);
}
}
//merage() 将x合并到*this身上,但是两个lists的内容都必须要先经过递增排序
void meage(list& x){
iterator first1 = begin();
iterator last1 = end();
iterator first2 = x.begin();
iterator last2 = x.end();
//两个list实现需要经过排序
while (first1 != last1 && first2 != last2){
if (*first2 < *first1){
iterator next = first2;
transfer(first1,first2,++next);
first2 = next;
} else{
++first1;
}
if (first2 != last2){
transfer(last1,first2,last2);
}
}
}
//reverse() 将this的内容 逆向重置
void reverse(){
//以下判断,如果是空的链表,或者仅仅只有一个元素,就不进行任何的操作
//使用size() == 0 || size() == 1 判断,速度较慢
if (node->next == node ||link_type(node->next)->next == node)
return;
iterator first = begin();
++first;
while (first != end()){
iterator old = first;
++first;
transfer(begin(),old,first);
}
}
//list不能使用STL算法的sort() 因为STL算法只接受randomAccessIterator
//本函数使用快速排序
void sort(){
//以下判断,如果是空的链表,或者仅仅只有一个元素,就不进行任何的操作
//使用size() == 0 || size() == 1 判断,速度较慢
if (node->next == node ||link_type(node->next)->next == node)
return;
//使用一些新的lists 作为中介数据存储区
list carry;
list counter[64];
int fill = 0;
while (!empty()){
carry.splice(carry.begin(),*this,begin());
int i = 0;
while (i < fill && !counter[i].empty()){
counter[i].merage(carry);
carry.swap(counter[i++]);
}
carry.swap(counter[i]);
if (i == fill){
++fill;
}
}
for (int i = 1; i < fill; ++i) {
counter[i].merage(counter[i-1]);
}
std::swap(counter[fill-1]);
}
};
//清除所有的节点(整个链表)
template <class T,class Alloc>
void list<T,Alloc>::clear() {
link_type cur = (link_type)node->next; //begin()
while (cur != node){ //遍历每一个节点
link_type tmp = cur;
cur = (link_type)cur->next;
destroy_node(tmp); //销毁、析构释放一个节点
}
//恢复node的原始状态
node->next = node;
node->prev = node;
}
//清除数值为value的所有元素
template<class T,class Alloc>
void list<T,Alloc>::remove(const T &value) {
typedef typename __list_iterator<T,T&,T*>::iterator iterator;
iterator first = __list_iterator<T,T&,T*>::begin();
iterator last = __list_iterator<T,T&,T*>::end();
while (first != last){
iterator next = first;
++next;
if (*first == value){
__list_iterator<T,T&,T*>::erase(value);
first = next;
}
}
}
//移除数值相同的连续元素,注意:只有"连续并且相同的元素",才会被删除只剩一个
template <class T,class Alloc>
void list<T,Alloc>::unique() {
typedef typename __list_iterator<T,T&,T*>::iterator iterator;
iterator first = __list_iterator<T,T&,T*>::begin();
iterator last = __list_iterator<T,T&,T*>::end();
if (first == last){
return; //空的链表 什么都不做
}
iterator next = first;
while(++next != last){ //遍历每一个节点
if (*first == *next){ //如果这个区段中存在相同的元素
__list_iterator<T,T&,T*>::erase(next); //移除之
} else{
first = next; //调整指针
}
next = first; //修正区段范围
}
}
template <class T,class Alloc>
void list<T,Alloc>::splice(__list_iterator<T, T &, T *>position, list<T, Alloc> &x) {
if (!x.empty()){
transfer(position,x.begin(),x.end());
}
}
- 涉及到transfer的相关函数的代码 理解不是很透彻 垃圾