【説明する】STL
作为C++标准不可缺少的一部分,STL应该是渗透在C++程序的角角落落里的。
STL不是实验室里的宠儿,也不是程序员桌上的摆设,她的激动人心并非昙花一现。
所以今天要整理的东西就是STL!(orz 杨乐大神)
一.引入
STL(Standard Template Library),即标准模板库。该库包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法。
从逻辑层次来看,在STL中体现了泛型化程序设计的思想(generic programming),引入了诸多新的名词,比如像需求(requirements),概念(concept),模型(model),容器(container),算法(algorithmn),迭代子(iterator)等。
与OOP(object-oriented programming)中的多态(polymorphism)一样,泛型也是一种软件的复用技术。
从实现层次看,整个STL是以一种类型参数化(type parameterized)的方式实现的,这种方式基于一个在早先C++标准中没有出现的语言特性--模板(template)。
如果查阅任何一个版本的STL源代码,你就会发现,模板作为构成整个STL的基石是一件千真万确的事情。
除此之外,还有许多C++的新特性为STL的实现提供了方便。
STL 相当于一个工具箱,里面有 C++ 内置的函数与容器,可以直接拿来使用(这样就不用连工具都要自己造了)!
但这些我们暂且不深入谈,仅仅来了解她的大体,会使用她便可(反正深了我也不会hhhh)
二.分析?
运用头文件大部分都是
#include<algorithm>
用的时候只需要在头文件中包含进来即可
algorithm(算法) 完成特定功能
container(容器) 用于存储数据
iterator(迭代器) 访问容器中的内容[类似于指针]
三.我认为比较常用的STL:
1.Algorithm(算法)部分
1)
* min(x, y):取两者中的较小值
* max(x, y):取两者中的最大值
max+min函数(这个好像是在cmath也是有的吧,记不太清楚,有兴趣的可以手动Ctrl)
{
它们调用起来十分简单,只要满足 x,y 是相同类型,并且可以比较大小即可
必须是同种类型之间进行的比较!
(int与double不能够进行比较)
Eg:
int a = 5, b = 4, c = min(a, b); // c = 4 double x = 1.5, y = 3.5, z = max(x, y); // z = 3.5
}
2)
* swap(x, y):交换两者的值
swap函数
{
调用时只要满足 x,y 是相同类型即可
Eg:
int a = 5, b = 4; swap(a, b); // a = 4, b = 5 double x = -1.0, y = 2.5; swap(x, y); // x = 2.5, y = -1.0 // !swap(a, x) 无法调用:类型不相同
}
3)
* sort(first, last):对于在 [first, last) 中的元素进行排序
* sort(first, last, comp):对于在 [first, last) 中的元素进行排序,其中 comp 为比较器
sort函数
{
默认是从小到大进行排序,可以修改为从大到小进行排序,如下:
int a[10] = {5, 2, 1, 3, 4}; sort(a, a+5);// a = [1, 2, 3, 4, 5, ...] 普通排序 int cmp(int x, int y) { return x > y; } // 比较器 sort(a, a+5, cmp);// a = [5, 4, 3, 2, 1, ...] 从大到小排序
几点需要注意的地方:
排序的区间为[first, last),左闭右开;
如果需要排序A[1..5]中的数,则需要调用sort(A+1, A+6);
* 其实还可以自己定义比较器,作为排序的准则:例如,我们需要按照个位数来比较大小,则可以定义比较器为
int cmp(int x, int y) { return x % 10 < y % 10; }
* 对于自己定义的结构体,可以定义自己的比较器来实现排序功能。
// 以 a 为第一关键字,b 为第二关键字进行排序
int cmp(Mystruct x, Mystruct y) { return x.a == y.a ? x.b < y.b : x.a < y.a;//三目运算符 }
}
4)
* lower_bound(first, last, element):
给定 [first, last)中的已经从小到大好排序的元素,找出最前的一个不比 element 要小的元素的位置
lower_bound函数
{
注意:element返回的是指针,并不是下标!!
它的作用就是:
找出最前的一个不比element要小的元素的位置
ps:若均大于element,则返回最开始的位置
(小) (后)
Eg:
void lower_bound_stl() {
int a[10] = {5, 2, 1, 3, 4, 3, 2, 4}; sort(a, a+8); // a = [1, 2, 2, 3, 3, 4, 4, 5] 已从小到大排好序 int p2 = lower_bound(a, a+8, 2) - a; // p2 = 1 // a中最前的不比 2 小的元素是: a[1] = 2 int p4 = lower_bound(a, a+8, 4) - a; // p4 = 5 // a中最前的不比 4 小的元素是: a[5] = 4 int p0 = lower_bound(a, a+8, 0) - a; // p0 = 0 // a中最前的不比 0 小的元素是: a[0] = 1 int p6 = lower_bound(a, a+8, 6) - a; // p6 = 8 // a中没有不比 6 小的元素,所以返回最后的一个位置 a[8] // 注意:a[8] 中并没有值,是数组的最末端
cout << p2 << endl;
cout << p3 << endl;
cout << p0 << endl;
cout << p6 << endl;
}
}
5)
疑似扯远的感觉?
*unique()函数是一个去重函数
unique()函数
{
STL中unique的函数 unique的功能是去除相邻的重复元素(只保留一个),还有一个容易忽视的特性是它并不真正把重复的元素删除。
他是c++中的函数,所以头文件要加#include<iostream>,具体用法如下:
int num[100]; unique(num,mun+n); /* 返回的是num去重后的尾地址,之所以说比不真正把重复的元素删除,其实是,该函数把重复的元素一到后面去了,然后依然保存到了原数组中,然后返回去重后最后一个元素的地址,因为unique去除的是相邻的重复元素,所以一般用之前都会要排一下序 */
}
6)
strchr()函数为字符串判断函数
strchr
{
char c[100]; strchr(c,'.') //如果c字符串中含有 '.' 则返回 '.' 的位置指针,否则返回NULL;
此函数包含在头文件#include<cstring>中。
如果有两个或两个以上字符就返回第一个的地址。
}
/*--------------------啦啦啦~我是萌萌的分割线酱~---------------------*/
2.容器 (Container)部分
STL 中的容器被分配在不同的库中,用的时候只需要在头文件中包含对应的库即可
#include <vector> // 向量:用于存储连续的元素,类似数组 #include <set> // 集合 #include <queue> // 队列 #include <stack> // 栈 #include <map> // 映射:相当于一个坐标无限大的数组 #include <priority_queue> // 优先队列:类似于堆 #include <list> // 列表:类似于链表
接下来介绍几个在程序中常使用的容器啦啦啦~
1)
向量(vector)
用于存储连续的元素,类似数组;并且可以动态改变数组的大小(不必提前声明数组大小)
给出可爱的代码酱~
void vector_stl() { // vector 声明 vector<int> a; // 声明一个空的 vector vector<int> b(5, 0); // 声明 vector 中有 5 个元素,并且初始值都为 0 // vector 访问 for(int i=0; i<5; i++) b[i] = i; // vector 中下标从 0 开始 // ! a[0] = 1; 非法操作: a 还是空的,没有第一个位置 // ! a[5] = 5; 非法操作: b 没有第六个位置 // vector 添加元素 for(int i=0; i<5; i++) a.push_back(i * i); // 在 a 最后增加一个元素 for(int i=0; i<5; i++) cout << a[i] << " "; // 输出 vector a // 输出结果: 0 1 4 9 16 // vector 设定长度 vector<int> c; c.resize(5); // 设置 c 的大小为 5,下标 [0-4] c[4] = -4; // c[4] 是可以被访问的 // vector 长度 (数组大小) int len = c.size(); // len = 5 // vector 清空 c.clear(); // 清空 c 数组 // ! c[4] = -4; 非法操作:数组已经被清空,长度变为 0 }
2)
二元组(pair)
用于存储二元组 (x,y)(并且 x,y 类型可以不相同)
代码酱来也~
void pair_stl() { // pair 声明 pair<int, int> a; // 声明一个二元组a pair<int, int> b(3, 4); // 声明一个二元组b, x=3, y=4 typedef pair<int, int> PI; PI c(5, 6); // 声明一个二元组c // pair 访问 int x = c.first, y = c.second; // x = 5, y = 6 PI d = c; // 相同类型的二元组可以直接赋值 c = PI(7, 8); // 重新赋值二元组 d = make_pair(9, 10); // 另一种赋值方式
/*二元组 (pair)的一个优点是可以直接比较大小;它会先比较第
一关键字(x),再比较第二关键字(y)*/
PI arr[10]; for(int i=0; i<5; i++) arr[i] = PI(5 - i, i * i); sort(arr, arr+5); for(int i=0; i<5; i++) cout << "First element:" << arr[i].first << " " << "Second element:" << arr[i].second << endl;
/* 通过二元组 (pair)可以把不同类型的元素给有机整合起来*/ typedef pair<int, PI> PII; // 定义三元组 PII p = PII(2, PI(4, 8)); cout << p.first << "," << p.second.first << "," << p.second.second << endl; typedef pair<string, int> People; // 定义(字符串,整数)二元组 People pa("Edward", 16); People pb("Bob", 17); if(pa > pb) swap(pa, pb); // 可以直接进行比较,以字符串为第一关键字,整数为第二关键字进行比较 cout << pa.first << ":" << pa.second << endl; }
3)
集合(set)
1.在集合 (set)中,可以像普通的集合一样,保存所有不同的数
set<int> S; // 定义一个整型类型的 set for(int i=0; i<10; i++) S.insert(i*i); // 把 0-9 的平方数加入集合中 set<int>::iterator p; // iterator:迭代器,相当于一个指针 p = S.find(4); // 指针 -- 找到 4 所在位置 cout << *p << endl; // 输出这个位置的值 -- 4 ++p; // 指针后移 cout << *p << endl; // 输出后一个平方数的值 -- 9 /* 输出结果: 4 9 */
2.在集合 (set)中,可以支持查找一个数的位置
p = S.find(5); // 假如我们想要找一个集合中没有的数 cout << "Notice : (5 is not a square number) " << *p << endl; cout << (p == S.end()) << endl; // 就会返回一个特殊的指针:S.end() 结尾的指针 // C++ 中的容器都是左闭右开的: // S.begin() 头指针 - 存放数据,S.end() 尾指针 - 不存放数据 /* 输出结果: Notice : (5 is not a square number) 10 1 */
3.在集合 (set)中,还有另一种方式查看一个数是否在集合中
for(int i=0; i<10; i++) if(S.count(i)) cout << i << " is an element of S." << endl; else cout << i << " is not an element of S." << endl; // count(x),如果 x 存在则返回 1,不存在则返回 0 /* 输出结果: 0 is an element of S. 1 is an element of S. 2 is not an element of S. 3 is not an element of S. 4 is an element of S. 5 is not an element of S. 6 is not an element of S. 7 is not an element of S. 8 is not an element of S. 9 is an element of S. */
4.还有最后一点就是,在集合 (set)中,亦可以直接支持lower_bound 操作
p = S.lower_bound(20); // 假如我们想要找一个集合中不小于 20 的数 cout << "The first element not lower than 20: " << *p << endl; S.delete(p); // 删除一个数:使用指针的方式 p = S.lower_bound(20); // 再次寻找 cout << "The first element not lower than 20: " << *p << endl; p = S.lower_bound(100); // 假如我们想要找一个集合中不小于 100 的数 cout << (p == S.end()) << endl; // 假如没有数比它大,则返回尾指针 /* 输出结果: The first element not lower than 20: 25 The first element not lower than 20: 36 1 */
3.迭代器 (Iterator)部分
这里的其实我也不是很清楚w
STL 中的迭代器相当于不同的容器的指针
vector<int>::iterator vi; // 定义迭代器,直接在后面加::iterator
vector<int> V; // 定义容器 for(int i=1; i<10; i++) V.push_back(i * 3 - 2); // 新增值 for(vi = V.begin(); vi != V.end(); ++vi) cout << *vi << " "; cout << endl; // 按顺序输出容器中的值 // 特殊的迭代器:V.begin(), V.end()(左闭右开) // 迭代器可以自增:往后挪一位 // 不同容器的迭代器存在着区别
输出结果:
1 4 7 10 13 16 19 22 25
// STL 中每个容器都有对应的迭代器 set<int> S; // 定义容器 set<int>::iterator p; // 定义迭代器 for(int i=0; i<10; i++) S.insert(i * i); // 插入平方数 p = S.begin(), ++p; S.erase(p); // 第一种删除方式(迭代器) :删除第二个元素 S.erase(49); // 第二种删除方式(值删除) :删除 49 cout << "The Sequence : "; for(p = S.begin(); p != S.end() ; ++p) cout << *p << " "; cout << endl; // 顺序输出
输出结果:
The Sequence : 0 4 9 16 25 36 64 81
End.