Unit 5
Unit 5
Unit 5
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
# 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 search(a, l, x):
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
def merge_sort(array, left_index, right_index):
if left_index >= right_index:
return middle = (left_index + right_index)//2
merge_sort(array, left_index, middle)
merge_sort(array, middle + 1, right_index)
merge(array, left_index, right_index, middle)
def mergeSort(arr):
if len(arr) > 1:
# 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
#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.
#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'))
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):
return inner1