initialize repository of algorithm-template
This commit is contained in:
16
ReadMe.md
Normal file
16
ReadMe.md
Normal file
@@ -0,0 +1,16 @@
|
||||
**C++ 常用算法模板**
|
||||
|
||||
| 类型 | 文件名 | 描述 |
|
||||
| ----------- | ----------- | ----------- |
|
||||
| 二分查找 | binary search | — |
|
||||
| 并查集 | union-find sets | 处理一些不相交集合的合并及查询问题 |
|
||||
| 拓扑排序 | topological sorting | — |
|
||||
| KMP算法 | knuth-morris-pratt | 快速的字符串匹配算法 |
|
||||
| Dijsktra | dijsktra | — |
|
||||
| 数学方法 | math | 含 quickpow, primality test, greatest common divisor 等方法|
|
||||
| 线段树 | segment tree | — |
|
||||
| 树状数组 | binary indexed tree | 用于高效计算数列的前缀和, 区间和 |
|
||||
| 最小生成树 | minimum spanning tree | krukal / prime |
|
||||
| 二叉搜索树/平衡树 | binary search tree & AVL tree | — |
|
||||
| 字典树 | trie tree| — |
|
||||
| K-D树 | k-d tree | — |
|
0
binary-index-tree/binary-index-tree.cpp
Normal file
0
binary-index-tree/binary-index-tree.cpp
Normal file
0
binary-search-tree/binary-search-tree.cpp
Normal file
0
binary-search-tree/binary-search-tree.cpp
Normal file
0
binary-search/binary-search.cpp
Normal file
0
binary-search/binary-search.cpp
Normal file
0
bipartite-graph/bipartite-graph.cpp
Normal file
0
bipartite-graph/bipartite-graph.cpp
Normal file
0
data-structure/lfu-cach.cpp
Normal file
0
data-structure/lfu-cach.cpp
Normal file
0
data-structure/lru-cache.cpp
Normal file
0
data-structure/lru-cache.cpp
Normal file
0
data-structure/mru-cache.cpp
Normal file
0
data-structure/mru-cache.cpp
Normal file
35
dijkstra/dijkstra.cpp
Normal file
35
dijkstra/dijkstra.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
class Solution {
|
||||
public:
|
||||
int diskstra(vector<vector<int>>& edges, int n, int start, int end) {
|
||||
vector<vector<int>> graph(n, vector<int>(n, INT_MAX / 2));
|
||||
for (auto& edge : edges) {
|
||||
int from = edge[0], to = edge[1], dist = edge[2];
|
||||
graph[from][to] = dist; // build the graph
|
||||
}
|
||||
|
||||
vector<int> distance(n, INT_MAX / 2), visited(n, 0);
|
||||
distance[start] = 0;
|
||||
while (true) {
|
||||
int next_node = -1;
|
||||
for (int node = 0; node < n; node++) {
|
||||
if (visited[node]) {
|
||||
continue; // update non-repeatedly
|
||||
}
|
||||
if (next_node < 0 || distance[next_node] > distance[node]) {
|
||||
next_node = node; // find the node with the smallest moving path
|
||||
}
|
||||
}
|
||||
|
||||
if (next_node < 0 || distance[next_node] == INT_MAX / 2) {
|
||||
break; // cannot find the node
|
||||
}
|
||||
|
||||
visited[next_node] = 1;
|
||||
for (int node = 0; node < n; node++) {
|
||||
// update the moving paths of the remaining nodes based on the nearest node
|
||||
distance[node] = min(distance[node], distance[next_node] + graph[next_node][node]);
|
||||
}
|
||||
}
|
||||
return distance[end] == INT_MAX / 2 ? -1 : distance[end];
|
||||
}
|
||||
};
|
0
k-d-Tree/k-d-tree.cpp
Normal file
0
k-d-Tree/k-d-tree.cpp
Normal file
114
mini-spanning-tree/minimum-spanning-tree.cpp
Normal file
114
mini-spanning-tree/minimum-spanning-tree.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
class MST
|
||||
{
|
||||
/**
|
||||
* Minumum Spanning Tree
|
||||
*
|
||||
*/
|
||||
|
||||
private:
|
||||
vector<int> _pre; // pre-node
|
||||
vector<int> _size; // size of node
|
||||
|
||||
/*!
|
||||
* @brief : finding function of union set
|
||||
* @param [x] : node index
|
||||
* @retval : parent node
|
||||
*/
|
||||
int find(int x)
|
||||
{
|
||||
if (_pre[x] == x)
|
||||
return x;
|
||||
_pre[x] = find(_pre[x]);
|
||||
return _pre[x];
|
||||
}
|
||||
public:
|
||||
/*
|
||||
* @brief : prim minimum spanning tree algorithm
|
||||
* @param [num_nodes] : number of nodes
|
||||
* @param [connections] : inter-node connection distance [start<72><74>end<6E><64>distance]
|
||||
* @retval : minimum weighted-sum
|
||||
*/
|
||||
int prim(int num_nodes, vector<vector<int>>& connections)
|
||||
{
|
||||
vector<vector<pair<int, int>>> edges(n);
|
||||
for (size_t i = 0; i < connections.size(); i++) {
|
||||
int city_a = connections[i][0], city_b = connections[i][1];
|
||||
int cost = connections[i][2];
|
||||
edges[city_a].push_back(make_pair(city_b, cost));
|
||||
edges[city_b].push_back(make_pair(city_a, cost));
|
||||
}
|
||||
set<int> intree; // set of visited node
|
||||
vector<pair<int, int>> out_edges; // external edge
|
||||
out_edges.push_back(make_pair(0, 0)); // target node
|
||||
|
||||
int ans = 0;
|
||||
|
||||
// iterate over all outward expanding edges until all nodes are visited
|
||||
while (out_edges.size() != 0 && intree.size() != num_nodes)
|
||||
{
|
||||
// find the edge with minimal weight
|
||||
vector<pair<int, int>>::iterator iter = min_element(out_edges.begin(), out_edges.end(), [&](pair<int, int>& elem1, pair<int, int>elem2)
|
||||
{
|
||||
return elem1.second < elem2.second;
|
||||
|
||||
});
|
||||
pair<int, int> out_edge = *iter;
|
||||
out_edges.erase(iter);
|
||||
|
||||
// add unvisited node
|
||||
if (intree.find(out_edge.first) == intree.end())
|
||||
{
|
||||
intree.insert(out_edge.first);
|
||||
ans += out_edge.second;
|
||||
for (pair<int, int> edge : edges[out_edge.first])
|
||||
{
|
||||
out_edges.push_back(make_pair(edge.first, edge.second));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (intree.size() != num_nodes)
|
||||
return -1; // not exist if two nodes is not connected
|
||||
return ans;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @brief : Kruskal MST algorithm
|
||||
* @param [num_nodes] : Number of nodes
|
||||
* @param [connections] : Inter-node connection distance [start<72><74>end<6E><64>distance]
|
||||
* @retval : Minimum weighted-sum
|
||||
*/
|
||||
int kruskal(int numNodes, vector<vector<int>>& connections)
|
||||
_pre.resize(numNodes), _size.resize(numNodes, 1);
|
||||
iota(_pre.begin(), _pre.end(), 0);
|
||||
|
||||
// sort with the distance
|
||||
sort(connections.begin(), connections.end(), [&](vector<int>& elem1, vector<int>& elem2) {
|
||||
return elem1.at(2) < elem2.at(2);
|
||||
});
|
||||
|
||||
int ans = 0; // minimum weighted-sum
|
||||
int edge_count = 0; // number of visited nodes
|
||||
for (size_t i = 0; i < connections.size(); i++) {
|
||||
int x = find(connections[i][0]), y = find(connections[i][1]);
|
||||
|
||||
// Union find set
|
||||
if (x != y) {
|
||||
if (_size[x] > _size[y]) {
|
||||
swap(x, y);
|
||||
}
|
||||
|
||||
_pre[x] = y;
|
||||
_size[y] += _size[x];
|
||||
ans += connections[i][2];
|
||||
edge_count++;
|
||||
if (edge_count == numNodes - 1) {
|
||||
return ans;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1; // not exist if two nodes is not connected
|
||||
}
|
||||
};
|
41
segment-tree/segment-tree.cpp
Normal file
41
segment-tree/segment-tree.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#include <vector>
|
||||
|
||||
class SegmentTree {
|
||||
private:
|
||||
vector<int> segVal;
|
||||
void maintain(int node) {
|
||||
segVal[node] = max(segVal[node * 2], segVal[node * 2 + 1]);
|
||||
}
|
||||
void build(const vector<int>& vec, int node, int left, int right) {
|
||||
if (left == right) {
|
||||
segVal[node] = vec[left];
|
||||
return;
|
||||
}
|
||||
int mid = (left + right) / 2;
|
||||
build(vec, node * 2, left, mid);
|
||||
build(vec, node * 2 + 1, mid + 1, right);
|
||||
maintain(node);
|
||||
}
|
||||
public:
|
||||
SegmentTree(const vector<int>& vec) {
|
||||
size_t n = vec.size();
|
||||
segVal.resize(2 << std::bit_width(n - 1));
|
||||
build(vec, 1, 0, n - 1);
|
||||
}
|
||||
int findFirstAndUpdate(int node, int left, int right, int val) {
|
||||
if (segVal[node] < val) {
|
||||
return -1; // not found;
|
||||
}
|
||||
if (left == right) {
|
||||
segVal[node] = -1; // update state
|
||||
return left;
|
||||
}
|
||||
int mid = (left + right) / 2;
|
||||
int idx = findFirstAndUpdate(node * 2, left, mid, val);
|
||||
if (idx < 0) {
|
||||
idx = findFirstAndUpdate(node * 2 + 1, mid + 1, right, val);
|
||||
}
|
||||
maintain(node);
|
||||
return idx;
|
||||
}
|
||||
};
|
72
topological-sorting/topological-sorting.cpp
Normal file
72
topological-sorting/topological-sorting.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
class TopologicalSort
|
||||
{
|
||||
private:
|
||||
enum class STATUS
|
||||
{
|
||||
UN_VISITED,
|
||||
IN_SEARCHING,
|
||||
FINISHED
|
||||
};
|
||||
|
||||
vector<vector<int>> edges;
|
||||
vector<STATUS> visited;
|
||||
vector<int> sequence;
|
||||
|
||||
bool find_cycle = false; // cycle
|
||||
|
||||
/**
|
||||
* @brief deep first search
|
||||
* @param[in] node index
|
||||
*
|
||||
*/
|
||||
void deepFirstSearch(int node)
|
||||
{
|
||||
visited[node] = STATUS::IN_SEARCHING;
|
||||
for (int neighbor : edges[node]) {
|
||||
if (visited[neighbor] == STATUS::UN_VISITED) {
|
||||
deepFirstSearch(neighbor);
|
||||
if (find_cycle) {
|
||||
return; // unsolvable
|
||||
}
|
||||
}
|
||||
else if (visited[neighbor] == STATUS::IN_SEARCHING) {
|
||||
find_cycle = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
visited[node] = STATUS::FINISHED;
|
||||
sequence.push_back(node);
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief topological sequence
|
||||
* @param[in] number of nodes
|
||||
* @param[in] node connection
|
||||
* @retval sequence
|
||||
*/
|
||||
vector<int> findTopologicalOrder(int numNodes, vector<vector<int>>& linkage)
|
||||
{
|
||||
edges.resize(numNodes);
|
||||
visited.resize(numNodes, STATUS::UN_VISITED);
|
||||
|
||||
// generate adjacency list
|
||||
for (const auto& info : linkage) {
|
||||
edges[info[1]].push_back(info[0]);
|
||||
}
|
||||
|
||||
// deep first search to determine the topological sequence
|
||||
for (int i = 0; i < numNodes && !find_cycle; ++i) {
|
||||
if (visited[i] == STATUS::UN_VISITED) {
|
||||
deepFirstSearch(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (find_cycle) {
|
||||
return vector<int>(); // unsolvable for cycle
|
||||
}
|
||||
|
||||
reverse(sequence.begin(), sequence.end());
|
||||
return sequence;
|
||||
}
|
||||
};
|
0
trick/greatest-common-divisor.cpp
Normal file
0
trick/greatest-common-divisor.cpp
Normal file
0
trick/knuth-morris-pratt.cpp
Normal file
0
trick/knuth-morris-pratt.cpp
Normal file
0
trick/primality-test.cpp
Normal file
0
trick/primality-test.cpp
Normal file
0
trick/quick-pow.cpp
Normal file
0
trick/quick-pow.cpp
Normal file
49
trie-tree/trie-tree.cpp
Normal file
49
trie-tree/trie-tree.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
class Trie
|
||||
{
|
||||
private:
|
||||
vector<Trie*> m_children;
|
||||
bool is_end;
|
||||
|
||||
Trie* searchPrefix(string prefix)
|
||||
{
|
||||
Trie* node = this;
|
||||
for (char ch : prefix) {
|
||||
if (node->m_children[ch - 'a'] == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
node = node->m_children[ch - 'a'];
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
public:
|
||||
Trie() :
|
||||
m_children(26),
|
||||
is_end(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void insert(string word)
|
||||
{
|
||||
Trie* node = this;
|
||||
for (char ch : word) {
|
||||
if (node->m_children[ch - 'a'] == nullptr) {
|
||||
node->m_children[ch - 'a'] = new Trie;
|
||||
}
|
||||
node = node->m_children[ch - 'a'];
|
||||
}
|
||||
node->is_end = true;
|
||||
}
|
||||
|
||||
bool search(string word)
|
||||
{
|
||||
Trie* node = searchPrefix(word);
|
||||
return node != nullptr && node->is_end;
|
||||
}
|
||||
|
||||
bool startsWith(string prefix)
|
||||
{
|
||||
return searchPrefix(prefix) != nullptr;
|
||||
}
|
||||
};
|
36
union-find-set/union-find-set.cpp
Normal file
36
union-find-set/union-find-set.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
class UnionFind {
|
||||
vector<int> _pre; // 代表元
|
||||
vector<int> _rank; // 集合的秩
|
||||
|
||||
public:
|
||||
UnionFind(int n) : _pre(n), _rank(n, 1) {
|
||||
iota(_pre.begin(), _pre.end(), 0);
|
||||
//ranges::iota(_pre, 0);
|
||||
}
|
||||
|
||||
int find(int x) {
|
||||
return _pre[x] == x ? x : _pre[x] = find(_pre[x]);
|
||||
}
|
||||
|
||||
bool same(int x, int y) {
|
||||
return find(x) == find(y);
|
||||
}
|
||||
|
||||
bool merge(int from, int to) {
|
||||
int x = find(from), y = find(to);
|
||||
if (x == y) {
|
||||
return false;
|
||||
}
|
||||
if (_rank[x] < _rank[y]) {
|
||||
_pre[x] = y;
|
||||
}
|
||||
else if (_rank[x] > _rank[y]) {
|
||||
_pre[y] = x;
|
||||
}
|
||||
else {
|
||||
_pre[x] = y;
|
||||
_rank[y]++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
Reference in New Issue
Block a user