Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
27 views

Data Structures and Algorithms PDF

Ds

Uploaded by

maileshsajeesh06
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
27 views

Data Structures and Algorithms PDF

Ds

Uploaded by

maileshsajeesh06
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 32

Data Structures

UNIT 1

Abstract Data Types (ADTs) – ADTs and classes – introduction to OOP – classes in Python – inheritance
– namespaces – shallow and deep copying. Introduction to analysis of algorithms – asymptotic notations
– recursion – analyzing recursive algorithms

UNIT 2

Linear Structures- List ADT – array-based implementations – linked list implementations – singly linked
lists – circularly linked lists – doubly linked lists – applications of lists – Stack ADT – Queue ADT –
double ended queues

UNIT 3

Sorting and Searching-Bubble sort – selection sort – insertion sort – merge sort – quick sort – linear
search – binary search – hashing – hash functions – collision handling – load factors, rehashing, and
efficiency 15

UNIT 4

Tree Structures - Tree ADT – Binary Tree ADT – tree traversals – binary search trees – AVL trees – heaps
– multi-way search trees. 1

UNIT 5

Graph Structures- Graph ADT – representations of graph – graph traversals – DAG – topological ordering
– shortest paths – minimum spanning trees.

Textbooks

1.Ellis Horowitz, Sartaj Shani, Data Structures, Galgotia Publication


2. Ellis Horowitz, Sartaj Shani, Sanguthevar Rajasekaran, Computer Algorithms, Galgotia Publication.

3. Michael T. Goodrich, Roberto Tamassia, and Michael H. Goldwasser, ―Data Structures & Algorithms
in Python‖, John Wiley & Sons Inc., 2013

4. Lee, Kent D., Hubbard, Steve, ―Data Structures and Algorithms with Python‖ Springer Edition 2015

5. Aho, Hopcroft, and Ullman, ―Data Structures and Algorithms‖, Pearson Education, 1983
Reference Books

1.Jean-Paul, Tremblay & Paul G .Sorenson , An Introduction to Data structures with Applications Tata
McGraw Hill Company 2008, 2ndEdition.

2. Samanta.D , Classic Data Structure Prentice Hall of India Pvt Ltd 2007, 9th Edition

3. Seymour Lipschutz, Data Structures McGraw Hill Publications, 2014, 1st Edition

4. Rance D. Necaise, ―Data Structures and Algorithms Using Python‖, John Wiley & Sons, 2011

5. Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein, ―Introduction to
Algorithms", Second Edition, McGraw Hill, 2002.

Web Resources

1. https://www.geeksforgeeks.org/data-structures/

2. https://www.tutorialspoint.com/data_structures_algorithms/index.htm

3. https://techdevguide.withgoogle.com/paths/data-structures-and-algorithms/

4. https://www.freecodecamp.org/news/learn-data-structures-and-algorithms/

5. https://www.worldscientific.com/worldscibooks/10.1142/5256#t=aboutBook
1.INDRODUCTION:
What is Data Structure:
A data structure is a storage that is used to store and organize data. It is a way of arranging
data on a computer so that it can be accessed and updated efficiently.

 A data structure is not only used for organizing the data. It is also used for processing, retrieving,
and storing data.
 There are different basic and advanced types of data structures that are used in almost every
program or software system that has been developed.
 So we must have good knowledge about data structures.

 Linear data structure: Data structure in which data elements are arranged sequentially or
linearly, where each element is attached to its previous and next adjacent elements, is
called a linear data structure.
Examples of linear data structures are array, stack, queue, linked list, etc.
 Static data structure: Static data structure has a fixed memory size. It is easier to
access the elements in a static data structure.
An example of this data structure is an array.
 Dynamic data structure: In dynamic data structure, the size is not fixed. It can be
randomly updated during the runtime which may be considered efficient concerning
the memory (space) complexity of the code.
Examples of this data structure are queue, stack, etc.
 Non-linear data structure: Data structures where data elements are not placed
sequentially or linearly are called non-linear data structures. In a non-linear data structure,
we can’t traverse all the elements in a single run only.
Examples of non-linear data structures are trees and graphs.

1.1Abstract Data Types or Classes:

 Abstract Data type (ADT) is a type (or class) for objects whose behavior
is defined by a set of values and a set of operations.
 The definition of ADT only mentions what operations are to be performed
but not how these operations will be implemented.
 It does not specify how data will be organized in memory and what
