diff --git a/README.md b/README.md index 0c2819e..cc0db73 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Examples include (and will expand to): * [integer-factorization](./integer-factorization/) * Encoding * [rot47](./rot47/) + * [prefix-sum](./prefix-sum/) * Data Structures * [map-with-unknown-key](./map-with-unknown-key/) * OOP diff --git a/prefix-sum/Makefile b/prefix-sum/Makefile new file mode 100644 index 0000000..ab8b3c0 --- /dev/null +++ b/prefix-sum/Makefile @@ -0,0 +1,31 @@ +# pull in shared compiler settings +include ../common.mk + +# per-example flags +# CXXFLAGS += -pthread + +## get it from the folder name +TARGET := $(notdir $(CURDIR)) +## all *.cpp files in this folder +SRCS := $(wildcard *.cpp) +OBJS := $(SRCS:.cpp=.o) + +all: $(TARGET) + +$(TARGET): $(OBJS) + $(CXX) $(CXXFLAGS) -o $@ $^ + +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c $< -o $@ + +run: $(TARGET) + ./$(TARGET) $(ARGS) + +clean: + rm -f $(OBJS) $(TARGET) + +# Delegates to top-level Makefile +check-format: + $(MAKE) -f ../Makefile check-format DIR=$(CURDIR) + +.PHONY: all clean run check-format diff --git a/prefix-sum/main.cpp b/prefix-sum/main.cpp new file mode 100644 index 0000000..873904a --- /dev/null +++ b/prefix-sum/main.cpp @@ -0,0 +1,171 @@ +/** +Different ways to compute the prefix sum of a list of numbers. +*/ + +#include +#include +#include +#include +#include + +using std::vector; + +vector +compute_prefix_sum1(const vector& nums) +{ + if (nums.empty()) { + return {}; + } + vector prefix_sum(nums.size()); + prefix_sum[0] = nums[0]; + for (size_t i = 1; i < nums.size(); ++i) { + prefix_sum[i] = prefix_sum[i - 1] + nums[i]; + } + return prefix_sum; +} + +vector +compute_prefix_sum2(const vector& nums) +{ + if (nums.empty()) { + return {}; + } + vector prefix_sum(nums.size()); + inclusive_scan(nums.begin(), nums.end(), prefix_sum.begin(), std::plus()); + return prefix_sum; +} + +vector +compute_prefix_sum3(const vector& nums) +{ + if (nums.empty()) { + return {}; + } + vector prefix_sum(nums.size()); + partial_sum(nums.begin(), nums.end(), prefix_sum.begin()); + return prefix_sum; +} + +vector +compute_prefix_sum4(const vector& nums) +{ + if (nums.empty()) { + return {}; + } + + vector prefix_sum; + prefix_sum.reserve(nums.size()); + int sum = 0; + for (const auto& num : nums) { + sum += num; + prefix_sum.push_back(sum); + } + return prefix_sum; +} + +vector +compute_prefix_sum5(const vector& nums) +{ + if (nums.empty()) { + return {}; + } + + vector prefix_sum(nums.size()); + std::transform( + std::begin(nums), std::end(nums), std::begin(prefix_sum), [n = 0](int num) mutable { return n += num; }); + return prefix_sum; +} + +vector +compute_prefix_sum6(const vector& nums) +{ + if (nums.empty()) { + return {}; + } + + vector prefix_sum; + prefix_sum.reserve(nums.size()); + std::accumulate(nums.begin(), nums.end(), 0, [&prefix_sum](int acc, int num) { + int new_sum = acc + num; + prefix_sum.push_back(new_sum); + return new_sum; + }); + return prefix_sum; +} + +vector +compute_prefix_sum7(const vector& nums) +{ + if (nums.empty()) { + return {}; + } + + vector prefix_sum; + prefix_sum.reserve(nums.size()); + int sum = 0; + std::for_each(nums.begin(), nums.end(), [&prefix_sum, &sum](int num) { + sum += num; + prefix_sum.push_back(sum); + }); + return prefix_sum; +} + +vector +assert_equal(const vector& a, const vector& b) +{ + if (a.size() != b.size()) { + throw std::runtime_error("Vectors have different sizes"); + } + if (std::equal(a.begin(), a.end(), b.begin())) { + return a; + } + // if (std::any_of(a.begin(), a.end(), [&, i = 0](int val) mutable { + // return val != b[i++]; + // })) { + // throw std::runtime_error("Vectors differ"); + // } + // if (std::all_of(a.begin(), a.end(), [&, i = 0](int val) mutable { + // return val == b[i++]; + // })) { + // return a; + // } + throw std::runtime_error("Vectors differ"); +} + +int +main() +{ + vector nums = {1, 2, 3, 4, 5}; + vector prefix_sum_expected = {1, 3, 6, 10, 15}; + + // Method 1: simple loop implementation + auto prefix_sum1 = compute_prefix_sum1(nums); + assert_equal(prefix_sum1, prefix_sum_expected); + + // Method 2: using inclusive_scan + auto prefix_sum2 = compute_prefix_sum2(nums); + assert_equal(prefix_sum2, prefix_sum_expected); + + // Method 3: using partial_sum + auto prefix_sum3 = compute_prefix_sum3(nums); + assert_equal(prefix_sum3, prefix_sum_expected); + + // Method 4: using push_back in a loop + auto prefix_sum4 = compute_prefix_sum4(nums); + assert_equal(prefix_sum4, prefix_sum_expected); + + // Method 5: using transform with a mutable lambda + auto prefix_sum5 = compute_prefix_sum5(nums); + assert_equal(prefix_sum5, prefix_sum_expected); + + // Method 6: using accumulate with a lambda that updates a vector + auto prefix_sum6 = compute_prefix_sum6(nums); + assert_equal(prefix_sum6, prefix_sum_expected); + + // Method 7: using for_each with a lambda that updates a vector + auto prefix_sum7 = compute_prefix_sum7(nums); + assert_equal(prefix_sum7, prefix_sum_expected); + + std::cout << "All tests passed!" << std::endl; + return 0; +} diff --git a/prefix-sum/tests.sh b/prefix-sum/tests.sh new file mode 100755 index 0000000..16e6ed9 --- /dev/null +++ b/prefix-sum/tests.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +set -ex + +./prefix-sum