/** * Max Sub Sum * CS 2240 * University of Vermont * Lisa Dion * 2019-???-?? * * Clayton Cafiero * 2020-Jun-25 * Revisions: * - Avoid use of using namespace std; but leave note that safe in context * - Include Kadane's algorithm * - Add step counter and revise each algorithm to count steps * - Display answer and number of steps taken * - Make use of random number generation to create array for testing * - Additional comments * - Minor changes to formatting */ #include #include #include "randi.h" #define SIZE 1000 #define RANGE 20 int steps; /** * Brute force, O(n^3) * @param a * @return */ int maxSubSum1(const std::vector &a) { int maxSum = 0; for (int i = 0; i < a.size(); ++i) { for (int j = i; j < a.size(); ++j) { int thisSum = 0; for (int k = i; k <= j; ++k) { thisSum += a[k]; steps++; } if (thisSum > maxSum) { maxSum = thisSum; } } } return maxSum; } /** * Improved, O(n^2) * @param a * @return */ int maxSubSum2(const std::vector &a) { int maxSum = 0; for (int i = 0; i < a.size(); ++i) { int thisSum = 0; for (int j = i; j < a.size(); ++j) { thisSum += a[j]; steps++; if (thisSum > maxSum) { maxSum = thisSum; } } } return maxSum; } /** * Recursive, divide and conquer approach, O(n log n) * After Shamos * @param a * @param left * @param right * @return */ int maxSumRec(const std::vector &a, int left, int right) { // base case for recursion, when we have one element if (left == right) { if (a[left] > 0) { return a[left]; } else { return 0; } } // divide into two halves int center = (left + right) / 2; // get the max subsequence sum from each of the two halves int maxLeftSum = maxSumRec(a, left, center); // recursive call int maxRightSum = maxSumRec(a, center + 1, right); // recursive call // starting from the center and working toward left boundary int maxLeftBorderSum = 0, leftBorderSum = 0; for (int i = center; i >= left; --i) { leftBorderSum += a[i]; steps++; if (leftBorderSum > maxLeftBorderSum) { maxLeftBorderSum = leftBorderSum; } } // starting from the center and working toward right boundary int maxRightBorderSum = 0, rightBorderSum = 0; for (int j = center + 1; j <= right; ++j) { rightBorderSum += a[j]; steps++; if (rightBorderSum > maxRightBorderSum) { maxRightBorderSum = rightBorderSum; } } int combined = maxLeftBorderSum + maxRightBorderSum; // return the max of the three subsequence sums return std::max(maxLeftSum, std::max(maxRightSum, combined)); } /** * Kadane's algorithm, O(n) */ int kadanesAlgo(const std::vector &a) { int bestSum = 0; int currentSum = 0; for (int i = 0; i < a.size(); ++i) { currentSum = std::max(0, currentSum + a[i]); bestSum = std::max(bestSum, currentSum); steps++; } return bestSum; } int main() { std::vector a; // populate array with SIZE random integers between -RANGE and RANGE randPopulateArray(a, SIZE, RANGE); steps = 0; std::cout << "Brute force, O(n^3)" << std::endl; std::cout << "Answer: " << maxSubSum1(a) << std::endl; std::cout << "Steps: " << steps << std::endl << std::endl; steps = 0; std::cout << "Improved, O(n^2)" << std::endl; std::cout << "Answer: " << maxSubSum2(a) << std::endl; std::cout << "Steps: " << steps << std::endl << std::endl; steps = 0; std::cout << "Shamos' divide and conquer, O(n log(n))" << std::endl; std::cout << "Answer: " << maxSumRec(a, 0, a.size() - 1) << std::endl; std::cout << "Steps: " << steps << std::endl << std::endl; steps = 0; std::cout << "Kadane's Algorithm, O(n)" << std::endl; std::cout << "Answer: " << kadanesAlgo(a) << std::endl; std::cout << "Steps: " << steps << std::endl; return 0; }