MDU BCA- Data Structures
MDU BCA- Data Structures
CONTACT NO-7827646303
2
Application of Stacks:Polish
Notation,Recursion
Queues:
Introduction
Array and Linked List Representation of
Queues
Operation on Queues
Deques
Priority Queues
Application of Queues
SECTION-IV
Trees:
Introduction
Defination
Representing Binary Tree in Memory
Traversing Binary Tree
Traversal Algorithm Using Stacks
Graph:
Introduction
Graph Theory Terminology
Sequential and Linked Representation of
Graphs
5
SECTION-I
INTRODUCTION
Elementary Data Organization:
Data Structure can be defined as the group of data elements
which provides an efficient way of storing and organising data
in the computer so that it can be used efficiently. Some
examples of Data Structures are arrays, Linked List, Stack,
Queue, etc. Data Structures are widely used in almost every
aspect of Computer Science i.e. Operating System, Compiler
Design, Artifical intelligence, Graphics and many more.
Data Structures are the main part of many computer science
algorithms as they enable the programmers to handle the data
in an efficient way. It plays a vital role in enhancing the
performance of a software or a program as the main function of
the software is to store and retrieve the user's data as fast as
possible.
Basic Terminology
Data structures are the building blocks of any program or the
software. Choosing the appropriate data structure for a program
is the most difficult task for a programmer. Following
terminology is used as far as data structures are concerned.
Data: Data can be defined as an elementary value or the
collection of values, for example, student's name and its id are
the data about the student.
6
children except the leaf nodes whereas each node can have
atmost one parent except the root node. Trees can be classfied
into many categories which will be discussed later in this
tutorial.
Graphs: Graphs can be defined as the pictorial representation
of the set of elements (represented by vertices) connected by
the links known as edges. A graph is different from tree in the
sense that a graph can have cycle while the tree can not have
the one.
Operations on data structure
1) Traversing: Every data structure contains the set of data
elements. Traversing the data structure means visiting each
element of the data structure in order to perform some specific
operation like searching or sorting.
Example: If we need to calculate the average of the marks
obtained by a student in 6 different subject, we need to traverse
the complete array of marks and calculate the total sum, then
we will devide that sum by the number of subjects i.e. 6, in
order to find the average.
2) Insertion: Insertion can be defined as the process of adding
the elements to the data structure at any location.
If the size of data structure is n then we can only insert n-1 data
elements into it.
3) Deletion:The process of removing an element from the data
structure is called Deletion. We can delete an element from the
data structure at any random location.
If we try to delete an element from an empty data structure
then underflow occurs.
11
Data structure has many different uses in our daily life. There
are many different data structures that are used to solve
different mathematical and logical problems. By using data
structure, one can organize and process a very large amount of
data in a relatively short period. Let’s look at different data
structures that are used in different situations.
18
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,
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.
20
computations.
It is used in image processing.
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 list:
Singly-linked list
Doubly linked list
Circular linked list
Doubly circular linked list
21
Linked List
etc.
The first node of the linked list is called the Head.
songs.
Stack:
Stack is a linear data structure that follows a particular order
in which the operations are performed. The order is LIFO(Last
in first out). Entering and retrieving data is possible from only
one end. The entering and retrieving of data is also called push
and pop operation in a stack. There are different operations
possible in a stack like reversing a stack using recursion,
Sorting, Deleting the middle element of a stack, etc.
23
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 array or linked list.
visited sites.
Call log in mobile also uses stack data structure.
Queue:
Queue is a linear data structure that follows a particular order
in which the operations are performed. The order is First In
First Out(FIFO) i.e. the data item stored first will be accessed
first. In this, entering and retrieving data is not done from only
one end. An example of a queue is any queue of consumers for
a resource where the consumer that came first is served first.
Different operations are performed on Queue like Reversing a
Queue (with or without using recursion), Reversing the first K
elements of a Queue, etc. Few basic operations performed In
Queue are enqueue, dequeue, front, rear, etc.
25
Characteristics of a Queue:
Queue has various different characteristics which are as
follows:
Queue is a FIFO (First In First Out) structure.
To remove the last element of Queue, all the elements
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 asynchronous transfer of data for e.g. pipes, file
IO, sockets.
Queues are used for job scheduling in operating system.
In social media to upload multiple phots or videos queue is
used.
To send an e-mail queue data structure is used.
To handle website traffic at a time queue are used.
In window operating system, to switch multiple application.
26
ticket windows.
Cashier line in a store is also an example of queue.
People on an escalator
Tree:
A tree is a non-linear and hierarchal 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.
27
Tree
Characteristics of a Tree:
Tree has various different characteristics which are as follows:
A tree is also known as a Recursive data structure.
In a tree, Height of the root can be defined as the longest
databases.
Syntax Tree helps in scanning, parsing, generation of code
in K-dimensional space.
Spanning trees are used in routers in computer networks.
networking site.
28
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. 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:
Graph has various different characteristics which are as
follows:
The maximum distance from a vertex to all the other
vertices is considered as the Eccentricity of that vertex.
The vertex having minimum Eccentricity is considered the
Also used in the World Wide Web where the web pages
represent the nodes.
Real-Life Applications of Graph:
One of the most common real-world examples of a graph is
chemistry.
Application of Strings:
3. Search engine.
4. Digital forensic and information retrieval system
5. Spell checkers.
6. In the database to check valid information of the user
Application of Matrix:
8. Mailing list.
9. Symbol table creation.
Application of Stack:
A stack is a data structure that uses LIFO order.
15. Recursion.
16. Used in IDEs to check for proper parentheses matching
17. Media playlist. T o play previous and next song
Application of Queue:
A queue is a data structure that uses FIFO order.
Priority Queue:
1. Process scheduling in the kernel.
2. Priority queues are used in file downloading operations in
a browser
3. Vehicle at the toll center.
Application of Graph:
Graph is a data structure where data is stored in a collection
of interconnected vertices (nodes) and edges (paths).
Application of Tree:
Trees are hierarchical structures having a single root node.
1. D Game Engine.
2. Computer Graphics Rendering.
3. Routing table.
RED-BLACK TREE
1. Used when there is frequent Insertion/Deletion and few
searches.
2. K -mean Clustering using a red-black tree, Databases,
Simple-minded database, searching words inside
dictionaries, searching on the web.
3. Process Scheduling in Linux.
AVL TREE
1. More Search and less Insertion/Deletion.
2. Data Analysis and Data Mining and the applications which
involve more searches.
SUFFIX TREE
1. Fast full-text search, used in most word processors.
TRIE
1. Dictionary application.
2. Autocomplete feature in searching.
3. Auto-completing the text and spells checking.
Application of Hash Tables:
Hash Tables are store data in key-value pairs. It only stores
data that has a key associated with it. Inserting and Searching
operations are easily manageable while using Hash Tables.
39
Application of Heap:
A Heap is a special case of a binary tree where the parent
nodes are compared to their children with their values and are
arranged accordingly.
1. Dijkstra algorithm.
2. Shopping on a tight budget but want to buy gifts for all
family members.
3. Prim’s and Kruskal’s algorithms are used for finding the
minimum spanning trees.
Dijkstra Algorithm
1. Used in applications like Google Maps to find the shortest
path in a graph.
PRIM’S and KRUSKAL’S
1. Used for finding the minimum spanning trees.
A. Real-life examples
1. In Google Maps to find the shortest path between the
source and the series of destinations (one by one) out of
the various available paths.
2. In networking to transfer data from a sender to various
receivers in a sequential manner.
B. Applications in Computer science
1. Multi-stage graph
2. Traveling salesman problem
3. Largest common subsequence – to identify similar videos
used by youtube
4. Optimal search binary tree- to get optimized search results.
5. Single source shortest path- Bellman-Ford Algorithm.
6. Document Distance Algorithms- to identify the extent of
similarity between two text documents used by Search
42
Application Of Backtracking:
F n = F n – 1 + F n – 2,
where, F0 = 0 and F1 = 1.
A simple solution to find the Nth Fibonacci
term using recursion from the above recurrence relation.
Below is the implementation using recursion:
#include <iostream>
int Fibonacci(int N)
// Base Case
if (N < 2)
return N;
// Driver Code
int main()
int N = 5;
// Function Call
return 0;
Output:
5
46
#include <iostream>
int Fibonacci(int N)
int i;
f[0] = 0;
f[1] = 1;
return f[N];
// Driver Code
int main()
int N = 5;
// Function Call
49
return 0;
Output:
5
Big-O notataion:
Big-O Analysis of Algorithms
O(N 2 )
Definition: Let g and f be functions from the set of natural
numbers to itself. The function f is said to be O(g) (read big-
50
C++
#include <bits/stdc++.h>
// main Code
int main()
//declare variable
int a = 0, b = 0;
//declare size
int N = 5, M = 5;
a = a + 5;
b = b + 10;
return 0;
Output
25 50
Explanation :
First Loop runs N Time whereas Second Loop runs M Time.
The calculation takes O(1)times.
So by adding them the time complexity will be O ( N + M +
1) = O( N + M).
Time Complexity : O( N + M)
57
CHAPTER-2
STRINGS
Introduction:
What is String?
Declaration of Strings
char str[] = { ‘J’ , ’A’ , ’V’ , ’A’ , ’T’ , ’P’ , ’O’ , ’I’ , ’N’
, ’T’ , ’\0’ };
char str[] = { “JAVATPOINT” };
o In this form of declaration, '0' will automatically
String datatypes
A datatype string is a datatype modeled on a structured
sequence concept. Strings are a data form that is so effective
and necessary that they are introduced in almost every
computer programming language. They are accessible as
primitive data types in a specific languages and synthetic
varieties in others. The structure of so many high-level
programming languages enables an occurrence of a string
datatype to be interpreted by a string, typically referenced in
certain manner; such a meta-string is called a symbolic or string
literal.
59
String Length
While structured strings may have an absolute fixed length,
they often restrict string's size to an imaginary maximum in
specific languages. Besides, there are two kinds of string data
types: strings of a specified length that have a defined
maximum size to be calculated at the time of compilation and
which use a similar amount of storage space, whether or not
this maximum is required, and strings of variable size which do
not have arbitrary finite size and which might be using different
amounts of storage at runtime, based on the exact parameters.
Variable-length strings are the bulk of sequences in other
programming languages. Although variable-length strings are,
for example, restricted in size by the amount of memory storage
usable. The string's length can be processed as a different
integer number (which can give the size another arbitrary
barrier) or impliedly as a revocation character, usually a
character quality with all null bits, such as in the computer
language C.
Character Encoding
Traditionally, string datatypes have assigned one byte per
character. Still, while the real character set diverse by province,
character implementations were sufficiently similar to prevent
developers from disregarding this because a program's
specially prepared characters (such as time frame, storage, and
comma) were in a similar place in all of the Unicode characters
that a project would encounter. Traditionally, these character
series are based on ASCII or EBCDIC. When a message was
exhibited on a framework using distinct encryption in one
processing, a message was often disfigured, although
somewhat legible. Some internet users learned to read the
disfigured text.
60
o Other Representations
Either text elimination or length codes restrict sequences: C
language character arrays contain null values. For instance,
they cannot be explicitly treated by the C string library's
operations: strings with a size value are constrained to the
maximum sized code value.
By creative programming, both of the above drawbacks can be
resolved.
Here, we have some different representations of string in
several languages-
66
Storing strings:
/* OR */
C
C
char *str;
*(str+0) = 'G';
*(str+1) = 'f';
*(str+2) = 'G';
*(str+3) = '\0';
int main()
char *str;
getchar();
return 0;
C
int main()
{
70
char str[] = "GfG"; /* Stored in stack segment like other auto variables
*/
getchar();
return 0;
C
int main()
int size = 4;
*(str+0) = 'G';
*(str+1) = 'f';
71
*(str+2) = 'G';
*(str+3) = '\0';
getchar();
return 0;
char *getString()
return str;
72
int main()
printf("%s", getString());
getchar();
return 0;
C
char *getString()
int size = 4;
*(str+0) = 'G';
*(str+1) = 'f';
*(str+2) = 'G';
*(str+3) = '\0';
return str;
int main()
printf("%s", getString());
getchar();
return 0;
But, the below program may print some garbage data as string
is stored in stack frame of function getString() and data may
not be there after getString() returns.
C
74
char *getString()
/* Problem can be solved if write static before char, i.e. static char
str[] = "GfG";*/
return str;
int main()
printf("%s", getString());
getchar();
return 0;
}
75
String operations:
Scaler Academy
Explanation:
First, we defined str1 and then we defined str2. And then
concatenated the two. str1 had a size large enough to
accomodate the concatenated string.
2. strncat
The name of this function looks similar to the previous one
and that is because this function is also used for
concatenation. The only difference is that we use this function
when we want to combine N characters of one string into
another.
One rule associated with the use of this function is that the
length of the destination string must be more than that of the
source string. At most N characters from the source string are
appended to the end of the destination string with this
function. On success, this function returns a reference to the
destination string; on failure, it returns NULL.
Syntax:
char *strncat(char *destination, const char *source, size_t N) ;
The first argument is the destination string. The second
argument is the source string.
The third argument is the number of characters that are
appended.
Code:
#include <stdio.h>
#include <string.h>
77
int main() {
char str1[50] = "Scaler ";
char str2[10] = "Academy";
strncat(str1, str2,2);
printf("%s",str1);
return 0;
}
Output:
Scaler Ac
Explanation:
First we define string1 and then we define string2. Then we
concatenate only the first two characters
of string2 i.e. “Ac” to str 1 i.e. "Scaler" to form “Scaler Ac”.
3. strlen
The length of a string is returned by this function, excluding
the null character at the end. That is, it returns the string's
character count minus 1 for the terminator.
Syntax:
size_t strlen(const char *string);
The argument is the string whose length needs to be found.
Code:
#include <stdio.h>
#include <string.h>
int main()
{
char str1[20]="Scaler";
78
printf("%zu",strlen(str1));
return 0;
}
Output:
1
Explanation:
First, str1 is defined and then it’s length is found using strlen.
%zu is used to print variables of size_t length.
4. strcpy
strcpy copies a string from the source string to the destination
string, including the null character terminator. The return
value of this function is a reference to the destination string.
Syntax:
char *strcpy(char *destination, const char *source) ;
The first argument is the destination string The second
argument is the source string
Code:
#include <stdio.h>
#include <string.h>
int main() {
char str1[50] = "Scaler Academy";
char str2[50];
strcpy(str2, str1);
printf("%s",str2);
}
79
Output:
Scaler Academy
Explanation:
First str1 and str 2 are defined. Since str2 is the string in
which str1 is copied, make sure str2 is larger than or equal
to str1’s size.
5. strncpy
Strncpy is similar to strcpy, but it allows you to
copy N characters.
Syntax:
char *strncpy(char *destination, const char *source, size_t N)
;
The first argument is the destination string.
The second argument is the source string.
The third argument is the number of characters that are to
be copied.
Code:
#include <stdio.h>
#include <string.h>
int main() {
char str1[50] = "Scaler Academy";
char str2[50];
strncpy(str2, str1,6);
printf("%s",str2);
return 0;
}
80
Output:
Scale
Explanation:
str1 is copied to str2 and the first 6 characters are printed.
6. strcmp
This function joins two strings together. It returns a value less
than zero if the second string is greater. It returns a number
greater than zero if the first string is greater than the second. It
returns 0 if the strings are equivalent.
Syntax:
int strcmp(const char *str1, const char *str2) ;
The first argument is the first string i.e. str1 from the image
above. The second argument is the second string i.e. str2 from
the image above.
Code:
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "a";
char str2[] = "b";
int res;
res = strcmp(str1, str2);
printf("%d\n", res);
return 0;
}
Output:
81
-1
Explanation:
a is smaller than b hence according to the image above, the
output is -1.
7. strncmp
Strncmp is similar to strcmp, but it allows you to compare the
first N characters of the respective strings.
Syntax:
int strncmp(const char *first, const char *second, size_T N) ;
The first argument is the first string i.e. str1 from the image
above. The second argument is the second string i.e. str2 from
the image above. The third argument is the number of
characters that will be compared.
Code:
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "abc";
char str2[] = "acb";
int res;
res = strncmp(str1, str2,1);
printf("%d\n", res);
res = strncmp(str1, str2,2);
printf("%d\n", res);
return 0;
}
82
Output:
0 -1
Explanation:
In the first res, only 1 character is compared and since both are
a, they’re the same and the output is 0. In the second
res, 2 characters are compared and hence the first string is
smaller than the second string and the output is -1.
8. memset
To initialise a string to all nulls or any character, use memset.
Syntax:
void *memset(const void *destination, int c, site_t N) ;
The first argument is the destination string which is the address
of memory to be filled. The second argument is the value to be
filled. The third argument is the number of bytes to be filled
starting from the destination string.
Code:
#include <stdio.h>
#include <string.h>
int main() {
char str1[50]="Hello";
char ch='.';
memset(str1+5,ch,sizeof(char));
printf("%s", str1);
return 0;
}
Output:
83
Hello.
Explanation:
str1+5 means the 5th position in the string, i.e. after ‘o’. After
memset, the character, i.e. ‘.’ is placed after o.
9. strtok
To retrieve the next token in a string, use the strtok function. A
list of possible delimiters is used to define the token.
Arrays of String
An Array of String is an array that stores a fixed number of
values that are of the String data type.
Array of String in C/C++:
Syntax:
char strarr[m][n]
Explanation:
m denotes the number of strings that can be stored in the array
and n denotes the maximum length of the String.
Code
char strarr[2][5]={“Code”,”Word”}
**Array of String in Python:**
Syntax:
strarr={“string1”,”string2”}
Explanation:
84
In the above code, we first declared the string and then passed
it to a function named func.
Passing a String to a function in Python:
Syntax:
functionName(string)
Code:
//Declaring a String
s='Hello'
In the above code, we first declared the string and then passed
it to a function named func.
Passing a String to a function in Java:
Syntax:
functionName(string);
Code:
//Declaring a String
String s="Hello";
In the above code, we first declared the string and then passed
it to a function named func.
String in C/C++
A string is a collection of characters that ends with the null
character \0 in C programming. By default, the compiler
appends a null character \0 to the end of a sequence of
characters wrapped in double quotation marks.
Declaring a String:
Syntax:
char str[5];
As seen in the photo below, the index starts from 0 and goes
uptil 4 meaning 5 locations.
Initializing a String:
String Manipulation
char *strarrPtr;
strarrPtr = strarr;
printf("%c", *strarrPtr); // Output: C
printf("%c", *(strarrPtr+1)); // Output: o
printf("%c", *(strarrPtr+7)); // Output: w
}
In the above code, it is seen that when *strarr is printed the first
character from the string “Coding with Strings”, i.e. C is
printed. When *strarr+1 is printed, the character
present 1 position away from the first character is printed,
i.e. o and so on. This is how manipulation in strings is done.
String Functions
strlen() - returns length of string
strcpy() - copies one string to another
strcmp() - compares two strings
strcat() - concatenates two strings
SECTION-II
CHAPTER-3
ARRAYS
Introduction of Arrays:
indexed by a subscript of 0.
1 (one-based indexing): The first element of the array is
the array]
2. Access elements in Array:
Accessing array elements become extremely important, in
order to perform operations on arrays.
Pseudo Code:
// to access array element at index position 2, we simply can
write
return arr[ 2 ] ;
Time Complexity: O(1)
3. Searching in Array:
We try to find a particular value in the array, in order to do that
we need to access all the array elements and look for the
particular value.
Pseudo Code:
// searching for value 2 in the array;
Loop from i = 0 to 5:
check if arr[i] = 2:
return true;
Time Complexity: O(N), where N is the size of the array.
Here is the code for working with an array:
95
#include <iostream>
int main()
int arr[10];
arr[0] = 5;
return 0;
}
96
Output
5
Here the value 5 is printed because the first element has index
zero and at the zeroth index, we already assigned the value 5.
Types of arrays :
1. One dimensional array (1-D arrays)
2. Multidimensional array
To learn about the differences between One-dimensional and
Multidimensional arrays, click here.
Advantages of using arrays:
Arrays allow random access to elements. This makes
difference in performance.
Arrays represent multiple data items of the same type using
a single name.
Disadvantages of using arrays:
You can’t change the size i.e. once you have declared the array
you can’t change its size because of static memory
allocation. Here Insertion(s) and deletion(s) are difficult as the
elements are stored in consecutive memory locations and the
shifting operation is costly too.
Now if take an example of the implementation of data
structure Stack using array there are some obvious flaws.
Let’s take the POP operation of the stack. The algorithm
would go something like this.
1. Check for the stack underflow
2. Decrement the top by 1
What we are doing here is, that the pointer to the topmost
element is decremented, which means we are just bounding
our view, and actually that element stays there taking up the
memory space. If you have an array (as a Stack) of any
97
Arrays are used when the size of the data set is known.
one name.
Arrays can be used for CPU scheduling.
Basic operations
Now, let's discuss the basic operations supported in the array -
o Traversal - This operation is used to print the elements of
the array.
o Insertion - It is used to add an element at a particular index.
o Deletion - It is used to delete an element from a particular
index.
o Search - It is used to search an element using the given
index or by the value.
o Update - It updates an element at a particular index.
Traversal operation
This operation is performed to traverse through the array
elements. It prints all array elements one after another. We can
understand it with the below program -
1. #include <stdio.h>
2. void main() {
3. int Arr[5] = {18, 30, 15, 70, 12};
4. int i;
5. printf("Elements of the array are:\n");
6. for(i = 0; i<5; i++) {
7. printf("Arr[%d] = %d, ", i, Arr[i]);
8. }
9. }
Output
102
Insertion operation
This operation is performed to insert one or more elements into
the array. As per the requirements, an element can be added at
the beginning, end, or at any index of the array. Now, let's see
the implementation of inserting an element into the array.
1. #include <stdio.h>
2. int main()
3. {
4. int arr[20] = { 18, 30, 15, 70, 12 };
5. int i, x, pos, n = 5;
6. printf("Array elements before insertion\n");
7. for (i = 0; i < n; i++)
8. printf("%d ", arr[i]);
9. printf("\n");
10.
11. x = 50; // element to be inserted
12. pos = 4;
13. n++;
14.
15. for (i = n-1; i >= pos; i--)
16. arr[i] = arr[i - 1];
17. arr[pos - 1] = x;
18. printf("Array elements after insertion\n");
19. for (i = 0; i < n; i++)
20. printf("%d ", arr[i]);
21. printf("\n");
22. return 0;
23. }
Output
103
Deletion operation
As the name implies, this operation removes an element from
the array and then reorganizes all of the array elements.
1. #include <stdio.h>
2.
3. void main() {
4. int arr[] = {18, 30, 15, 70, 12};
5. int k = 30, n = 5;
6. int i, j;
7.
8. printf("Given array elements are :\n");
9.
10. for(i = 0; i<n; i++) {
11. printf("arr[%d] = %d, ", i, arr[i]);
12. }
13.
14. j = k;
15.
16. while( j < n) {
17. arr[j-1] = arr[j];
18. j = j + 1;
19. }
20.
21. n = n -1;
22.
23. printf("\nElements of array after deletion:\n");
24.
25. for(i = 0; i<n; i++) {
26. printf("arr[%d] = %d, ", i, arr[i]);
104
27. }
28. }
Output
Search operation
This operation is performed to search an element in the array
based on the value or index.
1. #include <stdio.h>
2.
3. void main() {
4. int arr[5] = {18, 30, 15, 70, 12};
5. int item = 70, i, j=0 ;
6.
7. printf("Given array elements are :\n");
8.
9. for(i = 0; i<5; i++) {
10. printf("arr[%d] = %d, ", i, arr[i]);
11. }
12. printf("\nElement to be searched = %d", item);
13. while( j < 5){
14. if( arr[j] == item ) {
15. break;
16. }
17.
18. j = j + 1;
19. }
20.
105
Update operation
This operation is performed to update an existing array element
located at the given index.
1. #include <stdio.h>
2.
3. void main() {
4. int arr[5] = {18, 30, 15, 70, 12};
5. int item = 50, i, pos = 3;
6.
7. printf("Given array elements are :\n");
8.
9. for(i = 0; i<5; i++) {
10. printf("arr[%d] = %d, ", i, arr[i]);
11. }
12.
13. arr[pos-1] = item;
14. printf("\nArray elements after updation :\n");
15.
16. for(i = 0; i<5; i++) {
17. printf("arr[%d] = %d, ", i, arr[i]);
18. }
19. }
Output
106
Space Complexity
In array, space complexity for worst case is O(n).
Advantages of Array
o Array provides the single name for the group of variables
of the same type. Therefore, it is easy to remember the
name of all the elements of an array.
o Traversing an array is a very simple process; we just need
to increment the base address of the array in order to visit
each element one by one.
107
Linear arrays:
o Tree
It is a non-linear data structure that consists of various linked
nodes. It has a hierarchical tree structure that forms a parent-
child relationship. The diagrammatic representation of
a tree data structure is shown below:
and next
items.
Address Calculations:
2-D array
Example:
2-D array
From the above examples, it can be observed that for the same
position two different address locations are obtained that’s
because in row-major order movement is done across the rows
and then down to the next row, and in column-major order,
first move down to the first column and then next column. So
both the answers are right.
So it’s all based on the position of the element whose address
is to be found for some cases the same answers is also obtained
with row-major order and column-major order and for some
cases, different answers are obtained.
Calculate the address of any element in the 3-D Array:
A 3-Dimensional array is a collection of 2-Dimensional
arrays. It is specified by using three subscripts:
1. Block size
2. Row size
3. Column size
More dimensions in an array mean more data can be stored in
that array.
Example:
120
3-D array
Given:
Row Subset of an element whose address to be found I = 3
Column Subset of an element whose address to be found J =
3
Block Subset of an element whose address to be found K = 3
Base address B = 400
Storage size of one element store in any array(in Byte) W = 4
Lower Limit of row/start row index of matrix x = 1
Lower Limit of column/start column index of matrix y = -5
Lower Limit of blocks in matrix z = -10
M = Upper Bound – Lower Bound + 1 = 5 + 5 + 1 = 11
N = Upper Bound – Lower Bound + 1 = 5 + 10 + 1 = 16
Formula used:
Address of[i][j][k] = B + W(M * N(i – x) + M * (k – z) + (j –
y))
Solution:
Address of[3][3][3] = 400 + 4 * {[(3 – 1)] * 16 + [3 + 10] ]}
* 11 + [3 + 5]
= 400 + 4 * ((32 + 13) * 11 + 8)
= 400 + 4 * (503)
= 400 + 2012
= 2412
Traversal:
Insertions:
Deletion in an array:
Multidimensional arrays:
Examples:
Two dimensional array: int two_d[10][20];
elements.
Similarly array int x[5][10][20] can store total (5*10*20)
= 1000 elements.
Two-Dimensional Array
Example:
CPP
C
129
// Two-Dimensional array
#include<iostream>
int main()
return 0;
Output:
Element at x[0][0]: 0
Element at x[0][1]: 1
Element at x[1][0]: 2
Element at x[1][1]: 3
Element at x[2][0]: 4
Element at x[2][1]: 5
131
Three-Dimensional Array
// Array
#include <iostream>
int main()
int x[2][3][2] = { { { 0, 1 }, { 2, 3 }, { 4, 5 } },
{ { 6, 7 }, { 8, 9 }, { 10, 11 } } };
<< endl;
return 0;
Output:
Element at x[0][0][0] = 0
Element at x[0][0][1] = 1
Element at x[0][1][0] = 2
Element at x[0][1][1] = 3
Element at x[0][2][0] = 4
Element at x[0][2][1] = 5
Element at x[1][0][0] = 6
134
Element at x[1][0][1] = 7
Element at x[1][1][0] = 8
Element at x[1][1][1] = 9
Element at x[1][2][0] = 10
Element at x[1][2][1] = 11
In similar ways, we can create arrays with any number of
dimensions. However, the complexity also increases as the
number of dimensions increases. The most used
multidimensional array is the Two-Dimensional Array.
Parallel arrays:
the array
Print the values at the evaluated indices in other arrays
Sorting:
The arrays can be sorted in any way, numerical, alphabetical
or any other way but the elements are placed at equally spaced
addresses. Any of the sorting techniques can be used to sort
the record based on a specified criteria. Following steps are
performed to sort a record.
136
the arrays.
Thus, following the above steps, once the chosen array (the
array to be chosen on a specified criterion) is sorted, all the
arrays shall be sorted with respect to the chosen array.
Implementation:
1. The code below stores the first name, second name, and
height of 10 students.
2. Sorts them in increasing order of the height
using quicksort algorithm.
3. Searches the name of the 2nd tallest student, the 3rd shortest
student and the student having a height equal to 158 cms in
the record.
#include <iostream>
to right of pivot */
last_name[],
i++;
first_name[i] = first_name[j];
first_name[j] = temp;
139
temp = last_name[i];
last_name[i] = last_name[j];
last_name[j] = temp;
height[i] = height[j];
height[j] = temp1;
first_name[i + 1] = first_name[high];
first_name[high] = temp;
last_name[i + 1] = last_name[high];
last_name[high] = temp;
height[i + 1] = height[high];
140
height[high] = temp1;
return (i + 1);
at right place */
low, pi - 1);
pi + 1, high);
// at that index.
last_name[],
{
142
int index;
if (height[index] == 158) {
<< first_name[index]
return;
143
high = index - 1;
else
low = index + 1;
// Driver Function
int main()
145
int n = 10;
// their heights.
0, n - 1);
printParallelArray(first_name, last_name,
height, n);
// right end.
" is "
// left end.
<< endl;
// cms.
158, n);
return 0;
Output
Name of people in increasingorder of their height:
Jinny Weasly has height 152 cms
Welma Seger has height 158 cms
Harry Potter has height 160 cms
Emma Watson has height 163 cms
148
Sparse arrays:
1. Array Representation:
To represent a sparse array 2-D array is used with three rows
namely: Row, Column, and Value.
Row: Index of the row where non-zero elements are present.
Column: Index of the column where the non-zero element is
present.
Value: The non-zero value which is present in (Row, Column)
index.
C++
Java
C#
Javascript
152
#include <iostream>
int main()
int sparse[4][4] = { { 0, 0, 7, 0 },
{ 1, 0, 0, 0 },
{ 2, 0, 5, 0 },
{ 0, 8, 0, 4 } };
int s = 0;
if (sparse[i][j] != 0)
s++;
153
int representsparse[3][s];
int k = 0;
if (sparse[i][j] != 0) {
representsparse[0][k] = i;
representsparse[1][k] = j;
representsparse[2][k] = sparse[i][j];
k++;
"\n";
return 0;
Output
Representation of Sparse array using arrays :
012233
200213
712584
155
CHAPTER-4
LINKED LIST
Linked-List
Ease of Insertion/Deletion.
node of the linked list contains the link of the first/head node
of the linked list in its next pointer and the first/head node
contains the link of the last node of the linked list in its prev
pointer
Basic operations on Linked Lists:
Deletion
Insertion
Search
Display
struct Node {
int data;
};
// C program to implement a
// linked list
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
};
// Driver's code
int main()
| | |
| | |
|# |# | |# |# | | #| #|
anything yet */
| | |
| | |
| 1 | o----->| # | # | | # |# |
*/
second->data = 2;
162
second->next = third;
| | |
| | |
| 1 | o----->| 2 | o-----> | # | # |
third->next = NULL;
head
return 0;
C
C++
Java
Python3
C#
Javascript
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
};
while (n != NULL) {
n = n->next;
166
// Driver's code
int main()
second->next = third;
third->next = NULL;
// Function call
printList(head);
return 0;
Output
1 2 3
Time Complexity:
Time Complexity Worst Case Average Case
168
Advantages of Arrays:
Arrays store multiple data of similar types with the same
name.
It allows random access to elements.
Singly LinkedList
A singly LinkedList is Uni-directional, meaning traversal is
possible in forwarding direction
only.
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
174
16
17
18
19
20
21
22
23
24
25
26
#Traversing using singly linked list
class Node: #Creating a node
def __init__(self, data=None):
self.data = data
self.next = None
class SinglyLinkedList: #Node is attribute of linkedlist
def __init__(self):
self.head = None
def Traversal(self): #Traversal through linked List
n = self.head
while n is not None:
print (n.data)
n = n.next
175
list = SinglyLinkedList()
list.head = Node("Monday")
l2 = Node("Tuesday")
l3 = Node("Wedneday")
# Link first Node to second node
list.head.next = l2
# Link second Node to third node
l2.next = l3
list.Traversal()
Run
Traversal in a singly linked list
Explanation
Doubly LinkedList
A doubly LinkedList is Bi-directional, meaning traversal is
possible in both forward and backward
directions.
Example
1
2
3
4
5
6
7
8
9
10
11
12
177
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Node: #Creating a node
def __init__(self, data):
self.data = data
self.nref = None
self.pref=None
178
new_node.pref=n
Run
Traversal in doubly linkedlist
Explanation
Insertion:
C Function
1. #include<stdio.h>
2. #include<stdlib.h>
3. void beginsert(int);
4. struct node
5. {
6. int data;
7. struct node *next;
8. };
9. struct node *head;
10. void main ()
11. {
12. int choice,item;
13. do
14. {
182
Node inserted
Node inserted
Deletion of LinkedList:
C function
1. #include<stdio.h>
2. #include<stdlib.h>
3. void create(int);
4. void begdelete();
5. struct node
6. {
7. int data;
8. struct node *next;
9. };
10. struct node *head;
11. void main ()
12. {
13. int choice,item;
185
14. do
15. {
16. printf("\n1.Append List\n2.Delete node\n3.Exit\n4.
Enter your choice?");
17. scanf("%d",&choice);
18. switch(choice)
19. {
20. case 1:
21. printf("\nEnter the item\n");
22. scanf("%d",&item);
23. create(item);
24. break;
25. case 2:
26. begdelete();
27. break;
28. case 3:
29. exit(0);
30. break;
31. default:
32. printf("\nPlease enter valid choice\n");
33. }
34.
35. }while(choice != 3);
36. }
37. void create(int item)
38. {
39. struct node *ptr = (struct node *)malloc(sizeof(struc
t node *));
40. if(ptr == NULL)
41. {
42. printf("\nOVERFLOW\n");
43. }
44. else
186
45. {
46. ptr->data = item;
47. ptr->next = head;
48. head = ptr;
49. printf("\nNode inserted\n");
50. }
51.
52. }
53. void begdelete()
54. {
55. struct node *ptr;
56. if(head == NULL)
57. {
58. printf("\nList is empty");
59. }
60. else
61. {
62. ptr = head;
63. head = ptr->next;
64. free(ptr);
65. printf("\n Node deleted from the begining ...");
66. }
67. }
Output
1.Append List
2.Delete node
3.Exit
4.Enter your choice?1
Node inserted
1.Append List
2.Delete node
3.Exit
4.Enter your choice?2
o STEP 6: I = I + 1
o STEP 7: PTR = PTR → NEXT
[END OF LOOP]
o STEP 8: EXIT
C function
1. #include<stdio.h>
2. #include<stdlib.h>
3. void create(int);
4. void search();
5. struct node
6. {
7. int data;
8. struct node *next;
9. };
10. struct node *head;
11. void main ()
12. {
13. int choice,item,loc;
14. do
15. {
16. printf("\n1.Create\n2.Search\n3.Exit\n4.Enter your c
hoice?");
17. scanf("%d",&choice);
18. switch(choice)
19. {
20. case 1:
21. printf("\nEnter the item\n");
22. scanf("%d",&item);
23. create(item);
24. break;
189
25. case 2:
26. search();
27. case 3:
28. exit(0);
29. break;
30. default:
31. printf("\nPlease enter valid choice\n");
32. }
33.
34. }while(choice != 3);
35. }
36. void create(int item)
37. {
38. struct node *ptr = (struct node *)malloc(sizeof(struc
t node *));
39. if(ptr == NULL)
40. {
41. printf("\nOVERFLOW\n");
42. }
43. else
44. {
45. ptr->data = item;
46. ptr->next = head;
47. head = ptr;
48. printf("\nNode inserted\n");
49. }
50.
51. }
52. void search()
53. {
54. struct node *ptr;
55. int item,i=0,flag;
56. ptr = head;
190
64. scanf("%d",&item);
65. while (ptr!=NULL)
66. {
67. if(ptr->data == item)
68. {
69. printf("item found at location %d ",i+1);
70. flag=0;
71. }
72. else
73. {
74. flag=1;
75. }
76. i++;
77. ptr = ptr -> next;
78. }
79. if(flag==1)
80. {
81. printf("Item not found\n");
82. }
83. }
84.
85. }
Output
1.Create
191
2.Search
3.Exit
4.Enter your choice?1
Node inserted
1.Create
2.Search
3.Exit
4.Enter your choice?1
Node inserted
1.Create
2.Search
3.Exit
4.Enter your choice?2
#include <malloc.h>
#include <stdio.h>
194
struct link {
int info;
};
// Empty List
malloc(sizeof(struct link));
new_node->info = data;
new_node->next = NULL;
if (start == NULL) {
malloc(sizeof(struct link));
start->next = new_node;
else {
node = start;
node = node->next;
node->next = new_node;
return start;
node = start;
node = node->next;
node = node->next;
197
printf("\n");
return start;
// Driver code
int main()
create_header_list(11);
create_header_list(12);
create_header_list(13);
display();
create_header_list(14);
198
create_header_list(15);
display();
return 0;
Output:
11 12 13
11 12 13 14 15
The circular linked list is a linked list where all nodes are
connected to form a circle. In a circular linked list, the first
node and the last node are connected to each other which
forms a circle. There is no NULL at the end.
Circular linked lists are similar to single Linked Lists with the
exception of connecting the last node to the first node.
Node representation of a Circular Linked List:
C++
class Node{
int value;
Node next;
C++
201
// Connect nodes
one.next = two;
two.next = three;
three.next = one;
Explanation: In the above program one, two, and three are the
node with values 3, 5, and 9 respectively which are connected
in a circular manner as:
For Node One: The Next pointer stores the address of Node
two.
For Node Two: The Next stores the address of Node three
And then,
C++
if (last == NULL)
return last;
last = T.
Before insertion,
After insertion,
205
C++
if (last == NULL)
last = temp;
return last;
that node is P.
Make T -> next = P -> next;
207
P -> next = T.
Suppose 12 needs to be inserted after the node has the value
10,
if (last == NULL)
return NULL;
do
if (p ->data == item)
if (p == last)
last = temp;
return last;
p = p -> next;
cout << item << " not present in the list." << endl;
return last;
Keep the address of the node next to the last node in temp
and before moving to curr to the next node, every time set
prev = curr.
If the node is found, check if it is the only node in the list.
node, then set prev -> next = curr -> next and delete curr.
Below is the implementation for the above approach:
C++
// linked list.
#include <bits/stdc++.h>
class Node {
public:
int data;
Node* next;
};
// as next of it.
ptr1->data = data;
213
ptr1->next = *head_ref;
if (*head_ref != NULL) {
temp = temp->next;
temp->next = ptr1;
else
ptr1->next = ptr1;
*head_ref = ptr1;
if (head != NULL) {
do {
temp = temp->next;
}
215
if (*head == NULL)
return;
// single node
free(*head);
*head = NULL;
return;
// If head is to be deleted
if ((*head)->data == key) {
last = last->next;
// of the list
last->next = (*head)->next;
free(*head);
*head = last->next;
return;
// is not reached
last = last->next;
if (last->next->data == key) {
218
d = last->next;
last->next = d->next;
free(d);
else
// Driver code
int main()
// 2->5->7->8->10
219
push(&head, 2);
push(&head, 5);
push(&head, 7);
push(&head, 8);
push(&head, 10);
printList(head);
deleteNode(&head, 7);
printList(head);
return 0;
}
220
Output
List Before Deletion: 10 8 7 5 2
List After Deletion: 10 8 5 2
Time Complexity: O(N), Worst case occurs when the element
to be deleted is the last element and we need to move through
the whole list.
Auxiliary Space: O(1), As constant extra space is used.
Advantages of Circular Linked Lists:
Any node can be a starting point. We can traverse the whole
complex.
221
play.
A circular linked list can be used to organize multiple
is not necessary.
Any node can be set as the starting point.
Nodes are traversed quickly from the first to the last.
87
Threaded lists:
Garbage collection:
1. def gc():
2. stop_all_mutators()
3. mark_roots()
4. sweep()
5. resume_all_mutators()
6.
7. def mark_roots():
8. candidates = Stack()
9. for field in Roots:
10. if field != nil && not is_marked(field):
11. set_marked(field)
12. candidates.push(field)
13. mark(candidates)
14.
15. def mark(candidates):
16. while not candidates.empty():
17. ref = candidates.pop()
18. for field in pointers(ref):
225
2. # assumed that all objects are of the same type and size.
3. def new():
4. obj = allocate_memory()
5. obj.set_reference_count(1)
6. return obj
7.
8. # delete() is invoked when an object is no longer required by t
he client program
9. def delete(obj):
10. obj.decrement_reference_count()
11. if obj.get_reference_count() == 0:
12. for child in children(obj):
13. delete(child)
14. release_memory(obj)
15.
16. # update() is the only blessed way to perform pointer assi
gnments in the system.
17. def update(source, target):
18. # We increment before deleting, this correctly deals w
ith source == target case.
19. target.increment_reference_count()
20. delete(source)
21. source = target
The inability to recover cyclic storage is the most significant
disadvantage of reference counting. Cyclic data structures such
as doubly-linked lists and non-basic graphs cannot be
successfully recovered using a simple reference counting
technique and will leak memory.
Advantages of Reference Counting
o Compared to tracing collectors, the memory management
Example:
C++ program to add two polynomials
1. #include <iostream>
2. using namespace std;
3. int max(int m, int n) { return (m > n)? m: n; }
4. int *add(int A[], int B[], int m, int n)
5. {
6. int size = max(m, n);
7. int *sum = new int[size];
8. for (int i = 0; i<m; i++)
9. sum[i] = A[i];
10. for (int i=0; i<n; i++)
11. sum[i] += B[i];
12. return sum;
13. }
14. void printPoly(int poly[], int n)
15. {
16. for (int i=0; i<n; i++)
17. {
18. cout << poly[i];
19. if (i != 0)
20. cout << "x^" << i ;
238
21. if (i != n-1)
22. cout << " + ";
23. }
24. }
25. int main()
26. {
27. int A[] = { 5, 0, 10, 6 };
28. int B[] = { 1, 2, 4 };
29. int m = sizeof(A)/sizeof(A[0]);
30. int n = sizeof(B)/sizeof(B[0]);
31. cout << "First polynomial is \n";
32. printPoly(A, m);
33. cout << "\n Second polynomial is \n";
34. printPoly(B, n);
35. int *sum = add(A, B, m, n);
36. int size = max(m, n);
37. cout << "\n Sum of polynomial is \n";
38. printPoly(sum, size);
39. return 0;
40. }
Explanation:
In the above example, we have created an example of sum of
two polynomial using array.
Output:
Below is the output of this example.
239
Example:
C++ program for addition of two polynomials using Linked
Lists
1. #include <bits/stdc++.h>
2. #include <iostream.h>
3. using namespace std;
4. struct Node {
5. int coeff;
6. int pow;
7. struct Node* next;
8. };
9. void create_node(int x, int y, struct Node** temp)
10. {
11. struct Node *r, *z;
12. z = *temp;
13. if (z == NULL) {
14. r = (struct Node*)malloc(sizeof(struct Node));
15. r->coeff = x;
16. r->pow = y;
17. *temp = r;
18. r-
>next = (struct Node*)malloc(sizeof(struct Node));
19. r = r->next;
20. r->next = NULL;
21. }
22. else {
23. r->coeff = x;
24. r->pow = y;
25. r-
>next = (struct Node*)malloc(sizeof(struct Node));
26. r = r->next;
27. r->next = NULL;
242
28. }
29. }
30. void polyadd(struct Node* poly1, struct Node* poly2,
31. struct Node* poly)
32. {
33. while (poly1->next && poly2->next) {
34. if (poly1->pow > poly2->pow) {
35. poly->pow = poly1->pow;
36. poly->coeff = poly1->coeff;
37. poly1 = poly1->next;
38. }
39. else if (poly1->pow < poly2->pow) {
40. poly->pow = poly2->pow;
41. poly->coeff = poly2->coeff;
42. poly2 = poly2->next;
43. }
44. else {
45. poly->pow = poly1->pow;
46. poly->coeff = poly1->coeff + poly2->coeff;
47. poly1 = poly1->next;
48. poly2 = poly2->next;
49. }
50. poly->next
51. = (struct Node*)malloc(sizeof(struct Node));
52. poly = poly->next;
53. poly->next = NULL;
54. }
55. while (poly1->next || poly2->next) {
56. if (poly1->next) {
57. poly->pow = poly1->pow;
58. poly->coeff = poly1->coeff;
59. poly1 = poly1->next;
60. }
243
61. if (poly2->next) {
62. poly->pow = poly2->pow;
63. poly->coeff = poly2->coeff;
64. poly2 = poly2->next;
65. }
66. poly->next
67. = (struct Node*)malloc(sizeof(struct Node));
68. poly = poly->next;
69. poly->next = NULL;
70. }
71. }
72. void show(struct Node* node)
73. {
74. while (node->next != NULL) {
75. printf("%dx^%d", node->coeff, node->pow);
76. node = node->next;
77. if (node->coeff >= 0) {
78. if (node->next != NULL)
79. printf("+");
80. }
81. }
82. }
83. int main()
84. {
85. struct Node *poly1 = NULL, *poly2 = NULL, *poly
= NULL;
86. create_node(5, 2, &poly1);
87. create_node(4, 1, &poly1);
88. create_node(2, 0, &poly1);
89. create_node(-5, 1, &poly2);
90. create_node(-5, 0, &poly2);
91. printf("1st Number: ");
92. show(poly1);
244
18. {
19. cout << poly[i];
20. if (i != 0)
21. cout << "x^" << i ;
22. if (i != n-1)
23. cout << " + ";
24. }
25. }
26. int main()
27. {
28. int A[] = { 5, 0, 10, 6 };
29. int B[] = { 1, 2, 4 };
30. int m = sizeof(A)/sizeof(A[0]);
31. int n = sizeof(B)/sizeof(B[0]);
32. cout << "First polynomial is \n";
33. printPoly(A, m);
34. cout << "\nSecond polynomial is \n";
35. printPoly(B, n);
36. int *prod = multiply(A, B, m, n);
37. cout << "\nProduct of two polynomial is \n";
38. printPoly(prod, m+n-1);
39. return 0;
40. }
Explanation:
In the above example, we have created an example of multiple
of two polynomial using arrays.
Output:
Below is the output of this example.
247
SECTION-III
STACK
Introduction of Stack:
Stack
Push:
Adds an item to the stack. If the stack is full, then it is said to
be an Overflow condition.
Algorithm for push:
begin
if stack is full
return
250
endif
else
increment top
stack[top] assign value
end else
end procedure
Pop:
Removes an item from the stack. The items are popped in the
reversed order in which they are pushed. If the stack is empty,
then it is said to be an Underflow condition.
Algorithm for pop:
begin
if stack is empty
return
endif
else
store value of stack[top]
decrement top
return value
end else
end procedure
Top:
Returns the top element of the stack.
Algorithm for Top:
begin
return stack[top]
251
end procedure
isEmpty:
Returns true if the stack is empty, else false.
Algorithm for isEmpty:
begin
if top < 1
return true
else
return false
end procedure
Understanding stack practically:
There are many real-life examples of a stack. Consider the
simple example of plates stacked over one another in a
canteen. The plate which is at the top is the first one to be
removed, i.e. the plate which has been placed at the
bottommost position remains in the stack for the longest
period of time. So, it can be simply seen to follow the
LIFO/FILO order.
Complexity Analysis:
Time Complexity
Operations Complexity
push() O(1)
pop() O(1)
isEmpty() O(1)
252
Operations Complexity
size() O(1)
Types of Stacks:
Register Stack: This type of stack is also a memory
Connected Components
In Memory management, any modern computer uses a stack
operations */
#include <bits/stdc++.h>
class Stack {
int top;
public:
int pop();
int peek();
bool isEmpty();
};
bool Stack::push(int x)
return false;
else {
a[++top] = x;
return true;
int Stack::pop()
if (top < 0) {
return 0;
}
256
else {
int x = a[top--];
return x;
int Stack::peek()
if (top < 0) {
return 0;
else {
int x = a[top];
return x;
}
257
bool Stack::isEmpty()
int main()
class Stack s;
s.push(10);
s.push(20);
s.push(30);
while(!s.isEmpty())
s.pop();
return 0;
Output
10 pushed into stack
20 pushed into stack
30 pushed into stack
259
#include <bits/stdc++.h>
class StackNode {
public:
int data;
StackNode* next;
260
};
stackNode->data = data;
stackNode->next = NULL;
return stackNode;
return !root;
stackNode->next = *root;
*root = stackNode;
if (isEmpty(*root))
return INT_MIN;
*root = (*root)->next;
free(temp);
262
return popped;
if (isEmpty(root))
return INT_MIN;
return root->data;
// Driver code
int main()
push(&root, 10);
263
push(&root, 20);
push(&root, 30);
while(!isEmpty(root))
pop(&root);
}
264
return 0;
Output
10 pushed to stack
20 pushed to stack
30 pushed to stack
30 popped from stack
Top element is 20
Elements present in stack : 20 10
Advantages of Linked List implementation:
The linked list implementation of a stack can grow and
corrupted easily.
Stack cleans up the objects automatically.
Stack is a
linear data An array is a
structure collection of
represented related data
by a values called
sequential elements
collection of each
elements in a identified by
fixed an an indexed
Definition order array
Basis of
Comparison Stacks Array
Insertion and
deletion in
stacks take Insertion and
place only deletion in
from one end the array can
of the list be done at
called the any index in
Operations top. the array.
Basis of
Comparison Stacks Array
We can do
We can do both linear
only a linear and Binary
Methods search search
Random Random
access to access to
elements is elements is
not allowed allowed in
Data Access in stacks arrays
We can We cannot
implement a implement an
stack using array using
Implementation the array stack
Basis of
Comparison Stacks Array
pointer in compile-
indicates the time and is
address of also known
the topmost as static
element or memory
the last allocation.
inserted one
of the stack.
Complexity Analysis:
Operation Stack Operation Array
return true
else
return false
endif
end procedure
Implementation of isfull() function in C programming language
−
Example
bool isfull() {
if(top == MAXSIZE)
return true;
else
return false;
}
isempty()
Algorithm of isempty() function −
begin procedure isempty
end procedure
Implementation of isempty() function in C programming
language is slightly different. We initialize top at -1, as the
index in array starts from 0. So we check if the top is below
zero or -1 to determine if the stack is empty. Here's the code −
272
Example
bool isempty() {
if(top == -1)
return true;
else
return false;
}
Push Operation
The process of putting a new data element onto stack is known
as a Push Operation. Push operation involves a series of steps
−
Step 1 − Checks if the stack is full.
Step 2 − If the stack is full, produces an error and exit.
Step 3 − If the stack is not full, increments top to point
next empty space.
Step 4 − Adds data element to the stack location, where
top is pointing.
Step 5 − Returns success.
if stack is full
return null
endif
top ← top + 1
stack[top] ← data
end procedure
Implementation of this algorithm in C, is very easy. See the
following code −
Example
void push(int data) {
if(!isFull()) {
top = top + 1;
stack[top] = data;
} else {
printf("Could not insert data, Stack is full.\n");
}
}
Pop Operation
Accessing the content while removing it from the stack, is
known as a Pop Operation. In an array implementation of pop()
operation, the data element is not actually removed,
instead top is decremented to a lower position in the stack to
274
if stack is empty
return null
endif
data ← stack[top]
top ← top - 1
return data
275
end procedure
Implementation of this algorithm in C, is as follows −
Example
int pop(int data) {
if(!isempty()) {
data = stack[top];
top = top - 1;
return data;
} else {
printf("Could not retrieve data, Stack is empty.\n");
}
}
Applications of stacks:
o Backtracking
o Delimiter Checking
o Reverse a Data
o Postfix Notation
Infix Notation
The infix notation is a convenient way of writing an expression
in which each operator is placed between the operands. Infix
expressions can be parenthesized or unparenthesized
depending upon the problem requirement.
Example: A + B, (C - D) etc.
All these expressions are in infix notation because the operator
comes between the operands.
Prefix Notation
The prefix notation places the operator before the operands.
This notation was introduced by the Polish mathematician and
hence often referred to as polish notation.
Example: + A B, -CD etc.
All these expressions are in prefix notation because the operator
comes before the operands.
Postfix Notation
The postfix notation places the operator after the operands. This
notation is just the reverse of Polish notation and also known
as Reverse Polish notation.
Example: AB +, CD+, etc.
All these expressions are in postfix notation because the
operator comes after the operands.
278
2. Backtracking
Backtracking is another application of Stack. It is a recursive
algorithm that is used for solving the optimization problem.
3. Delimiter Checking
The common application of Stack is delimiter checking, i.e.,
parsing that involves analyzing a source program syntactically.
It is also called parenthesis checking. When the compiler
translates a source program written in some programming
language such as C, C++ to a machine language, it parses the
program into multiple individual parts such as variable names,
keywords, etc. By scanning from left to right. The main
problem encountered while translating is the unmatched
delimiters. We make use of different types of delimiters include
the parenthesis checking (,), curly braces {,} and square
brackets [,], and common delimiters /* and */. Every opening
delimiter must match a closing delimiter, i.e., every opening
281
{ ( a + b) - c } { ( a + b) - c
4. Reverse a Data:
To reverse a given set of data, we need to reorder the data so
that the first and last elements are exchanged, the second and
second last element are exchanged, and so on for all other
elements.
Example: Suppose we have a string Welcome, then on
reversing it would be Emoclew.
There are different reversing applications:
o Reversing a string
o Converting Decimal to Binary
283
Reverse a String
A Stack can be used to reverse the characters of a string. This
can be achieved by simply pushing one by one each character
onto the Stack, which later can be popped from the Stack one
by one. Because of the last in first out property of the Stack,
the first character of the Stack is on the bottom of the Stack and
the last character of the String is on the Top of the Stack and
after performing the pop operation in the Stack, the Stack
returns the String in Reverse order.
Polish notation:
Infix form
Prefix form
Postfix form
Infix form
Is exactly the fully parenthesized notation we have just
introduced. Let me remind you once again the Recursive
definition
Examples
287
(3 * 7)
((1 + 3) * 2)
((1 + 3) * ( 2 - 3))
Prefix form
Main Feature: the operator preceeds the two operands.
prefix-expression := atom
Examples
(* 3 7) or simply * 3 7
(* ( + 1 3) 2) or simply * + 1 3 2
( * ( + 1 3) ( - 2 3)) or simply * + 1 3 - 2 3
Postfix form
Main Feature: the operator is after the two
operands. Recursive definition
Examples
(3 7 *) or simply 3 7 *
((1 3 + ) 2 *) or simply 1 3 + 2 *
((1 3 +) ( 2 3 -) * ) or simply 1 3 + 2 3 - *
Recursion:
What is Recursion?
smaller.
Base condition is needed to stop the recursion otherwise
data-structure/
int fact(int n)
{
if (n < = 1) // base case
return 1;
else
return n*fact(n-1);
}
In the above example, the base case for n < = 1 is defined and
the larger value of a number can be solved by converting to a
smaller one till the base case is reached.
How a particular problem is solved using recursion?
The idea is to represent a problem in terms of one or more
smaller problems, and add one or more base conditions that
stop the recursion. For example, we compute factorial n if we
know the factorial of (n-1). The base case for factorial would
be n = 0. We return 1 when n = 0.
Why Stack Overflow error occurs in recursion?
If the base case is not reached or not defined, then the stack
overflow problem may arise. Let us take an example to
understand this.
int fact(int n)
{
// wrong base case (it may cause
292
// stack overflow).
if (n == 100)
return 1;
else
return n*fact(n-1);
}
If fact(10) is called, it will call fact(9), fact(8), fact(7), and so
on but the number will never reach 100. So, the base case is
not reached. If the memory is exhausted by these functions
on the stack, it will cause a stack overflow error.
What is the difference between direct and indirect
recursion?
A function fun is called direct recursive if it calls the same
function fun. A function fun is called indirect recursive if it
calls another function say fun_new and fun_new calls fun
directly or indirectly. The difference between direct and
indirect recursion has been illustrated in Table 1.
// An example of direct recursion
void directRecFun()
{
// Some code....
directRecFun();
// Some code...
}
{
// Some code...
indirectRecFun2();
// Some code...
}
void indirectRecFun2()
{
// Some code...
indirectRecFun1();
// Some code...
}
What is the difference between tailed and non-tailed
recursion?
A recursive function is tail recursive when a recursive call is
the last thing executed by the function. Please refer tail
recursion article for details.
How memory is allocated to different function calls in
recursion?
When any function is called from main(), the memory is
allocated to it on the stack. A recursive function calls itself,
the memory for a called function is allocated on top of
memory allocated to the calling function and a different copy
of local variables is created for each function call. When the
base case is reached, the function returns its value to the
function by whom it is called and memory is de-allocated and
the process continues.
Let us take the example of how recursion works by taking a
simple function.
294
// recursion
#include <bits/stdc++.h>
if (test < 1)
return;
else {
return;
}
295
// Driver Code
int main()
int test = 3;
printFun(test);
Output :
321123
When printFun(3) is called from main(), memory is
allocated to printFun(3) and a local variable test is
initialized to 3 and statement 1 to 4 are pushed on the stack
as shown in below diagram. It first prints ‘3’. In statement
2, printFun(2) is called and memory is allocated
to printFun(2) and a local variable test is initialized to 2 and
statement 1 to 4 are pushed into the stack.
Similarly, printFun(2) calls printFun(1) and printFun(1) c
alls printFun(0). printFun(0) goes to if statement and it
return to printFun(1). The remaining statements
of printFun(1) are executed and it returns
to printFun(2) and so on. In the output, values from 3 to 1
are printed and then 1 to 3 are printed. The memory stack has
been shown in below diagram.
296
Recursion VS Iteration
SR
No. Recursion Iteration
#include <bits/stdc++.h>
int fib(int n)
298
// Stop condition
if (n == 0)
return 0;
// Stop condition
if (n == 1 || n == 2)
return 1;
// Recursion function
else
// Driver Code
int main()
299
// Initialize variable n.
int n = 5;
cout<<fib(i)<<" ";
return 0;
Output
Fibonacci series of 5 numbers is: 0 1 1 2 3
Time Complexity: O(2n)
Auxiliary Space: O(n)
Here is the recursive tree for input 5 which shows a clear
picture of how a big problem can be solved into smaller
ones.
300
#include <bits/stdc++.h>
// Factorial function
int f(int n)
// Stop condition
if (n == 0 || n == 1)
return 1;
// Recursive condition
else
}
302
// Driver code
int main()
int n = 5;
return 0;
Output
factorial of 5 is: 120
Time complexity: O(2n).
Auxiliary Space: O(n)
Working:
CHAPTER-6
QUEUES
Introduction of Queue:
What is Queue?
A queue is defined as a linear data structure that is open at
both ends and the operations are performed in First In First
Out (FIFO) order.
We define a queue to be a list in which all additions to the list
are made at one end, and all deletions from the list are made
at the other end. The element which is first pushed into the
order, the operation is first performed on that.
the first person in line is the first person served. (i.e. First
come first serve).
Position of the entry in a queue ready to be served, that is,
Characteristics of Queue:
Queue can handle multiple data.
Queue Representation:
2. {
3. if (rear + 1 == max)
4. {
5. printf("overflow");
6. }
309
7. else
8. {
9. if(front == -1 && rear == -1)
10. {
11. front = 0;
12. rear = 0;
13. }
14. else
15. {
16. rear = rear + 1;
17. }
18. queue[rear]=item;
19. }
20. }
Algorithm to delete an element from the queue
If, the value of front is -1 or value of front is greater than rear
, write an underflow message and exit.
Otherwise, keep increasing the value of front and return the
item stored at the front end of the queue at each time.
Algorithm
o Step 1: IF FRONT = -1 or FRONT > REAR
Write UNDERFLOW
ELSE
SET VAL = QUEUE[FRONT]
SET FRONT = FRONT + 1
[END OF IF]
o Step 2: EXIT
C Function
310
1. int delete (int queue[], int max, int front, int rear)
2. {
3. int y;
4. if (front == -1 || front > rear)
5.
6. {
7. printf("underflow");
8. }
9. else
10. {
11. y = queue[front];
12. if(front == rear)
13. {
14. front = rear = -1;
15. else
16. front = front + 1;
17.
18. }
19. return y;
20. }
21. }
Menu driven program to implement queue using array
1. #include<stdio.h>
2. #include<stdlib.h>
3. #define maxsize 5
4. void insert();
5. void delete();
6. void display();
7. int front = -1, rear = -1;
8. int queue[maxsize];
9. void main ()
10. {
311
74. {
75. front = -1;
76. rear = -1 ;
77. }
78. else
79. {
80. front = front + 1;
81. }
82. printf("\nvalue deleted ");
83. }
84.
85.
86. }
87.
88. void display()
89. {
90. int i;
91. if(rear == -1)
92. {
93. printf("\nEmpty queue\n");
94. }
95. else
96. { printf("\nprinting values .....\n");
97. for(i=front;i<=rear;i++)
98. {
99. printf("\n%d\n",queue[i]);
100. }
101. }
102. }
Output:
*************Main Menu**************
314
============================================
==
1.insert an element
2.Delete an element
3.Display the queue
4.Exit
Value inserted
*************Main Menu**************
============================================
==
1.insert an element
2.Delete an element
3.Display the queue
4.Exit
Value inserted
*************Main Menu**************
315
===================================
1.insert an element
2.Delete an element
3.Display the queue
4.Exit
value deleted
*************Main Menu**************
============================================
==
1.insert an element
2.Delete an element
3.Display the queue
4.Exit
90
*************Main Menu**************
============================================
==
1.insert an element
316
2.Delete an element
3.Display the queue
4.Exit
There can be the two scenario of inserting this new node ptr
into the linked queue.
In the first scenario, we insert element into an empty queue. In
this case, the condition front = NULL becomes true. Now, the
new element will be added as the only element of the queue and
the next pointer of front and rear pointer both, will point to
NULL.
1. ptr -> data = item;
2. if(front == NULL)
3. {
4. front = ptr;
5. rear = ptr;
6. front -> next = NULL;
7. rear -> next = NULL;
8. }
In the second case, the queue contains more than one element.
The condition front = NULL becomes false. In this scenario,
we need to update the end pointer rear so that the next pointer
of rear will point to the new node ptr. Since, this is a linked
queue, hence we also need to make the rear pointer point to the
newly added node ptr. We also need to make the next pointer
of rear point to NULL.
1. rear -> next = ptr;
2. rear = ptr;
3. rear->next = NULL;
In this way, the element is inserted into the queue. The
algorithm and the C implementation is given as follows.
320
Algorithm
o Step 1: Allocate the space for the new node PTR
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
C Function
1. void insert(struct node *ptr, int item; )
2. {
3.
4.
5. ptr = (struct node *) malloc (sizeof(struct node));
6. if(ptr == NULL)
7. {
8. printf("\nOVERFLOW\n");
9. return;
10. }
11. else
12. {
13. ptr -> data = item;
14. if(front == NULL)
15. {
16. front = ptr;
17. rear = ptr;
18. front -> next = NULL;
321
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
C Function
1. void delete (struct node *ptr)
2. {
3. if(front == NULL)
4. {
5. printf("\nUNDERFLOW\n");
6. return;
7. }
8. else
9. {
10. ptr = front;
11. front = front -> next;
12. free(ptr);
13. }
14. }
Menu-Driven Program implementing all the operations on
Linked Queue
1. #include<stdio.h>
2. #include<stdlib.h>
3. struct node
4. {
5. int data;
6. struct node *next;
7. };
323
71. }
72. }
73. void delete ()
74. {
75. struct node *ptr;
76. if(front == NULL)
77. {
78. printf("\nUNDERFLOW\n");
79. return;
80. }
81. else
82. {
83. ptr = front;
84. front = front -> next;
85. free(ptr);
86. }
87. }
88. void display()
89. {
90. struct node *ptr;
91. ptr = front;
92. if(front == NULL)
93. {
94. printf("\nEmpty queue\n");
95. }
96. else
97. { printf("\nprinting values .....\n");
98. while(ptr != NULL)
99. {
100. printf("\n%d\n",ptr -> data);
101. ptr = ptr -> next;
102. }
103. }
326
104. }
Operations on queues:
After seeing all the different valid operations for the queue data
structure, let us write a code to implement all of these
operations as functions in the desired programming language.
Let us begin with writing a basic program in Java programming
language that will have the functions to simulate all the
operations discussed above on the queue data
C Code:
1. // Queue implementation in C
2. // Queue implementation in C
3.
4. #include <stdio.h>
5. #define SIZE_OF_QUEUE 7
6.
7. void enQueue(int);
8. void deQueue();
9. void display();
10.
11. int array_of_Queue[SIZE_OF_QUEUE], front_index = -
1, rear_index = -1;
12.
13. int main() {
14.
15. int data;
16. char ch;
17. /* Perform tree operations */
18. do
19. {
20. printf("\nSelect one of the operations::");
21. printf("\n1. To insert data in the Queue Data Stru
cture.");
22. printf("\n2. To display the data present in the Que
ue Data Structure.");
328
86. printf("\n");
87. }
Output:
Select any one of the operations::
1. To insert data in the Queue Data Structure.
2. To display the data present in the Queue Data Structure.
3. To perform the deQueue operation on the Queue Data
Structure.
1
Inserted -> 23
Do you want to continue (Type y or n)
y
Inserted -> 22
Do you want to continue (Type y or n)
y
Inserted -> 87
Do you want to continue (Type y or n)
y
Inserted -> 12
Do you want to continue (Type y or n)
y
Inserted -> 90
Do you want to continue (Type y or n)
y
Inserted -> 78
Do you want to continue (Type y or n)
y
Inserted -> 56
333
Queue is Full!!
Do you want to continue (Type y or n)
y
Dequeue Done.
Deleted : 23
Do you want to continue (Type y or n)
y
Enqueue() Operation
Dequeue() Operation
Now that you have dealt with the operations that allow
manipulation of data entities, you will encounter supportive
functions of the queues -
Peek() Operation
isFull() Operation
isNull() Operation
Types of deque
There are two types of deque -
o Input restricted queue
o Output restricted queue
Input restricted Queue
In input restricted queue, insertion operation can be performed
at only one end, while deletion can be performed from both
ends.
340
Check empty
This operation is performed to check whether the deque is
empty or not. If front = -1, it means that the deque is empty.
Check full
This operation is performed to check whether the deque is full
or not. If front = rear + 1, or front = 0 and rear = n - 1 it means
that the deque is full.
The time complexity of all of the above operations of the deque
is O(1), i.e., constant.
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.
Implementation of deque
Now, let's see the implementation of deque in C programming
language.
1. #include <stdio.h>
2. #define size 5
3. int deque[size];
4. int f = -1, r = -1;
5. // insert_front function will insert the value from the front
6. void insert_front(int x)
7. {
8. if((f==0 && r==size-1) || (f==r+1))
9. {
346
10. printf("Overflow");
11. }
12. else if((f==-1) && (r==-1))
13. {
14. f=r=0;
15. deque[f]=x;
16. }
17. else if(f==0)
18. {
19. f=size-1;
20. deque[f]=x;
21. }
22. else
23. {
24. f=f-1;
25. deque[f]=x;
26. }
27. }
28.
29. // insert_rear function will insert the value from the rear
42. {
43. r=0;
44. deque[r]=x;
45. }
46. else
47. {
48. r++;
49. deque[r]=x;
50. }
51.
52. }
53.
54. // display function prints all the value of deque.
55. void display()
56. {
57. int i=f;
58. printf("\nElements in a deque are: ");
59.
60. while(i!=r)
61. {
62. printf("%d ",deque[i]);
63. i=(i+1)%size;
64. }
65. printf("%d",deque[r]);
66. }
67.
68. // getfront function retrieves the first value of the deque.
74. }
75. else
76. {
77. printf("\nThe value of the element at front is: %d", d
eque[f]);
78. }
79.
80. }
81.
82. // getrear function retrieves the last value of the deque.
83. void getrear()
84. {
85. if((f==-1) && (r==-1))
86. {
87. printf("Deque is empty");
88. }
89. else
90. {
91. printf("\nThe value of the element at rear is %d", de
que[r]);
92. }
93.
94. }
95.
96. // delete_front() function deletes the element from the fro
nt
97. void delete_front()
98. {
99. if((f==-1) && (r==-1))
100. {
101. printf("Deque is empty");
102. }
103. else if(f==r)
349
104. {
105. printf("\nThe deleted element is %d", deque[f]);
106. f=-1;
107. r=-1;
108.
109. }
110. else if(f==(size-1))
111. {
112. printf("\nThe deleted element is %d", deque[f]);
113. f=0;
114. }
115. else
116. {
117. printf("\nThe deleted element is %d", deque[f]);
118. f=f+1;
119. }
120. }
121.
122. // delete_rear() function deletes the element from the rear
Priority Queues:
What is Heap?
A heap is a tree-based data structure that forms a complete
binary tree, and satisfies the heap property. If A is a parent node
of B, then A is ordered with respect to the node B for all nodes
A and B in a heap. It means that the value of the parent node
could be more than or equal to the value of the child node, or
the value of the parent node could be less than or equal to the
value of the child node. Therefore, we can say that there are
two types of heaps:
o Max heap: The max heap is a heap in which the value of
the parent node is greater than the value of the child nodes.
357
Both the heaps are the binary heap, as each has exactly two
child nodes.
Priority Queue Operations
The common operations that we can perform on a priority
queue are insertion, deletion and peek. Let's see how we can
maintain the heap data structure.
o Inserting the element in a priority queue (max heap)
If we insert an element in a priority queue, it will move to the
empty slot by looking from top to bottom and left to right.
If the element is not in a correct place then it is compared with
the parent node; if it is found out of order, elements are
swapped. This process continues until the element is placed in
a correct position.
358
child and right child, and swap with the smaller of the two. It
keeps moving down the tree until the heap property is restored.
Applications of Priority queue
The following are the applications of the priority queue:
o It is used in the Dijkstra's shortest path algorithm.
o It is used in prim's algorithm
o It is used in data compression techniques like Huffman
code.
o It is used in heap sort.
o It is also used in operating system like priority scheduling,
load balancing and interrupt handling.
Program to create the priority queue using the binary max
heap.
1. #include <stdio.h>
2. #include <stdio.h>
3. int heap[40];
4. int size=-1;
5.
6. // retrieving the parent node of the child node
7. int parent(int i)
8. {
9.
10. return (i - 1) / 2;
11. }
12.
13. // retrieving the left child of the parent node.
360
46.
47. }
48. // updating the value of i to i/2
49. i=i/2;
50. }
51. }
52.
53. //function to move the node down the tree in order to rest
ore the heap property.
54. void moveDown(int k)
55. {
56. int index = k;
57.
58. // getting the location of the Left Child
59. int left = left_child(k);
60.
61. if (left <= size && heap[left] > heap[index]) {
62. index = left;
63. }
64.
65. // getting the location of the Right Child
66. int right = right_child(k);
67.
68. if (right <= size && heap[right] > heap[index]) {
69. index = right;
70. }
71.
72. // If k is not equal to index
73. if (k != index) {
74. int temp;
75. temp=heap[index];
76. heap[index]=heap[k];
77. heap[k]=temp;
362
78. moveDown(index);
79. }
80. }
81.
82. // Removing the element of maximum priority
83. void removeMax()
84. {
85. int r= heap[0];
86. heap[0]=heap[size];
87. size=size-1;
88. moveDown(0);
89. }
90. //inserting the element in a priority queue
91. void insert(int p)
92. {
93. size = size + 1;
94. heap[size] = p;
95.
96. // move Up to maintain heap property
97. moveUp(size);
98. }
99.
100. //Removing the element from the priority queue at a give
n index i.
101. void delete(int i)
102. {
103. heap[i] = heap[0] + 1;
104.
105. // move the node stored at ith location is shifted to the r
oot node
106. moveUp(i);
107.
108. // Removing the node having maximum priority
363
109. removeMax();
110. }
111. int main()
112. {
113. // Inserting the elements in a priority queue
114.
115. insert(20);
116. insert(19);
117. insert(21);
118. insert(18);
119. insert(12);
120. insert(17);
121. insert(15);
122. insert(16);
123. insert(14);
124. int i=0;
125.
126. printf("Elements in a priority queue are : ");
127. for(int i=0;i<=size;i++)
128. {
129. printf("%d ",heap[i]);
130. }
131. delete(2); // deleting the element whose index is 2.
132. printf("\nElements in a priority queue after deleting th
e element are : ");
133. for(int i=0;i<=size;i++)
134. {
135. printf("%d ",heap[i]);
136. }
137. int max=get_Max();
138. printf("\nThe element which is having the highest prio
rity is %d: ",max);
139.
364
140.
141. int min=get_Min();
142. printf("\nThe element which is having the minimum
priority is : %d",min);
143. return 0;
144. }
In the above program, we have created the following
functions:
o int parent(int i): This function returns the index of the
parent node of a child node, i.e., i.
o int left_child(int i): This function returns the index of the
left child of a given index, i.e., i.
o int right_child(int i): This function returns the index of
the right child of a given index, i.e., i.
o void moveUp(int i): This function will keep moving the
node up the tree until the heap property is restored.
o void moveDown(int i): This function will keep moving
the node down the tree until the heap property is restored.
o void removeMax(): This function removes the element
which is having the highest priority.
o void insert(int p): It inserts the element in a priority
queue which is passed as an argument in a function.
o void delete(int i): It deletes the element from a priority
queue at a given index.
o int get_Max(): It returns the element which is having the
highest priority, and we know that in max heap, the root
node contains the element which has the largest value, and
highest priority.
o int get_Min(): It returns the element which is having the
minimum priority, and we know that in max heap, the last
365
Applications of queues:
queue
Spooling in printers
Mail Queues
SECTION-IV
CHAPTER-7
TREE
Introduction of Tree:
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:
named Tom and Raj. Tom has one direct report named Bill.
This particular logical structure is known as a Tree. Its structure
is similar to the real tree, so it is named a Tree. In this structure,
the root is at the top, and its branches are moving in a
downward direction. Therefore, we can say that the Tree data
structure is an efficient way of storing the data in a hierarchical
way.
Let's understand some key points of the Tree data
structure.
o A tree data structure is defined as a collection of objects
or entities known as nodes that are linked together to
represent or simulate hierarchy.
o A tree data structure is a non-linear data structure because
it does not store in a sequential manner. It is a hierarchical
structure as elements in a Tree are arranged in multiple
levels.
o In the Tree data structure, the topmost node is known as a
root node. Each node contains some data, and data can be
of any type. In the above tree structure, the node contains
the name of the employee, so the type of data would be a
string.
o Each node contains some data and the link or reference of
other nodes that can be called children.
369
Implementation of Tree
The tree data structure can be created by creating the nodes
dynamically with the help of the pointers. The tree in the
memory can be represented as shown below:
1. struct node
2. {
3. int data;
4. struct node *left;
5. struct node *right;
6. }
The above structure can only be defined for the binary trees
because the binary tree can have utmost two children, and
373
generic trees can have more than two children. The structure of
the node for generic trees would be different as compared to the
binary tree.
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.
Types of Tree data structure
The following are the types of a tree data structure:
o General tree: The general tree is one of the types of tree
data structure. In the general tree, a node can have either
0 or maximum n number of nodes. There is no restriction
imposed on the degree of the node (the number of nodes
374
1. struct node
2. {
3. int data;
4. struct node *left;
5. struct node *right;
6. }
The above is the node structure with three fields: data field, the
second field is the left pointer of the node type, and the third
field is the right pointer of the node type.
o AVL tree
each node in the AVL tree should have the value of the
balancing factor either as 0, -1, or 1.
o Red-Black Tree
o B-tree
child2=⟮2∗parent⟯+1child2=⟮2∗parent⟯+1
381
15. {
16. struct node *newNode;
17.
18. newNode = malloc(sizeof(struct node));
19.
20. newNode->key = val;
21. newNode->left = NULL;
22. newNode->right = NULL;
23.
24. return newNode;
25. }
26.
27. //inserts nodes in the binary search tree
28. struct node *insertNode(struct node *root, int val)
29. {
30. if(root == NULL)
31. return getNode(val);
32.
33. if(root->key < val)
34. root->right = insertNode(root->right,val);
35.
36. if(root->key > val)
37. root->left = insertNode(root->left,val);
38.
39. return root;
40. }
41.
42. //inorder traversal of the binary search tree
43. void inorder(struct node *root)
44. {
45. if(root == NULL)
46. return;
47.
385
78. scanf("%d",&data);
79. root = insertNode(root,data);
80. break;
81. case 2 :
82. printf("\nInorder Traversal of the Binary Tree::
\n");
83. inorder(root);
84. break;
85. default :
86. printf("Wrong Entry\n");
87. break;
88. }
89.
90. printf("\nDo you want to continue (Type y or n)\n
");
91. scanf(" %c",&ch);
92. } while (ch == 'Y'|| ch == 'y');
93.
94. return 0;
95. }
Output
The above C code hives the following output.
Select one of the operations::
1. To insert a new node in the Binary Tree
2. To display the nodes of the Binary Tree (via Inorder
Traversal).
1
49. return;
50.
51. //visit the root
52. printf("%d ",root->key);
53.
54. //traverse the left subtree
55. preorder(root->left);
56.
57. //traverse the right subtree
58. preorder(root->right);
59. }
60.
61. int main()
62. {
63. struct node *root = NULL;
64.
65. int data;
66. char ch;
67. /* Do while loop to display various options to selec
t from to decide the input */
68. do
69. {
70. printf("\nSelect one of the operations::");
71. printf("\n1. To insert a new node in the Binary Tr
ee");
72. printf("\n2. To display the nodes of the Binary Tr
ee(via Preorder Traversal).\n");
73.
74. int choice;
75. scanf("%d",&choice);
76. switch (choice)
77. {
78. case 1 :
392
58. }
59. int main()
60. {
61. struct node *root = NULL;
62.
63.
64. int data;
65. char ch;
66. /* Do while loop to display various options to selec
t from to decide the input */
67. do
68. {
69. printf("\nSelect one of the operations::");
70. printf("\n1. To insert a new node in the Binary Tr
ee");
71. printf("\n2. To display the nodes of the Binary Tr
ee(via Postorder Traversal).\n");
72.
73. int choice;
74. scanf("%d",&choice);
75. switch (choice)
76. {
77. case 1 :
78. printf("\nEnter the value to be inserted\n");
79. scanf("%d",&data);
80. root = insertNode(root,data);
81. break;
82. case 2 :
83. printf("\nPostorder Traversal of the Binary Tre
e::\n");
84. postorder(root);
85. break;
86. default :
400
88
54. case 4 :
55. printf("\nPostorder Traversal of the Binary Tre
e::\n");
56. postorder(ptr);
57. break;
58. default :
59. printf("Wrong Entry\n");
60. break;
61. }
62.
63. printf("\nDo you want to continue (Type y or n)\n
");
64. scanf(" %c",&ch);
65. } while (ch == 'Y'|| ch == 'y');
66.
67.
68. // printf("\nProgram for Tree Traversal\n");
69. // printf("Enter the number of nodes to add to the tree.
<BR>\n");
70. // scanf("%d",&no);
71.
72. // for(i=0;i<no;i++)
73. // {
74. // printf("Enter the item\n");
75. // scanf("%d",&num);
76. // insert(&ptr,num);
77. // }
78.
79. // //getch();
80. // printf("\nINORDER TRAVERSAL\n");
81. // inorder(ptr);
82.
83. // printf("\nPREORDER TRAVERSAL\n");
408
84. // preorder(ptr);
85.
86. // printf("\nPOSTORDER TRAVERSAL\n");
87. // postorder(ptr);
88.
89. }
90.
91. void insert(struct node **p,int num)
92. {
93. if((*p)==NULL)
94. {
95. printf("Leaf node created.");
96. (*p)=malloc(sizeof(struct node));
97. (*p)->left = NULL;
98. (*p)->right = NULL;
99. (*p)->data = num;
100. return;
101. }
102. else
103. {
104. if(num==(*p)->data)
105. {
106. printf("\nREPEATED ENTRY ERROR VALUE
REJECTED\n");
107. return;
108. }
109. if(num<(*p)->data)
110. {
111. printf("\nDirected to left link.\n");
112. insert(&((*p)->left),num);
113. }
114. else
115. {
409
149. if(p!=NULL)
150. {
151. postorder(p->left);
152. postorder(p->right);
153. printf("%d ",p->data);
154. }
155. else
156. return;
157. }
Output:
Select one of the operations::
1. To insert a new node in the Binary Tree
2. To display the nodes of the Binary Tree(via Preorder
Traversal).
3. To display the nodes of the Binary Tree(via Inorder
Traversal).
4. To display the nodes of the Binary Tree(via Postorder
Traversal).
1
A. Inorder Traversal
Go to step 3.
import java.util.Stack;
class Node {
int data;
data = item;
}
418
class BinaryTree {
Node root;
void inorder()
if (root == null)
return;
s.push(curr);
curr = curr.left;
curr = s.pop();
// subtree's turn
420
curr = curr.right;
tree.inorder();
421
Output
42513
TimeComplexity: O(n)
SpaceComplexity: O(n)
B. Preorder Traversal
Java
422
import java.util.*;
import java.io.*;
class Node {
int data;
data = item;
class BinaryTree {
423
Node root;
void preorder()
if (root == null)
return;
s.push(curr);
curr = curr.left;
curr = s.pop();
// subtree's turn
curr = curr.right;
425
tree.preorder();
}
426
Output
12453
Time Complexity: O(n)
Space Complexity: O(n)
Java
427
import java.util.Stack;
class Node {
int data;
data = item;
class BinaryTree {
Node root;
void preorder()
if (root == null) {
return;
S.add(root);
if (root.right != null) {
S.add(root.right);
if (root.left != null) {
S.add(root.left);
while (S.size() != 1) {
S.pop();
if (temp != null) {
if (temp.right != null) {
S.add(temp.right);
if (temp.left != null) {
S.add(temp.left);
{
431
tree.preorder();
Output
12453
TimeComplexity: O(n)
SpaceComplexity: O(n)
C. PostOrder Traversal
top of the stack, then remove the right child from the stack,
push the root back, and set the root as root’s right child.
Else print root’s data and set root as NULL.
Java
import java.util.ArrayList;
import java.util.Stack;
class Node {
int data;
Node(int item)
data = item;
left = right;
class BinaryTree {
Node root;
if (node == null)
return;
S.push(node);
while (!S.isEmpty()) {
|| prev.right == current) {
if (current.left != null)
S.push(current.left);
S.push(current.right);
else {
S.pop();
if (current.right != null)
S.push(current.right);
else {
S.pop();
S.pop();
prev = current;
tree.postOrder(tree.root);
Output
45231
Time Complexity: O(n)
Space Complexity: O(n)
438
439
CHAPTER-8
GRAPH
Introduction of Graph:
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 unordered pairs in the definition of every edge.
4. Directed Graph
A graph in which edge has direction. That is the nodes are
ordered pairs in the definition of every edge.
441
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.
442
7. Regular Graph
The graph in which the degree of every vertex is equal to the
other vertices of the graph. Let the degree of each vertex
be K then the graph
8. Complete Graph
The graph in which from each node there is an edge to each
other node.
443
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.
444
Representation of Graphs
There are two ways to store a graph:
Adjacency Matrix
Adjacency List
Adjacency Matrix
In this method, the graph is stored in the form of the 2D matrix
where rows and columns denote vertices. Each entry in the
matrix represents the weight of the edge between those
vertices.
447
Adjacency List
This graph is represented as a collection of linked lists. There
is an array of pointer which points to the edges connected to
that vertex.
448
the graph.
Searching on Graphs – Search an entity in the graph.
Usage of graphs
Maps can be represented using graphs and then can be used
moves from current states. In-game of tic tac toe this can be
used.
Real-Life Applications of Graph
Point
A point is a particular position in a one-dimensional, two-
dimensional, or three-dimensional space. For better
understanding, a point can be denoted by an alphabet. It can be
represented with a dot.
Example
Here, ‘a’ and ‘b’ are the points. The link between these two
points is called a line.
Vertex
A vertex is a point where multiple lines meet. It is also called
a node. Similar to points, a vertex is also denoted by an
alphabet.
Example
Edge
An edge is the mathematical term for a line that connects two
vertices. Many edges can be formed from a single vertex.
Without a vertex, an edge cannot be formed. There must be a
starting vertex and an ending vertex for an edge.
Example
Here, ‘a’ and ‘b’ are the two vertices and the link between them
is called an edge.
Graph
A graph ‘G’ is defined as G = (V, E) Where V is a set of all
vertices and E is a set of all edges in the graph.
Example 1
In the above example, ab, ac, cd, and bd are the edges of the
graph. Similarly, a, b, c, and d are the vertices of the graph.
Example 2
452
In this graph, there are two loops which are formed at vertex a,
and vertex b.
Degree of Vertex
It is the number of vertices adjacent to a vertex V.
453
Notation − deg(V).
In a simple graph with n number of vertices, the degree of any
vertices is −
deg(v) ≤ n – 1 ∀ v ∈ G
A vertex can form an edge with all other vertices except by
itself. So the degree of a vertex will be up to the number of
vertices in the graph minus 1. This 1 is for the self-vertex as
it cannot form a loop by itself. If there is a loop at any of the
vertices, then it is not a Simple Graph.
Degree of vertex can be considered under two cases of graphs
−
Undirected Graph
Directed Graph
Degree of Vertex in an Undirected Graph
An undirected graph has no directed edges. Consider the
following examples.
Example 1
Take a look at the following graph −
454
The vertex ‘e’ is an isolated vertex. The graph does not have
any pendent vertex.
Degree of Vertex in a Directed Graph
In a directed graph, each vertex has an indegree and
an outdegree.
Indegree of a Graph
Indegree of vertex V is the number of edges which are
Outdegree of a Graph
Outdegree of vertex V is the number of edges which are
a 1 2
b 2 0
c 2 1
d 1 1
e 1 1
f 1 1
g 0 2
457
Example 2
Take a look at the following directed graph. Vertex ‘a’ has an
edge ‘ae’ going outwards from vertex ‘a’. Hence its outdegree
is 1. Similarly, the graph has an edge ‘ba’ coming towards
vertex ‘a’. Hence the indegree of ‘a’ is 1.
a 1 1
b 0 2
c 2 0
d 1 1
e 1 1
Pendent Vertex
By using degree of a vertex, we have a two special types of
vertices. A vertex with degree one is called a pendent vertex.
458
Example
Example 1
In the above graph, ‘a’ and ‘b’ are the two vertices which are
connected by two edges ‘ab’ and ‘ab’ between them. So it is
called as a parallel edge.
Multi Graph
A graph having parallel edges is known as a Multigraph.
Example 1
In the above graph, there are five edges ‘ab’, ‘ac’, ‘cd’, ‘cd’,
and ‘bd’. Since ‘c’ and ‘d’ have two parallel edges between
them, it a Multigraph.
Example 2
461
In the above graph, the vertices ‘b’ and ‘c’ have two edges. The
vertices ‘e’ and ‘d’ also have two edges between them. Hence
it is a Multigraph.
Degree Sequence of a Graph
If the degrees of all vertices in a graph are arranged in
descending or ascending order, then the sequence obtained is
known as the degree sequence of the graph.
Example 1
Vertex A b c d e
Degree 2 2 2 3 1
In the above graph, for the vertices {d, a, b, c, e}, the degree
sequence is {3, 2, 2, 2, 1}.
462
Example 2
Vertex A b c d e f
Degree 2 2 2 2 2 0
In the above graph, for the vertices {a, b, c, d, e, f}, the degree
sequence is {2, 2, 2, 2, 2, 0}.
Graph representation
In this article, we will discuss the ways to represent the graph.
By Graph representation, we simply mean the technique to be
used to store some graph into the computer's memory.
463
Now, consider the weighted directed graph, and let's see the
adjacency list representation of that graph.
5.
6. /* function to initialize the matrix to zero */
7. void init(int arr[][V]) {
8. int i, j;
9. for (i = 0; i < V; i++)
10. for (j = 0; j < V; j++)
11. arr[i][j] = 0;
12. }
13.
14. /* function to add edges to the graph */
15. void insertEdge(int arr[][V], int i, int j) {
16. arr[i][j] = 1;
17. arr[j][i] = 1;
18. }
19.
20. /* function to print the matrix elements */
21. void printAdjMatrix(int arr[][V]) {
22. int i, j;
23. for (i = 0; i < V; i++) {
24. printf("%d: ", i);
25. for (j = 0; j < V; j++) {
26. printf("%d ", arr[i][j]);
27. }
28. printf("\n");
29. }
30. }
31.
32. int main() {
33. int adjMatrix[V][V];
34.
35. init(adjMatrix);
36. insertEdge(adjMatrix, 0, 1);
37. insertEdge(adjMatrix, 0, 2);
470
10.
11. /* structure to represent an adjacency list */
12. struct AdjList {
13. struct AdjNode* head;
14. };
15.
16. /* structure to represent the graph */
17. struct Graph {
18. int V; /*number of vertices in the graph*/
19. struct AdjList* array;
20. };
21.
22.
23. struct AdjNode* newAdjNode(int dest)
24. {
25. struct AdjNode* newNode = (struct AdjNode*)mallo
c(sizeof(struct AdjNode));
26. newNode->dest = dest;
27. newNode->next = NULL;
28. return newNode;
29. }
30.
31. struct Graph* createGraph(int V)
32. {
33. struct Graph* graph = (struct Graph*)malloc(sizeof(s
truct Graph));
34. graph->V = V;
35. graph-
>array = (struct AdjList*)malloc(V * sizeof(struct AdjList));
36.
37. /* Initialize each adjacency list as empty by making he
ad as NULL */
472
38. int i;
39. for (i = 0; i < V; ++i)
40. graph->array[i].head = NULL;
41. return graph;
42. }
43.
44. /* function to add an edge to an undirected graph */
45. void addEdge(struct Graph* graph, int src, int dest)
46. {
47. /* Add an edge from src to dest. The node is added at t
he beginning */
48. struct AdjNode* check = NULL;
49. struct AdjNode* newNode = newAdjNode(dest);
50.
51. if (graph->array[src].head == NULL) {
52. newNode->next = graph->array[src].head;
53. graph->array[src].head = newNode;
54. }
55. else {
56.
57. check = graph->array[src].head;
58. while (check->next != NULL) {
59. check = check->next;
60. }
61. // graph->array[src].head = newNode;
62. check->next = newNode;
63. }
64.
65. /* Since graph is undirected, add an edge from dest to
src also */
66. newNode = newAdjNode(src);
67. if (graph->array[dest].head == NULL) {
68. newNode->next = graph->array[dest].head;
473