algorithms will be used for implementing the operations. It is called
“abstract” because it gives an implementation-independent view.
The process of providing only the essentials and hiding the details is known as
abstraction.

The user of data type does not need to know how that data type is
implemented, for example, we have been using Primitive values like int, float,
char data types only with the knowledge that these data type can operate and
be performed on without any idea of how they are implemented.
So a user only needs to know what a data type can do, but not how it will be
implemented. Think of ADT as a black box which hides the inner structure and
design of the data type. Now we’ll define three ADTs
namely List ADT, Stack ADT, Queue ADT.
1. List ADT
Vies of list

 The data is generally stored in key sequence in a list which has a head
structure consisting of count, pointers and address of compare
function needed to compare the data in the list.
 The data node contains the pointer to a data structure and a self-referential
pointer which points to the next node in the list.
 The List ADT Functions is given below:
 get() – Return an element from the list at any given position.
 insert() – Insert an element at any position of the list.
 remove() – Remove the first occurrence of any element from a non-empty
list.
 removeAt() – Remove the element at a specified location from a non-empty
list.
 replace() – Replace an element at any position by another element.
 size() – Return the number of elements in the list.
 isEmpty() – Return true if the list is empty, otherwise return false.
 isFull() – Return true if the list is full, otherwise return false.
2. Stack ADT

View of stack

 In Stack ADT Implementation instead of data being stored in each node, the
pointer to data is stored.
 The program allocates memory for the data and address is passed to the
stack ADT.
 The head node and the data nodes are encapsulated in the ADT. The calling
function can only see the pointer to the stack.
 The stack head structure also contains a pointer to top and count of number
of entries currently in stack.
 push() – Insert an element at one end of the stack called top.
 pop() – Remove and return the element at the top of the stack, if it is not
empty.
 peek() – Return the element at the top of the stack without removing it, if the
stack is not empty.
 size() – Return the number of elements in the stack.
 isEmpty() – Return true if the stack is empty, otherwise return false.
 isFull() – Return true if the stack is full, otherwise return false.
3. Queue ADT

View of Queue

 The queue abstract data type (ADT) follows the basic design of the stack
abstract data type.
 Each node contains a void pointer to the data and the link pointer to the next
element in the queue. The program’s responsibility is to allocate memory for
storing the data.
 enqueue() – Insert an element at the end of the queue.
 dequeue() – Remove and return the first element of the queue, if the queue
is not empty.
 peek() – Return the element of the queue without removing it, if the queue is
not empty.
 size() – Return the number of elements in the queue.
 isEmpty() – Return true if the queue is empty, otherwise return false.
 isFull() – Return true if the queue is full, otherwise return false.
Features of ADT:

Abstract data types (ADTs) are a way of encapsulating data and operations on that
data into a single unit. Some of the key features of ADTs include:

 Abstraction: The user does not need to know the implementation of the data
structure only essentials are provided.
 Better Conceptualization: ADT gives us a better conceptualization of the real
world.
 Robust: The program is robust and has the ability to catch errors.
 Encapsulation: ADTs hide the internal details of the data and provide a public
interface for users to interact with the data. This allows for easier maintenance and
modification of the data structure.
 Data Abstraction: ADTs provide a level of abstraction from the implementation
details of the data. Users only need to know the operations that can be performed on
the data, not how those operations are implemented.
 Data Structure Independence: ADTs can be implemented using different data
structures, such as arrays or linked lists, without affecting the functionality of the
ADT.
 Information Hiding: ADTs can protect the integrity of the data by allowing access
only to authorized users and operations. This helps prevent errors and misuse of the
data.
 Modularity: ADTs can be combined with other ADTs to form larger, more complex
data structures. This allows for greater flexibility and modularity in programming.
Overall, ADTs provide a powerful tool for organizing and manipulating data in a
structured and efficient manner.
Abstract data types (ADTs) have several advantages and disadvantages that should be
considered when deciding to use them in software development. Here are some of the
main advantages and disadvantages of using ADTs:

Advantages:

 Encapsulation: ADTs provide a way to encapsulate data and operations into a


single unit, making it easier to manage and modify the data structure.
 Abstraction: ADTs allow users to work with data structures without having to
know the implementation details, which can simplify programming and reduce
errors.
 Data Structure Independence: ADTs can be implemented using different data
structures, which can make it easier to adapt to changing needs and requirements.
 Information Hiding: ADTs can protect the integrity of data by controlling access
