//myClasses/Algorithms.hpp //Matthew Ellison // Created: 11-08-18 //Modified: 06-01-21 //This file contains the declarations and implementations to several algoritms that I have found useful /* Copyright (C) 2021 Matthew Ellison This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef MEE_ALGORITHMS_HPP #define MEE_ALGORITHMS_HPP #include #include #include #include #include #include #include namespace mee{ //A list of functions in the file //Also works as prototypes with general information //This function determines whether the number passed into it is a prime template bool isPrime(T num); //This is a function that returns all the primes <= goalNumber and returns a vector with those prime numbers template std::vector getPrimes(T goalNumber); //This function returns a vector with a specific number of primes template std::vector getNumPrimes(T numberOfPrimes); //This function returns all prime factors of a number template std::vector getFactors(T goalNumber); //This is a function that gets all the divisors of num and returns a vector containing the divisors template std::vector getDivisors(T num); //This is a function that returns the sum of all elements in a vector template T getSum(const std::vector& numbers); //This is a function that returns the product of all elements in a vector template T getProduct(const std::vector& nums); //This is a function that searches a vecter for an element. Returns true if the key is found in list template bool isFound(std::vector ary, T key); //This is a function that creates all permutations of a string and returns a vector of those permutations. //It is meant to have only the string passed into it from the calling function. num is used for recursion purposes //It can however be used with num if you want the first num characters to be stationary std::vector getPermutations(std::string master, int num = 0); //These functions return the numth Fibonacci number template T getFib(const T num); //This function returns a vector that includes all Fibonacci numbers <= num template std::vector getAllFib(const T num); //This is a function that performs a bubble sort on a vector template void bubbleSort(std::vector& ary); //This is a function that makes quick sort easier to start template void quickSort(std::vector& ary); //This is the function that actually performs the quick sort on the vector template void quickSort(std::vector& ary, int64_t bottom, int64_t top); //This is a helper function for quickSort. It chooses a pivot element and sorts everything to larger or smaller than the pivot. Returns location of pivot template int64_t partition(std::vector& ary, int64_t bottom, int64_t top); //This is a function that performs a search on a vector and returns the subscript of the item being searched for (-1 if not found) template int64_t search(const std::vector& ary, T num); //This function finds the smallest element in a vector template T findMin(const std::vector& ary); //This function finds the largest element in a vector template T findMax(const std::vector& ary); //This function returns the number of times the character occurs in the string int findNumOccurrence(std::string str, char ch); template class SieveOfEratosthenes{ private: T possiblePrime; //The next number that could be a prime std::unordered_map> compositeMap; //A map to keep track of all of the composite numbers public: SieveOfEratosthenes(): possiblePrime(2){} bool hasNext(){ return true; } T next(){ T prime; if(possiblePrime > 2){ //Loop until you find a prime number for(;compositeMap[possiblePrime].size() > 0;possiblePrime += 2){ //Create the next entry for all entries in the map for(T num : compositeMap[possiblePrime]){ compositeMap[possiblePrime + num + num].push_back(num); } //Delete the current entry compositeMap.erase(possiblePrime); } //If the number is a prime //Save that it is a prime prime = possiblePrime; //Add the next entry to the prime compositeMap[prime * 3].push_back(prime); possiblePrime += 2; } else{ prime = possiblePrime++; } return prime; } }; //This is a function that returns all the primes <= goalNumber and returns a vector with those prime numbers template std::vector getPrimes(T goalNumber){ std::vector primes; bool foundFactor = false; //If the number is 1, 0, or a negative number return an empty vector if(goalNumber <= 1){ return primes; } else{ primes.push_back(2); } //We can now start at 3 and skip all of the even numbers for(T possiblePrime = 3;possiblePrime <= goalNumber;possiblePrime += 2){ //Step through every element in the current primes. If you don't find anything that divides it, it must be a prime itself uint64_t topPossibleFactor = ceil(sqrt(possiblePrime)); for(uint64_t cnt = 0;(cnt < primes.size()) && (primes.at(cnt) <= topPossibleFactor);++cnt){ if((possiblePrime % primes.at(cnt)) == 0){ foundFactor = true; break; } } //If you didn't find a factor then it must be prime if(!foundFactor){ primes.push_back(possiblePrime); } //If you did find a factor you need to reset the flag else{ foundFactor = false; } } std::sort(primes.begin(), primes.end()); return primes; } //This function returns a vector with a specific number of primes template std::vector getNumPrimes(T numberOfPrimes){ std::vector primes; primes.reserve(numberOfPrimes); //Saves cycles later bool foundFactor = false; //If the number is 1, 0, or a negative number return an empty vector if(numberOfPrimes <= 1){ return primes; } //Otherwise 2 is the first prime number else{ primes.push_back(2); } //Loop through every odd number starting at 3 until we find the requisite number of primes //Using possiblePrime >= 3 to make sure it doesn't loop back around in an overflow error and create an infinite loop for(T possiblePrime = 3;(primes.size() < numberOfPrimes) && (possiblePrime >= 3);possiblePrime += 2){ //Step through every element in the current primes. If you don't find anything that divides it, it must be a prime itself uint64_t topPossibleFactor = ceil(sqrt(possiblePrime)); for(uint64_t cnt = 0;(cnt < primes.size()) && (primes.at(cnt) <= topPossibleFactor);++cnt){ if((possiblePrime % primes.at(cnt)) == 0){ foundFactor = true; break; } } //If you didn't find a factor then it must be prime if(!foundFactor){ primes.push_back(possiblePrime); } //If you did find a factor you need to reset the flag else{ foundFactor = false; } } //The numbers should be in order, but sort them anyway just in case std::sort(primes.begin(), primes.end()); return primes; } //This function determines whether the number passed into it is a prime template bool isPrime(T possiblePrime){ if(possiblePrime <= 3){ return possiblePrime > 1; } else if(((possiblePrime % 2) == 0) || ((possiblePrime % 3) == 0)){ return false; } for(T cnt = 5;(cnt * cnt) <= possiblePrime;cnt += 6){ if(((possiblePrime % cnt) == 0) || ((possiblePrime % (cnt + 2)) == 0)){ return false; } } return true; } //This function returns all prime factors of a number template std::vector getFactors(T goalNumber){ //Get all the prime numbers up to sqrt(number). If there is a prime < goalNumber it will have to be <= sqrt(goalNumber) std::vector primes = getPrimes((T)ceil(sqrt(goalNumber))); //Make sure you are getting a vector of the correct type std::vector factors; //Need to step through each prime and see if it is a factor of the number for(int cnt = 0;cnt < primes.size();){ if((goalNumber % primes[cnt]) == 0){ factors.push_back(primes[cnt]); goalNumber /= primes[cnt]; } else{ ++cnt; } } //If it didn't find any factors in the primes the number itself must be prime if(factors.size() == 0){ factors.push_back(goalNumber); goalNumber /= goalNumber; } ///Should add some kind of error throwing inc ase the number != 1 after searching for all prime factors return factors; } //This is a function that gets all the divisors of num and returns a vector containing the divisors template std::vector getDivisors(T num){ std::vector divisors; //Holds the number of divisors //Ensure the parameter is a valid number if(num <= 0){ return divisors; } else if(num == 1){ divisors.push_back(1); return divisors; } //You only need to check up to sqrt(num) T topPossibleDivisor = ceil(sqrt(num)); for(uint64_t possibleDivisor = 1;possibleDivisor <= topPossibleDivisor;++possibleDivisor){ //Check if the counter evenly divides the number //If it does the counter and the other number are both divisors if((num % possibleDivisor) == 0){ //We don't need to check if the number already exists because we are only checking numbers <= sqrt(num), so there can be no duplicates divisors.push_back(possibleDivisor); //We still need to account for sqrt(num) being a divisor if(possibleDivisor != topPossibleDivisor){ divisors.push_back(num / possibleDivisor); } //Take care of a few occations where a number was added twice if(divisors.at(divisors.size() - 1) == (possibleDivisor + 1)){ ++possibleDivisor; } } } //Sort the vector for neatness std::sort(divisors.begin(), divisors.end()); //Return the vector of divisors return divisors; } //This is a function that returns the sum of all elements in a vector template T getSum(const std::vector& ary){ T sum = 0; for(unsigned int cnt = 0;cnt < ary.size();++cnt){ sum += ary.at(cnt); } return sum; } //This is a function that returns the product of all elmements in a vector template T getProduct(const std::vector& ary){ //Make sure there is something in the array if(ary.size() == 0){ return 0; } //Multiply all elements in the array together T prod = 1; for(T cnt = 0;cnt < ary.size();++cnt){ prod *= ary.at(cnt); } return prod; } //This is a function that searches a vecter for an element. Returns true if they key is found in list template bool isFound(std::vector ary, T key){ typename std::vector::iterator location = std::find(ary.begin(), ary.end(), key); if(location == ary.end()){ return false; } else{ return true; } } //This is a function that creates all permutations of a string and returns a vector of those permutations. std::vector getPermutations(std::string master, int num){ std::vector perms; //Check if the number is out of bounds if((num >= master.size()) || (num < 0)){ return perms; } //If this is the last possible recurse just return the current string else if(num == (master.size() - 1)){ perms.push_back(master); return perms; } //If there are more possible recurses, recurse with the current permutation std::vector temp; temp = getPermutations(master, num + 1); perms.insert(perms.end(), temp.begin(), temp.end()); //You need to swap the current letter with every possible letter after it //The ones needed to swap before will happen automatically when the function recurses for(int cnt = 1;(num + cnt) < master.size();++cnt){ std::swap(master[num], master[num + cnt]); temp = getPermutations(master, num + 1); perms.insert(perms.end(), temp.begin(), temp.end()); std::swap(master[num], master[num + cnt]); } //The array is not necessarily in alpha-numeric order. So if this is the full array sort it before returning if(num == 0){ std::sort(perms.begin(), perms.end()); } return perms; } //These functions return the numth Fibonacci number template T getFib(const T num){ //Make sure the number is within bounds if(num <= 2){ return 1; } //Setup the variables T fib = 0; T tempNums[3]; tempNums[0] = tempNums[1] = 1; //Do the calculation unsigned int cnt; for(cnt = 2;(cnt < num) && (tempNums[(cnt - 1) % 3] >= tempNums[(cnt - 2) % 3]);++cnt){ tempNums[cnt % 3] = tempNums[(cnt + 1) % 3] + tempNums[(cnt + 2) % 3]; } fib = tempNums[(cnt - 1) % 3]; //Transfer the answer to permanent variable. -1 to account for the offset of starting at 0 return fib; } //This function returns a vector that includes all Fibonacci numbers <= num template std::vector getAllFib(const T num){ std::vector fibList; //Make sure the number is within bounds if(num <= 1){ fibList.push_back(1); return fibList; } else{ //Make sure to add the first 2 elements fibList.push_back(1); fibList.push_back(1); } //Setup the variables T fib = 0; T tempNums[3]; tempNums[0] = tempNums[1] = 1; //Do the calculation and add each number to the vector for(T cnt = 2;(tempNums[(cnt - 1) % 3] <= num) && (tempNums[(cnt - 1) % 3] >= tempNums[(cnt - 2) % 3]);++cnt){ tempNums[cnt % 3] = tempNums[(cnt + 1) % 3] + tempNums[(cnt + 2) % 3]; fibList.push_back(tempNums[cnt % 3]); } //If you triggered the exit statement you have one more element than you need fibList.pop_back(); //Return the vector that contains all of the Fibonacci numbers return fibList; } //This is a function that performs a bubble sort on a vector template void bubbleSort(std::vector& ary){ bool notFinished = true; //A flag to determine if the loop is finished for(int numLoops = 0;numLoops < ary.size();++numLoops){ //Loop until you finish notFinished = false; //Assume you are finished until you find an element out of order //Loop through every element in the vector, moving the largest one to the end for(int cnt = 1;cnt < (ary.size() - numLoops);++cnt){ //use size - 1 to make sure you don't go out of bounds if(ary.at(cnt) < ary.at(cnt - 1)){ std::swap(ary.at(cnt), ary.at(cnt - 1)); notFinished = true; } } } } //This is a function that makes quick sort easier to start template void quickSort(std::vector& ary){ //Call the other quickSort function with all the necessary info quickSort(ary, 0, ary.size() - 1); } //This is the function that actually performs the quick sort on the vector template void quickSort(std::vector& ary, int64_t bottom, int64_t top){ //Make sure you have a valid slice of the vector if(bottom < top){ //Get the pivot location int64_t pivot = partition(ary, bottom, top); //Sort all element less than the pivot quickSort(ary, bottom, pivot - 1); //Sort all element greater than the pivot quickSort(ary, pivot + 1, top); } } //This is a helper function for quickSort. It chooses a pivot element and sorts everything to larger or smaller than the pivot. Returns location of pivot template int64_t partition(std::vector& ary, int64_t bottom, int64_t top){ int64_t pivot = ary.at(top); //Pick a pivot element int64_t smaller = bottom - 1; //Keep track of where all elements are smaller than the pivot //Loop through every element in the vector testing if it is smaller than pivot for(int64_t cnt = bottom;cnt < top;++cnt){ //If the element is smaller than pivot move it to the correct location if(ary.at(cnt) < pivot){ //Increment the tracker for elements smaller than pivot ++smaller; //Swap the current element to the correct location for being smaller than the pivot std::swap(ary.at(smaller), ary.at(cnt)); } } //Move the pivot element to the correct location ++smaller; std::swap(ary.at(top), ary.at(smaller)); //Return the pivot element return smaller; } //This is a function that performs a search on a vector and returns the subscript of the item being searched for template int64_t search(const std::vector& ary, T num){ int64_t subscript = 0; //Start with the subscript at 0 //Step through every element in the vector and return the subscript if you find the correct element while(subscript < ary.size()){ if(ary.at(subscript) == num){ return subscript; } else{ ++subscript; } } //If you cannot find the element return -1 return -1; } //This function finds the smallest element in a vector template T findMin(const std::vector& ary){ T min; //For the smallest element //Make sure the vector is not empty if(ary.size() > 0){ //Use the first element as the smallest element min = ary.at(0); //Run through every element in the vector, checking it against the current minimum for(int cnt = 1;cnt < ary.size();++cnt){ //If the current element is smaller than the minimum, make it the new minimum if(ary.at(cnt) < min){ min = ary.at(cnt); } } } //Return the element return min; } //This function finds the largest element in a vector template T findMax(const std::vector& ary){ T max; //For the largest element //Make sure the vector is not empty if(ary.size() > 0){ //Use the first element as the largest element max = ary.at(0); //Run through every element in the vector, checking it against the current minimum for(int cnt = 1;cnt < ary.size();++cnt){ //If the current element is larger than the maximum, make it the new maximum if(ary.at(cnt) > max){ max = ary.at(cnt); } } } //Return the element return max; } //This function returns the number of times the character occurs in the string int findNumOccurrence(std::string str, char ch){ int num = 0; //Set the number of occurrences to 0 to start //Loop through every character in the string and compare it to the character passed in for(char strCh : str){ //If the character is the same as the one passed in increment the counter if(strCh == ch){ ++num; } } //Return the number of times the character appeared in the string return num; } //Return a vector of strings split on the delimiter std::vector split(std::string str, char delimiter){ std::vector splitStrings; int location = 0; location = str.find(delimiter); while(location != std::string::npos){ //Split the string std::string firstString = str.substr(0, location); str = str.substr(location + 1); //+1 to skip the delimiter itself //Add the string to the vector splitStrings.push_back(firstString); //Get the location of the next delimiter location = str.find(delimiter); } //Get the final string if it isn't empty if(!str.empty()){ splitStrings.push_back(str); } //Return the vector of strings return splitStrings; } //Return the factorial of the number passed in template T factorial(T num){ T fact = 1; for(T cnt = 1;cnt <= num;++cnt){ fact *= cnt; } return fact; } } #endif //MEE_ALGORITHMS_HPP