0% found this document useful (0 votes)
29 views

Course File of DS-1 BCA

Uploaded by

drpreeti.wctm
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
29 views

Course File of DS-1 BCA

Uploaded by

drpreeti.wctm
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 271

WORLD COLLEGE OF TECHNOLOGY & MANAGEMENT(WCTM)

MS. SWATI
FACULTY NAME

DEPARTMENT COMPUTER SCIENCE AND ENGINEERING


DATA STRUCTURES-1
SUBJECT

CLASS BACHELOR OF COMPUTER APPLICATIONS

SEMESTER 3rd SEMESTER

SESSION ODD (AUG 2024 - DEC 2024)


Contents

 Lesson Plan
 Syllabus
 Notes (Unit 1-4)
 Previous Year Question Papers
Lesson Plan
Name of the Faculty: Ms. Swati

Discipline BCA

Semester 3th SEMESTER

Subject DATA STRUCTURE-1

Lesson Plan Duration: 13 weeks (FROM AUG 2024 to DEC 2024)

Work Load (Lecture / Practical) per week (in hours): Lectures-05 Practical -02

THEORY
WEEK DATE
LECTURE DAY TOPIC (Including assignments and Tests)
Introduction: Elementary data organization, , Categories
1st of data structures, Data structure operations,
Applications of data structures, Algorithms complexity
1st and time-space tradeoff, Big-O notataion.
Strings: Introduction, Storing strings, String operations, Pattern matching
algorithms
2nd Data Structure definition
Data type vs. data structure
3rd

4th
Categories of data structures

5th
Data structure operations,

6th

2nd 7th

8th

9th

10th

7th Functions of each layer

3rd 8th Services and Protocols of each layer

9th TCP/IP: Introduction

10th History of TCP/IP


11th Layers of TCP/IP, Protocols
4th
12th Internet Protocol, Transmission Control Protocol

13th User Datagram Protocol,

5th 14th IP Addressing, IP address classes

15th Subnet Addressing

6th 16th Internet Control Protocols

17th ARP, RARP, ICMP

18th Domain Name System, Email – SMTP

19th POP,IMAP, FTP,


1
7th 20th Overview of IP version 6

21st Local Area Networks: Introduction to LANs

22nd Features of LANs, Components of LANs,

8th 23rd Usage of LANs, LAN Standards,

24th IEEE802 standards,

25th Channel Access Methods, Aloha, CSMA

9th 26th CSMA/CD,

27th Token Passing, Ethernet, Layer 2 & 3 switching

28th Fast Ethernet and Gigabit Ethernet, Token Ring

10th 29th LAN interconnecting devices: Hubs, Switches,

30th Bridges, Routers, Gateways.

31st Wide Area Networks: Introduction of WANs, Routing,

11th 32nd Congestion Control, WAN Technologies, Distributed Queue Dual


Bus (DQDB),
33rd Revision

34th Synchronous Digital Hierarchy (SDH)/ Synchronous Optical


th

BCA – 202 : DATA STRUCTURES – I

External Marks: 80
Internal Marks: 20
Time: 3 hours
Note: Examiner will be required to set NINE questions in all. Question Number 1 will consist of total
8 parts (short-answer type questions) covering the entire syllabus and will carry 16 marks. In addition to the
compulsory question there will be four units i.e. Unit-I to Unit-IV. Examiner will set two questions from
each Unit of the syllabus and each question will carry 16 marks. Student will be required to attempt FIVE
questions in all. Question Number 1 will be compulsory. In addition to compulsory question, student will
have to attempt four more questions selecting one question from each Unit.

UNIT – I
Introduction: Elementary data organization, Data Structure definition, Data type vs. data structure,
Categories of data structures, Data structure operations, Applications of data structures, Algorithms
complexity and time-space tradeoff, Big-O notataion.
Strings: Introduction, Storing strings, String operations, Pattern matching algorithms.
UNIT – II
Arrays: Introduction, Linear arrays, Representation of linear array in memory, address calculations,
Traversal, Insertions, Deletion in an array, Multidimensional arrays, Parallel arrays, Sparse arrays.
Linked List: Introduction, Array vs. linked list, Representation of linked lists in memory,Traversal,
Insertion, Deletion, Searching in a linked list, Header linked list, Circular linked list, Two-way linked list,
Threaded lists, Garbage collection, Applications of linked lists.
UNIT – III
Stack: Introduction, Array and linked representation of stacks, Operations on stacks, Applications of
stacks: Polish notation, Recursion.
Queues: Introduction, Array and linked representation of queues, Operations on queues, Deques, Priority
Queues, Applications of queues.
UNIT – IV
Tree: Introduction, Definition, Representing Binary tree in memory, Traversing binary trees, Traversal
algorithms using stacks.
Graph: Introduction, Graph theory terminology, Sequential and linked representation of graphs.
SUGGESTED READINGS
1. Seymour Lipschutz, “Data Structure”, Tata-McGraw-Hill
2. Horowitz, Sahni & Anderson-Freed, “Fundamentals of Data Structures in C”, Orient
Longman.
3. Trembley, J.P. And Sorenson P.G., “An Introduction to Data Structures With Applications”,
Mcgrraw- Hill International Student Edition, New York.
4. Mark Allen Weiss Data Structures and Algorithm Analysis In C, Addison- Wesley,(An Imprint
Of Pearson Education), Mexico City.Prentice- Hall Of India Pvt. Ltd., New Delhi.
5. Yedidyan Langsam, Moshe J. Augenstein, and Aaron M. Tenenbaum, “Data Structures Using
C”, Prentice- Hall of India Pvt. Ltd., New Delhi.
Note: Latest and additional good books may be suggested and added from time to time.

2
UNIT-1

Elementary Data organization:

Data are simply values or sets of values. A single unit of value is called a Data item.
Data items are divided into subgroups called Group items.

An Entity is something that has certain attributes which may be assigned values. An
entity with similar attributes is called an Entity set.

Eg:-
Entity : Employee
Attribute : Name , Age phone
Values : "ABC", 42,
9847092568
Entity set : All employees in an organization.
Meaningful or processed data is called information. The collection of data is organized into
the hierarchy of fields, records and files. A single elementary unit of information
representing an attribute of an entity is called a Field.

Records are the collection of field values of a given entity. Collection of records of the
entities in a given entity set is called a file. Each record may contain a certain field that
uniquely represents that record.
Such a field K is called a primary key.

Based on their length, records may be classified into two. They are,

 Fixed-length record : All record contain the same data items with the same
amount of space assigned to each items.
 Variance length record: Records may contain different length data items.

What is Data Structure?


The data structure name indicates itself that organizing the data in memory. There are
many ways of organizing the data in the memory as we have already seen one of the
data structures, i.e., array in C language. Array is a collection of memory elements in
which data is stored sequentially, i.e., one after another. In other words, we can say that
array stores the elements in a continuous manner. This organization of data is done with
the help of an array of data structures. There are also other ways to organize the data in
memory. Let's see the different types of data structures.

The data structure is not any programming language like C, C++, java, etc. It is a set of
algorithms that we can use in any programming language to structure the data in the
memory. 3
To structure the data in memory, 'n' number of algorithms were proposed, and all these
algorithms are known as Abstract data types. These abstract data types are the set of rules.

Why Learn Data Structure?

Data structure and algorithms are two of the most important aspects of computer
science. Data structures allow us to organize and store data, while algorithms allow us
to process that data in a meaningful way. Learning data structure and algorithms
will help you become a better programmer. You will be able to write code that is
more efficient and more reliable. You will also be able to solve problems more quickly
and more effectively.

Advantages of Data Structure –

1. Data structures allow storing the information on hard disks.


2. An appropriate choice of ADT (Abstract Data Type) makes the program
more efficient.
3. Data Structures are necessary for designing efficient algorithms.
4. It provides reusability and abstraction.
5. Using appropriate data structures can help programmers save a good
amount of time while performing operations such as storage, retrieval, or
processing of data.
6. Manipulation of large amounts of data is easier.

4
How Data Structure varies from Data Type:
We already have learned about data structure. Many times, what happens is
that people get confused between data type and data structure. So let’s see a
few differences between data type and data structure to make it clear.

Data Type Data Structure

The data type is the form of a Data structure is a collection of different


variable to which a value can be kinds of data. That entire data can be
assigned. It defines that the represented using an object and can be
particular variable will assign the used throughout the program.
values of the given data type only.

It can hold value but not data. It can hold multiple types of data
Therefore, it is dataless. within a single object.

The implementation of a data Data structure implementation is known as


type is known as abstract concrete implementation.
implementation.

There is no time complexity in the In data structure objects, time complexity


case of data types. plays an important role.

While in the case of data structures, the


In the case of data types, the
data and its value acquire the space in
value of data is not stored
the computer’s main memory. Also, a
because it only represents the
data structure can hold different kinds
type of data that can be stored.
and types of data within one single
object.

Data type examples are int, float, Data structure examples are stack,
double, etc. queue, tree, etc.

Classification of Data Structure:


Data structure has many different uses in our daily life. There are many
different data structures that are used to solve different mathematical and
logical problems. By using data structure, one can organize and process a
very large amount of data in a relatively short period. Let’s look at different
data structures that are used in different situations.
5
Classification of Data Structure

 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 the 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.

Need Of Data structure :


The structure of the data and the synthesis of the algorithm are relative to
each other. Data presentation must be easy to understand so the developer, as
6
well as the user, can make an efficient implementation of the operation.
Data structures provide an easy way of organizing, retrieving, managing, and
storing data. Here is a list of the needs for data.
1. Data structure modification is easy.

7
2. It requires less time.
3. Save storage memory space.
4. Data representation is easy.
5. Easy access to the large database.

Arrays:
An array is a linear data structure and it is a collection of items stored at
contiguous memory locations. The idea is to store multiple items of the same
type together in one place. It allows the processing of a large amount of data
in a relatively short period. The first element of the array is indexed by a
subscript of 0. There are different operations possible in an array, like
Searching, Sorting, Inserting, Traversing, Reversing, and Deleting.

Array

Characteristics of an Array:
An array has various characteristics which are as follows:
 Arrays use an index-based data structure which helps to identify
each of the elements in an array easily using the index.
 If a user wants to store multiple values of the same data type, then
the array can be utilized efficiently.
 An array can also handle complex data structures by storing
data in a two- dimensional array.
 An array is also used to implement other data structures like
Stacks, Queues, Heaps, Hash tables, etc.
 The search process in an array can be done very easily.
Operations performed on array:
 Initialization: An array can be initialized with values at the time of
declaration or later using an assignment statement.
 Accessing elements: Elements in an array can be accessed by their
index, which starts from 0 and goes up to the size of the array minus
8
one.
 Searching for elements: Arrays can be searched for a specific
element using linear search or binary search algorithms.

9
 Sorting elements: Elements in an array can be sorted in ascending or
descending order using algorithms like bubble sort, insertion sort, or
quick sort.
 Inserting elements: Elements can be inserted into an array at a specific
location, but this operation can be time-consuming because it requires
shifting existing elements in the array.
 Deleting elements: Elements can be deleted from an array by
shifting the elements that come after it to fill the gap.
 Updating elements: Elements in an array can be updated or
modified by assigning a new value to a specific index.
 Traversing elements: The elements in an array can be traversed in order,
visiting each element once.
These are some of the most common operations performed on arrays. The
specific operations and algorithms used may vary based on the requirements of
the problem and the programming language used.
Applications of Array:
Different applications of an array are as follows:
 An array is used in solving matrix problems.
 Database records are also implemented by an array.
 It helps in implementing a sorting algorithm.
 It is also used to implement other data structures like Stacks,
Queues, Heaps, Hash tables, etc.
 An array can be used for CPU scheduling.
 Can be applied as a lookup table in computers.
 Arrays can be used in speech processing where every speech signal is an
array.
 The screen of the computer is also displayed by an array. Here
we use a multidimensional array.
 The array is used in many management systems like a library,
students, parliament, etc.
 The array is used in the online ticket booking system. Contacts on a cell
phone are displayed by this array.
 In games like online chess, where the player can store his past moves
as well as current moves. It indicates a hint of position.
 To save images in a specific dimension in the android Like 360*1200
Real-Life Applications of Array:
 An array is frequently used to store data for mathematical computations.
 It is used in image processing.
1
0
 It is also used in record management.
 Book pages are also real-life examples of an array.
 It is used in ordering boxes as well.

1
1
Linked list:
A linked list is a linear data structure in which elements are not stored at
contiguous memory locations. The elements in a linked list are linked using
pointers as shown in the below image:
Types of linked lists:
 Singly-linked list
 Doubly linked list
 Circular linked list
 Doubly circular linked list

Linked List

Characteristics of a Linked list:


A linked list has various characteristics which are as follows:
 A linked list uses extra memory to store links.
 During the initialization of the linked list, there is no need to know
the size of the elements.
 Linked lists are used to implement stacks, queues, graphs, etc.
 The first node of the linked list is called the Head.
 The next pointer of the last node always points to NULL.
 In a linked list, insertion and deletion are possible easily.
 Each node of the linked list consists of a pointer/link which is the
address of the next node.
 Linked lists can shrink or grow at any point in time easily.
Operations performed on Linked list:
A linked list is a linear data structure where each node contains a value and a
reference to the next node. Here are some common operations performed on
linked lists:
 Initialization: A linked list can be initialized by creating a head
node with a reference to the first node. Each subsequent node
contains a value and a reference to the next node.
 Inserting elements: Elements can be inserted at the head, tail, or at a
specific position in the linked list.
1
2
 Deleting elements: Elements can be deleted from the linked list by
updating the reference of the previous node to point to the next node,
effectively removing the current node from the list.
 Searching for elements: Linked lists can be searched for a specific
element by starting from the head node and following the references
to the next nodes until the desired element is found.
 Updating elements: Elements in a linked list can be updated by
modifying the value of a specific node.
 Traversing elements: The elements in a linked list can be traversed by
starting from the head node and following the references to the next
nodes until the end of the list is reached.
 Reversing a linked list: The linked list can be reversed by updating the
references of each node so that they point to the previous node instead
of the next node.
These are some of the most common operations performed on linked lists. The
specific operations and algorithms used may vary based on the requirements of
the problem and the programming language used.
Applications of the Linked list:
Different applications of linked lists are as follows:
 Linked lists are used to implement stacks, queues, graphs, etc.
 Linked lists are used to perform arithmetic operations on long integers.
 It is used for the representation of sparse matrices.
 It is used in the linked allocation of files.
 It helps in memory management.
 It is used in the representation of Polynomial Manipulation
where each polynomial term represents a node in the linked
list.
 Linked lists are used to display image containers. Users can visit past,
current, and next images.
 They are used to store the history of the visited page.
 They are used to perform undo operations.
 Linked are used in software development where they indicate the
correct syntax of a tag.
 Linked lists are used to display social media feeds.
Real-Life Applications of a Linked list:
 A linked list is used in Round-Robin scheduling to keep track of
the turn in multiplayer games.
 It is used in image viewer. The previous and next images are linked,
1
3
and hence can be accessed by the previous and next buttons.
 In a music playlist, songs are linked to the previous and next songs.

1
4
Stack:
Stack is a linear data structure that follows a particular order in which the
operations are performed. The order is LIFO(Last in first out). Entering and
retrieving data is possible from only one end. The entering and retrieving of
data is also called push and pop operation in a stack. There are different
operations possible in a stack like reversing a stack using recursion, Sorting,

Deleting the middle element of a stack, etc.

Characteristics of a Stack:
Stack has various different characteristics which are as follows:
 Stack is used in many different algorithms like Tower of Hanoi, tree
traversal, recursion, etc.
 Stack is implemented through an array or linked list.
 It follows the Last In First Out operation i.e., an element that is
inserted first will pop in last and vice versa.
 The insertion and deletion are performed at one end i.e. from the top of
the stack.
 In stack, if the allocated space for the stack is full, and still anyone
attempts to add more elements, it will lead to stack overflow.
Applications of Stack:
Different applications of Stack are as follows:
 The stack data structure is used in the evaluation and conversion of
arithmetic expressions.
 Stack is used in Recursion.
 It is used for parenthesis checking.
 While reversing a string, the stack is used as well.
 Stack is used in memory management.
 It is also used for processing function calls.
 The stack is used to convert expressions from infix to postfix.
 The stack is used to perform undo as well as redo operations in word
processors.
1
5
 The stack is used in virtual machines like JVM.
 The stack is used in the media players. Useful to play the next and
previous song.

1
6
 The stack is used in recursion operations.

Operation performed on stack ;


A stack is a linear data structure that implements the Last-In-First-Out
(LIFO) principle. Here are some common operations performed on stacks:
 Push: Elements can be pushed onto the top of the stack, adding a new
element to the top of the stack.
 Pop: The top element can be removed from the stack by performing
a pop operation, effectively removing the last element that was
pushed onto the stack.
 Peek: The top element can be inspected without removing it from the
stack using a peek operation.
 IsEmpty: A check can be made to determine if the stack is empty.
 Size: The number of elements in the stack can be determined
using a size operation.
These are some of the most common operations performed on stacks. The
specific operations and algorithms used may vary based on the requirements of
the problem and the programming language used. Stacks are commonly used in
applications such as evaluating expressions, implementing function call stacks
in computer programs, and many others.
Real-Life Applications of Stack:
 Real life example of a stack is the layer of eating plates arranged one
above the other. When you remove a plate from the pile, you can
take the plate to the top of the pile. But this is exactly the plate that
was added most recently to the pile. If you want the plate at the
bottom of the pile, you must remove all the plates on top of it to
reach it.
 Browsers use stack data structures to keep track of previously visited sites.
 Call log in mobile also uses stack data structure.

Queue:
Queue is a linear data structure that follows a particular order in which the
operations are performed. The order is First In First Out(FIFO) i.e. the data item
stored first will be accessed first. In this, entering and retrieving data is not
done from only one end. An example of a queue is any queue of consumers for
a resource where the consumer that came first is served first. Different
operations are performed on a Queue like Reversing a Queue (with or without
using recursion), Reversing the first K elements of a Queue, etc. A few basic
1
7
operations performed In Queue are enqueue, dequeue, front, rear, etc.

1
8
Characteristics of a Queue:
The queue has various different characteristics which are as follows:
 The queue is a FIFO (First In First Out) structure.
 To remove the last element of the Queue, all the elements
inserted before the new element in the queue must be removed.
 A queue is an ordered list of elements of similar data types.
Applications of Queue:
Different applications of Queue are as follows:
 Queue is used for handling website traffic.
 It helps to maintain the playlist in media players.
 Queue is used in operating systems for handling interrupts.
 It helps in serving requests on a single shared resource, like a printer,
CPU task scheduling, etc.
 It is used in the asynchronous transfer of data e.g. pipes, file IO, and
sockets.
 Queues are used for job scheduling in the operating system.
 In social media to upload multiple photos or videos queue is used.
 To send an e-mail queue data structure is used.
 To handle website traffic at a time queues are used.
 In Windows operating system, to switch multiple applications.
Operation performed on queue:
A queue is a linear data structure that implements the First-In-First-Out (FIFO)
principle. Here are some common operations performed on queues:
 Enqueue: Elements can be added to the back of the queue, adding a
new element to the end of the queue.
 Dequeue: The front element can be removed from the queue by
performing a dequeue operation, effectively removing the first
element that was added to the queue.
 Peek: The front element can be inspected without removing it from
the queue using a peek operation.
 IsEmpty: A check can be made to determine if the queue is empty.
1
3
 Size: The number of elements in the queue can be determined
using a size operation.
These are some of the most common operations performed on queues. The
specific operations and algorithms used may vary based on the requirements
of the problem and the programming language used. Queues are commonly
used in applications such as scheduling tasks, managing communication
between processes, and many others.
Real-Life Applications of Queue:
 A real-world example of a queue is a single-lane one-way road,
where the vehicle that enters first will exit first.
 A more real-world example can be seen in the queue at the ticket
windows.
 A cashier line in a store is also an example of a queue.
 People on an escalator

Tree:
A tree is a non-linear and hierarchical data structure where the elements are
arranged in a tree-like structure. In a tree, the topmost node is called the root
node. Each node contains some data, and data can be of any type. It consists of
a central node, structural nodes, and sub-nodes which are connected via edges.
Different tree data structures allow quicker and easier access to the data as it
is a non-linear data structure. A tree has various terminologies like Node,
Root, Edge, Height of a tree, Degree of a tree, etc.
There are different types of Tree-like
 Binary Tree,
 Binary Search Tree,
 AVL Tree,
 B-Tree, etc.

1
4
Tree

Characteristics of a Tree:

1
5
The tree has various different characteristics which are as follows:
 A tree is also known as a Recursive data structure.
 In a tree, the Height of the root can be defined as the longest path
from the root node to the leaf node.
 In a tree, one can also calculate the depth from the top to any node.
The root node has a depth of 0.
Applications of Tree:
Different applications of Tree are as follows:
 Heap is a tree data structure that is implemented using arrays
and used to implement priority queues.
 B-Tree and B+ Tree are used to implement indexing in databases.
 Syntax Tree helps in scanning, parsing, generation of code, and
evaluation of arithmetic expressions in Compiler design.
 K-D Tree is a space partitioning tree used to organize points in K-
dimensional space.
 Spanning trees are used in routers in computer networks.
Operation performed on tree:
A tree is a non-linear data structure that consists of nodes connected by edges.
Here are some common operations performed on trees:
 Insertion: New nodes can be added to the tree to create a new
branch or to increase the height of the tree.
 Deletion: Nodes can be removed from the tree by updating the
references of the parent node to remove the reference to the current
node.
 Search: Elements can be searched for in a tree by starting from the root
node and traversing the tree based on the value of the current node
until the desired node is found.
 Traversal: The elements in a tree can be traversed in several
different ways, including in-order, pre-order, and post-order
traversal.
 Height: The height of the tree can be determined by counting the
number of edges from the root node to the furthest leaf node.
 Depth: The depth of a node can be determined by counting the
number of edges from the root node to the current node.
 Balancing: The tree can be balanced to ensure that the height of
the tree is minimized and the distribution of nodes is as even as
possible.
These are some of the most common operations performed on trees. The
1
6
specific operations and algorithms used may vary based on the requirements
of the problem and the programming language used. Trees are commonly used
in applications such as searching, sorting, and storing hierarchical data.
Real-Life Applications of Tree:

1
7
 In real life, tree data structure helps in Game Development.
 It also helps in indexing in databases.
 A Decision Tree is an efficient machine-learning tool, commonly used in
decision analysis. It has a flowchart-like structure that helps to
understand data.
 Domain Name Server also uses a tree data structure.
 The most common use case of a tree is any social networking site.
Graph:
A graph is a non-linear data structure that consists of vertices (or nodes) and
edges. It consists of a finite set of vertices and set of edges that connect a pair
of nodes. The graph is used to solve the most challenging and complex
programming problems. It has different terminologies which are Path, Degree,
Adjacent vertices, Connected components, etc.

Graph

Characteristics of Graph:
The graph has various different characteristics which are as follows:
 The maximum distance from a vertex to all the other vertices is
considered the Eccentricity of that vertex.
 The vertex having minimum Eccentricity is considered the central
point of the graph.
 The minimum value of Eccentricity from all vertices is considered the
radius of a connected graph.
Applications of Graph:
Different applications of Graphs are as follows:
 The graph is used to represent the flow of computation.
 It is used in modeling graphs.
 The operating system uses Resource Allocation Graph.
 Also used in the World Wide Web where the web pages represent the

1
8
nodes.
Operation performed on Graph:
A graph is a non-linear data structure consisting of nodes and edges. Here
are some common operations performed on graphs:

1
9
 Add Vertex: New vertices can be added to the graph to represent a new
node.
 Add Edge: Edges can be added between vertices to represent a
relationship between nodes.
 Remove Vertex: Vertices can be removed from the graph by
updating the references of adjacent vertices to remove the
reference to the current vertex.
 Remove Edge: Edges can be removed by updating the references of the
adjacent vertices to remove the reference to the current edge.
 Depth-First Search (DFS): A graph can be traversed using a depth-first
search by visiting the vertices in a depth-first manner.
 Breadth-First Search (BFS): A graph can be traversed using a
breadth-first search by visiting the vertices in a breadth-first
manner.
 Shortest Path: The shortest path between two vertices can be
determined using algorithms such as Dijkstra’s algorithm or A*
algorithm.
 Connected Components: The connected components of a graph can be
determined by finding sets of vertices that are connected to each
other but not to any other vertices in the graph.
 Cycle Detection: Cycles in a graph can be detected by checking for
back edges during a depth-first search.
These are some of the most common operations performed on graphs. The
specific operations and algorithms used may vary based on the requirements
of the problem and the programming language used. Graphs are commonly
used in applications such as computer networks, social networks, and routing
problems.
Real-Life Applications of Graph:
 One of the most common real-world examples of a graph is Google
Maps where cities are located as vertices and paths connecting those
vertices are located as edges of the graph.
 A social network is also one real-world example of a graph where
every person on the network is a node, and all of their friendships on
the network are the edges of the graph.
 A graph is also used to study molecules in physics and chemistry.

Algorithm & complexity:


An algorithm is a well-defined sequential computational technique that accepts a
value or a collection of values as input and produces the output(s) needed to
2
0
solve a problem.
Or we can say that an algorithm is said to be accurate if and only if it stops with
the proper output for each input instance.
NEED OF THE ALGORITHMS :

2
1
Algorithms are used to solve problems or automate tasks in a systematic
and efficient manner. They are a set of instructions or rules that guide the
computer or software in performing a particular task or solving a problem.
There are several reasons why we use algorithms:
 Efficiency: Algorithms can perform tasks quickly and accurately, making
them an essential tool for tasks that require a lot of calculations or
data processing.
 Consistency: Algorithms are repeatable and produce consistent
results every time they are executed. This is important when dealing
with large amounts of data or complex processes.
 Scalability: Algorithms can be scaled up to handle large datasets or
complex problems, which makes them useful for applications that
require processing large volumes of data.
 Automation: Algorithms can automate repetitive tasks, reducing the
need for human intervention and freeing up time for other tasks.
 Standardization: Algorithms can be standardized and shared among
different teams or organizations, making it easier for people to
collaborate and share knowledge.
Overall, algorithms are an essential tool for solving problems in a variety of
fields, including computer science, engineering, data analysis, finance, and
many others.
Example:
Consider a box where no one can see what’s happening inside, we say a black box.
We give input to the box and it gives us the output we need but the procedure
that we might need to know behind the conversion of input to desired output is
an ALGORITHM.
An algorithm is independent of the language used. It tells the programmer the
logic used to solve the problem. So, it is a logical step-by-step procedure that
acts as a blueprint to programmers.
Real-life examples that define the use of algorithms:
 Consider a clock. We know the clock is ticking but how does the
manufacturer set those nuts and bolts so that it keeps on moving
every 60 seconds, the min hand should move and every 60 mins, the
hour hand should move? So to solve this problem, there must be an
algorithm behind it.

2
2
 Seen someone cooking your favorite food for you? Is the recipe
