CONTENTS
- STL
- vector
- deque/list
- stack/queue
- priority_queue
- pair/tuple
- map/multimap
- set/multiset
- unordered_map/unordered_multimap/unordered_set/unordered_multiset
- DIY sort
- Iterator
- 2.5.3 The decltype Type Specifier
- 3.5.1 Defining and Initializing Built-in Arrays
- 3.6 Multidimensional Arrays
- 7.1.2 Defining the Revised Sales_data Class
- 13.6 Moving Objects
- Tips
- High Frequency Templates
STL
using namespace std;
vector
vector<int> v; //create
vector<int> v(nSize);
vector<int> v(nSize, t); //create and assign the size and initial value
vector<int> v{1,2,3};
v.push_back(elem);
v.popback(); //ATTENTION! return void!
v.insert(pos,elem);
v.emplace_back(elem); //construct quicker
v.size();
v.erase(beg,end); //delete elements from iterator beg to end. The "end" argument can be omit.
deque/list
deque
is implemented by array, and lisi
by double linked list. They can be used in the same way.
deque<int> dq(nSize, t);
list<int> lst(nSize, t);
dq.push_front(elem); //can be replace with "emplace" too
dq.pop_front(); //can push and pop at back too
dq.front(); //return element in the front
dq.back();
dp.empty(); //return bool value
stack/queue
Here we list all member functions.
stack<int> s(nSize, t); //default construct by deque, no iterator
queue<int, list<int>> q(nSize, t);
s.empty(); s.emplace(); s1.swap(s2); s.push(elem); s.pop(); //both
s.top(); //only stack, return reference
q.front(); q.back(); //only queue, return reference
priority_queue
ATTENTION: compare function less()
corresponds to a max heap, and function greater()
to a min heap.
priority_queue<int> q; //default construct by vector(diffrent from normal queue)
priority_queue<int, vector<int>, less<int>> q; //default compare function is less
pair/tuple
pair <string, string> pair1("key1","value1");
pair <string, string> pair2(make_pair("key2","value2"));
pair1.first="key3";
pair1.second="value3";
tuple<int, int, char> tp(10, 20, 'a');
get<0>(tp)=20;
map/multimap
map<string, int> mp;
map<string, int, greater<string>> mp2; //default less
map<string, int> mmp;
mp.emplace("one",1); //can use "insert({})" too
mp["two"]=2; //insert a new pair
mp["three"]+=3; //mp["three"]=3: once use index to get a element that doesn't exsit, insert a default pair
mp.find("one"); //return a interator to the position or the end, can check if a key exists
int count = mmp.count("key");
int val = mp["two"]; //if there is now such a key, insert a pair with default value
mp.empty(); //check if is empty
int count = mmp.erase("two"); //delete the element, count is the number of elements deleted
mp.erase(mp.begin(), mp.end()); //when one augument means delete one element
set/multiset
set<string> st;
multiset<string, less<string>> mst;
set.emplace("one");
set.find("one");
set.empty();
set.erase(--st.end()); //delete the last element
int count = mst.count("one");
int count = mst.erase("one");
unordered_map/unordered_multimap/unordered_set/unordered_multiset
Almost same usage as ordered container.
DIY sort
- For associative containers (like set) or
sort()
, we can define and use a function object.
class cmp {
public:
//can use "struct cmp {" instread of line 1-2 too
//override operator ()
bool operator ()(const string &a,const string &b) const { //const is necessary
//sort ascending by length
return (a.length() < b.length());
}
};
int main(){
set<string, cmp>myset{"11", "1", "111"};
return 0;
}
Attention that if you want use it in a priority queue, use a<b to make a max heap, while a>b is a min heap.
2. If the type of elements is not structure pointer or class pointer, we can overloaded relational operators in the member function of elements:
class myString {
public:
myString(string a):str(a){}
string str;
bool operator < (const myString &m)const { //const is necessary
return str.length() < m.str.length();
}
};
int main(){
vector<myString>v{myString("11"), myString("1"), myString("111")};
sort(v.begin(), v.end());
return 0;
}
- For
sort()
, we can define and use a normal function, too.
bool mycomp(string &a, string &b) { //reference makes it faster
return (a.length() < b.length());
}
int main(){
vector<string>v{"11", "1", "111"};
sort(v.begin(), v.end(), mycomp);
//same as this lambda:
sort(v.begin(), v.end(), [](const string & a, const string & b){
return a.length() < b.length();
});
return 0;
}
- The standard library defines a set of classes that represent the arithmetic, relational, and logical operators.
For example, if svec is a vector,
// passes a temporary function object that applies the < operator to two strings
sort(svec.begin(), svec.end(), greater<string>());
sorts the vector in descending order.
5. If want to use lambda in an ordered data structure:
auto cmp = [](const tuple<int, int, int>& a, const tuple<int, int, int>& b){
return get<0>(a)*get<1>(b)>get<1>(a)*get<0>(b);
};
priority_queue<tuple<int, int, int>, vector<tuple<int, int, int>>, decltype(cmp)> q;
Be aware of sort in pair/tuple is much faster than vector.
Iterator
for (auto first = values.begin(); first != values.end(); ++first) {
cout << *first << " ";
}
//use "rbegin()" and "rend()" to iterate in reverse order
mp.lower_bound(key0)->second //value of first element whose key is equal or bigger than key0
mp.upper_bound(key0)->second //value of first element whose key is bigger than key0
mp.equal_range(key0) //pair of iterator, in the pair the first is mp.lower_bound(key0), the second is mp.upper_bound(key0)
auto it=values.begin();
auto it2=values.end();
int len=distance(it, it2);
advance(it,-3); //move it back 3 position
auto it3=prev(it, 2); //it3 is the iterator before 3 position to it
auto it4=next(it, 2);
2.5.3 The decltype Type Specifier
decltype and References
// decltype of an expression can be a reference type
int i = 42, *p = &i, &r = i;
decltype(r + 0) b; // ok: addition yields an int; b is an (uninitialized) int
decltype(*p) c; // error: c is int& and must be initialized
// decltype of a parenthesized variable is always a reference
decltype((i)) d; // error: d is int& and must be initialized
decltype(i) e; // ok: e is an (uninitialized) int
3.5.1 Defining and Initializing Built-in Arrays
…the dimension must be known at compile time, which means that the dimension must be a constant expression.
unsigned cnt = 42; // not a constant expression
constexpr unsigned sz = 42; // constant expression
int *parr[sz]; // array of 42 pointers to int
string bad[cnt]; // error: cnt is not a constant expression
Understanding Complicated Array Declarations
int *(&arry)[10] = ptrs; // arry is a reference to an array of ten pointers
3.6 Multidimensional Arrays
Using a Range for with Multidimensional Arrays
size_t cnt = 0;
for (auto &row : ia) // for every element in the outer array
for (auto &col : row) { // for every element in the inner array
col = cnt; // give this element the next value
++cnt; // increment cnt
}
If row
is not a reference, when the compiler initializes row
it will convert each array element (like any other object of array type) to a pointer to that array’s first element. As a result, in this loop the type of row
is int*
. The inner for loop is illegal.
7.1.2 Defining the Revised Sales_data Class
Defining Member Functions
std::string isbn() const { return bookNo; }
We can think of the body of isbn as if it were written as
// pseudo-code illustration of how the implicit this pointer is used
// this code is illegal: we may not explicitly define the this pointer ourselves
// note that this is a pointer to const because isbn is a const member
std::string Sales_data::isbn(const Sales_data *const this)
{ return this->isbn; }
The fact that this is a pointer to const means that const member functions cannot change the object on which they are called.
Note: in const Sales_data *const this
, the first const means the object “Sales_data” is const, as is mentioned above; the second const means the pointer “this” is const.
13.6 Moving Objects
- We are free to “move” resources from an rvalue reference to another object. We can obtain an rvalue reference bound to an lvalue by calling a new library function named
move
. - By defining move operations, the Message class can use the string and set move operations to avoid the overhead of copying the contents and folders members.
// move the Folder pointers from m to this Message
void Message::move_Folders(Message *m)
{
folders = std::move(m->folders); // uses set move assignment
for (auto f : folders) { // for each Folder
f->remMsg(m); // remove the old Message from the Folder
f->addMsg(this); // add this Message to that Folder
}
m->folders.clear(); // ensure that destroying m is harmless
}
Note: why is it quicker to use moving than copying? In “folders = std::move(m->folders);”, the move assignment operator “=” has the similar action as making “folders” set point to “m->folders” set and then making “m->folders” set point to an empty set, instead of copy every element from one set to another.
Tips
- max value:
const int INF = 0x3f3f3f3f;
const int inf = 1000000007;
Be aware that sometimes we are supposed to use a larger value, like long long
(1e18
/1LL<<30
).
- search direction in grid:
static constexpr int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
- Input/Output
#include <iostream>
using namespace std;
int main() {
int a, b;
while (cin >> a >> b) {
cout << a + b << endl;
}
}
- vector debug
template <typename T>
void prtv(vector<T> &v) {
auto iter = v.begin();
if(iter==v.end()) return;
cout<<*iter;
while(++iter!=v.end()) cout<<", "<<*iter;
cout<<endl;
}
- TreeNode
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
High Frequency Templates
Quick Sort
void quickSort(vector<int> &nums, int l, int r){
if(l>=r) return; // don't forget bigger!
int tmp = l+rand()%(r-l+1);
swap(nums[l], nums[tmp]); //not nums[0]!
int pivot=nums[l]; //not nums[0]!
int i=l, j=r;
while(j>i){
while(j>i&&nums[j]>pivot) j--; // attention for boundary; not nums[j]>nums[i]!
nums[i]=nums[j];
while(j>i&&nums[i]<=pivot) i++;
nums[j]=nums[i];
}
nums[i]=pivot;
quickSort(nums, l, i-1);
quickSort(nums, i+1, r);
}
Merge Sort
void MergeSort(vector<int>&nums, int left, int right){
if(left>=right) return;
int mid = left + (right-left)/2;
MergeSort(nums, left, mid);
MergeSort(nums, mid+1, right);
Merge(nums, left, right);
}
void Merge(vector<int>&nums, int left, int right){
int mid = left + (right-left)/2;
vector<int> temp(right-left+1);
int i = left, j = mid+1, k = 0;
while(i<=mid&&j<=right){ // attention for boundary
if(nums[i]<=nums[j]) temp[k++] = nums[i++];
else temp[k++] = nums[j++];
}
while(i<=mid) temp[k++] = nums[i++]; // attention for boundary
while(j<=right) temp[k++] = nums[j++];
for(k=0;k<right-left+1;++k) nums[left+k]=temp[k];
}
Heap Sort
void maxHeapify(vector<int>& nums, int i, int len){
while(i*2+1<len){
int large = i;
if(i*2+1<len&&nums[i*2+1]>nums[large]) large = i*2+1;
if(i*2+2<len&&nums[i*2+2]>nums[large]) large = i*2+2; // attention for nums[large]
if(large!=i) swap(nums[i], nums[large]);
else break;
i = large;
}
}
void buildMaxHeap(vector<int>& nums) {
for(int i=nums.size()/2;i>=0;--i)
maxHeapify(nums, i, nums.size());
}
void HeapSort(vector<int> &nums) {
buildMaxHeap(nums);
for(int i=nums.size()-1;i>=1;--i){
swap(nums[0], nums[i]);
maxHeapify(nums, 0, i);
}
}
Fenwick Tree
template <class T> class FenwickTree {
int limit;
vector<T> arr;
int lowbit(int x) { return x & (-x); }
public:
FenwickTree(int limit) {
this->limit = limit;
arr = vector<T>(limit + 1);
}
void update(int idx, T delta) {
for (; idx <= limit; idx += lowbit(idx))
arr[idx] += delta;
}
T query(int idx) {
T ans = 0;
for (; idx > 0; idx -= lowbit(idx))
ans += arr[idx];
return ans;
}
};
Dijkstra
using ll = long long;
const ll INF = 1e12;
class Solution {
vector<ll> dijkstra(vector<vector<pair<int, int>>> &adj, int s) {
int n = adj.size();
priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<>> pq;
vector<ll> dis(n, INF);
dis[s] = 0;
pq.emplace(0, s);
while (!pq.empty()) {
auto [d, u] = pq.top();
pq.pop();
if (d > dis[u]) continue;
for (auto [v, w] : adj[u]) {
if (d + w < dis[v]) {
dis[v] = d + w;
pq.emplace(dis[v], v);
}
}
}
return dis;
}
Union-Find Set
class UnionFind {
private:
vector<int> parent;
vector<int> rank;
public:
UnionFind(int n) {
parent = vector<int>(n);
rank = vector<int>(n);
for (int i = 0; i < n; i++) parent[i] = i;
}
// merge by rank
void uni(int x, int y) {
int rootx = find(x), rooty = find(y);
if (rootx != rooty) {
if (rank[rootx] > rank[rooty]) {
parent[rooty] = rootx;
} else if (rank[rootx] < rank[rooty]) {
parent[rootx] = rooty;
} else {
parent[rooty] = rootx;
rank[rootx]++;
}
}
}
// path compression
int find(int x) {
return parent[x] == x ? x : parent[x] = find(parent[x]);
}
};
Eratosthenes Sieve
bool flag[mx + 1];
memset(flag, 0, sizeof(flag));
for (int i = 2; i <= mx; i++) if (!flag[i]) for (int j = i * 2; j <= mx; j += i) flag[j] = true;
vector<int> prime;
for (int i = 2; i <= mx; i++) if (!flag[i]) prime.push_back(i);
Fast Power with Modulo
auto power = [&](long long a, long long b) {
long long y = 1;
for (; b; b >>= 1) {
if (b & 1) y = y * a % MOD;
a = a * a % MOD;
}
return y;
};