STL学习_stl_list.h_源码分析

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

时间: 2024-11-08 21:00:07

STL学习_stl_list.h_源码分析的相关文章

C++:浅谈c++资源管理以及对[STL]智能指针auto_ptr源码分析,左值与右值

C++:浅谈c++资源管理以及对[STL]智能指针auto_ptr源码分析 by 小威威 1. 知识引入 在C++编程中,动态分配的内存在使用完毕之后一般都要delete(释放),否则就会造成内存泄漏,导致不必要的后果.虽然大多数初学者都会有这样的意识,但是有些却不以为意.我曾问我的同学关于动态内存的分配与释放,他的回答是:"只要保证new和delete成对出现就行了.如果在构造函数中new(动态分配内存),那么在析构函数中delete(释放)就可以避免内存泄漏了!" 事实果真如此么?

集合类学习之Arraylist 源码分析

1.概述 ArrayList是List接口的可变数组的实现.实现了所有可选列表操作,并允许包括 null 在内的所有元素.除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小. 每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小.它总是至少等于列表的大小(如果不指定capacity,默认是10).    /**      * Constructs an empty list with an initial capacity of ten.

Volley简单学习使用三——源码分析一(修改)

一.Volley框架图 根据图简单猜测Volley工作的流程,见右下角的注释,蓝色表示主线程(main thread),绿色表示缓存线程(cache thread),黄色表示网络线程(network threads): 再寻找图中的关键字:queue(RequestQueue),cache queue,CacheDispatcher,NetworkDispatcher; 流程可简单那描述为:RequestQueue的add()操作将Request添加到缓存队列cache queue中.Cache

Volley简单学习使用三——源码分析一

一.Volley框架图 根据图简单猜测Volley工作的流程,见右下角的注释,蓝色表示主线程(main thread),绿色表示缓存线程(cache thread),黄色表示网络线程(network threads): 再寻找图中的关键字:queue(RequestQueue),cache queue,CacheDispatcher,NetworkDispatcher; 流程可简单那描述为:RequestQueue的add()操作将Request添加到缓存队列cache queue中.Cache

java学习笔记-String源码分析(2)

承接上篇文章关于String源码的分析,我们继续总结String中的方法 方法汇总 4.subString方法 public String substring(int beginIndex) public String substring(int beginIndex, int endIndex) subString()有2个重载版本,beginIndex指定开始索引(包括),endIndex指定结束索引(不包括).两个方法实现类似,我们关注一个即可. public String substri

Volley简单学习使用四——源码分析二

一.Volley工作流程图: 继续从CacheDispatcher和NetworkDispatcher开始看起. 二.CacheDispatcher: 一个线程,用于调度处理走缓存的请求.启动后会不断从缓存请求队列中取请求处理,队列为空则等待,请求处理结束则将结果传递给ResponseDelivery 去执行后续处理.当结果未缓存过.缓存失效或缓存需要刷新的情况下,该请求都需要重新进入NetworkDispatcher去调度处理. (一)看源码前,先看一下从其成员变量与处理流程: (1). 成员

Spring源码学习之Aop源码分析

在使用Aop功能时要添加注解@EnableAspectJAutoProxy,所以这个注解就是Aop的入口了.这个注解的作用就是在Spring的后置处理器中添加一个处理器来处理springBean,使之成为一个代理对象. 1 @Target({ElementType.TYPE}) 2 @Retention(RetentionPolicy.RUNTIME) 3 @Documented 4 @Import({AspectJAutoProxyRegistrar.class}) 5 public @int

Java集合源码分析(二)ArrayList

ArrayList简介 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Collections.synchronizedList(List l)函数返回一个线程安全的ArrayList类,也可以使用concurrent并发包下的CopyOnWriteArrayList类. ArrayList实现了Serializable接口,因此它支持序列化,能够通过

死磕 java集合之LinkedHashSet源码分析

问题 (1)LinkedHashSet的底层使用什么存储元素? (2)LinkedHashSet与HashSet有什么不同? (3)LinkedHashSet是有序的吗? (4)LinkedHashSet支持按元素访问顺序排序吗? 简介 上一节我们说HashSet中的元素是无序的,那么有没有什么办法保证Set中的元素是有序的呢? 答案是当然可以. 我们今天的主角LinkedHashSet就有这个功能,它是怎么实现有序的呢?让我们来一起学习吧. 源码分析 LinkedHashSet继承自HashS