necessary for it? Yes, it is necessary as a recipe is a sequential
procedure that turns a raw potato into a chilly potato. This is what an
algorithm is: following a procedure to get the desired output. Is the
sequence necessary to be followed? Yes, the sequence is the most
important thing that has to be followed to get what we want.

2
3
Types of Algorithms:
 Sorting algorithms: Bubble Sort, insertion sort, and many more. These
algorithms are used to sort the data in a particular format.
 Searching algorithms: Linear search, binary search, etc. These algorithms
are used in finding a value or record that the user demands.
 Graph Algorithms: It is used to find solutions to problems like finding
the shortest path between cities, and real-life problems like traveling
salesman problems.
Sorting algorithms are algorithms that take a collection of elements and rearrange them in a specified
order (e.g. ascending or descending). There are many different sorting algorithms, each with its own
strengths and weaknesses. Some of the most commonly used sorting algorithms include:
Bubble sort: A simple sorting algorithm that repeatedly steps through the list,
compares adjacent elements and swaps them if they are in the wrong order.
Insertion sort: A simple sorting algorithm that builds up the final sorted array
one item at a time, by comparing each new item to the items that have already
been sorted and inserting it in the correct position.
Selection sort: A simple sorting algorithm that repeatedly selects the
minimum element from the unsorted part of the array and moves it to the
end of the sorted part.
Merge sort: A divide-and-conquer sorting algorithm that works by dividing the
unsorted list into n sub-lists, sorting each sub-list, and then merging them
back into a single sorted list.
Quick sort: A divide-and-conquer sorting algorithm that works by selecting a
“pivot” element from the array and partitioning the other elements into two
sub-arrays, according to whether they are less than or greater than the pivot.
The sub-arrays are then sorted recursively.
Each of these algorithms has different time and space complexities, making
some more suitable for certain use cases than others.
Searching algorithms are algorithms that search for a particular element or value in a data structure (such
as an array or a linked list). Some of the most commonly used searching algorithms include:
Linear search: A simple searching algorithm that iterates through every element
of a list until it finds a match.
Binary search: A searching algorithm that works by dividing a sorted list in half
repeatedly, until the desired element is found or it can be determined that the
element is not present.
Jump search: A searching algorithm that works by jumping ahead by fixed steps
in the list, until a suitable candidate is found, and then performing a linear
search in the surrounding elements.
2
4
Interpolation search: A searching algorithm that works by using information about
the range of values in the list to estimate the position of the desired element
and then verifying that it is indeed present.

2
5
Hash table search: A searching algorithm that uses a hash function to map
elements to indices in an array, and then performs constant-time lookups in
the array to find the desired element.
Each of these algorithms has different time and space complexities, making
some more suitable for certain use cases than others. The choice of which
algorithm to use depends on the specific requirements of the problem, such as
the size of the data structure, the distribution of values, and the desired time
complexity.
Graph algorithms are a set of algorithms that are used to process, analyze and understand graph data
structures. Graphs are mathematical structures used to model relationships between objects, where the
objects are represented as vertices (or nodes) and the relationships between them are represented as
edges. Graph algorithms are used in a variety of applications such as network analysis, social network
analysis, recommendation systems, and in many other areas where understanding the relationships
between objects is important. Some of the common graph algorithms include:
Shortest Path algorithms (e.g. Dijkstra’s, Bellman-Ford, A*)
Minimum Spanning Tree algorithms (e.g. Kruskal, Prim)
Maximum Flow algorithms (e.g. Ford-Fulkerson, Edmonds-
Karp) Network Flow algorithms (e.g. Bipartite Matching)
Connectivity algorithms (e.g. Depth-first Search, Breadth-first Search)
Why do we use algorithms?
Consider two kids, Aman and Rohan, solving the Rubik’s Cube. Aman knows how to solve it
in a definite number of steps. On the other hand, Rohan knows that he will do it but is not
aware of the procedure. Aman solves the cube within 2 minutes whereas Rohan is still stuck
and by the end of the day, he somehow managed to solve it (might have cheated as the
procedure is necessary).
So the time required to solve with a procedure/algorithm is much more effective than that
without any procedure. Hence the need for an algorithm is a must.
In terms of designing a solution to an IT problem, computers are fast but not
infinitely fast. The memory may be inexpensive but not free. So, computing time
is therefore a bounded resource and so is the space in memory. So we should use
these resources wisely and algorithms that are efficient in terms of time and
space will help you do so.
Creating an Algorithm:
Since the algorithm is language-independent, we write the steps to
demonstrate the logic behind the solution to be used for solving a problem.
But before writing an algorithm, keep the following points in mind:
 The algorithm should be clear and unambiguous.
2
6
 There should be 0 or more well-defined inputs in an algorithm.

2
7
 An algorithm must produce one or more well-defined outputs that are
equivalent to the desired output. After a specific number of steps,
algorithms must ground to a halt.
 Algorithms must stop or end after a finite number of steps.
 In an algorithm, step-by-step instructions should be supplied, and they
should be independent of any computer code.
Know about Algorithm Complexity:
Complexity in algorithms refers to the amount of resources (such as time or
memory) required to solve a problem or perform a task. The most common
measure of complexity is time complexity, which refers to the amount of time
an algorithm takes to produce a result as a function of the size of the input.
Memory complexity refers to the amount of memory used by an algorithm.
Algorithm designers strive to develop algorithms with the lowest possible time
and memory complexities, since this makes them more efficient and scalable.
The complexity of an algorithm is a function describing the efficiency of the
algorithm in terms of the amount of data the algorithm must process.
Usually there are natural units for the domain and range of this function.
An algorithm is analyzed using Time Complexity and Space Complexity. Writing
an efficient algorithm help to consume the minimum amount of time for
processing the logic. For algorithm A, it is judged on the basis of two
parameters for an input of size n :
 Time Complexity: Time taken by the algorithm to solve the problem. It is
measured by calculating the iteration of loops, number of comparisons etc.
 Time complexity is a function describing the amount of time an algorithm takes
in terms of the amount of input to the algorithm.
 “Time” can mean the number of memory accesses performed, the number of
comparisons between integers, the number of times some inner loop is executed,
or some other natural unit related to the amount of real time the algorithm will
take.
 Space Complexity: Space taken by the algorithm to solve the problem. It includes
space used by necessary input variables and any extra space (excluding the space
taken by inputs) that is used by the algorithm. For example, if we use a hash table
(a kind of data structure), we need an array to store values so
 this is an extra space occupied, hence will count towards the space complexity
of the algorithm. This extra space is known as Auxiliary Space.
 Space complexity is a function describing the amount of memory(space)an
algorithm takes in terms of the amount of input to the algorithm.
2
8
 Space complexity is sometimes ignored because the space used is minimal and/ or
obvious, but sometimes it becomes an issue as time.

2
9
.The time complexity of the operations:
 The choice of data structure should be based on the time complexity of
the operations that will be performed.
 Time complexity is defined in terms of how many times it takes to run a
given algorithm, based on the length of the input.
 The time complexity of an algorithm is the amount of time it takes for
each statement to complete. It is highly dependent on the size of the processed
data.
 For example, if you need to perform searches frequently, you should use a
binary search tree.
.The space complexity of the operations:
 The choice of data structure should be based on the space complexity of
the operations that will be performed.
 The amount of memory used by a program to execute it is represented by its space
complexity.
 Because a program requires memory to store input data and temporal values while
running , the space complexity is auxiliary and input space.
 For example, if you need to store a lot of data, you should use an array.
cases in complexities:
There are two commonly studied cases of complexity in algorithms:
1. Best case complexity: The best-case scenario for an algorithm is the scenario
in which the algorithm performs the minimum amount of work (e.g. takes
the shortest amount of time, uses the least amount of memory, etc.).
2. Worst case complexity: The worst-case scenario for an algorithm is the scenario
in which the algorithm performs the maximum amount of work (e.g. takes the
longest amount of time, uses the most amount of memory, etc.).
In analyzing the complexity of an algorithm, it is often more informative to
study the worst- case scenario, as this gives a guaranteed upper bound on the
performance of the algorithm. Best-case scenario analysis is sometimes
performed, but is generally less important as it provides a lower bound that is
often trivial to achieve.
Advantages of Algorithms
 Easy to understand: Since it is a stepwise representation of a solution to
a given problem, it is easy to understand.
 Language Independent: It is not dependent on any programming
language, so it can easily be understood by anyone.
 Debug / Error Finding: Every step is independent / in a flow so it will be
3
0
easy to spot and fix the error.

3
1
 Sub-Problems: It is written in a flow so now the programmer can divide
the tasks which makes them easier to code.
Disadvantages of Algorithms
 Creating efficient algorithms is time-consuming and requires good logical
skills.
 Nasty to show branching and looping in algorithms.

Time Space Tradeoff:


It is a way of solving a problem or calculation in less time by using more
storage space (or memory), or by solving a problem in very little space by
spending a long time.
It is a case where an algorithm or program trades increased space usage with
decreased time. Here, space refers to the data storage consumed in
performing a given task
(RAM, HDD, etc), and time refers to the time consumed in performing a given
task (computation time or response time)
1. Best Case : The minimum possible value of f(n) is called the best case.
2. Average Case : The expected value of f(n).
3. Worst Case : The maximum value of f(n) for any key possible input.
Example:
The time complexity of merge sort is O(nlogn) in all cases i.e. best, worst and
average but requires an auxiliary array. Quicksort has O(nlogn) time complexity
for best and average case and O(n^2) for worst case but does not require
auxiliary space. So while sorting, depending on your constraint, you can choose
which one to use.

Big O notation:

Asymptotic analysis is the study of how the algorithm's performance changes when the
order of the input size changes. We employ big-notation to asymptotically confine the
expansion of a running time to within constant factors above and below. The amount of
time, storage, and other resources required to perform an algorithm determine its
efficiency. Asymptotic notations are used to determine the efficiency. For different types
of inputs, an algorithm's performance may vary. The performance will fluctuate as the
input size grows larger.

When the input tends towards a certain value or a limiting value, asymptotic notations
are used to represent how long an algorithm takes to execute. When the input array is
already sorted, for example, the time spent by the method is linear, which is the best
3
2
scenario.

However, when the input array is in reverse order, the method takes the longest
(quadratic) time to sort the items, which is the worst-case scenario. It takes average
time when the input array is not sorted or in reverse order. Asymptotic notations are
used to represent these durations.

3
3
Big O notation classifies functions based on their growth rates: several functions with the
same growth rate can be written using the same O notation. The symbol O is utilized
since a function's development rate is also known as the order of the function. A large O
notation description of a function generally only offers an upper constraint on the
function's development rate.

It would be convenient to have a form of asymptotic notation that means "the running
time grows at most this much, but it could grow more slowly." We use "big-O" notation
for just such occasions.

Advantages of Big O Notation


o When examining the efficiency of an algorithm using run-time inputs, asymptotic analysis
is quite useful. Otherwise, if we do it manually with passing test cases for various inputs,
performance may vary as the algorithm's input changes.
o When the algorithm is executed on multiple computers, its performance varies. As a
result, we pick an algorithm whose performance does not change much as the number of
inputs increases. As a result, a mathematical representation provides a clear
understanding of the top and lower boundaries of an algorithm's run-time.

Examples
Now let us have a deeper look at the Big O notation of various examples:

O(1):

1. void constantTimeComplexity(int arr[])


2. {
3. printf("First element of array = %d",arr[0]);
4. }

This function runs in O(1) time (or "constant time") relative to its input. The input array
could be 1 item or 1,000 items, but this function would still just require one step.

O(n):

1. void linearTimeComplexity(int arr[], int size)


2. {
3. for (int i = 0; i < size; i++)
4. {
5. printf("%d\n", arr[i]);
6. }
7. }

3
4
This function runs in O(n) time (or "linear time"), where n is the number of items in the
array. If the array has 10 items, we have to print 10 times. If it has 1000 items, we have
to print 1000 times.

O(n^2):

1. void quadraticTimeComplexity(int arr[], int size)


2. {
3. for (int i = 0; i < size; i++)
4. {
5. for (int j = 0; j < size; j++)
6. {
7. printf("%d = %d\n", arr[i], arr[j]);
8. }
9. }
10. }

Here we're nesting two loops. If our array has n items, our outer loop runs n times, and
our inner loop runs n times for each iteration of the outer loop, giving us n^2 total prints.
If the array has 10 items, we have to print 100 times. If it has 1000 items, we have to
print 1000000 times. Thus this function runs in O(n^2) time (or "quadratic time").

O(2^n):

1. int fibonacci(int num)


2. {
3. if (num <= 1) return num;
4. return fibonacci(num - 2) + fibonacci(num - 1);
5. }

An example of an O(2^n) function is the recursive calculation of Fibonacci numbers.


O(2^n) denotes an algorithm whose growth doubles with each addition to the input data
set. The growth curve of an O(2^n) function is exponential - starting off very shallow,
then rising meteorically.

Strings in Data Structures


Strings and functions in C
A string is a collection of characters. We'll learn how to declare strings, operate
with strings in C programming, and use pre-defined string handling routines.
We'll look at how to compare two strings, concatenate strings, copy one string to
another, and execute other string operations. The pre-defined functions in the
"string.h" header file can be used to conduct similar operations. You must include
the string.h file in your C programme in order to utilise these string functions.
2
5
Declaration of Strings
 char str[] = { ‘J’ , ’A’ , ’V’ , ’A’ , ’T’ , ’P’ , ’O’ , ’I’ , ’N’ , ’T’ , ’\0’ };
 char str[] = { “JAVATPOINT” };
o In this form of declaration, '0' will automatically insert at the end.

What is NULL Char “\0”?


'\0' represents the end of the string. It is also referred as String terminator & Null
Character.
In C programming, string Input/Output

Using the Printf() and Scanf() functions in C, read and write Strings.

2
6
#include <stdio.h>

#include <string.h>

int main()

/* String Declaration*/

char str[20];

printf("Enter your string here:");

/* The input string is read and stored in variable str. Because the array name acts
as the base address, we may use str instead of &str here.*/

2
7
scanf("%s", str);

/*Displaying String*/

printf("%s",str);

return 0;

The following output should be generated by this programme:


Output
Enter your string here: JavaTPoint

JavaTPoint

IMPORTANT: For strings input/output, the %s format specifier is utilised.


In C, use the gets() and puts() methods to read and write strings.
#include <stdio.h>

#include <string.h>

int main()

/* String Declaration*/

char str[20];

/* Console display using puts */

puts("Enter your string here:");

/*Input using gets*/

2
8
gets(str);

puts(str);

return 0;

String functions in C
 strlen() - Returns the string's length.
 strlwr() - This command lowercases a string.
 istrupr() - It transforms a string to uppercase .
 strcat() - appends one string to the end of another.
 strncat() - This command appends the first n characters of a string to
the end of another string.
 strcpy() - to copy a string into another string.
 strncpy() - This command copies the first n characters of a string into another.
 strcmp() - function that compares two strings.
 strncmp() - compares two strings' first n characters.
 strcmpi() - This function compares two strings without regard to case I
indicates that this function ignores case).
 stricmp() - compares two strings regardless of case (identical to strcmpi).
 strnicmp() – This function compares the first n characters of two strings.
There is no difference in case.
 strdup() - This command duplicates a string.
 strchr() - Finds the first instance of a character in a string.
 strrchr() - Returns the position of a given character in a string.
 strstr() - Looks for the first instance of a string in another string.
 strset() - This command changes all characters in a string to a specific
character.
 strnset() - This command changes the first n characters of a string to
a specific character.
 strrev() - It reverses a string
2
9
1.strlen is a C string function.
Syntax
size_t strlen(const char *str)
size_t is an unsigned short. It returns the length of the string minus the ending
character (char
'0').
#include <stdio.h>

#include <string.h>

int main()

char string_a[] = "JAVATPOINT";

printf("Length of string string_a: %d", strlen(string_a));

return 0;

The following output should be generated by this programme:


Output
Length of string string_a: 10

strlen vs sizeof
While strlen delivers the length of the string contained in the array, sizeof
returns the array's entire allocated size. So, if I analyse the same example
again, the following sentences will provide the numbers below.
Because the array size is 20, strlen(str1) returned 13. sizeof(str1) would return
20. (see the first statement in main function).
2.strnlen is a C string function.
Syntax
size_t strnlen(const char *str, size_t maxlen)
size_t is an unsigned short. If the length of the string is less than the number
supplied for maxlen (maximum length), it returns the length of string value;
otherwise, it returns the maxlen value.

3
0
#include <stdio.h>

#include <string.h>

int main()

char string_a[20] = "JavaTPoint";

printf("Length of string string_a when maximum length is 30: %d", strnlen(string_a,


30));

3
1
printf("Length of string string_a when maximum length is 5: %d", strnlen(string_a,
5));

return 0;

The following output should be generated by this programme:


Output
Length of string string_a when maximum length is 30: 10

Length of string string_a when maximum length is 5: 5

Have you observed that even though the string length was 10, the second printf
statement
only returned 5 because the maxlen was 5.
3.strcmp is a C string function.
Syntax
int strcmp(const char *string_1, const char *string_2)
The function compares the two strings and returns the result as an integer. This
function will
return 0 if two strings are equal, else it will return a negative or positive number
depending on the comparison.
A negative number would occur if string2 OR string1 is a substring of string2.
If string1 is greater than string2, the result will be positive.
When using this method to compare strings, you'll obtain 0(zero) if string1 ==
string2.
#include <stdio.h>

#include <string.h>

int main()

char string_1[20] = "JavaTPoint";

char string_2[20] = "JavaTPoint.COM";

if (strcmp(string_1, string_2) ==0)

printf("string 1 and string 2 are equal");

}else

printf("string 1 and string 2 are different");

return 0;

}
3
0
The following output should be generated by this programme:
Output
string 1 and string 2 are different

4.strncmp is a C string function.


Syntax
int strncmp(const char *string_1, const char *string_2, size_t n)
Unassigned short is represented by size_t. It compares both strings till they
reach n characters, or the first n characters of both strings.
#include <stdio.h>

#include <string.h>

int main()

char string_1[20] = "JavaTPoint";

char string_2[20] = "JavaTPoint.COM";

/* below the first nine characters of string 1 and string 2 are compared.*/

if ( strncmp(string_1, string_2, 9) == 0 )

printf("string 1 and string 2 are equal");

}else

printf("string 1 and 2 are different");

return 0;

The following output should be generated by this programme:


Output
String_1 and string_2 are equal

5.strcat is a C string function.


Syntax
char *strcat(char *string_1, char *string_2)
It joins two strings together and returns the resulting string.
#include <stdio.h>

#include <string.h>

int main()
3
1
{

char string_1[10] = "Java";

char string_2[10] = "TPoint";

strcat(string_1,string_2);

printf("Output string after concatenation: %s", string_1);

return 0;

The following output should be generated by this programme:


Output
Output string after concatenation: JavaTPoint

6.strncat is a C string function.


Syntax
char *strncat(char *string_1, char *string_2, int n)
It joins n characters from str2 to the string str1. At the conclusion of the
concatenated text, a terminator char ('0') will always be attached.
#include <stdio.h>

#include <string.h>

int main()

char string_1[10] = "Java";

char string_2[10] = "TPoint";

strncat(string_1,string_2, 3);

printf("Concatenation using strncat: %s", string_1);

return 0;

The following output should be generated by this programme:


Output
Concatenation using strncat: JavaTPo

7.strcpy is a C string function.


Syntax
char *strcpy( char *str1, char *str2)
It replicates str2 into str1, including the last character (terminator char '0').
#include <stdio.h>

#include <string.h>
3
2
int main()

char string_1[30] = "string 1";

char string_2[30] = "string 2 : I’m gonna copied into string_1";

/* this function has copied string_2 into string_1*/

strcpy(string_1,string_2);

printf("String string_1 is: %s", string_1);

return 0;

The following output should be generated by this programme:


Output
String s1 is: string 2: I’m gonna copied into s1

8.strncpy is a C string function.


Syntax
char *strncpy( char *string_1, char *string_2, size_t n)
n is an integer and size_t is an unassigned short.

 Case 1: If the length of string_2 is more than n, it simply copies the first n
characters of string_2 into string_1.
 Case 2: If the length of string_2 is more than n, it copies all of the
characters from string_2 into string_1 and appends extra terminator chars
('0') to increase the length of string_1 to n.

#include <stdio.h>

#include <string.h>

int main()

char string_1[30] = "string 1";

char string_2[30] = "string 2: I’m using strncpy now";

/* This method copied the first twelve characters of string_2 into string_1.*/

strncpy(string_1,string_2, 12);

printf("String string_1 is: %s", string_1);

return 0;
3
3
}

The following output should be generated by this programme:


Output
String string_1 is: string 2: I’
9.strchr is a C string function.
Syntax
char *strchr(char *string_1, int ch)
It searches string string 1 for character ch (you may be asking why I gave the data
type of ch
as int in the preceding description; don't worry, I didn't make a mistake; it should
only be int). When we use strchr, whatever character we pass in is internally
transformed to an integer for improved searching.)
#include <stdio.h>

#include <string.h>

int main()

char mystring[30] = "This is an example of function implementation strchr";

printf ("%s", strchr(mystring, 'f'));

return 0;

The following output should be generated by this programme:


Output
f function strchr

10.strrchr is a C string function.


Syntax
char *strrchr(char *string_1, int ch)
It is identical to the function strchr, with the exception that it searches the
string in reverse order. You may have guessed why there is an additional r in
strrchr, and you are correct. Consider the following example:

3
4
#include <stdio.h>

#include <string.h>

int main()

char mystring30] = " This is an example of function implementation strchr ";

printf ("%s", strrchr(mystring, 'f'));

return 0;

3
5
}

The following output should be generated by this programme:


Output
function strchr
Why is output different from strchr? It is because it began looking from the end of
the string
and discovered the first 'f' in function rather than the first 'of'.
11. strstr is a C string function.
Syntax
char *strstr(char *str, char *srch_term)
It is similar to strchr, except that it looks for the string srch term rather than a single
character.
#include <stdio.h>

#include <string.h>

int main()

char mystring[70] = "String Function in C at JavaTPoint.com";

printf ("Output string is: %s", strstr(mystring, 'Java'));

return 0;

The following output should be generated by this programme:


Output
Output string is: JavaTPoint.com
You may also use this method instead of strchr since you can pass a single character
in place
of the search term string.

String storage

Generally three types of structures are used to store strings.

 Fixed length storage : In a fixed-length structure, each line of print is viewed as a


record. All records have the same length, i.e. where each record accommodates the
same number of characters. Since data are frequently input on terminals with 80
column images or using 80 column cards.
Advantages of fixed length storage/Record-oriented:
1. The ease of accessing data from any given record.
2. The ease of updating data in any given record(as long as the length of the
new data does not exceed the record length).
Disadvantages of fixed length storage/Record-oriented:
1. Time is wasted reading an entire record if most of the storage consists of
inessential blank
spaces.
2. Certain records may acquire more space than variable.
3. When the correction consists of more or fewer characters than the original
3
text, changing a misspelled word requires the entire record to be changed.
 Variable-length storage: Variable length strings can be stored in memory cells either
by using a marker like $$ or \0 to represent the end of the string or by listing the
length of the string as an additional element in a pointer array.
 Linked Storage: We use a linked list to store strings. It helps to easily delete, change,
and insert words, sentences even paragraphs in the text. A linked list is an ordered
sequence of nodes, where each node contains a link which has the address of the
next node in the list. Here each node is assigned one character or a fixed number of

3
6
The complexity of the pattern can be measured by the number of comparisons between
characters in pattern PAT and characters of string TEXT. Let N k denote the number of
comparisons takes place inside the inner loop when PAT is compared with substring W k.

Here L is the position of where first PAT appears, or L=MAX if PAT doesn’t appear in TEXT.

The data size for the algorithm, when length of TEXT is s and length of PAT is r, is,

When every character of PAT expect the last matches every SUBSTRING W k

we know that, s=n-r.

the maximum value of C(n) occurs when r=(n+1)/4. Substituting the value of r in the formula,

3
7
UNIT-2

Array
An array is a list of a finite number ‘n’ of homogeneous data element such that
a. The elements of the array are reference respectively by an index set
consisting of n consecutive numbers.
b. The element of the array are respectively in successive memory locations.

The number n of elements is called the length or size of the array. The length or
thenumbers of elements of the array can be obtained from the index set by the
formula When LB = 0,
Length = UB – LB
+ 1When LB = 1,
Length = UB
Where,
UB is the largest index called the Upper
Bound LB is the smallest index, called
the Lower Bound

Representation of linear arrays in memory

Let LA be a linear array in the memory of the computer. The memory of the
computer is simply a sequence of address location as shown below,

1000
1001
1002
1003
1004

LOC (LA [K]) = address of the element LA [K] of the

array LAThe elements of LA are stored in successive

memory cells.
The computer does not keep track of the address of every element of LA, but
needsto keep track only the address of the first element of LA denoted by,
3
8
Base (LA) and called the base address of LA.

Using the base address of LA, the computer calculates the address of any element
ofLA by the formula
LOC (LA[K]) = Base(LA) + w(K – lower bound)

Where, w is the number of words per memory cell for the array LA.

ARRAY OPERATIONS

1. Traversing
Let A be a collection of data elements stored in the memory of the
computer. Suppose if the contents of the each elements of array A needs to be
printed or to count the numbers of elements of A with a given property can be
accomplished by Traversing.
Traversing is a accessing and processing each element in the array exactly once.

Algorithm 1: (Traversing a Linear Array)

Hear LA is a linear array with the lower bound LB and upper bound UB. This
algorithm traverses LA applying an operation PROCESS to each element of
LA using while loop.
1. [Initialize Counter] set K:= LB
2. Repeat step 3 and 4 while K ≤ UB
3. [Visit element] Apply PROCESS to LA
[K]
4. [Increase counter] Set K:= K + 1
[End of step 2 loop]
5. Exit
Program
#include<stdio.h>
#include<conio.h>
int main()
{
int A[100],K=0,UB;
printf(“Enter the Array size less than 100:
“); scanf(“%d”,&UB);
printf(“Enter the elements in array:
\n”);for(K=0;K<UB;K++)
3
9
{
scanf(“%d”,&A[K]);
}
printf(“The Traverse of array
is:\n”);for(K=0;K<UB;K++)
{
printf(“%d\n”,A[K]);
}
getch();
return 0;
}

2. Inserting

Let A be a collection of data elements stored in the memory of the


computer. Inserting refers to the operation of adding another element
to the collection A.

Inserting an element at the “end” of the linear array can be easily done
provided the memory space allocated for the array is large enough to
accommodate the additional element.

Inserting an element in the middle of the array, then on average, half of the
elements must be moved downwards to new locations to accommodate the
new element and keep the order of the other elements.

Algorithm:

INSERT (LA, N, K, ITEM)

Here LA is a linear array with N elements and K is a positive integer such that K
≤ N.This algorithm inserts an element ITEM into the Kt h position in LA.
1. [Initialize counter] set J:= N

2. Repeat step 3 and 4 while J ≥ K

