C++ STL初步学习

Standard Template Library (STL)是C++中一个挺方便的东西. (参考蒙教授学习笔记)

<一> Vector

size和capacity

size平时用得很多,而capacity就基本没用过了。其中size表示的是vector里面当前有多少个元素,而capacity表示的是内存实际分配了多少个元素的空间给vector。和数组一样,vector也是支持随机访问的,所以vector里面的元素的存储必然是连续的。和数组不一样的是,vector的大小是可以改变的,所以内存要预先给vector分配一定量的空间,当vector使用的空间超过分配的空间时,那么程序将在内存中寻找另外一段更长的连续空间,将原来的数据copy到新的内存空间中,然后再销毁原来使用的那一段空间。这一个过程的时间复杂度是O(n)。

resize和reserve

resize改变vector的size,reserve改变vector的capacity。

push_back和insert

push_back和insert用于vector元素的插入,不同的是,push_back仅能在vector末尾添加元素,而insert可以在任意位置添加元素。当要往vector插入一个元素时,若size超过了capacity,那么此次操作的时间复杂度是O(n)的,反之是O(1)的,所以可以认为平摊的时间复杂度是O(1)。

insert的主要用法有两个,第一个就是在vector的某一个位置插入一个数据,另外一个就是在某一个位置插入一段数据,显然这两种用法的时间复杂度都是O(n)的。

pop_back和erase

pop_back和erase用于vector的删除,不同的是pop_back只能删除最后一个元素,而erase可以删除任意一个位置或者一段范围的元素。pop_back是一个过程,而erase会返回一个指向首个所删除元素的位置的迭代器。因为涉及到元素的移动,所以erase的时间复杂度也是O(n)的。

swap

swap的作用是交换两个vector

clear

clear的作用就是清除vector里的所有元素。clear的实质就是调用erase,时间复杂度也是O(n)。值得注意的是,clear虽然清除了vector里面的元素,但之前使用的空间是没被释放的。

[]、at、front、back

vector可以通过迭代器访问,也可以用过下表操作[]、at来访问。[]和at唯一不同的地方就是at会作范围检测,如果下标超过了vector的size,那么程序会报范围错误。front和back分别表示vector的第一个元素和最后一个元素

 

<二>List

size和resize

size表示list里面有多少个数据,resize的作用是重新设置list容纳数据的大小。

与vector的存储结构不同,list的元素不是连续存储的,所以求list中两个位置的距离不能直接用+-操作来求,而是要逐个遍历求得,所以list.size()的时间复杂度是O(n)的。

和vector的resize不同的是,若new_size小于当前的size,list的resize删除多余元素之后会释放内存空间。

empty
empty的作用是判断list当前是否为空,方法是判断list的头指针和为指针是否相等,相等则表明list为空。

front和back

分别返回list的第一个元素和最后一个元素。相当于*begin()和*(--end())

push_front、push_back和insert

和deque一样,list可以用push_front在list的头端插入元素,用push_back在list的尾端插入元素,以及用insert在任意位置插入元素。由于list采用的是链表结构,所以在任意位置插入元素的时间复杂度是O(1)的。但测试表明,若只从线性表的两端插入元素的话,list的效率远不及vector和deque。先看insert的源代码。

push_front和push_back以及assign都是调用insert这个过程进行插入操作。和vector不同的是,list的非端点插入元素时只要设置好新节点和左右两个节点的位置关系即可,无需复制元素,这个特点让list在非端点插入元素具有极高的效率。虽说list在随机位置插入的效率很高,但前提是你首先要获取要插入位置的iterator,所以list的随机插入的时间复杂度取决于寻找插入位置的时间复杂度,实际是O(n)的,实验结果表明,在完全随机插入位置的情况下,list的效率竟远不及vector高

pop_front、pop_back、clear和erase

pop_front和pop_back用于删除list首端和尾端的数据,clear是清空list所有数据,erase可以删除任意位置或者一段范围的数据。pop_front和pop_back只是erase的一个特例,它们都是调用erase的过程。先看erase的源代码。

一个比较奇怪的现象是,我先用push_back插入数据,然后用pop_back删除数据,不停重复,观察内存使用情况发现,内存使用率竟然不停地增长。但用clear()删除数据时发现内存会被释放。

swap

swap可以交换两个list,用法可以是list1.swap(list2)或者swap(list1,list2);由于只交换他们的头指针,所有时间复杂度是O(1)的。

splice

splice的作用就是把一个list的一段数据移动插入到另外一个list(或者自己本身)的任意一个位置。这一过程只需要处理移动的那一段数据的头尾指针与所移动到位置前后指针的关系即可,所以时间复杂度是常数级别的。splice提供了3个版本

remove和remove_if

remove的作用是删除list中和参数相等的所有数据,对参数的要求是必须支持==运算。时间复杂度是O(n)的。以下是remove的源代码。

remove_if和remove不同的地方就是remove_if不使用list数据类型默认的==操作(也就是list中的数据不必要有==操作),而是调用一个比较函数来比较参数和list中的数据,若比较函数返回非0值,则表示匹配成功,删除list中相应的数据。

unique

unique的作用是删除相邻重复的数据。和algorithm里面的unique有所不同的地方是list的unique是真实地删除相邻重复数据,而algorithm库的unique并没有真实删除相邻重复的元素,而是把这些元素移动到容器的后端。unique有两个版本,一个是不带参数,另外一个可以带一个比较函数。以下是unique不带参数的源代码。

merge

merge的作用是合并两段有序的list,并且合并后的list也是有序的,时间复杂度为O(n)

sort

algorithm库里的sort仅供能连续存储的容器使用,由于list是链表结构,所以不能用algorithm库的sort给list排序。不过,标准库根据list的特点,为list设计了一个时间复杂度同为nlog(n)的算法。这个排序算法应该算是非递归版的归并排序。list的sort有两个版本,一个是不带参数的,另外一个是带一个比较函数的。以下是不带参数的sort的源程序。

 

posted @ 2012-12-06 15:01  gumcstronger  阅读(918)  评论(0)    收藏  举报