wk09_algorithms_datastructures_2


Algorithms and Datastructures, part 2

C++ program that demonstrates the use of Heaps, Priority Queues, and Recursion in a scientific computing context. We'll implement a simulation system that manages computational tasks with different priorities and uses recursion for a divide-and-conquer algorithm.

Resources (C++ Tutorial)

algorithm, auto, command_line_arguments, exception, iostream, namespace, range-based, sstream, std::cin, std::cout, std::cerr, std::exception, std::ifstream, std::ofstream, stdexcept, throw, vector

Implementation:

#include <iostream>
#include <vector>
#include <queue>
#include <functional>
#include <string>
#include <cmath>

// Structure to represent a computational task
struct ComputationalTask {
    std::string name;
    int priority;
    double complexity;

    ComputationalTask(std::string n, int p, double c) : name(n), priority(p), complexity(c) {}

    // Overload the comparison operator for priority queue
    bool operator<(const ComputationalTask& other) const {
        return priority < other.priority;
    }
};

// Priority Queue for managing computational tasks
class TaskScheduler {
private:
    std::priority_queue<ComputationalTask> tasks;

public:
    void addTask(const ComputationalTask& task) {
        tasks.push(task);
    }

    ComputationalTask getNextTask() {
        if (tasks.empty()) {
            throw std::runtime_error("No tasks available");
        }
        ComputationalTask nextTask = tasks.top();
        tasks.pop();
        return nextTask;
    }

    bool hasTasks() const {
        return !tasks.empty();
    }
};

// Recursive function to compute factorial
unsigned long long factorial(int n) {
    if (n == 0 || n == 1) {
        return 1;
    }
    return n * factorial(n - 1);
}

// Recursive function for numerical integration using Simpson's rule
double simpsonIntegration(std::function<double(double)> f, double a, double b, int depth, int maxDepth) {
    double c = (a + b) / 2;
    double h = b - a;
    double fa = f(a), fb = f(b), fc = f(c);

    double s = (h / 6) * (fa + 4 * fc + fb);

    if (depth >= maxDepth) {
        return s;
    }

    double left = simpsonIntegration(f, a, c, depth + 1, maxDepth);
    double right = simpsonIntegration(f, c, b, depth + 1, maxDepth);

    return left + right;
}

int main() {
    TaskScheduler scheduler;

    // Add some computational tasks
    scheduler.addTask(ComputationalTask("Matrix Multiplication", 3, 100.0));
    scheduler.addTask(ComputationalTask("FFT", 2, 50.0));
    scheduler.addTask(ComputationalTask("Neural Network Training", 1, 500.0));
    scheduler.addTask(ComputationalTask("Data Preprocessing", 4, 30.0));

    std::cout << "Processing tasks in priority order:\n";
    while (scheduler.hasTasks()) {
        ComputationalTask task = scheduler.getNextTask();
        std::cout << "Executing task: " << task.name 
                  << " (Priority: " << task.priority 
                  << ", Complexity: " << task.complexity << ")\n";
    }

    std::cout << "\nDemonstrating recursive factorial calculation:\n";
    int n = 5;
    std::cout << "Factorial of " << n << " is: " << factorial(n) << "\n";

    std::cout << "\nDemonstrating recursive numerical integration:\n";
    auto f = [](double x) { return std::sin(x); };  // Function to integrate
    double a = 0, b = M_PI;
    int maxDepth = 10;
    double result = simpsonIntegration(f, a, b, 0, maxDepth);
    std::cout << "Integral of sin(x) from 0 to pi: " << result << "\n";

    return 0;
}

This program demonstrates the following concepts in a scientific computing context:

  1. Heaps and Priority Queues:
  2. The TaskScheduler class uses std::priority_queue to manage computational tasks.
  3. Tasks are prioritized based on their priority value, with higher priority tasks processed first.
  4. This simulates a system where computational resources are allocated to more critical tasks first.

  5. Recursion and Stack Frames:

  6. The factorial function demonstrates simple recursion to calculate factorials.
  7. The simpsonIntegration function shows a more complex recursive algorithm for numerical integration using Simpson's rule.
  8. Both functions implicitly demonstrate the use of stack frames in recursion.

  9. Scientific Computing Applications:

  10. Task Scheduling: Simulates managing different computational tasks in a scientific computing environment.
  11. Factorial Calculation: A simple example of recursive mathematical computation.
  12. Numerical Integration: Demonstrates a practical application of recursion in scientific computing for approximating definite integrals.

  13. Additional C++ Features:

  14. std::function is used to pass a lambda function for integration.
  15. Lambda functions are used to define the function to be integrated.

This implementation provides examples of how heaps (via priority queues) and recursion can be applied in scientific computing scenarios:

The program also implicitly demonstrates the concept of stack frames through its recursive functions. Each recursive call creates a new stack frame, storing local variables and the return address. This is particularly evident in the simpsonIntegration function, where the recursion depth is tracked and limited to prevent stack overflow.

Related

Previous Page | Course Schedule | Course Content