3. [Move Jt h element downward] Set LA [J+1] :=


LA[J]
4. [Decrease counter] set J:= J – 1

4
0
[End of step 2 loop]

5. [Insert element] set LA[K]:= ITEM

6. [Reset N] set N:= N+1

7. Exit

Program
#include <stdio.h>

int main()
{
int array[100], position, c, n, value;
printf("Enter number of elements in
array\n"); scanf("%d", &n);
printf("Enter %d elements\n",
n);for (c = 0; c < n; c++)
scanf("%d", &array[c]);
printf("Enter the location where you wish to insert an
element\n");scanf("%d", &position);
printf("Enter the value to
insert\n");scanf("%d", &value);
for (c = n - 1; c >= position - 1;
c--)array[c+1] = array[c];
array[position-1] = value;
printf("Resultant array is\n");
for (c = 0; c <= n; c++)
printf("%d\n", array[c]);
return 0;
}
3. Deleting

Deleting refers to the operation of removing one element to the collection A.

Deleting an element at the “end” of the linear array can be easily done with
difficulties.

If element at the middle of the array needs to be deleted, then each


subsequent elements be moved one location upward to fill up the array.

4
1
Algorithm

DELETE (LA, N, K, ITEM)

Here LA is a linear array with N elements and K is a positive integer such that K ≤
N.this algorithm deletes the Kt h element from LA

1. Set ITEM:= LA[K]

2. Repeat for J = K to N – 1

[Move J + 1 element upward] set LA[J]:=


LA[J+1]
[End of loop]

3. [Reset the number N of elements in LA] set N:= N – 1

4. Exit

program
#include <stdio.h>

int main()
{
int array[100], position, c, n;
printf("Enter number of elements in
array\n");scanf("%d", &n);
printf("Enter %d elements\n",
n);for (c = 0; c < n; c++)
scanf("%d", &array[c]);
printf("Enter the location where you wish to delete
element\n");scanf("%d", &position);
if (position >= n+1)
printf("Deletion not
possible.\n");
else
{
for (c = position - 1; c < n -
1; c++)array[c] = array[c+1];
printf("Resultant array:\n");
4
2
for (c = 0; c < n - 1;
c++) printf("%d\n",
array[c]);
}
return 0;
}

Multidimensional Arrays

In C, we can define multidimensional arrays in simple words as array of arrays. Data in


multidimensional arrays are stored in tabular form (in row major order).
General form of declaring N-dimensional arrays:
data_type array_name[size1][size2].. [sizeN];
data_type: Type of data to be stored in the
array. Here data_type is valid C data type
array_name: Name of the array
size1, size2,... ,sizeN: Sizes of the dimensions
Examples:
Two dimensional
array:int
two_d[10][20];
Three dimensional array:
int three_d[10][20][30];
Size of multidimensional arrays
Total number of elements that can be stored in a multidimensional array can be
calculated by multiplying the size of all the dimensions.
For example:
The array int x[10][20] can store total (10*20) = 200 elements.
Similarly array int x[5][10][20] can store total (5*10*20) = 1000 elements.

Example : Sum of two matrices using Two


dimensional arrays

4
3
// C program to find the sum of two matrices of order 2*2

#include
<stdio.h> int
main()
{
float a[2][2], b[2][2], c[2][2];
int i, j;

// Taking input using nested for loop


printf("Enter elements of 1st matrix\
n");for(i=0; i<2; ++i)
for(j=0; j<2; ++j)
{
printf("Enter a%d%d: ", i+1,
j+1); scanf("%f", &a[i][j]);
}

// Taking input using nested for loop


printf("Enter elements of 2nd matrix\n");

4
4
for(i=0; i<2; +
+i) for(j=0;
j<2; ++j)
{
printf("Enter b%d%d: ", i+1,
j+1); scanf("%f", &b[i][j]);
}

// adding corresponding elements of two


arrays for(i=0; i<2; ++i)
for(j=0; j<2; ++j)
{
c[i][j] = a[i][j] + b[i][j];
}

// Displaying the sum


printf("\nSum Of
Matrix:");

for(i=0; i<2; +
+i) for(j=0;
j<2; ++j)
{
printf("%.1f\t", c[i][j]);

if(j==1)
printf("\n");
}
return 0;
}
4
5
Ouput

4
6
Enter elements of 1st
matrix
Enter a11:
2;
Enter a12:
0.5;
Enter a21: -
1.1;
Enter a22:
2;
Enter elements of 2nd
matrix
Enter b11:
0.2;
Enter b12:
0;
Enter b21:
0.23;
Enter b22:
23;

Sum Of
Matrix:
2. 0.
2 5
- 25.
0.9 0

Representation of 2D arrays in memory

A 2D array’s elements are stored in continuous memory locations. It can be


represented in memory using any of the following two ways:
1. Column-Major Order

4
7
2. Row-Major Order
1. Column-Major Order:
In this method the elements are stored column wise, i.e. m elements of first
column arestored in first m locations, m elements of second column are stored in
next m locations and so on. E.g.
A 3 x 4 array will stored as below:

2. Row-Major Order:
In this method the elements are stored row wise, i.e. n elements of first row are
storedin first n locations, n elements of second row are stored in next n locations
and so on. E.g.

4
8
A 3 x 4 array will stored as below:

Address Calculation in Double (Two) Dimensional Array:


While storing the elements of a 2-D array in memory, these are allocated
contiguous memory locations. Therefore, a 2-D array must be linearized so as to
enable their storage. There are two alternatives to achieve linearization: Row-
Major and Column- Major.

4
9
Address of an element of any array say “A[ I ][ J ]” is calculated in two forms as given:
(1) Row Major System (2) Column Major System
Row Major System:
The address of a location in Row Major System is calculated using the following
formula:
Address of A [ I ][ J ] = B + W * [ N * ( I – Lr ) + ( J – Lc ) ]
Column Major System:
The address of a location in Column Major System is calculated using the
followingformula:
Address of A [ I ][ J ] Column Major Wise = B + W * [( I – Lr ) + M *
( J – Lc )]Where,
B = Base address
I = Row subscript of element whose address is to be found
J = Column subscript of element whose address is to be
foundW = Storage Size of one element stored in the array
(in byte)
Lr = Lower limit of row/start row index of matrix, if not given assume 0 (zero)

5
0
Lc = Lower limit of column/start column index of matrix, if not given assume 0
(zero) M = Number of row of the given matrix
N = Number of column of the given matrix

Introduction to Sorting

Sorting is nothing but arranging the data in ascending or descending order. The
term sorting came into picture, as humans realised the importance of searching
quickly.

There are so many things in our real life that we need to search for, like a
particular record in database, roll numbers in merit list, a particular telephone
number in telephone directory, a particular page in a book etc. All this would have
been a mess if the data was kept unordered and unsorted, but fortunately
the conceptof sorting came into existence, making it easier for everyone to
arrange data in an order, hence making it easier to search.

Sorting arranges data in a sequence which makes searching easier.

Sorting Efficiency

If you ask me, how will I arrange a deck of shuffled cards in order, I would say, I
willstart by checking every card, and making the deck as I move on.

It can take me hours to arrange the deck in order, but that's how I will

do it.Well, thank god, computers don't work like this.

5
1
Since the beginning of the programming age, computer scientists have been
working onsolving the problem of sorting by coming up with various different
algorithms to sort data.

The two main criterias to judge which algorithm is better than the other have been:

1. Time taken to sort the given data.

2. Memory Space required to do so.

Different Sorting Algorithms

There are many different techniques available for sorting, differentiated by their
efficiency and space requirements. Following are some sorting techniques which
we will be covering in next few tutorials.

1. Bubble Sort

2. Insertion Sort

3. Selection Sort

Bubble sort

Bubble sort is a simple sorting algorithm. This sorting algorithm is comparison-

based algorithm in which each pair of adjacent elements is compared and the

elements are swapped if they are not in order. This algorithm is not suitable for

large data sets as its average and worst case complexity are of Ο(n 2) where n is the

number of items.

5
2
HowBubbleSortWorks?

We take an unsorted array for our example. Bubble sort takes Ο(n2) time so

we'rekeeping it short and precise.

Bubble sort starts with very first two elements, comparing them to check which

one isgreater.

In this case, value 33 is greater than 14, so it is already in sorted locations. Next,

wecompare 33 with 27.

We find that 27 is smaller than 33 and these two values must be swapped.

The new array should look like this −

Next we compare 33 and 35. We find that both are in already sorted positions.

5
3
Then we move to the next two values, 35 and 10.

We know then that 10 is smaller 35. Hence they are not sorted.

We swap these values. We find that we have reached the end of the array. After

oneiteration, the array should look like this −

To be precise, we are now showing how an array should look like after each

iteration.After the second iteration, it should look like this −

Notice that after each iteration, at least one value moves at the end.

And when there's no swap required, bubble sorts learns that an array is

completelysorted.

5
4
Now we should look into some practical aspects of bubble sort.
Algorithm

We assume list is an array of n elements. We further assume that swap function

swapsthe values of the given array elements.

begin

BubbleSort(list) for

all elements of list

if list[i] > list[i+1]

swap(list[i],

list[i+1])

end if

end for

program

#include <stdio.h>

int main()

int data[100],i,n,step,temp;

printf("Enter the number of elements to be sorted: ");

scanf("%d",&n);

5
5
for(i=0;i<n;++i)
{
printf("%d. Enter element:
",i+1); scanf("%d",&data[i]);
}

for(step=0;step<n-1;++step)
for(i=0;i<n-step-1;++i)
{
if(data[i]>data[i+1]) /* To sort in descending order, change > to < in this line. */
{
temp=data[i];
data[i]=data[i+1];
data[i+1]=temp;
}
}
printf("In ascending order: ");
for(i=0;i<n;++i)
printf("%d ",data[i]);
return 0;
}

5
6
Complexity Analysis of Bubble Sort
In Bubble Sort, n-1 comparisons will be done in the 1st pass, n-2 in 2nd pass, n-3
in 3rdpass and so on. So the total number of comparisons will be,

(n-1) + (n-2) + (n-3) + .+ 3 + 2 + 1


Sum = n(n-1)/2
i.e O(n2)
Hence the time complexity of Bubble Sort is O(n2).
The main advantage of Bubble Sort is the simplicity of the algorithm.
The space complexity for Bubble Sort is O(1), because only a single additional
memoryspace is required i.e. for temp variable.
Also, the best case time complexity will be O(n), it is when the list is already
sorted.Following are the Time and Space complexity for the Bubble Sort
algorithm.

 Worst Case Time Complexity [ Big-O ]: O(n2)


 Best Case Time Complexity [Big-omega]: O(n)
 Average Time Complexity [Big-theta]: O(n2)
 Space Complexity: O(1)

Selection sort

 Selection sort is a simple sorting algorithm. This sorting algorithm is an in-place


comparison-based algorithm in which the list is divided into two parts, the sorted
part at the left end and the unsorted part at the right end. Initially, the sorted part is
empty and the unsorted part is the entire list.
 The smallest element is selected from the unsorted array and swapped with the
leftmost element, and that element becomes a part of the sorted array. This
process continues moving unsorted array boundary by one element to the right.
 This algorithm is not suitable for large data sets as its average and worst case
complexities are of Ο(n2), where n is the number of items.
5
7
 How SelectionSortWorks?
 Consider the following depicted array as an example.

 For the first position in the sorted list, the whole list is scanned sequentially. The
first position where 14 is stored presently, we search the whole list and find that
10 is the lowest value.

 So we replace 14 with 10. After one iteration 10, which happens to be the
minimum value in the list, appears in the first position of the sorted list.

 For the second position, where 33 is residing, we start scanning the rest of the list
in a linear manner.

 We find that 14 is the second lowest value in the list and it should appear at the
second place. We swap these values.

 After two iterations, two least values are positioned at the beginning in a sorted
manner.

 The same process is applied to the rest of the items in the array.

5
8
 Following is a pictorial depiction of the entire sorting process −

 Now, let us learn some programming aspects of selection sort.


 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 element

5
9
 Step 5 − Repeat until list is sorted

#include

<stdio.h>int

main()

int array[100], n, c, d, position,

swap; printf("Enter number of

elements\n");scanf("%d", &n);

printf("Enter %d integers\n",

n);for (c = 0; c < n; c++)

scanf("%d", &array[c]);

for (c = 0; c < (n - 1); c++)

position = c;

for (d = c + 1; d < n; d++)

if (array[position] >

array[d])position = d;

if (position != c)
6
0
{

swap = array[c];

array[c] =

array[position];

array[position] = swap;

printf("Sorted list in ascending

order:\n");for (c = 0; c < n; c++)

printf("%d\n",

array[c]);return 0;

Complexity Analysis of Selection Sort


Selection Sort requires two nested for loops to complete itself, one for loop is in
the function selectionSort, and inside the first loop we are making a call to another
function indexOfMinimum, which has the second(inner) for loop.
Hence for a given input size of n, following will be the time and space complexity
for selection sort algorithm:
Worst Case Time Complexity [ Big-O ]:
O(n2)Best Case Time Complexity [Big-
omega]:(n2)Average Time Complexity
[Big-theta]:(n2) Space Complexity: O(1)

6
1
Insertion Sort Algorithm

This is an in-place comparison-based sorting algorithm. Here, a sub-list is

maintained which is always sorted. For example, the lower part of an array is

maintained to be sorted. An element which is to be 'insert'ed in this sorted sub-list,

has to find its appropriate place and then it has to be inserted there. Hence the

name, insertion sort.

The array is searched sequentially and unsorted items are moved and inserted into

the sorted sub-list (in the same array). This algorithm is not suitable for large data

sets asits average and worst case complexity are of Ο(n2), where n is the number

of items.
HowInsertionSortWorks?

We take an unsorted array for our example.

Insertion sort compares the first two elements.

It finds that both 14 and 33 are already in ascending order. For now, 14 is in

sorted sub-list.

Insertion sort moves ahead and compares 33 with 27.


6
2
And finds that 33 is not in the correct position.

It swaps 33 with 27. It also checks with all the elements of sorted sub-list. Here

we see that the sorted sub-list has only one element 14, and 27 is greater than 14.

Hence, the sorted sub-list remains sorted after swapping.

By now we have 14 and 27 in the sorted sub-list. Next, it compares 33 with 10.

These values are not in a sorted order.

So we swap them.

However, swapping makes 27 and 10 unsorted.

6
3
Hence, we swap them too.

Again we find 14 and 10 in an unsorted order.

We swap them again. By the end of third iteration, we have a sorted sub-list of 4 items.

This process goes on until all the unsorted values are covered in a sorted sub-list.

Nowwe shall see some programming aspects of insertion sort.


Algorithm

Now we have a bigger picture of how this sorting technique works, so we can

derivesimple steps by which we can achieve insertion sort.

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

Insertion sort algorithm implementation in C


/* Insertion sort ascending order */

6
4
#include <stdio.h>

int main()

int n, array[1000], c, d, temp;

printf("Enter number of elements\n");

scanf("%d", &n);

printf("Enter %d integers\n",

n);for (c = 0; c < n; c++)

scanf("%d", &array[c]);

for (c = 1 ; c <= n - 1;

c++) {d = c;

while ( d > 0 && array[d-1] >

array[d]) {temp = array[d];

array[d] = array[d-

1];array[d-1] =

temp;
d--;
}
}
printf("Sorted list in ascending order:\

n");for (c = 0; c <= n - 1; c++) {


printf("%d\n", array[c]);

6
5
}
return 0;

Complexity Analysis of Insertion Sort


As we mentioned above that insertion sort is an efficient sorting algorithm, as it
does not run on preset conditions using for loops, but instead it uses one while
loop, which avoids extra steps once the array gets sorted.
Even though insertion sort is efficient, still, if we provide an already sorted array to
the insertion sort algorithm, it will still execute the outer for loop, thereby requiring
n steps to sort an already sorted array of n elements, which makes its best case
time complexity a linear function of n.
Worst Case Time Complexity [ Big-O ]:
O(n2) Best Case Time Complexity [Big-
omega]: O(n)Average Time Complexity
[Big-theta]: O(n2) Space Complexity:
O(1)

Searching Algorithms

1 linear search
2 binary search

linear search

In Linear Search the list is searched sequentially and the position is returned if the
key element to be searched is available in the list, otherwise -1 is returned. The
search in Linear Search starts at the beginning of an array and move to the end,
testing for a match at each item.
All the elements preceding the search element are traversed before the search
element is traversed. i.e. if the element to be searched is in position 10, all
elements form 1-9 are checked before 10
Linear search is a very simple search algorithm. In this type of search, a
sequential search is made over all items one by one. Every item is checked and if
a match is found then that particular item is returned, otherwise the search
6
6
continues till the

6
7
end of the data collection.
Assume the element 45 is searched from a sequence of sorted elements 12, 18, 25,
36, 45, 48, 50. The Linear search starts from the first element 12, since the value to
be searched is not 12 (value 45), the next element 18 is compared and is also not
45, bythis way all the elements before 45 are compared and when the index is 5,
the element 45 is compared with the search value and is equal, hence the element is
found and the element position is 5.

LinearsearchAlgorithm
Linear Search ( 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

program
#include<stdio.h
>
int linear_search(int a[],
int, int);main()
{
6
8
int array[100], search, c, n, position;
printf("Enter the number of elements in
array\n");scanf("%d",&n);
printf("Enter %d numbers\n",
n);for ( c = 0 ; c < n ; c++ )
scanf("%d",&array[c]);
printf("Enter the number to
search\n");scanf("%d",&search);
position = linear_search(array, n,
search);if ( position == -1 )
printf("%d is not present in array.\
n", search);else
printf("%d is present at location %d.\n", search, position+1);
return 0;
}
int linear_search(int a[], int n, int find)
{
int c;
for ( c = 0 ; c < n ; c++ )
{
if (a[c) ==
find )return
c;
}
return -1;
}

6
9
Binary search
Binary search is a fast search algorithm with run-time complexity of Ο(log n).
This search algorithm works on the principle of divide and conquer. For this
algorithm to work properly, the data collection should be in the sorted form.
Binary search looks for a particular item by comparing the middle most item of
the collection. If a match occurs, then the index of item is returned. If the middle
item is greater than the item, then the item is searched in the sub-array to the left
of the middle item. Otherwise, the item is searched for in the sub-array to the right
of the middle item. This process continues on the sub-array as well until the size
of the subarray reduces to zero.
How Binary Search Works?
For a binary search to work, it is mandatory for the target array to be sorted. We
shall learn the process of binary search with a pictorial example. The following is
our sorted array and let us assume that we need to search the location of value 31
using binary search.

First, we shall determine half of the array by using this formula −

mid = low + (high - low) / 2

Here it is, 0 + (9 - 0 ) / 2 = 4 (integer value of 4.5). So, 4 is the mid of the array.

Now we compare the value stored at location 4, with the value being searched, i.e.

31. We find that the value at location 4 is 27, which is not a match. As the value is

greater than 27 and we have a sorted array, so we also know that the target value

must be in the upper portion of the array.

7
0
We change our low to mid + 1 and find the new mid value again.

low = mid + 1
mid = low + (high - low) / 2

Our new mid is 7 now. We compare the value stored at location 7 with our target

value31.

The value stored at location 7 is not a match, rather it is more than what we are

lookingfor. So, the value must be in the lower part from this location.

Hence, we calculate the mid again. This time it is 5.

We compare the value stored at location 5 with our target value. We find that it

is amatch.

7
1
We conclude that the target value 31 is stored at location 5.

Binary search halves the searchable items and thus reduces the count of

comparisonsto be made to very less numbers.


Algorithm
Algorithm
BINSRCH (a, n,
x)
// array a(1 : n) of elements in increasing order, n 0,
// determine whether ‘x’ is present, and if so, set j such that x = a(j)
// else return j
{
low :=1 ; high :=n ;
while (low < high)
do
{
mid :=|(low + high)/2|
if (x < a [mid]) then high:=mid –
1; else if (x > a [mid]) then
low:= mid + 1else return mid;
}
return 0;
}
program

#include<stdio.h
>
#include<stdlib.
h> #define size
10

7
2
int binsearch(int[], int, int,

7
3
int);int main() {
int num, i, key,
position;int low, high,
list[size];

printf("\nEnter the total number of


elements");scanf("%d", &num);

printf("\nEnter the elements of list


:");for (i = 0; i < num; i++) {
scanf("%d", &list[i]);
}

low = 0;
high = num - 1;

printf("\nEnter element to be searched :


");scanf("%d", &key);

position = binsearch(list, key, low, high);

if (position != -1) {
printf("\nNumber present at %d", (position + 1));
} else
printf("\n The number is not present in the
list"); return (0);
}

// Binary Search function


int binsearch(int a[], int x, int low, int
high) {int mid;

if (low >
high)return
-1;

mid = (low + high) /

2;if (x == a[mid]) {
return (mid);
} else if (x < a[mid]) {
7
4
binsearch(a, x, low, mid
- 1);
} else {
binsearch(a, x, mid + 1, high);
}
}

Sparse Matrix and its representations


A matrix is a two-dimensional data object made of m rows and n
columns, therefore having total m x n values. If most of the elements of
the matrix have 0 value, then it is called a sparse matrix.
Why to use Sparse Matrix instead of simple matrix ?
 Storage: There are lesser non-zero elements than zeros and
thus lesser memory can be used to store only those elements.
 Computing time: Computing time can be saved by logically
designing a data structure traversing only non-zero elements..
Example:
0 0 3 0 4
0 0 5 7 0
0 0 0 0 0
0 2 6 0 0
Representing a sparse matrix by a 2D array leads to wastage of lots of
memory as zeroes in the matrix are of no use in most of the cases. So,
instead of storing zeroes with non-zero elements, we only store non-zero
elements. This means storing non- zero elements with triples- (Row, Column,
value).

2D array is used to represent a sparse matrix in which there are three


rows named as
 Row: Index of row, where non-zero element is located
 Column: Index of column, where non-zero element is located
 Value: Value of the non zero element located at index – (row,column)

7
5
// C++ program for Sparse Matrix Representation
// using Array
#include<stdio.h>

int main()
{
// Assume 4x5 sparse
matrixint
sparseMatrix[4][5] =
{
{0 , 0 , 3 , 0 , 4 },
{0 , 0 , 5 , 7 , 0 },
{0 , 0 , 0 , 0 , 0 },
{0 , 2 , 6 , 0 , 0 }
};

int size = 0;
for (int i = 0; i < 4; i++)
for (int j = 0; j < 5; j++)
if (sparseMatrix[i][j] !
= 0)size++;

// number of columns in compactMatrix (size) must be


// equal to number of non - zero elements in
// sparseMatrix
int compactMatrix[3][size];

// Making of
new matrixint k
= 0;
for (int i = 0; i < 4; i++)
for (int j = 0; j < 5; j++)
if (sparseMatrix[i][j] != 0)
7
6
{

7
7
for (int i=0; i<3; i++)
{compactMatrix[0][k] = i; compactMatrix[1][k] = j; compactMatrix[2][k] =
sparseMatrix[i][j];k++;
for (int j=0; j<size; j++)
printf("%d ", compactMatrix[i][j]);

printf("\n");
}
return 0;
}

7
8
Linked List
o Linked List can be defined as collection of objects called nodes that are randomly stored in
the memory.
o A node contains two fields i.e. data stored at that particular address and the pointer which
contains the address of the next node in the memory.
o The last node of the list contains pointer to the null.

Uses of Linked List


o The list is not required to be contiguously present in the memory. The node can reside any
where in the memory and linked together to make a list. This achieves optimized
utilization of space.
o list size is limited to the memory size and doesn't need to be declared in advance.
o Empty node can not be present in the linked list.
o We can store values of primitive types or objects in the singly linked list.

Why use linked list over array?


Till now, we were using array data structure to organize the group of elements that are
to be stored individually in the memory. However, Array has several advantages and
disadvantages which must be known in order to decide the data structure which will be
used throughout the program.

Array contains following limitations:

1. The size of array must be known in advance before using it in the program.
2. Increasing size of the array is a time taking process. It is almost impossible to expand the
size of the array at run time.
3. All the elements in the array need to be contiguously stored in the memory. Inserting any
element in the array needs shifting of all its predecessors.

Linked list is the data structure which can overcome all the limitations of an array. Using
linked list is useful because,

7
9
1. It allocates the memory dynamically. All the nodes of linked list are non-contiguously
stored in the memory and linked together with the help of pointers.
2. Sizing is no longer a problem since we do not need to define its size at the time of
declaration. List grows as per the program's demand and limited to the available memory
space.

Head and Tail pointer

The Head pointer keeps track of the starting node of the linked list. And the Tail
pointer point to the end of the linked list. A tail pointer is a must if we want to
insert the node at the end of the list in constant time. Linked lists are not
indexable so for inserting any node we need to traverse the whole list to get the
location to insert the node. As the pointer modification needs to be done.

A real-world example of uses of Linked List –

Consider an example in which we have to design a song playlist, and in that


playlist, songs are to be added dynamically. So, if we use an array here, then
that is not a memory-efficient solution. Because we need to predefine the size of
the playlist. And the playlist doesn’t need to contain a fixed number of songs.

So what we can do here is, we can create different nodes for each of the song IDs.
And then we somehow need to connect these nodes. So we can use a pointer to
connect that. So here we can use the concept of the linked list to solve this
problem.

The below image shows the high-level idea of the linked list for the playlist of songs.

8
0
Types of Linked Lists

Following are the types of Linked List

1. Singly Linked List


2. Doubly Linked List
3. Circular Linked List
4. Doubly Circular Linked List

1. Singly Linked List

 Each node has a single link to another node is called Singly Linked List.
 Singly Linked List does not store any pointer any reference to the previous node.
 Each node stores the contents of the node and a reference to the next node in the
list.
 In a singly linked list, last node has a pointer which indicates that it is the last node.
It requires a reference to the first node to store a single linked list.
 It has two successive nodes linked together in linear way and contains address of the
next node to be followed.
 It has successor and predecessor. First node does not have predecessor while last
node does not have successor. Last node have successor reference as NULL.
 It has only single link for the next node.
 In this type of linked list, only forward sequential movement is possible, no direct
access is allowed.

 In the above figure, the address of the first node is always store in a reference node
known as Head or Front. Reference part of the last node must be null.

8
1
2. Doubly Linked List

 Doubly linked list is a sequence of elements in which every node has link to its
previous node and next node.
 Traversing can be done in both directions and displays the contents in the whole list.

In the above figure, Link1 field stores the address of the previous node and Link2 field
stores the address of the next node. The Data Item field stores the actual value of that
node. If we insert a data into the linked list, it will be look like as follows:

Important Note:
First node is always pointed by head. In doubly linked list, previous field of the first node is
always NULL (it must be NULL) and the next field of the last must be NULL.

In the above figure we see that, doubly linked list contains three fields. In this, link of two
nodes allow traversal of the list in either direction. There is no need to traverse the list to
find the previous node. We can traverse from head to tail as well as tail to head.

Advantages of Doubly Linked List


 Doubly linked list can be traversed in both forward and backward directions.
 To delete a node in singly linked list, the previous node is required, while in doubly
linked list, we can get the previous node using previous pointer.
 It is very convenient than singly linked list. Doubly linked list maintains the links for
bidirectional traversing.
Disadvantages of Doubly Linked List
 In doubly linked list, each node requires extra space for previous pointer.

8
2
 All operations such as Insert, Delete, Traverse etc. require extra previous pointer to
be maintained.

3. Circular Linked List

 Circular linked list is similar to singly linked list. The only difference is that in circular
linked list, the last node points to the first node in the list.
 It is a sequence of elements in which every element has link to its next element in the
sequence and has a link to the first element in the sequence.

 In the above figure we see that, each node points to its next node in the sequence
but the last node points to the first node in the list. The previous element stores the
address of the next element and the last element stores the address of the starting
element. It forms a circular chain because the element points to each other in a
circular way.
 In circular linked list, the memory can be allocated when it is required because it has
a dynamic size.
 Circular linked list is used in personal computers, where multiple applications are
running. The operating system provides a fixed time slot for all running applications
and the running applications are kept in a circular linked list until all the applications
are completed. This is a real life example of circular linked list.
 We can insert elements anywhere in circular linked list, but in the array we cannot
insert elements anywhere in the list because it is in the contiguous memory.

4. Doubly Circular Linked List

 Doubly circular linked list is a linked data structure which consists of a set of
sequentially linked records called nodes.

8
3
 Doubly circular linked list can be conceptualized as two singly linked lists formed from
the same data items, but in opposite sequential orders.

 The above diagram represents the basic structure of Doubly Circular Linked List. In
doubly circular linked list, the previous link of the first node points to the last node
and the next link of the last node points to the first node.
 In doubly circular linked list, each node contains two fields called links used to
represent references to the previous and the next node in the sequence of nodes.

Arrays vs Linked list

Array Linked list

An array is a collection of elements of a A linked list is a collection of objects known as


similar data type. a node where node consists of two parts, i.e.,
data and address.

Array elements store in a contiguous Linked list elements can be stored


memory location. anywhere in the memory or randomly
stored.
Array works with a static memory. Here The Linked list works with dynamic memory.
static memory means that the memory Here, dynamic memory means that the
size is fixed and cannot be changed at the memory size can be changed at the run time
run time. according to our requirements.

Array elements are independent of each Linked list elements are dependent on each
other. other. As each node contains the address of
the next node so to access the next node, we
need to access its previous node.

Array takes more time while Linked list takes less time while
performing any operation like performing any operation like insertion,
insertion, deletion, etc. deletion, etc.
8
4
Accessing any element in an array is Accessing an element in a linked list is
faster as the element in an array can be slower as it starts traversing from the first
directly accessed through the index. element of the linked list.

In the case of an array, memory is In the case of a linked list, memory is allocated
allocated at compile-time. at run time.

Memory utilization is inefficient in the Memory utilization is efficient in the case of a


array. For example, if the size of the linked list as the memory can be allocated or
array is 6, and array consists of 3 deallocated at the run time according to our
elements only then the rest of the space requirement.
will be unused.

Representation of linked list in memory

In memory the linked list is stored in scattered cells (locations). The memory for each node is
allocated dynamically means as and when required. So the Linked List can increase as per the
user wish and the size is not fixed, it can vary.

Suppose first node of linked list is allocated with an address 1008. Its graphical
representation looks like the figure shown below:

Suppose next node is allocated at an address 506, so the list becomes,

Suppose next node is allocated with an address with an address 10,s the list become,

8
5
The other way to represent the linked list is as shown below:

In the above representation the data stored in the linked list is “INDIA”, the information part of
each node contains one character. The external pointer root points to first node’s address 1005.
The link part of the node containing information I contains 1007, the address of next node. The
last node of the list contains an address 0, the invalid address or NULL address.

Operations of Linked list

The basic linked list operations are:

 Traversal – Access the nodes of the list.


 Insertion – Adds a new node to an existing linked list.
 Deletion – Removes a node from an existing linked list.
 Search – Finds a particular element in the linked list.
Traverse a Linked List

Accessing the nodes of a linked list in order to process it is called traversing a linked list.
Normally we use the traverse operation to display the contents or to search for an
element in the linked list. The algorithm for traversing a linked list is given below.

Algorithm: Traverse

Step 1: [INITIALIZE] SET PTR = HEAD


Step 2: Repeat Steps 3 and 4 while PTR !=
NULL Step 3: Apply process to PTR -> DATA
Step 4: SET PTR = PTR-
>NEXT [END OF LOOP]
Step 5: EXIT

8
6
 We first initialize PTR with the address of HEAD. Now the PTR points to the first node
of the linked list.
 A while loop is executed, and the operation is continued until PTR reaches the last
node (PTR = NULL).
 Apply the process(display) to the current node.
 Move to the next node by making the value of PTR to the address of next node.

Inserting Elements to a Linked List

We will see how a new node can be added to an existing linked list in the following cases.

1. The new node is inserted at the beginning.


2. The new node is inserted at the end.
3. The new node is inserted after a given node.
Insert a Node at the beginning of a Linked list

Consider the linked list shown in the figure. Suppose we want to create a new node with
data 24 and add it as the first node of the list. The linked list will be modified as follows.

 Allocate memory for new node and initialize its DATA part to 24.
 Add the new node as the first node of the list by pointing the NEXT part of the new node
to HEAD.
 Make HEAD to point to the first node of the list.
Algorithm: InsertAtBeginning

Step 1: IF AVAIL = NULL

8
7
Write
OVERFLOW
Go to Step 7

8
8
[END OF IF]
Step 2: SET NEW_NODE = AVAIL
Step 3: SET AVAIL = AVAIL ->
NEXT Step 4: SET NEW_NODE ->
DATA = VAL Step 5: SET
NEW_NODE -> NEXT = HEAD
Step 6: SET HEAD = NEW_NODE
Step 7: EXIT

Note that the first step of the algorithm checks if there is enough memory available to create
a new node. The second, and third steps allocate memory for the new node.

Insert a Node at the end of a Linked list

Take a look at the linked list in the figure. Suppose we want to add a new node with data 24
as the last node of the list. Then the linked list will be modified as follows.

 Allocate memory for new node and initialize its DATA part to 24.
 Traverse to last node.
 Point the NEXT part of the last node to the newly created node.
 Make the value of next part of last node to NULL.
Algorithm: InsertAtEnd

Step 1: IF AVAIL = NULL


Write
OVERFLOW
Go to Step 10
[END OF IF]
Step 2: SET NEW_NODE = AVAIL

8
9
Step 3: SET AVAIL = AVAIL ->
NEXT Step 4: SET NEW_NODE ->
DATA = VAL Step 5: SET
NEW_NODE -> NEXT = NULL
Step 6: SET PTR = HEAD
Step 7: Repeat Step 8 while PTR -> NEXT !=
NULL Step 8: SET PTR = PTR -> NEXT
[END OF LOOP]
Step 9: SET PTR -> NEXT =
NEW_NODE Step 10: EXIT

Insert a Node after a given Node in a Linked list

The last case is when we want to add a new node after a given node. Suppose we want to
add a new node with value 24 after the node having data 9. These changes will be done
in the linked list.
 Allocate memory for new node and initialize its DATA part to 24.
 Traverse the list until the specified node is reached.
 Change NEXT pointers accordingly.

9
0
Algorithm: InsertAfterAnElement

Step 1: IF AVAIL = NULL


Write
OVERFLOW
Go to Step 12
[END OF IF]
Step 2: SET NEW_NODE = AVAIL
Step 3: SET AVAIL = AVAIL ->
NEXT Step 4: SET NEW_NODE -
> DATA = VAL Step 5: SET PTR
= HEAD
Step 6: SET PREPTR = PTR
Step 7: Repeat Steps 8 and 9 while PREPTR -> DATA !
= NUM Step 8: SET PREPTR = PTR
Step 9: SET PTR = PTR ->
NEXT [END OF LOOP]
Step 1 : PREPTR -> NEXT =
NEW_NODE Step 11: SET
NEW_NODE -> NEXT = PTR Step
12: EXIT

Deleting Elements from a Linked List

1. The first node is deleted.


2. The last node is deleted.
3. The node after a given node is deleted.

Delete a Node from the beginning of a Linked list

Suppose we want to delete a node from the beginning of the linked list. The list has to
be modified as follows:

9
1
 Check if the linked list is empty or not. Exit if the list is empty.
 Make HEAD points to the second node.
 Free the first node from memory.
Algorithm: DeleteFromBeginning

Step 1: IF HEAD =
NULL Write
UNDERFLOW
Go to Step
5 [END OF
IF]
Step 2: SET PTR = HEAD
Step 3: SET HEAD = HEAD ->
NEXT Step 4: FREE PTR
Step 5: EXIT

Delete last Node from a Linked list

9
2
 Traverse to the end of the list.
 Change value of next pointer of second last node to NULL.
 Free last node from memory.
Algorithm: DeleteFromEnd

Step 1: IF HEAD =
NULL Write
UNDERFLOW
Go to Step
8 [END OF
IF]
Step 2: SET PTR = HEAD
Step 3: Repeat Steps 4 and 5 while PTR -> NEXT !=
NULL Step 4: SET PREPTR = PTR
Step 5: SET PTR = PTR ->
NEXT [END OF LOOP]
Step 6: SET PREPTR -> NEXT =
NULL Step 7: FREE PTR
Step 8: EXIT
Here we use two pointers PTR and PREPTR to access the last node and the second last node.

Delete the Node after a given Node in a Linked list

9
3
 Traverse the list upto the specified node.
 Change value of next pointer of previous node(9) to next pointer of current node(10).
Algorithm:
DeleteAfterANode
Step 1: IF HEAD = NULL
Write UNDERFLOW
Go to Step
10 [END OF
IF]
Step 2: SET PTR =
HEAD Step 3: SET
PREPTR = PTR
Step 4: Repeat Steps 5 and 6 while PREPTR -> DATA !
= NUM Step 5: SET PREPTR = PTR
Step 6: SET PTR = PTR ->
NEXT [END OF LOOP]
Step 7: SET TEMP = PTR
Step 8: SET PREPTR -> NEXT = PTR -
> NEXT Step 9: FREE TEMP
Step 10 : EXIT

Search

Finding an element is similar to a traversal operation. Instead of displaying data, we


have to check whether the data matches with the item to find.
 Initialize PTR with the address of HEAD. Now the PTR points to the first node of the
linked list.
 A while loop is executed which will compare data of every node with item.
 If item has been found then control goes to last step.
Algorithm:
Search
Step 1: [INITIALIZE] SET PTR = HEAD
Step 2: Repeat Steps 3 and 4 while PTR !=
NULL Step 3: If ITEM = PTR -> DATA
SET POS = PTR
Go To Step
5 ELSE
SET PTR = PTR ->
NEXT [END OF IF]
[END OF LOOP]
Step 4: SET POS =
NULL Step 5: EXIT

9
4
Header Linked List

A header node is a special node that is found at the beginning of the list. A list
that contains this type of node, is called the header-linked list. This type of list
is useful when information other than that found in each node is needed.
For example, suppose there is an application in which the number of items in a list is
often calculated. Usually, a list is always traversed to find the length of the list.
However, if the current length is maintained in an additional header node that
information can be easily obtained.
Types of Header Linked List
1. Grounded Header Linked List
It is a list whose last node contains the NULL pointer. In the header
linked list the start pointer always points to the header node. start -
> next =
NULL indicates that the grounded header linked list is empty. The
operations that are possible on this type of linked list are Insertion,
Deletion, and Traversing.

9
5
2. Circular Header Linked List
A list in which last node points back to the header node is called circular
linked

9
6
list. The chains do not indicate first or last nodes. In this case,
external pointers provide a frame of reference because last node of a
circular linked list does not contain the NULL pointer. The possible
operations on this type of linked list are Insertion, Deletion and
Traversing.

Applications of Header Linked List


Polynomials
 The header linked lists are frequently used to maintain the
polynomials in memory. The header node is used to represent the
zero polynomial.
 Suppose we have
F(x) = 5x5 – 3x3 + 2x2 + x1 +10x0
 From the polynomial represented by F(x) it is clear that this
polynomial has two parts, coefficient and exponent, where, x is formal
parameter. Hence, we can say that a polynomial is sum of terms, each of
9
7
which consists of a coefficient and an exponent.

9
8
 The computer implementation requires implementing polynomials as a
list of pair of coefficient and exponent. Each of these pairs will constitute a
structure, so a polynomial will be represented as a list of structures.
 If one wants to represent F(x) with help of linked list then the list
will contain 5 nodes. When we link each node we get a linked list
structure that represents polynomial F(x).

Addition of polynomials
1. To add two polynomials, we need to scan them once.
2. If we find terms with the same exponent in the two polynomials, then
we add the coefficients, otherwise, we copy the term of larger
exponent into the sum and go on.
3. When we reach at the end of one of the polynomial, then
remaining part of the other is copied into the sum.
4. Suppose we have two polynomials as illustrated and we have to
perform addition of these polynomials.

9
9
1
0
5. When we scan first node of the two polynomials, we find that
exponential power of first node in the second polynomial is greater
than that of first node of the first polynomial.
6. Here the exponent of the first node of the second polynomial is greater
hence we have to copy first node of the second polynomial into the
sum.
7. Then we consider the first node of the first polynomial and once
again first node value of first polynomial is compared with the
second node value of the second polynomial.
8. Here the first node exponent value of the first polynomial is greater
than the second node exponent value of the second polynomial. We
copy the first node of the first polynomial into the sum.
9. Now consider the second node of the first polynomial and compare
it with the second node of the second polynomial.
10. Here the exponent value of the second node of the second
polynomial is greater than the second node of the first polynomial,
hence we copy the second node of the second list into the sum.
1
0
11. Now we consider the third node exponent of the second
polynomial and compare it with second node exponent value of the
first polynomial. We find that both are equal, hence perform addition
of their coefficient and copy in to the sum.
12. This process continues till all the nodes of both the polynomial are
exhausted.
For example after adding the above two polynomials,
we get the following resultant polynomial as shown.
and cannot be increased or decreased after allocation. If more memory is allocated than requirement, then
memory is wasted. If less memory is allocated than requirement, then program will not run successfully. So
exact memory requirements must be known in advance.
95
2. Dynamic Memory Allocation:

When memory is allocated during run/execution time, it is called ‘Dynamic Memory Allocation’. This memory
is not fixed and is allocated according to our requirements. Thus in it there is no wastage of memory. So there
is no need to know exact memory requirements in advance.

(b) Garbage Collection-

Whenever a node is deleted, some memory space becomes reusable. This memory space should be available
for future use. One way to do this is to immediately insert the free space into availability list. But this method
may be time consuming for the operating system. So another method is used which is called ‘Garbage
Collection’. This method is described below: In this method the OS collects the deleted space time to time onto
the availability list. This process happens in two steps. In first step, the OS goes through all the lists and tags
all those cells which are currently being used. In the second step, the OS goes through all the lists again and
collects untagged space and adds this collected space to availability list. The garbage collection may occur
when small amount of free space is left in the system or no free space is left in the system or when CPU is idle
and has time to do the garbage collection.

(c) Overflow & Underflow-

Overflow happens at the time of insertion. If we have to insert new space into the data structure, but there is
no free space i.e. availability list is empty, then this situation is called ‘Overflow’. The programmer can handle
this situation by printing the message of OVERFLOW.

Underflow happens at the time of deletion. If we have to delete data from the data structure, but there is no
data in the data structure i.e. data structure is empty, then this situation is called ‘Underflow’. The
programmer can handle this situation by printing the message of UNDERFLOW.

96
UNIT-3
What is a Stack?
A Stack is a linear data structure that follows the LIFO (Last-In-First-Out) principle. Stack has one end, whereas the
Queue has two ends (front and rear). It contains only one pointer top pointer pointing to the topmost element of the
stack. Whenever an element is added in the stack, it is added on the top of the stack, and the element can be deleted only
from the stack. In other words, a stack can be defined as a container in which insertion and deletion can be done from
the one end known as the top of the stack.

Some key points related to stack


o It is called as stack because it behaves like a real-world stack, piles of books, etc.
o A Stack is an abstract data type with a pre-defined capacity, which means that it can store the elements of a
limited size.
o It is a data structure that follows some order to insert and delete the elements, and that order can be LIFO or

FILO. Working of Stack

Stack works on the LIFO pattern. As we can observe in the below figure there are five memory blocks in the stack;
therefore, the size of the stack is 5.

Suppose we want to store the elements in a stack and let's assume that stack is empty. We have taken the stack of size 5 as
shown below in which we are pushing the elements one by one until the stack becomes full.

Since our stack is full as the size of the stack is 5. In the above cases, we can observe that it goes from the top to the
bottom when we were entering the new element in the stack. The stack gets filled up from the bottom to the top.

When we perform the delete operation on the stack, there is only one way for entry and exit as the other end is closed. It
follows the LIFO pattern, which means that the value entered first will be removed last. In the above case, the value 5 is
entered first, so it will be removed only after the deletion of all the other elements.

9
7
Standard Stack Operations

The following are some common operations implemented on the stack:

o push(): When we insert an element in a stack then the operation is known as a push. If the stack is full then the
overflow condition occurs.
o pop(): When we delete an element from the stack, the operation is known as a pop. If the stack is empty means
that no element exists in the stack, this state is known as an underflow state.
o isEmpty(): It determines whether the stack is empty or not.
o isFull(): It determines whether the stack is full or not.'
o peek(): It returns the element at the given position.
o count(): It returns the total number of elements available in a stack.
o change(): It changes the element at the given position.
o display(): It prints all the elements available in the stack.

PUSH operation

The steps involved in the PUSH operation is given below:

o Before inserting an element in a stack, we check whether the stack is full.


o If we try to insert the element in a stack, and the stack is full, then the overflow condition occurs.
o When we initialize a stack, we set the value of top as -1 to check that the stack is empty.
o When the new element is pushed in a stack, first, the value of the top gets incremented, i.e., top=top+1, and the
element will be placed at the new position of the top.
o The elements will be inserted until we reach the max size of the stack.

9
8
POP operation

The steps involved in the POP operation is given below:

o Before deleting the element from the stack, we check whether the stack is empty.
o If we try to delete the element from the empty stack, then the underflow condition occurs.
o If the stack is not empty, we first access the element which is pointed by the top
o Once the pop operation is performed, the top is decremented by 1, i.e., top=top-1.

Applications of Stack

The following are the applications of the stack:

o Balancing of symbols: Stack is used for balancing a symbol. For example, we have the following program:

1. int main()
2. {
3. cout<<"Hello";
4. cout<<"World";
5. }

As we know, each program has an opening and closing braces; when the opening braces come, we push the braces in a
stack, and when the closing braces appear, we pop the opening braces from the stack. Therefore, the net value comes out
to be zero. If any symbol is left in the stack, it means that some syntax occurs in a program.

9
9
o String reversal: Stack is also used for reversing a string. For example, we want to reverse a "javaTpoint" string,
so we can achieve this with the help of a stack.
First, we push all the characters of the string in a stack until we reach the null character.
After pushing all the characters, we start taking out the character one by one until we reach the bottom of the
stack.
o UNDO/REDO: It can also be used for performing UNDO/REDO operations. For example, we have an editor in
which we write 'a', then 'b', and then 'c'; therefore, the text written in an editor is abc. So, there are three states, a,
ab, and abc, which are stored in a stack. There would be two stacks in which one stack shows UNDO state, and
the other shows REDO state.
If we want to perform UNDO operation, and want to achieve 'ab' state, then we implement pop operation.
o Recursion: The recursion means that the function is calling itself again. To maintain the previous states, the
compiler creates a system stack in which all the previous records of the function are maintained.
o DFS(Depth First Search): This search is implemented on a Graph, and Graph uses the stack data structure.
o Backtracking: Suppose we have to create a path to solve a maze problem. If we are moving in a particular path,
and we realize that we come on the wrong way. In order to come at the beginning of the path to create a new path,
we have to use the stack data structure.
o Expression conversion: Stack can also be used for expression conversion. This is one of the most important
applications of stack. The list of the expression conversion is given below:
o Infix to prefix
o Infix to postfix
o Prefix to infix
o Prefix to postfix
Postfix to infix
o Memory management: The stack manages the memory. The memory is assigned in the contiguous memory
blocks. The memory is known as stack memory as all the variables are assigned in a function call stack memory.
The memory size assigned to the program is known to the compiler. When the function is created, all its variables
are assigned in the stack memory. When the function completed its execution, all the variables assigned in the
stack are released.

Array implementation of Stack


In array implementation, the stack is formed by using the array. All the operations
regarding the stack are performed using arrays. Lets see how each operation can be
implemented on the stack using array data structure.

Adding an element onto the stack (push operation)


Adding an element into the top of the stack is referred to as push operation. Push
operation involves following two steps.
10
0
1. Increment the variable Top so that it can now refere to the next memory location.
2. Add element at the position of incremented top. This is referred to as adding new element
at the top of the stack.

Stack is overflown when we try to insert an element into a completely filled stack
therefore, our main function must always avoid stack overflow condition.

Algorithm:

1. begin
2. if top = n then stack full
3. top = top + 1
4. stack (top) : = item;
5. end

Time Complexity : o(1)

implementation of push algorithm in C language


1. void push (int val,int n) //n is size of the stack
2. {
3. if (top == n )
4. printf("\n Overflow");
5. else
6. {
7. top = top +1;
8. stack[top] = val;
9. }
10. }
Deletion of an element from a stack (Pop operation)
Deletion of an element from the top of the stack is called pop operation. The value of the
variable top will be incremented by 1 whenever an item is deleted from the stack. The
top most element of the stack is stored in an another variable and then the top is
decremented by 1. the operation returns the deleted value that was stored in another
variable as the result.

The underflow condition occurs when we try to delete an element from an already empty
stack.

Algorithm :

1. begin
2. if top = 0 then stack
empty; 101
3. item := stack(top);
4. top = top - 1;
5. end;

Time Complexity : o(1)

Implementation of POP algorithm using C language


1. int pop ()
2. {
3. if(top == -1)
4. {
5. printf("Underflow");
6. return 0;
7. }
8. else
9. {
10. return stack[top - - ];
11. }
12. }
Visiting each element of the stack (Peek operation)
Peek operation involves returning the element which is present at the top of the stack
without deleting it. Underflow condition can occur if we try to return the top element in
an already empty stack.

Algorithm :

PEEK (STACK, TOP)

1. Begin
2. if top = -1 then stack empty
3. item = stack[top]
4. return item
5. End

Time complexity: o(n)

Implementation of Peek algorithm in C language


1. int peek()
2. {
3. if (top == -1)
4. {

5 printf("Underflow 102
. ");
6. return 0;
7. }
8. else
9. {
10. return stack [top];
11. }
12. }

Stack Implementation Using Linked-List

Stack implementation using linked-list, the nodes aíe maintained in non-contiguous


memoíy. Each node contains a pointeí to the immediate next in line node in the Stack.

In Stack, implementation using Linked-List, eveíy new element inseíted to the top of the
Stack which means eveíy new inseíting element pointed by the top and wheneveí we
want to delete element fíom the Stack which is pointing to the top of the Stack by
moving the top by moving top to is the píevious node in the linked -list. ľhe following
field of the fiíst element must always be NULL. ľheíe is an oveíflow condition in the
Stack if the space left in the memoíy heap is not sufficient to cíeate a node.

10
3
Píoceduíe foí Stack Implementation Using Linked-List

Push Opeíation

Adding a new node in the Stack is teímed a push opeíation.

Pushing a node in the linked list is quite diffeíent fíom inseíting an element in the
aííay. Push opeíation on stack implementation using linked-list involves seveíal
steps:

 Cíeate a node fiíst and allocate memoíy to it.

 If the list is empty, then the node is pushed as the fiíst node of the linked list. ľhis
opeíation assigns a value to the data paít of the node and gives NULL to the addíess
paít of the node.

 If some nodes aíe alíeady in the linked list, then we have to add a new node at the
beginning to the list not to violate the Stack's píopeíty. Foí this, assign the element to
the addíess field of the new node and make a new node which will be staíting node of
the list.

 An oveíflow condition occuís when we tíy to push an opeíation if the Stack is alíeady full.

10
4
Pop Opeíation

Deleting a node fíom the Stack is known as a pop opeíation.

ľhe popping node fíom the linked list is diffeíent fíom the popping element fíom the
aííay. ľo peífoím the pop opeíation involves the following steps:

 In Stack, the node is íemoved fíom the end of the linked list. ľheíefoíe, must delete
the value stoíed in the head pointeí, and the node must get fíee. ľhe following link
node will become the head node now.

 An undeíflow condition will occuí when we tíy to pop an opeíation when the Stack is
alíeady empty. ľhe Stack will be meaningless if the head pointeí of the list points to
NULL.

10
5
Píos and Cons of Stack Implementation Using Linked-List

ľheíe is some píos and cons of stack implementation using linked-list:

Píos of Stack Implementation Using Linked-List.

10
6
 Dynamic Daīa Sīíucīuíe

Linked-list is a dynamic data stíuctuíe, so it can gíow and shíink at íuntime by


allocating and deallocating memoíy.

 Inseíīion and Deleīion

Unlike in an aííay, we don't have to shift elements afteí inseítion and deletion of stuff.
Inseítion and deletion in linked-list aíe íelatively easieí by updating the addíess píesent in
the next pointeí of a node.

 No Memoíy Wasīage

In linked lists, the size can be incíeased and decíeased at the íun time leading to no
memoíy wastage.

Cons of Stack Implementation Using Linked-List.

 Memoíy Usage

Moíe memoíy is íequiíed to stoíe elements in a linked list because each node contains a
pointeí in the linked list, and it íequiíes extía memoíy foí itself.

 ľíaveísal

Node tíaveísal in linked lists is quite tíicky. Foí example, if we want to access a node at
position n, then we have to tíaveíse all the nodes befoíe it. So the time íequiíed to access
a node is laíge.

 Reveíse ľíaveísing

Reveíse tíaveísing in stack implementation using linked-list is quite tíicky because extía
memoíy is íequiíed foí back pointeí hence wastage of memoíy.

10
7
Operation on Stack

1. PUSH: PUSH operation implies the insertion of a new element into a Stack. A new
element is always inserted from the topmost position of the Stack; thus, we always
need to check if the top is empty or not, i.e., TOP=Max-1 if this condition goes false, it
means the Stack is full, and no more elements can be inserted, and even if we try to
insert the element, a Stack overflow message will be displayed.

Algorithm:

Step-1: If TOP = Max-1

Print “Overflow”

Goto Step 4

Step-2: Set TOP= TOP + 1

Step-3: Set Stack[TOP]=


ELEMENT Step-4: END

2. POP: POP means to delete an element from the Stack. Before deleting an element,
make sure to check if the Stack Top is NULL, i.e., TOP=NULL. If this condition goes true, it
means the Stack is empty, and no deletion operation can be performed, and even if we
try to delete, then the Stack underflow message will be generated.
10
8
Algorithm:

Step-1: If TOP= NULL

Print “Underflow”

Goto Step 4

Step-2: Set VAL=


Stack[TOP] Step-3: Set
TOP= TOP-1

Step-4: END

3. PEEK: When we need to return the value of the topmost element of the Stack without
deleting it from the Stack, the Peek operation is used. This operation first checks if the
Stack is empty, i.e., TOP = NULL; if it is so, then an appropriate message will display,
else the value will return.

Algorithm:

Step-1: If TOP = NULL

PRINT “Stack is Empty”

Goto Step 3

Step-2: Return
Stack[TOP] Step-3: END
Applications of Stack in Data Structure
1. Function Calls-
The state of the program is placed into the Stack when a function is invoked. The
preceding function's execution is continued after the process returns by popping the
state off the Stack.
2. Backtracking-
Stacks can be used for backtracking or to verify if an expression's parentheses match.
Stacks are used by the backtracking method to maintain track of the stages of the
solution process. The old state is removed from the Stack when the algorithm goes
backwards after pushing the current state onto it.
3. Undo/Redo Operations-
Many apps' undo-redo functionality employs stacks to remember the prior operations. A
new action is added to the Stack each time it is completed. The top member of the Stack
is popped to undo the action, and the original procedure is then carried out.

10
9
Stacks are used by web browsers to record the websites you visit. When you click the
back button, the previous URL is removed from the Stack and is added to the Stack
each time you visit a new page.
5. Reverse the Data-
We must reorganize the data so that the first and final items are switched; the second
and second- last elements are exchanged, and so on for all subsequent elements if we
want to reverse a particular collection of data.
For example: If we have string codingNinja, then on reversing, it will become ajniNgnidoc.
6. Parenthesis checking-
To determine if brackets are balanced or not, a stack data structure is utilized. An
opening parenthesis is popped off the Stack as a closing parenthesis is added onto it.
The brackets are balanced if the Stack is empty at the conclusion of the expression.
7. Expression Evaluation-
Expressions written in infix, postfix, and prefix notations are evaluated using a stack data
structure. The Stack is used to hold operators and operands, and the top pieces of the
Stack are used to carry out operations
Introduction to Polish Notation in Data Structure

This type of notation was introduced by the Polish mathematician Lukasiewicz. Polish Notation in data
structure tells us about different ways to write an arithmetic expression. An arithmetic expression
contains 2 things, i.e., operands and operators. Operands are either numbers or variables that can be replaced
by numbers to evaluate the expressions. Operators are symbols symbolizing the operation to be performed

becomes ∗+12+34∗+12+34 in Polish Notation. Polish notation is also called prefix notation. It means that
between operands present in the expression. Like the expression (1+2)∗(3+4)(1+2)∗(3+4) standard

operations are written before the operands. The operators are placed left for every pair of operands. Let’s say for
the expression a+b, the prefix notation would be +ab.

Types of Notations

Three types of polish notations exist in the data structure. Let's have look at them one-by-one.

 Infix Notation :
This polish notation in data structure states that the operator is written in between the operands. It is the
most common type of notation we generally use to represent expressions. It's the fully parenthesized
notation. We find it much easier to write mathematical expressions in Infix Notation, but it is difficult to
parse expressions on computers in the form of infix Polish Notation.
 (3+7)
 (1*(2+3))
 Prefix Notation :
This polish notation in data structure states that the operator should be present as a prefix or before the
operands. This notation is also known as "Polish Notation". For example, if we have an expression
like x+y, then here x and y are operands, and ‘+’ is the operator. The prefix notation or polish notation
of this expression will be "+xy".
 3+7 will convert into +37
 1*(2+3) will convert into *1(+23)
 Postfix Notation :
This notation states that the operator should be present as a suffix, postfix, or after the operands. It is
also known as Suffix notation or Reverse Polish Notation. For example, if we have an expression
11
0
like x+y, then here x and y are operands, and ‘+’ is the operator. The prefix notation or polish notation
of this expression will be "xy+".

In general, a computer can easily understand postfix expressions. This notation is universally accepted
and is preferred for designing and programming the arithmetic and logical units of a CPU (Central
Processing Unit). All the expressions that are entered into a computer are converted
into Postfix or Reverse Polish Notation, stored in a stack, and then computed. Therefore, postfix
expression plays a vital role in the tech industry.

3+7 will convert into 37+


1*(2+3) will convert into (23+)1*
Explore free courses by our top instructorsView All

TARUN LUTHRA
Java Course - Mastering the Fundamentals
82k+ enrolled

RAHUL JANGHU
Python Course for Beginners With Certification: Mastering the Essentials
73k+ enrolled

PRATEEK NARANG
C++ Course: Learn the Essentials
42k+ enrolled
35,262+ learners have attended these Courses.
Conversion of an Infix Expression to Postfix Expression

Generally, humans find infix polish notation much easier to understand than postfix or reverse polish notation.
To convert each expression from infix to postfix, we assign priority to each of the operators present in the
expression. Each operator has its priority for an expression. For example, if we take some operators, i.e., +, -
, *, /, then these will be arranged in priority.

Higher Priority Operators : *, /, %.

Order of Operators : +, −, ∗, /, ^.
Lower Priority Operators : +, -.

A Conversion Algorithm for INFIX POLISH NOTATION to POSTFIX POLISH NOTATION is given
below :

 Push "(" in the stack and add ")" at the end of the infix polish notation of the given expression.
 Repeat the below steps for each of the elements present in the Infix Polish Notation.
o If "(" is encountered, then push the element onto the stack.
o If an operand, i.e. a variable or a number, is encountered, we add it in the postfix or reverse
polish notation.
o If ")" is encountered, we pop from the stack until the popped element is "(" and add these elements to the
postfix expression. After that discard "(" from the stack and do not add it again to the postfix expression.
o If an operator "x" is encountered, then, again and again, pop from the stack and add each operator to the
postfix expression which has the same or higher precedence than operator "x".
 After performing step 2 on each element, we will pop all the elements from the stack and add them to
the postfix expression 11
1
Reverse Polish Notation

Reverse Polish notation is also known as Postfix notation and Suffix Notation. It plays a vital role in the tech
industry. In general, humans find Infix polish notation or parenthesized format of expression easy to
evaluate, whereas computers find it difficult to parse expressions in the form of Infix Polish Notation, so our
computer converts the expression into postfix polish notation or reverse polish notation to evaluate the
expression.

A reverse Polish notation states that the operator should be present after the operands. For example, if an
expression is x+y, then x and y are operands and ‘+’ is the operator. The prefix notation or polish notation of
this expression will be "xy+".

Sample Code to Evaluate a Postfix notation through stack :

def postfix_eval(postfix_expression):
postfix_expression = postfix_expression.split()
n = len(postfix_expression)
stack = []
for i in range(n):
if postfix_expression[i].isdigit():
stack.append(int(postfix_expression[i]))
elif postfix_expression[i] == "+":
x = stack.pop()
y = stack.pop()
stack.append(int(x) + int(y))
elif postfix_expression[i] == "*":
x = stack.pop()
y = stack.pop()
stack.append(int(x) * int(y))
elif postfix_expression[i] == "/":
x = stack.pop()
y = stack.pop()
stack.append(int(y) / int(x))
elif postfix_expression[i] == "-":
x = stack.pop()
y = stack.pop()
stack.append(int(y) - int(x))
return stack.pop()

postfix_expression = "1 2 + 3 *"


ans = postfix_eval(postfix_expression)
print("Infix Expression: ")
print(postfix_expression)
print("Evaluation of Postfix Expression using Stack: ")
print(ans)

Output :

Infix Expression:-
1 2 + 3 *
Evaluation of Postfix Expression using Stack :-
9

This is how we can evaluate a reverse polish notation or postfix expression using Stack.

Polish Notation in data structure plays a vital role in the tech industry.
Applications of Polish
Notation 112

Polish Notation in data structure plays a vital role in the tech industry.
Let's see some of the applications of the polish notation :

 The Polish Notations play a very vital role in evaluating arithmetic expressions for computers and different types
of machines, as they find infix or parenthesized expressions difficult to parse, whereas they find them easy to
parse the postfix or reverse polish notation expressions.
 The modern Stack-organized computers are better suited for postfix and prefix notations than normally used infix
notations due to their difficulty in parsing.
 The compiler can quickly evaluate these expressions without having to scan the expression for operators first and
then for operands, which would require several scans. The compiler can then evaluate the expression in one step
by converting the Infix expression to Polish notation.

Queue

Queue is also an abstract data type or a linear data structure, just like stack data
structure, in which the first element is inserted from one end called the REAR(also
called tail), and the removal of existing element takes place from the other end called
as FRONT(also called head).

This makes queue as FIFO(First in First Out) data structure, which means that
element inserted first will be removed first.

Which is exactly how queue system works in real world. If you go to a ticket counter to
buy movie tickets, and are first in the queue, then you will be the first one to get the
tickets. Right? Same is the case with Queue data structure. Data inserted first, will leave
the queue first.

The process to add an element into queue is called Enqueue and the process of
removal of an element from queue is called Dequeue.

11
3
Basic features of Queue

1. Like stack, queue is also an ordered list of elements of similar data types.

2. Queue is a FIFO( First in First Out ) structure.

3. Once a new element is inserted into the Queue, all the elements inserted
before the new element in the queue must be removed, to remove the new
element.

4. peek( ) function is oftenly used to return the value of first element without dequeuing it.

Applications of Queue

Queue, as the name suggests is used whenever we need to manage any group of
objects in an order in which the first one coming in, also gets out first while the others
wait for their turn, like in the following scenarios:

1. Serving requests on a single shared resource, like a printer, CPU task scheduling etc.

2. In real life scenario, Call Center phone systems uses Queues to hold people
calling them in an order, until a service representative is free.

3. Handling of interrupts in real-time systems. The interrupts are handled in the


same order as they arrive i.e First come first served.

Implementation of Queue Data Structure

Queue can be implemented using an Array, Stack or Linked List. The easiest way of
implementing a queue is by using an Array.

Initially the head(FRONT) and the tail(REAR) of the queue points at the first index of
the array (starting the index of array from 0). As we add elements to the queue, the
tail keeps on moving ahead, always pointing to the position where the next element
will be inserted, while
the head remains at the first index.

11
4
When we remove an element from Queue, we can follow two possible approaches
(mentioned [A] and [B] in above diagram). In [A] approach, we remove the element at
head position, and then one by one shift all the other elements in forward position.

In approach [B] we remove the element from head position and then move head to the
next position.

In approach [A] there is an overhead of shifting the elements one position


forward every time we remove the first element.

In approach [B] there is no such overhead, but whenever we move head one position
ahead, after removal of first element, the size on Queue is reduced by one
space each time.

Array representation of Queue


We can easily represent queue by using linear arrays. There are two variables i.e. front
and rear, that are implemented in the case of every queue. Front and rear variables
point to the position from where insertions and deletions are performed in a queue.
11
5
Initially, the value of front and queue is -1 which

11
6
represents an empty queue. Array representation of a queue containing 5 elements
along with the respective values of front and rear, is shown in the following figure.

The above figure shows the queue of characters forming the English word "HELLO".
Since, No deletion is performed in the queue till now, therefore the value of front remains
-1 . However, the value of rear increases by one every time an insertion is performed in
the queue. After inserting an element into the queue shown in the above figure, the
queue will look something like following. The value of rear will become 5 while the value
of front remains same.

After deleting an element, the value of front will increase from -1 to 0. however, the
queue will look something like following.

11
7
Algorithm to insert any element in a queue
Check if the queue is already full by comparing rear to max - 1. if so, then return an
overflow error.

If the item is to be inserted as the first element in the list, in that case set the value of
front and rear to 0 and insert the element at the rear end.

Otherwise keep increasing the value of rear and insert each element one by one having
rear as the index.

Algorithm
o Step 1: IF REAR =
MAX - 1 Write
OVERFLOW
Go to step
[END OF
IF]
o Step 2: IF FRONT = -1 and
REAR = -1 SET FRONT = REAR =
0
ELSE
SET REAR = REAR
+ 1 [END OF IF]
o Step 3: Set QUEUE[REAR] = NUM
o Step 4: EXIT

Algorithm to delete an element from the queue


If, the value of front is -1 or value of front is greater than rear , write an underflow11message
7
and exit.
Otherwise, keep increasing the value of front and return the item stored at the front end
of the queue at each time.

Algorithm
o Step 1: IF FRONT = -1 or FRONT >
REAR Write UNDERFLOW
ELSE
SET VAL =
QUEUE[FRONT] SET
FRONT = FRONT + 1
[END OF IF]
o Step 2: EXIT

Linked List implementation of Queue


Due to the drawbacks discussed in the previous section of this tutorial, the array
implementation can not be used for the large scale applications where the queues are
implemented. One of the alternative of array implementation is linked list
implementation of queue.

The storage requirement of linked representation of a queue with n elements is o(n)


while the time requirement for operations is o(1).

In a linked queue, each node of the queue consists of two parts i.e. data part and the link
part. Each element of the queue points to its immediate next element in the memory.

In the linked queue, there are two pointers maintained in the memory i.e. front pointer
and rear pointer. The front pointer contains the address of the starting element of the
queue while the rear pointer contains the address of the last element of the queue.

Insertion and deletions are performed at rear and front end respectively. If front and rear
both are NULL, it indicates that the queue is empty.

The linked representation of queue is shown in the following figure.

118
Operation on Linked Queue
There are two basic operations which can be implemented on the linked queues. The
operations are Insertion and Deletion.

Insert operation
The insert operation append the queue by adding an element to the end of the queue.
The new element will be the last element of the queue.

Firstly, allocate the memory for the new node ptr by using the following statement.

1. Ptr = (struct node *) malloc (sizeof(struct node));

There can be the two scenario of inserting this new node ptr into the linked queue.

In the first scenario, we insert element into an empty queue. In this case, the condition
front = NULL becomes true. Now, the new element will be added as the only element
of the queue and the next pointer of front and rear pointer both, will point to NULL.

1. ptr -> data = item;


2. if(front == NULL)
3. {
4. front = ptr;
5. rear = ptr;
6. front -> next = NULL;
7. rear -> next = NULL;
8. }

In the second case, the queue contains more than one element. The condition front =
NULL becomes false. In this scenario, we need to update the end pointer rear so that the
next pointer of rear will point to the new node ptr. Since, this is a linked queue, hence we
also need to make the rear pointer point to the newly added node ptr. We also need to
make the next pointer of rear point to NULL.

1. rear -> next = ptr;


2. rear = ptr;
3. rear->next = NULL;

In this way, the element is inserted into the queue. The algorithm and the C
implementation is given as follows.

Algorithm
11
o Step 1: Allocate the space for the new node PTR 9
o Step 2: SET PTR -> DATA = VAL
o Step 3: IF FRONT =
NULL SET FRONT =
REAR = PTR
SET FRONT -> NEXT = REAR -> NEXT =
NULL ELSE
SET REAR -> NEXT =
PTR SET REAR = PTR
SET REAR -> NEXT =
NULL [END OF IF]
o Step 4: END

Deletion
Deletion operation removes the element that is first inserted among all the queue
elements. Firstly, we need to check either the list is empty or not. The condition front ==
NULL becomes true if the list is empty, in this case , we simply write underflow on the
console and make exit.

Otherwise, we will delete the element that is pointed by the pointer front. For this
purpose, copy the node pointed by the front pointer into the pointer ptr. Now, shift the
front pointer, point to its next node and free the node pointed by the node ptr. This is
done by using the following statements.

1. ptr = front;
2. front = front -> next;
3. free(ptr);

The algorithm and C function is given as follows.

Algorithm
o Step 1: IF FRONT =
NULL Write "
Underflow "
Go to Step
5 [END OF
IF]
o Step 2: SET PTR = FRONT
o Step 3: SET FRONT = FRONT -> NEXT
o Step 4: FREE PTR
o Step 5: END

12
0
What is a Deque (or double-ended queue)
The deque stands for Double Ended Queue. Deque is a linear data structure where the
insertion and deletion operations are performed from both ends. We can say that deque
is a generalized version of the queue.

Though the insertion and deletion in a deque can be performed on both ends, it does not
follow the FIFO rule. The representation of a deque is given as follows -

Types of deque
There are two types of deque -

o Input restricted queue


o Output restricted queue

Input restricted Queue

In input restricted queue, insertion operation can be performed at only one end, while
deletion can be performed from both ends.

Output restricted Queue

In output restricted queue, deletion operation can be performed at only one end, while
insertion can be performed from both ends.

12
1
Operations performed on deque
There are the following operations that can be applied on a deque -

o Insertion at front
o Insertion at rear
o Deletion at front
o Deletion at rear

We can also perform peek operations in the deque along with the operations listed
above. Through peek operation, we can get the deque's front and rear elements of the
deque. So, in addition to the above operations, following operations are also supported
in deque -

o Get the front item from the deque


o Get the rear item from the deque
o Check whether the deque is full or not
o Checks whether the deque is empty or not

Now, let's understand the operation performed on deque using an example.

Insertion at the front end

In this operation, the element is inserted from the front end of the queue. Before
implementing the operation, we first have to check whether the queue is full or not. If
the queue is not full, then the element can be inserted from the front end by using the
below conditions -

o If the queue is empty, both rear and front are initialized with 0. Now, both will point to the first
element.
o Otherwise, check the position of the front if the front is less than 1 (front < 1), then reinitialize
it by front
= n - 1, i.e., the last index of the array.

12
2
Insertion at the rear end

In this operation, the element is inserted from the rear end of the queue. Before
implementing the operation, we first have to check again whether the queue is full or
not. If the queue is not full, then the element can be inserted from the rear end by using
the below conditions -

o If the queue is empty, both rear and front are initialized with 0. Now, both will point to the first
element.
o Otherwise, increment the rear by 1. If the rear is at last index (or size - 1), then instead of
increasing it by 1, we have to make it equal to 0.

Deletion at the front end

In this operation, the element is deleted from the front end of the queue. Before
implementing the operation, we first have to check whether the queue is empty or not.

12
3
If the queue is empty, i.e., front = -1, it is the underflow condition, and we cannot
perform the deletion. If the queue is not full, then the element can be inserted from the
front end by using the below conditions -

If the deque has only one element, set rear = -1 and

front = -1. Else if front is at end (that means front =

size - 1), set front = 0. Else increment the front by 1,

(i.e., front = front + 1).

Deletion at the rear end

In this operation, the element is deleted from the rear end of the queue. Before
implementing the operation, we first have to check whether the queue is empty or not.

If the queue is empty, i.e., front = -1, it is the underflow condition, and we cannot

perform the deletion. If the deque has only one element, set rear = -1 and front = -1.

If rear = 0 (rear is at front), then set rear =

n - 1. Else, decrement the rear by 1 (or, rear

= rear -1).

12
4
Applications of deque
o Deque can be used as both stack and queue, as it supports both operations.
o Deque can be used as a palindrome checker means that if we read the string from both
ends, the string would be the same.

What is a priority queue?


A priority queue is an abstract data type that behaves similarly to the normal queue
except that each element has some priority, i.e., the element with the highest priority
would come first in a priority queue. The priority of the elements in a priority queue will
determine the order in which elements are removed from the priority queue.

The priority queue supports only comparable elements, which means that the elements
are either arranged in an ascending or descending order.

For example, suppose we have some values like 1, 3, 4, 8, 14, 22 inserted in a priority
queue with an ordering imposed on the values is from least to the greatest. Therefore,
the 1 number would be having the highest priority while 22 will be having the lowest
priority.

Characteristics of a Priority queue


A priority queue is an extension of a queue that contains the following characteristics:

o Every element in a priority queue has some priority associated with it.
o An element with the higher priority will be deleted before the deletion of the lesser priority.
o If two elements in a priority queue have the same priority, they will be arranged using the
FIFO principle.

12
5
Let's understand the priority queue through an example.

We have a priority queue that contains the following values:

1, 3, 4, 8, 14, 22

All the values are arranged in ascending order. Now, we will observe how the priority
queue will look after performing the following operations:

o poll(): This function will remove the highest priority element from the priority queue. In
the above priority queue, the '1' element has the highest priority, so it will be removed
from the priority queue.
o add(2): This function will insert '2' element in a priority queue. As 2 is the smallest
element among all the numbers so it will obtain the highest priority.
o poll(): It will remove '2' element from the priority queue as it has the highest priority queue.
o add(5): It will insert 5 element after 4 as 5 is larger than 4 and lesser than 8, so it will
obtain the third highest priority in a priority queue.

Types of Priority Queue


There are two types of priority queue:

o Ascending order priority queue: In ascending order priority queue, a lower priority
number is given as a higher priority in a priority. For example, we take the numbers from 1
to 5 arranged in an ascending order like 1,2,3,4,5; therefore, the smallest number, i.e., 1 is
given as the highest priority in a priority queue.

o Descending order priority queue: In descending order priority queue, a higher priority
number is given as a higher priority in a priority. For example, we take the numbers from 1
to 5 arranged in descending order like 5, 4, 3, 2, 1; therefore, the largest number, i.e., 5
is given as the highest priority in a priority
126
queue.

Representation of priority queue


Now, we will see how to represent the priority queue through a one-way list.

We will create the priority queue by using the list given below in which INFO list contains
the data elements, PRN list contains the priority numbers of each data element available
in the INFO list, and LINK basically contains the address of the next node.

Let's create the priority queue step by step.

In the case of priority queue, lower priority number is considered the higher
priority, i.e., lower priority number = higher priority. 12
7
Step 1: In the list, lower priority number is 1, whose data value is 333, so it will be
inserted in the list as shown in the below diagram:

Step 2: After inserting 333, priority number 2 is having a higher priority, and data
values associated with this priority are 222 and 111. So, this data will be inserted based
on the FIFO principle; therefore 222 will be added first and then 111.

Step 3: After inserting the elements of priority 2, the next higher priority number is 4
and data elements associated with 4 priority numbers are 444, 555, 777. In this case,
elements would be inserted based on the FIFO principle; therefore, 444 will be added
first, then 555, and then 777.

Step 4: After inserting the elements of priority 4, the next higher priority number is 5,
and the value associated with priority 5 is 666, so it will be inserted at the end of the
queue.

Implementation of Priority Queue


The priority queue can be implemented in four ways that include arrays, linked list, heap
data structure and binary search tree. The heap data structure is the most efficient way
of implementing the priority queue, so we will implement the priority queue using a heap
data structure in this topic. Now, first we understand the reason why heap is the most
efficient way among all the other data structures.

Analysis of complexities using different implementations

Implementation add Remov peek


e
Linked list O(1) O(n) O(n)

Binary heap O(logn) O(logn) O(1)

Binary search O(logn) O(logn) O(1)


tree
What is Heap?
A heap is a tree-based data structure that forms a complete binary tree, and satisfies the
heap property. If A is a parent node of B, then A is ordered with respect to the node B for
all nodes A and B in a heap. It means that the value of the parent node could be more
than or equal to the value of the child node, or the value of the parent node could be less
than or equal to the value of the child node. Therefore, we can say that there are two
types of heaps: 12
8
o Max heap: The max heap is a heap in which the value of the parent node is greater than
the value of the child

nodes.

o Min heap: The min heap is a heap in which the value of the parent node is less than the
value of the child nodes.

Both the heaps are the binary heap, as each has exactly two child nodes.

Priority Queue Operations


129
The common operations that we can perform on a priority queue are insertion, deletion
and peek. Let's see how we can maintain the heap data structure.

o Inserting the element in a priority queue (max heap)

If we insert an element in a priority queue, it will move to the empty slot by looking from
top to bottom and left to right.

If the element is not in a correct place then it is compared with the parent node; if it is
found out of order, elements are swapped. This process continues until the element is
placed in a correct position.

o Removing the minimum element from the priority queue 13


0
As we know that in a max heap, the maximum element is the root node. When we
remove the root node, it creates an empty slot. The last inserted element will be added
in this empty slot. Then, this element is compared with the child nodes, i.e., left-child and
right child, and swap with the smaller of the two. It keeps moving down the tree until the
heap property is restored.

Applications of Priority queue


The following are the applications of the priority queue:

o It is used in the Dijkstra's shortest path algorithm.


o It is used in prim's algorithm
o It is used in data compression techniques like Huffman code.
o It is used in heap sort.
o It is also used in operating system like priority scheduling, load balancing and interrupt
handling.

13
1
UNIT-4

Tree Data Structure


We read the linear data structures like an array, linked list, stack and queue in which all
the elements are arranged in a sequential manner. The different data structures are used
for different kinds of data.

Some factors are considered for choosing the data structure:

o What type of data needs to be stored?: It might be a possibility that a certain data
structure can be the best fit for some kind of data.
o Cost of operations: If we want to minimize the cost for the operations for the most
frequently performed operations. For example, we have a simple list on which we have to
perform the search operation; then, we can create an array in which elements are stored
in sorted order to perform the binary search. The binary search works very fast for the
simple list as it divides the search space into half.
o Memory usage: Sometimes, we want a data structure that utilizes less memory.

A tree is also one of the data structures that represent hierarchical data. Suppose we want
to show the employees and their positions in the hierarchical form then it can be
represented as shown below:

13
2
The above tree shows the organization hierarchy of some company. In the above
structure, john is the CEO of the company, and John has two direct reports named as
Steve and Rohan. Steve has three direct reports named Lee, Bob, Ella where Steve
is a manager. Bob has two direct reports named Sal and Emma. Emma has two
direct reports named Tom and Raj. Tom has one direct report named Bill. This particular
logical structure is known as a Tree. Its structure is similar to the real tree, so it is
named a Tree. In this structure, the root is at the top, and its branches are moving in a
downward direction. Therefore, we can say that the Tree data structure is an efficient
way of storing the data in a hierarchical way.

Let's understand some key points of the Tree data structure.

o A tree data structure is defined as a collection of objects or entities known as nodes that
are linked together to represent or simulate hierarchy.
o A tree data structure is a non-linear data structure because it does not store in a
sequential manner. It is a hierarchical structure as elements in a Tree are arranged in
multiple levels.
o In the Tree data structure, the topmost node is known as a root node. Each node contains
some data, and data can be of any type. In the above tree structure, the node contains
the name of the employee, so the type of data would be a string.
o Each node contains some data and the link or reference of other nodes that can be called
children.

Some basic terms used in Tree data structure.

Let's consider the tree structure, which is shown below:

13
3
In the above structure, each node is labelled with some number. Each arrow shown in the
above figure is known as a link between the two nodes.

o Root: The root node is the topmost node in the tree hierarchy. In other words, the root
node is the one that doesn't have any parent. In the above structure, node numbered 1 is
the root node of the tree. If a node is directly linked to some other node, it would be
called a parent-child relationship.
o Child node: If the node is a descendant of any node, then the node is known as a child node.
o Parent: If the node contains any sub-node, then that node is said to be the parent of that
sub-node.
o Sibling: The nodes that have the same parent are known as siblings.
o Leaf Node:- The node of the tree, which doesn't have any child node, is called a leaf
node. A leaf node is the bottom-most node of the tree. There can be any number of leaf
nodes present in a general tree. Leaf nodes can also be called external nodes.
o Internal nodes: A node has atleast one child node known as an internal
o Ancestor node:- An ancestor of a node is any predecessor node on a path from the root
to that node. The root node doesn't have any ancestors. In the tree shown in the above
image, nodes 1, 2, and 5 are the ancestors of node 10.
o Descendant: The immediate successor of the given node is known as a descendant of a
node. In the above figure, 10 is the descendant of node 5.

Properties of Tree data structure


o Recursive data structure: The tree is also known as a recursive data structure. A
tree can be defined as recursively because the distinguished node in a tree data structure
is known as a root node. The root node of the tree contains a link to all the roots of its
subtrees. The left subtree is shown in the yellow color in the below figure, and the right
subtree is shown in the red color. The left subtree can be further split into subtrees shown
in three different colors. Recursion means reducing something in a self-similar manner. So,
this recursive property of the tree data structure is implemented in various applications.

13
4
o Number of edges: If there are n nodes, then there would n-1 edges. Each arrow in the
structure represents the link or path. Each node, except the root node, will have atleast
one incoming link known as an edge. There would be one link for the parent-child
relationship.
o Depth of node x: The depth of node x can be defined as the length of the path from the
root to the node x. One edge contributes one-unit length in the path. So, the depth of node
x can also be defined as the number of edges between the root node and the node x. The
root node has 0 depth.
o Height of node x: The height of node x can be defined as the longest path from the node
x to the leaf node.

Based on the properties of the Tree data structure, trees are classified into various
categories.

Applications of trees
The following are the applications of trees:

o Storing naturally hierarchical data: Trees are used to store the data in the hierarchical
structure. For example, the file system. The file system stored on the disc drive, the file
and folder are in the form of the naturally hierarchical data and stored in the form of trees.
o Organize data: It is used to organize data for efficient insertion, deletion and searching.
For example, a binary tree has a logN time for searching an element.
o Trie: It is a special kind of tree that is used to store the dictionary. It is a fast and efficient
way for dynamic spell checking.
o Heap: It is also a tree data structure implemented using arrays. It is used to implement
priority queues.
o B-Tree and B+Tree: B-Tree and B+Tree are the tree data structures used to implement
indexing in databases.
o Routing table: The tree data structure is also used to store the data in routing tables in the
routers.

135
Tree Data Structure Terminologies
Terminology Description Example from Diagram
‘1’, ‘2’, ‘3’ are the node
Node Each vertex of a tree is a node.
in the tree.
Node ‘1’ is the topmost
Root Topmost node of a tree.
root node.
Node ‘2’ is the parent
Parent Node The node has an edge-sharing to a child node. of ‘5’ and ‘6’, and Node
‘3’ is the parent of ‘7’.
‘5’ and ‘6’ is the
Child Node The sub-node of a parent node is the child node.
children of ‘2’.
The last node which does have any subnode is the ‘5’, ‘6’, ‘9’ and ‘8’ are
Leaf
leaf node. leaf nodes.
The link between ‘1’ and
Edge Connecting link between two nodes. ‘2’,
‘2’ and ‘5’, ‘2’ and ‘6’
are edges
‘5’ and ‘6’ are siblings
Siblings Nodes with the same parent are siblings.
with ‘2’ as their parent.
The height of a tree is the length of the longest
The height of ‘1’ is 3.
Height path from the root to a leaf node. It is calculated
(longest path is 1-3-7-9)
with the total number of edges.
Depth The number of edges from the root node to that 13 ‘1’
The depth of root node
node is is 6
called the Depth of that node. the height of ‘1’ – 1 = 2
Depth of a tree = Height of tree – 1
Each step from top to bottom is called a Level. If ‘1’ or root node is at
Level the root node is at level 0, its next child node is level 0, ‘2’, ‘3’, and ‘4’
at level 1, its grandchild is at level 2, and so on. is at level 1, and so on.
Nodes ‘2’, ‘5’, and
Sub-Tree Descendants of a node represent a subtree.
‘6’ represent a
sub-tree.
Degree of The degree of a node represents the total The degree of ‘2’ is 2 (‘5’
Node number of children in it. and
‘6’). The degree of ‘4’ is 1.

ľypes of ľíee in Data Stíuctuíes

Heíe aíe the diffeíent kinds of tíee in data stíuctuíes:

Geneíal ľíee

ľhe geneíal tíee is the type of tíee wheíe theíe aíe no constíaints on the hieíaíchical
stíuctuíe.

Píopeíīies

 ľhe geneíal tíee follows all píopeíties of the tíee data stíuctuíe.

 A node can have any numbeí of nodes.

13
7
Binaíy ľíee

A binaíy tíee has the following píopeíties:

Píopeíīies

 Follows all píopeíties of the tíee data stíuctuíe.

 Binaíy tíees can have at most two child nodes.

 ľhese two childíen aíe called the left child and the íight child.

Binaíy Seaích ľíee

A binaíy seaích tíee is a type of tíee that is a moíe constíicted extension of a binaíy
tíee data stíuctuíe.

Píopeíīies

 Follows all píopeíties of the tíee data stíuctuíe.

13
8
 ľhe binaíy seaích tíee has a unique píopeíty known as the binaíy seaích píopeíty.
ľhis states that the value of a left child node of the tíee should be less than oí equal to
the paíent node value of the tíee. And the value of the íight child node should be
gíeateí than oí equal to the paíent value.

AVL ľíee

An AVL tíee is a type of tíee that is a self-balancing binaíy seaích tíee.

Píopeíīies

 Follows all píopeíties of the tíee data stíuctuíe.

 Self-balancing.

 Each node stoíes a value called a balanced factoí, which is the diffeíence in the
height of the left sub-tíee and íight sub-tíee.

 All the nodes in the AVL tíee must have a balance factoí of -1, 0, and 1.

13
9
Red-Black ľíee

 A íed-black tíee is a self-balancing binaíy seaích tíee, wheíe each node has eitheí the
coloí of íed oí black.

 ľhe coloís of the nodes aíe used to make suíe that the tíee íemains appíoximately
balanced duíing inseítion and deletion.

Píopeíīies

 Follow all píopeíties of binaíy tíee data stíuctuíe.

 Self-balancing.

 Each node is eitheí íed oí black.

 ľhe íoot and leaves nodes aíe black.

 If the node is íed, then both childíen aíe black.

 Eveíy path fíom a given node to any of its nodes must go thíough the same numbeí of black
nodes.

14
0
Splay ľíee

A splay tíee is a self-balancing binaíy seaích tíee.

Píopeíīies

 Follows píopeíties of binaíy tíee data stíuctuíe.

 Self-balancing.

 Recently accessed elements aíe quickeí to access again.

Afteí you peífoím opeíations such as inseítion and deletion, the splay tíee acts, which is
called splaying. Heíe it íeaííanges the tíee so that the paíticulaí elements aíe placed at
the íoot of the tíee.

14
1
ľíeap ľíee

ľhe ľíeap tíee is made up of a tíee, and the heap is a binaíy seaích tíee.

Píopeíīies

 Each node has two values: a key and a píioíity.

 Follows a binaíy seaích tíee píopeíty.

 Píioíity of the tíeap tíee follows the heap píopeíty.

14
2
1. Ïull Binaíy ľíee: A full binaíy tíee is a binaíy tíee wheíe eveíy node
has eitheí 0 oí 2 childíen. No node can have only 1 child. ľhis type of tíee
is also known as a stíict binaíy tíee. In a full binaíy tíee, the numbeí of
leaf nodes is equal to the numbeí of inteínal nodes plus 1. ľhis type of
tíee is often used to íepíesent hieíaíchical íelationships, as each node
can have a paíent and two childíen.

2. Peífect Binaíy ľíee: A peífect binaíy tíee is a full binaíy tíee wheíe all
leaf nodes aíe at the same depth and all inteínal nodes have two
childíen. ľhe height of a peífect binaíy tíee is log2n, wheíe n is the
numbeí of nodes in the tíee. ľhis type of tíee is often used in computeí
algoíithms, as it allows foí efficient íepíesentation and píocessing of
data.

3. Complete Binaíy ľíee: A complete binaíy tíee is a binaíy tíee wheíe


eveíy level is completely filled, except foí possibly the last level, which is
filled fíom left to íight. ľhis type of tíee is often used in algoíithms that
íequiíe data to be stoíed in a heap stíuctuíe, such as a píioíity queue oí
heap soít. ľhe advantage of using a complete binaíy tíee oveí otheí
types of tíees is that the tíee can be efficiently stoíed in an aííay.

14
3
4. Degeneíate Binaíy ľíee: A degeneíate binaíy tíee is a tíee in which
eveíy inteínal node has only one child. ľhis íesults in a tíee that is
similaí to a linked list. Degeneíate tíees aíe not commonly used in
computeí algoíithms, as they do not píovide efficient access to data. In
many cases, a degeneíate tíee can be íeplaced with a moíe efficient
data stíuctuíe, such as an aííay oí linked list.

5. Balanced Binaíy ľíee: A balanced binaíy tíee is a binaíy tíee wheíe


the height diffeíence between the left and íight subtíees of any node is
no gíeateí than some constant value. ľhis helps ensuíe fast seaích
times and píevent the tíee fíom becoming too unbalanced. Examples of
balanced binaíy tíees include íed-black tíees and AVL tíees. ľhese tíees
aíe commonly used in computeí algoíithms and data stíuctuíes that 14
íequiíe fast access to data, such as seaích tíees and heaps. 4
ľhe advantage of using a balanced binaíy tíee is that seaích times aíe
guaíanteed to be logaíithmic, ensuíing efficient access to data.

Representing Binary Trees in memory

 Binary trees can be represented

I. using a single array called the sequential representation of the tree


II. using linked list

Sequential representation of Binary Trees-

This representation uses only a single linear array Tree as follows:

 The root R of T is stored in TREE[1]


 If a node N occupies TREE[K], then its left child is stored in TREE[2*K] and its right
child is stored in TREE[2*K+1]

145
 It can be seen that a sequential representation of a binary tree requires
numbering of nodes; starting with nodes on level 1, then on level 2, and so on. The
nodes are numbered from left to right.
 It is an ideal case for the representation of a complete binary tree and in this case,
no space is wasted. However, for other binary trees, most of the space remains
unutilized. As can be seen in the figure, we require 14 locations in the array even
though the tree has only 9 nodes. If null entries for successors of the terminal
nodes are included, we would actually require 29 locations instead of 14. Thus
sequential representation is usually inefficient unless the binary tree is complete
or nearly complete.

14
6
Linked representation of Binary Tree

 In linked representation, Tree is maintained in memory by means of three parallel


arrays, INFO, LEFT, and RIGHT, and a pointer variable ROOT. Each node N of T will
correspond to a location K such that INFO[K] contains data at node
N. LEFT[K] contains the location of the left child of node N and RIGHT[K] contains
the location of right child of node N. ROOT will contain the location of root R of
Tree. If any subtree is empty, the corresponding pointer will contain a null value. If
the tree T itself is empty, then ROOT will contain a null value

Traversing binary trees


There are three types of binary tree traversals.

1. In - Order Traversal
2. Pre - Order Traversal
3. Post - Order Traversal

Consider the following binary tree...

147
1. In - Order Traversal ( leftChild - root - rightChild )
In In-Order traversal, the root node is visited between the left child and right child. In this traversal, the left
child node is visited first, then the root node is visited and later we go for visiting the right child node. This
in-order traversal is applicable for every root node of all subtrees in the tree. This is performed recursively
for all nodes inthetree.
In the above example of a binary tree, first we try to visit left child of root node 'A', but A's left child 'B' is a
root node for left subtree. so we try to visit its (B's) left child 'D' and again D is a root for subtree with
nodes D, I and
J. So we try to visit its left child 'I' and it is the leftmost child. So first we visit 'I' then go for its root node 'D'
and later we visit D's right child 'J'. With this we have completed the left part of node B. Then visit 'B' and
next B's right child 'F' is visited. With this we have completed left part of node A. Then visit root node 'A'.
With this we have completed left and root parts of node A. Then we go for the right part of the node A.
In right of A again there is a subtree with root C. So go for left child of C and again it is a subtree with root
G. But G does not have left part so we visit 'G' and then visit G's right child K. With this we have completed
the left part of node C. Then visit root node 'C' and next visit C's right child 'H' which is the rightmost child
in the tree. So we stop the process.

That means here we have visited in the order of I - D - J - B - F - A - G - K - C - H using In-Order Traversal.
In-Order Traversal for above example of binary tree is

I-D-J-B-F-A-G-K-C-H

2. Pre - Order Traversal ( root - leftChild - rightChild )


In Pre-Order traversal, the root node is visited before the left child and right child nodes. In this traversal,
the root node is visited first, then its left child and later its right child. This pre-order traversal is applicable
for every root node of all subtrees in the
tree. In the above example of binary tree, first we visit root node 'A' then visit its left child
'B' which is a root for D and F. So we visit B's left child 'D' and again D is a root for I and J. So we visit D's
left child 'I' which is the leftmost child. So next we go for visiting D's right child 'J'. With this we have
completed root, left and right parts of node D and root, left parts of node B. Next visit B's right child 'F'.
With this we have completed root and left parts of node A. So we go for A's right child 'C' which is a root
node for G and H. After visiting C, we go for its left child 'G' which is a root for node K. So next we visit left
of G, but it does not have left child so we go for G's right child 'K'. With this, we have completed node C's
root and left parts. Next visit C's right child 'H' which is the rightmost child in the
tree. So we stop the process.

That means here we have visited in the order of A-B-D-I-J-F-C-G-K-H using Pre-Order Traversal.
Pre-Order Traversal for above example binary tree is

A-B-D-I-J-F-C-G-K-H

3. Post - Order Traversal ( leftChild - rightChild - root )


In Post-Order traversal, the root node is visited after left child and right child. In this traversal, left child
node is visited first, then its right child and then its root node. This is recursively performed until 14
the right
most node is 8
visited.

Here we have visited in the order of I - J - D - F - B - K - G - H - C - A using Post-Order Traversal.


Post-Order Traversal for above example binary tree is

I-J-D-F-B-K-G-H-C-A

Pre-order Traversal Without Recursion

The following operations are performed to traverse a binary tree in pre-order using a stack:

1. Start with root node and push onto stack.


2. Repeat while the stack is not empty
1. POP the top element (PTR) from the stack and process the node.
2. PUSH the right child of PTR onto to stack.
3. PUSH the left child of PTR onto to stack.
Consider the following tree.

Start with node 4 and push it onto the stack.

Since the stack is not empty, POP 4 from the stack, process it and PUSH its left(7) and right(18) child onto the
stack. 14
9
Repeat the same process since the stack is not empty. POP 7 from the stack, process it and PUSH its left(8)
and right (13) child onto the stack.

Again, POP 8 from the stack and process it. Since it has no right or left child we don’t have to PUSH anything to
the stack.

Now POP 13 from the stack and process it. We don’t have to PUSH anything to the stack because it also doesn’t
have any subtrees.

15
0
POP 18 from the stack, process it and PUSH its left(5) and right(2) child to the stack.

Similarly POP 5 and 2 from the stack one after another. Since both these nodes don’t have any child, we don’t
have to PUSH anything onto the stack.

15
1
The nodes are processed in the order

[ 4, 7, 8, 3, 18, 5, 2 ]
. This is the required preorder traversal of the given tree.
The formal algorithm is given below:

1. Set TOP = 1. STACK[1] = NULL and PTR = ROOT.


2. Repeat Steps 3 to 5 while PTR ≠ NULL:
3. Apply PROCESS to PTR->DATA.
4. If PTR->RIGHT ≠ NULL, then:
Set TOP = TOP + 1, and STACK[TOP] = PTR->RIGHT.
[End of If]
5. If PTR->LEFT ≠ NULL, then:
Set PTR = PTR -> LEFT.
Else:
Set PTR = STACK[TOP] and TOP = TOP - 1.
[End of If]
[End of Step 2 loop.]
6. Exit.
In-order Traversal Without Recursion

The following operations are performed to traverse a binary tree in in-order using a stack:

1. Start from the root, call it PTR.


2. Push PTR onto stack if PTR is not NULL.
3. Move to left of PTR and repeat step 2.
4. If PTR is NULL and stack is not empty, then Pop element from stack and set as PTR.
5. Process PTR and move to right of PTR , go to step
2. Consider the following tree.

15
2
Start with node 4 and call it PTR. Since PTR is not NULL, PUSH it onto the stack.

Move to the left of node 4. Now PTR is node 7, which is not NULL. So PUSH it onto the stack.

Again, move to the left of node 7. Now PTR is node 8, which is not NULL. So PUSH it onto the stack.

15
3
When we move again to the left of node 8, PTR becomes NULL. So POP 8 from the stack. Process PTR (8).

Move to the right child of PTR(8), which is NULL. So POP 7 from the stack and process it. Now PTR points to 7.

Move to the right child(13) of PTR and PUSH it onto the stack.

15
4
Move to the left of node 13, which is NULL. So POP 13 from the stack and process it.

Since node 13 don’t have any right child, POP 4 from the stack and process it. Now PTR points to node 4.

Move to the right of node 4 and put it on to the stack. Now PTR points to node 18.

15
5
Move to the left(5) child of 18 and put it onto the stack. Now PTR points to node 5.

Move to the left of node 5, which is NULL. So POP 5 from the stack and process it.

Now, move to the right of node 5, which is NULL. So POP 18 from the stack and process it.

15
6
Move to the right(2) of node 18 and PUSH it on to the stack.

Since node 2 has left child, POP 2 from the stack and process it. Now the stack is empty and node 2 has
no right child. So stop traversing.

The nodes are processed in the order

[ 8, 7, 13, 4, 5, 18, 2 ]
. This is the required in order traversal of the given tree.
The formal algorithm is given below:

1. Set TOP = 1, STACK[1] = NULL and PTR = ROOT.


2. Repeat while PTR ≠ NULL: 15
7
(a) Set TOP = TOP + 1 and STACK[TOP] = PTR.
(b) Set PTR = PTR-
>LEFT. [End of loop.]
3. Set PTR = STACK[TOP] and TOP = TOP - 1.
4. Repeat Steps 5 to 7 while PTR ≠ NULL:
5. Apply PROCESS to PTR->INFO.
6. If PTR->RIGHT ≠ NULL, then:
(a) Set PTR = PTR->RIGHT.
(b) Go to Step
3. [End of If]
7. Set PTR = STACK[TOP] and TOP =
TOP -1. [End of Step 4 loop.]
8. Exit.
Post-order Traversal Without Recursion

The post order traversal algorithm is more difficult to implement than the previous two algorithms. The
following operations are performed to traverse a binary tree in post-order using a stack:

1. Start from the root, call it PTR.


2. Push PTR onto stack if PTR is not NULL.
3. Move to left of PTR and repeat step 2.
4. If PTR has a right child R, then PUSH -R onto the stack.
5. Pop and process positive element from stack and set as PTR.
6. If a negative node is popped, (PTR = -N), then set PTR = N and go to step 2.

The formal algorithm is given below:

1. Set TOP = 1. STACK[1] = NULL and PTR = ROOT.

2. Repeat Steps 3 to 5 while PTR ≠ NULL:

3. Set TOP = TOP + 1 and STACK[TOP] = PTR.

4. If PTR->RIGHT ≠ NULL. then: [Push on

STACK. ] Set TOP = TOP + 1 and

STACK[TOP] = PTR->-RIGHT. [End of If

structure.]

5. Set PTR = PTR->LEFT. [Updates pointer PTR.]

15
[End of Step 2 loop.] 8
6. Set PTR = STACK[TOP] and TOP = TOP - 1.

7. Repeat while PTR > 0:

(a) Apply PROCESS to PTR->INFO.

(b) Set PTR = STACK[TOP] and TOP = TOP - 1.

[End of loop.]

8. If PTR < 0, then:

(a) Set PTR = -PTR.

(b) Go to Step 2.

[End of If structure]

9. Exit.

Introduction:

A Graph is a non-linear data structure consisting of vertices and edges. The


vertices are sometimes also referred to as nodes and the edges are lines or arcs
that connect any two nodes in the graph. More formally a Graph is composed of
a set of vertices( V ) and a set of edges( E ). The graph is denoted by G(V, E).
Imagine a game of football as a web of connections, where players are the
nodes and their interactions on the field are the edges. This web of
connections is exactly what a graph data structure represents, and it’s the key
to unlocking insights into team performance and player dynamics in sports.
Components of a Graph
 Vertices: Vertices are the fundamental units of the graph. Sometimes,
vertices are also known as vertex or nodes. Every node/vertex can be
labeled or unlabelled.
 Edges: Edges are drawn or used to connect two nodes of the graph. It
can be ordered pair of nodes in a directed graph. Edges can connect
any two nodes in any possible way. There are no rules. Sometimes,
edges are also known as arcs. Every edge can be labelled/unlabelled.

159
Types Of Graph
1. Null Graph
A graph is known as a null graph if there are no edges in the graph.
2. Trivial Graph
Graph having only a single vertex, it is also the smallest graph possible.

3. Undirected Graph
A graph in which edges do not have any direction. That is the nodes are
16
unordered pairs in the definition of every edge. 0
4. Directed Graph
A graph in which edge has direction. That is the nodes are ordered pairs in the
definition of every edge.

5. Connected Graph
The graph in which from one node we can visit any other node in the graph is
known as a connected graph.
6. Disconnected Graph
The graph in which at least one node is not reachable from a node is known
as a disconnected graph.

7. Regular Graph
The graph in which the degree of every vertex is equal to K is called K regular
graph.
8. Complete Graph
The graph in which from each node there is an edge to each other node.
16
1
.

9. Cycle Graph
The graph in which the graph is a cycle in itself, the degree of each vertex is 2.
10. Cyclic Graph
A graph containing at least one cycle is known as a Cyclic graph.

11. Directed Acyclic Graph


A Directed Graph that does not contain any cycle.
12. Bipartite Graph
A graph in which vertex can be divided into two sets such that vertex in each set
does not contain any edge between them.

162
13. Weighted Graph
 A graph in which the edges are already specified with suitable
weight is known as a weighted graph.
 Weighted graphs can be further classified as directed weighted
graphs and undirected weighted graphs.

Graph representation
A graph is a data structure that consist a sets of vertices (called nodes) and edges. There
are two ways to store Graphs into the computer's memory:

o Sequential representation (or, Adjacency matrix representation)


o Linked list representation (or, Adjacency list representation)

In sequential representation, an adjacency matrix is used to store the graph. Whereas in


linked list representation, there is a use of an adjacency list to store the graph.

In this tutorial, we will discuss each one of them in detail.

Now, let's start discussing the ways of representing a graph in the data structure.

Sequential representation
In sequential representation, there is a use of an adjacency matrix to represent the
mapping between vertices and edges of the graph. We can use an adjacency matrix to
represent the undirected graph, directed graph, weighted directed graph, and weighted
undirected graph.

If adj[i][j] = w, it means that there is an edge exists from vertex i to vertex j with weight w.
16
3
An entry Aij in the adjacency matrix representation of an undirected graph G will be 1 if
an edge exists between Vi and Vj. If an Undirected Graph G consists of n vertices, then
the adjacency matrix for that graph is n x n, and the matrix A = [aij] can be defined as -

aij = 1 {if there is a path exists from Vi

to Vj} aij = 0 {Otherwise}

It means that, in an adjacency matrix, 0 represents that there is no association exists


between the nodes, whereas 1 represents the existence of a path between two edges.

If there is no self-loop present in the graph, it means that the diagonal entries of the
adjacency matrix will be 0.

Now, let's see the adjacency matrix representation of an undirected graph.

In the above figure, an image shows the mapping among the vertices (A, B, C, D, E), and
this mapping is represented by using the adjacency matrix.

There exist different adjacency matrices for the directed and undirected graph. In a directed
graph, an entry Aij will be 1 only when there is an edge directed from Vi to Vj.

Adjacency matrix for a directed graph


In a directed graph, edges represent a specific path from one vertex to another vertex.
Suppose a path exists from vertex A to another vertex B; it means that node A is the
initial node, while node B is the terminal node.

Consider the below-directed graph and try to construct the adjacency matrix of it.

164
In the above graph, we can see there is no self-loop, so the diagonal entries of the
adjacent matrix are 0.

Adjacency matrix for a weighted directed graph

It is similar to an adjacency matrix representation of a directed graph except that


instead of using the '1' for the existence of a path, here we have to use the weight
associated with the edge. The weights on the graph edges will be represented as the
entries of the adjacency matrix. We can understand it with the help of an example.
Consider the below graph and its adjacency matrix representation. In the representation,
we can see that the weight associated with the edges is represented as the entries in the
adjacency matrix.

In the above image, we can see that the adjacency matrix representation of the weighted
directed graph is different from other representations. It is because, in this
representation, the non-zero values are replaced by the actual weight assigned to the
edges.

Adjacency matrix is easier to implement and follow. An adjacency matrix can be used
when the graph is dense and a number of edges are large.
16
5
Though, it is advantageous to use an adjacency matrix, but it consumes more space.
Even if the graph is sparse, the matrix still consumes the same space.

Linked list representation


An adjacency list is used in the linked representation to store the Graph in the
computer's memory. It is efficient in terms of storage as we only have to store the values
for edges.

Let's see the adjacency list representation of an undirected graph.

In the above figure, we can see that there is a linked list or adjacency list for every node
of the graph. From vertex A, there are paths to vertex B and vertex D. These nodes are
linked to nodes A in the given adjacency list.

An adjacency list is maintained for each node present in the graph, which stores the
node value and a pointer to the next adjacent node to the respective node. If all the
adjacent nodes are traversed, then store the NULL in the pointer field of the last node of
the list.

The sum of the lengths of adjacency lists is equal to twice the number of edges present
in an undirected graph.

Now, consider the directed graph, and let's see the adjacency list representation of that
graph.

For a directed graph, the sum of the lengths of adjacency lists is equal to the number of
edges present in the graph. 16
6
Now, consider the weighted directed graph, and let's see the adjacency list representation
of that graph.

In the case of a weighted directed graph, each node contains an extra field that is called
the weight of the node.

In an adjacency list, it is easy to add a vertex. Because of using the linked list, it also saves
space.

Graph Traversal in Data Structure

We can tíaveíse a gíaph in two ways :

1. BFS ( Bíeadth Fiíst Seaích )

2. DFS ( Depth Fiíst Seaích )


BFS Graph Traversal in Data Structure

Bíeadth-fiíst seaích (BFS) tíaveísal is a technique foí visiting all nodes in a given
netwoík. ľhis tíaveísal algoíithm selects a node and visits all neaíby nodes in
oídeí. Afteí checking all neaíby veítices, examine anotheí set of veítices, then
íecheck adjacent veítices. ľhis algoíithm uses a queue as a data stíuctuíe as
an additional data stíuctuíe to stoíe nodes foí fuítheí píocessing. Queue size is
the maximum total numbeí of veítices in the gíaph.

How does BFS work?


Starting from the root, all the nodes at a particular level are visited first and
then the nodes of the next level are traversed till all the nodes are visited.
To do this a queue is used. All the adjacent unvisited nodes of the current level
are pushed into the queue and the nodes of the current level are marked
visited and popped from the queue.
Illustration:
Let us understand the working of the algorithm with the help of the following
example.
Step1: Initially queue and visited arrays are empty.
167
Queue and visited arrays are empty initially.

Step2: Push node 0 into queue and mark it visited.

Push node 0 into queue and mark it visited.

Step 3: Remove node 0 from the front of queue and visit the unvisited neighbours and
push them into queue.

168
Remove node 0 from the front of queue and visited the unvisited neighbours and push into queue.

Step 4: Remove node 1 from the front of queue and visit the unvisited neighbours and
push them into queue.

Remove node 1 from the front of queue and visited the unvisited neighbours and push

Step 5: Remove node 2 from the front of queue and visit the unvisited neighbours and
push them into queue.

Remove node 2 from the front of queue and visit the unvisited neighbours and push them into queue.

Step 6: Remove node 3 from the front of queue and visit the unvisited neighbours and
push them into queue.
As we can see that every neighbours of node 3 is visited, so move to the next node that are
in the front of the queue.

169
Remove node 3 from the front of queue and visit the unvisited neighbours and push them into queue.

Steps 7: Remove node 4 from the front of queue and visit the unvisited neighbours and
push them into queue.
As we can see that every neighbours of node 4 are visited, so move to the next node that is
in the front of the queue.

Remove node 4 from the front of queue and visit the unvisited neighbours and push them into queue.

Now, Queue becomes empty, So, terminate these process of iteration.

DFS Graph Traversal in Data Structure

When tíaveísing a gíaph, the DFS method goes as faí as it can befoíe tuíning
aíound. ľhis algoíithm exploíes the gíaph in depth-fiíst oídeí, staíting with a
given souíce node and then íecuísively visiting all of its suííounding veítices
befoíe backtíacking. DFS will analyze the deepest veítices in a bíanch of the
gíaph befoíe moving on to otheí bíanches. ľo implement DFS, eitheí íecuísion 17
oí an explicit stack might be utilized. 0
Example of Depth-Ïiíst Seaích Algoíithm

ľhe outcome of a DFS tíaveísal of a gíaph is a spanning tíee. A spanning tíee is a


gíaph that is devoid of loops. ľo implement DFS tíaveísal, you need to utilize a stack
data stíuctuíe with a maximum size equal to the total numbeí of veítices in the
gíaph.

ľo implement DFS tíaveísal, you need to take the following stages.

Step 1: Cíeate a stack with the total numbeí of veítices in the gíaph as the size.

Step 2: Choose any veítex as the tíaveísal's beginning point. Push a visit to that veítex
and add it to the stack.

Step 3 - Push any non-visited adjacent veítices of a veítex at the top of the stack to
the top of the stack.

Step 4 - Repeat steps 3 and 4 until theíe aíe no moíe veítices to visit fíom the veítex at the
top of the stack.

Step 5 - If theíe aíe no new veítices to visit, go back and pop one fíom the stack using

backtíacking. Step 6 - Continue using steps 3, 4, and 5 until the stack is empty.

Step 7 - When the stack is entiíely unoccupied, cíeate the final spanning tíee by deleting the
gíaph's unused edges.

Consideí the following gíaph as an example of how to use the dfs algoíithm.

171
Step 1: Maík veítex A as a visited souíce node by selecting it as a souíce node.

 You should push veítex A to the top of the stack.

17
2
Step 2: Any neaíby unvisited veítex of veítex A, say B, should be visited.

 You should push veítex B to the top of the stack.

Step 3: Fíom veítex C and D, visit any adjacent unvisited veítices of veítex B.
Imagine you have chosen veítex C, and you want to make C a visited veítex.

 Veítex C is pushed to the top of the stack.

17
3
Step 4: You can visit any neaíby unvisited veítices of veítex C, you need to select
veítex D and designate it as a visited veítex.

 Veítex D is pushed to the top of the stack.

17
4
Step 5: Veítex E is the lone unvisited adjacent veítex of veítex D, thus maíking it as visited.

 Veítex E should be pushed to the top of the stack.

Step 6: Veítex E's neaíby veítices, namely veítex C and D have been visited, pop
veítex E fíom the stack.

175
Step 7: Now that all of veítex D's neaíby veítices, namely veítex B and C, have been
visited, pop veítex D fíom the stack.

Step 8: Similaíly, veítex C's adjacent veítices have alíeady been visited; theíefoíe,
pop it fíom the stack.

17
6
Step 9: ľheíe is no moíe unvisited adjacent veítex of b, thus pop it fíom the stack.

17
7
Step 10: All of the neaíby veítices of Veítex A, B, and C, have alíeady been visited, so
pop veítex A fíom the stack as well.

Now, examine the pseudocode foí the depth-fiíst seaích algoíithm in this.

17
8
DATA STRUCTURES-1
Assignment-1
Q1: What is the need of data structure? Discuss various types of data
structures. Q2: What do you mean by efficiency of an algorithm?
Q3: Difference between time and space complexity.
Q4: Explain the concept of best case, average case & worst case time complexity.
Q5: What is strings and its operations?
Q6: Write an algorithm of Pattern matching.

DATA STRUCTURES-1
Assignment- 2
Q1: What is an array? Discuss the various operations on linear array and write and algorithm for inserting and deleting an
element into a linear array.
Q2: What is the difference between array and linked list? How can you represent a linked in memory? Explain the
insertion and deletion operation of linked list.
Q3: Write a short note on:
a) Sparse arrays
b) Header linked list
c) Circular linked list
d) Two-way linked list
e) Threaded linked list
f) Garbage collection
Q4: Differentiate between 1-D and 2-D arrays with example.
Q5: Discuss the advantages and disadvantages of array and linked list. Also write its applications.

DATA STRUCTURES-1
Assignment-3
Q1: What is stack? What are the basic operations performed on stack? Write down the algo to perform these
operations.
Q2: What is postfix notation? Explain the method of evaluating postfix expression by giving suitable example.
Q3: What is queue? How are queues implemented in memory? What are the various queue operations? Write an
algo for each.
Q4: Write shorn note on:
a) Priority queue
b) Double ended queue
c) Polish notation
d) Applications of stack & queue
DATA STRUCTURES-1
Assignment-4
Q1: What is binary tree? What are its traversing methods? Explain with the help of example.
Q2: Describe binary search tree and its application. Write an algo for searching and inserting a node in
binary search tree.
Q3: Describe graph. Explain sequential & linked representation of graphs.
Q4: Discuss the breadth first search & depth first search traversal technique with the help of example.

17
9
18
0
18
1
Ans 1 a): What is Stíing?

Strings are defined as an array of characters. The difference between a character array and a string is the
string is terminated with a special character ‘\0’.

String Data Structure

Below aíe some examples of stíings:


“geeks”, “for”, “geeks”, “GeeksforGeeks”, “Geeks for Geeks”, “123Geeks”, “@123 Geeks”

How Stíing is íepíesented in Memoíy?


In C, a string can be referred to either using a character pointer or as a character array. When
strings are declared as character arrays, they are stored like other types of arrays in C. For
example, if str[] is an auto variable then the string is stored in the stack segment, if it’s a global or
static variable then stored in the data segment, etc.

What is String & How String is represented in Memory

18
2
b) What is an Algorithm?

An algorithm is a process or a set of rules required to perform calculations or some other


problem- solving operations especially by a computer. The formal definition of an
algorithm is that it contains the finite set of instructions which are being carried in a
specific order to perform the specific task. It is not the complete program or code; it is
just a solution (logic) of a problem, which can be represented either as an informal
description using a Flowchart or Pseudocode.

Characteristics of an Algorithm
The following are the characteristics of an algorithm:

o Input: An algorithm has some input values. We can pass 0 or some input value to an
algorithm.
o Output: We will get 1 or more output at the end of an algorithm.
o Unambiguity: An algorithm should be unambiguous which means that the instructions in
an algorithm should be clear and simple.
o Finiteness: An algorithm should have finiteness. Here, finiteness means that the
algorithm should contain a limited number of instructions, i.e., the instructions should be
countable.
o Effectiveness: An algorithm should be effective as each instruction in an algorithm
affects the overall process.
o Language independent: An algorithm must be language-independent so that the
instructions in an algorithm can be implemented in any of the languages with the same
output.

c) What is Aííay?

An array is a collection of items stored at contiguous memory locations. The idea is to store multiple items of
the same type together. This makes it easier to calculate the position of each element by simply adding an
offset to a base value, i.e., the memory location of the first element of the array (generally denoted by the
name of the array).

Array Data Structure 18


3
The above image can be looked as a top-level view of a staircase where you are at the base of the staircase.
Each element can be uniquely identified by their index in the array (in a similar way as you could identify
your friends by the step on which they were on in the above example).

d) A header linked list is a variation of the standard linked list data structure. It is used to
keep track of the head (first element) and tail (last element) of the list, allowing for faster
manipulation at both ends of the list. This makes it useful in certain types of data
manipulation or traversal tasks, such as those that require frequent additions or removals at
both the front and back of the list.

e) A priority queue is a type of queue that arranges elements based on their


priority values. Elements with higher priority values are typically retrieved
before elements with lower priority values.
In a priority queue, each element has a priority value associated with it. When
you add an element to the queue, it is inserted in a position based on its priority
value. For example, if you add an element with a high priority value to a
priority queue, it may be inserted near the front of the queue, while an
element with a low priority value may be inserted near the back.

f) Applications of Priority queue


The following are the applications of the priority queue:

o It is used in the Dijkstra's shortest path algorithm.


o It is used in prim's algorithm
o It is used in data compression techniques like Huffman code.
o It is used in heap sort.
o It is also used in operating system like priority scheduling, load balancing and interrupt
handling.

g) Properties of Tree Data Structure

In computer science, a tree is a widely used data structure that simulates a


hierarchical tree structure with a set of linked nodes. A tree data structure has the
following properties:

1. Recursive data structure


2. Number of edges
3. Depth of node x
4. Height of node x
1. Recursive Data Structure: A tree is a recursive data structure because it has a root node, and every node
has zero or more child nodes. The root node is the topmost node in the tree, and the child nodes
ar1e84located
below the root node. If each node in the tree has zero or more child nodes, then the tree is said to be an n-
aryl tree.
2. Number of Edges: The number of edges in a tree is always one less than the number of nodes. This is
because there is always one fewer edge than there are nodes in any given path from the root to any
leaf node.
3. Depth of Node x: The depth of a node is defined as the length of the shortest path from the root to that
node. In other words, it is simply the number of edges on the path from the root to that particular
node.
4. Height of Node x: The height of a node is expressed as the length of the longest path from the node to any
leaf node. In other words, it is simply the number of edges on the path from that particular node to the
deepest leaf node.

h) Applications of Graph Data Structure



A graph is a non-linear data structure, which consists of vertices(or nodes) connected by
edges(or arcs) where edges may be directed or undirected.

 In Computer science graphs are used to represent the flow of computation.


 Google maps uses graphs for building transportation systems, where intersection of
two(or more) roads are considered to be a vertex and the road connecting two
vertices is considered to be an edge, thus their navigation system is based on the
algorithm to calculate the shortest path between two vertices.
 In Facebook, users are considered to be the vertices and if they are friends then
there is an edge running between them. Facebook’s Friend suggestion algorithm uses
graph theory. Facebook is an example of undirected graph.
 In World Wide Web, web pages are considered to be the vertices. There is an edge
from a page u to other page v if there is a link of page v on page u. This is an
example of Directed graph. It was the basic idea behind Google Page Ranking
Algorithm.
 In Operating System, we come across the Resource Allocation Graph where each
process and resources are considered to be vertices. Edges are drawn from
resources to the allocated process, or from requesting process to the requested
resource. If this leads to any formation of a cycle then a deadlock will occur.
18
5
Unit-1
Ans 2: Differentiate between:
S.NO Linear Data Structure Non-linear Data Structure

In a linear data structure, data elements are


arranged in a linear order where each and In a non-linear data structure, data elements
1.
every element is attached to its previous and are attached in hierarchically manner.
next adjacent.

In linear data structure, single level is Whereas in non-linear data structure, multiple
2.
involved. levels are involved.

Its implementation is easy in comparison to While its implementation is complex in


3.
non-linear data structure. comparison to linear data structure.

While in non-linear data structure, data


In linear data structure, data elements can be
4. elements can’t be traversed in a single run
traversed in a single run only.
only.

While in a non-linear data structure, memory


In a linear data structure, memory is not
5. is utilized in an efficient way.
utilized in an efficient way.

Its examples are: array, stack, queue, linked


6. While its examples are: trees and graphs.
list, etc.

Applications of non-linear data structures are


Applications of linear data structures are
7. in Artificial Intelligence and image
mainly in application software development.
processing.

Non-linear data structures are useful for


Linear data structures are useful for simple representing complex relationships and data
8.
data storage and manipulation. hierarchies, such as in social networks, file
systems, or computer networks.

Performance is usually good for simple


Performance can vary depending on the
operations like adding or removing at the
9. structure and the operation, but can be
ends, but slower for operations like searching
optimized for specific operations.
or removing elements in the middle.

18
6
Primitive data structure Non-primitive data structure

Primitive data structure is a kind of Non-primitive data structure is a type of data


data structure that stores the data of structure that can store the data of more
only one type. than one type.

Examples of primitive data structure Examples of non-primitive data structure are


are integer, character, float. Array, Linked list, stack.

Primitive data structure will contain Non-primitive data structure can consist of a
some value, i.e., it cannot be NULL. NULL value.

The size depends on the type of the In case of non-primitive data structure, size
data structure. is not fixed.

It starts with a lowercase character. It starts with an uppercase character.

Primitive data structure can be used to Non-primitive data structure cannot be used
call the methods. to call the methods.

Aspect Static Data Structure Dynamic Data Structure

Memory Memory is allocated


Memory is allocated at run-
allocation at compile- time
time

Size is fixed and cannot


Size Size can be modified during
be modified runtime

Memory Memory utilization may Memory utilization is efficient as


utilization be inefficient memory can be reused

Access time is faster as Access time may be slower


Access
it is fixed due to indexing and
pointer usage

Arrays, Stacks, Queues, Lists, Trees (with variable size),


Examples
Trees (with fixed Hash tables
size)

18
7
Ans 3: Complexity in algorithms refers to the amount of resources (such as time or
memory) required to solve a problem or perform a task. The most common
measure of complexity is time complexity, which refers to the amount of time
an algorithm takes to produce a result as a function of the size of the input.
Memory complexity refers to the amount of memory used by an algorithm.
Algorithm designers strive to develop algorithms with the lowest possible time
and memory complexities, since this makes them more efficient and scalable.
The complexity of an algorithm is a function describing the efficiency of the
algorithm in terms of the amount of data the algorithm must process.
Usually there are natural units for the domain and range of this function.
An algorithm is analyzed using Time Complexity and Space Complexity. Writing
an efficient algorithm help to consume the minimum amount of time for
processing the logic. For algorithm A, it is judged on the basis of two
parameters for an input of size n :
 Time Complexity: Time taken by the algorithm to solve the problem. It is
measured by calculating the iteration of loops, number of comparisons etc.
 Time complexity is a function describing the amount of time an algorithm takes
in terms of the amount of input to the algorithm.
 “Time” can mean the number of memory accesses performed, the number of
comparisons between integers, the number of times some inner loop is executed,
or some other natural unit related to the amount of real time the algorithm will
take.
 Space Complexity: Space taken by the algorithm to solve the problem. It includes
space used by necessary input variables and any extra space (excluding the space
taken by inputs) that is used by the algorithm. For example, if we use a hash table
(a kind of data structure), we need an array to store values so
 this is an extra space occupied, hence will count towards the space complexity
of the algorithm. This extra space is known as Auxiliary Space.
 Space complexity is a function describing the amount of memory(space)an
algorithm takes in terms of the amount of input to the algorithm.
 Space complexity is sometimes ignored because the space used is minimal and/ or
obvious, but sometimes it becomes an issue as time.

Time-Space Trade-Off in Algorithms


Space-Time tradeoff in computer science is basically a problem solving technique in which we
solve the problem:

 Either in less time and using more space, or


18
8
 In very little space by spending more time.

18
9
The best algorithm is the one which helps to solve a problem that requires less space in
memory as well as takes less time to generate the output.But in general, it is not always
possible to achieve both of these conditions at the same time.

If our problem is taking a long time but not much memory, a space-time trade-off would let
us use more memory and solve the problem more quickly. Or, if it could be solved very
quickly but requires more memory than we have, we can try to spend more time solving the
problem in the limited memory.

Types of Time-Space Trade-Off

 Lookup tables or Recalculation


 Compressed or Uncompressed data
 Re Rendering or Stored images
 Smaller code or loop unrolling

1. Lookup tables or Recalculation:


In a lookup table, an implementation can include the entire table which reduces computing
time but increases the amount of memory required. It can recalculate i.e., compute table
entries as needed, increasing computing time but reducing memory requirements.

2. Compressed or Uncompressed data:


A space-time trade-off can be applied to the problem of data storage. If data stored is
uncompressed, it takes more space but less time. But if the data is stored compressed, it
takes less space but more time to run the decompression algorithm. There are many
instances where it is possible to directly work with compressed data. In that case of
compressed bitmap indices, where it is faster to work with compression than without
compression.

3. Re Rendering or Stored images:


In this case, storing only the source and rendering it as an image would take more space but
less time i.e., storing an image in the cache is faster than re-rendering but requires more
space in memory.

4. Smaller code or loop unrolling:


Smaller code occupies less space in memory but it requires high computation time that
is required for jumping back to the beginning of the loop at the end of each iteration.
Loop 18
9
unrolling can optimize execution speed at the cost of increased binary size. It occupies
more space in memory but requires less computation time.

Example:
There are many algorithms that make use of time-space tradeoffs. Some of the algorithms are:

 In the field of cryptography, using space-time trade-off, the attacker is decreasing the
exponential time required for a brute-force attack. Rainbow tables use partially
precomputed values in the hash space of a cryptographic hash function to crack
passwords in minutes instead of weeks. Decreasing the size of the rainbow table
increases the time required to iterate over the hash space. The meet-in-the-middle
attack uses a space-time trade-off to find the cryptographic key in only 2^{n+1}
encryptions (and O(2^{n}) space) compared to the expected 2^{2n} encryptions
(but only O(1) space) of the normal attack.
 Dynamic programming is another example where the time of solving problems
can be decreased by using more memory. Fibonacci problem can be solved faster
with DP.

What is Big O Notation in Data Stíuctuíe?

Big O Notation in Data Stíuctuíe is used to expíess algoíithmic complexity using algebíaic
teíms. It descíibes the uppeí bound of an algoíithm's íuntime and calculates the time and
amount of memoíy needed to execute the algoíithm foí an input value.

Mathematical Definition

Consideí the functions f(n) and g(n), wheíe functions f and g aíe defined on an
unbounded set of positive íeal numbeís. g(n) is stíictly positive foí eveíy laíge value
of n.

ľhe function f is said to be O(g) (íead as big- oh of g), if, foí a constant c>0 and a natuíal
numbeí n0, f
(n) ≤ CG(n) foí all n >= n0

ľhis can be wíitten as:

190
f(n) = O(g(n)), wheíe n tends to infinity (n
→ ∞)
We can simply wíite the above expíession as:

f(n) = O(g(n))

Píopeíties of Big O Notation

ľhe most impoítant píopeíties of Big O Notation in Data Stíuctuíe aíe:

 Constant Multiplication:

If f(n) = CG(n), then O(f(n)) = O(g(n)) foí a constant c > 0

 Summation Function:

If f(n) = f1(n) + f2(n) + -- + FM(n) and fi(n)≤ fi+1(n) ∀ i=1, 2, --, m,

then O(f(n)) = O(max(f1(n), f2(n), --, fm(n)))

 Logaíithmic Function:

If f(n) = log an and g(n)=log

bn, then O(f(n)) = O(g(n))

 Polynomial Function:

If f(n) = a0 + a1.n + a2.n2 + -- +

am.nm, then O(f(n)) = O(nm)

19
1
Unit-2
Ans4: Array
An array is a list of a finite number ‘n’ of homogeneous data element such that
c. The elements of the array are reference respectively by an index set
consisting of n consecutive numbers.
d. The element of the array are respectively in successive memory locations.

The number n of elements is called the length or size of the array. The length or
thenumbers of elements of the array can be obtained from the index set by the
formula When LB = 0,
Length = UB – LB
+ 1When LB = 1,
Length = UB
Where,
UB is the largest index called the Upper
Bound LB is the smallest index, called
the Lower Bound

4.Inserting

Let A be a collection of data elements stored in the memory of the


computer. Inserting refers to the operation of adding another element
to the collection A.

Inserting an element at the “end” of the linear array can be easily done
provided the memory space allocated for the array is large enough to
accommodate the additional element.

Inserting an element in the middle of the array, then on average, half of the
elements must be moved downwards to new locations to accommodate the
new element and keep the order of the other elements.

Algorithm:

INSERT (LA, N, K, ITEM)

Here LA is a linear array with N elements and K is a positive integer such that K
≤ N.This algorithm inserts an element ITEM into the Kt h position in LA.
1. [Initialize counter] set J:= N
19
2
2. Repeat step 3 and 4 while J ≥ K

3. [Move Jt h element downward] Set LA [J+1] :=


LA[J]
4. [Decrease counter] set J:= J – 1
[End of step 2 loop]

5. [Insert element] set LA[K]:= ITEM

6. [Reset N] set N:= N+1

7. Exit

b) 2D Array
2D array can be defined as an array of arrays. The 2D array is organized as matrices
which can be represented as the collection of rows and columns.

