You are on page 1of 42

Sieve of Eratosthenes

• The sieve of Eratosthenes is one of the most efficient


ways to find all primes smaller than n when n is smaller
than 10 million or so
• Following is the algorithm to find all the prime numbers
less than or equal to a given integer n by the
Eratosthene’s method:
When the algorithm terminates, all the numbers in the
list that are not marked are prime.
To find all the prime numbers less than or equal to a given integer n by Eratosthenes'
method:
1.Create a list of consecutive integers from 2 through n: (2, 3, 4, ..., n).
2.Initially, let p equal 2, the smallest prime number.
3.Enumerate the multiples of p by counting in increments of p from 2p to n, and
mark them in the list (these will be 2p, 3p, 4p, ...; the p itself should not be
marked).
4.Find the smallest number in the list greater than p that is not marked. If there
was no such number, stop. Otherwise, let p now equal this new number (which is
the next prime), and repeat from step 3.
5.When the algorithm terminates, the numbers remaining not marked in the list
are all the primes below n.
Pseudocode

algorithm Sieve of Eratosthenes is


input: an integer n > 1.
output: all prime numbers from 2 through n.
let A be an array of Boolean values, indexed by integers 2 to n,
initially all set to true.
for i = 2, 3, 4, ..., not exceeding √n do
if A[i] is true
for j = i2 , i2+i, i2+2i, i2+3i, ..., not exceeding n do
set A[j] := false
return all i such that A[i] is true.
# Python program for the above approach
Primes = [0] * 500001
def SieveOfEratosthenes(n) :
Primes[0] = 1
i=3
while(i*i <= n) :
if (Primes[i // 2] == 0) :
for j in range(3 * i, n+1, 2 * i) :
Primes[j // 2] = 1

i += 2

# Driver Code
if __name__ == "__main__":

n = 100
SieveOfEratosthenes(n)
for i in range(1, n+1) :
if (i == 2) :
print( i, end = " ")
elif (i % 2 == 1 and Primes[i // 2] == 0) :
print( i, end = " ")
Example
What are all prime numbers less than 20. (Use the
Sieve of Eratosthenes method).
Solution: Let us first write the numbers from 2 to 20.
2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20

•Start from 2
•In the next step, encircle 2 and cross the multiples of 2 (4, 6, 8, 10, 12,
14, 16, 18, 20)
•Encircle 3 and cross the left multiples of 3 (9, 15)
•Encircle 5 and cross the left multiples of 5 (only 10 is left)
•Now, encircle the rest of the numbers 7, 11, 13, 17 and 19.
Therefore, the required prime numbers between 1 to 20 are 2, 3, 5, 7, 11,
13, 17 and 19.
Fill all prime numbers less than or equal to 30.

Solution
•Step 1: The first step is to list all the numbers.
2, 3, 4, 5, 6 ,7 ,8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, and 30.
•Step 2: Write in bold all multiples of 2, except 2 itself.
2, 3, 4, 5, 6 , 7 , 8, 9, 10,11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, and 30.
•Step 3: The next unshaded number is 3. Write its square (32 = 9) in bold.
2, 3, 4, 5, 6 , 7 , 8, 9, 10,11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, and 30.
•Step 4: Now the third unshaded number is 5. Write its square 52=25 in bold.
2, 3, 4, 5, 6 , 7 , 8, 9, 10,11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, and 30.
•Step 5: The fourth unshaded number is 7 and more than the square root of 30.
Therefore, there are no multiples of 7 left since they have been eliminated by 2
and 3 as 14, 28, and 21 respectively. The remaining numbers 2, 3, 5, 7, 11, 13,
17, 19, 23, and 29 are prime.
ADT
Abstract Data Types (ADT): Defining ‘What’ not ‘How

Abstract Data Types define the conceptual framework for 'what' needs to be accomplished but
leaves the 'how' of it all up to developers. In this way, ADTs are very much like upper
management—complete with a lack of regard for your personal time.
Characteristics of ADTs
• Encapsulates a Data Type and set of operations to manipulate the Type
• Operations are only defined by inputs and outputs
• Operation details are hidden from the user through encapsulation
• Theoretical in nature
• Define what is getting done not how it is getting done
• Allows internal implementation details to change without
ADT operations
Recursion and Iteration
• Recursion is defined as a process in which a function calls itself repeatedly.
Recursion uses a selection structure. If the recursion step does not reduce the
problem in a manner that converges on some condition, called base condition,
then an infinite recursion occurs. An infinite recursion can crash the system.
Recursion terminates when a base case is recognized.
• Iteration is defined as the repetition of computational or mathematical procedures
that continues until the controlling condition becomes false. It uses a
repetition structure. If the loop condition test never becomes false, then an infinite
loop occurs with iteration. This infinite looping uses CPU cycles repeatedly. An
iteration terminates when the loop condition fails. Iteration consumes less memory
but makes the code longer which is difficult to read and write.
Difference between Recursion and Iteration
Recursion Iteration
Recursion uses the selection structure. Iteration uses the repetition structure.

Infinite recursion occurs if the step in recursion An infinite loop occurs when the condition in the
doesn't reduce the problem to a smaller problem. It loop doesn't become False ever.
also becomes infinite recursion if it doesn't convert
on a specific condition. This specific condition is
known as the base case.

The system crashes when infinite recursion is Iteration uses the CPU cycles again and again when
encountered. an infinite loop occurs.

Recursion terminates when the base case is met. Iteration terminates when the condition in the loop
fails.
Recursion is slower than iteration since it has the Iteration is quick in comparison to recursion. It
overhead of maintaining and updating the stack. doesn't utilize the stack.

Recursion uses more memory in comparison to Iteration uses less memory in comparison to
iteration. recursion.
Recursion reduces the size of the code. Iteration increases the size of the code.
Recursive Fibonacci
A Fibonacci sequence is the integer sequence of 0, 1, 1, 2, 3, 5, 8....
The first two terms are 0 and 1. All other terms are obtained by adding the preceding
two terms.This means to say the nth term is the sum of (n-1)th and (n-2)th term.
# Python program to display the Fibonacci sequence

def recur_fibo(n):
if n <= 1:
return n
else:
return(recur_fibo(n-1) + recur_fibo(n-2))

nterms = 10

# check if the number of terms is valid


if nterms <= 0:
print("Plese enter a positive integer")
else:
print("Fibonacci sequence:")
for i in range(nterms):
print(recur_fibo(i))
Tower of Hanoi
Tower of Hanoi is a mathematical puzzle where we have three rods and n disks. The
objective of the puzzle is to move the entire stack to another rod, obeying the
following simple rules:
1) Only one disk can be moved at a time.
2) Each move consists of taking the upper disk from one of the stacks and placing it on
top of another stack i.e. a disk can only be moved if it is the uppermost disk on a
stack.
3) No disk may be placed on top of a smaller disk.
Note: Transferring the top n-1 disks from the source rod to the Auxiliary rod can again
be thought of as a fresh problem and can be solved in the same manner.
Tower of Hanoi
Tower of Hanoi
def TowerOfHanoi(n , source, destination, auxiliary):
if n==1:
print ("Move disk 1 from source",source,"to
destination",destination)
return
TowerOfHanoi(n-1, source, auxiliary, destination)
print ("Move disk",n,"from source",source,"to
destination",destination)
TowerOfHanoi(n-1, auxiliary, destination, source)

# Driver code
n=4
TowerOfHanoi(n,'A','B','C')
# A, C, B are the name of rods
Searching algorithm
What is Searching Algorithm?
Searching Algorithms are designed to check for an element or retrieve an element from any data
structure where it is stored.

Based on the type of search operation, these algorithms are generally classified into two categories:
1. Sequential Search: In this, the list or array is traversed sequentially and every element is checked.
For example Linear Search.
Linear Search to find the element “20” in a given list of numbers
Code for liner search
def linear_search(values, search_for):
search_at = 0
search_res = False # Match the value
with each data element while
search_at < len(values) and search_res
is False: if values[search_at] ==
search_for: search_res = True else:
search_at = search_at + 1 return
search_res l = [64, 34, 25, 12, 22, 11,
90] print(linear_search(l, 12))
print(linear_search(l, 91))
Time complexity
Time Complexity Analysis
The Best Case: occurs when the target element is the first element of the array. The number
of comparisons, in this case, is 1. So, the time complexity is O(1).

The Average Case: The target element will be somewhere in the middle of the array. The
number of comparisons, in this case, will be N/2. So, the time complexity will be O(N) (the
constant being ignored).

The Worst Case occurs when the target element is the last element in the array or not in the
array. In this case, we have to traverse the entire array, so the number of comparisons will be
N. So, the time complexity will be O(N).
Binary search
2. Interval Search: These algorithms are specifically designed to search sorted data
structures. These types of searching algorithms are much more efficient than Linear Search
as they repeatedly target the center of the search structure and divide the search space in
half. For Example Binary Search.
Binary Search to find the element “23” in a given list of numbers
Time complexity
Time Complexity Analysis
The Best Case occurs when the target element is the middle element of the array. The
number of comparisons, in this case, is 1. So, the time complexity is O(1).

The Average Case: The target element will be somewhere in the array. So, the time
complexity will be O(logN).

The Worst Case occurs when the target element is not in the list or it is away from the
middle element. So, the time complexity will be O(logN).
Code for binary search
def search(nums, target):
start = 0
end = len(nums)-1
while start <= end:
mid = start + (end-start)//2
if nums[mid] > target:
end = mid-1
elif nums[mid] < target:
start = mid+1
else:
return mid
return -1
if __name__ == '__main__’:
nums = [2, 12, 15, 17, 27, 29, 45]
target = 17
print(search(nums, target))
Merge Sort
Merge Sort is one of the most popular sorting algorithms that is based
on the principle of Divide and Conquer Algorithm.
Here, a problem is divided into multiple sub-problems. Each sub-
problem is solved individually. Finally, sub-problems are combined to
form the final solution.
Algorithm
1.def merge_sort(array, left_index, right_index):
2. if left_index >= right_index:
3. return middle = (left_index + right_index)//2
4. merge_sort(array, left_index, middle)
5. merge_sort(array, middle + 1, right_index)
6. merge(array, left_index, right_index, middle)
def mergeSort(arr):
if len(arr) > 1:

# Create sub_array2 ← A[start..mid] and sub_array2 ← A[mid+1..end]


mid = len(arr)//2
sub_array1 = arr[:mid]
sub_array2 = arr[mid:]

# Sort the two halves


mergeSort(sub_array1)
mergeSort(sub_array2)

# Initial values for pointers that we use to keep track of where we are in each array
i= j=k =0

# Until we reach the end of either start or end, pick larger among
# elements start and end and place them in the correct position in the sorted array
while i < len(sub_array1) and j < len(sub_array2):
if sub_array1[i] < sub_array2[j]:
arr[k] = sub_array1[i]
i += 1
else:
arr[k] = sub_array2[j]
j += 1
k += 1

# When all elements are traversed in either arr1 or arr2,


# pick up the remaining elements and put in sorted array
while i < len(sub_array1):
arr[k] = sub_array1[i]
i += 1
k += 1

while j < len(sub_array2):


arr[k] = sub_array2[j]
j += 1
k += 1

arr = [10, 9, 2, 4, 6, 13]


Selection Sort
The selection sort algorithm sorts an array by repeatedly finding the minimum element
(considering ascending order) from the unsorted part and putting it at the beginning.
The algorithm maintains two subarrays in a given array.
1) The subarray which is already sorted.
2) Remaining subarray which is unsorted. In every iteration of the selection sort, the
minimum element (considering ascending order) from the unsorted subarray is picked
and moved to the sorted subarray.
Algorithm
1.selection_sort(array)
2. repeat (0, length - 1) times
3. set the first unsorted element as the minimum
4. for each of the unsorted elements
5. if element < currentMinimum
6. set element as new minimum
7. swap minimum with first unsorted position
8.end selection_sort
# Selection sort in Python
# time complexity O(n*n)
#sorting by finding min_index
def selectionSort(array, size):

for ind in range(size):


min_index = ind

for j in range(ind + 1, size):


# select the minimum element in every iteration
if array[j] < array[min_index]:
min_index = j
# swapping the elements to sort the array
(array[ind], array[min_index]) = (array[min_index], array[ind])

arr = [-2, 45, 0, 11, -9,88,-97,-202,747]


size = len(arr)
selectionSort(arr, size)
print('The array after sorting in Ascending Order by selection sort is:')
print(arr)

Time Complexity: O(n2).


Auxiliary Space: O(1).
Merge List
A list is a data structure in Python that contains a sequence of elements. We can have
many lists in our code, which sometimes we may need to merge, join, or concatenate.

• merge two lists in Python through append()


• merge two lists in Python using the + operator
• merge two lists in Python using the List comprehension
• extend() method
1. Using append() function
• The append() method in Python adds a single item to the existing list.
• It doesn't return a new list of items. Instead, it modifies the original list by adding
the item to the end of the list.
Append method
# python program to demonstrate merging
# of lists using python
def append_lists():
#list 1
ls1 = [1,2,3,4]
#list 2
ls2 = [5,6,7,8]

#iterating over list2


for i in ls2:
#appending in list1
ls1.append(i)
print(ls1)

#function call
append_lists()
‘+’ Operator
2. Using the '+' Operator

The '+' operator is a multipurpose operator, which we can use for arithmetic
calculations and for merging purposes, strings, lists, etc.

#merge lists Using the '+' operator


def merge():
#list 1
ls1 = [15,20,35,40]
#list 2
ls2 = [99,44,13]
#merging using '+' operator
ls = ls1 + ls2
print(ls)

#function call
merge()
List comprehension
3. Using List Comprehension
• List comprehension offers a shorter and crisper syntax when we want to create a
new list based on the values of an existing list.
• It may also be called an alternative to the loop method.

def list_comprehension():
num1=[1,2,3]
num2=[4,5,6]
#using list comprehension
num3=[x for n in (num1,num2) for x in n]
print(num3)
#function call
list_comprehension()
Extend Method
4. Using the extend() method
• The extend() method adds all the elements of an iterable (list, tuple, string, etc.) to
the end of the list.
• It updates the original list itself. Hence its return type is None.
• It can be used to merge two lists in Python.

def extend_lists():
#list 1
ls1 = [11,19,25,40]
#list 2
ls2 = [31,84,13]
ls1.extend(ls2)
print(ls1)
#function call
extend_lists()
High Order Sort(Function)
A function in Python with another function as an argument or returns a
function as output is called the High order function. Let’s see the
properties −
• A function is an instance of the Object type.
• HOF can store the function in a variable.
• HOF can pass the function as a parameter to another function.
• HOF can return the function from a function.
• HOF can store them in data structures such as hash tables, lists, …
Functions as objects
# Python program to illustrate functions
# can be treated as objects
def shout(text):
return text.upper()

print(shout('Hello'))

# Assigning function to a variable


yell = shout

print(yell('Hello'))
Passing Function as an argument to other function
# Python program to illustrate functions
# can be passed as arguments to other functions
def shout(text):
return text.upper()

def whisper(text):
return text.lower()

def greet(func):
# storing the function in a variable
greeting = func("Hi, I am created by a function \
passed as an argument.")
print(greeting)

greet(shout)
greet(whisper)
Output:
HI, I AM CREATED BY A FUNCTION PASSED AS AN ARGUMENT. hi, i am
created by a function passed as an argument.
Returning function
As functions are objects, we can also return a function from another
function.
# Python program to illustrate functions
# Functions can return another function

def create_adder(x):
def adder(y):
return x + y

return adder

add_15 = create_adder(15)

print(add_15(10))
Output:
25
Decorators
• Decorators are the most common use of higher-order functions in Python.
• It allows programmers to modify the behavior of a function or class.
• Decorators allow us to wrap another function in order to extend the behavior of the
wrapped function, without permanently modifying it.
• In Decorators, functions are taken as the argument into another function and then
called inside the wrapper function.

Syntax:
@gfg_decorator def hello_decorator(): . . .
Example
# defining a decorator
def hello_decorator(func):

# inner1 is a Wrapper function in


# which the argument is called

# inner function can access the outer local


# functions like in this case "func"
def inner1():
print("Hello, this is before function execution")

# calling the actual function now


# inside the wrapper function.
func()

print("This is after function execution")

return inner1

# defining a function, to be called inside wrapper


def function_to_be_used():
print("This is inside the function !!")

# passing 'function_to_be_used' inside the


# decorator to control its behavior
function_to_be_used = hello_decorator(function_to_be_used)

# calling the function


function_to_be_used()
Built-in Functions
We have some built-in higher-order functions in Python.
1. Map Function
Syntax:- map (function, sequence)
It takes a function and sequence as the arguments and then returns a list after applying
the function to each sequence’s items.

#function for performing the multiplication operation


def multiply(n):
#retuning the values
return n*n
#driver code to test the program
num = (10,15,78,25)
#map function(function, sequence/iterable)
result = map(multiply, num)
#returning the result in a list
print(list(result))
Output : [100, 225, 6084, 625]
Filter function
2. Filter function
Syntax:- filter (function, sequence/iterable)
The filter takes two parameters, the first one is a function and the second one is a
sequence.
Then it returns an iterator that passed through a function test for those elements
function returns True.
Let us consider an example, suppose we want to filter out those numbers which are
greater than 50 from a given list of numbers.
#driver code to test the program
numbers = [55, 92, 27, 48, 34, 62, 71, 18, 28, 43]
#function to check the numbers whether they are greater than 50 or not
def numCheck(n):
if n < 50:
return False
else:
return True
#passing through the filter function
result = filter(numCheck, numbers)
#displaying the result
for n in result:
print(n)
Output : 55 92 62 71
Sorted Function
3. Sorted Function
The sorted function simply sorts a given sequence in a specific
order. (either in ascending order or in descending order)
Syntax:- sorted (sequence, key (optional), reverse(optional))
Note:- The difference is that the sort() function doesn’t return any
value but in the case of the sorted() function, it returns an iterable
list.
#declaring string
str = "codespeedy“
#calling sorted function
result = sorted(str) # sorting string
#displaying result
print(result)
Reduce Function
4. Reduce Function
Syntax:- reduce (function, sequence/iterable)
It takes a sequence/iterable of input data then applies it to the
function provided and gives a single result.

#import the reduce function from functools module


from functools import reduce
#function to divide two numbers
def addition(a,b):
return a+b
#taking input
n=map(int, input("Enter the numbers you want to add: ").split())
#reduce function
reduce(addition,n)

You might also like