Data Structure Notes in r22
Data Structure Notes in r22
Department of CSE
(Emerging Technologies)
(Data Science, Internet of Things, Cyber Security)
B.TECH(R-22 Regulation)
(II YEAR – I SEM)
(2024-25)
DATA STRUCTURES
(R22A0503)
LECTURE NOTES
Prepared by
Dr.P.Dileep, Professor
MALLA REDDY COLLEGE OF ENGINEERING & TECHNOLOGY
(Autonomous Institution – UGC, Govt. of India)
Recognized under 2(f) and 12(B) of UGC ACT 1956
(Affiliated to JNTUH, Hyderabad, Approved by AICTE-Accredited by NBA & NAAC – ‘A’ Grade - ISO 9001:2015 Certified)
Maisammaguda, Dhulapally (Post Via. Hakimpet), Secunderabad–500100, Telangana State, India
Data Structures
B.Tech – CSE (Emerging Technologies) R-22
Prepared by
V.Bala
Asst.prof.
On
30.07.2022
Updated by
Dr.P.Dileep
Professor
On
31.07.2023
Updated by
V.Bala
Asst.prof.
On
11.07.2024
Data Structures
Department of Computer Science and Engineering
EMERGING TECHNOLOGIES
Vision
“To be at the forefront of Emerging Technologies and to evolve as a Centre of Excellence in Research,
Learning and Consultancy to foster the students into globally competent professionals useful to the
Society.”
Mission
The department of CSE (Emerging Technologies) is committed to:
To offer highest Professional and Academic Standards in terms of Personal growth andsatisfaction.
Make the society as the hub of emerging technologies and thereby capture
opportunities in new age technologies.
To create a benchmark in the areas of Research, Education and Public Outreach.
To provide students a platform where independent learning and scientific study areencouraged
with emphasis on latest engineering techniques.
QUALITY POLICY
To pursue continual improvement of teaching learning process of Undergraduate andPost
Graduate programs in Engineering & Management vigorously.
To provide state of art infrastructure and expertise to impart the quality education andresearch
environment to students for a complete learning experience.
To offer quality relevant and cost effective programmes to produce engineers as per
requirements of the industry need.
3
SYLLABUS
MALLA REDDY COLLEGE OF ENGINEERING AND TECHNOLOGY
II Year B.Tech CSE(DS,CS,IOT) -I SEM L/T/P/C
3-/ -/ -/3
(R22A0503) DATA STRUCTURES
COURSE OBJECTIVES:
This course will enable students to
1. Implement Object Oriented Programming concepts in Python.
2. Understand Lists, Dictionaries and Regular expressions in Python.
3. Understanding how searching and sorting is performed in Python.
4. Understanding how linear and non-linear data structures works.
5. To learn the fundamentals of writing Python scripts.
UNIT – I
Oops Concepts- class, object, constructors, types of variables, types of methods. Inheritance:
single, multiple, multi-level, hierarchical, hybrid, Polymorphism: with functions and objects,
with class methods, with inheritance, Abstraction: abstract classes.
UNIT – II
Searching- Linear Search and Binary Search.
Sorting - Bubble Sort, Selection Sort, Insertion Sort, Merge Sort, Quick Sort.
UNIT -III
Data Structures –Definition, Linear Data Structures, Non-Linear Data Structures,
Stacks - Overview of Stack, Implementation of Stack (List), Applications of Stack
Queues: Overview of Queue, Implementation of Queue (List), Applications of Queues, Priority
Queues
Linked Lists – Implementation of Singly Linked Lists, Doubly Linked Lists, Circular Linked Lists.
Implementation of Stack and Queue using Linked list.
UNIT -IV
Dictionaries: linear list representation, skip list representation, operations - insertion, deletion
and searching. Directed vs Undirected Graphs, Weighted vs Unweighted Graphs,
Representations, Breadth First Search, Depth First Search.
UNIT -V
Trees - Overview of Trees, Tree Terminology, Binary Trees: Introduction, Implementation,
Applications. Tree Traversals
Binary Search Trees: Introduction, Implementation
AVL Trees: Introduction, Rotations, Implementation, B-Trees and B+ Trees.
TEXTBOOKS:
1. Data structures and algorithms in python by Michael T. Goodrich
2. Data Structures and Algorithmic Thinking with Python by Narasimha Karumanchi
REFERENCE BOOKS:
1. Hands-On Data Structures and Algorithms with Python: Write complex and powerful code
using the latest features of Python 3.7, 2nd Edition by Dr. Basant Agarwal, Benjamin Baka.
2. Data Structures and Algorithms with Python by Kent D. Lee and Steve Hubbard.
3. Problem Solving with Algorithms and Data Structures Using Python by Bradley N Miller and
David L.Ranum.
4. Core Python Programming -Second Edition, R. Nageswara Rao, Dreamtech Press
COURSE OUTCOMES:
The students should be able to:
1. Examine Python syntax and semantics and apply Python flow control and functions.
2. Create, run and manipulate Python Programs using core data structures like Lists,
3. Apply Dictionaries and use Regular Expressions.
4. Interpret the concepts of Object-Oriented Programming as used in Python.
INDEX
DICTIONARIES, GRAPHS
4 IV 46 – 63
UNIT – I
1. INTRODUCTION:
Python is a high-level programming language that is translated by the python interpreter. As is
known, an interpreter works by translating line-by-line and executing. It was developed by
Guido-van-rossum in 1990, at the National Research Institute for Mathematics and Computer
Science in Netherlands. Python doesn’t refer to the snake but was named after the famous
British comedy troupe, Monty Python’s Flying Circus.
Python is Interpreted: Python is processed at runtime by the interpreter. You do not needto
compile your program before executing it.
Python is Interactive: we can actually sit at a Python prompt and interact with the interpreter
directly to write our programs.
Python is Object-Oriented: Python supports Object-Oriented style or technique of
programming that encapsulates code within objects.
Application of python used in Search engine. In mission critical projects in Naza, in processing
financial transaction at New york stock Exchange.
The following are some of the features of Python:
Python is an Open Source: It is freely downloadable, from the link “http:// python.org/”
Python is portable: It runs on different operating systems / platforms3
Python has automatic memory management
Python is flexible with both procedural oriented and object oriented programming
Python is easy to learn, read and maintain
Python is Extendable. You can add low-level modules to the Python is Interpreted. These
modules enable programmers to add to or customize their tools to be more efficient.
Python supports GUI applications that can be created and ported to many system calls, libraries
and windows systems, such as Windows MFC, Macintosh, and the X Window system of Unix.
Points to Remember:
Case sensitive : Example - In case of print statement use only lower case and not upper case
Punctuation is not required at end of the statement
In case of string use single or double quotes i.e. ‘ ’ or “ ”
Must use proper indentation.
The following are used Without Indentation
o Special characters like (,),# etc. are used
o () ->Used in opening and closing parameters of functions
o #-> The Pound sign is used to comment a line
2. OOPS CONCEPTS
An object-oriented paradigm is to design the program using classes and objects. The object is
related to real-word entities such as book, house, pencil, etc. The oops concept focuses on
writing the reusable code. It is a widespread technique to solve the problem by creating objects.
The main concept of object-oriented Programming (OOPs) or oops concepts in Python is to bind
the data and the functions that work together as a single unit so that no other part of the code
can access this data which includes Class, Objects, Polymorphism, Encapsulation, Inheritance and
Data Abstraction.
I. 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.
Dept. of CSE(ET) 2
Data Structures A. Y. 2024 - 2025
II. OBJECT:
In object-oriented programming Python, The object is an entity that has a state and behavior
associated with it. It may be any real-world object like a mouse, keyboard, chair, table, pen, etc.
Integers, strings, floating-point numbers, even arrays, and dictionaries, are all objects.
An object consists of:
State: It is represented by the attributes of an object. It also reflects the properties ofan object.
Behavior: It is represented by the methods of an object. It also reflects the response ofan object
to other objects.
Identity: It gives a unique name to an object and enables one object to interact with other
objects.
All classes have a function called init (), which is always executed when the class is being
initiated. Use the init () function to assign values to object properties, or other operations that
are necessary to do when the object is being created:
Create a class named Person, use the init () function to assign values for name and age:
class Person:
def init (self, name, age):
self.name = name
self.age = age
p1 = Person("John", 36)
print(p1.name) print(p1.age)
Note: The init () function is called automatically every time the class is being used to createa
new object.
III. METHOD:
The method is a function that is associated with an object. In Python, a method is not unique to
class instances. Any object type can have methods.
Dept. of CSE(ET) 3
Data Structures A. Y. 2024 - 2025
IV. INHERITANCE:
Inheritance is a way of creating a new class for using details of an existing class without
modifying it. The newly formed class is a derived class (or child class). Similarly, the existing class
is a base class (or parent class).
Inheritance is the most important aspect of object-oriented programming, which simulates the
real-world concept of inheritance. It specifies that the child object acquires all the properties and
behaviors of the parent object. By using inheritance, we can create a class which uses all the
properties and behavior of another 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.
V. POLYMORPHISM:
Polymorphism contains two words "poly" and "morphs". Poly means many, and morph means
shape. By polymorphism, we understand that one task can be performed in different ways. For
example, we need to determine if the given species of birds fly or not, using polymorphism we
can do this using a single function.
VI. ENCAPSULATION:
It describes the idea of wrapping data and the methods that work on data within one unit. This
puts restrictions on accessing variables and methods directly and can prevent the accidental
modification of data. To prevent accidental change, an object’s variable can only be changed by an
object’s method. Those types of variables are known as private variables. A class is an example of
encapsulation as it encapsulates all the data that is member functions, variables, etc.
Dept. of CSE(ET) 4
Data Structures A. Y. 2024 - 2025
Example 2:
# This program adds two numbersnum1 = 1.5
Dept. of CSE(ET) 5
Data Structures A. Y. 2024 - 2025
num2 = 6.3
# Add two numbers sum = num1 +
num2# Display the sum
print('The sum of {0} and {1} is {2}'.format(num1, num2, sum))Output : The sum of
1.5 and 6.3 is 7.8
Example 3:
# Store input numbers
num1 = input('Enter first number: ') num2 = input('Enter
second number: ')# Add two numbers
sum = float(num1) + float(num2)# Display the sum
print('The sum of {0} and {1} is {2}'.format(num1, num2, sum))
Output:
Enter first number: 1.5 Enter second
number: 6.3
The sum of 1.5 and 6.3 is 7.8
4. CONSTRUCTORS
A constructor is an instance method in a class, that is automatically called whenever a new
object of the class is created. The constructor's role is to assign value to instance variables as
soon as the object is declared.
Python uses a special method called init () to initialize the instance variables for the object,as
soon as it is declared. The “ init ()” method acts as a constructor. It needs a mandatory
argument self, which is the reference to the object.
Syntax
def init (self): #initialize instance variables
The init () method as well as any instance method in a class has a mandatory parameter,
self. However, you can give any name to the first parameter, not necessarily self.
Ex:
class Employee:
'Common base class for all employees' def
init (self):
self.name = "Bhavana"self.age = 24
e1 = Employee()
Dept. of CSE(ET) 6
Data Structures A. Y. 2024 - 2025
Parameterized Constructor
For the above Employee class, each object we declare will have same value for its instance
variables name and age. To declare objects with varying attributes instead of the default, define
arguments for the init () method. (A method is nothing but a function defined insidea class.)
Ex: The init () constructor has two formal arguments. We declare Employee objects with
different values –
class Employee:
'Common base class for all employees'def init (self, name, age):
self.name = nameself.age = age
e1 = Employee("Bhavana", 24) e2 =
Employee("Bharat", 25)
print ("Name: {}".format(e1.name))
print ("age: {}".format(e1.age))
print ("Name: {}".format(e2.name))
print ("age: {}".format(e2.age))
Output:
Name: Bhavana age:
24
Name: Bharat age:
25
Non-parameterized Constructor
On the opposite spectrum, we have non-parameterized constructors. These don’t take any
parameters, ensuring that every object has a standardized structure by allocating default values.
The highlight of non-parameterized constructors is their simplicity. When an object comes to life,
it gets furnished with predefined values, ensuring uniformity and consistency.
Dept. of CSE(ET) 7
Data Structures A. Y. 2024 - 2025
5. TYPES OF VARIABLES
Scope refers to the region of a program where a variable is defined and can be accessed. In
Python, there are three types of variable scopes: global, local, and nonlocal.
Global Variables - Global variables are defined outside any function or class and can be accessed
from anywhere within the program. They have a global scope, meaning they are visible to all
functions and classes. Global variables are useful when you want to share data between different
parts of your program.
Ex:
count = 0
def increment():global count count += 1
increment()print(count)
Output : 1
Local Variables - Local variables are defined within a function or a block of code and can only be
accessed within that specific function or block. They have a local scope, meaning they are only
visible within the function or block where they are defined. Local variables are temporary and
are destroyed once the function or block of code is executed.
Ex:
def calculate_sum(a, b):result = a + b
return result
sum = calculate_sum(5, 10)print(sum)
Output : 15
Nonlocal Variables - Nonlocal variables are used in nested functions, where a function is defined
inside another function. They are neither global nor local variables. Nonlocal variables can be
accessed and modified by the inner function, as well as the outer function that enclosesit.
Ex;
def outer_function():x = 10
def inner_function():nonlocal x
x += 5
print(x) # Output: 15
inner_function() outer_function()
Output : 15
Identifier :
Identifier is a name given to various programming elements such as a variable, function, class,
module or any other object. Following are the rules to create an identifier.
The allowed characters are a-z, A-Z, 0-9 and underscore (_)
It should begin with an alphabet or underscore
Dept. of CSE(ET) 8
Data Structures A. Y. 2024 - 2025
Keywords are the identifiers which have a specific meaning in python, there are 33keywords in
python. These may vary from version to version.
o False, None, True, and, as, assert, break, class, continue, def, del, elif, else, except, finally, for,
From, global, if, import, in, is, lambda, nonlocal, not, or, pass, raise, return, try, while, with, yield
Variables and Types
When we create a program, we often need store values so that it can be used in a program. We
use variables to store data which can be manipulated by the computer program.
Every variable:
Can be of any size
Have allowed characters, which are a-z, A-Z, 0-9 and underscore (_)
should begin with an alphabet or underscore
should not be a keyword
6. TYPES OF METHODS
In Python, there are three different method types: the static method, the class method and the
instance method. Each one of them has different characteristics and should be used in different
situations.
Static Methods
A static method in Python must be created by decorating it with @staticmethod. This lets Python
know that the method should be static. The main characteristic of a static method is that they
can be called without instantiating the class. These methods are self-contained, meaning that
they can’t access any other attribute or call any other method within that class.
You could use a static method when you have a class, but you don’t need a specific instance in
order to access that method. For example, if you have a class called Math and you have a
method called factorial, you probably won’t need a specific instance to call that method. So, you
could use a static method.
class Math:
Dept. osta
@ f CtSicEm(E
etTh)od
9
Data Structures A. Y. 2024 - 2025
Class Method
Class methods have to be created with the decorator @classmethod, and these methods sharea
characteristic with the static methods in that they can be called without having an instance ofthe
class. The difference relies on the capability to access other methods and class attributes but no
instance attributes.
Instance Methods
This method can only be called if the class has been instantiated. Once an object of that class has
been created, the instance method can be called and can access all the attributes of that class
through the reserved word self. An instance method is capable of creating, getting and setting
new instance attributes and calling other instance, class and static methods.
In simple terms, it comes down to method types. self is used to access an instance method, cls is
used to access a class method and nothing is applied when it’s a static method.
The difference between the keywords selfand cls reside only in the method type. If the created
method is an instance method then the reserved word self to be used, but if the method is a
class method then the keyword cls must be used. Finally, if the method is a static method then
none of those words will be used. Static methods are self-contained and don’t have access to the
instance or class variables nor to the instance or class methods.
7. INHERITANCE
The new class inherits from older classes. The new class copies all the older class's functions and
attributes without rewriting the syntax in the new classes. These new classes are called derived
classes, and old ones are called base classes.
Syntax:
class DerivedClass(BaseClass): # Class definition
Derived Class is the class that will inherit from the Base Class. The Base Class is the class thatwill
serve as the parent or superclass.
Dept. of CSE(ET) 10
Data Structures A. Y. 2024 - 2025
Example:
class Person:
def init (self, name, age): # Constructor to initialize name and age attributes
self.name = name
self.age = age
def say_hello(self): # Method to greet and introduce the person
print(f"Hello, my name is {self.name} and I am {self.age} years old.")
class Student(Person):
def init (self, name, age, grade):
super(). init (name, age)
self.grade = grade
def say_hello(self):
super().say_hello()
print(f"I am a student in grade {self.grade}.")
person = Person("John", 30)
person.say_hello()
student = Student("Mary", 18, 12)
student.say_hello()
Output:
Hello, my name is John and I am 30 years old. Hello, my name is Mary and I
am 18 years old.I am a student in grade 12.
a. SINGLE INHERITANCE
Single Inheritance is the simplest form of inheritance where a single child class is derived froma
single parent class. Due to its candid nature, it is also known as Simple Inheritance.
# python 3 syntax
# single inheritance example
class child(parent):
# child class
def func2(self): # we include the parent class
print("Hello Child") # as an argument in the child
# class
# Driver Code
test = child() # object created
test.func1() # parent method called via child object
test.func2() # child method called
Output:
Hello ParentHello Child
Dept. of CSE(ET) 11
Data Structures A. Y. 2024 - 2025
b. MULTIPLE INHERITANCE
In multiple inheritance, a single child class is inherited from two or more parent classes. It means
the child class has access to all the parent classes' methods and attributes.
However, if two parents have the same “named” methods, the child class performs the method of
the first parent in order of reference. To better understand which class’s methods shall be
executed first, we can use the Method Resolution Order function (mro). It tells the order in
which the child class is interpreted to visit the other classes.
# python 3 syntax
# multiple inheritance example
# Driver Code
test = child() # object created
test.func1() # parent1 method called via child
test.func2() # parent2 method called via child instead of parent3
test.func3() # child method called
find the order of classes visited by the child class, we use mro on the child class
print(child. mro )
Output:
> Hello Parent1
> Hello Parent2
> Hello Child
>(<class ' main .child'>, <class ' main .parent1'>, <class ' main
Dept. of CSE(ET) 12
Data Structures A. Y. 2024 - 2025
c. MULTI-LEVEL INHERITANCE
In multilevel inheritance, we go beyond just a parent-child relation. We introduce grandchildren,
great-grandchildren, grandparents, etc. We have seen only two levels of inheritance with a
superior parent class/es and a derived class/es, but here we can have multiple levels where the
parent class/es itself is derived from another class/es.
class grandparent: # first level
def func1(self):
print("Hello Grandparent")
class parent(grandparent): # second level
def func2(self):
print("Hello Parent")
# Driver Code
test = child() # object created
test.func1() # 3rd level calls 1st level
test.func2() # 3rd level calls 2nd level
test.func3() # 3rd level calls 3rd level
Output:
> Hello Grandparent
> Hello Parent
> Hello Child
d. HIERARCHICAL INHERITANCE
Hierarchical Inheritance is the right opposite of multiple inheritance. It means that there are
multiple derived child classes from a single-parent class.
# python 3 syntax
# hierarchical inheritance example
# Driver Code
test1 = child1() # objects created
test2 = child2()
Output:
> Hello Parent
> Hello Child1
> Hello Parent
> Hello Child2
e. HYBRID INHERITANCE
Hybrid Inheritance is the mixture of two or more different types of inheritance. Here we can
have many relationships between parent and child classes with multiple levels.
# python 3 syntax
# hybrid inheritance example
# Driver Code
test1 = child1() # object created
test2 = child2()
Output:
> Hello Parent1
> Hello Child1
> Hello Parent1
> Hello Parent2
> Hello Child1
> Hello Child2
8. POLYMORPHISM
Polymorphism is defined as the circumstance of occurring in several forms. It refers to the usage
of a single type entity (method, operator, or object) to represent several types in various
contexts. Polymorphism is made from 2 words – ‘poly‘ and ‘morphs.’ The word ‘poly’ means
‘many’ and ‘morphs’ means ‘many forms.
Polymorphism has the following advantages:
It is beneficial to reuse the codes.
The codes are simple to debug.
A single variable can store multiple data types.
Dept. of CSE(ET) 15
Data Structures A. Y. 2024 - 2025
Types of Polymorphism:
Compile-Time Polymorphism (Static Binding / Method Overloading): Compile-time
polymorphism is primarily achieved through function overloading, although Python does not
support true function overloading. However, you can define functions with the same name in
Python, but only the latest defined function will be considered.
class Dog(Animal):
def make_sound(self):print("Dog barks")
my_animal = Dog()
my_animal.make_sound() # Calls the overridden method in the Dog class
Interface Polymorphism: Python follows a concept called "duck typing," which is a form of
interface polymorphism. If an object behaves like a particular interface (has the required
methods and attributes), it can be treated as an instance of that interface.
class Bird:
def fly(self):pass
Method Overriding: Method overriding is a type of polymorphism in which a child class which is
extending the parent class can provide different definition to any function defined in the parent
class as per its own requirements.
Method Overloading : Method overriding or function overloading is a type of polymorphism in
which we can define a number of methods with the same name but with a different number of
parameters as well as parameters can be of different types. These methods can perform a similar
or different function.
Python doesn't support method overloading on the basis of different number of parameters in
functions.
a. FUNCTION POLYMORPHISM
There are certain Python functions that can be used with different data types. The len() function
is one example of such a function. Python allows it to work with a wide range of data types.
The built-in function len() estimates an object’s length based on its type. If an object is a string, it
returns the number of characters; or if an object is a list, it returns the number of elements inthe
list. If the object is a dictionary, it gives the total number of keys found in the dictionary.
Dept. of CSE(ET) 17
Data Structures A. Y. 2024 - 2025
Example:
Output:
Length of string: 11 Length of list: 5 Length
of dict: 2
b. CLASS POLYMORPHISM
Because Python allows various classes to have methods with the same name, we can leverage
the concept of polymorphism when constructing class methods. We may then generalize calling
these methods by not caring about the object we’re working with. Then we can write a for loop
that iterates through a tuple of items.
Example:
class Tiger():
def nature(self):
print('I am a Tiger and I am dangerous.')
def color(self):
print('Tigers are orange with black strips')
def color(self):
print('Elephants are grayish black')
for animal in (obj1, obj2): # creating a loop to iterate through the obj1 and
obj2
animal.nature() animal.color()
Output:
I am a Tiger and I am dangerous. Tigers are
orange with black strips
I am an Elephant and I am calm and harmless Elephants are
grayish black
Dept. of CSE(ET) 18
Data Structures A. Y. 2024 - 2025
Example:
class Vehicle:
def init (self, brand, model, price):self.brand = brand
self.model = modelself.price = price
def show(self):
print('Details:', self.brand, self.model, 'Price:', self.price)
def gear_system(self):
print('Vehicle has 6 shifter gearbox')
def gear_system(self):
print('Car has Automatic Transmission')
# Car Object
car = Car('Audi', 'R8', 9000000)
car.show()
# call methods from Car class car.max_speed()
car.gear_system()
# Vehicle Object
vehicle = Vehicle('Nissan', 'Magnite', 550000)
vehicle.show()
# call method from a Vehicle class
vehicle.max_speed() vehicle.gear_system()
Output:
Details: Audi R8 Price: 9000000Car max speed is 260
Car has Automatic Transmission Details: Nissan Magnite Price:
550000Vehicle max speed is 160
Vehicle has 6 shifter gearbox
Dept. of CSE(ET) 19
Data Structures A. Y. 2024 - 2025
9. ABSTRACTION
Abstraction is used to hide the internal functionality of the function from the users. The users
only interact with the basic implementation of the function, but inner working is hidden. User is
familiar with that "what function does" but they don't know "how it does." An abstraction is
used to hide the irrelevant data/class in order to reduce the complexity. It also enhances the
application efficiency
For example, When we use the TV remote to increase the volume. We don't know how pressing
a key increases the volume of the TV. We only know to press the "+" button to increase the
volume.
Example: # Python program showing abstract base class workfrom abc import ABC,
abstractmethod
class Polygon(ABC): @abstractmethoddef
noofsides(self):
pass
class Triangle(Polygon):
class Pentagon(Polygon):
class Hexagon(Polygon):
class Quadrilateral(Polygon):
Output
I have 3 sidesI have 4 sidesI have 5 sidesI have 6 sides
Dept. of CSE(ET) 21
Data Structures A. Y. 2024 - 2025
UNIT II
SORTING AND SEARCHING
1. SEARCHING
Search algorithms are methods that allow us to find the location of a specific element within a
list of elements. Depending on the list, you will need to use one algorithm or another; for
example, if the list has ordered elements, you can use a binary search algorithm, but if the list
contains the elements in an unordered way this algorithm will not work. To search for an
element in an unordered list you must use a linear search algorithm.
2. LINEAR SEARCH
Linear search algorithms, also known as sequential search, involve going through a list of items
one by one until a specific item is found. This algorithm is very simple to implement in code but
can be very inefficient depending on the length of the list and the location of the item.
def linear_search(list, objective):
Algorithm:
LinearSearch ( Array A, Value x)Step 1: Set i to 1
Step 2: if i > n then go to step 7 Step 3: if A[i] = x
then go to step 6Step 4: Set i to i + 1
Step 5: Go to Step 2
Step 6: Print Element x Found at index i and go to step 8 Step 7: Print
element not found
Step 8: Exit
code output:
The Number 39 is located at position: 14
Dept. of CSE(ET) 22
Data Structures A. Y. 2024 - 2025
Pros:
Simplicity: Linear search is one of the simplest and easiest search algorithms to implement. It
only requires iterating through the list of items one by one until the target is found.
flexibility: The linear search can be applied to any type of list, regardless of whether it issorted or
not.
Cons:
Inefficiency in large lists: The main disadvantage of linear search is its inefficiency in large lists.
Because it compares each item one by one, its execution time grows linearly with the size of the
list.
Not suitable for ordered lists: Although it can work on unordered lists, linear search is not
efficient for ordered lists. In such cases, more efficient search algorithms, such as binary search,
are preferable.
3. BINARY SEARCH
The binary search algorithm is a very efficient algorithm that applies only to ordered lists. It
works by repeatedly dividing the list into two halves and comparing the target element with the
middle element, this significantly reduces the number of comparisons needed.
Algorithm:
In binary search, we follow the following steps:
i. We start by comparing the element to be searched with the element in the middle of the
list/array.
ii. If we get a match, we return the index of the middle element.
iii. If we do not get a match, we check whether the element to be searched is less or greater than
invalue than the middle element.
iv. If the element/number to be searched is greater in value than the middle number, then we pick
the elements on the right side of the middle element(as the list/array is sorted, hence on the
right, we will have all the numbers greater than the middle number), and start again from the
step 1.
v. If the element/number to be searched is lesser in value than the middle number, then we pick the
elements on the left side of the middle element, and start again from the step 1.
Dept. of CSE(ET) 23
Data Structures A. Y. 2024 - 2025
return -1
# Example of use
list = [1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 15, 20, 27, 34, 39, 50]
objective = 27
start_search = 0 end_search = len(list) - 1
Efficiency of ordered lists: The main advantage of binary search is its efficiency on ordered lists.
Its execution time is O(log n), which means that it decreases rapidly as thelist size increases.
Fewer comparisons: Compared to linear search, binary search performs fewer comparisons on
average, making it faster to find the target.
Cons:
Requires a sorted list: Binary search is only applicable to sorted lists. If the list is not sorted, an
additional operation must be performed to sort the list before using binary search.
Higher deployment complexity: Compared to linear search, binary search is more complex to
implement due to its recursive nature.
Dept. of CSE(ET) 24
Data Structures A. Y. 2024 - 2025
4. SORTING
A sorting algorithm allows us to rearrange a list of elements or nodes in a specific order, for
example in ascending or descending order depending on the occasion.
a. BUBBLE SORT
The bubble sort algorithm is one of the simplest but least efficient algorithms. It works by
comparing pairs of elements and swapping them if they are in the wrong order, this process is
done over and over again until the list is sorted correctly. It has a time complexity of O(n2) in the
average and worst cases scenarios and O(n) in the best-case scenario.
def bubble_sort(list):length = len(list)
for i in range(length):
for j in range(0, (length-i) - 1):
Pros:
Simplicity: The bubble algorithm is easy to understand and implement, which makes it a good
choice for introducing ordering concepts in programming.
Simple deployment: Requires little amount of code and does not involve complex data
structures.
Cons:
Slow for large lists: Due to its quadratic complexity the bubble algorithm becomes slow in
practice for lists of considerable size.
Does not consider partial order: Unlike other algorithms, the bubble algorithm performs the
same number of comparisons and swaps regardless of whether the listis already largely sorted.
Dept. of CSE(ET) 25
Data Structures A. Y. 2024 - 2025
b. SELECTION SORT
This sorting technique repeatedly finds the minimum element and sort it in order. Bubble Sort
does not occupy any extra memory space. During the execution of this algorithm, two subarrays
are maintained, the subarray which is already sorted, and the remaining subarray which is
unsorted. During the execution of Selection Sort for every iteration, the minimum element of the
unsorted subarray is arranged in the sorted subarray. Selection Sort is a more efficient algorithm
than bubble sort. Sort has a Time-Complexity of O(n2) in the average, worst, and in the best
cases.
Algorithm
Step 1: Set MIN to location 0
Step 2: Search the minimum element in the list Step 3: Swap with
value at location MIN
Step 4: Increment MIN to point to next elementStep 5: Repeat until
list is sorted
for s in range(size):min_idx = s
Output
Sorted Array in Ascending Order is : [1, 2, 6, 7]
Dept. of CSE(ET) 26
Data Structures A. Y. 2024 - 2025
Advantages
The main advantage of the selection sort is that it performs well on a small list.
Because it is an in-place sorting algorithm, no additional temporary storage is requiredbeyond
what is needed to hold the original list.
Its performance is easily influenced by the initial ordering of the items before thesorting process.
Disadvantages
The primary disadvantage of the selection sort is its poor efficiency when dealing with ahuge list of
items.
The selection sort requires n-squared number of steps for sorting n elements.
Quick Sort is much more efficient than selection sort
c. INSERTION SORT
The insertion sort algorithm is a simple but efficient algorithm. It works by dividing the list into
two parts, an ordered part and an unordered part. As the unordered list is traversed, elements
are inserted in the correct position in the ordered part. Insertion Sort has a Time-Complexity of
O(n2) in the average and worst case, and O(n) in the best case.
Algorithm
Step 1: If it is the first element, it is already sorted. return 1;Step 2:
Pick next element
Step 3: Compare with all elements in the sorted sub-list
Step 4: Shift all the elements in the sorted sub-list that is greater than the value to be
sorted
Step 5: Insert the value
Step 6: Repeat until list is sorted
"""
This loop interchanges the two position numbers, as long as the previous
number is larger than the current number."""
while index > 0 and list[index - 1] > actual:list[index] = list[index - 1]
index = index - 1list[index] = actual
return list
unordered_list = [39, 45, 32, 4, 2, 85, 43, 7, 18, 16, 5, 67, 32]
ordered_list = insertion_sort(unordered_list) print(ordered_list)
Dept. of CSE(ET) 27
Data Structures A. Y. 2024 - 2025
# output: [2, 4, 5, 7, 16, 18, 32, 32, 39, 43, 45, 67, 85]
Pros:
Low overhead: Requires fewer comparisons and moves than algorithms such as bubble sort,
which makes it more efficient in terms of item exchanges.
Simplicity: insertion sort is one of the simplest sorting algorithms to implement and
understand. This makes it suitable for teaching basic sorting concepts.
Cons:
Inefficiency in large lists: As the list size increases, the performance of insertion sort decreases.
Its quadratic complexity of O(n^2) in the worst case makes it inefficient forlarge lists.
Non-scalable: Like other quadratic complexity algorithms, insertion sort is not scalable for large
lists, as its execution time increases considerably with the size of the list.
d. MERGE SORT
Merge Sort is a Divide and Conquer algorithm. It divides input array in two halves, calls itself for
the two halves and then merges the two sorted halves. The merge() function is used for merging
two halves. The merge(arr, l, m, r) is key process that assumes that arr[l..m] and arr[m+1..r] are
sorted and merges the two sorted sub-arrays into one. Time Complexity of merge sort is
O(n*log(n))
Dept. of CSE(ET) 28
Data Structures A. Y. 2024 - 2025
Dept. of CSE(ET) 29
Data Structures A. Y. 2024 - 2025
# l is for left index and r is right index of the# sub-array of arr to be sorted
Output
Given array is 12 11 13 5 6 7
Sorted array is 5 6 7 11 12 13
e. QUICK SORT
Quick sort is a well-known sorting algorithm. It is highly efficient and also known as partition
exchange sort. In this sorting algorithm the array is divided into 2 sub array. One contain smaller
values than pivot value and other array contain elements having greater values than pivot value.
Pivot is an element that is used to compare and divide the elements of the main array into two.
Quick sort partitions an array and then calls itself recursively twice to sort the two resulting sub
arrays. This algorithm is quite efficient for large data sets. The Average and worst case
Dept. of CSE(ET) 30
Data Structures A. Y. 2024 - 2025
Advantages
The quick sort is regarded as the best sorting algorithm.
It is able to deal well with a huge list of items.
Because it sorts in place, no additional storage is required as well
Disadvantages
The slight disadvantage of quick sort is that its worst-case performance is similar to average
performances of the bubble, insertion or selections sorts.
If the list is already sorted than bubble sort is much more efficient than quick sort
If the sorting element is integers than radix sort is more efficient than quick sort.
Dept. of CSE(ET) 31
Data Structures A. Y. 2024 - 2025
Dept. of CSE(ET) 32
Data Structures A. Y. 2024 - 2025
a linear manner. There are multiple levels of nonlinear data structures. It is also called a
multilevel data structure. Implementing a non-linear data structure can be more challenging
compared to its linear counterpart. However, it offers more efficient memory utilization.
Examples of non-linear data structures include trees and graphs.
Factor Linear Data Structure Non-Linear Data Structure
Data Element In a linear data structure, data elements In a non-linear data structure, data
Arrangement are sequentially connected, allowing elements are hierarchically
users to traverse all elements connected, appearing on multiple
in one run. levels.
Implementation Linear data structures are relatively Non-linear data structures require a
Complexity easier to implement. higher level of understanding and
are more complex to implement.
Levels All data elements in a linear data Data elements in a non-linear data
structure exist on a single level. structure span multiple levels.
Traversal A linear data structure can be Traversing a non-linear data
traversed in a single run. structure is more complex, requiring
multiple runs.
Memory Utilization Linear data structures do not efficiently Non-linear data structures are more
utilize memory. memory friendly.
Time Complexity The time complexity of a linear data The time complexity of a non-linear
structure is directly proportional to its data structure often remains
size, increasing as input size increases. constant, irrespective of its input
size.
Applications Linear data structures are ideal for Non-linear data structures are
application software development. commonly used in image processing
and Artificial Intelligence.
Examples Linked List, Queue, Stack, Array. Tree, Graph, Hash Map.
Can push/pop data from a single end of the stack. Users can insert the data into the stack via
push operation and remove data from the stack via pop operation. The stack follows the rule of
LIFO (last in first out). Users can access all the stack data from the top of the stack in a linear
manner. In real-life problems, the stack data structure is used in many applications. For
Dept. of CSE(ET) 33
Data Structures A. Y. 2024 - 2025
example, the web browsers use the stack to store the backward/forward operations. For the
array-based implementation of a stack, the push and pop operations take constant time, i.e. O(1)
There are some basic operations that allow us to perform different actions on a stack.
Push: Add an element to the top of a stack
Pop: Remove an element from the top of a stack
IsEmpty: Check if the stack is empty
IsFull: Check if the stack is full
Peek: Get the value of the top element without removing it
On popping an element, we return the element pointed to by TOP and reduce its value.
Before pushing, we check if the stack is already full
Before popping, we check if the stack is already empty
Python’s built-in list data structure is a simple and effective way to implement a stack. The key
operations in a stack, namely ‘push’ (add an element to the top of the stack) and ‘pop’ (removean
element from the top of the stack), can be easily achieved using the append() and pop() methods
of a list.
To add an element to the stack (push operation), you can use the append() method. This method
adds an element to the end of the list, which corresponds to the top of the
Dept. of CSE(ET) 34
Data Structures A. Y. 2024 - 2025
To remove an element from the stack (pop operation), you can use the pop() method. This
method removes the last element from the list, which corresponds to the top of the stack.
last_element = stack.pop() print(f'Popped Element:
{last_element}')print(f'Stack after Pop: {stack}')
# Output:
# Popped Element: c
# Stack after Pop: ['a', 'b']
Dept. of CSE(ET) 35
Data Structures A. Y. 2024 - 2025
b. APPLICATIONS OF STACK
To reverse a word - Put all the letters in a stack and pop them out. Because of the LIFOorder of
stack, you will get the letters in reverse order.
In compilers - Compilers use the stack to calculate the value of expressions like 2 + 4 / 5
* (7 - 9) by converting the expression to prefix or postfix form.
In browsers - The back button in a browser saves all the URLs you have visited previously in a
stack. Each time you visit a new page, it is added on top of the stack. When you press the back
button, the current URL is removed from the stack, and the previous URL is accessed.
Backtracking Algorithms - Backtracking is a method of solving problems where you move forward
only if there is no obstacle in the solution path, and if you encounter an obstacle, you move
backwards and try another path. Stacks are used extensively in backtracking problems to keep
track of the visited paths and to backtrack when no solution is found on the current path.
Parsing - In compilers, stacks are used in the parsing phase to check the correctness of
expressions and their syntax. For example, they can be used to check whether the opening and
closing parentheses in an expression are balanced.
Memory Management - Stacks play a vital role in memory management. When a function is
called, the memory for its variables is allocated on the stack, and when the function returns, this
memory is freed up.
Dept. of CSE(ET) 36
Data Structures A. Y. 2024 - 2025
Dequeue: This operation removes an element from the queue. Since it bases the queueon a FIFO
manner, it releases the items in the order of their additions. When the queuebecomes empty, it
reaches an underflow condition. The time complexity is O:1.
Front: It gives you the first item from the queue. The time complexity is O:1.
Rare: It gives you the last item from the queue. The time complexity is O:1.
Output:
Queue before any operation [‘x’ , ‘y’, ‘z’]Dequeue items x , y, z
Output:
Queue length is 5
b. APPLICATIONS OF QUEUES
A queue data structure is generally used in scenarios where the FIFO approach (First In First Out)
has to be implemented. The following are some of the most common queue applications in data
structure:
Managing requests on a single shared resource such as CPU scheduling and disk scheduling
Handling hardware or real-time systems interrupts
Handling website traffic
Routers and switches in networking
Maintaining the playlist in media players
Queues can be used to manage and allocate resources, such as printers or CPUprocessing time.
Queues can be used to handle batch processing jobs, such as data analysis or image
rendering.
c. PRIORITY QUEUES
Priority queue in Python is a special type of queue that is executed based on priorities. It is nota
completely FIFO queue as it sorts and dequeues an element based on priority and not based on
when they were added. It calculates the priorities based on the ordering of their key pairs. They
are most useful in scheduling tasks where priority is of importance. For instance, an operating
system executes and completes a task based on priority; hence, a priority queue can be used
here.
There are multiple ways to implement a priority queue. The two standard ways are through:
Manually sorted list
queue.PriorityQueue Class
Dept. of CSE(ET) 38
Data Structures A. Y. 2024 - 2025
inserting new elements can be challenging as it follows an O(n) time complexity. Hence, the best
use of a manually sorted list can be when the number of insertions is minimal. In the code below,
you will manually sort a list to implement a priority queue in Python.
priority_queu = [] priority_queu.append((3, 'Huindai'))
priority_queu.append((4, 'Mahindra'))
priority_queu.append((1, 'Maruthi'))
priority_queu.append((2, 'TATA'))
# Resort everytime a new element is addedpriority_queu.sort(reverse=True)
while priority_queu:
nxt_itm = priority_queu.pop()print(nxt_itm)
Output:
( 1, ‘Maruthi’)
(2, TATA’)
(3, Huindai’)
(4, ‘Mahindra’)
Output:
( 1, ‘Maruthi’)
(2, TATA’)
(3, Huindai’)
(4, ‘Mahindra’)
Dept. of CSE(ET) 39
Data Structures A. Y. 2024 - 2025
6. ARRAYS
The array is the most used Linear data type. The array stores the objects of the same data typein
a linear fashion. Users can use an array to construct all linear or non-linear data structures. For
example, Inside the car management software to store the car names array of the strings is
useful. We can access the element of the array by the index of elements. In an array, the index
always starts at 0. To prevent memory wastage, users should create an array of dynamic sizes.
7. LINKED LISTS
LinkedList data structure stores the data in the form of a node. Every linked list node contains
the element value and address pointer. The address pointer of the LinkedList consists of the
address of the next node. It can store unique or duplicate elements.
A singly-linked list is the simplest type of linked list, where each node contains some data and a
reference to the next node in the sequence. They can only be traversed in a single direction -
from the head (the first node) to the tail (the last node).
Each node in a singly-linked list typically consists of two parts:
Data: The actual information stored in the node.
Next Pointer: A reference to the next node. The last node’s next pointer is usually set tonull.
Dept. of CSE(ET) 40
Data Structures A. Y. 2024 - 2025
Since these data structures can only be traversed in a single direction, accessing a specific
element by value or index requires starting from the head and sequentially moving through the
nodes until the desired node is found. This operation has a time complexity of O(n), making it
less efficient for large lists.
Inserting and deleting a node at the beginning of a singly-linked list is highly efficient with a time
complexity of O(1). However, insertion and deletion in the middle or at the end requires
traversing the list until that point, leading to an O(n) time complexity.
The design of singly-linked lists makes them a useful data structure when performing operations
that occur at the beginning of the list.
The below program creates the linked list with three data elements.
class Node:
def init (self, dataval=None): self.dataval = dataval
self.nextval = None
class SLinkedList:
def init (self): self.headval = None
Singly linked lists can be traversed in only forward direction starting form the first data element.
We simply print the value of the next data element by assigning the pointer of the next node to
the current data element.
Insertion in a Linked List
Inserting element in the linked list involves reassigning the pointers from the existing nodes to
the newly inserted node. Depending on whether the new data element is getting inserted at the
beginning or at the middle or at the end of the linked list, we have the below scenarios.
Inserting at the Beginning - This involves pointing the next pointer of the new data node to the
current head of the linked list. So the current head of the linked list becomes the second data
element and the new node becomes the head of the linked list.
Dept. of CSE(ET) 41
Data Structures A. Y. 2024 - 2025
Inserting at the End - This involves pointing the next pointer of the the current last node of the
linked list to the new data node. So the current last node of the linked list becomes the second
last data node and the new node becomes the last node of the linked list.
Inserting in between two Data Nodes - This involves changing the pointer of a specific node to
point to the new node. That is possible by passing in both the new node and the existing node
after which the new node will be inserted. So we define an additionalclass which will change the
next pointer of the new node to the next pointer of middle node. Then assign the new node to
next pointer of the middle node.
Algorithm:
Define a Node class which represents a node in the list. It will have three properties: data,
previous which will point to the previous node and next which will point to the next node.
Define another class for creating a doubly linked list, and it has two nodes: head and tail. Initially,
head and tail will point to null.
o
o The new node will become the new tail. Tail's next pointer will point to null.
display() will show all the nodes present in the list.
o Define a new node 'current' that will point to the head.
o Print current.data till current points to null.
o Current will point to the next node in the list in each iteration.
Dept. of CSE(ET) 43
Data Structures A. Y. 2024 - 2025
Output:
Nodes of doubly linked list: 1234 5
ALGORITHM:
Define a Node class which represents a node in the list. It has two properties data and next
which will point to the next node.
Define another class for creating the circular linked list, and it has two nodes: head andtail. It has
two methods: add() and display() .
add() will add the node to the list:
o It first checks whether the head is null, then it will insert the node as the head.
o Both head and tail will point to the newly added node.
o If the head is not null, the new node will be the new tail, and the new tail willpoint to the
head as it is a circular linked list.
display() will show all the nodes present in the list.
Define a new node 'current' that will point to the head.
Print current.data till current will points to head
Current will point to the next node in the list in each iteration
Program:
#Represents the node of list.class Node:
def init (self,data):self.data = data; self.next =
None;
Dept. of CSE(ET) 44
Data Structures A. Y. 2024 - 2025
class CreateList:
#Declaring head and tail pointer as null.def init (self):
self.head = Node(None); self.tail = Node(None);
self.head.next = self.tail;self.tail.next = self.head;
#This function will add the new node at the end of the list.def add(self,data):
newNode = Node(data); #Checks if the list is empty.if
self.head.data is None:
#If list is empty, both head and tail would point to new node.self.head = newNode;
self.tail = newNode; newNode.next = self.head; else:
#tail will point to new node.self.tail.next = newNode;
#New node will become new tail.self.tail = newNode;
#Since, it is circular linked list tail will point to head.self.tail.next = self.head;
Dept. of CSE(ET) 45
Data Structures A. Y. 2024 - 2025
Output:
Nodes of the circular linked list:1 2 3 4
Dept. of CSE(ET) 46
Data Structures A. Y. 2024 - 2025
1. INTRODUCTION
Python provides another composite data type called a dictionary, which is similar to a list in
that it is a collection of objects. Dictionaries are Python’s implementation of a data structure
that is more generally known as an associative array. A dictionary consists of a collection of
key-value pairs. Each key-value pair maps the key to its associated value.
You can define a dictionary by enclosing a comma-separated list of key-value pairs in curly
braces ({}). A colon (:) separates each key from its associated value:
d={
<key>: <value>,
<key>: <value>,
.
.
.
<key>: <value>
}
Dept. of CSE(ET) 47
Data Structures A. Y. 2024 - 2025
Let's take an example to understand the working of the skip list. In this example, we have 14
nodes, such that these nodes are divided into two layers, as shown in the diagram.
The lower layer is a common line that links all nodes, and the top layer is an express line thatlinks
only the main nodes, as you can see in the diagram.
Suppose you want to find 47 in this example. You will start the search from the first node of
the express line and continue running on the express line until you find a node that is equal a47
or more than 47.
You can see in the example that 47 does not exist in the express line, so you search for a nodeof
less than 47, which is 40. Now, you go to the normal line with the help of 40, and search the47,
as shown in the diagram.
Dept. of CSE(ET) 48
Data Structures A. Y. 2024 - 2025
Search Operation: The search operation is used to search a particular node in a skip list.
Algorithm of the insertion operation
for i = 0 to level do
a → forward[i] = update[i] → forward[i]update[i] → forward[i]
=a
It is used to implement a dynamic elastic concurrent queue with low lock contention.
It is also used with the QMap template class.
The indexing of the skip list is used in running median problems.
The skip list is used for the delta-encoding posting in the Lucene search.
3. GRAPHS
A graph is an advanced data structure that is used to organize items in an interconnected
network. Each item in a graph is known as a node(or vertex) and these nodes are connected by
edges.
In the figure below, we have a simple graph where there are five nodes in total and six edges.
The nodes in any graph can be referred to as entities and the edges that connect different nodes
define the relationships between these entities. In the above graph we have a set of nodes {V} =
{A, B, C, D, E} and a set of edges, {E} = {A-B, A-D, B-C, B-D, C-D, D-E} respectively
Types of Graphs
Dept. of CSE(ET) 50
Data Structures A. Y. 2024 - 2025
A) Null Graphs
A graph is said to be null if there are no edges in that graph. A pictorial representation of the
null graph is given below:
B) Undirected Graphs
If we take a look at the pictorial representation that we had in the Real-world example above, we
can clearly see that different nodes are connected by a link (i.e. edge) and that edge doesn'thave
any kind of direction associated with it. For example, the edge between "Anuj" and "Deepak" is
bi-directional and hence the relationship between them is two ways, which turns out to be that
"Anuj" knows "Deepak" and "Deepak" also knows about "Anuj". These types of graphs where the
relation is bi-directional or there is not a single direction, are known as Undirected graphs.
A pictorial representation of another undirected graph is given below:
C) Directed Graphs
What if the relation between the two people is something like, "Shreya" know "Abhishek" but
"Abhishek" doesn't know "Shreya". This type of relationship is one-way, and it does include a
direction. The edges with arrows basically denote the direction of the relationship and such
graphs are known as directed graphs.
A pictorial representation of the graph is given below:
It can also be noted that the edge from "Shreya" to "Abhishek" is an outgoing edge for "Shreya" and an
incoming edge for "Abhishek".
Dept. of CSE(ET) 51
Data Structures A. Y. 2024 - 2025
D) Cyclic Graph
A graph that contains at least one node that traverses back to itself is known as a cyclic graph. In
simple words, a graph should have at least one cycle formation for it to be called a cyclic graph.
A pictorial representation of a cyclic graph is given below:
It can be easily seen that there exists a cycle between the nodes (a, b, c) and hence it is a cyclic graph.
E) Acyclic Graph
A graph where there's no way we can start from one node and can traverse back to the same
one, or simply doesn't have a single cycle is known as an acyclic graph.
A pictorial representation of an acyclic graph is given below:
F) Weighted Graph
When the edge in a graph has some weight associated with it, we call that graph as a weighted
graph. The weight is generally a number that could mean anything, totally dependent on the
relationship between the nodes of that graph.
A pictorial representation of the weighted graph is given below:
It can also be noted that if any graph doesn't have any weight associated with it, we simply call it
an unweighted graph.
Dept. of CSE(ET) 52
Data Structures A. Y. 2024 - 2025
G) Connected Graph
A graph where we have a path between every two nodes of the graph is known as a connected
graph. A path here means that we are able to traverse from a node "A" to say any node "B". In
simple terms, we can say that if we start from one node of the graph we will always be able to
traverse to all the other nodes of the graph from that node, hence the connectivity.
A pictorial representation of the connected graph is given below:
H) Disconnected Graph
A graph that is not connected is simply known as a disconnected graph. In a disconnected
graph, we will not be able to find a path from between every two nodes of the graph.
A pictorial representation of the disconnected graph is given below:
I) Complete Graph
A graph is said to be a complete graph if there exists an edge for every pair of vertices(nodes)of
that graph. A pictorial representation of the complete graph is given below:
J) Multigraph
A graph is said to be a multigraph if there exist two or more than two edges between any pairof
nodes in the graph.
A pictorial representation of the multigraph is given below:
Dept. of CSE(ET) 53
Data Structures A. Y. 2024 - 2025
Path - A sequence of alternating nodes and edges such that each of the successive nodes
are connected by the edge.
Cycle - A path where the starting and the ending node is the same.
Simple Path - A path where we do not encounter a vertex again.
Bridge - An edge whose removal will simply make the graph disconnected.
Forest - A forest is a graph without cycles.
Tree - A connected graph that doesn't have any cycles.
Degree - The degree in a graph is the number of edges that are incident on a particularnode.
Neighbour - We say vertex "A" and "B" are neighbours if there exists an edge betweenthem.
Dept. of CSE(ET) 54
Data Structures A. Y. 2024 - 2025
Document link graphs: Link weighted graphs are used to analyze relevance of web pages, the
best sources of information, and good link sites by taking the count of thenumber of views as
weights in the graph.
Epidemiology: Weighted graphs can be used to find the maximum distance transmission from an
infectious to a healthy person.
Graphs in quantum field theory: Vertices represent states of a quantum system and the edges
represent transitions between them. The graphs can be used to analyze path integrals and
summing these up generates a quantum amplitude. Research to find the maximum frequency
along a path can be done using weighted graphs.
Social network graphs: We can find which all users are connected in a network both
directly(direct connection) and indirectly(indirect connection). But now weighted graphs are
also used in social media for many purposes, for example, In recent times Instagram is using
features like close friends which is not the same as all friends these features are being
implemented using weighted graphs.
Network packet traffic graphs: Network packet traffic graphs are used for analyzing network
security, studying the spread of worms, and tracking criminal or non-criminalactivity.
Unweighted graphs are used to represent data that are not related in terms of
magnitude.
Unweighted graphs are used to represent computation flow.
Representation of image segmentation, where pixels are represented as nodes and edges
represent adjacency relationships.
Dept. of CSE(ET) 55
Data Structures A. Y. 2024 - 2025
5. REPRESENTATIONS
Breadth-first search and Depth-first search in python are algorithms used to traverse a graph ora
tree.
a. BREADTH FIRST SEARCH
Traversing means visiting each node of the graph. Breadth-First Search is a recursive algorithm to
search all the vertices of a graph or a tree. BFS in python can be implemented by using data
structures like a dictionary and lists. Breadth-First Search in tree and graph is almost the same.
The only difference is that the graph may contain cycles, so we may traverse to the same node
again.
As breadth-first search is the process of traversing each node of the graph, a standard BFS
algorithm traverses each vertex of the graph into two parts: 1) Visited 2) Not Visited. So, the
purpose of the algorithm is to visit all the vertex while avoiding cycles.
BFS starts from a node, then it checks all the nodes at distance one from the beginning node,
then it checks all the nodes at distance two, and so on. So as to recollect the nodes to be visited,
BFS uses a queue.
The steps of the algorithm work as follow:
Start by putting any one of the graph’s vertices at the back of the queue.
Now take the front item of the queue and add it to the visited list.
Create a list of that vertex's adjacent nodes. Add those which are not within the visited
list to the rear of the queue.
Keep continuing steps two and three till the queue is empty.
The pseudocode for BFS in python goes as below:
create a queue Q
mark v as visited and put v into Qwhile Q is non-empty
remove the head u of Q
mark and enqueue all (unvisited) neighbors of u
Dept. of CSE(ET) 56
Data Structures A. Y. 2024 - 2025
graph = {
'5' : ['3','7'],
'3' : ['2', '4'],
'7' : ['8'],
'2' : [],
'4' : ['8'],
'8' : []
}
# Driver Code
print("Following is the Breadth-First Search") bfs(visited,
graph, '5') # function calling
The output of the above code will be as follow:Following is the Breadth-First Search
537248
Dept. of CSE(ET) 57
Data Structures A. Y. 2024 - 2025
We begin from the vertex P, the BFS algorithmic program starts by putting it within the Visitedlist
and puts all its adjacent vertices within the stack.
Fig 2: Visit starting verted and add its adjacent vertices to queue
Next, we have a tendency to visit the part at the front of the queue i.e. Q and visit its adjacent
nodes. Since P has already been visited, we have a tendency to visit R instead.
Dept. of CSE(ET) 58
Data Structures A. Y. 2024 - 2025
Fig 4: Visit R which was added to queue earlier to add its neighbor
Fig 6: Visited all nodes hence list visited is full and queue is empty
Since the queue is empty, we've completed the Traversal of the graph.
The time complexity of the Breadth first Search algorithm is in the form of O(V+E), where V is
Dept. of CSE(ET) 59
Data Structures A. Y. 2024 - 2025
the representation of the number of nodes and E is the number of edges. Also, the space
complexity of the BFS algorithm is O(V).
Applications of BFS Algorithm
Breadth-first Search Algorithm has a wide range of applications in the real-world. Some of them
are as discussed below:
In GPS navigation, it helps in finding the shortest path available from one point to
another.
In pathfinding algorithms
Cycle detection in an undirected graph
In minimum spanning tree
To build index by search index
In Ford-Fulkerson algorithm to find maximum flow in a network.
Dept. of CSE(ET) 60
Data Structures A. Y. 2024 - 2025
The pseudocode for Depth-First Search in python goes as below: In the init() function, notice that
we run the DFS function on every node because many times, a graph may contain two different
disconnected part and therefore to make sure that we have visited every vertex, we can also run
the DFS algorithm at every node.
DFS(G, u)
u.visited = true
for each v ∈ G.Adj[u]if v.visited == false
DFS(G,v)
init() {
For each u ∈G u.visited = false
For each u ∈ G
DFS(G, u)
}
Example
Let us see how the DFS algorithm works with an example. Here, we will use an undirected
graph with 5 vertices.
We begin from the vertex P, the DFS rule starts by putting it within the Visited list and puttingall
its adjacent vertices within the stack.
Dept. of CSE(ET) 61
Data Structures A. Y. 2024 - 2025
Fig 2: Visit starting vertex and add its adjacent vertices to stack
Next, we tend to visit the part at the highest of the stack i.e. Q, and head to its adjacent nodes.
Since P has already been visited, we tend to visit R instead.
Vertex R has the unvisited adjacent vertex in T, therefore we will be adding that to the highestof
the stack and visit it.
Fig 4: Vertex R has unvisited node T so we include it to the top of the stack and then visit it.
Dept. of CSE(ET) 62
Data Structures A. Y. 2024 - 2025
Fig 5: Vertex R has an unvisited node T, so we include it to the top of stack and then visit it. At
last, we will visit the last component S, it does not have any unvisited adjacent nodes, thus
we've completed the Depth First Traversal of the graph.
Fig 6: After visiting last node S, it doesn’t have any adjacent node
The time complexity of the Depth-First Search algorithm is represented within the sort of O(V +E),
where V is that the number of nodes and E is that the number of edges. The space complexity of
the algorithm is O(V).
Applications
Depth-First Search Algorithm has a wide range of applications for practical purposes. Some of them
are as discussed below:
Dept. of CSE(ET) 63
Data Structures A. Y. 2024 - 2025
Dept. of CSE(ET) 64
Data Structures A. Y. 2024 - 2025
UNIT –V TREES
1. OVERVIEW OF TREES
Trees are non-linear data structures that store data hierarchically and are made up of nodes
connected by edges. For example, in a family tree, a node would represent a person, and an edge
would represent the relationship between two nodes. Tree data struc ture is a hierarchical structure
that is used to represent and organize data in a way that is easy to navigate and search. It is a
collection of nodes that are connected by edges and has a hierarchical relationship between the
nodes.
Example of tree:
a. TREE TERMINOLOGY
Root: A node that doesn’t have any parent, and the entire tree originates from it. In Fig. 1, the
root is node a.
Leaf: Nodes that don’t have any child. In Fig. 1, leaf nodes are nodes c, d, and e.
Parent node: Immediate predecessor of a node. In Fig. 1, node a is the parent node ofnodes b
and c.
Child node: Immediate successor of a node. In Fig. 1, Node b is the child node of Nodea.
Ancestors: All predecessors of a node. In Fig. 1, nodes a and b are ancestors of node d.
Descendants: All successors of a node. In Fig. 1, nodes d and e are descendants of nodeb.
Siblings: Nodes that have the same parent. In Fig. 1, node d and e are siblings.
Dept. of CSE(ET) 65
Data Structures A. Y. 2024 - 2025
Left sibling: Sibling to the left of the node. In Fig. 1, node d is the left sibling of node e.
Right sibling: Sibling to the right of the node. In Fig. 1, node e is the right sibling of noded.
Depth: Length of the path from node to root. In Fig. 1, the depth of node b is 2, andNode d is
3.
Height/Max depth: Maximum depth of root to a leaf node. In Fig. 1, the height of thetree is 3.
Traversal: Traversing a tree allows you to visit each node in a specific order. Common traversal
algorithms include depth-first traversal (pre-order, in-order, post-order) and breadth-first
traversal.
Searching: Searching for a specific node or value in a tree can be done using various search
algorithms like depth-first search (DFS) or breadth-first search (BFS).
Insertion and Deletion: Adding or removing nodes from a tree while maintaining its properties.
Height and Depth Calculation: Calculating the height and depth of a tree or a specific node.
Balancing: Balancing a tree to ensure efficient operations, especially in search trees likeAVL trees
or Red-Black trees.
Types of TREE Data Structure:
Tree data structure can be classified into three types based upon the number of children each
node of the tree can have. The types are:
Binary tree: In a binary tree, each node can have a maximum of two children linked to it. Some
common types of binary trees include full binary trees, complete binary trees, balanced binary
trees, and degenerate or pathological binary trees.
Ternary Tree: A Ternary Tree is a tree data structure in which each node has at most three child
nodes, usually distinguished as “left”, “mid” and “right”.
N-ary Tree or Generic Tree: Generic trees are a collection of nodes where each node is a data
structure that consists of records and a list of references to its children(duplicate references are
not allowed). Unlike the linked list, each node stores the address of multiple nodes.
Dept. of CSE(ET) 66
Data Structures A. Y. 2024 - 2025
2. BINARY TREES
Binary Tree is a form of a tree whose nodes cannot have more than two children. Each node of
the binary tree has two pointers associated with it, one points to the left child, and the other
points to the right child of the node. It is an unordered tree having no fixed organized structure
for the arrangement of nodes. Binary Tree is slow for the searching, insertion, or deletion of the
data because of its unordered structure. The time complexity of these operations is (𝑁).
Dept. of CSE(ET) 67
Data Structures A. Y. 2024 - 2025
Leaf Nodes: Nodes that do not have any children are called leaf nodes or terminal nodes. They
are the nodes at the bottom-most level of the tree.
Internal Nodes: Nodes that have at least one child are called internal nodes. They are not leaf
nodes and are located somewhere between the root node and the leaf nodes.
Depth and Height: The depth of a node is the length of the path from the root node to that
node. The height of a node is the length of the longest path from that node to a leaf node. The
height of the binary tree is the height of the root node.
Binary Search Property: In a binary search tree (a specific type of binary tree), the values stored
in the left subtree of a node are less than the value of the node, and the values stored in the
right subtree are greater than the value of the node. This property allows for efficient searching,
insertion, and deletion operations.
a. IMPLEMENTATION
Crete the Node class
class Node:
"""
A node class representing a single element in the binary tree."""
def init (self, data):
self.data = data
self.left = None # Left child self.right = None # Right
child
Dept. of CSE(ET) 68
Data Structures A. Y. 2024 - 2025
output
print("Inorder traversal: ")inorder_traversal(root)
After inserting 50, 30, 20, 40, 70, 60
Dept. of CSE(ET) 69
Data Structures A. Y. 2024 - 2025
c. TREE TRAVERSALS
There are three types of tree traversal techniques, These traversal in trees are types of depthfirst
search.
Now according to the inorder tree traversal method, we first traverse the left subtree of the
original tree. Remember, even while traversing the left subtree, we will follow the same process
i.e. left -> root -> right if the left child node of the original tree has furthermore child nodes. After
traversing the left subtree, we will add the result to the array as shown below.
Dept. of CSE(ET) 70
Data Structures A. Y. 2024 - 2025
After following the first step, we will traverse the root node of the original tree as shownbelow.
Lastly, we will traverse the right subtree following the same process i.e. left -> root -> right if the
right child node of the original tree has more than one child node.
Dept. of CSE(ET) 71
Data Structures A. Y. 2024 - 2025
According to the preorder traversal method, we will first traverse the root node of the original
tree and put it in the result array as shown in the figure below.
Then, we will traverse the left subtree of the original tree by calling the preorder traversal
method. Here we will recursively call the function preorder to maintain the same process of
traversal i.e root -> left -> right if the left child of the original tree has more than one child node
and add the answer in the array as shown in the figure below.
Dept. of CSE(ET) 72
Data Structures A. Y. 2024 - 2025
Lastly, we will traverse the right subtree of the original tree similarly like we did with the left
subtree and put the result in the answer array as shown below.
Using the postorder tree traversal method we first visit the left subtree of the original tree
followed by the right subtree and lastly the root node of the original tree. Below is the Python
code for Postorder Tree Traversal with recursion:
Calling left-subtree
Calling right-subtree
Visit root node
Let us consider the following example tree:
Dept. of CSE(ET) 73
Data Structures A. Y. 2024 - 2025
Using the postorder traversal method, we will first traverse the left subtree of the original tree.
Remember that we will follow the same process of traversing of left subtree i.e left -> right ->
root if the left subtree has more than one child node and then put the result in the answer array
as shown in the figure.
Later we will traverse the right subtree of the original tree similarly like we did with the left
subtree and add the answer in the result array as shown below.
Dept. of CSE(ET) 74
Data Structures A. Y. 2024 - 2025
And lastly, we will traverse the root node of the original tree and finish our traversal method as
shown in the figure below.
Dept. of CSE(ET) 75
Data Structures A. Y. 2024 - 2025
Complete binary tree: The root key has a sub-tree with two or no nodes, and all levelsof the
tree are filled.
Balanced binary tree: A balanced binary tree, also referred to as a height-balanced binary
tree, is defined as a binary tree in which the height of the left and right subtree of any node
differ by not more than 1.
Full binary tree: A full binary tree is defined as a binary tree in which all nodes have either zero
or two child nodes. Conversely, there is no node in a full binary tree, whichhas one child node.
a. IMPLEMENTATION
How to Insert a Node in the Binary Search Tree?
In a Binary Search Tree Python, while inserting a node, we need to take care of its property, i.e.,
left <= root <= right. In this, we try to insert a new key value in an existing Binary Search Tree
while retaining its properties and all the existing keys and values.
Algorithm:
Start from the root node.
When inserting an element, compare it to the root; if it is smaller than the root, call the left
subtree recursively; otherwise, call the right subtree recursively.
Simply insert the node at the left (if less than current) or the right (if not) after reachingthe end.
Dept. of CSE(ET) 76
Data Structures A. Y. 2024 - 2025
Dept. of CSE(ET) 77
Data Structures A. Y. 2024 - 2025
Time Complexity
Average cases : O(logn)
Worst case : O(n) , when the tree is unbalanced.
Space Complexity : O(n)
4. AVL TREES
AVL tree is a height-balanced binary search tree. That means, an AVL tree is also a binary search
tree but it is a balanced tree. A binary tree is said to be balanced if, the difference between the
heights of left and right subtrees of every node in the tree is either -1, 0 or +1. In other words, a
binary tree is said to be balanced if the height of left and right children of every node differ by
either -1, 0 or +1. In an AVL tree, every node maintains an extra information known as balance
factor. The AVL tree was introduced in the year 1962 by G.M. Adelson Velsky and E.M. Landis.
Balance factor of a node is the difference between the heights of the left and right subtrees of
that node. The balance factor of a node is calculated either height of left subtree - height of right
subtree (OR) height of right subtree - height of left subtree. In the following explanation,
Dept. of CSE(ET) 78
Data Structures A. Y. 2024 - 2025
we calculate as follows...
The below tree is AVL because the differences between the heights of left and right subtrees
for every node are less than or equal to 1.
Dept. of CSE(ET) 79
Data Structures A. Y. 2024 - 2025
Single RR(Right Right) Rotation - Here, every node of the tree moves toward the right from the
current position. Therefore, the parent becomes a left child in RR rotation. Letus see the below
example:
Double Rotation
Single rotation does not fix the LR rotation and RL rotation. For this, we require double rotation
involving three nodes. Therefore, double rotation is equivalent to the sequence of two single
rotations.
LR(Left-Right) Rotation - The LR rotation is the process where we perform a single left rotation
followed by a single right rotation. Therefore, first, every node moves towards the left and then
the node of this new tree moves one position towards the right. Let ussee the below example:
Dept. of CSE(ET) 80
Data Structures A. Y. 2024 - 2025
RL (Right-Left) Rotation - The RL rotation is the process where we perform a single rightrotation
followed by a single left rotation. Therefore, first, every node moves towards the right and then
the node of this new tree moves one position towards the left. Let us see the below example:
Python's standard library does not include an AVL tree implementation. There are, however, a
number of third-party libraries available that provide AVL tree functionality.
The 'avl tree' is a popular Python library for working with AVL trees, and it can be installed with
pip: pip install avl_tree.
Dept. of CSE(ET) 81
Data Structures A. Y. 2024 - 2025
rotation process and continue it until we are back at the root. Remember that the
modification of the balance factor must happen in a bottom-up fashion.
Ex: we have to delete the node '25' from the tree. As the node to be deleted does not have any
child node, we will simply remove the node from the tree:
Dept. of CSE(ET) 82
Data Structures A. Y. 2024 - 2025
5. B-TREES
A B-tree is a self-balancing tree data structure that maintains sorted data and allows searches,
sequential access, insertions, and deletions in logarithmic time.
B-TREE TRAVERSALS
Step-by-step algorithm:
Create a node with the name ‘BTreeNode‘ to create a default node with a list of keysand a list
of children nodes.
The b-tree class will be created which has two attributes ‘root‘ and ‘t‘, root represents
Dept. of CSE(ET) 83
Data Structures A. Y. 2024 - 2025
the root node, and ‘t‘ represents the minimum degree of the B-tree.
The display function in class ‘Btree‘ will be used to print to nodes of the tree in level- wise
format.
The final tree is created in the main function by inserting keys in the B-tree.
Now we will compare m with all the keys of the current node i.e. 10 and 20 but the firstkey of
this node is equal to m so we found the element.
Dept. of CSE(ET) 84
Data Structures A. Y. 2024 - 2025
Case 2: Deletion of an internal node - We search for the particular element to be deleted. This
node will be deleted and be replaced by its left child which comes just before it in the inorder
predecessor. Note that it is only possible if the left child has more than the minimum number of
keys. In case the left node doesn’t have more than the minimum number of keys. then the
deleted node is replaced by its right child whichcomes just after it in the inorder successor. Note
that it is only possible if the left child has more than the minimum number of keys. If both
children have a case where they only have the minimum number of keys, they are merged to
replace that deleted node.
Case 3: If the height of the tree reduces - If we witness case 2 repeatedly, then we will have to
merge the left and right nodes several times which can shrink the tree. In this case, children are
re-arranged in increasing order to maintain the height of the tree.
Dept. of CSE(ET) 85
Data Structures A. Y. 2024 - 2025
6. B+ TREES
A B+ tree is an advanced form of a self-balancing tree in which all the values are present in the
leaf level. An important concept to be understood before learning B+ tree is multilevel indexing.
In multilevel indexing, the index of indices is created as in figure below. It makes accessing the
data easier and faster.
Properties of a B+ Tree
The leaves are not connected with each other on a B-tree whereas they are connectedon a B+
tree.
Operations on a B+ tree are faster than on a B-tree.
Dept. of CSE(ET) 86
Data Structures A. Y. 2024 - 2025
SEARCHING ON A B+ TREE
The following steps are followed to search for data in a B+ Tree of order m. Let the data to be
searched be k.
Start from the root node. Compare k with the keys at the root node [k1, k2, k3,................. km - 1].
If k < k1, go to the left child of the root node.
Else if k == k1, compare k2. If k < k2, k lies between k1 and k2. So, search in the left child ofk2.
EXAMPLE:
Let us search k = 45 on the following B+ tree.
ii. Since k > 25, go to the right child. (Go to right of the root)
Dept. of CSE(ET) 87
Data Structures A. Y. 2024 - 2025
iii. Compare k with 35. Since k > 30, compare k with 45. (K Not Found)
v. k is found. (k is found)
Dept. of CSE(ET) 88