However, 2D arrays are created to implement a relational database look alike data
structure. It provides ease of holding bulk of data at once which can be passed to any
number of functions wherever required.

How to declare 2D Array


The syntax of declaring two dimensional array is very much similar to that of a one
dimensional array, given as follows.

1. int arr[max_rows][max_columns];

19
3
Above image shows the two dimensional array, the elements are organized in the form
of rows and columns. First element of the first row is represented by a[0][0] where the
number shown in the first index is the number of that row while the number shown in the
second index is the number of the column.

How do we access data in a 2D array


Due to the fact that the elements of 2D arrays can be random accessed. Similar to one
dimensional arrays, we can access the individual cells in a 2D array by using the indices
of the cells. There are two indices attached to a particular cell, one is its row number
while the other is its column number.

However, we can store the value stored in any particular cell of a 2D array to some
variable x by using the following syntax.

1. int x = a[i][j];

where i and j is the row and column number of the cell

respectively. We can assign each cell of a 2D array to 0 by

using the following code:

1. for ( int i=0; i<n ;i++)


2. {
3. for (int j=0; j<n; j++)
4. {
5. a[i][j] = 0;
6. }
7. }

Mapping 2D array to 1D array


When it comes to map a 2 dimensional array, most of us might think that why this
mapping is required. However, 2 D arrays exists from the user point of view. 2D arrays
are created to implement a relational database table lookalike data structure, in
computer memory, the storage technique for 2D array is similar to that of an one
dimensional array.

