A modest STL tutorial

-------大纲(Outline)-------

STL 包含由5大模块组成:容器(container,迭加器(iterators,算法(algorithms),函数对象(function objects),配置器(allocators).

Section1: Sample

分别用不同的例子简单描述上述5大组件(components).

Section2:Philosophy

解释STL框架的原理

Section3:Componets.

详细介绍5大组件(components

Section4:Extending STL

介绍怎样自己定义STL 模板

 

Example

大多数情况下我们需要一个类似数组(array)的能自动分配空间的类型,STL 有个vector ,下面举例说明vector怎样工作的,

将一组interger 类型的数据进行排序(sort),并打印(print)

version1: Standart C++

#include <stdlib.h>

#include <iostream.h>

// a and b point to integers.  cmp returns -1 if a is less than b, 
// 0 if they are equal, and 1 if a is greater than b.

inline int cmp(const void *a,const void *b)

{

int aa=*(int *)a;

int bb=*(int *)b;

return (aa<bb)? 1: (aa>bb)?1 : 0;

}

// Read a list of integers from stdin
// Sort (c library qsort)
// Print the list
void main(int argc,char *argv[])
{
   const int size=1000; //array of 1000 integers
   int array[size];
   int n=0;
   //read an integer into the n+1 the element of array
   while(cin>>array[n++]);
   n--; //it got incremented once too many times
   qsort(array,n,sizeof(int),cmp);
   for(int i=0; i<n;i++)
      count<<array[i]<</n;
}
 

Version2: containers ,iterators, algorithms
STL提供了大量能够包含其他对象的容器类(container),vector 就是其中一种,他类似于数组(array),能够需要自增长度,比如它的一个操作(operation) push_pack,将元素(element)加在vector(向量)的末尾,长度加1。
Vector 是一种sequence container,支持随机访问元素,常量时间内在尾端安插和移除元素,以及线性时间内在开头,中间处安插或移除元素.vector 的元素个数能够动态变更,其内存管理行为完全自动.【Generic Programming and the STL】
Vector 的大小(size,其所包含的元素个数)与容量(capacity,其内存所容纳的元素个数)之间有重要的区别.

  
  

   
    
     
     
      
      
     
     
    
    
 
   
   

    
     
   
   
  
  所以,你可以用STL sort实现来替代上例的qsort实现,STL提供很多算法(algorithms), sort 是通用的,它可以在不同类型的容器(containers)中工作,因为它不是直接依赖容器(container)而是迭代器(iterators).

Preview of iterators

在后面我们详细介绍iterators, 它为容器提供了一种元素的位置指针服务,iterator 可以增加也可以减少,而且可以比较,这种特殊迭代器我们把它叫做past-the-end;

可以通过iterator 指向vector 的开始(begin)和结尾(end).

Vector<int> v;

//add some integers to v

vector::iterator i1=v.begin();

vector::iterator i2=v.end();

 

排序(sort) 就是在两个iterators 指定的范围(rang)操作,比如通过增加i1(i1++),只要小于iT2,注意,它是一个semi-open rang 半闭环区

例子:

#include <string.h>

#include <algo.h>

#include <vector.h>

#include <stdlib.h>

#include <iostream.h>

void main()

{

    vector<int> v;

    int input;

    while(cin>>input)  //while not end of file ENTER key

        v.push_back(input);

    // sort takes two random iterators, and sorts the elements between
   // them.  As is always the case in STL, this includes the value
   // referred to by first but not the one referred to by last; indeed,
   // this is often the past-the-end value, and is therefore not
   // dereferenceable.

   sort(v.begin(),v.end());

   int n=v.size();

   for(int I=0;I<n;I++)

cout<<v[I]<</n;

}

Incidentally,sort 比 qsort 实现的速度要快!

 

Version 3: 迭代器配接器(iterator adaptors)

STL 事先定义的iterator大多数能迭代于container元素之中,但这并非必要条件,iterator的概念极为一般性,他们可用来表现“以任何次序安排“的数值(而非只是container中已排序好的数值)身上的迭代动作,STL 的stream iterators,就是基于C++ 的stream I/O Library实现输入与输出动作的。

STL 提供了一个配置器(adaptors),他能够实现将每个接口转换成另一种接口。Istream_iterator 其实就是一个有用的adaptor,它是一个template type,我们可以参数化想要处理的流(stream),比如 integers: 可以用 istream_iteraotr<int>. 一旦stream 结束,istream_iterator 便有一个特别的stream 结束值,此值就是 past-the-end iterator.

Istream_interator<int>(cin) 动作示意图:

为了讲标准输入的元素读入到一个vector中,我们需要用到copy算法(algorithm),copy包含3个iterators,第一和第二个指定(specify)源区间(source rang),第三个指定目标(destination):

int main()

{

    vector <int > V;

    copy(istream_iterator<int> (cin),istream_iterator<int>(), back_inserter(V));

}

也可以用:

typedef istream_iterator<int> istream_iterator_int;

algorthm 可以改成

copy(istream_iterator_int(cin),istream_iterator_int(),v.begin());

 

NOTE:有一个小问题就是如果第三个参数用v.begin(),假设,v没有足够的空间来存取所有的元素,这时 iterator 讲破坏past-the-end iterator 规则,引起错误。因为copy没有办法将新元素插入V中,其实是一种覆盖(overwrite)操作,就是讲新赋值于V既有的元素上,而不是插入新的元素,要实现插入新元素,就必须调用V的member function.其实我们用insertion操作来替代overwriting,利用另外一个adaptor做这些,back_insert_iterator,

它包含一个参数表示你要插入的对象类型:

 

back_insert_interator(v)动作示意图:

所以一个input动作可以描述:

typedef istream_iterator<int,ptrdiff_t> istream_iterator_int;

vector<int> v;

istream_iterator_int start (cin);

istream_iteratro_int end;

back_insert_iterator<vector<int>>dest (v);

copy(start,end,dest);

 

同样,输出动作也可以用copy algorithm;

copy(v.begin(),v.end(),ostream_iterator<int>(cout,”/n”);

 

ostream_iterator 是另外一个提供输出功能的adaptor,constructor包含两个实参;第二个参数是字符串,用于每个元素打印之后被打印

例:

#include <string.h>

#include <algo.h>

#include <vector.h>

#include <stdlib.h>

#include<iostream.h>

 

void main()

{

vector<int>v;

istream_iterator<int,ptrdiff_t> start (cin);

istream_iterator<int,ptrdiff_t> end;

back_insert_iterator<vector<int> >dest (v);

 

copy(start,end, dest);

sort(v.begin(),v.end());

copy(v.begin(),v.end(),ostream_iterator<int>(cout,”/n”));
}

 

结论:

STL算法(algorithms)依赖于一个区间的概念(Rangs),它是贯穿了整个容器组件(container).这样,一般容器(container)都一个了一些基于区间的操作,比如,STL有个count algorithms,它用于计算[  first, last  区间与value相等的元素的个数。

template <class InputIterator, class T, class Size>
void count (InputIterator start, InputIterator end, const T& value, Size& n);

在区间内符合*I==value,的iterator的个数加入n中

所以必须要产生一个局部变量n,并讲它初始化0;

C++ Standart[ISO98]版中,提供了另外一种简单的实现

template<class InputIterator,class EqualityComparable>

typename iterator_traits<InputIterator>::difference_type

count(InputIterator first,InputIterator last,const EqualityComparable& value);

 

 

Section2:原理 (Philosophy)

STL编程我们讲它称为泛型编程(generic programming),它提供使得尽可能满足一般的参数类型的一系列算法。

 

STL 组件:

Containers

容器就是能够用于包含其他对象,并且能够确定这些被包含对象的基本属性,而不依赖于具体的对象类型。

就是数据结构,例如:

vectors,lists,deques,sets,maps,multisets,mulitimaps,queues,stacks,and priority queues

下图给出我们常用的一些容器的抽象层次(hierarchy):

 

序列(Sequences)

Sequence 是一个大小可变的container,它不会以某种规定来排列元素,它必须具有两个member function insert erase,如果 s Sequence,p指向s内的某个元素iterator, s.erase(p)会移除并释放改元素,s.insert(p,x)会产生一个新对象,此对象是x的一个副本,然后被安置于p所指元素之前,注意是之前而不是之后,因为iteratorrange是非对称的,只有所谓”past-the-end”的元素,没有所谓”before-the-beginning”的元素,可以在s.begin()之前做插入动作,也可以在s.end()之后做插入动作,前者在最前头处插入一个元素,后者在最尾端处插入一个元素,如果s.insert(p,x)是将x插入在p之后,而非之前的化,那么上面的行为就没法达到了。

虽然2member function 很简单,但存在两个重要问题:

1.       当进行插入和erase操作时,对指向Sequence的那个iterator有没有影响?

2.     inserterase的复杂度如何?

 

这两个问题,我们只能视情况而定,不同的Sequence,有个不同的体现。

STL包含3Sequences:

Vector:

在尾端插入很快,而且允许随机访问。

Lists

它是以节点(node)为基础的container,插入任何位置的速度都很快,但只提供顺序访问

Deques:

在尾端插入很快, 而且允许随机访问。但它具有类型限制。而且许多操作不支持.

Stacks and queues,同上

 

 

(关联性容器)Associative containers

Associative container 是一种可变大小的container,可以高效率的根据“以key为基础“的元素。它的每个元素有一个相关联的key,只要给定一个key,Associative container会很快查询key 的元素,

Associative container的基本操作是查询(lookup),插入(insert)和删除(erase).它不允许讲元素插入到Associative container的任意位置。

Sets, Multisets,Maps,Multimaps都是Associative container.

 

Iterators

前面已经描述了Iterator的意思,它实际上是用于指定容器或流的位置,类似于指针操作。它能够遍历由object所形成的range之中。有了iterator,得以将container和作用于它上的algorithmes 分离。

Input iterators

Input iterators 用于访问数据源。

 

Output iterators

它是用来存储数值序列。

Forward iterators

Forward iterator符合线性数值序列(liner sequence of values)的只觉概念,它不同于input iterator,也不同于output iterator,可用于多回(multipass)算法,顾名思义,它只能在range中向前移动。

Bidirectional iterators

它是一个可以incremented 也可以decrementediterator.

 

Random access iterators

它是一中可以incremented 也可以decrementediterator,并在向前或向后移动任意步数时,以及在比较两个iterators时,耗用固定的时间.它提供类似C指针的所以操作能力。

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值