C++ Algorithm Notes

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
    • Quick Sort
    • Merge Sort
    • Heap Sort
    • Fenwick Tree
    • Dijkstra
    • Union-Find Set
    • Eratosthenes Sieve
    • Fast Power with Modulo

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();
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

  1. 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 ab 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;
}
  1. 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;
}
  1. The standard library defines a set of classes that represent the arithmetic, relational, and logical operators.
    C++ Algorithm Notes_第1张图片

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.

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

  1. 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.
  2. 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

  1. 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).

  1. search direction in grid:
static constexpr int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
  1. Input/Output
#include 
using namespace std;

int main() {
    int a, b;
    while (cin >> a >> b) {
        cout << a + b << endl;
    }
}
  1. 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;
}
  1. 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;
};

你可能感兴趣的:(C++,OJ,c++,开发语言,算法,数据结构,线性回归,链表,动态规划)