The size of a two dimensional array is equal to the multiplication of number of rows and
the number of columns present in the array. We do need to map two dimensional array
to the one dimensional array in order to store them in the memory.

A 3 X 3 two dimensional array is shown in the following image. However, this array needs
to be mapped to a one dimensional array in order to store it into the memory.
19
4
There are two main techniques of storing 2D array elements into memory

1. Row Major ordering


In row major ordering, all the rows of the 2D array are stored into the memory
contiguously. Considering the array shown in the above image, its memory allocation
according to row major order is shown as follows.

first, the 1st row of the array is stored into the memory completely, then the 2nd row of
the array is stored into the memory completely and so on till the last row.

2. Column Major ordering

19
5
According to the column major ordering, all the columns of the 2D array are stored into
the memory contiguously. The memory allocation of the array which is shown in in the
above image is given as follows.

first, the 1st column of the array is stored into the memory completely, then the 2 nd row
of the array is stored into the memory completely and so on till the last column of the
array.

Calculating the Address of the random element of a 2D array


Due to the fact that, there are two different techniques of storing the two dimensional
array into the memory, there are two different formulas to calculate the address of a
random element of the 2D array.

By Row Major Order


If array is declared by a[m][n] where m is the number of rows while n is the number of
columns, then address of an element a[i][j] of the array stored in row major order is
calculated as,

