STL学习_stl_list.h_源码分析
来源:互联网 发布:网站如何绑定其他域名 编辑:程序博客网 时间:2024/06/11 08:41
stl_list.h中有几个函数自己觉得比较重要,transfer() merge() sort()
#ifndef _SGI_STL_INTERNAL_LIST_H#define _SGI_STL_INTERNAL_LIST_H//list迭代器结构//不同的容器往往要给容器设置符合自己的迭代器,list的迭代器类型是双向迭代器//list的迭代器必须有能力进行递增,递减,取值,成员存取等操作template<class T, class Ref, class Ptr>struct __list_iterator{ typedef __list_iterator<T, T&, T*> iterator; typedef __list_iterator< T, const T&, const T*> const_iterator; typedef __list_iterator<T, Ref, Ptr> self; //这样写的目的是,为了否和规范,自行开发的迭代器因该提供五个内嵌相应型别, //以利于traits萃取。 typedef bidirectional_iterator_tag iterator_category; typedef T value_type; typedef Ref reference; typedef Ptr pointer; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef __list_node<T>* link_type; //迭代器内部指针node指向list的节点 link_type node; //list迭代器的构造函数 __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; } //对迭代器的成员存取 pointer operator->()const { return &(operator*()); } //迭代器前进一个节点(对前置++的符号重载) self& operator++() { node = (link_type)((*node).next); return *this; } //(对后置++的符号重载) self& operator++(int) { self tmp = *this; ++*this; return tmp; } //迭代器后退一个节点 self& operator--() { node = (link_type)((*node).prev); return *this; } self& operator--(int) { self tmp = *this; --*this; return tmp; } };//list的节点结构template<class T>struct __list_node{ typedef void* void_pointer; void_pointer next; void_pointer perv; T data;};//list的结构//list缺省使用alloc第二空间配置器template<class T, class Alloc=alloc>class list{protected: typedef __list_node<T> list_node; //定义的list_node_allocator这个专属空间配置器,方便以节点大小为配置单位 typedef simple_alloc<list_node, Alloc> list_node_allocator; typedef void* void_pointer;public: typedef T value_type; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; typedef list_node* link_type; size_t size_t size_type; typedef ptrdiff_t difference_type;public: typedef __list_iterator<T, T&, T*> iterator; typedef __list_iterator<T, const T&, const T*> const_iterator; //逆置迭代器 typedef reverse_iterator<const_iterator> const_reverse_iterator; typedef reverse_iterator<iterator> reverse_iterator;public: //list提供的接口 iterator begin(){return (link_type)((*node).next);} const_iterator begin()const{return (link_type)((*node).next);} iterator end(){return node;} const_iterator end()const {return node;} //指向反向序列的序列头 reverse_iterator rbegin(){return reverse_iterator(end());} const_reverse_iterator rbegin()const { return const_reverse_iterator(end()); } //指向反向序列的序列尾 reverse_iterator rend() { return reverse_iterator(begin()); } const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } bool empty()const{return node->next == node;} size_type size()const{ size_type result = 0; distance(begin(), end(), result); return result; } size_type max_size()const{ return size_type(-1); } reference front(){return *begin();} const_reference front()const{return *begin();} reference back(){return *(--end());} const_reference back(){return *(--end());} void swap(list<T, Alloc>&x) { __STD::swap(node, x.node); } void clear(); iterator erase(iterator position); iterator erase(iterator first, iterator last); //重置list的大小 void resize(size_type new_size, const T& x); //将数值为value的元素全部移除,注意区分不同容器的remove的用法不同 void remove(const T& x); //移除数值相同的连续元素 void unique(); void push_front(const T& x){insert(begin(), x);} void push_back(const T& X){insert(end(), x);} void pop_front(){erase(begin());} void pop_back() { iterator tmp = end(); erase(--tmp); } //将两个链表接合,其实是transfer()的封装 void splice(iterator position, list& x) { if(!empty()){ transfer(position, x.begin(), x.end()); } } //逆置链表,就是按顺序将list的节点接合到链表的begin()位置 void reverse(); //链表排序 void sort(); //将两个有序链表接合并且排序 void merge(list& x);public: //list链表的构造函数的重载有5种 list(){empty_initialize();} list(size_type n, const T& value){fill_initialize(n, value);} list(int n, const T& value){fill_initialize(n, value);} list(long n, const T& value){fill_initialize(n, value);} explicit list(size_type n){fill_initialize(n, T());} ~list() { clear(); put_node(node); }public: //insert函数的重载 iterator insert(iterator position, const T& x) { link_type tmp = create_node(x); tmp->next = position.node; tmp->prev = position.node->prev; (link_type(position.node->prev))->next = tmp; position.node->prev = tmp; return tmp; } void insert(iterator pos, size_type n, const T& x); void insert(iterator pos, int n, const T& x) { insert(pos, (size_type)n , x); } void insert(iterator pos, long n, const T& x) { insert(pos, (size_type)n, x); } void insert(iterator position, InputIterator first, InputIterator last);protected: //产生一个空链表 void empty_initialize() { node = get_node(); node->next = node; node->prev = node; } //填充链表 fill_initialize(size_type n, const T& value) { empty_initialize(); insert(begin(), n, value); } //配置一个节点仅仅是申请一个节点大小的空间 link_type get_node() { return list_node_allocator::allocate(); } //配置并且构造一个节点 link_type create_node() { link_type p = get_node(); construct(&p->data, x); return p; } //释放一个节点 void put_node(link_type p) { return list_node_allocator::deallocate(p); } //释放并且析构一个节点 void destory_node(link_type p) { destory(&p->data); put_node(p); }protected: //将[first, last)内部的所有元素移动到position之前 //这个内置的迁移函数很重要 //分为7步 void transfer(iterator position, iterator first, iterator last) { //如果不是在尾部插入 if(position != last){ //(1)将插入范围的最后的元素的next指针指向要插入的位置position上 (*(link_type((*last.node).prev))).next = position.node; //(2)将第二个链表的断开的位置的next指针指向另一端断开的位置 (*(link_type((*first.node).prev))).next = last.node; //(3)将第一个链表的插入位置的前驱的next指针指向要插入范围的起始位置 (*(link_type((*position.node).prev))).next = first.node; //(4)让tmp指向插入位置的前驱节点 iterator tmp = link_type((*position.node).prev); //(5)让插入位置position的next指针指向插入范围的结束位置 (*positon.node).prev = (*last.node).prev; //(6)第二个链表的断开位置的prev指针指向第二个链表的前面的断开位置 (*last.node).prev = (*fist.node).prev; //(7)让插入范围的起始位置的prev指针指向第一个链表的插入位置position的前驱节点 (*first.node).prev = tmp; } }};template<class T, class Alloc>void list<T, Alloc>::insert(iterator position, size_type n, const T& x){ for( ; n > 0; --n){ insert(position, x); }}template<class T, class Alloc>void list<T, Alloc>::insert(iterator position, const T* first, const T* last){ for( ; first != last; ++first){ insert(position, *first); }}template<class T, class Alloc>void list<T, Alloc>::clear(){ link_type cur = (link_type)node->next; while(cur != node){ link_type tmp = cur; cur = (link_type)cur->next; destory_node(tmp); } //恢复node的原始状态也就是空链表状态 node->next = node; node->perv = node;}template<class T, class Alloc>iterator list<T, Alloc>::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; destory_node(position.node); return iterator(next_node);}template<class T, class Alloc>iterator list<T, Alloc>::erase(iterator first, iterator last){ while(first != last){ erase(first++); return last; }}template<class T, class Alloc>void list<T, Alloc>::resize(size_type new_size, const T& x){ iterator i = begin(); size_type len = 0; for( ; i != end() && len < new_size; ++i){ ++len; } if(len == new_size){ erase(i, end()); } else{ insert(end(), new_size-len, x); }}template<calss T, class Alloc>void list<T, Alloc>::remove(const T& x){ iterator first = begin(); iterator last = end(); while(first != last){ iterator next = first; ++next; if(x == *first){ erase(first); } first = next; }}template<class T, class Alloc>void list<T, Alloc>::unique(){ iterator first = begin(); iterator last = end(); //空链的话直接退出 if(first == last){ return ; } iterator next = first; //一个一个遍历 while(++next != last){ if(*next == *first){ erase(next); }else{ first = next; } next = first; }}template<class T, class Alloc>void list<T, Alloc>::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; //在begin()位置插入[old, first)范围内的数值 transfer(begin(), old, first); }}//整体思想是:让两个迭代器分别指向第一个第二个有序链表,对两个链表进行遍历//如果第二个迭代器指向的节点小于第一个迭代器指向的节点则进行插入操作,如果//不符合条件则继续增加第一个迭代器直到找到那个比第二个迭代器大的节点位置进//型插入操作并移动第二个迭代器,就这样重复进行判断template<class T, class Alloc>void list<T, Alloc>::merge(list<T, Alloc>& x){ iterator first1 = begin(); iterator last1 = end(); iterator first2 = x.begin(); iterator last2 = x.end(); //从头到尾遍历一二链表 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); }}//list不能使用STL的算法sort(),必须使用自己的排序算法,因为STL的排序算法只接受//RamdonAccessIterator类型的迭代器//这里采用的是quick sort//sort()的大致思想:例如排序的链表是21,45,1,30,52,3,58,47,22,59,0,58//那么先放入第一个节点21 counter[0]:21 //然后放入第二个节点45,放入之前要进行merge()排序 counter[0]:21, 45 //放入第三个节点但是counter[0]最大只能存放两个节点,所以将counter[0]的所有节点放入counter[1]中//则counter[0]:1 counter[1]21, 45//放入第四个节点30, 放入之前要进行merge()排序 counter[0]1, 30 counter[1]21, 45//放入第五个节点52,由于counter[0]以满,则将所有节点放入counter[1]中,放之前要进行merge()排序//即counter[0]:52 counter[1]1, 21, 30, 45就这样不停的轮询template<class T, class Alloc>void list<T, Alloc>::sort(){ if(node->next == node || link_type(node->next->next == node)){ return ; } //carry counter[64]这些新的list作为中介数据存放区 list<T, Alloc> carry; //这里的counter[64]存放64个元素的数组,是用来做中转的存放区的 list<T, Alloc> counter[64]; int fill = 0; while(!empty()){ carry.splice(carry.begin(), *this, begin()); int i = 0; while(i < 0 && !counter[i].empty()){ counter[i].merge(carry); carry.swap(counter[i++]); } carry.swap(counter[i++]); if(i == fill){ ++fill; } } for(int i = 0; i < fill; ++i){ counter[i].merge(counter[i - 1]); } swap(counter[fill - 1]);}#endif
比如我们的list里有如下几个需要排序的元素:21,45,1,30,52,3,58,47,22,59,0,58。
排序的时候怎么做,我们先定义若干中转list在上述代码中定义了64个元素的数组
list<_Tp, _Alloc> __counter[64]; 其中里边存什么呢?他们都是用来中转用的
__counter[0]里存放2(0+1)次方个元素
__counter[1]里存放2(1+1)次方个元素
__counter[2]里存放2(2+1)次方个元素
__counter[3]里存放2(3+1)次方个元素,依次类推
那又是怎么个存放方法呢?一个指导原则就是当第i个元素即__counter[i]的内容个数等于2(i+1)次方时,就要把__counter[i]的数据转移给__count[i+1]。
具体过程如下:
取出第1个数21,放到__counter[0]里,这时__counter[0]里有一个元素,小于2,继续
__counter[0]: 21
__counter[1]: NULL
取出第2个数45,放到__counter[0]里(不是简单的放,而是排序放,类似两个list做merge),这时__counter[0]里有2个元素了,需要把这两个元素转移到__counter[1].
__counter[0]: NULL
__counter[1]: 21,45
取出第3个数1,放到__counter[0]里,__count[0]与__count[1]都小于规定个数
__counter[0]: 1
__counter[1]: 21,45
取出第4个数30,放到__counter[0]里,这时__counter[0]的个数等于2了,需要转移到__counter[1]里
__counter[0]: NULL
__counter[1]: 1,21,30,45
但这时__counter[1]里的个数又等于4了,所有需要把__counter[1]的值转移到__counter[2]里,
__counter[0]: NULL
__counter[1]: NULL
__counter[2]: 1,21,30,45
然后取出52,放入__counter[0]
__counter[0]: 52
__counter[1]: NULL
__counter[2]: 1,21,30,45
然后取出3,放入__counter[0]
__counter[0]: 3,52
__counter[1]: NULL
__counter[2]: 1,21,30,45
这时候需要转移
__counter[0]: NULL
__counter[1]: 3,52
__counter[2]: 1,21,30,45
然后取58
__counter[0]: 58
__counter[1]: 3,52
__counter[2]: 1,21,30,45
然后取47
__counter[0]: 47,58
__counter[1]: 3,52
__counter[2]: 1,21,30,45
需要转移
__counter[0]: NULL
__counter[1]: 3,47,52,58
__counter[2]: 1,21,30,45
还需要转移
__counter[0]: NULL
__counter[1]: NULL
__counter[2]: 1,3,21,30,47,45,52,58
还需要转移
__counter[0]: NULL
__counter[1]: NULL
__counter[2]: NULL
__counter[3]: 1,3,21,30,47,45,52,58
然后再取59
__counter[0]: 59
__counter[1]: NULL
__counter[2]: NULL
__counter[3]: 1,3,21,30,47,45,52,58
然后取0
__counter[0]: 0,59
__counter[1]: NULL
__counter[2]: NULL
__counter[3]: 1,3,21,30,47,45,52,58
需要转移
__counter[0]: NULL
__counter[1]: 0,59
__counter[2]: NULL
__counter[3]: 1,3,21,30,47,45,52,58
最后取58
__counter[0]: 58
__counter[1]: 0,59
__counter[2]: NULL
__counter[3]: 1,3,21,30,47,45,52,58
- STL学习_stl_list.h_源码分析
- STL学习_hash_table源码分析
- [Muduo网络库源码分析] (1) base/Atomic.h_原子操作与原子整数
- [Muduo网络库源码分析] (6) base/Mutex.h_互斥锁操作
- [Muduo网络库源码分析] (8) base/StringPiece.h_字符串参数传递类型
- [Muduo网络库源码分析] (11) base/Types.h_基本类型声明
- C++学习_string.h_的使用
- stl源码分析请教
- [STL]源码分析:allocator
- STL hashtable 源码分析
- STL源码分析--list
- STL源码分析--deque
- STL源码分析--算法
- STL源码分析 # vector #
- STL 源码分析 # stl_number #
- STL 源码分析 # stl_pair #
- C++ STL 源码分析
- STL源码分析(总结)
- JAVA聊天室代码
- Codeforces Round #179 (Div. 2) B (codeforces 296b) Yaroslav and Two Strings
- Android 读取指定路径文件
- bzoj 1854: [Scoi2010]游戏(二分图的最大匹配)
- POJ - 1988 Cube Stacking
- STL学习_stl_list.h_源码分析
- Xcode界面编辑器 could not insert new outlet connection
- AR与VR学习该如何开始-探索篇
- java容器总结
- 利用本地服务器发布网站(IIS配置+花生壳映射服务)
- Unityads安卓接入
- Closest Common Ancestors【POJ1470】——LCA
- 好的个人网站收藏
- [Modern OpenGL系列(四)]在OpenGL中使用Shader