and preventing unauthorized modifications.
 Modularity: ADTs can be combined with other ADTs to form more complex data
structures, which can increase flexibility and modularity in programming.

Disadvantages:

 Overhead: Implementing ADTs can add overhead in terms of memory and


processing, which can affect performance.
 Complexity: ADTs can be complex to implement, especially for large and complex
data structures.
 Learning Curve: Using ADTs requires knowledge of their implementation and
usage, which can take time and effort to learn.
 Limited Flexibility: Some ADTs may be limited in their functionality or may not
be suitable for all types of data structures.
 Cost: Implementing ADTs may require additional resources and investment, which
can increase the cost of development.

1.2 Introduction to OOP
Python OOPs Concepts:

 In Python, object-oriented Programming (OOPs) is a programming


paradigm that uses objects and classes in programming.
 It aims to implement real-world entities like inheritance, polymorphisms,
encapsulation, etc. in the programming.
 The main concept of OOPs is to bind the data and the functions that work
on that together as a single unit so that no other part of the code can
access this data.
OOPs Concepts in Python
 Class
 Objects
 Polymorphism
 Encapsulation
 Inheritance
 Data Abstraction

OOPs

1.3 Python Class


 A class is a collection of objects. A class contains the blueprints or
the prototype from which the objects are being created.
 It is a logical entity that contains some attributes and methods.
 To understand the need for creating a class let’s consider an
example, let’s say you wanted to track the number of dogs that may
have different attributes like breed, and age.
If a list is used, the first element could be the dog’s breed while the second
element could represent its age. Let’s suppose there are 100 different dogs,
then how would you know which element is supposed to be which? What if you
wanted to add other properties to these dogs? This lacks organization and it’s
the exact need for classes.
Some points on Python class:
 Classes are created by keyword class.
 Attributes are the variables that belong to a class.
 Attributes are always public and can be accessed using the dot (.) operator.
Eg.: Myclass.Myattribute

Class Definition Syntax:


class ClassName:
# Statement-1
.
.
.
# Statement-N
Creating an Empty Class in Python

In the above example, we have created a class named Dog using the class
keyword.

 Python

# Python3 program to

# demonstrate defining

# a class

class Dog:

pass

1.3.1 Python Inheritance


Inheritance is the capability of one class to derive or inherit the properties from
another class. The class that derives properties is called the derived class or
child class and the class from which the properties are being derived is called
the base class or parent class. The benefits of inheritance are:
 It represents real-world relationships well.
 It provides the reusability of a code. We don’t have to write the same code
again and again. Also, it allows us to add more features to a class without
modifying it.
 It is transitive in nature, which means that if class B inherits from another
class A, then all the subclasses of B would automatically inherit from class
A.
Types of Inheritance
 Single Inheritance: Single-level inheritance enables a derived class to
inherit characteristics from a single-parent class.
 Multilevel Inheritance: Multi-level inheritance enables a derived class to
inherit properties from an immediate parent class which in turn inherits
properties from his parent class.
 Hierarchical Inheritance: Hierarchical-level inheritance enables more than
one derived class to inherit properties from a parent class.
 Multiple Inheritance: Multiple-level inheritance enables one derived class to
inherit properties from more than one base class.

Inheritance in Python

 In the above article, we have created two classes i.e. Person (parent class) and
Employee (Child Class).
 The Employee class inherits from the Person class. We can use the methods of
the person class through the employee class as seen in the display function in the
above code.
 A child class can also modify the behavior of the parent class as seen through the
details() method.

 Python3

# Python code to demonstrate how parent constructors

# are called.

# parent class

class Person(object):

# __init__ is known as the constructor

def __init__(self, name, idnumber):


self.name = name

self.idnumber = idnumber

def display(self):

print(self.name)

print(self.idnumber)

def details(self):

print("My name is {}".format(self.name))

print("IdNumber: {}".format(self.idnumber))

# child class

class Employee(Person):

def __init__(self, name, idnumber, salary, post):

self.salary = salary

self.post = post

# invoking the __init__ of the parent class

Person.__init__(self, name, idnumber)


def details(self):

print("My name is {}".format(self.name))

print("IdNumber: {}".format(self.idnumber))

print("Post: {}".format(self.post))

# creation of an object variable or an instance

a = Employee('Rahul', 886012, 200000, "Intern")

# calling a function of the class Person using

# its instance

a.display()

a.details()