1. Address(a[i][j]) = B. A. + (i * n + j) * size

where, B. A. is the base address or the address of the first element of the array a[0][0] .

Example :

1. a[10...30, 55...75], base address of the array (BA) = 0, size of an element = 4 bytes .
2. Find the location of a[15][68].
3.
4. Address(a[15][68]) = 0 +
5. ((15 - 10) x (68 - 55 + 1) + (68 - 196
55)) x 4
6.
7. = (5 x 14 + 13) x 4
8. = 83 x 4
9. = 332 answer
By Column major order
If array is declared by a[m][n] where m is the number of rows while n is the number of
columns, then address of an element a[i][j] of the array stored in row major order is
calculated as,

1. Address(a[i][j]) = ((j*m)+i)*Size

+ BA where BA is the base address of

the array. Example:

1. A [-5 ... +20][20 ... 70], BA = 1020, Size of element = 8 bytes. Find the location of
a[0][30].
2.
3. Address [A[0][30]) = ((30-20) x 24 + 5) x 8 + 1020 = 245 x 8 + 1020 = 2980 bytes

Ans 5: What is a Linked List?

 A linked list is a lineaí data stíuctuíe that stoíes a collection of data elements dynamically.

 Nodes íepíesent those data elements, and links oí pointeís connect each node.

 Each node consists of two fields, the infoímation stoíed in a linked list and a pointeí
