//myClasses/Algorithms.hpp //Matthew Ellison // Created: 11-8-18 //Modified: 1-30-19 //This file contains the declarations and implementations to several algoritms that I have found useful /* Copyright (C) 2018 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 //This library is licensed under lgplv3 //You can find more information at gmplib.org //In order to use this functionality you must use the -DNEEDGMP flag in your compiler //You must also link both libgmpxx and libgmp #ifdef NEEDGMP #include //This is necessary for the getGmpFib function for numbers larger than a normal int can hold. It can be commented out if needed #endif //NEEDGMP namespace mee{ //A list of functions in the file //Also works as prototypes with general information //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 gets the sum of all elements in a vector and returns the number template T getSum(std::vector numbers); //This is a function that searches a vecter for an element. Returns true if num is found in list template bool isFound(T num, std::vector list); //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(T num); //In order to use this functionality you must use the -DNEEDGMP flag in your compiler //You must also link both libgmpxx and libgmp #ifdef NEEDGMP mpz_class getMpzFib(uint64_t num); #endif //NEEDGMP //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 bool bubbleSort(std::vector nums); //This is a function that perfomrs a quick sort on a vector template bool quickSort(std::vector nums); //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(std::vector nums, T num); //This function finds the smallest element in a vector template T findMin(std::vector arr); //This function finds the largest element in a vector template T findMax(std::vector arr); template std::vector getPrimes(T goalNumber){ std::vector primes; bool foundFactor = false; //If the number is 0 or a negative number return an empty vector if(goalNumber < 1){ return primes; } //If the number is even 2 is a factor if((goalNumber % 2) == 0){ 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; } template std::vector getNumPrimes(T numberOfPrimes){ std::vector primes; primes.reserve(numberOfPrimes); //Saves cycles later bool foundFactor = false; //If the number is 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; } 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 0; } 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); } else{ divisors.push_back(1); divisors.push_back(num); } //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); } } } //Sort the vector for neatness std::sort(divisors.begin(), divisors.end()); //Return the vector of divisors return divisors; } template T getSum(std::vector numbers){ T sum = 0; for(unsigned int cnt = 0;cnt < numbers.size();++cnt){ sum += numbers.at(cnt); } return sum; } template bool isFound(T num, std::vector list){ for(int cnt = 0;cnt < list.size();++cnt){ if(list.at(cnt) == num){ return true; } } return false; } 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; } template T getFib(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 for(T 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[(num - 1) % 3]; //Transfer the answer to permanent variable. -1 to account for the offset of starting at 0 return fib; } //In order to use this functionality you must use the -DNEEDGMP flag in your compiler //You must also link both libgmpxx and libgmp #ifdef NEEDGMP mpz_class getMpzFib(uint64_t num){ //Make sure the number is within bounds if(num <= 0){ return 0; } else if(num <= 2){ return 1; } mpz_class fibNum = 0; mpz_class tempNums[3]; //Initialize the variables tempNums[0] = 1; tempNums[1] = 1; //Do the calculation for(uint64_t cnt = 2;cnt < num;++cnt){ tempNums[cnt % 3] = tempNums[(cnt + 1) % 3] + tempNums[(cnt + 2) % 3]; } return tempNums[(num - 1) % 3]; //Return the answer } #endif //NEEDGMP //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]); } //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 bool bubbleSort(std::vector nums){ bool notFinished = true; //A flag to determine if the loop is finished for(int numLoops = 0;notFinished;++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 = 0;cnt < ((nums.size() - 1) - numLoops);++cnt){ //use size - 1 to make sure you don't go out of bounds if(nums.at(cnt) > nums.at(cnt + 1)){ std::swap(nums.at(cnt), nums.at(cnt + 1)); notFinished = true; } } } } //This is a function that perfomrs a quick sort on a vector template bool quickSort(std::vector nums){ } //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(std::vector nums, 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 < nums.size()){ if(nums.at(subscript) == num){ return subscript; } } //If you cannot find the element return -1 return -1; } //This function finds the smallest element in a vector template T findMin(std::vector arr){ T min; //For the smallest element //Make sure the vector is not empty if(arr.size() > 0){ //Use the first element as the smallest element min = arr.at(0); //Run through every element in the vector, checking it against the current minimum for(int cnt = 1;cnt < arr.size();++cnt){ //If the current element is smaller than the minimum, make it the new minimum if(arr.at(cnt) < min){ min = arr.at(cnt); } } } //Return the element return min; } //This function finds the largest element in a vector template T findMax(std::vector arr){ T max; //For the largest element //Make sure the vector is not empty if(arr.size() > 0){ //Use the first element as the largest element max = arr.at(0); //Run through every element in the vector, checking it against the current minimum for(int cnt = 1;cnt < arr.size();++cnt){ //If the current element is larger than the maximum, make it the new maximum if(arr.at(cnt) > max){ max = arr.at(cnt); } } } //Return the element return max; } } #endif //MEE_ALGORITHMS_HPP