文章目录
STL 标准模板库使用参考
C++ 的 STL 从广义上可以分为 algorithm(算法)、container(容器) 和 iterator(迭代器) 三类,包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法
STL 被组织在以下 13 个头文件中:
< algorithm >
< deque >
< functional >
< iterator >
< vector >
< list >
< map >
< memory >
< numeric >
< quee >
< set >
< stack >
< utility >
Vector 向量容器
简介
vector 是一种简单高效的容器,在尾端插入和删除元素,算法时间度为 O(1),其他元素插入和删除为 O(n). vector 可以动态调整所占用的内存空间。
头文件: < vector >
用数组方式访问 vector 元素参考代码
#include <iostream>
#include <vector>
using namespace std;
int main() {
/// 声明方式
vector<int> v;
v.push_back(20);
v.push_back(26);
v.push_back(12);
/// vector 可以用数组的方式访问
for (int i = 0; i < v.size(); i++) {
cout << v[i] << " ";
}
return 0;
}
用迭代器访问 vector 的参考代码
#include <iostream>
#include <vector>
using namespace std;
int main() {
int j;
vector<int> v;
v.push_back(0);
v.push_back(1);
v.push_back(2);
/// 0 1 2
/// 插入 9 在第二个后面
v.insert(v.begin() + 2, 9);
/// 0 1 9 2
/// 插入 5 为首元素
v.insert(v.begin(), 5);
/// 5 0 1 9 2
/// 插入 12 为末元素
v.insert(v.end(), 12);
/// 5 0 1 9 2 12
/// 删除第二个元素
v.erase(v.begin() + 1);
/// 5 1 9 2 12
/// 删除前三个元素
v.erase(v.begin(), v.begin() + 2);
/// 9 2 12
/// 迭代器,相当于游标
vector<int>::iterator i;
for (i = v.begin(), j = 0; i != v.end(); i++, j++) {
cout << "v[" << j << "] = " << *i << endl;
}
/// 判断是否为空 (为空返回 1, 不为空返回 0)
cout << v.empty() << endl;
/// 0
/// 元素实际个数
cout << v.size() << endl;
/// 可容纳的最大元素个数
cout << v.max_size() << endl;
/// 当前可容纳的 vector 元素个数
cout << v.capacity() << endl;
/// 首元素引用
cout << v.front() << endl;
/// 末元素引用
cout << v.back() << endl;
/// 删除末尾的一个元素
v.pop_back();
/// 调整数据空间大小
v.reserve(30);
cout << v.capacity() << endl;
/// 反向迭代器
vector<int> :: reverse_iterator ri;
/// 首尾反向
for (ri = v.rbegin(); ri != v.rend(); ri++) {
cout << * ri << " ";
}
/// 2 9
return 0;
}
结构体容器参考代码
#include <iostream>
#include <vector>
using namespace std;
struct stu {
int x;
int y;
};
int main() {
int j;
/// 结构体容器
vector<stu> v1;
vector<stu> v2;
struct stu a = {1, 2};
struct stu b = {2, 3};
struct stu c = {4, 5};
v1.push_back(a);
v1.push_back(b);
v1.push_back(c);
v2.push_back(c);
v2.push_back(b);
v2.push_back(a);
cout << "v1:" << endl;
for (int i = 0; i < v1.size(); i++) {
cout << v1[i].x << " " << v1[i].y << endl;
}
cout << "v2:" << endl;
for (int i = 0; i < v2.size(); i++) {
cout << v2[i].x << " " << v2[i].y << endl;
}
/// 两结构体元素交换
swap(v1, v2);
cout << "v1:" << endl;
for (int i = 0; i < v1.size(); i++) {
cout << v1[i].x << " " << v1[i].y << endl;
}
cout << "v2:" << endl;
for (int i = 0; i < v2.size(); i++) {
cout << v2[i].x << " " << v2[i].y << endl;
}
return 0;
}
deque 双端队列容器
deque 与 vector 很相似,不仅可以在尾部插入和删除元素,还可以在头部插入和删除,时间复杂度为 O(1),考虑到容器元素的内存分配策略和操作性能时,deque 比 vectot 有优势。
由于使用了 Map 管理以及块为单位进行内存分配,所以不易实现 capacity 和 reverse 函数,而且也不需要这种函数。
参考代码:
#include <iostream>
#include <deque>
using namespace std;
int main() {
deque<string> d;
/// 尾部插入元素
d.push_back("1a");
d.push_back("2");
d.push_back("3");
/// 高效的头部插入元素
d.push_front("front");
/// 删除首元素
//d.pop_front();
/// 删除尾元素
//d.pop_back();
/// 删除指定位置元素
d.erase(d.begin() + 1);
/// 删除所有元素
//d.clear();
/// 指定位置插入
d.insert(d.end() - 1, "insert");
/// 数组方式访问
for (int i = 0; i < d.size(); i++) {
cout << d[i] << " ";
}
cout << endl;
/// 迭代器访问
deque<string> :: iterator i;
for (i = d.begin(); i != d.end(); i++) {
cout << *i << " ";
}
cout << endl;
/// 两元素交换,可交换两个 queue 的所有元素
swap(d[1], d[2]);
/// 反向遍历
deque<string> :: reverse_iterator pi;
for (pi = d.rbegin(); pi != d.rend(); pi++) {
cout << *pi << " ";
}
cout << endl;
cout << "deque 是否有元素 " << d.empty() << endl;
cout << "deque 元素个数 " << d.size() << endl;
cout << "deque 的首元素为 " << d.front() << endl;
cout << "deque 的末元素 " << d.back() << endl;
cout << "deque 的最大容量为 " << d.max_size() << endl;
return 0;
}
list 双向链表容器
list 双向链表中任一位置的元素查找、插入和删除都具有高效的常数阶算法时间复杂度 O(1)。
set 集合容器
set 集合容器使用一种红黑树的平均二叉检索树,不会将重复键值插入,检索效率高 logn。检索使用二叉树的中序遍历,因此可将元素由小到大排列出来。
参考代码
#include <iostream>
#include <set>
using namespace std;
int main() {
set<int> s;
/// set<int, greater<int>> s; 在创建 set 时可以规定排序方式
for (int i = 1; i <= 100; i++) {
/// 此条语句判断是否插入成功
pair<set<int>::iterator, bool> p = s.insert(i);
if (p.second) {
cout << "插入成功" << endl;
} else {
cout << "已存在该元素,不重复插入" << endl;
}
}
/// 拷贝 s 生成 s2
set<int> s2(s);
/// 如果删除的是首尾元素可以直接使用 begin() end()
s.erase(s.begin());
cout << "erase 的返回值是删除成功元素的个数 " << s.erase(10) << endl;
cout << "\n";
s.erase(s.erase(10));
/// 不会重复插入
s.insert(5);
set<int>::iterator ii;
for (ii = s.begin(); ii != s.end(); ii++) {
cout << *ii << " ";
}
cout << "\n反向遍历" << endl;
set<int>::reverse_iterator ri;
for (ri = s.rbegin(); ri != s.rend(); ri++) {
cout << *ri << " ";
}
cout << endl;
cout << "元素个数为 " << s.size() << endl;
cout << "元素是否为空 " << s.empty() << endl;
/// 查找元素值,如指标不在尾末,则找到输出
ii = s.find(10);
if (ii != s.end()) {
cout << "查找 = " << *ii;
}
return 0;
}
multiset 多重集合容器
multiset 多重集合容器可将重复元素插入
参考代码
#include <iostream>
#include <set>
using namespace std;
int main() {
multiset<int> ms;
/// 插入元素
ms.insert(10);
ms.insert(13);
ms.insert(11);
ms.insert(13);
ms.insert(12);
ms.insert(13);
/// 查找元素
int v = 121;
multiset<int>::iterator ii = ms.find(v);
// auto ii = ms.find(v);
if (ii != ms.end()) {
cout << *ii << endl;
}
auto i = ms.begin();
while (i != ms.end()) {
cout << *i << " ";
i++;
}
cout << endl;
cout << "等于13的个数:" << ms.count(13);
return 0;
}
map 映照容器
map 映照容器的元素数据是一个键值和一个映照数据组成的,键值与映照数据之间有一一映照的关系。
参考代码
#include <iostream>
#include <map>
using namespace std;
int main() {
map<const char*, float> m;
m["apple"] = 3.4;
m["orange"] = 1.2;
m["pear"] = 3.5;
cout << m["apple"] << endl;
cout << m["orange"] << endl;
cout << m["pear"] << endl;
return 0;
}
#include <iostream>
#include <map>
using namespace std;
int main() {
map<int, string> m;
m[1] = "s1";
m[1] = "s2";
m[2] = "s3";
map<int, string>::iterator i;
for (i = m.begin(); i != m.end(); i++) {
cout << i->first << " " << i->second << endl;
}
return 0;
}
multimap 多重映照容器
multimap 与 map 基本相同,唯独不同的是,multimap 允许插入重复键值的元素,由于重复键值的存在,所以,multimap 的元素的插入、删除、查找都与 map 不相同。
参考代码
#include <iostream>
#include <map>
using namespace std;
int main() {
/// 定义 map 对象,当前没有任何元素
multimap<string, double> mp;
mp.insert(pair<string, double>("Jack", 300.5));
mp.insert(pair<string, double>("Kity", 200));
mp.insert(pair<string, double>("Memi", 500));
mp.insert(pair<string, double>("Jack", 306));
/// 使用前向迭代器中序遍历 multimap
multimap<string, double>::iterator it;
/// 删除键值等于 “Jack” 的元素
mp.erase("Jack");
for (it = mp.begin(); it != mp.end(); it++) {
cout << (*it).first << " " << (*it).second << endl;
}
/// 元素查找
it = mp.find("Nacy");
if (it != mp.end()) {
cout << (*it).first << " " << (*it).second << endl;
} else {
cout << "Not find if!" << endl;
}
return 0;
}
stack 堆栈容器
堆栈是一个线性表,插入和删除只在表的一端进行。一端称为栈顶(Stack Top);另一端则为栈底(Stack Bottom)。堆栈的元素插入称为入栈,元素的删除称为出栈。由于元素的入栈和出栈总在栈顶进行,因此,堆栈是一个后进先出(Last In First Out)表,即 LIFO 表。
C++ STL 的 stack 堆栈容器不设最大容量,提供入栈、出栈、栈顶元素访问和判断是否为空的基本操作。
参考代码
//
// Created by 10940 on 2020/8/4.
//
#include <iostream>
#include <stack>
using namespace std;
#define STACK_SIZE 100
int main() {
/// 创建
stack<string> s;
/// 插入元素
s.push("aaa");
s.push("bbb");
s.push("ccc");
/// 可限制大小
if (s.size() < STACK_SIZE) {
s.push("68");
}
/// empty 判断栈是否为空 为空返回 true 否则返回 false
while (!s.empty()) {
/// top 取栈顶元素(但不删除)
cout << s.top() << endl;
/// pop 删除栈顶元素
s.pop();
}
return 0;
}
queue 队列容器
queue 队列是一个线性存储器,与后进先出的堆栈不同,元素数据的插入在表的一端进行,在另一端删除,从而构成了一个先进先出(First In First Out)表。插入一端称为队尾,删除一端称为队首。
参考代码
#include <iostream>
#include <queue>
using namespace std;
int main() {
/// 创建一个队列
queue<int> q;
/// 插入数据
q.push(3);
q.push(5);
q.push(2);
cout << "元素个数为: " << q.size() << endl;
/// back 队末元素
cout << q.back() << endl;
while (!q.empty()) {
/// 打印队首元素
cout << q.front() << endl;
q.pop();
}
return 0;
}
priority_queue优先队列容器
优先队列是一种容器适配器,它的第一个元素(位于头部 top )总是队列中最大的元素,这里的“最大”是指队列元素的严格弱序中的“最大”。严格弱序是一系列数或事物按照一定的比较关系"<“排列得到的序列,”<"可以是数学中进行数值比较的大于,也可以是小于,还可以是其他含义。
priority_queue 优先队列容器使用堆排序算法,每次将最大值或最小值出列。时间复杂度为 O(nlogn)。
创建一个优先队列的格式为 priority_queue<T, Container, Comper>, 可以看出,创建一个优先队列默认需要三个参数(实际应用上有些参数可以省去)。
T : 队列中元素的数据类型
Container : 用于存储和访问队列元素的底层容器类型。
Compare : 比较关系,默认是数值上的小于关系,比如 1 < 2, 6 < 7,此时队列中元素由队头到队尾由大到小排列,采用默认 compare 时此参数可以省去。当需要采用其他标准进行比较时需要额外定义这一比较方式。当满足比较关系 “ < " 时,返回 true ,否则返回 false。
参考代码
#include <iostream>
#include <queue>
using namespace std;
int main() {
/// 创建优先队列,默认降序
priority_queue<int> q;
/// 完整格式
/// 末尾两个 > > 之间一定要有空格
/// 数据类型 容器 比较方式 这里一定要有空格
// priority_queue< T, Container, Compare> > a;
/// 升序队列
// priority_queue< int, vector<int>, greater<int> > a;
/// 降序队列
// priority_queue< int, vector<int>, less<int> > a;
/// 插入数据
q.push(93);
q.push(5);
q.push(2);
q.push(33);
q.push(52);
q.push(12);
cout << "元素个数为: " << q.size() << endl;
while (!q.empty()) {
/// 去队首元素
cout << q.top() << endl;
/// 出队列要先判断是否为空
q.pop();
}
return 0;
}
#include <iostream>
#include <queue>
using namespace std;
/*class cmp {
public:
bool operator() (const int a, const int b) {
return a > b;
}
};*/
/// 自定义比较方式
struct cmp {
bool operator() (const int a, const int b) {
return a > b;
}
};
int main() {
priority_queue<int, vector<int>, cmp > q1;
priority_queue<int, vector<int> > q2;
int a[] = {1, 3, 4, 2, 5, 0, 6};
for (int i = 0; i < 7; i++) {
q1.push(a[i]);
q2.push(a[i]);
}
cout << "q1: ";
while (!q1.empty()) {
cout << q1.top() << " ";
q1.pop();
}
cout << "q2: ";
while (!q2.empty()) {
cout << q2.top() << " ";
q2.pop();
}
return 0;
}
Unique 去重
"unique"是C++语言中的STL函数,包含于头文件中。功能是将数组中相邻的重复元素去除。然而其本质是将重复的元素移动到数组的末尾,
最后再将迭代器末尾指向最后不重复的下标。
注意:想要实现完全去重功能,需要在执行unique函数之前先对数组进行排序。
参考代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int a[maxn];
int main() {
int N;
while(scanf("%d", &N) != EOF) {
for (int i = 0; i < N; ++i) scanf("%d", &a[i]);
sort( a, a + N);
///去重
/// m 是去重后剩余的个数
int m = unique(a, a + N) - a;
printf("%d", m);
for (int i = m - 1; i >= 0; --i) printf(" %d", a[i]);
printf("\n");
}
return 0;
}
本文内容摘自《算法竞赛宝典 基础算法艺术》