that stoíes the addíess of its next node.

 ľhe last node contains null in its second field because it will point to no node.

 A linked list can gíow and shíink its size, as peí the íequiíement.

 It does not waste memoíy space.

Repíesentation of a Linked List

ľhis íepíesentation of a linked list depicts that each node consists of two fields. ľhe
fiíst field consists of data, and the second field consists of pointeís that point to
anotheí node.
19
7
Heíe, the staít pointeí stoíes the addíess of the fiíst node, and at the end, theíe is a null
pointeí that states the end of the Linked List.

Cíeation of Node and Declaíation of Linked Lists

stíuct node

int data;

stíuct node *

next;

};
19
8
stíuct node * n;

n=(stíuct node*)malloc(sizeof(stíuct
node*));

It is a declaíation of a node that consists of the fiíst vaíiable as data and the next as a
pointeí, which will keep the addíess of the next node.

Heíe you need to use the malloc function to allocate memoíy foí the nodes dynamically.

ľypes of Linked Lists

ľhe linked list mainly has thíee types, they aíe:

1. Singly Linked List

2. Doubly Linked List

3. Ciículaí Linked List

Singly Linked List

A singly linked list is the most common type of linked list. Each node has data and an
addíess field that contains a íefeíence to the next node.

19
9
Doubly Linked List

