Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .vscode/c_cpp_properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
{
"name": "Mac",
"includePath": [
"${workspaceFolder}/**", // Overall project path
"/opt/homebrew/include" // M1~ Standard path for Mac
"${workspaceFolder}/**",
"/opt/homebrew/include"
],
"defines": [],
"macFrameworkPath": [
Expand All @@ -17,4 +17,4 @@
}
],
"version": 4
}
}
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"C_Cpp.default.compilerPath": "/usr/bin/clang",
"C_Cpp.default.cppStandard": "c++20",
"C_Cpp.default.includePath": [
"${workspaceFolder}/src"
],
"C_Cpp.default.intelliSenseMode": "clang-x64"
}
124 changes: 124 additions & 0 deletions src/graph/kruskal.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#ifndef KRUSKAL_HPP
#define KRUSKAL_HPP

#include <algorithm>
#include <concepts>
#include <iostream>
#include <vector>

/**
* @brief Edge structure for Kruskal's algorithm
*/
struct KruskalEdge {
int from;
int to;
long long weight;

// Operator for sorting edges by weight
bool operator<(const KruskalEdge& other) const {
return weight < other.weight;
}
};

/**
* @brief Disjoint Set Union (DSU) data structure for Kruskal's algorithm
*/
class DisjointSet {
private:
std::vector<int> parent;
std::vector<int> rank;

public:
/**
* @brief Initialize a DSU with n elements
* @param n Number of elements
*/
DisjointSet(int n) : parent(n), rank(n, 0) {
for (int i = 0; i < n; i++) {
parent[i] = i; // Each element is its own parent initially
}
}

/**
* @brief Find the representative of the set containing x
* @param x Element to find
* @return Representative of the set
*/
int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]); // Path compression
}
return parent[x];
}

/**
* @brief Union of two sets
* @param x First element
* @param y Second element
* @return True if x and y were in different sets, false otherwise
*/
bool unite(int x, int y) {
int rootX = find(x);
int rootY = find(y);

if (rootX == rootY) {
return false; // Already in the same set
}

// Union by rank
if (rank[rootX] < rank[rootY]) {
parent[rootX] = rootY;
} else if (rank[rootX] > rank[rootY]) {
parent[rootY] = rootX;
} else {
parent[rootY] = rootX;
rank[rootX]++;
}

return true;
}
};

/**
* @brief Kruskal's algorithm for finding the Minimum Spanning Tree (MST) of a graph
*
* @param n Number of vertices in the graph
* @param edges Vector of edges in the graph
* @return Vector of edges that form the MST and the total weight of the MST
*/
std::pair<std::vector<KruskalEdge>, long long> kruskal(int n, std::vector<KruskalEdge>& edges) {
// Sort edges by weight
std::sort(edges.begin(), edges.end());

DisjointSet dsu(n);
std::vector<KruskalEdge> mst;
long long totalWeight = 0;

for (const auto& edge : edges) {
if (dsu.unite(edge.from, edge.to)) {
// This edge is part of the MST
mst.push_back(edge);
totalWeight += edge.weight;

// If we have n-1 edges, we have a complete MST
if (mst.size() == n - 1) {
break;
}
}
}

return {mst, totalWeight};
}

/**
* @brief Check if the graph is connected
*
* @param n Number of vertices
* @param mst The MST edges
* @return True if the graph is connected, false otherwise
*/
bool isConnected(int n, const std::vector<KruskalEdge>& mst) {
return mst.size() == n - 1;
}

#endif // KRUSKAL_HPP
122 changes: 122 additions & 0 deletions src/search/binary_search.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#ifndef BINARY_SEARCH_HPP
#define BINARY_SEARCH_HPP

#include <concepts>
#include <functional>
#include <vector>

namespace clavis {
namespace search {

/**
* @brief Binary search algorithm for finding an element in a sorted array
*
* @tparam T Type of elements in the array (must be comparable)
* @param arr Sorted array to search in
* @param target Element to search for
* @return Index of the target element if found, -1 otherwise
*/
template <typename T>
requires std::totally_ordered<T>
int binary_search(const std::vector<T>& arr, const T& target) {
int left = 0;
int right = arr.size() - 1;

while (left <= right) {
int mid = left + (right - left) / 2; // Avoid potential overflow

if (arr[mid] == target) {
return mid; // Found the target
} else if (arr[mid] < target) {
left = mid + 1; // Search in the right half
} else {
right = mid - 1; // Search in the left half
}
}

return -1; // Target not found
}

/**
* @brief Lower bound binary search - finds the first element not less than the target
*
* @tparam T Type of elements in the array (must be comparable)
* @param arr Sorted array to search in
* @param target Element to search for
* @return Index of the first element not less than target, or arr.size() if all elements are less than target
*/
template <typename T>
requires std::totally_ordered<T>
int lower_bound(const std::vector<T>& arr, const T& target) {
int left = 0;
int right = arr.size(); // Note: right is arr.size(), not arr.size() - 1

while (left < right) {
int mid = left + (right - left) / 2;

if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid;
}
}

return left; // Returns arr.size() if all elements are less than target
}

/**
* @brief Upper bound binary search - finds the first element greater than the target
*
* @tparam T Type of elements in the array (must be comparable)
* @param arr Sorted array to search in
* @param target Element to search for
* @return Index of the first element greater than target, or arr.size() if no such element exists
*/
template <typename T>
requires std::totally_ordered<T>
int upper_bound(const std::vector<T>& arr, const T& target) {
int left = 0;
int right = arr.size(); // Note: right is arr.size(), not arr.size() - 1

while (left < right) {
int mid = left + (right - left) / 2;

if (arr[mid] <= target) {
left = mid + 1;
} else {
right = mid;
}
}

return left; // Returns arr.size() if all elements are less than or equal to target
}

/**
* @brief Binary search on a predicate function
*
* @tparam T Type of elements in the search space
* @param left Left boundary of the search space (inclusive)
* @param right Right boundary of the search space (exclusive)
* @param predicate Function that returns true for elements that satisfy the condition
* @return The first element in the range [left, right) for which predicate returns true, or right if none exists
*/
template <typename T>
requires std::integral<T>
T binary_search_predicate(T left, T right, const std::function<bool(T)>& predicate) {
while (left < right) {
T mid = left + (right - left) / 2;

if (predicate(mid)) {
right = mid;
} else {
left = mid + 1;
}
}

return left; // Returns right if no element satisfies the predicate
}

} // namespace search
} // namespace clavis

#endif // BINARY_SEARCH_HPP
Loading