序列式容器
<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<int> 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<int> 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<int>::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 <class T> 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<T> 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<T> > 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<int> > 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<T>, class Compare = less<typename Sequence::value_type> > 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 <class InputIterator> priority_queue(InputIterator first, InputIterator last, const Compare& x) : c(first, last), comp(x) { make_heap(c.begin(), c.end(), comp); } template <class InputIterator> 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()); } };