目录
list的节点(node)
list迭代器
list 的构造和内存管理
list 的元素操作
-
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;//3link_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 _PODtypedef 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函数 需要配置并构造一个节点,然后在尾端进行指针操作,将新的节点插入进去//函数的目的是为了在迭代器指定的位置插入一个节点,内容为xiterator insert(iterator position,const T&x){ //产生一个节点,默认初始化元素数值为xlink_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;//3link_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必须不同于*thisvoid splice(__list_iterator<T, T &, T *>, list &x);//将i指向的元素结合于position所指定的位置之前。position和i可以指向同一个listvoid 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的相关函数的代码 理解不是很透彻 垃圾