Output

Rahul
886012
My name is Rahul
IdNumber: 886012
Post: Intern
1.3.2 NAMESPACESES IN PYTHON:

What is namespace:
 A namespace is a system that has a unique name for each and every
object in Python.
 An object might be a variable or a method. Python itself maintains a
namespace in the form of a Python dictionary.
 Let’s go through an example, a directory-file system structure in
computers.
 Needless to say, that one can have multiple directories having a file with
the same name inside every directory.
 But one can get directed to the file, one wishes, just by specifying the
absolute path to the file.
 Real-time example, the role of a namespace is like a surname. One might
not find a single “Alice” in the class there might be multiple “Alice” but
when you particularly ask for “Alice Lee” or “Alice Clark” (with a surname),
there will be only one (time being don’t think of both first name and
surname are same for multiple students).
 On similar lines, the Python interpreter understands what exact method or
variable one is trying to point to in the code, depending upon the
namespace.
 So, the division of the word itself gives a little more information.
Its Name (which means name, a unique identifier) + Space(which talks
something related to scope).
 Here, a name might be of any Python method or variable and space
depends upon the location from where is trying to access a variable or a
method.

Types of namespaces :

 When Python interpreter runs solely without any user-defined modules,


methods, classes, etc.
 Some functions like print(), id() are always present, these are built-in
namespaces. When a user creates a module, a global namespace gets
created, later the creation of local functions creates the local namespace.
 The built-in namespace encompasses the global namespace and the
global namespace encompasses the local namespace.
The lifetime of a namespace :

A lifetime of a namespace depends upon the scope of objects, if the scope of


an object ends, the lifetime of that namespace comes to an end.
Hence, it is not possible to access the inner namespace’s objects from an outer
namespace.

Example:
 Python3

# var1 is in the global namespace

var1 = 5

def some_func():

# var2 is in the local namespace

var2 = 6
def some_inner_func():

# var3 is in the nested local

# namespace

var3 = 7

As shown in the following figure, the same object name can be present in
multiple namespaces as isolation between the same name is maintained by
their namespace.

But in some cases, one might be interested in updating or processing global


variables only,
as shown in the following example, one should mark it explicitly as global and
the update or process.
Note that the line “count = count +1” references the global variable and
therefore uses the global variable, but compare this to the same line written
“count = 1”.
Then the line “global count” is absolutely needed according to scope rules.
 Python3

# Python program processing

# global variable

count = 5

def some_method():

global count

count = count + 1

print(count)

some_method()

Output:
6

1.3.4 Shallow and Deep copy of a class:

Shallow Copy:
 Shallow repetition is quicker. However, it’s “lazy” it handles pointers and
references. Rather than creating a contemporary copy of the particular
knowledge the pointer points to, it simply copies over the pointer price.
 So, each of the first and therefore the copy can have pointers that reference
constant underlying knowledge.

Deep Copy:
 Deep repetition truly clones the underlying data. It is not shared between the
first and therefore the copy.
Difference between Shallow and Deep copy of a class

Shallow Copy Deep Copy

Shallow Copy stores the references of objects to


Deep copy stores copies of the object’s value.
the original memory address.

Shallow Copy reflects changes made to the Deep copy doesn’t reflect changes made to the
new/copied object in the original object. new/copied object in the original object.

Shallow Copy stores the copy of the original Deep copy stores the copy of the original object
object and points the references to the objects. and recursively copies the objects as well.

A shallow copy is faster. Deep copy is comparatively slower.

1.4 INTRODUCTION TO ANALYSIS OF ALGORITHM:


 A lay man perceives that a computer perform anything and everything. It is very difficult to
ensure that it is not really the computer but the man behind computer who does the whole
thing.
 For example users just enter their queries and can get information as he/she desire. A common
man rarely understands that a man made procedure called search has done the entire task and
the only support provided by the computer is the execution speed and organized storage
information.
 ‘Algorithm’ is defined after the name of Abu Ja’ far Muhammad ibn Musa Al-Khwarizmi, Ninth
century , al-jabr means “restoring” referring to the process of moving a subtracted quantity to
other side of an equation; al-muqabala is “comparing” and refers to subtracting equal
quantities from both sides of an equation.

Definition of Algorithm

 An algorithm is a set of rules for carrying out calculation either by hand or on a


machine.
 An algorithm is a sequence of computational steps that transform the input into the
output.
 An algorithm is a sequence of operations performed on data that have to be organized
