歌舞程序

导航

STL的一点笔记

1、 容器:

有时我们要创建对象,但不知道创建多少个对象,这里对存储造成了麻烦,分配内存太大了浪费,分配太少了,不够用,于是在面向对象的程序设计中,可以使用另一种方法,只创建对象的另一种类型就可以了,对于存储问题,这些新的对象类型持有其他对象或者指向这些对旬有指针,这种新的对象类型,通常在C++中称为容器,每当必须适应放置在它内部的所有对象的需要的时候,容器都会自行扩展。所以不必预先知道容器中将要放入多少个对象;仅需创建一个容器对象,然后由容器来处理全部细节。

2、 迭代器:

对于灵活的元素访问的解决方案是使用迭代器,迭代器是一个对象,它的工作就是在容器中挑选元素并将其呈献给迭代器的使用者。作为一个类,迭代器同时也提供了一个抽象层,因此可以将容器的内部实现细节与用来访问容器的代码分隔开来。通过迭代器,容器可以被看作一个序列。迭代器允许遍历一个序列而无需考虑其基本结构----即不管它是vector还是list或者是一个set或其它结构。如此一来,就提供了灵活性,即使更改了底层的数据结构,也不会扰乱遍历容器的程序代码。将迭代操作从容器的控制下分隔开来,也允许同时存在多种迭代器。

3、 迭代器主要可以为:

1) 前向迭代器

2) 双向迭代器

3) 随机访问迭代器

4、 容器分类:

1)序列容器     vectorlistdeque

2)适配器       queuestackpriority_queue

3)关联式容器   setmapmultisetmultimap

5、 序列容器详解:

   1vector

   Vector需要分配一块连续的内在,因此具有类似数组的特性,如:可高效随机访问其中的元素,但其缺点也比较明显,在中间部分插入元素的效率较低(毕竟需要将插入位置后的元素往后挪)。当需要存入vector的元素过多,预分配的内在不够时,vector将重新分配一块更大的内存,并且将原先的对象复制到新的存储区域中,并销毁原内存的对象,释放原内存,主要进行以下工作:

A)分配一块新的、更大的存储区

B) 将旧存储区中的对象拷贝到新开辟的存储区中去(使用拷贝构造函数)

C) 销毁旧存储区中的所有对象(为每一个对象调用析构函数)

D)释放旧存储区的内存。

温馨提示:对于复杂对象,如果经常把vector装填得过满的话,系统将会为这些拷贝构造函数和析构函数的完成付出高昂的代价,这就是为什么vector(以及一般STL容器)被设计成值类型容器的原因,当然也包括指针。

2deque

双端队列deque容器是一种优化了的、在序列两端对元素进行添加和删除操作的基本序列容器。它也允许适度快速地进行随机访问----就像vector一样,它也有一个operator[]操作符。然而,它没有vector的那种把所有的东西都保存在一块连续的内存块的约束。Deque的典型实现是利用多个连续的存储块(同时在一个映射结构中保持对这些块及其顺序的跟踪)。因此,向deque的两端添加或删除元素所带来的开销很小。另外,它从不需要在分配新的存储区时复制并销毁所包含的对象(像vector那样),所以在向序列两端添加未知数量的对象时,deque远比vector更有效率。这意味着,只有在确切知道到底需要多少个对象的时候,vector才是最佳选择。

3list

list是以一个双向链表数据结构来实现,如此设计是为了在一个序列的任何地方快速插入或删除元素。因此在具有频繁插入操作时,因选择list作为存储结构,list的缺点是对于元素的访问过程,需要遍历,因此遍历效率低下。

 

因此,要根据程序要求,结合这些容器的特点,进行选择。

 

6、 适配器 stack queu

适配器是在前面的基本序列容器中,通过一定的调整以存储自己的数据

   1stack

   栈,先进后出,只能从尾端进和出,一般只需要poppushtop三个函数就行了,其中pop返回值为空,只负责出栈,而top则返回栈顶元素的一个引用。这样做具有更高的效率,因为传统的pop()函数必须返回一个值而不是一个引用,因此调用拷贝构造函数,必须是异常安全的,如果pop在改变栈状态的同时试图返回栈顶元素,那么在元素的拷贝构造函数中产生的某个异常就会导致元素的丢失。

   Stack的默认方式是使用deque,当然也可自己选择:

   Typedef stack<string> Stack1; //default :deque<string>

   Typedef stack<string, vector<string> > Stack2;

   Typedef stack<string, list<string> > Stack3;

   2queue

   队列,是一个受到限制的deque形式,只可以在队列一端放入元素,而在另一端删除它们。需要使用queue而不是deque的惟一理由就是,当读者希望强调仅仅执行与queue相似的行为的时候。

   Queue的理想和默认实现是基于deque的。

   3priority_queue

   当向一个优先队列用push压入一个对象时,那个对象根据一个比较函数或函数对象在队列中排序,priority_queue确定在用top查看顶部元素时,该元素是具有最高优先级的一个元素,当处理完该元素,用pop删除后,下一个元素进入该位置,因此,priority_queue拥有与stack几乎相同的接口,但它们的表现不同。

    Priority_queue的默认序列容器是vector.

7、 关联式容器

Setmapmultisetmultimap,是关联式容器,因为它们将关键字与值对应起来,至少mapmultimap是这样,而set可看成是没有值的map,它只有关键字,它们都是通过树形结构来实现,如set为平衡二叉树。

1) set

仅接受每个元素的一个副本,它也对元素进行排序(进行排序并不是set的概念定义所有,但是set用一棵平衡树数据结构来存储其元素以提供快速的查找,因此在遍历set的时候就产生了排序的结果)

2) map

是每个关键字对应一个值

3) multiset

可接受相同元素的多个副本

4) multimap

一个关键字对应着多个映射值。

Set

set的底层实现是基于平衡二叉树的(当然标准书中并没有这么规定)

②由于关联式容器是顺序的,那么set就不允许对其中的元素作直接的修改,否则所谓的关联式将不再关联——容器中的元素已经不再符合某种顺序了。

set的排序规则有两种确定方式,一是采用模板参数,一是采用构造参数。前者使得排序规则成为set类型的一部分(在对整个容器作比较等运算的时候,这个是比需的);后者仅在构造一个实例对像的时候用到,但其类型不会改变(虽然排序规则发生了变 化),此处的排序规则通常比模板参数中的规则具有更高的优先级。

④由于STL基本上采用的是reference语义,故要求其元素必须具备assignable,copyable,comparable

Map

mapset的最大区别在于map是一种特殊的set,它的所有元素都是pair<key,value>

map最大的特性在于map提供了下标subscript操作的能力,你可以向数组一样操作map[key]来引用相应的值。这个除了方便以外同样也是问题的根源。

③几乎所有针对map的操作都是基于key的。比如,排序就是通过比较key来进行的。

④对于set成立的操作在map中基本上都成立

 

posted on 2012-06-29 22:33  歌舞程序  阅读(194)  评论(0编辑  收藏  举报