《STL 源码解析》之序列式容器

序列式容器
所谓序列容器即容器其中的元素都可序,但未必有序。常见的序列容器包括vector,list,deque,queue以及stack.

vector
array是静态空间,一旦配置就不可改变。vector是动态空间,随着元素的加入,内部机制会自动扩充以容纳新元素。

1.1迭代器

vector维护的是一个线性区间,所以无论元素类型为何,普通指针都可以作为vector的迭代器而满足所有的必要条件。vector支持随机存取,而普通指针正好具备这样的能力,所以vector提供的是随机读取迭代器。即Random Access Iterators.

template <class T,class Alloc = alloc>
class vector{
public:
typedef T value_type;
typedef value_type* iterator; //vector的迭代器时普通指针

};
1.2 分配器

vector缺省使用alloc作为空间分配器,并据此另外定义了一个data_allocator.为的是更方便的以元素大小为配置单位。

template<class T,class Alloc = alloc>
class vector{
protected:
typedef simple_alloc<value_type,Alloc> data_allocator;

};
因此,data_allocator::allocate(n)表示分配n个元素空间。

1.3常见操作:

Vector_se ve(10,10,4);
//size()测试
int size = ve.size();
cout << "size: "<<size << endl;
//insert()函数测试
ve.insert(11);
ve.insert(4,19);
ve.insert(5,78);
for(int i = 0 ; i < ve.size(); i++){
cout << ve[i] << endl;
}
cout << ve.empty() << endl;
int flag_disorder = ve.disordered();
//输出逆序对数
cout << flag_disorder << endl;
//stl中的vector
int i;
vector v(2,9);
cout <<“size:” << v.size() << endl;
cout << “capacity:” << v.capacity() << endl;
v.push_back(1);
cout <<“size:” << v.size() << endl;
cout << “capacity:” << v.capacity() << endl;
v.push_back(3);
cout <<“size:” << v.size() << endl;
cout << “capacity:” << v.capacity() << endl;
v.push_back(4);
cout <<“size:” << v.size() << endl;
cout << “capacity:” << v.capacity() << endl;
vector::iterator iter = find(v.begin(),v.end(),3);
if(iter != v.end()){
cout << “finded” << endl;
v.erase(iter);
}
v.insert(iter,5);
for(int i = 0 ; i < v.size(); i++){
cout << v[i] << endl;
}
v.clear();
插入操作导致容器容量增加,此时会发生扩容操作,即会造成原先的迭代器失效。
2、list
2.1 节点
template
struct __list_node{
typedef void* void_pointer;
void_pointer prev; //类型为void*
void_pointer next;
T data;
};
 
2.2 迭代器

list不像vector一样,以普通指针作为迭代器,因为其节点在空间中不保证连续存在。list迭代器必须保证指向list的节点,并能够递增,递减,取值以及成员存取等操作。list中是双向链表。所以迭代器必须具备前移和后移的能力。list的插入和接合操作都不会造成原有的list迭代器失效,对于删除操作,也只有”指向被删除元素“的那个迭代器失效,其它迭代器不受任何影响。

SGI list不仅是一个双向链表,还是一个环状双向链表。所以它只需要一个指针,便可完整表现整个链表。

template <class T, class Alloc = alloc>
class list {
protected:
typedef __list_node list_node;
public:
typedef list_node* link_type;

protected:
link_type node; //只要一个指针,便可表示整个环状双向链表
};

iterator begin() { return (link_type)((*node).next); }
iterator end() { return node; }
size_type size() const {
size_type result = 0;
distance(begin(), end(), result);
return result;
}

2.3 分配器

list缺省使用alloc作为空间分配器,并据此另外定义了一个list_node_allocator,为的是更方便以节点大小为配置单位:

template <class T, class Alloc = alloc>
class list {
protected:
typedef simple_alloc<list_node, Alloc> list_node_allocator;

};
因此,list_node_allocator::allocate(n)表示分配n个节点空间

2.4 list常见操作

节点操作
分配节点:get_node()
释放节点:put_node()
生成一个节点:create_node()
销毁一个节点:destory_node()
节点插入:push_back(),push_front(),insert()
节点移除:erase(),pop_back()和pop_front()
移除某一数值的所有节点:remove()
移除相同节点值的连续节点:unique()
链表操作
创建空链表:list(),empty_initialize()
链表清空:clear()
链表拼接:splice()
将[first,last)内的元素移动到position之前,transfer(first,last)区间可以在同一个list内,也可以是两个不同的list.

3.deque

deque是一种双向开口的连续线性空间。

deque和vector最大的差异:

deque允许常数时间内对起头端进行元素的插入或者移除操作。
deque没有所谓容量观念,因为它是动态地以分段连续空间组合而成,随时可以增加一段新的空间并链接起来(deque没有必要提供所谓的空间保留功能)
3.1 迭代器