in the data structures.
 A finite set of instruction that specify a sequence of operations to be carried out in
order to solve a specific problem or class of problems is called an algorithm.
 An algorithm is an abstraction of a program to be executed on a physical machine
(model computation).
 An algorithm is defined as set of instructions to perform a specific task within finite no.
of steps.
 Algorithm is defined as a step by step procedure to perform a specific task within finite
number of steps.
 It can be defined as a sequence of definite and effective instructions, while terminates
with the production of correct output from the given input.
Example of algorithm
Let us assume can common example of ATM withdrawal system .To present the
scenario of a person under goes the following steps.
1. SWAP the card
2. Enter the PIN
3. Put the amount
4. Withdraw amount
5. Check balance

CHARACTERISTICS OF AN ALGORITHM

Every algorithm should have the following five characteristic features:

a) Input

b) Output

c) Finiteness

d) Definiteness
e) Effectiveness

f) Precision

g) Determination

h) Correctness

i) Generality

a) Input

An algorithm may have one or more inputs. The inputs are taken from a specified set of subjects.
The input pattern may be texts, images or any type of files

b) Output :

An algorithm may have one or more outputs. Output is basically a quantity which has a specified
relation with the input

c) Finiteness:

An algorithm should terminate after a countable number of steps. In some cases the repetition of
steps may be larger in number. If a procedure is able to resolve in finite number of execution of steps,
then it is referred to be computational method.

d) Definiteness:

Each step of an algorithm must be precisely defined. The action to be carried out must be on
ambiguously specified for each case. Due to the lack of understandability one may think that the step
might be lacking definiteness. Therefore in such cases mathematically expressions are written, so that it
resembles the instruction of any computer language.

e) Effectiveness :

An algorithm is generally expected to effective. Means the steps should be sufficiently basic, so that it
may be possible for a man to resolve them.

f) Precision :The steps are precisely stated.

g) Determination: The intermediate results of each step of execution are unique and are determined
only by input and output of the preceding steps.

h) Correctness: Output produced by the algorithm should correct.

i) Generality: Algorithm applies to set of standard inputs.


1.4.1 Asymptotic Notations:
.Asymptotic Notations are programming languages that allow you to analyze an
algorithm’s running time by identifying its behavior as its input size grows.
 This is also referred to as an algorithm’s growth rate.
 You can’t compare two algorithm’s head to head.
 You compare space and time complexity using asymptotic analysis.
 It compares two algorithms based on changes in their performance as the
input size is increased or decreased.

There are mainly three asymptotic notations:


1. Big-O Notation (O-notation)
2. Omega Notation (Ω-notation)
3. Theta Notation (Θ-notation)

1. Theta Notation (Θ-Notation):


 Theta notation encloses the function from above and below. Since it
represents the upper and the lower bound of the running time of an
algorithm, it is used for analyzing the average-case complexity of an
algorithm.
 Theta (Average Case) You add the running times for each possible input
combination and take the average in the average case.
Let g and f be the function from the set of natural numbers to its
Theta notation
function f is said to be Θ(g), if there are constants c1, c2 > 0 and a natural
number n0 such that c1* g(n) ≤ f(n) ≤ c2 * g(n) for all n ≥ n0

Mathematical Representation of Theta notation:


Θ (g(n)) = {f(n): there exist positive constants c1, c2 and n0 such that 0 ≤ c1 *
g(n) ≤ f(n) ≤ c2 * g(n) for all n ≥ n0}

Note: Θ(g) is a set


The above expression can be described as if f(n) is theta of g(n), then the value
f(n) is always between c1 * g(n) and c2 * g(n) for large values of n (n ≥ n0). The
definition of theta also requires that f(n) must be non-negative for values of n
greater than n0.
The execution time serves as both a lower and upper bound on the
algorithm’s time complexity.
It exist as both, most, and least boundaries for a given input value.
 A simple way to get the Theta notation of an expression is to drop low-
order terms and ignore leading constants.
 For example, Consider the expression 3n3 + 6n2 + 6000 = Θ(n3), the
