From a876627598a98ca1693dec422eeabc38122ea11b Mon Sep 17 00:00:00 2001 From: hit-lu Date: Fri, 8 Aug 2025 23:09:34 +0800 Subject: [PATCH] initialize repository of algorithm-template --- ReadMe.md | 16 +++ binary-index-tree/binary-index-tree.cpp | 0 binary-search-tree/binary-search-tree.cpp | 0 binary-search/binary-search.cpp | 0 bipartite-graph/bipartite-graph.cpp | 0 data-structure/lfu-cach.cpp | 0 data-structure/lru-cache.cpp | 0 data-structure/mru-cache.cpp | 0 dijkstra/dijkstra.cpp | 35 ++++++ k-d-Tree/k-d-tree.cpp | 0 mini-spanning-tree/minimum-spanning-tree.cpp | 114 +++++++++++++++++++ segment-tree/segment-tree.cpp | 41 +++++++ topological-sorting/topological-sorting.cpp | 72 ++++++++++++ trick/greatest-common-divisor.cpp | 0 trick/knuth-morris-pratt.cpp | 0 trick/primality-test.cpp | 0 trick/quick-pow.cpp | 0 trie-tree/trie-tree.cpp | 49 ++++++++ union-find-set/union-find-set.cpp | 36 ++++++ 19 files changed, 363 insertions(+) create mode 100644 ReadMe.md create mode 100644 binary-index-tree/binary-index-tree.cpp create mode 100644 binary-search-tree/binary-search-tree.cpp create mode 100644 binary-search/binary-search.cpp create mode 100644 bipartite-graph/bipartite-graph.cpp create mode 100644 data-structure/lfu-cach.cpp create mode 100644 data-structure/lru-cache.cpp create mode 100644 data-structure/mru-cache.cpp create mode 100644 dijkstra/dijkstra.cpp create mode 100644 k-d-Tree/k-d-tree.cpp create mode 100644 mini-spanning-tree/minimum-spanning-tree.cpp create mode 100644 segment-tree/segment-tree.cpp create mode 100644 topological-sorting/topological-sorting.cpp create mode 100644 trick/greatest-common-divisor.cpp create mode 100644 trick/knuth-morris-pratt.cpp create mode 100644 trick/primality-test.cpp create mode 100644 trick/quick-pow.cpp create mode 100644 trie-tree/trie-tree.cpp create mode 100644 union-find-set/union-find-set.cpp diff --git a/ReadMe.md b/ReadMe.md new file mode 100644 index 0000000..e06ab55 --- /dev/null +++ b/ReadMe.md @@ -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 | — | \ No newline at end of file diff --git a/binary-index-tree/binary-index-tree.cpp b/binary-index-tree/binary-index-tree.cpp new file mode 100644 index 0000000..e69de29 diff --git a/binary-search-tree/binary-search-tree.cpp b/binary-search-tree/binary-search-tree.cpp new file mode 100644 index 0000000..e69de29 diff --git a/binary-search/binary-search.cpp b/binary-search/binary-search.cpp new file mode 100644 index 0000000..e69de29 diff --git a/bipartite-graph/bipartite-graph.cpp b/bipartite-graph/bipartite-graph.cpp new file mode 100644 index 0000000..e69de29 diff --git a/data-structure/lfu-cach.cpp b/data-structure/lfu-cach.cpp new file mode 100644 index 0000000..e69de29 diff --git a/data-structure/lru-cache.cpp b/data-structure/lru-cache.cpp new file mode 100644 index 0000000..e69de29 diff --git a/data-structure/mru-cache.cpp b/data-structure/mru-cache.cpp new file mode 100644 index 0000000..e69de29 diff --git a/dijkstra/dijkstra.cpp b/dijkstra/dijkstra.cpp new file mode 100644 index 0000000..32e5a1b --- /dev/null +++ b/dijkstra/dijkstra.cpp @@ -0,0 +1,35 @@ +class Solution { +public: + int diskstra(vector>& edges, int n, int start, int end) { + vector> graph(n, vector(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 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]; + } +}; \ No newline at end of file diff --git a/k-d-Tree/k-d-tree.cpp b/k-d-Tree/k-d-tree.cpp new file mode 100644 index 0000000..e69de29 diff --git a/mini-spanning-tree/minimum-spanning-tree.cpp b/mini-spanning-tree/minimum-spanning-tree.cpp new file mode 100644 index 0000000..e2ab05d --- /dev/null +++ b/mini-spanning-tree/minimum-spanning-tree.cpp @@ -0,0 +1,114 @@ +class MST +{ + /** + * Minumum Spanning Tree + * + */ + +private: + vector _pre; // pre-node + vector _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 [startenddistance] + * @retval : minimum weighted-sum + */ + int prim(int num_nodes, vector>& connections) + { + vector>> 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 intree; // set of visited node + vector> 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>::iterator iter = min_element(out_edges.begin(), out_edges.end(), [&](pair& elem1, pairelem2) + { + return elem1.second < elem2.second; + + }); + pair 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 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 [startenddistance] + * @retval : Minimum weighted-sum + */ + int kruskal(int numNodes, vector>& connections) + _pre.resize(numNodes), _size.resize(numNodes, 1); + iota(_pre.begin(), _pre.end(), 0); + + // sort with the distance + sort(connections.begin(), connections.end(), [&](vector& elem1, vector& 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 + } +}; \ No newline at end of file diff --git a/segment-tree/segment-tree.cpp b/segment-tree/segment-tree.cpp new file mode 100644 index 0000000..12fc0ac --- /dev/null +++ b/segment-tree/segment-tree.cpp @@ -0,0 +1,41 @@ +#include + +class SegmentTree { +private: + vector segVal; + void maintain(int node) { + segVal[node] = max(segVal[node * 2], segVal[node * 2 + 1]); + } + void build(const vector& 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& 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; + } +}; \ No newline at end of file diff --git a/topological-sorting/topological-sorting.cpp b/topological-sorting/topological-sorting.cpp new file mode 100644 index 0000000..ec10812 --- /dev/null +++ b/topological-sorting/topological-sorting.cpp @@ -0,0 +1,72 @@ +class TopologicalSort +{ +private: + enum class STATUS + { + UN_VISITED, + IN_SEARCHING, + FINISHED + }; + + vector> edges; + vector visited; + vector 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 findTopologicalOrder(int numNodes, vector>& 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(); // unsolvable for cycle + } + + reverse(sequence.begin(), sequence.end()); + return sequence; + } +}; \ No newline at end of file diff --git a/trick/greatest-common-divisor.cpp b/trick/greatest-common-divisor.cpp new file mode 100644 index 0000000..e69de29 diff --git a/trick/knuth-morris-pratt.cpp b/trick/knuth-morris-pratt.cpp new file mode 100644 index 0000000..e69de29 diff --git a/trick/primality-test.cpp b/trick/primality-test.cpp new file mode 100644 index 0000000..e69de29 diff --git a/trick/quick-pow.cpp b/trick/quick-pow.cpp new file mode 100644 index 0000000..e69de29 diff --git a/trie-tree/trie-tree.cpp b/trie-tree/trie-tree.cpp new file mode 100644 index 0000000..f8b8b8a --- /dev/null +++ b/trie-tree/trie-tree.cpp @@ -0,0 +1,49 @@ +class Trie +{ +private: + vector 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; + } +}; \ No newline at end of file diff --git a/union-find-set/union-find-set.cpp b/union-find-set/union-find-set.cpp new file mode 100644 index 0000000..34d48a6 --- /dev/null +++ b/union-find-set/union-find-set.cpp @@ -0,0 +1,36 @@ +class UnionFind { + vector _pre; // 代表元 + vector _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; + } +}; \ No newline at end of file