C++学习笔记(一) 序列式容器及适配器
容器是存储数据的集合,序列容器则是指明它的存储方式为序列式存储。C++有三种序列式容器:vector,deque,list。其中,前两种都是顺序存储方式,第三种则是指链表。为了实现算法和容器的分离,STL提供的这几个容器都只实现了很少的操作,例如插入,删除,以及对容器本身容量的设置等,而像排序,查找之类的操作则都是由算法库去提供的。
从效率上而言,因为前两者是顺序存储,所以他可支持随机访问,若按某种次序存放,在查找时则可有较高的效率,但在插入上,因为有后移操作,所以效率不高。list则正好相反。所以在容器的选择上,我们应该根据需要的业务逻辑来选择合适的容易。
提到容器,就不得不提迭代器,每一个容器都有自己的迭代器,利用它可以访问容器内部的元素,它的使用方式和指针类似,实际上,指针可以看成是特殊的迭代器。以Vector为例,获得迭代器的函数如下:
[cpp]
vector::begin(3)
Return iterator to beginning (public member function)
vector::end(3)
Return iterator to end (public member function)
vector::rbegin(3) Return reverse iterator to reverse beginning (public member function)
vector::rend(3) Return reverse iterator to reverse end (public member function)
[html] view plaincopy
<span style="white-space:pre"> </span>
在容器的其他各类方法中,迭代器也大量的被使用在其中,具体的还是参考文档更好,这里就不详述了。
对于这三种容器,它们有很多共有的函数,像:push_back, pop_back, insert, erase等等,但同时某些容器也有它单独的方法,例如deque和list还具有push_front, pop_front等函数方法,这个中的区别主要还在于这些容器的实现方式上。
string其实可以看做是一个特殊的序列式容器,它拥有几乎所有的容器的基本函数,所以我们也能通过迭代去访问string对象。
适配器
C++primer对适配器是这样定义的:
A library type, function, or iterator that given a type, function, or iterator, makes it act like another. There are three sequential container adaptors: stack, queue , and priority_queue . Each of these adaptors defines a new inte易做图ce on top of an underlying sequential container.
而我对它是这样理解的,适配器就像一个接口,其底层可以封装各类容器,它对外则表现出一种抽象类型,使得用户只能通过抽象类型所提供的接口函数实现对底层容器的操作。
然后,在我的学习过程中,却渐渐产生了一个疑惑,翻阅C++的帮助文档,适配器一般只提供了这样一种构造函数,例如stack:
[cpp]
explicit stack ( const Container& ctnr = Container() );
也就是说如果你不为其提供一个容器,它将使用自己默认的容器deque,而如果你为它提供了一个容器,它将维护的不是这个容器本身,而是它的一个拷贝。
A container adaptor keeps a container object as data. This container object is a copy of the argument passed to the constructor, if any, otherwise it is an empty container.
这样看来,如果我已经持有了一个容器,那么,我将无法使用适配器对该容器进行封装操作,而只能封装它的一个拷贝,通过接口执行的所有的操作只对副本有效,这样似乎会导致这样一种限制,那就是:只能使用一种适配器对容器进行封装,并且封装后,原来的容器应该被丢弃掉。存在这样的限制将使在如下需求中应用适配器成为不可能,即:我持有一个容器,我希望它在不同的场合表现出不同的特征,例如某些场合中我希望它只表现出栈的特征,而在另一些场合中,则希望它表现出队列的特征。限制它不能使用适配器的原因就在于适配器的拷贝机制,如果我分别使用栈和队列去封装它,那么这两个队列将各自得到一个原始容器的拷贝,从而造成数据的不一致,这将使我通过不同的适配器对相同的容器进行操作成为不可能。
其实,在java中也有类似的概念,不同的是,它是可以使用接口去解决这个问题,例如一个容器可以实现栈的接口,也可以实现队列的接口,我可以持有一个栈的引用变量和一个队列的引用变量,并让它们都指向这个容器,那么我通过不同的引用去访问这个容器就只能使用那个引用特有的方法,问题也就解决了。
STL在设计之初应该不可能没有考虑到这个问题,是不是存在着这样一个机制能够解决这个问题呢?如果有哪位大神路过,请一定留下您的笔墨为小弟答疑解惑,小弟感激不尽。
作者:jus易做图anda
补充:软件开发 , C++ ,