mirror of
https://bitbucket.org/Mattrixwv/pyclasses.git
synced 2025-12-06 18:33:58 -05:00
234 lines
7.8 KiB
Python
234 lines
7.8 KiB
Python
#Python/myClasses/Algorithms.py
|
|
#Matthew Ellison
|
|
# Created: 01-27-19
|
|
#Modified: 03-22-19
|
|
#This is a file that contains a few algorithms that I have used several times
|
|
"""
|
|
Copyright (C) 2019 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 <https://www.gnu.org/licenses/>.
|
|
"""
|
|
|
|
|
|
import math
|
|
|
|
|
|
#Generate an infinite sequence of prime numbers using the Sieve of Eratosthenes
|
|
#Based on code by David Eppstein found at https://code.activestate.com/recipes/117119/
|
|
def primeGenerator():
|
|
#Return 2 the first time, this lets us skip all even numbers later
|
|
yield 2
|
|
|
|
#Map composite integers to primes witnessing their compositeness
|
|
dict = {}
|
|
|
|
#Start checking for primes with the number 3
|
|
possiblePrime = 3
|
|
while True:
|
|
#If q is not in the dictionary it is a new prime number
|
|
#Return it and mark it's next multiple
|
|
if possiblePrime not in dict:
|
|
yield possiblePrime
|
|
dict[possiblePrime * possiblePrime] = [possiblePrime]
|
|
#If q is in the dictionary it is a composite number
|
|
else:
|
|
#Move each witness to it's next multiple
|
|
for num in dict[possiblePrime]:
|
|
dict.setdefault(num + possiblePrime, []).append(num)
|
|
#We no longer need this, free the memory
|
|
del dict[possiblePrime]
|
|
|
|
#Skip all multiples of 2
|
|
possiblePrime += 2
|
|
|
|
#This function returns a list with all the prime numbers <= goalNumber
|
|
def getPrimes(goalNumber: int) -> list:
|
|
primes = []
|
|
foundFactor = False
|
|
|
|
#If the number is 0 or negative return an empty list
|
|
if(goalNumber <= 1):
|
|
return primes
|
|
#Otherwise the number is at least 2, therefore 2 should be added to the list
|
|
else:
|
|
primes.append(2)
|
|
|
|
#We can now start at 3 and skip all even numbers, because they cannot be prime
|
|
for possiblePrime in range(3, goalNumber + 1, 2): #Need goalNumber + 1 to account for goalNumber being prime
|
|
#Check all current primes, up to sqrt(possiblePrime), to see if there is a divisor
|
|
primesCnt = 0
|
|
#We can safely assume that there will at lease be 1 element in the primes list because of 2 being added before the loop
|
|
topPossibleFactor = math.ceil(math.sqrt(possiblePrime))
|
|
while(primes[primesCnt] <= topPossibleFactor):
|
|
if((possiblePrime % primes[primesCnt]) == 0):
|
|
foundFactor = True
|
|
break
|
|
else:
|
|
primesCnt += 1
|
|
#Check if the index has gone out of range
|
|
if(primesCnt >= len(primes)):
|
|
break
|
|
|
|
#If you didn't find a factor then the current number must be prime
|
|
if(not foundFactor):
|
|
primes.append(possiblePrime)
|
|
else:
|
|
foundFactor = False
|
|
|
|
primes.sort()
|
|
return primes
|
|
|
|
#This function gets a certain number of primes
|
|
def getNumPrimes(numberOfPrimes: int) -> list:
|
|
gen = primeGenerator()
|
|
#gen = postponed_sieve()
|
|
primes = []
|
|
for _ in range(1, numberOfPrimes + 1):
|
|
primes.append(next(gen))
|
|
|
|
#Return the list with all the prime numbers
|
|
return primes
|
|
|
|
#This is a function that returns all the factors of goalNumber
|
|
def getFactors(goalNumber: int) -> list:
|
|
prime_factors_list = []
|
|
while goalNumber % 2 == 0:
|
|
prime_factors_list.append(2)
|
|
goalNumber /= 2
|
|
for i in range(3, int(math.sqrt(goalNumber))+1, 2):
|
|
if goalNumber % i == 0:
|
|
prime_factors_list.append(i)
|
|
goalNumber /= i
|
|
if goalNumber > 2:
|
|
prime_factors_list.append(int(goalNumber))
|
|
prime_factors_list.sort()
|
|
return prime_factors_list
|
|
|
|
#This function returns all the divisors of goalNumber
|
|
def getDivisors(goalNumber: int) -> list:
|
|
divisors = []
|
|
#Start by checking that the number is positive
|
|
if(goalNumber <= 0):
|
|
return divisors
|
|
#If the number is 1 return just itself
|
|
elif(goalNumber == 1):
|
|
divisors.append(1)
|
|
return divisors
|
|
|
|
#Start at 3 and loop through all numbers < (goalNumber / 2 ) looking for a number that divides it evenly
|
|
topPossibleDivisor = math.ceil(math.sqrt(goalNumber))
|
|
possibleDivisor = 1
|
|
while(possibleDivisor <= topPossibleDivisor):
|
|
#If you find one add it and the number it creates to the list
|
|
if((goalNumber % possibleDivisor) == 0):
|
|
divisors.append(possibleDivisor)
|
|
#Account for the possibility sqrt(goalNumber) being a divisor
|
|
if(possibleDivisor != topPossibleDivisor):
|
|
divisors.append(goalNumber / possibleDivisor)
|
|
#Take care of a few occations where a number was added twice
|
|
if(divisors[len(divisors) - 1] == (possibleDivisor + 1)):
|
|
possibleDivisor += 1
|
|
possibleDivisor += 1
|
|
|
|
#Sort the list before returning for neatness
|
|
divisors.sort()
|
|
#Return the list
|
|
return divisors
|
|
|
|
#This function returns the numth Fibonacci number
|
|
def getFib(goalSubscript: int) -> int:
|
|
#Setup the variables
|
|
fibNums = [1, 1, 0] #A list to keep track of the Fibonacci numbers. It need only be 3 long because we only need the one we are working on and the last 2
|
|
|
|
#If the number is <= 0 return 0
|
|
if(goalSubscript <= 0):
|
|
return 0
|
|
|
|
#Loop through the list, generating Fibonacci numbers until it finds the correct subscript
|
|
fibLoc = 2
|
|
while(fibLoc < goalSubscript):
|
|
fibNums[fibLoc % 3] = fibNums[(fibLoc - 1) % 3] + fibNums[(fibLoc - 2) % 3]
|
|
fibLoc += 1
|
|
|
|
#Return the propper number. The location counter is 1 off of the subscript
|
|
return fibNums[(fibLoc - 1) % 3]
|
|
|
|
#This function returns a list of all Fibonacci numbers <= num
|
|
def getAllFib(goalNumber: int) -> list:
|
|
#Setup the variables
|
|
fibNums = [] #A list to save the Fibonacci numbers
|
|
|
|
#If the number is <= 0 return an empty list
|
|
if(goalNumber <= 0):
|
|
return fibNums
|
|
|
|
#This means that at least 2 1's are elements
|
|
fibNums.append(1)
|
|
fibNums.append(1)
|
|
|
|
#Loop to generate the rest of the Fibonacci numbers
|
|
while(fibNums[len(fibNums) - 1] <= goalNumber):
|
|
fibNums.append(fibNums[len(fibNums) - 1] + fibNums[len(fibNums) - 2])
|
|
|
|
#At this point the most recent number is > goalNumber, so remove it
|
|
fibNums.pop()
|
|
return fibNums
|
|
|
|
#This function returns the product of all elements in the list
|
|
def prod(nums: list) -> int:
|
|
#If a blank list was sent to the function return 0 as the product
|
|
if(len(nums) == 0):
|
|
return 0
|
|
|
|
#Setup the variables
|
|
product = 1 #Start at 1 because of working with multiplication
|
|
|
|
#Loop through every element in a list and multiply them together
|
|
for num in nums:
|
|
product *= num
|
|
|
|
#Return the product of all elements
|
|
return product
|
|
|
|
#This is a function that creates all permutations of a string and returns a vector of those permutations.
|
|
def getPermutations(master: str, num: int = 0) -> list:
|
|
perms = []
|
|
#Check if the number is out of bounds
|
|
if((num >= len(master)) or (num < 0)):
|
|
#Do nothing and return and empty list
|
|
perms
|
|
#If this is the last possible recurse just return the current string
|
|
elif(num == (len(master) - 1)):
|
|
perms.append(master)
|
|
#If there are more possible recurses, recurse with the current permutations
|
|
else:
|
|
temp = getPermutations(master, num + 1)
|
|
perms += temp
|
|
#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 cnt in range(1, len(master) - num):
|
|
#Swap two elements
|
|
master = master[0:num] + master[num + cnt] + master[num + 1 : num + cnt] + master[num] + master[num + cnt + 1:]
|
|
#Get the permutations after swapping two elements
|
|
temp = getPermutations(master, num + 1)
|
|
perms += temp
|
|
#Swap the elements back
|
|
master = master[0:num] + master[num + cnt] + master[num + 1 : num + cnt] + master[num] + master[num + cnt + 1:]
|
|
|
|
#The array is not necessarily in alpha-numeric order. So if this is the full array sort it before returning
|
|
if(num == 0):
|
|
perms.sort()
|
|
#Return the list
|
|
return perms
|