为什么要使用STL
数据结构的分离(如vector)和算法的分离(如,STL的sort()函数是完全通用的,你可以用它来操作几乎任何数据集合,包括链表,容器和数组)。
STL其实是一种泛型编程(Generic Programming,简写GP)是一种基于参数化(parameterization)的编程技巧:可以使用类型参数化另一种类型(例如,vector的元素类型就是通过参数确定的);算法也可以参数化另一种算法(例如,使用比较函数参数化排序函数)。GP的目的是将有用的算法或者数据结构尽可能地一般化,并使其最优化。
三个基本的STL组件
1)迭代器提供了访问容器中对象的方法。例如,可以使用一对迭代器指定list或vector中的一定范围的对象。事实上,C++的指针也是一种迭代器。
2)容器是一种数据结构,如list,vector,和deques ,以模板类的方法提供。为了访问容器中的数据,可以使用由容器类输出的迭代器。
3)算法是用来操作容器中的数据的模板函数。例如,STL用sort()来对一个vector中的数据进行排序,用find()来搜索一个list中的对象。函数本身与他们操作的数据的结构和类型无关,因此他们可以在从简单数组到高度复杂容器的任何数据结构上使用。
STL的标志符都封装在名字空间std中。如,STL的sort()算法编译为std::sort()
几种容器比较
vector和数组类似,它拥有一段连续的内存空间,并且起始地址不变,因此它能非常好的支持随机存取,即[]操作符,但由于它的内存空间是连续的,所以在中间进行插入和删除会造成内存块的拷贝,另外,当该数组后的内存空间不够时,需要重新申请一块足够大的内存并进行内存的拷贝。
list就是数据结构中的双向链表,因此它的内存空间可以是不连续的,通过指针来进行数据的访问,这个特点使得它的随机存取变的非常没有效率,即没有[]操作符的重载。但由于链表的特点,它可以以很好的效率支持任意地方的删除和插入。
deque是一个double-ended queue,它的具体实现不太清楚,但知道它具有以下两个特点:
它支持[]操作符,也就是支持随机存取,并且和vector的效率相差无几,它支持在两端的
操作:push_back,push_front,pop_back,pop_front等,并且在两端操作上与list的效率
也差不多。
Map是STL的一个关联容器,它的元素是键-值对,map内部的实现自建一颗红黑树,这颗树具有对数据自动排序的功能。
set是集合,也是一个关联容器,元素是键-值对。set中不会包含重复的元素,这是和vector的第一个区别,第二个区别是set内部用红黑树实现,便于元素查找,而vector是使用连续内存存储,便于随机存取。
Eg:
set s; //与map的区别,这里只操作key(int) s.insert(1); s.insert(2); s.insert(1); //插入重复元素,直接别忽略 s.insert(6); set::iterator i; i = s.find(6); //返回元素值为6的位置 cout << *i << endl; //输出元素值
因此在实际使用时,如何选择这几个容器中哪一个,应根据你的需要而定,一般应遵循下面
的原则:
1、如果你需要高效的随机存取,而不在乎插入和删除的效率,使用vector
2、如果你需要大量的插入和删除,而不关心随机存取,则应使用list
3、如果你需要随机存取,而且关心两端数据的插入和删除,则应使用deque。
4、如果你要存储一个数据字典,并要求方便地根据key找value,那么map是较好的选择
5、如果你要查找一个元素是否在某集合内存中,则使用set存储这个集合比较好
几种算法介绍
1、sort 函数
可以直接对数组排序,复杂度为 n*log(n) ,默认的排序方式是升序,使用sort函数需要#include 。
这个函数可以传两个参数或三个参数。sort(int a, int b)表示排序数组区间[a,b)。注意第二个参数是区间尾地址的下一地址。如, 对int a[100] 排序是sort(a,a+100),对向量 v 排序是sort(v.begin(),v.end())。第三个参数是可以自行定义的比较函数。返回值是 bool 型,两个参数的类型是数组类型,它规定了什么样的关系才是“小于”。如:
bool cmp(int a,int b) { return a < b; }
如果要降序排列,只要将”<”改成”>”就可以了
2、qsort函数
有四个参数,分别是,数组名,数组长度,sizeof(数组类型),比较函数。如:qsort(a,100,sizeof(a[0]),cmp);
比较函数的定义与sort不同。对于int,char类型
int cmp(void *a, void *b) { return *(int *) a - *(int *)b; }
对于double类型
对 double 类型数组排序(特别要注意)
int cmp( const void *a , const void *b ) { return *(double *)a > *(double *)b ? 1 : -1; }
3、find函数
(1)size_type string::find(char c) const;
(2)size_type string::find(char c,size_type idx) const;
(3)size_type string::find(const string& str) const;
(4)size_type string::find(const string& str,size_type idx) const;
(5)size_type string::find(const char* cstr) const;
(6)size_type string::find(const char* cstr,size_type idx) const;
(7)size_type string::find(const char* cstr,size_type idx,size_type chars_len) const;
以上函数如果查找失败返回string::npos,如果成功:
函数(1)返回从头开始的第一个字符所在位置
函数(2)返回从idx开始的第一个字符所在位置
函数(3)返回从头开始的第一个子字符串所在位置
函数(4)返回从idx开始的第一个子字符串所在位置
函数(5)返回从头开始的与char*串相等的第一个子串所在位置
函数(6)返回从idx开始的与char*串相等的第一个子串所在位置
函数(7)返回从idx开始的与char*串前chars_len个字符相等的第一个子串所在位置
如果你可以确定你要查找的字符串靠后或者同时有多个子字符串符合,应该使用rfind()系列或者find_last_of()系列函数来查找