deque是分段连续空间。维持其”整体连续“假象的任务,落在了迭代器的operator++和operator–两个运算子身上。deque迭代器必须能够指出分段连续空间(即缓冲区)在哪;必须能够判断自己是否已经处于其所在缓冲器的边缘。为了能够正确跳跃,迭代器必须随时掌握中控器map。

3.2deque的数据结构

deque采用一块所谓的map作为主控(中控器)。这里所谓的map是指一小块连续空间,其中每个元素都是一个指针,指向另一段(较大的)连续线性空间,称为缓冲区。缓冲区才是deque的存储空间主体。SGI STL允许我们指定缓冲区大小,默认值0表示使用512bytes缓冲区。

deque的中控器,缓冲区,迭代器的关系如下

3.4常见操作

deque的构造和初始化:deque()
插入:push_back(),push_front(),insert().
弹出:pop_back(),pop_front()
清除所有:clear()
清除某个空间:erase()
4.stack

具有”修改某物接口,形成另一种风貌“的性质者,称为适配器。因此,STL stack往往不被归类为容器,而被归类为容器适配器.stack不能被遍历,因而没有迭代器

template <class T, class Sequence = deque >
class stack {
//以下__STL_NULL_TMPL_ARGS会展开为 <>
friend bool operator== __STL_NULL_TMPL_ARGS (const stack&, const stack&);
friend bool operator< __STL_NULL_TMPL_ARGS (const stack&, const stack&);
public:
typedef typename Sequence::value_type value_type;
typedef typename Sequence::size_type size_type;
typedef typename Sequence::reference reference;
typedef typename Sequence::const_reference const_reference;
protected:
Sequence c; //底层容器
public:
//以下完全利用Sequence c的操作,完成stack的操作
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
reference top() { return c.back(); }
const_reference top() const { return c.back(); }
//deque是两头可进出,stack是后进后出
void push(const value_type& x) { c.push_back(x); }
void pop() { c.pop_back(); }
};

template <class T, class Sequence>
bool operator==(const stack<T, Sequence>& x, const stack<T, Sequence>& y) {
return x.c == y.c;
}

template <class T, class Sequence>
bool operator<(const stack<T, Sequence>& x, const stack<T, Sequence>& y) {
return x.c < y.c;
}
只有stack顶端的元素有机会被外界取用,stack不提供遍历功能,也不提供迭代器。可以指定其它容器作为stack的底部容器。

5.queue:队列,是一种先进先出的数据结构,尾端插入,首部移出。只有首部元素才有机会被外界取用,queue不提供遍历功能,也不提供迭代器。指定其它容器作为queue的底层容器的方法:

queue<int,list > iqueue;
6、heap

heap并不归属与STL容器组件,它是个幕后英雄,扮演priority queue的助手.heap是一颗完全二叉树,完全二叉树使用数组实现,因此使用一个vector作为heap的结构,然后通过一组xxx_heap算法,使其符合heap的性质.

push_heap()上溯,在此操作时,应该先push_back()
pop_heap():去顶:要pop_back()
sort_heap():排序后,不具备堆结构
make_heap():建堆
7.priority_queue

priority_queue就是具有优先级的queue,允许首部移出,尾端插入。缺省情况下利用一个max-heap完成,因此首部元素优先级最高.和queue一样,priority queue只有首部的元素有机会被外界取用。不提供遍历功能,也不提供迭代器.

template <class T, class Sequence = vector,
class Compare = less >
class priority_queue {
public:
typedef typename Sequence::value_type value_type;
typedef typename Sequence::size_type size_type;
typedef typename Sequence::reference reference;
typedef typename Sequence::const_reference const_reference;
protected:
Sequence c; //底层容器
Compare comp; //元素大小比较标准
public:
priority_queue() : c() {}
explicit priority_queue(const Compare& x) : c(), comp(x) {}

//以下用到的make_heap()、push_heap()、pop_heap()都是泛型算法
//构造一个priority queue,首先根据传入的迭代器区间初始化底层容器c,然后调用
//make_heap()使用底层容器建堆
template
priority_queue(InputIterator first, InputIterator last, const Compare& x)
: c(first, last), comp(x) { make_heap(c.begin(), c.end(), comp); }
template
priority_queue(InputIterator first, InputIterator last)
: c(first, last) { make_heap(c.begin(), c.end(), comp); }

bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
const_reference top() const { return c.front(); }
void push(const value_type& x) {
//先利用底层容器的push_back()将新元素推入末端,再重排heap
__STL_TRY {
c.push_back(x);
push_heap(c.begin(), c.end(), comp);
}
__STL_UNWIND(c.clear());
}
void pop() {
//从heap内取出一个元素。但不是真正弹出,而是重排heap,然后以底层容器的pop_back()
//取得被弹出的元素
__STL_TRY {
pop_heap(c.begin(), c.end(), comp);
c.pop_back();
}
__STL_UNWIND(c.clear());
}
};
————————————————
版权声明:本文为CSDN博主「Wilder_ting」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Wilder_ting/article/details/89426351

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值