ľheíe aíe two pointeí stoíage blocks in the doubly linked list. ľhe fiíst pointeí block in
each node stoíes the addíess of the píevious node. Hence, in the doubly linked inventoíy,
theíe aíe thíee fields that aíe the píevious pointeís, that contain a íefeíence to the
píevious node. ľhen theíe is the data, and last you have the next pointeí, which points to
the next node. ľhus, you can go in both diíections (backwaíd and foíwaíd).

20
0
Ciículaí Linked List

ľhe ciículaí linked list is extíemely similaí to the singly linked list. ľhe only diffeíence is
that the last node is connected with the fiíst node, foíming a ciículaí loop in the
ciículaí linked list.

Ciículaí link lists can eitheí be singly oí doubly-linked lists.

 ľhe next node's next pointeí will point to the fiíst node to foím a singly linked list.

 ľhe píevious pointeí of the fiíst node keeps the addíess of the last node to foím a doubly-
linked list.

Essential Opeíation on Linked Lists

 ľíaveísing: ľo tíaveíse all nodes one by one.

 Inseítion: ľo inseít new nodes at specific positions.

 Deletion: ľo delete nodes fíom specific positions.

 Seaíching: ľo seaích foí an element fíom the linked list.

Advantages of a Linked List over Arrays


20
Below aíe some advantages of Linked List oveí Aííays in píogíamming, including:
1
1. Dynamic Size: One of the most significant advantages of linked list
oveí aííays is that linked lists can gíow oí shíink dynamically duíing
íuntime. ľhis means that the size of a linked list can be adjusted to
accommodate new elements oí íemove existing elements without having
to allocate oí deallocate a fixed-size block of memoíy, as is the case
with aííays.
2. Efficient Inseítion and Deletion: Linked lists allow efficient inseítion
and deletion of elements at any position in the list, wheíeas aííays íequiíe
shifting of elements when a new element is added oí íemoved, which can
be slow and inefficient foí laíge aííays.
3. Memoíy Efficiency: Linked lists use memoíy moíe efficiently than
aííays. In an aííay, all elements must be stoíed in contiguous memoíy
locations, even if some of the elements aíe not used. In contíast, linked
lists only allocate memoíy foí the elements that aíe used, which can save
memoíy in cases wheíe the size of the data set is unknown oí vaíies oveí
time.
4. Easy Implementation of Abstíact Data ľypes: Linked lists aíe
easy to use and implement when implementing abstíact data types
such as stacks, queues, and tíees. ľhese data stíuctuíes íequiíe
fíequent inseítion and deletion of elements, which is a task in which
linked lists aíe well-suited.
5. Moíe Efficient Soíting: In some cases, linked lists can be moíe
efficient foí soíting algoíithms than aííays. ľhis is because linked lists do
not íequiíe swapping elements like aííays, which can be time-consuming
foí laíge aííays.

In shoít, theíe aíe seveíal advantages of linked list oveí aííays, such as dynamic
size, efficient inseítion and deletion, memoíy efficiency, easy implementation
of abstíact data types, and moíe efficient soíting in some cases.

Disadvantages of a Linked List over Arrays

While theíe aíe seveíal advantages of linked list oveí aííays, they also have
some disadvantages that need to be consideíed. Heíe aíe some
disadvantages of linked list oveí aííays:

1. Random Access: Linked lists do not píovide íandom access to elements


like aííays do. ľo access an element in a linked list, we have to staít at
the beginning of the list and tíaveíse the list until we find the desiíed
element. ľhis makes accessing individual elements in a linked list
sloweí than in an aííay.

2. Extía Memoíy Usage: Linked lists íequiíe extía memoíy compaíed to


aííays. Each element in a linked list íequiíes a íefeíence to the next
element, which takes up additional memoíy space. In contíast, aííays
only need memoíy to stoíe the elements themselves.
3. Moíe Complex Implementation: Implementing a linked list is moíe
complex than implementing an aííay because it íequiíes managing
pointeís and dynamically allocating memoíy. ľhis complexity can lead
to moíe bugs and eííoís in the code.
b) Deleting Elements from a Linked List

Let’s discuss how a node can be deleted from a linked listed in the following cases.

4. The first node is deleted.


5. The last node is deleted.
6. The node after a given node is deleted.

Delete a Node from the beginning of a Linked list

Suppose we want to delete a node from the beginning of the linked list. The list has to be
modified as follows:

 Check if the linked list is empty or not. Exit if the list is empty.
 Make HEAD points to the second node.
 Free the first node from memory.
Algorithm: DeleteFromBeginning

Step 1: IF HEAD = NULL


Write UNDERFLOW
Go to Step
5 [END OF
IF]
Step 2: SET PTR = HEAD
Step 3: SET HEAD = HEAD ->
NEXT Step 4: FREE PTR 20
3
Step 5: EXIT
Delete last Node from a Linked list

Suppose we want to delete the last node from the linked list. The linked list has to be

 Traverse to the end of the list.


 Change value of next pointer of second last node to NULL.
 Free last node from memory.
Algorithm: DeleteFromEnd

Step 1: IF HEAD =
NULL Write
UNDERFLOW
Go to Step
8 [END OF
IF]
Step 2: SET PTR = HEAD
Step 3: Repeat Steps 4 and 5 while PTR -> NEXT !=
NULL Step 4: SET PREPTR = PTR
Step 5: SET PTR = PTR ->
NEXT [END OF LOOP]
Step 6: SET PREPTR -> NEXT =
NULL Step 7: FREE PTR
Step 8: EXIT
Here we use two pointers PTR and PREPTR to access the last node and the second last node.

Delete the Node after a given Node in a Linked list

20
4
 Traverse the list upto the specified node.
 Change value of next pointer of previous node(9) to next pointer of current node(10).
Algorithm: DeleteAfterANode

Step 1: IF HEAD =
NULL Write
UNDERFLOW
Go to Step
10 [END OF
IF]
Step 2: SET PTR =
HEAD Step 3: SET
PREPTR = PTR
Step 4: Repeat Steps 5 and 6 while PREPTR -> DATA !
= NUM Step 5: SET PREPTR = PTR
Step 6: SET PTR = PTR ->
NEXT [END OF LOOP]
Step 7: SET TEMP = PTR
Step 8: SET PREPTR -> NEXT = PTR -
> NEXT Step 9: FREE TEMP

20
5
Unit-3

Ans 6 a): What is a


Stack?
A Stack is a linear data structure that follows the LIFO (Last-In-First-Out) principle.
Stack has one end, whereas the Queue has two ends (front and rear). It contains only
one pointer top pointer pointing to the topmost element of the stack. Whenever an
element is added in the stack, it is added on the top of the stack, and the element can be
deleted only from the stack. In other words, a stack can be defined as a container in
which insertion and deletion can be done from the one end known as the top
of the stack.

Some key points related to stack


o It is called as stack because it behaves like a real-world stack, piles of books, etc.
o A Stack is an abstract data type with a pre-defined capacity, which means that it can
store the elements of a limited size.
o It is a data structure that follows some order to insert and delete the elements, and that
order can be LIFO or FILO.

Working of Stack
Stack works on the LIFO pattern. As we can observe in the below figure there are five
memory blocks in the stack; therefore, the size of the stack is 5.

Suppose we want to store the elements in a stack and let's assume that stack is empty.
We have taken the stack of size 5 as shown below in which we are pushing the elements
one by one until the stack becomes full.

20
6
Since our stack is full as the size of the stack is 5. In the above cases, we can observe
that it goes from the top to the bottom when we were entering the new element in the
stack. The stack gets filled up from the bottom to the top.

When we perform the delete operation on the stack, there is only one way for entry and
exit as the other end is closed. It follows the LIFO pattern, which means that the value
entered first will be removed last. In the above case, the value 5 is entered first, so it will
be removed only after the deletion of all the other elements.

Standard Stack Operations


The following are some common operations implemented on the stack:

o push(): When we insert an element in a stack then the operation is known as a push. If
the stack is full then the overflow condition occurs.
o pop(): When we delete an element from the stack, the operation is known as a pop. If the
stack is empty means that no element exists in the stack, this state is known as an
underflow state.
o isEmpty(): It determines whether the stack is empty or not.
o isFull(): It determines whether the stack is full or not.'
o peek(): It returns the element at the given position.
o count(): It returns the total number of elements available in a stack.
o change(): It changes the element at the given position.
o display(): It prints all the elements available in the stack.

PUSH operation
The steps involved in the PUSH operation is given below:

o Before inserting an element in a stack, we check whether the stack is full.


o If we try to insert the element in a stack, and the stack is full, then the overflow condition
occurs.
o When we initialize a stack, we set the value of top as -1 to check that the stack is empty.
o When the new element is pushed in a stack, first, the value of the top gets
incremented, i.e., top=top+1, and the element will be placed at the new position of the
top.
o The elements will be inserted until we reach the max size of the stack.

20
7
POP operation
The steps involved in the POP operation is given below:

o Before deleting the element from the stack, we check whether the stack is empty.
o If we try to delete the element from the empty stack, then the underflow condition occurs.
o If the stack is not empty, we first access the element which is pointed by the top
o Once the pop operation is performed, the top is decremented by 1, i.e., top=top-1.

20
8
Applications of Stack
The following are the applications of the stack:

o Balancing of symbols: Stack is used for balancing a symbol. For example, we have the
following program:

1. int main()
2. {
3. cout<<"Hello";
4. cout<<"javaTpoint";
5. }

As we know, each program has an opening and closing braces; when the opening braces
come, we push the braces in a stack, and when the closing braces appear, we pop the
opening braces from the stack. Therefore, the net value comes out to be zero. If any
symbol is left in the stack, it means that some syntax occurs in a program.

o String reversal: Stack is also used for reversing a string. For example, we want to
reverse a "javaTpoint" string, so we can achieve this with
the help of a stack. First, we push all the characters of the string in
a stack until we reach the null character. After pushing all the characters, we start
taking out the character one by one until we reach the bottom of the stack.
o UNDO/REDO: It can also be used for performing UNDO/REDO operations. For example, we
have an editor in which we write 'a', then 'b', and then 'c'; therefore, the text written in an
editor is abc. So, there are three states, a, ab, and abc, which are stored in a stack. There
would be two stacks in which one stack shows UNDO state, and the
other shows REDO state. If we want to perform UNDO operation, and want
to achieve 'ab' state, then we implement pop operation.
o Recursion: The recursion means that the function is calling itself again. To maintain the
previous states, the compiler creates a system stack in which all the previous records of
the function are maintained.
o DFS(Depth First Search): This search is implemented on a Graph, and Graph uses the
stack data structure.
o Backtracking: Suppose we have to create a path to solve a maze problem. If we are
moving in a particular path, and we realize that we come on the wrong way. In order to
come at the beginning of the path to create a new path, we have to use the stack data
structure.
o Expression conversion: Stack can also be used for expression conversion. This is one of
the most important applications of stack. The list of the expression conversion is given
below:
o Infix to prefix
o Infix to postfix 20
9
o Prefix to infix
o Prefix to postfix
Postfix to infix

o Memory management: The stack manages the memory. The memory is assigned in the
contiguous memory blocks. The memory is known as stack memory as all the variables
are assigned in a function call stack memory. The memory size assigned to the program is
known to the compiler. When the function is created, all its variables are assigned in the
stack memory. When the function completed its execution, all the variables assigned in
the stack are released.

b) Array implementation of Stack


In array implementation, the stack is formed by using the array. All the operations
regarding the stack are performed using arrays. Lets see how each operation can be
implemented on the stack using array data structure.

Adding an element onto the stack (push operation)


Adding an element into the top of the stack is referred to as push operation. Push
operation involves following two steps.

1. Increment the variable Top so that it can now refere to the next memory location.
2. Add element at the position of incremented top. This is referred to as adding new element
at the top of the stack.

Stack is overflown when we try to insert an element into a completely filled stack
therefore, our main function must always avoid stack overflow condition.

Algorithm:

1. begin
2. if top = n then stack full
3. top = top + 1
4. stack (top) : = item;
5. end

Time Complexity : o(1)

implementation of push algorithm in C


language
1. void push (int val,int n) //n is size of the stack
210
2. {
3. if (top == n )
4. printf("\n Overflow");
5. else
6. {
7. top = top +1;
8. stack[top] = val;
9. }
10. }
Deletion of an element from a stack (Pop operation)
Deletion of an element from the top of the stack is called pop operation. The value of the
variable top will be incremented by 1 whenever an item is deleted from the stack. The
top most element of the stack is stored in an another variable and then the top is
decremented by 1. the operation returns the deleted value that was stored in another
variable as the result.

The underflow condition occurs when we try to delete an element from an already empty
stack.

Algorithm :

1. begin
2. if top = 0 then stack empty;
3. item := stack(top);
4. top = top - 1;
5. end;

Time Complexity : o(1)

Implementation of POP algorithm using C


language
1. int pop ()
2. {
3. if(top == -1)
4. {
5. printf("Underflow");
6. return 0;
7. }
8. else
9. {
10. return stack[top - - ];
11. }
12. }
Visiting each element of the stack (Peek
operation)
211
Peek operation involves returning the element which is present at the top of the stack
without deleting it. Underflow condition can occur if we try to return the top element in
an already empty stack.

Algorithm :

PEEK (STACK, TOP)

1. Begin
2. if top = -1 then stack empty
3. item = stack[top]
4. return item
5. End

Time complexity: o(n)

Implementation of Peek algorithm in C language


1. int peek()
2. {
3. if (top == -1)
4. {
5. printf("Underflow");
6. return 0;
7. }
8. else
9. {
10. return stack [top];
11. }
12. }

Ans 7 a): What is Queue Data Stíuctuíe?


A Queue is defined as a linear data structure that is open at both ends and the operations are performed
in First In First Out (FIFO) order.
We define a queue to be a list in which all additions to the list are made at one end, and all deletions
from the list are made at the other end. The element which is first pushed into the order, the operation
is first performed on that.

21
2
Queue Data Structure

FIFO Píinciple of Queue:


 A Queue is like a line waiting to purchase tickets, where the first person in line is the first
person served. (i.e. First come first serve).
 Position of the entry in a queue ready to be served, that is, the first entry that will be removed from
the queue, is called the front of the queue(sometimes, head of the queue), similarly, the position of
the last entry in the queue, that is, the one most recently added, is called the rear (or the tail) of the
queue. See the below figure.

Fifo Property in Queue

Chaíacteíistics of Queue:
 Queue can handle multiple data.
 We can access both ends.
 They are fast and flexible.

21
3
Some common applications of Queue data structure :
1. Task Scheduling: Queues can be used to schedule tasks based on
priority or the order in which they were received.
2. Resource Allocation: Queues can be used to manage and allocate
resources, such as printers or CPU processing time.
3. Batch Processing: Queues can be used to handle batch processing jobs,
such as data analysis or image rendering.
4. Message Buffering: Queues can be used to buffer messages in
communication systems, such as message queues in messaging
systems or buffers in computer networks.
5. Event Handling: Queues can be used to handle events in event-driven
systems, such as GUI applications or simulation systems.
6. Traffic Management: Queues can be used to manage traffic flow in
transportation systems, such as airport control systems or road
networks.
7. Operating systems: Operating systems often use queues to manage
processes and resources. For example, a process scheduler might use
a queue to manage the order in which processes are executed.
8. Network protocols: Network protocols like TCP and UDP use queues to
manage packets that are transmitted over the network. Queues can
help to ensure that packets are delivered in the correct order and at
the appropriate rate.
9. Printer queues :In printing systems, queues are used to manage the
order in which print jobs are processed. Jobs are added to the
queue as they are submitted, and the printer processes them in
the order they were received.
10. Web servers: Web servers use queues to manage incoming
requests from clients. Requests are added to the queue as they are
received, and they are processed by the server in the order they
were received.
11. Breadth-first search algorithm: The breadth-first search algorithm uses
a queue to explore nodes in a graph level-by-level. The algorithm
starts at a given node, adds its neighbors to the queue, and then
processes each neighbor in turn.

b) What is a Circular Queue?


A Circular Queue is an extended version of a normal queue where the last element of the
queue is connected to the first element of the queue forming a circle.
21
4
The operations are performed based on FIFO (First In First Out) principle. It is
also called ‘Ring Buffer’.

21
5
In a normal Queue, we can insert elements until queue becomes full. But once
queue becomes full, we can not insert the next element even if there is a space
in front of queue.

Algorithm
Insertion of an element
o STEP 1 START
o STEP 2 Store the element to insert in linear data structure
o STEP 3 Check if (front == 0 && rear == MAX-1) || (front == rear+1) then queue Overflow
else goto step 4
o STEP 4 Check if (front == -1) then front = 0; rear= 0; else goto step 5
o STEP 5 Check if (rear == MAX -1) then rear=0; else rear= rear+1; and goto step 6
o STEP 6 Insert element cqueue_arr[rear] = item;
o STEP 7 STOP

21
6
Unit-4

Ans 8: Binary
Tree
The Binary tree means that the node can have maximum two children. Here, binary name
itself suggests that 'two'; therefore, each node can have either 0, 1 or 2 children.

Let's understand the binary tree through an example.

The above tree is a binary tree because each node contains the utmost two children.
The logical representation of the above tree is given below:

21
7
In the above tree, node 1 contains two pointers, i.e., left and a right pointer pointing to
the left and right node respectively. The node 2 contains both the nodes (left and right
node); therefore, it has two pointers (left and right). The nodes 3, 5 and 6 are the
leaf nodes, so all these nodes contain NULL pointer on both left and right parts.

Properties of Binary Tree


o At each level of i, the maximum number of nodes is 2i.
o The height of the tree is defined as the longest path from the root node to the leaf node.
The tree which is shown above has a height equal to 3. Therefore, the maximum number
of nodes at height 3 is equal to (1+2+4+8) = 15. In general, the maximum number of
nodes possible at height h is (2 0 + 21 + 22+….2h) = 2h+1 -1.
o The minimum number of nodes possible at height h is equal to h+1.
o If the number of nodes is minimum, then the height of the tree would be maximum.
Conversely, if the number of nodes is maximum, then the height of the tree would be
minimum.

Traversing in the Binary Tree


Tree traversal is the process of visiting each node in the tree exactly once.
Visiting each node in a graph should be done in a systematic manner. If search
result in a visit to all the vertices, it is called a traversal. There are basically three
traversal techniques for a binary tree that are,

1. Preorder traversal
2. Inorder traversal
3. Postorder traversal
21
8
1) Preorder traversal
To traverse a binary tree in preorder, following operations are carried out:

1. Visit the root.


2. Traverse the left sub tree of root.
3. Traverse the right sub tree of root.

Note: Preorder traversal is also known as NLR traversal.

Algorithm:

Algorithm preorder(t)
/*t is a binary tree. Each node of t has three fields:
lchild, data, and rchild.*/
{
If t! =0 then
{
Visit(t);
Preorder(t->lchild);
Preorder(t->rchild);
}
}

Example: Let us consider the given binary tree,

21
9
Therefore, the preorder traversal of the above tree will be: 7,1,0,3,2,5,4,6,9,8,10

2) Inorder traversal
To traverse a binary tree in inorder traversal, following operations are carried out:

1. Traverse the left most sub tree.


2. Visit the root.
3. Traverse the right most sub tree.

Note: Inorder traversal is also known as LNR traversal.

Algorithm:

Algorithm inorder(t)

/*t is a binary tree. Each node of t has three fields:


lchild, data, and rchild.*/
{
If t! =0 then
{
Inorder(t->lchild);
Visit(t);
Inorder(t->rchild);
}
}

Example: Let us consider a given binary tree.

22
0
Therefore the inorder traversal of above tree will be: 0,1,2,3,4,5,6,7,8,9,10

3) Postorder traversal
To traverse a binary tree in postorder traversal, following operations are carried out:

1. Traverse the left sub tree of root.


2. Traverse the right sub tree of root.
3. Visit the root.

Note: Postorder traversal is also known as LRN traversal.

Algorithm:

Algorithm postorder(t)

/*t is a binary tree .Each node of t has three fields:


lchild, data, and rchild.*/
{
If t! =0 then
{
Postorder(t->lchild);
Postorder(t->rchild);
Visit(t);
}
}

Example: Let us consider a given binary tree.

Therefore the postorder traversal of the above tree will be: 220
0,2,4,6,5,3,1,8,10,9,7
Ans 9: What is a tree?
A tree is a kind of data structure that is used to represent the data in hierarchical form. It
can be defined as a collection of objects or entities called as nodes that are linked
together to simulate a hierarchy. Tree is a non-linear data structure as the data in a tree
is not stored linearly or sequentially.

Now, let's start the topic, the Binary Search tree.

What is a Binary Search tree?


A binary search tree follows some order to arrange the elements. In a Binary search tree,
the value of left node must be smaller than the parent node, and the value of right node
must be greater than the parent node. This rule is applied recursively to the left and
right subtrees of the root.

Let's understand the concept of Binary search tree with an example.

In the above figure, we can observe that the root node is 40, and all the nodes of the left
subtree are smaller than the root node, and all the nodes of the right subtree are greater
than the root node.

Similarly, we can see the left child of root node is greater than its left child and smaller
than its right child. So, it also satisfies the property of binary search tree. Therefore, we
can say that the tree in the above image is a binary search tree.

Suppose if we change the value of node 35 to 55 in the above tree, check whether the
tree will be binary search tree or not.

22
1
In the above tree, the value of root node is 40, which is greater than its left child 30 but
smaller than right child of 30, i.e., 55. So, the above tree does not satisfy the property of
Binary search tree. Therefore, the above tree is not a binary search tree.

Advantages of Binary search tree


o Searching an element in the Binary search tree is easy as we always have a hint that
which subtree has the desired element.
o As compared to array and linked lists, insertion and deletion operations are faster in BST.

Example of creating a binary search tree


Now, let's see the creation of binary search tree using an

example. Suppose the data elements are - 45, 15, 79, 90, 10,

55, 12, 20, 50

o First, we have to insert 45 into the tree as the root of the tree.
o Then, read the next element; if it is smaller than the root node, insert it as the root of the
left subtree, and move to the next element.
o Otherwise, if the element is larger than the root node, then insert it as the root of the right
subtree.

Now, let's see the process of creating the Binary search tree using the given data
element. The process of creating the BST is shown below -

Step 1 - Insert 45.

22
2
Step 2 - Insert 15.

As 15 is smaller than 45, so insert it as the root node of the left subtree.

Step 3 - Insert 79.

As 79 is greater than 45, so insert it as the root node of the right subtree.

Step 4 - Insert 90.

90 is greater than 45 and 79, so it will be inserted as the right subtree of 79.

22
3
Step 5 - Insert 10.

10 is smaller than 45 and 15, so it will be inserted as a left subtree of 15.

Step 6 - Insert 55.

55 is larger than 45 and smaller than 79, so it will be inserted as the left subtree of 79.

22
4
Step 7 - Insert 12.

12 is smaller than 45 and 15 but greater than 10, so it will be inserted as the right subtree
of 10.

Step 8 - Insert 20.

20 is smaller than 45 but greater than 15, so it will be inserted as the right subtree of 15.

22
5
Step 9 - Insert 50.

50 is greater than 45 but smaller than 79 and 55. So, it will be inserted as a left subtree of
55.

Now, the creation of binary search tree is completed. After that, let's move towards the
operations that can be performed on Binary search tree.
22
6
We can perform insert, delete and search operations on the binary

search tree. Let's understand how a search is performed on a binary

search tree.

Searching in Binary search tree


Searching means to find or locate a specific element or node in a data structure. In
Binary search tree, searching a node is easy because elements in BST are stored in a
specific order. The steps of searching a node in Binary Search tree are listed as follows -

1. First, compare the element to be searched with the root element of the tree.
2. If root is matched with the target element, then return the node's location.
3. If it is not matched, then check whether the item is less than the root element, if it is
smaller than the root element, then move to the left subtree.
4. If it is larger than the root element, then move to the right subtree.
5. Repeat the above procedure recursively until the match is found.
6. If the element is not found or not present in the tree, then return NULL.

Now, let's understand the searching in binary tree using an example. We are taking the
binary search tree formed above. Suppose we have to find node 20 from the below tree.

Step1:

Step2:

227
Step3:

Now, let's see the algorithm to search an element in the Binary search tree.

Algorithm to search an element in Binary search tree


1. Search (root, item)
2. Step 1 - if (item = root → data) or (root = NULL)
3. return root
4. else if (item < root → data)
5. return Search(root → left, item)
6. else
7. return Search(root → right, item)
8. END if
9. Step 2 - END

Now let's understand how the deletion is performed on a binary search tree. We will also
see an example to delete an element from the given tree. 22
8
Deletion in Binary Search tree
In a binary search tree, we must delete a node from the tree by keeping in mind that the
property of BST is not violated. To delete a node from BST, there are three possible
situations occur -

o The node to be deleted is the leaf node, or,


o The node to be deleted has only one child, and,
o The node to be deleted has two children

We will understand the situations listed above in detail.

When the node to be deleted is the leaf node

It is the simplest case to delete a node in BST. Here, we have to replace the leaf node
with NULL and simply free the allocated space.

We can see the process to delete a leaf node from BST in the below image. In below
image, suppose we have to delete node 90, as the node to be deleted is a leaf node, so it
will be replaced with NULL, and the allocated space will free.

When the node to be deleted has only one child

In this case, we have to replace the target node with its child, and then delete the child
node. It means that after replacing the target node with its child node, the child node will
now contain the value to be deleted. So, we simply have to replace the child node with
NULL and free up the allocated space.

We can see the process of deleting a node with one child from BST in the below image.
In the below image, suppose we have to delete the node 79, as the node to be deleted
has only one child, so it will be replaced with its child 55.

So, the replaced node 79 will now be a leaf node that can be easily deleted.

22
9
When the node to be deleted has two children

This case of deleting a node in BST is a bit complex among other two cases. In such a
case, the steps to be followed are listed as follows -

o First, find the inorder successor of the node to be deleted.


o After that, replace that node with the inorder successor until the target node is placed at the
leaf of tree.
o And at last, replace the node with NULL and free up the allocated space.

The inorder successor is required when the right child of the node is not empty. We can
obtain the inorder successor by finding the minimum element in the right child of the
node.

We can see the process of deleting a node with two children from BST in the below
image. In the below image, suppose we have to delete node 45 that is the root node, as
the node to be deleted has two children, so it will be replaced with its inorder successor.
Now, node 45 will be at the leaf of the tree so that it can be deleted easily.

Now let's understand how insertion is performed on a binary search tree.

Insertion in Binary Search tree

23
0
A new key in BST is always inserted at the leaf. To insert an element in BST, we have to
start searching from the root node; if the node to be inserted is less than the root node,
then search for an empty location in the left subtree. Else, search for the empty location
in the right subtree and insert the data. Insert in BST is similar to searching, as we
always have to maintain the rule that the left subtree is smaller than the root, and right
subtree is larger than the root.

Now, let's see the process of inserting a node into BST using an example.

23
1
23
2

You might also like