Vector容器
又称作变长数组,随着元素的增加,其内部机制会自行扩充空间以容纳新元素。
其实现的原理是:在vector中有三个容器分别表示容器目前使用空间的头,尾和可用空间的尾。即容器分配的内存要大于等于实际使用的内存。
如果vector无使用内存的话,容器会重新分配一块更大的空间,然后将数据移动到新的空间,然后将旧空间释放掉。
所以vector有两个成员函数,size()代表使用空间的大小;capacity()代表可用空间的大小
由于vector采用的连续空间,所以vector的迭代器是原型指针。
template<Class T, class Alloc= alloc>
class vector{
public:
typedef T value_type;
typedef value_type* iterator;
}
vector最关键的技术是insert函数:
template<class T, class Alloc>
void vector<T, Alloc>::insert_aux(iterator position, const T& x){
if(finish != end_of_storage){ //还有备用空间
construct(finish , *(finish - 1));
//调整水位
++finish;
T x_copy = x;
copy_backward(position, finish - 2, finish - 1);// 将[first, last )区间内的每一个元素,即[position, finish-2),以逆行的方向复制到以result-1即(finish -1)起点的区间
*position = x_copy;
}
else
{
const size_type old_size = size();
const size_type len = old_size != 0 ? 2 * old_size : 1; //如果空间分配不足,按照2倍空间分配
iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start;
try{
new_finish = uinitalized_copy(start , position,new_start);
construct(new_finish,x);
++new_finish;
new_finish = uinitalized_copy(position + 1, finish, new_finish);'
}
catch{
destroy(new_start, new finish);
data_alloctor::deallocate(new_start, len);
}
}
destory(begin(),end());
deallocate();
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
//由于vector 成员函数的操作中使用到了copy 函数,需要对copy函数进行解析
copy函数---强化效率无所输入不用其极,模板偏特化,函数重载,型别特性等
copy函数:将输入区间[first ,last) 内元素复制到输出区间[result, result + (last - first)) copy算法对template参数所要求的条件非常宽松,
其输入区间只需由InputIterator,输出区间只需由OutputIterator,拷贝算法特别通用。
copy 完全泛化版本:
template<class InputIterator , class OutputIterator>
inline OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result)
{
return _copy_dispatch<InputIterator , OutputIterator > ()(first, last , result); // 仿函数临时对象
}
//特化版本,采用的重载技术
inline char* copy(char * first , char * last , char * result )
{
memmove(result, first , last - first);
return result + (last - first);
}
inline wchar* copy(wchar * first , wchar * last , wchar * result )
{
memmove(result, first , last - first);
return result + (last - first);
}
//泛化版本的仿函数
template<class InputIterator , class OutputIterator >
struct _copy_dispatch
{
OutputIerator operator()(InputIterator first, InputIterator last, OutputIterator result){
return _copy(first ,last ,result , Iterator_category_category(first));
}
};
//特化版本的仿函数
template<T>
struct _copy_dispatch<T* ,T*>
{
T* operator()(T* first , T* last, T* result)
{
typedef typename _type_traits<T>::has_trivial_assignment_operator t;
return _copy_t(first , last , result , t()); //特化版本一种是通过memmove 、 _copy_d
}
};
template<T>
struct _copy_dispatch<const T* ,T*>
{
T* operator()(T* first , T* last, T* result)
{
typedef typename _type_traits<T>::has_trivial_assignment_operator t;
return _copy_t(first , last , result , t());
}
};
//重载函数根据迭代器的类型
template<class InputIterator , class OutputIterator>inline OutputIterator _copy(InputIterator first, InputIterator last, OutputIterator result, input_iterator_tag)
{
for(; first ! = last ; last++)
{
*result = *first;
}
return result;
}
template<class RandomAccessIterator , class OutputIterator>
inline OutputIterator _copy(RandomAccessIterator first, RandomAccessIterator last, OutputIterator result, random_access_iterator_tag)
{
return _copy_d(first , last , result , distance_type(first) );
}
temlate<class RandomAccessIterator , class OutputIterator, class Distance>
inline OutputIterator _copy_d(RandomAccessIterator first, RandomAccessIterator last , OutputIterator result, Distance*)
{
for(Distance n = last - frist ; n > 0;--n ,++result, ++first){
*result = * first;
}
return result;
}
list容器:
list容器是一个普通数据结构中的双向链表。
其节点的结构如下:
template<class T>
struct _list_node{
typedef void* void_pointer;
void_pointer * pre;
void_pointer * next;
T data;
}
list实现采用的是环形的双向链表,所以list的迭代器类型为Bidirectional Iterators
_list_iterator的设计其中必须存在一个执行list节点的指针即
template<class T, class Ref, class Ptr>
struct _list_iterator
{
typedef _list_iterator<T,Ref,Ptr> self; //为了实现迭代器之间的比较
typedef _list_node<T> * link_type;
link_type node;//用于接收指针,递增,递减,比较等操作
}
list操作可以参考下,作为设计链表的参考代码:
链表的插入:
template<class T>
iterator insert(iterator position , const T& x)
{
link_type tmp = create_node(x);
tmp->next = position.node; //新节点的next 指向postion节点
tmp->pre = position.node->pre;//新节点的pre执行position节点的pre
(link_type(position.node)->pre)->next = tmp;// position节点的pre的next指向tmp
position.node->pre = tmp;// position的前驱pre指向tmp
return tmp;
}
链表的删除:
iterator erase(iterator position){
link_type pre_node = link_type(position.node->pre);
link_type next_node = link_type(position.node->next);
pre_node->next = next_node;
next_node->pre = pre_node;
destroy(positon.node);
return iterator(next_node);
}
///deque 是一种双向开口的连续线性空间。
deque的特点:允许于常数时间内对起头端进行插入或移动操作;deque没有所谓的容量观念。
deque实现原理:
deque采用一块所谓的map作为主控,这里所谓map是一小块连续空间,其中每个元素都是指针,指向另一段连续线性空间,称为缓冲区。
template<class T, class Alloc = alloc, size_t BufSiz = 0>
class deque{
public :
typedef T value_type; //数值类型
typedef value_type* pointer;//指针
typedef size_t size_type;
typedef _deque_iterator<T, T&,T*,BufSiz> iterator;
protected:
typedef pointer* map_pointer;//指针的指针
iterator start;
iterator finish;
map_pointer map; //中控器
size_type map_size; //管理内存指针的大小
}
template<class T, class Ref, class Ptr, size_t BufSiz>
struct _deque_iterator{
typedef _deque_iterator<T, T&, T*,BufSize> iterator;
typedef _deque_iterator<T, const T&,const T*,BufSiz> const_iterator;
static size_t buffer_size(){return _deque_buf_size(BufSiz, sizeof(T));}
typedef random_access_iterator_tag iterator_category;
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T** map_pointer;
typedef _deque_iterator self;
T* cur;
T* first;
T* last;
map_pointer node;
}
deque实现的关键是通过迭代器的operator操作符,接下来一一分析
void set_node(map_pointer new_node)
{
node = new_node;
first = * new_node;
last = first + difference_type(buff_size());
}
reference operator* () const { return *cur};
pointer operator->() const { return &(operator*() ) ; }
difference_type operator- (const self &) const {
return difference_type(buffer_size()) * (node - x.node + 1) + (cur - first ) + (x.last - x.cur);
}
self& operator++(){ //前置式,先加
++cur;
if(cur == last){ //加完后发现本节点的无内存可用
set_node(node + 1); //移动到下一个节点
cur = first; //令当前节点等于第一个节点,迭代器设计
}
return * this;
}
self operator++(int)//后置式标准写法
{
self tmp = *this; //返回本迭代器节点
++*this; //采用前置法
return tmp;
}
self& operator--()
{
if(cur == first)
{
set_node(node -1);
cur =last;
}
--cur;
return *this;
}
self operator--(int)
{
self tmp = *this;
--*this;
return tmp;
}
self& operator +=(difference_type n)//跳跃多个距离,n可以为负值
{
difference_type offset = n + (cur - first);
if(offset >= 0 && offset < difference_type(buffer_size())
else{cur += n;
difference_type node_offset = offset > 0 ? offset / difference_type(buffer_size()) : -difference_type((-offset -1) / buffer_size() ) - 1;
set_node(node + node_offset);
cur = first + (offset - node_offset * difference_type(buffer_size()));
}
return *this;
}
self operator+(difference_type n)
{
self tmp = *this;
return tmp += n;
}
self operator-=(difference_type n)
{
return *this += -n;
}
self operator-(difference_type n)
{
self tmp = *this;
return tmp -= n;
}
reference operator[](difference_type n) const {return *(*this + n); }
//迭代器的上述操作,能够满足deque的插入,访问等。如果空间不足的时候 需要调整中控器的大小。
//stack栈
stack是一种配接器,它是以改变底层容器的接口为实现,称为配接器。
由于栈只能先进后出的数据结构,可以通过deque和list作为底层实现的容器,其实用vector也可以实现。
//queue队列
队列是一种先进先出的结构
queue也是一种配接器,也是通过底层容器实现,可以由deque和list为底层实现的容器,其实用vector也可以实现
//heap堆
完全二叉树,可以利用array来存储所有节点。将array的0号元素保留,那么某个节点位于array的i处,左子节点 必位于2i处,右子节点位于2i+1处。
我们采用vector作为存储介质,然后配合heap的插入,删除,取极值等算法组成。
//插入算法,保持堆的特性
template<class RandomAccessIterator>
inline void push_heap(RandomAccessIterator first , RandomAccessIterator last)
{
_push_heap_aux(first, last , distance_type(first), value_type(first) );
}
template<class RandomAccessIterator, class Distance, class T>
inline void _push_heap_aux(RandomAccessIterator first, RandomAccessIterator last, Distance* , T*)
{
_push_heap(first, Distance((last - first) - 1), Distance(0) , T(*(last - 1)) );
}
template<class RandomAccessIterator , class Distance, class T>
inline void _push_heap(RandomAccessIterator first, Distance holeIndex , Distance topIndex, T value)
{
Distance parent = (holeIndex - 1) / 2; //找到父节点
while(holeIndex > topIndex && *(first + parent) < value) //判断当前节点是否为头结点,以及 当前节点的值是否大于父节点的值
{
*(first + holeIndex) = *(first +parent); //移动父节点的值
holeIndex = parent; //更换holeIndex的位置
parent = (holeIdex - 1 )/ 2; //重新计算父节点的位置
}
*(first + holeIndex) = value; //将新值插入
}
//删除算法,保持堆的特性
template<class RandomAccessIterator , class Distance, class T>
void _adjust_heap(RandomAcessIterator first, Distance holeIndex, Distance len , T value)
{
Distance topIndex = holeIndex; //保留topIndex
Distance secondChild = 2 * holeIndex + 2; //取右子节点
while(secondChild < len) //小于最大长度
{
if(*(first + secondChild) < *(first + secondChild -1 ))// 比较子节点大小
sencondChild--;
*(first + holeIdex) = *(first + secondChild); //将子节点移动到移除节点位置
holeIndex = secondChild;
secondChild = secondChild * 2 + 2;
}
if(secondChild == len)
{
*(first + holeIndex) = *(first + secondChild -1 );
holeIndex = secondChild - 1;
}
_push_heap(first, holeIndex , topIndex, value);
}
//优先级队列priority_queue
优先级队列是以heap为底层容器的配接器。
//slist单向链表
单向链表与双向链表相比的特点:
1. 迭代器是InputIterator 单向迭代器
2. 类只是先了push_front 和popfront,因为使用insert插入只能插在其前面不能插在后面
3. 迭代器使用继承,没看懂好处在哪里?