Agent Skills: Algorithms Skill

>

algorithmsdata-structurescomplexity-analysisoptimizationcomputational-theory
coreID: pluginagentmarketplace/custom-plugin-cpp/algorithms

Skill Files

Browse the full folder contents for algorithms.

Download Skill

Loading file tree…

skills/algorithms/SKILL.md

Skill Metadata

Name
algorithms
Description
"Level of explanation detail"

Algorithms Skill

Production-Grade Learning Skill | Algorithms & Data Structures

Master algorithm design and implementation in C++ with complexity analysis.


Complexity Analysis

Big O Notation Reference

| Complexity | Name | Example | Operations (n=1000) | |------------|------|---------|---------------------| | O(1) | Constant | Array access | 1 | | O(log n) | Logarithmic | Binary search | 10 | | O(n) | Linear | Linear search | 1,000 | | O(n log n) | Linearithmic | Merge sort | 10,000 | | O(n²) | Quadratic | Bubble sort | 1,000,000 | | O(2^n) | Exponential | Recursive fib | 10^301 |

Complexity Analysis Framework

// Time Complexity Analysis Template
// 1. Count primitive operations
// 2. Express as function of input size n
// 3. Keep highest order term
// 4. Drop constants

// Example: Find maximum
int findMax(const std::vector<int>& v) {  // O(n)
    int max = v[0];                        // O(1)
    for (int i = 1; i < v.size(); ++i) {   // O(n) iterations
        if (v[i] > max) {                  // O(1)
            max = v[i];                    // O(1)
        }
    }
    return max;                            // O(1)
}  // Total: O(1) + O(n) * O(1) = O(n)

Sorting Algorithms

STL Sorting

#include <algorithm>
#include <vector>

std::vector<int> v = {5, 2, 8, 1, 9};

// Introsort - O(n log n) guaranteed
std::sort(v.begin(), v.end());

// Stable sort - preserves relative order of equal elements
std::stable_sort(v.begin(), v.end());

// Partial sort - only first k elements sorted
std::partial_sort(v.begin(), v.begin() + 3, v.end());

// Nth element - partition around nth element (O(n) average)
std::nth_element(v.begin(), v.begin() + v.size()/2, v.end());

// Custom comparator (descending order)
std::sort(v.begin(), v.end(), std::greater<int>());

// Sort by projection (C++20)
std::ranges::sort(v, {}, [](int x) { return std::abs(x); });

Sorting Algorithm Comparison

| Algorithm | Best | Average | Worst | Space | Stable | |-----------|------|---------|-------|-------|--------| | Quick Sort | O(n log n) | O(n log n) | O(n²) | O(log n) | No | | Merge Sort | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes | | Heap Sort | O(n log n) | O(n log n) | O(n log n) | O(1) | No | | Insertion Sort | O(n) | O(n²) | O(n²) | O(1) | Yes | | Tim Sort | O(n) | O(n log n) | O(n log n) | O(n) | Yes |


Searching Algorithms

Binary Search

#include <algorithm>

// STL binary search - O(log n), requires sorted range
std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9};

// Check existence
bool found = std::binary_search(v.begin(), v.end(), 5);

// Find position
auto it = std::lower_bound(v.begin(), v.end(), 5);  // First >= 5
auto it2 = std::upper_bound(v.begin(), v.end(), 5); // First > 5

// Range of equal elements
auto [lo, hi] = std::equal_range(v.begin(), v.end(), 5);

// Custom binary search with predicate
template<typename T, typename Pred>
T binary_search_first_true(T lo, T hi, Pred pred) {
    while (lo < hi) {
        T mid = lo + (hi - lo) / 2;
        if (pred(mid)) {
            hi = mid;
        } else {
            lo = mid + 1;
        }
    }
    return lo;
}

Graph Algorithms

Graph Representations

// Adjacency List (preferred for sparse graphs)
std::vector<std::vector<int>> adj(n);
adj[0].push_back(1);  // Edge 0 -> 1

// Adjacency List with weights
std::vector<std::vector<std::pair<int, int>>> adj(n);
adj[0].push_back({1, weight});  // Edge 0 -> 1 with weight

// Adjacency Matrix (for dense graphs)
std::vector<std::vector<int>> adj(n, std::vector<int>(n, 0));
adj[0][1] = 1;  // Edge 0 -> 1

BFS - Breadth First Search

std::vector<int> bfs(int start, const std::vector<std::vector<int>>& adj) {
    std::vector<int> dist(adj.size(), -1);
    std::queue<int> q;

    dist[start] = 0;
    q.push(start);

    while (!q.empty()) {
        int node = q.front();
        q.pop();

        for (int neighbor : adj[node]) {
            if (dist[neighbor] == -1) {
                dist[neighbor] = dist[node] + 1;
                q.push(neighbor);
            }
        }
    }
    return dist;  // Shortest distances from start
}

DFS - Depth First Search

void dfs(int node, const std::vector<std::vector<int>>& adj,
         std::vector<bool>& visited, std::vector<int>& result) {
    visited[node] = true;
    result.push_back(node);

    for (int neighbor : adj[node]) {
        if (!visited[neighbor]) {
            dfs(neighbor, adj, visited, result);
        }
    }
}

Dijkstra's Algorithm

