Course File of DS-1 BCA
Course File of DS-1 BCA
MS. SWATI
FACULTY NAME
Lesson Plan
Syllabus
Notes (Unit 1-4)
Previous Year Question Papers
Lesson Plan
Name of the Faculty: Ms. Swati
Discipline BCA
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
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
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.
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.
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.
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.
It can hold value but not data. It can hold multiple types of data
Therefore, it is dataless. within a single object.
Data type examples are int, float, Data structure examples are stack,
double, etc. queue, tree, etc.
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
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,
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.
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.
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.
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.
Examples
Now let us have a deeper look at the Big O notation of various examples:
O(1):
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):
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):
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):
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];
/* 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;
JavaTPoint
#include <string.h>
int main()
/* String Declaration*/
char str[20];
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()
return 0;
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()
3
1
printf("Length of string string_a when maximum length is 5: %d", strnlen(string_a,
5));
return 0;
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()
}else
return 0;
}
3
0
The following output should be generated by this programme:
Output
string 1 and string 2 are different
#include <string.h>
int main()
/* below the first nine characters of string 1 and string 2 are compared.*/
if ( strncmp(string_1, string_2, 9) == 0 )
}else
return 0;
#include <string.h>
int main()
3
1
{
strcat(string_1,string_2);
return 0;
#include <string.h>
int main()
strncat(string_1,string_2, 3);
return 0;
#include <string.h>
3
2
int main()
strcpy(string_1,string_2);
return 0;
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()
/* This method copied the first twelve characters of string_2 into string_1.*/
strncpy(string_1,string_2, 12);
return 0;
3
3
}
#include <string.h>
int main()
return 0;
3
4
#include <stdio.h>
#include <string.h>
int main()
return 0;
3
5
}
#include <string.h>
int main()
return 0;
String storage
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
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
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
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.
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
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:
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
4
0
[End of step 2 loop]
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 an element at the “end” of the linear array can be easily done with
difficulties.
4
1
Algorithm
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
2. Repeat for J = K to 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
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;
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]);
}
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
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:
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 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
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:
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
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
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,
We find that 27 is smaller than 33 and these two values must be swapped.
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
To be precise, we are now showing how an array should look like after each
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
begin
BubbleSort(list) for
swap(list[i],
list[i+1])
end if
end for
program
#include <stdio.h>
int main()
int data[100],i,n,step,temp;
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,
Selection sort
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 −
5
9
Step 5 − Repeat until list is sorted
#include
<stdio.h>int
main()
elements\n");scanf("%d", &n);
printf("Enter %d integers\n",
scanf("%d", &array[c]);
position = c;
if (array[position] >
array[d])position = d;
if (position != c)
6
0
{
swap = array[c];
array[c] =
array[position];
array[position] = swap;
printf("%d\n",
array[c]);return 0;
6
1
Insertion Sort Algorithm
maintained which is always sorted. For example, the lower part of an array is
has to find its appropriate place and then it has to be inserted there. Hence the
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?
It finds that both 14 and 33 are already in ascending order. For now, 14 is in
sorted sub-list.
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.
By now we have 14 and 27 in the sorted sub-list. Next, it compares 33 with 10.
So we swap them.
6
3
Hence, we swap them too.
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.
Now we have a bigger picture of how this sorting technique works, so we can
6
4
#include <stdio.h>
int main()
scanf("%d", &n);
printf("Enter %d integers\n",
scanf("%d", &array[c]);
for (c = 1 ; c <= n - 1;
c++) {d = c;
array[d] = array[d-
1];array[d-1] =
temp;
d--;
}
}
printf("Sorted list in ascending order:\
6
5
}
return 0;
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.
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
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.
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
#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];
low = 0;
high = num - 1;
if (position != -1) {
printf("\nNumber present at %d", (position + 1));
} else
printf("\n The number is not present in the
list"); return (0);
}
if (low >
high)return
-1;
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);
}
}
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++;
// 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.
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.
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.
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
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.
8
2
All operations such as Insert, Delete, Traverse etc. require extra previous pointer to
be maintained.
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.
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.
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.
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 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.
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
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.
We will see how a new node can be added to an existing linked list in the following cases.
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
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.
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
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
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
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
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.
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
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.
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.
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.
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.
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
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
9
8
POP operation
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
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.
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
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;
Algorithm :
1. Begin
2. if top = -1 then stack empty
3. item = stack[top]
4. return item
5. End
5 printf("Underflow 102
. ");
6. return 0;
7. }
8. else
9. {
10. return stack [top];
11. }
12. }
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
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:
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
ľ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
10
6
Dynamic Daīa Sīíucīuíe
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.
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:
Print “Overflow”
Goto Step 4
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:
Print “Underflow”
Goto Step 4
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:
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.
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.
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+".
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()
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.
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.
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 [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.
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
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
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.
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.
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.
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.
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);
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 -
In input restricted queue, insertion operation can be performed at only one end, while
deletion can be performed from both ends.
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 -
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.
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 -
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.
= 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.
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.
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.
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.
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.
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.
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.
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.
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.
13
1
UNIT-4
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.
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.
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.
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.
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.
13
7
Binaíy ľíee
Píopeíīies
ľhese two childíen aíe called the left child and the íight child.
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
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
Píopeíīies
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
Self-balancing.
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
Píopeíīies
Self-balancing.
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
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.
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.
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
1. In - Order Traversal
2. Pre - Order Traversal
3. Post - Order Traversal
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
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
I-J-D-F-B-K-G-H-C-A
The following operations are performed to traverse a binary tree in pre-order using a 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:
The following operations are performed to traverse a binary tree in in-order using a stack:
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.
[ 8, 7, 13, 4, 5, 18, 2 ]
. This is the required in order traversal of the given tree.
The formal algorithm is given below:
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:
structure.]
15
[End of Step 2 loop.] 8
6. Set PTR = STACK[TOP] and TOP = TOP - 1.
[End of loop.]
(b) Go to Step 2.
[End of If structure]
9. Exit.
Introduction:
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.
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:
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 -
If there is no self-loop present in the graph, it means that the diagonal entries of the
adjacency matrix will be 0.
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.
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.
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.
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.
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.
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.
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
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.
17
2
Step 2: Any neaíby unvisited veítex of veítex A, say B, should be visited.
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.
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.
17
4
Step 5: Veítex E is the lone unvisited adjacent veítex of veítex D, thus maíking it as visited.
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’.
18
2
b) What is an Algorithm?
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).
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.
In linear data structure, single level is Whereas in non-linear data structure, multiple
2.
involved. levels are involved.
18
6
Primitive data structure Non-primitive data structure
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.
Primitive data structure can be used to Non-primitive data structure cannot be used
call the methods. to call the methods.
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.
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.
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.
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
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))
Constant Multiplication:
Summation Function:
Logaíithmic Function:
Polynomial Function:
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
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:
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
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.
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.
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];
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
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.
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.
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
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
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.
ľ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.
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.
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.
ľ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.
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.
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:
Let’s discuss how a node can be deleted from a linked listed in the following cases.
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
Suppose we want to delete the last node from the linked list. The linked list has to be
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.
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
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.
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:
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.
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
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;
Algorithm :
1. Begin
2. if top = -1 then stack empty
3. item = stack[top]
4. return item
5. End
21
2
Queue Data Structure
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.
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.
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.
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:
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);
}
}
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:
Algorithm:
Algorithm inorder(t)
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:
Algorithm:
Algorithm postorder(t)
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.
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.
example. Suppose the data elements are - 45, 15, 79, 90, 10,
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 -
22
2
Step 2 - Insert 15.
As 15 is smaller than 45, so insert it as the root node of the left subtree.
As 79 is greater than 45, so insert it as the root node of the right subtree.
90 is greater than 45 and 79, so it will be inserted as the right subtree of 79.
22
3
Step 5 - Insert 10.
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.
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.
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.
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 -
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.
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 -
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.
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