在刷算法题时,若使用C++,有了STL的助力会使会使代码简洁易懂很多,写起来也会变得便捷。有人说用STL会弱化编程能力,其实我认为,如果只用基本的数据结构的基本操作的话,不算是在走捷径,毕竟不可能每次用到一个数据结构的时候都现造轮子,尤其是在笔试面试这样的短时间高强度的场合中。因此本文总结归纳一些算法题中常会用到的数据结构和基本操作,并尽量保证所展现的操作不超出数据结构本身的能力范围。同时,也会有一些系统自带的基础算法和一些结构等。只要算法题中我遇到的都会写在本文中。
常用容器
Vector
Vector相当于动态数组,平常一般用来直接作为数组使用。在LeetCode中vector现在一般也直接用作数组的输入和输出参数。
引用文件:#include <vector>
初始化一个vector:
vector<int> vec; vector<int> vec1(12); vector<int> vec2(12, 9);
vector<int> vec3(a+i, a+j)
|
其他的一些基本操作:
vec.push_back(x); vec.pop_back();
for(int i = 0; i < vec.size(); i++) vector<int>::iterator iter = vec.begin(); cout << *iter << endl;
vec.insert(vec.begin() + i, count, number);
vec.erase(vec.begin() + i, vec.begin() + j);
vec.clear();
|
Set
Set 在算法题中一般就是拿来当作一个不含重复值的数组来使用了。
#include <set> set<int> s;
s.insert(x);
if(s.find(x) != s.end()) { s.erase(x); } s.count(x)
if(!s.empty()) { s.clear(); }
|
Queue
队列是非常常用的一种数据结构,特点为先进先出。若只需要普通队列的功能,头文件 <queue>
即可;若需要使用双端队列,可引入STL头文件 <deque>
。
普通队列:
#include <cstdlib> #include <queue>
queue<int> q; q.push(x); if(!q.empty()) { q.pop(); } int m = q.front() int n = q.back() int length = q.size()
|
双端队列:
#include <deque>
deque<int> dq; deque<int> dq1(dq); dq1.swap(dq);
dq.push_back(x); dq.pop_front();
dq.push_front(x); dq.pop_back();
int m = dq.front(); int n = dq.back();
int length = dq.size(); bool isEmpty = dq.empty(); dq.clear();
|
Stack
栈也是一种很常见的数据结构,特点是先进后出。
#include <stack>
stack<int> s;
s.push(x); int m = s.top(); if(!s.empty()) { s.pop(); }
int length = s.size();
|
Map
Map是STL的一个关联容器,提供一对一的数据处理能力,在算法题中,我一般拿它当作哈希表来用。实际上STL还有 hash_map
。区别上,map
是用红黑树来实现的,查找复杂度为 O(log(n))
,hash_map
是用哈希表实现的,查找时间复杂度为 O(1)
,如果记录非常大,还是建议使用 hash_map
,查找效率会高很多。使用上两者的使用方法差别不大,这里就用 map
来做个示范。
#include <map>
map<int, int> mymap;
mymap[i] = j; mymap.erase(i);
int size = mymap.size(); if(mymap.find(i) != mymap.end()) { }
mymap.clear();
|
堆
使用STL构建一个堆主要是 vector
容器和几个函数相结合。在时间复杂度上面,堆插入元素的时间复杂度为 O(logn)
,得到最小(最大)值的时间复杂度为 O(1)
。示例代码如下:
#include <algorithm> #include <vector>
void Insert(int num) { if (((min.size() + max.size()) & 0x1) == 0) { if (max.size() > 0 && num < max[0]) { max.push_back(num); push_heap(max.begin(), max.end(), less<int>()); num = max[0]; pop_heap(max.begin(), max.end(), less<int>()); max.pop_back(); } min.push_back(num); push_heap(min.begin(), min.end(), greater<int>()); } else { if (min.size() > 0 && num > min[0]) { min.push_back(num); push_heap(min.begin(), min.end(), greater<int>()); num = min[0]; pop_heap(min.begin(), min.end(), greater<int>()); min.pop_back(); } max.push_back(num); push_heap(max.begin(), max.end(), less<int>()); } }
|
Algorithm
C++ 的 <algorithm>
库很强大,很多算法题常用的函数都在该库中。
sort
sort
主要用于对于一个序列,有序的操作比乱序简便很多,且快排 O(nlog(n))
的时间复杂度对于处理该问题可以接受时。
#include <algorithm>
bool myfunction(int i, int j) { return (i < j); }
sort(vector.begin(), vector.end()); sort(vector.begin(), vector.end(), myfunction); sort(vector.begin(), vector.end(), [](int i, int j) { return i < j; });
|
此外,还有三种排序,只做简单说明:
1、stable_sort
:稳定排序
2、partial_sort
:部分排序
3、partial_sort_copy
:复制并排序
最大值、最小值、replace、swap
很简单,主要为了做说明,直接上代码:
#include <iostream> // std::cout #include <algorithm> // std::min_element, std::max_element
using namespace std;
bool myfn(int i, int j) { return i<j; }
int main () { int myints[] = {10, 20, 30, 30, 20, 10, 20}; vector<int> myvector(myints, myints + 8);
cout << min(myints[0], myints[1]) << endl; cout << max(myints[0], myints[1]) << endl;
cout << *min_element(myints, myints+7) << endl; cout << *max_element(myints, myints+7) << endl;
cout << *min_element(myints, myints+7,myfn) << endl; cout << *max_element(myints, myints+7,myfn) << endl; replace(myvector.begin(), myvector.end(), 20, 90) swap(myvector[0], myvector[1]);
return 0; }
|
其他
pair
pair
是在做LeetCode 406题时遇到的,然后对其进行了一番查找,发现其操作还是挺简便的。
#include <utility> // pair 的头文件 #include <vector>
pair<int, int> p; vector<pair<int, int>> vec;
while(cin >> p.first >> p.second) { vec.push_back(make_pair(p.first, p.second)); }
for(auto node : p) { }
|