std::vector<int> dijkstra(int start,
    const std::vector<std::vector<std::pair<int,int>>>& adj) {

    std::vector<int> dist(adj.size(), INT_MAX);
    std::priority_queue<std::pair<int,int>,
        std::vector<std::pair<int,int>>,
        std::greater<>> pq;

    dist[start] = 0;
    pq.push({0, start});

    while (!pq.empty()) {
        auto [d, u] = pq.top();
        pq.pop();

        if (d > dist[u]) continue;  // Skip outdated entries

        for (auto [v, w] : adj[u]) {
            if (dist[u] + w < dist[v]) {
                dist[v] = dist[u] + w;
                pq.push({dist[v], v});
            }
        }
    }
    return dist;
}

Dynamic Programming

DP Framework

// 1. Define state: What subproblem does dp[i] represent?
// 2. Define transition: How to compute dp[i] from previous states?
// 3. Define base case: What are the initial values?
// 4. Define answer: Which state(s) give the final answer?

// Example: Longest Increasing Subsequence
int lis(const std::vector<int>& nums) {
    int n = nums.size();
    std::vector<int> dp(n, 1);  // dp[i] = LIS ending at i

    for (int i = 1; i < n; ++i) {
        for (int j = 0; j < i; ++j) {
            if (nums[j] < nums[i]) {
                dp[i] = std::max(dp[i], dp[j] + 1);
            }
        }
    }
    return *std::max_element(dp.begin(), dp.end());
}

// Optimized LIS with binary search - O(n log n)
int lisOptimized(const std::vector<int>& nums) {
    std::vector<int> tails;
    for (int x : nums) {
        auto it = std::lower_bound(tails.begin(), tails.end(), x);
        if (it == tails.end()) {
            tails.push_back(x);
        } else {
            *it = x;
        }
    }
    return tails.size();
}

Common DP Patterns

| Pattern | Example | State | Complexity | |---------|---------|-------|------------| | Linear | Fibonacci | dp[i] | O(n) | | 2D Grid | Path count | dp[i][j] | O(n×m) | | Interval | Matrix chain | dp[i][j] | O(n³) | | Subset | Knapsack | dp[mask] | O(2^n) | | Tree | Tree DP | dp[node] | O(n) |


Algorithm Selection Flowchart

What type of problem?
├── Searching
│   ├── Sorted data? → Binary Search O(log n)
│   └── Unsorted? → Linear Search O(n) or Hash O(1)
├── Sorting
│   ├── Need stable? → std::stable_sort
│   ├── Partial sort? → std::partial_sort
│   └── General? → std::sort
├── Optimization
│   ├── Overlapping subproblems? → Dynamic Programming
│   └── Greedy choice property? → Greedy Algorithm
├── Graph
│   ├── Shortest path (unweighted)? → BFS
│   ├── Shortest path (weighted)? → Dijkstra/Bellman-Ford
│   ├── All pairs shortest? → Floyd-Warshall
│   └── Minimum spanning tree? → Kruskal/Prim
└── String
    ├── Pattern matching? → KMP/Rabin-Karp
    └── Longest common? → DP

Troubleshooting Decision Tree

Algorithm not working correctly?
├── Wrong output
│   ├── Check base cases
│   ├── Verify loop bounds
│   ├── Test edge cases (empty, single element)
│   └── Print intermediate values
├── Time Limit Exceeded (TLE)
│   ├── Check complexity matches constraint
│   ├── Look for unnecessary recomputation
│   ├── Consider memoization/DP
│   └── Use better data structure
├── Memory Limit Exceeded (MLE)
│   ├── Reduce DP state dimensions
│   ├── Use rolling array technique
│   └── Clear visited sets between runs
└── Runtime Error
    ├── Check array bounds
    ├── Check integer overflow
    └── Check stack overflow (recursion depth)

Unit Test Template

#include <gtest/gtest.h>
#include "algorithms.hpp"

class AlgorithmTest : public ::testing::Test {
protected:
    void SetUp() override {
        sorted_vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        unsorted_vec = {5, 2, 8, 1, 9, 3, 7, 4, 6, 10};
    }

    std::vector<int> sorted_vec;
    std::vector<int> unsorted_vec;
};

TEST_F(AlgorithmTest, BinarySearchFindsElement) {
    EXPECT_TRUE(std::binary_search(sorted_vec.begin(), sorted_vec.end(), 5));
    EXPECT_FALSE(std::binary_search(sorted_vec.begin(), sorted_vec.end(), 11));
}

TEST_F(AlgorithmTest, SortProducesOrderedOutput) {
    std::sort(unsorted_vec.begin(), unsorted_vec.end());
    EXPECT_TRUE(std::is_sorted(unsorted_vec.begin(), unsorted_vec.end()));
}

TEST_F(AlgorithmTest, BFSFindsShortestPath) {
    std::vector<std::vector<int>> adj = {{1, 2}, {0, 3}, {0, 3}, {1, 2}};
    auto dist = bfs(0, adj);
    EXPECT_EQ(dist[0], 0);
    EXPECT_EQ(dist[1], 1);
    EXPECT_EQ(dist[3], 2);
}

TEST_F(AlgorithmTest, LISHandlesEdgeCases) {
    EXPECT_EQ(lis({}), 0);
    EXPECT_EQ(lis({1}), 1);
    EXPECT_EQ(lis({3, 2, 1}), 1);  // Decreasing
    EXPECT_EQ(lis({1, 2, 3}), 3);  // Increasing
}

Integration Points

| Component | Interface | |-----------|-----------| | stl-master | Container selection | | performance-optimizer | Algorithm optimization | | modern-cpp-expert | Ranges and concepts | | cpp-fundamentals-agent | Basic concepts |


C++ Plugin v3.0.0 - Production-Grade Learning Skill