dropping lower order terms is always fine because there will always be a
number(n) after which Θ(n3) has higher values than Θ(n2) irrespective of
the constants involved. For a given function g(n), we denote Θ(g(n)) is
following set of functions.
Examples :
{ 100 , log (2000) , 10^4 } belongs to Θ(1)
{ (n/4) , (2n+3) , (n/100 + log(n)) } belongs to Θ(n)
{ (n^2+n) , (2n^2) , (n^2+log(n))} belongs to Θ( n2)
Note: Θ provides exact bounds.
2. Big-O Notation (O-notation):
Big-O notation represents the upper bound of the running time of an algorithm.
Therefore, it gives the worst-case complexity of an algorithm.
.It is the most widely used notation for Asymptotic analysis.
.It specifies the upper bound of a function.
.The maximum time required by an algorithm or the worst-case time complexity.
.It returns the highest possible output value(big-O) for a given input.
.Big-Oh(Worst Case) It is defined as the condition that allows an algorithm to
complete statement execution in the longest amount of time possible.

 If f(n) describes the running time of an algorithm, f(n) is O(g(n)) if there


exist a positive constant C and n0 such that, 0 ≤ f(n) ≤ cg(n) for all n ≥ n0
It returns the highest possible output value (big-O)for a given input.
The execution time serves as an upper bound on the algorithm’s time
complexity.

Mathematical Representation of Big-O Notation:


O(g(n)) = { f(n): there exist positive constants c and n0 such that 0 ≤ f(n) ≤ cg(n)
for all n ≥ n0 }
For example, Consider the case of Insertion Sort. It takes linear time in the best
case and quadratic time in the worst case. We can safely say that the time
complexity of the Insertion sort is O(n2).
Note: O(n2) also covers linear time.
If we use Θ notation to represent the time complexity of Insertion sort, we have
to use two statements for best and worst cases:
 The worst-case time complexity of Insertion Sort is Θ(n2).
 The best case time complexity of Insertion Sort is Θ(n).
The Big-O notation is useful when we only have an upper bound on the time
complexity of an algorithm. Many times we easily find an upper bound by simply
looking at the algorithm.

Examples :
{ 100 , log (2000) , 10^4 } belongs to O(1)
U { (n/4) , (2n+3) , (n/100 + log(n)) } belongs to O(n)
U { (n^2+n) , (2n^2) , (n^2+log(n))} belongs to O( n^2)
Note: Here, U represents union, we can write it in these manner because O
provides exact or upper bounds .

3. Omega Notation (Ω-Notation):


Omega notation represents the lower bound of the running time of an algorithm.
Thus, it provides the best case complexity of an algorithm.
 The execution time serves as a lower bound on the algorithm’s time
complexity.
 It is defined as the condition that allows an algorithm to complete
statement execution in the shortest amount of time.

Let g and f be the function from the set of natural numbers to itself. The function
f is said to be Ω(g), if there is a constant c > 0 and a natural number n0 such
that c*g(n) ≤ f(n) for all n ≥ n0
Mathematical Representation of Omega notation :
Ω(g(n)) = { f(n): there exist positive constants c and n0 such that 0 ≤ cg(n) ≤ f(n)
for all n ≥ n0 }
Let us consider the same Insertion sort example here. The time complexity of
Insertion Sort can be written as Ω(n), but it is not very useful information about
insertion sort, as we are generally interested in worst-case and sometimes in
the average case.
Examples :
{ (n^2+n) , (2n^2) , (n^2+log(n))} belongs to Ω( n^2)
U { (n/4) , (2n+3) , (n/100 + log(n)) } belongs to Ω(n)
U { 100 , log (2000) , 10^4 } belongs to Ω(1)
Note: Here, U represents union, we can write it in these manner because Ω
provides exact or lower bounds.
Introduction to Recursion :

What is Recursion?
The process in which a function calls itself directly or indirectly is called
recursion and the corresponding function is called a Recursive function. Using
a recursive algorithm, certain problems can be solved quite easily.

Examples of such problems are Towers of Hanoi


(TOH), Inorder/Preorder/Postorder Tree Traversals, DFS of Graph, etc

Need of Recursion
Recursion is an amazing technique with the help of which we can reduce
the length of our code and make it easier to read and write. It has certain
advantages over the iteration technique which will be discussed later.
A task that can be defined with its similar subtask, recursion is one of the
best solutions for it. For example; The Factorial of a number.
Properties of Recursion:
 Performing the same operations multiple times with different inputs.
 In every step, we try smaller inputs to make the problem smaller.
 Base condition is needed to stop the recursion otherwise infinite loop will
occur

SR
Recursion Iteration
No.

Terminates when the base case Terminates when the condition


1)
becomes true. becomes false.

2) Used with functions. Used with loops.

Every recursive call needs extra space Every iteration does not require any
3)
in the stack memory. extra space.

4) Smaller code size. Larger code size.


Recursion VS Iteration
Now, let’s discuss a few practical problems which can be solved by using
recursion and understand its basic working. For basic understanding please
read the following articles.

Basic understanding of Recursion.


Problem 1: Write a program and recurrence relation to find the Fibonacci series
of n where n>2 .
Mathematical Equation:
n if n == 0, n == 1;

fib(n) = fib(n-1) + fib(n-2) otherwise;

Recurrence Relation:
T(n) = T(n-1) + T(n-2) + O(1)

Recursive program:
Input: n = 5
Output:
Fibonacci series of 5 numbers is : 0 1 1 2 3

ANALYZING RECURSIVE ALGORITHM:


What Is a Recursive Algorithm?
A recursive algorithm calls itself with smaller input values and returns the result for the
current input by carrying out basic operations on the returned value for the smaller input.
Generally, if a problem can be solved by applying solutions to smaller versions of the same
problem, and the smaller versions shrink to readily solvable instances, then the problem can be
solved using a recursive algorithm.
To build a recursive algorithm, you will break the given problem statement into two
parts. The first one is the base case, and the second one is the recursive step.

 Base Case: It is nothing more than the simplest instance of a problem, consisting of a
condition that terminates the recursive function. This base case evaluates the result when a
given condition is met.

 Recursive Step: It computes the result by making recursive calls to the same function, but
with the inputs decreased in size or complexity.

For example, consider this problem statement: Print sum of n natural numbers using
recursion. This statement clarifies that we need to formulate a function that will calculate
the summation of all natural numbers in the range 1 to n. Hence, mathematically you
can represent the function as:

F(n) = 1 + 2 + 3 + 4 + …………..+ (n-2) + (n-1) + n

Different Types of Recursion

There are four different types of recursive algorithms, you will look at them one by one.

 Direct Recursion

A function is called direct recursive if it calls itself in its function body repeatedly. To
better understand this definition, look at the structure of a direct recursive program.

int fun(int z){

fun(z-1); //Recursive call

In this program, you have a method named fun that calls itself again in its function body.
Thus, you can say that it is direct recursive.
 Indirect Recursion

The recursion in which the function calls itself via another function is called indirect
recursion. Now, look at the indirect recursive program structure.

int fun1(int z){ int fun2(int y){

fun2(z-1); fun1(y-2)

} }

In this example, you can see that the function fun1 explicitly calls fun2, which is invoking
fun1 again. Hence, you can say that this is an example of indirect recursion.

 Tailed Recursion

A recursive function is said to be tail-recursive if the recursive call is the last execution
done by the function. Let’s try to understand this definition with the help of an example.

int fun(int z)

printf(“%d”,z);

fun(z-1);

//Recursive call is last executed statement

}
If you observe this program, you can see that the last line ADI will execute for method
fun is a recursive call. And because of that, there is no need to remember any previous
state of the program.

 Non-Tailed Recursion

A recursive function is said to be non-tail recursive if the recursion call is not the last
thing done by the function.

After returning back, there is something left to evaluate. Now, consider this example.

int fun(int z)

fun(z-1);

printf(“%d”,z);

//Recursive call is not the last executed statement

In this function, you can observe that there is another operation after the recursive call.
Hence the ADI will have to memorize the previous state inside this method block. That
is why this program can be considered non-tail recursive.

Moving forward, you will implement a C program that exhibits recursive algorithmic
nature.
Program to Demonstrate Recursion:

You will look at a C program to understand recursion in the case of the sum of n natural
numbers problem.

#include<stdio.h>

int Sum(int n){

if(n==0){

return 0;

int temp = Sum(n-1);

return n + temp;

int main()

int n;

printf("Enter the natural number n to calculate the sum of n numbers: ");

scanf("%d",&n);

printf("%d",Sum(n));

}
Output:

The output for the sum of n natural numbers program is represented in the image below.

IMPOTANT QUESTIONS:

1.Short Notes ADT and its features

2.Explain the Charecteristics of Abstract data types

3.Descibe advantages and disadvantages of ADT

4.Overview the recursion algorithms

5.Breifly explain the OOP concepts in python

6.Difference between shallow and Deep Copying

7.Explain the difference types of recursion algorithms

8.Overview of Asymptotic notations

You might also like