CSIT124 - Data Structure Using C PDF
CSIT124 - Data Structure Using C PDF
ity
Structure:
rs
1.1.2 Algorithm Design
1.1.3 Complexity, Time-Space Tradeoffs
1.1.4 Use of pointers in data structures
ve
Unit-1.2: Arrays
1.2.1 Array Definition and Analysis
1.2.2 Representation of Linear Arrays in Memory
1.2.3 Traversing of Linear Arrays
ni
1.2.4 Insertion and Deletion
1.2.5 Single Dimensional Arrays
1.2.6 Two Dimensional Arrays
1.2.7 Multidimensional Arrays
U
1.2.8 Function Associated with Arrays
Unit-1.3: Strings
1.3.1 Character String in C
ity
ity
1.1.1 Definition and Types of Data structure
Data structure is a representation of data and the operations allowed on that
data. A data structure is a way to store and organize data to facilitate the access and
modifications. The data structure name indicates itself that organizing the data in
memory. There are many ways of organizing the data in the memory. Data Structure
rs
are the method of representing of logical relationships between individual data elements
related to the solution of a given problem. To structure the data in memory, ‘n’ number
of algorithms were used, and all these algorithms are known as Abstract data types.
ve
access and modification. Here are several basic and advanced structure types.
ni
The structure should be simple enough that one can effectively process the
data when necessary.
Data Structure
U
Linear data Non-linear data
Structure Structure
Linked
Array Stack Queue Graphs Trees
ity
list
There are two types of data structures: The primitive data structures are primitive
data types. The int, char, float, double, and pointer are the primitive data structures
m
that can hold a single value. The non-primitive data structure is divided into two types:
Linear data structure & Non-linear data structure.
Other than linear and non-linear there are below more types of data structures
available.
)A
Static or dynamic data structures: This type tells how the data structures are
compiled. Static data structures have fixed sizes and Dynamic data structures have
flexible size. In Static data structure, the content of the data structure can be modified
but without changing the memory space allocated to it. Dynamic data structure can be
modified during the operations performed on it. Dynamic data structures are designed Notes
ity
to facilitate change of data structures in the run time.
Linear Data Structures: In Linear data structure, values are arranged in linear
fashion. The data structures used for this purpose are Arrays, Linked list, Stacks,
and Queues. In these data structures, one element is connected to only one another
element in a linear form.
rs
●● Array: A collection of items when we store at adjoining memory locations
is called an Array. Same type of elements gets stored together so that the
position of each element can be calculated or retrieved easily. Arrays can be
of fixed or flexible length. It is a finite group of data and is allocated contiguous
memory locations. To access an element within the array can be accessed by
ve
an index key.
Example: The syntax for storing and displaying the values in an array typically
looks something like this:
arrayname[0] = “This “;
arrayname[1] = “is “;
print arrayname[0];
ni
U
print arrayname[1];
print arrayname[2];
The above commands would print the first three values of the array, or “This is
pretty simple.” By using a “while” or “for” loop, the programmer can tell the program
ity
to output each value in the array until the last value has been reached. So not only do
arrays help manage memory more efficiently, they make the programmer’s job more
efficient as well.
Element
First index (at index 8)
m
0 1 2 3 4 5 6 7 8 9 Indices
Array length is 10
)A
An array of 10 elements
particular order in which the operations are applied is called stack. This order
could be last in first out (LIFO) or first in first out (FIFO). In LIFO, elements are
added to top and removed from top.
Notes
ity
3
1 3
2 2 2
1 1 1
rs
stack
ve
middle or end of linked list. Linked list contains data elements along with its
pointer which points to the next data element. In this case memory locations
are not contiguous. In linked list
Linked List contains a link called first. Each link carries a data field and a link field.
Link field is called next. Each link is linked with its next link using its next link. Last
ni
link carries a link as null to mark the end of the list. The various types of linked list are
Simple Linked List, Doubly Linked List, Circular Linked List.
U
Data
Pointer to the
Head next node
A Node
5 7 2 15
ity
Notes
ity
Back Front
Dequeue
Enqueue
rs
Fig 1.5: Queue
ve
Non-Linear Data Structures: The data values in this structure are not arranged in
order.
●● Hash tables: Hash tables, also known as hash map, stores a collection of
data in an associative manner. Array items are associated with keys. Items
are in (key, value) format. It is an unordered list which use a ‘hash function’ to
●●
●●
insert and search.
Tree: Data is organized in branches.
ni
Graph: A more general branching structure, with less strict connection
conditions than for a tree
U
Liner Vs. Non Linear Data Structure:
6. Its examples are: array, stack, queue, While its examples are: trees and
linked list, etc. graphs.
ity
Algorithm is a step-by-step procedure, which defines a set of instructions to be
executed in a certain order to get the desired output. Algorithms are generally created
independent of underlying languages, i.e., an algorithm can be implemented in more
than one programming language.
Characteristics of an Algorithm
rs
Not all procedures can be called an algorithm. An algorithm should have the
following characteristics −
ve
●● Input − An algorithm should have 0 or more well-defined inputs.
●● Output − An algorithm should have 1 or more well-defined outputs and should
match the desired output.
●● Finiteness − Algorithms must terminate after a finite number of steps.
●●
●●
ni
Feasibility − Should be feasible with the available resources.
Independent − An algorithm should have step-by-step directions, which should
be independent of any programming code.
U
1.1.3 Complexity, Time-Space Tradeoffs
Algorithm Analysis
Analysis, we evaluate the performance of an algorithm in terms of input size (we don’t
measure the actual running time). We calculate, how the time (or space) taken by an
algorithm increases with the input size. For example, let us consider the search problem
(searching a given item) in a sorted array. One way to search is Linear Search (order of
growth is linear) and the other way is Binary Search (order of growth is logarithmic).
m
which means that A is 5000 times more powerful than B. For small values of input array
size n, the fast computer may take less time. But, after a certain value of input array
size, the Binary Search will definitely start taking less time compared to the Linear
Search even though the Binary Search is being run on a slow machine. The reason is
the order of growth of Binary Search with respect to input size is logarithmic while the
order of growth of Linear Search is linear. So the machine dependent constants can
(c
ity
●● Identify unknown quantities that can be used to describe the frequency of
execution of the basic operations.
●● Develop a realistic model for the input to the program.
●● Analyze the unknown quantities, assuming the modelled input.
●● Calculate the total running time by multiplying the time by the frequency for
rs
each operation, then adding all the products.
●● A Priori Analysis − This is a theoretical analysis of an algorithm. Efficiency
of an algorithm is measured by assuming that all other factors, for example,
processor speed, are constant and have no effect on the implementation.
ve
●● A Posterior Analysis − This is an empirical analysis of an algorithm. The
selected algorithm is implemented using programming language. This is then
executed on target computer machine. In this analysis, actual statistics like
running time and space required, are collected.
Algorithm Complexity
ni
Suppose X is an algorithm and n is the size of input data, the time and space
used by the algorithm X are the two main factors, which decide the efficiency of X.
Space Complexity
ity
●● A fixed part that is a space required to store certain data and variables, that
are independent of the size of the problem. For example, simple variables and
constants used, program size, etc.
m
Time Complexity
Time Complexity of an algorithm is the representation of the amount of time
required by the algorithm to execute to completion. Time requirements can be denoted
or defined as a numerical function t(N), where t(N) can be measured as the number of
steps, provided each step takes constant time.
For example, in case of addition of two n-bit integers, N steps are taken.
(c
Consequently, the total computational time is t(N) = c*n, where c is the time consumed
for addition of two bits. Here, we observe that t(N) grows linearly as input size
increases.
In divide and conquer approach, a problem is divided into smaller problems, then
Notes the smaller problems are solved independently, and finally the solutions of smaller
ity
problems are combined into a solution for the large problem.
●● Divide the problem into a number of sub-problems that are smaller instances
of the same problem.
●● Conquer the sub-problems by solving them recursively. If they are small
rs
enough, solve the sub-problems as base cases.
●● Combine the solutions to the sub-problems into the solution for the original
problem.
●● Divide and conquer approach supports parallelism as sub-problems are
ve
independent. Hence, an algorithm, which is designed using this technique,
can run on the multiprocessor system or in different machines simultaneously.
●● In this approach, most of the algorithms are designed using recursion, hence
memory management is very high. For recursive function stack is used, where
function state needs to be stored.
conquer approach.
●●
ni
Following are some problems, which are solved using divide and
The Max-Min Problem in algorithm analysis is finding the maximum and minimum
value in an array.
Solution
To find the maximum and minimum numbers in a given array numbers[] of size n,
the following algorithm can be used. First we are representing the naive method and
m
the pointer is something like a variable that holds that memory address of the variable.
One can easily find the page using the location referred to there. Such pointers usage
helps in the dynamic implementation of various data structures such as stack or list.
Optimization of our code and improving the time complexity of one algorithm. Since
using pointers helps to reduce the time needed by an algorithm to copy data from one
place to another. Since it used the memory locations directly, any change made to the
(c
Like we have pointers to int, char and other data-types, we also have pointers
pointing to structures. These pointers are called structure pointers.
ity
struct structure_name
data-type member-1;
data-type member-1;
rs
data-type member-1;
data-type member-1;
};
ve
int main()
ni
U
ity
m
)A
(c
Unit-1.2: Arrays
Notes
ity
1.2.1 Array Definition and Analysis
An array is a collection of items stored at contiguous memory locations. The idea is
to store multiple items of the same type together. This makes it easier to calculate the
position of each element by simply adding an offset to a base value, i.e., the memory
location of the first element of the array (generally denoted by the name of the array).
rs
Memory Location
200 201 202 203 204 205 206 ▪ ▪ ▪
U B F D A E C ▪ ▪ ▪
ve
0 1 2 3 4 5 6 ▪ ▪ ▪
Index
ni
1.2.2 Representation of Linear Arrays in Memory
A linear array is a list of finite numbers of elements stored in the memory. In a
linear array, we can store only homogeneous data elements. Elements of the array
form a sequence or linear list, that can have the same type of data.
U
Each element of the array is referred by an index set. The total number of
elements in the array list, is the length of an array. We can access these elements with
the help of the index set. For example, consider an array of employee names with the
index set from 0 to 7, which contains 8 elements as shown in fig:
ity
0 1 2 3 4 5 6 7
Now, if we want to retrieve the name ‘Alex’ from the given array, we can do so by
m
calling “employees [3]”. It gives the element stored in that location, that is ‘Alex’, and so
on.
We can calculate the length, or a total number of elements, of a linear array (LA),
by the given formula:
)A
Length (LA)=UB-LB+1
Here, UB refers to the upper bound, the largest index set of the given array list.
LB refers to the lower bound, smallest index set of the given array list.
For example, we have an array of employees, in which lower bound is 153 and
the upper bound is 234, so we can calculate the total number of elements in the list, by
(c
234-153+1=82
ity
We can process each element of an array with the help of an index set. The array
elements are stored in contiguous (i.e. one after the other) memory locations. All the
array elements must be of one particular data types like either int or, float or, char or,
double etc. or they can be of any user-defined data types like structures and unions.
Example:
rs
/*Array traversal*/
#include <stdio.h>
int main()
ve
int arr[5],i;
for(i=0;i<5;i++){
scanf(“%d”,&arr[i]);
printf(“\n”); ni
U
}
for(i=0;i<5;i++){
return 0;
}
Output:
m
arr[0] = 10
arr[0] = 20
)A
arr[0] = 30
arr[0] = 40
arr[0] = 50
Array insertion, of an element at the end of the list, is quite simple. We can do
so by providing the unallocated space to the new element. On the other hand, if we
need to insert an element in the middle of an array, lots of internal shifting is required to
Notes insert the new element. i.e., half of the elements must be moved downward, to the new
ity
location, to enter the new element.
Similarly, deletion of the element from the end of the array, is quite simple. But, if
we need to delete an element from the middle of the array, then on average, half of the
elements must be moved upward, to fill the blank space, after deleting the element from
the specified location.
rs
1.2.5 Single Dimensional Arrays
An array is a collection of elements of one specific type in a horizontal fashion.
The array in contention here is that of the one-dimensional array in C programming.
ve
Anything having one-dimension means that there is only one parameter to deal
with. In regular terms, it is the length of something. Similarly, as far as an array is
concerned, one dimension means it has only one value per location or index.
As you can see in the example given above, firstly, you need to declare the
elements that you want to be in the specified array. Secondly, the location of each
ity
element needs to particularize as well, since that is where the elements will be stored
respectively.
data_type array_name[array_size];
Here is the general form to initialize values to one dimensional array in C: data_
m
Example:
#include<stdio.h>
int main()
int i;
return 0;
Notes
ity
}
Output:
rs
Elements of One dimensional array is: 3
ve
1.2.6 Two Dimensional Arrays
An array keeps track of multiple pieces of information in linear order, a one-
dimensional list. However, the data associated with certain systems (a digital image,
a board game, etc.) lives in two dimensions. To visualize this data, we need a multi-
dimensional data structure, that is, a multi-dimensional array. A two-dimensional array
ni
is really nothing more than an array of arrays (a three-dimensional array is an array
of arrays of arrays). Think of your dinner. You could have a one-dimensional list of
everything you eat: (lettuce, tomatoes, steak, mashed potatoes, cake, ice cream) Or
you could have a two-dimensional list of three courses, each containing two things you
U
eat: (lettuce, tomatoes) and (steak, mashed potatoes) and (cake, ice cream)
In the case of an array, our old-fashioned one-dimensional array looks like this: int[]
myArray = {0,1,2,3};
{3, 2, 1, 0},
{3, 5, 6, 1},
)A
{3, 8, 3, 4} };
Example:
#include<stdio.h>
int main(){
(c
int a=0,b=0;
int arr[4][3]={{1,2,3},{2,3,4},{3,4,5},{4,5,6}};
//traversing 2D array
for(a=0;a<4;a++){
Notes
ity
for(b=0;b<3;b++){
}j
rs
return 0;
}
Output:
arr[0] [0] = 1
ve
arr[0] [1] = 2
arr[0] [2] = 3
arr[1] [0] = 2
arr[1] [1] = 3
arr[1] [2] = 4
arr[2] [0] = 3
ni
U
arr[2] [1] = 4
arr[2] [2] = 5
arr[3] [0] = 4
arr[3] [1] = 5
ity
arr[3] [2] = 6
multidimensional arrays. For example, x is a two-dimensional (2d) array. The array can
hold 12 elements. You can think the array as a table with 3 rows and each row has 4
columns.
ity
to represent dimensions 3 and higher.
Example:
/*Multi-dimensional array*/
#include<stdio.h>
rs
int main()
int a, b, c;
ve
int arr[3][3][3]=
{1, 2, 3},
},
{4, 5, 6},
{7, 8, 9}
ni
U
{
},
},
)A
};
for(a=0;a<3;a++)
for(b=0;b<3;b++)
(c
for(c=0;c<3;c++)
{
Notes
ity
printf(“%d\t”,arr[a][b][c]);
printf(“\n”);
rs
printf(“\n”);
return 0;
ve
}
Output:
3D Array Elements:
1 2 3
7
5
8
6
9
ni
U
11 12 13
14 15 16
17 18 19
ity
21 22 23
24 25 26
27 28 29
m
does not limit the number of dimensions in an Array. Traversing, searching, insertion,
deletion, sorting are different functions associated with array.
In an Array, the search operation is used to find a particular data item or element in.
We can perform searching in an unsorted array with the help of traversal of the Array. Notes
ity
The linear traversal from the first element to the last element can be used to search if a
given number is present in an Array and can also be used to find its position if present.
rs
#include <stdio.h>
int main()
ve
int arr[MAX_SIZE];
int size;
int i, j, temp;
scanf(“%d”, &arr[i]);
temp = arr[i];
arr[i] = arr[j];
Notes
ity
arr[j] = temp;
rs
/* Print the sorted array */
ve
for(i=0; i<size; i++)
printf(“%d\t”, arr[i]);
}
return 0;
Output:
ni
U
Enter size of array: 5
Unit-1.3: Strings
Notes
ity
1.3.1 Character String in C
In C programming, a string is a sequence of characters terminated with a null
character \0.
rs
When the compiler encounters a sequence of characters enclosed in the double
quotation marks, it appends a null character \0 at the end by default.
c s t r i n g \0
ve
Here is how you can declare strings:
char s[5];
a b c d \0
Arrays and strings are second-class citizens in C; they do not support the
assignment operator once it is declared.
m
●● strcpy : strcpy copies a string, including the null character terminator from
the source string to the destination. This function returns a pointer to the
destination string.
(c
●● strcmp : Two strings are compred with this function. If the first string is greater
Notes than the second, it returns a number greater than zero. If the second string is
ity
greater, it returns a number less than zero. If the strings are equal, it returns 0.
●● strlen : This function returns the length of a string, not counting the null
character at the end. That is, it returns the character count of the string,
without the terminator.
We can use the scanf() function to read a string.
rs
The scanf() function reads the sequence of characters until it encounters
whitespace (space, newline, tab, etc.).
ve
#include <stdio.h>
int main()
char name[20];
scanf(“%s”, name);
ni
printf(“Your name is %s.”, name);
U
return 0;
}
Output:
You can use the fgets() function to read a line of string. You can use puts()
m
to display the string. The puts() function is used to write a line or string to the output
stream. It prints the passed string with a newline and returns an integer value.
Example of fgets():
)A
#include <stdio.h>
#define MAX 15
int main()
char buf[MAX];
(c
ity
return 0;
}
Output:
rs
The string is: Learning C
Example of puts():
#include<stdio.h>
int main()
ve
{
//string initialization
ni
char str2[10] = “Language”;
puts(str1);
}
Output:
C
ity
Language
declaration methods produce similar results because each tells the compiler that an
integer pointer is going to be received. Similarly, you can pass multi-dimensional arrays
as formal parameters.
Example:
#include <stdio.h>
int main() {
ity
result = calculateSum(age);
return 0;
rs
float calculateSum(float age[]) {
int i;
ve
for( i = 0; i < 6; ++i) {
sum += age[i];
return sum;
Output:
Result = 162.50
ni
U
Example : Passing two-dimensional arrays
#include <stdio.h>
int main()
int num[2][2], a, b;
printf(“Enter 4 numbers:\n”);
m
scanf(“%d”, &num[a][b]);
)A
displayNumbers(num);
return 0;
int i, j;
ity
for (i = 0; i < 2; ++i) {
printf(“%d\t”, num[i][j]);
rs
printf(“\n”);
ve
Output:
Enter 4 numbers:
2345
4
3
5
ni
U
ity
m
)A
(c
ity
1.4.1 Implementing One Dimensional Array
To implement an array, first we need to declare the data type and then declare
array name and mention size of array.
rs
For example: float mark [5];
Here, we declared an array (name of array is mark) of floating-point type and size
is 5 i.e., it can hold 5 floating-point values. It is important to note that the size and type
of an array cannot be changed once it is declared.
ve
A variable can be initialized in its declaration.
ni
separated with commas and enclosed within braces.
For example: int age [5] = {23, 56, 87, 92, 38};
In this declaration, age [0] is initialized to 23, age [1] is initialized to 56, and so on.
U
There must be at least one initial value between braces. If too many initial values are
specified, a syntax error will occur. If the number of initial values is less than the array
size, the remaining array elements will be initialized to zero.
●● Storage: There are lesser non-zero elements than zeros and thus lesser
memory can be used to store only those elements.
m
00304
)A
00570
00000
02600
zeroes in the matrix are of no use in most of the cases. So, instead of storing zeroes
with non-zero elements, we only store non-zero elements. This means storing non-zero
elements with triples- (Row, Column, value).
Sparse Matrix Representations can be done in many ways following are two
common representations: Notes
ity
●● Array representation
●● Linked list representation
rs
#include<stdio.h>
int main()
ve
int i, j, rows, columns, a[10][10], Total = 0;
scanf(“%d”, &a[rows][columns]);
} }
ity
{
m
if(a[rows][columns] == 0)
Total++;
)A
}
Amity Directorate of Distance & Online Education
26 Data Structure Using C
else
Notes
ity
{
printf(“\n The Matrix that you entered is Not a Sparse Matrix “);
return 0;
rs
}
Output:
ve
Enter the Matrix Elements:
00304
00570
00000
02600
ni
The Matrix that you entered is a Sparse Matrix
4. The number of items used by the dynamic array contents is its ______
a) Physical size
b) Capacity
Notes
ity
c) Logical size
d) Random size
5. Array is divided into two parts in ____________
a) Hashed Array Tree
b) Geometric Array
rs
c) Bounded-size dynamic array
d) Sparse Array
6. In which of the following cases dynamic arrays are not preferred?
ve
a) If the size of the array is unknown
b) If the size of the array changes after few iterations
c) If the memory reallocation takes more time i.e. expensive
d) If the array holds less number of elements
7.
ni
Which of the following is not the method to represent Sparse Matrix?
a) Dictionary of Keys
b) Linked List
U
c) Array
d) Heap
8. What will be the output of the following C code?
#include <stdio.h>
ity
}
void main()
{
int a[2][3] = {0};
f(a);
(c
a) 0 3 0 0 0 0
Notes
ity
b) Junk 3 junk junk junk junk
c) Compile time error
d) All junk values
9. What will strcmp() function do?
a) compares the first n characters of the object
rs
b) compares the string
c) undefined function
d) copies the string
ve
10. Which of the following function is correct that finds the length of a string?
a) int xstrlen(char *s)
{
int length=0;
while(*s!=’\0’)
{ length++; s++; }
return (length);
ni
U
}
b) int xstrlen(char s)
{
int length=0;
ity
while(*s!=’\0’)
length++; s++;
return (length);
}
m
while(*s!=’\0’)
length++;
return (length);
}
d) int xstrlen(char *s)
(c
{
int length=0;
while(*s!=’\0’)
Notes
ity
s++;
return (length);
}
Answer key:
rs
1. c, 2. a, 3. b, 4. c, 5. c, 6. d, 7. d, 8. a, 9. b, 10. a
ve
ni
U
ity
m
)A
(c
ity
Structure:
rs
2.1.2 Array Representation of Stack
2.1.3 Operations Associated with Stacks- Push & Pop
2.1.4 Polish expressions
2.1.5 Conversion of infix to postfix
ve
2.1.6 Infix to Prefix (and vice versa),
2.1.7 Application of stacks recursion
2.1.8 Polish expression and their compilation
2.1.9 Conversion of infix expression to prefix and postfix expression
Unit-2.1: Stack
Notes
ity
2.1.1 Definition
Stack is a linear data structure which follows a particular order in which the
operations are performed. The order may be LIFO(Last In First Out) or FILO(First In
Last Out).
rs
Push
ve
Top
Stack is a linear data structure which follows a particular order in which the
operations are performed. The order may be LIFO (Last in First Out) or FILO (First In
Last Out).
●●
ni
Mainly the following three basic operations are performed in the stack:
Push: Adds an item in the stack. If the stack is full, then it is said to be an
Overflow condition.
U
●● 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.
●● Peek or Top: Returns top element of stack.
●● isEmpty: Returns true if stack is empty, else false.
ity
Adding an element into the top of the stack is referred to as push operation. Push
operation involves following two steps.
1. Increment the variable Top so that it can now refer to the next memory location.
)A
(0) (1) (2) (3) (4) (5) (6) (7) (8) (9)
Notes
ity
Array
12 Top
Elements of stack to
12 [12, 08, 21, 33, 18, 40]
be added in the array
12
12 (0) (1) (2) (3) (4) (5) (6) (7) (8) (9)
12
12
Stack
Memory that will be occupied
by the stack elements
rs
2.1.3 Operations Associated with Stacks- Push & Pop
A stack is a simple last-in, first-out (LIFO) data structure. That is, the last data
ve
element stored in a stack is the first data element retrieved from the stack. The common
analogy is a stack of plates in a cafeteria: when you go through the line, you pop the top
plate off the stack; the dish washer (stepping away from reality a bit), pushes a single
clean plate on top of the stack. So a stack supports two basic operations: push and
pop. Some stacks also provide additional operations: size (the number of data elements
currently on the stack) and peek (look at the top element without removing it).
Operation
ni
Based on these operations, the snapshots shown in Figure 3 illustrate the
appearance of a stack as data (characters) are stored in or pushed on to it.
Picture Execution
U
Stack is empty 3
2
1
0 ← sp = 0
ity
st
st
0 A
st
st
The push operation illustrated. Each call to the push function (left column)
pushes a data element on to the stack. The main instruction in the push function is Notes
ity
st [sp++] = data, where “data” is the function argument. The middle column abstractly
illustrates how the stack (the array and the stack pointer) appear after each call to the
push function. The right column breaks the behaviour of the push function in to two
steps.
Similarly, the data (characters) stored in a stack can be retrieved from or popped
rs
off it.
data = pop(); 3 sp = 3 - 1;
return sp[2];
ve
2 C ← sp = 2
1 B
0 A
st
data = pop(); 3 sp = 2 - 1;
ni
2 C return sp[2];
1 B ← sp = 1
0 A
st
U
data = pop(); 3 sp = 1 - 1;
2 C return sp[2];
1 B
0 A ← sp = 0
st
ity
●● Infix form
●● Prefix form
●● Postfix form
)A
3. - (unary negation)
2. */
1. + - (subtraction)
Notes
ity
Thus, high priority corresponds to high number in the table.
Step 2) If the token is an operand, do not stack it. Pass it to the output.
-- Pop the stack until you find a symbol of lower priority number than the current
one. An incoming left parenthesis will be considered to have higher priority than any
rs
other symbol. A left parenthesis on the stack will not be removed unless an incoming
right parenthesis is found.
ve
--Stack the current symbol.
-- If a right parenthesis is the current symbol, pop the stack down to (and
including) the first left parenthesis. Write all the symbols except the left parenthesis to
the output (i.e. write the operators to the output).
-- After the last token is read, pop the remainder of the stack and write any symbol
Move
ni
(except left parenthesis) to output.
2 * * A
3 ( (* A
ity
4 B (* AB
5 + +(* AB
6 C +(* ABC
7 ) * ABC+
8 * * ABC+*
m
9 D * ABC+*D
10 empty
)A
Step 2. Scan A from right to left and repeat step 3 to 6 for each element of A until
the STACK is empty.
a. Repeatedly pop from STACK and add to B, each operator (on the top of STACK)
which has same or higher precedence than the operator. Notes
ity
b. Add operator to STACK.
Step 6. If left parenthesis is encountered then
a. Repeatedly pop from the STACK and add to B (each operator on top of stack
until a left parenthesis is encountered)
rs
b. Remove the left parenthesis.
Step 7. Exit
Expression = (A+B^C)*D+E^5
ve
Step 1. Reverse the infix expression.
5^E+D*)C^B+A(
5^E+D*(C^B+A)
A+(B*C-(D/E-F)*G)*H
E+D*(C^B+A) ^ 5 Push
ity
+D*(C^B+A) ^ 5E Push
ity
“Recursion” is technique of solving any problem by calling same function again
and again until some breaking (base) condition where recursion stops, and it starts
calculating the solution from there on. By using stack, many programming languages
implement recursion. When a function calls another function, the value of all variables
need to be saved, hence, when the called function returns, the values are exactly as
they were left. We know when a recursive function calls itself, it is a series of nested
rs
functions. It may not have any local variables, but always have a return address and the
stack facilitates this. To store and restore the recursive function and arguments, stack is
used.
ve
int fact(int n){
if(n == 0){
return 1;
}
ni
return (n * fact(n-1)); //function fact() is calling itself
U
2.1.8 Polish Expression and Their Compilation
Notation is the way to write arithmetic expression. The name comes from the
Polish mathematician/logician Lukasiewicz, who introduced it. There are 3 different
ways to write an algebraic expressions:
ity
●● Infix form
●● Prefix form
●● Postfix form
a×b × ab ab ×
m
a+b×c +a × bc abc × +
(a + b) × c × + abc ab + c ×
Infix form
In infix form, the operators are used in between operands. Though it is easy for
human to read and understand this form easily but the same is not true for computing
device.
(c
For examples
(3 * 7)
((1 + 3) * 2)
Notes
ity
((1 + 3) * ( 2 - 3))
rs
understanding, just think of an infix notation, (a+b) and if the same expression we want
to write in prefix notation then it would be like +ab.
ve
(* 3 7) or simply * 3 7
(* ( + 1 3) 2) or simply * + 1 3 2
( * ( + 1 3) ( - 2 3)) or simply * + 1 3 - 2 3
ni
In postfix form, as the name suggests, the operator is post fixed or lies after the two
operands. For better understanding, just think of an infix notation, (a+b) and if the same
expression we want to write in postfix form, then it would be like ab+
U
More 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 - *
ity
In this case, we have operator’s stack, output’s stack and one input string.
m
Operator’s stack works as FILO (First In Last Out). Output’s stack works as FIFO (First
In First Out).
ity
) ) -
) )) -
T )) T
- ))- T
rs
S ))- ST
( ) -ST
/ )/ -ST
ve
) )/) -ST
R )/) R-ST
* )/)* R-ST
Q )/)* QR-ST
ni
( )/ *QR-ST
+ )+ /*QR-ST
P )+ P/*QR-ST
U
( Empty +P/*QR-ST
In this case, we use the stacks to convert infix to postfix. We have operator’s stack,
output’s stack and one input string. Operator’s stack works as FILO (First In Last Out).
Output’s stack works as FIFO (First In First Out).
●● If the character is opening round bracket ( ‘(‘ ), push it into operator’s stack.
●● If the character is closing round bracket ( ‘)’ ), pop out operators from
operator’s stack until we find an opening bracket (‘(‘ ).
Amity Directorate of Distance & Online Education
Data Structure Using C 39
●● Now pop out all the remaining operators from the operator’s stack and push
into output stack. Notes
ity
Infix expression: (A/(B-C)*D+E)
( ( -
A ( A
rs
/ (/ A
( (/( A
B (/( AB
ve
- (/(- AB
C (/(- ABC
) (/ ABC-
* (* ABC-/
E
(*
(+
(+
ni
ABC-/D
ABC-/D*
ABC-/D*E
U
) Empty ABC-/D*E+
Tower of Hanoi is a mathematical puzzle where we have three rods and n disks.
The objective of the puzzle is to move the entire stack to another rod, obeying the
following simple rules:
it on top of another stack i.e., a disk can only be moved if it is the uppermost
disk on a stack.
3. No disk may be placed on top of a smaller disk.
)A
ity
Shift ‘n-1’ disks from ‘B’ to ‘C’.
3 Disk 1
A B C A B C
2 3 4
rs
A B C A B C A B C
5 6 7
ve
A B C A B C A B C
Example:
#include <stdio.h>
int num;
scanf(“%d”, &num);
return 0;
m
{
)A
if (num == 1)
return;
(c
printf(“\n Move disk %d from peg %c to peg %c”, num, frompeg, topeg);
Notes
ity
towers(num - 1, auxpeg, topeg, frompeg);
Output:
rs
The sequence of moves involved in the Tower of Hanoi are :
ve
Move disk 1 from peg C to peg B
ni
U
ity
m
)A
(c
Unit-2.2: Queue
Notes
ity
2.2.1 Definition
Queue is an abstract data structure, somewhat like Stacks. Unlike stacks, a queue
is open at both its ends. One end is always used to insert data (enqueue) and the other
is used to remove data (dequeue). Queue follows First-In-First-Out methodology, i.e.,
the data item stored first will be accessed first.
rs
A Queue is a linear structure which follows a particular order in which the
operations are performed. The order is First In First Out (FIFO). A good example of a
queue is any queue of consumers for a resource where the consumer that came first
is served first. The difference between stacks and queues is in removing. In a stack
ve
we remove the item the most recently added; in a queue, we remove the item the least
recently added.
Queue
Insertion and Deletion
happen on different ends
Enqueue
ni Rear
Queue
Notes
FRONT
REAR -1 0 1 2 3 4
ity
empty queue
-1 0 1 2 3 4
1
queue the first element
rs
-1 0 1 2 3 4
1 2
enqueue
ve
-1 0 1 2 3 4
1 2 3 4 5
enqueue
-1 0 1 2 3 4
2 3 4 5
ni
dequeue
-1 0 1 2 3 4
5
dequeue the last element
U
-1 0 1 2 3 4
5
empty queue
Enqueue Operation
●● check if the queue is full
●● for the first element, set the value of FRONT to 0
●● increase the REAR index by 1
m
Dequeue Operation
●● check if the queue is empty
)A
●● peek() − Gets the element at the front of the queue without removing it.
●● isfull() − Checks if the queue is full.
ity
2.2.4 Priority Queue
Priority Queue is an extension of queue with following properties.
rs
3. If two elements have the same priority, they are served according to their order
in the queue.
A typical priority queue supports following operations.
ve
getHighestPriority(): Returns the highest priority item.
ni
Element with the
highest priority 9
4
5
3
Dequeue
U
2
1
Enqueue
0
)A
9
1 2
3 5
3 4 5 6
(c
1 4 2 7
Heapify the tree.
0
Notes
ity
9
1 2
3 7
3 4 5 6
rs
1 4 2 5
Algorithm for insertion of an element into priority queue (max-heap)
If there is no node,
ve
create a newNode.
insert the newNode at the end (last node from left to right.)
9
1 2
ity
3 7
3 4 5 6
1 4 2 5
m
9
1 2
5 7
3 4 5 6
(c
1 4 2 3
Remove the last element.
0
Notes
ity
9
1 2
5 7
3 4 5
rs
6
1 4 2
3
Heapify the tree.
ve
0
9
1 2
5 7
3
1 ni 4
4
5
2
U
Algorithm for deletion of an element in the priority queue (max-heap)
remove noteToBeDeleted
1) CPU Scheduling
m
#include <stdio.h>
#include <stdlib.h>
#define MAX 5
void insert_by_priority(int);
(c
void delete_by_priority(int);
void create();
void check(int);
Notes
ity
void display_pqueue();
int pri_que[MAX];
void main()
rs
{
int n, ch;
ve
printf(“\n2 - Delete an element from queue”);
printf(“\n4 - Exit”);
create();
while (1)
switch (ch)
{
ity
case 1:
scanf(“%d”,&n);
insert_by_priority(n);
m
break;
case 2:
scanf(“%d”,&n);
delete_by_priority(n);
break;
case 3:
display_pqueue();
(c
break;
case 4:
exit(0);
Notes
ity
default:
rs
}
void create()
ve
{
return;
ity
front++;
m
rear++;
pri_que[rear] = data;
return;
)A
else
check(data);
rear++;
}
(c
{
Notes
ity
int i,j;
rs
{
ve
pri_que[j] = pri_que[j - 1];
pri_que[i] = data;
return;
}
}
pri_que[i] = data;
ni
U
}
int i;
{
m
return;
}
)A
if (data == pri_que[i])
}
Notes
ity
pri_que[i] = -99;
rear--;
if (rear == -1)
front = -1;
rs
return;
ve
printf(“\n%d Not found in queue to delete”, data);
void display_pqueue()
ni
if ((front == -1) && (rear == -1))
{
U
printf(“\nQueue is empty”);
return;
}
ity
printf(“ %d “, pri_que[front]);
}
m
front = 0;
Output:
)A
4 - Exit
ity
Enter your choice: 1
25 10 5
rs
Enter your choice: 2
ve
25 5
ni
FIFO(First In First Out), but instead of ending the queue at the last position, it again
starts from the first position after the last, hence making the queue behave like a
circular data structure.
In case of a circular queue, head pointer will always point to the front of the queue,
U
and tail pointer will always point to the end of the queue.
Initially, the head and the tail pointers will be pointing to the same location, this
would mean that the queue is empty.
Head
ity
Tail
New data is always added to the location pointed by the tail pointer, and once the
data is added, tail pointer is incremented to point to the next available location.
)A
Circular Queue works by the process of circular increment i.e. when we try to
increment the pointer and we reach the end of the queue, we start from the beginning of
the queue.
Here, the circular increment is performed by modulo division with the queue size.
That is,
2.2.6 Deque
Notes
ity
Deque or Double Ended Queue is a generalized version of Queue data structure
that allows insert and delete at both ends.
Operations on Deque:
rs
insertLast(): Adds an item at the rear of Deque.
ve
Applications of Deque:
Since Deque supports both stack and queue operations, it can be used as both.
The Deque data structure supports clockwise and anticlockwise rotations in O(1) time
which can be useful in certain applications.
#include <stdio.h>
#define size 5
ni
U
void insertq(int[], int);
void deleteq(int[]);
void display(int[]);
ity
int front = - 1;
int rear = - 1;
int main()
int n, ch;
m
int queue[size];
do
)A
scanf(“%d”, &ch);
switch (ch)
(c
case 1:
ity
scanf(“%d”, &n);
insertq(queue, n);
break;
case 2:
rs
deleteq(queue);
break;
case 3:
ve
display(queue);
break;
{
ni
U
if ((front == 0 && rear == size - 1) || (front == rear + 1))
printf(“queue is full”);
ity
return;
else if (rear == - 1)
{
m
rear++;
front++;
}
)A
rear = 0;
else
(c
rear++;
}
Notes
ity
queue[rear] = item;
rs
int i;
printf(“\n”);
ve
{
printf(“%d “, queue[i]);
ni
for (i = 0; i <= rear; i++)
printf(“%d “, queue[i]);
U
}
else
{
ity
printf(“%d “, queue[i]);
}
m
if (front == - 1)
)A
{
(c
front = - 1;
Notes
ity
rear = - 1;
else
rs
printf(“\n %d deleted”, queue[front]);
front++;
ve
}
d) -18
3. When the user tries to delete the element from the empty stack then the condition
is said to be a ____
a) Underflow
m
b) Garbage collection
c) Overflow
d) None of the above
4. Entries in a stack are “ordered”. What is the meaning of this statement?
)A
5. If the size of the stack is 10 and we try to add the 11th element in the stack then
the condition is known as___
a) Underflow
b) Garbage collection
Notes
ity
c) Overflow
d) None of the above
6. Which one of the following is not the application of the stack data structure
a) String reversal
b) Recursion
rs
c) Backtracking
d) Asynchronous data transfer
7. Which data structure is mainly used for implementing the recursive algorithm?
ve
a) Queue
b) Stack
c) Binary tree
d) Linked list
8.
ni
Which data structure is required to convert the infix to prefix notation?
a) Stack
b) Linked list
U
c) Binary tree
d) Queue
9. Which of the following is the prefix form of A+B*C?
a) A+(BC*)
ity
b) +AB*C
c) ABC+*
d) +A*BC
10. Which of the following is not the correct statement for a stack data structure?
m
Answer key:
1. c, 2. d, 3. a, 4. d, 5. c, 6. d, 7. b, 8. a, 9. d, 10. b
(c
ity
Structure:
rs
3.1.2 Traversing, Searching, Insertion, Deletion from linked list
3.1.3 Garbage collection and compaction
ve
3.2.1 Introduction to doubly linked list
3.2.2 Operations on doubly linked list
ity
3.1.1 Introduction and Representation of linked lists in Memory
Linked list is a linear data structure. Linked list is defined as collection of objects
called nodes and nodes are stored randomly in memory. A node contains two fields,
one field contains data and the other field contains address of the node. The last node
points to NULL. Unlike array here the list is not contiguous in memory. Empty node
rs
cannot be present here.
Singly Linked is collection of ordered set of nodes. According to the need of the
program, the number of nodes varies. Linked list components are not stored at a
contiguous location. The elements are linked using pointers. Singly link list can traverse
ve
only in one direction.
Head
A B C D NULL
Data Next
ni
Fig 3.1 Singly link list
In the above figure, the arrow represents the link and the data part contains values.
A linked list is characterized by a pointer to the first node of the linked list. In the figure,
U
next defines the address of the next node. The first node is termed the head. If the
linked list is empty, then the value of head is NULL.
The list is not necessary to be contiguously present in the memory. The node
can reside anyplace in the memory and linked together to make a list. This achieves
ity
optimized utilization of space. List size is limited to the memory size and does not
require to be declared in advance. Empty node cannot be appear in the linked list. We
can store values of primitive types or objects in the singly linked list. Data part of the
node stores genuine information that is to be epitomized by the node while the link part
of the node stores the address of its current successor.
One way chain or singly linked list can be traversed only in one direction. In
m
other words, we can say that each node includes only next pointer, therefore we
cannot traverse the list in the reverse direction. Let us take one example for better
understanding. In below figure we can see a singly linked list which shows the marks
obtained by the student in three subjects.
)A
Head
23 34 90
In the above figure, the arrow symbolizes the links which hold the address of next
(c
node. The last node in the list is pinpointed by the null pointer which is present in the
address part of the last node. We can have as many elements as possible we require,
in the data part of the list.
ity
Operations on Singly Linked List:
Node Creation:
struct node
rs
int data;
};
ve
struct node *head, *ptr;
Insertion
The insertion into a singly linked list can be performed at different positions. Based
on the position of the new node being inserted, the insertion is categorized into the
following categories.
Insertion at beginning
ni
By this process we can insert any element at the beginning of the list. For doing
U
this, we need to make the new node as the head of the list.
Steps:
Example:
newNode->data = 4;
)A
newNode->next = head;
head = newNode;
By this process, we can insert a node at the end of the list. The new node has to
be added after the last node. Let us think of a link list like 10->20->30->40 and now we
(c
want to add a new node 50 at the end of the list, so the list will become 10->20->30-
>40->50. For doing this, we have to traverse the list till the end and we need to make
change of next of last node to new node.
Steps:
Notes
ity
●● Allocate memory for new node
●● Store data
●● Traverse to last node
●● Change next of last node to recently created node
Example:
rs
struct node *newNode;
newNode->data = 4;
ve
newNode->next = NULL;
while(temp->next != NULL){
temp = temp->next;
temp->next = newNode; ni
U
This process contains insertion at the last of the linked list. The new node can be
inserted as the only node in the list or it can be inserted as the last one. Different logics
we have to implemented for each scenario.
By this process, we can insert a node after a specific node in the list. We already
ity
Steps:
newNode->data = 4;
if(temp->next != NULL) {
(c
temp = temp->next;
} }
newNode->next = temp->next;
Notes
ity
temp->next = newNode;
Traversing
rs
Example:
ptr = head;
while (ptr!=NULL)
ve
{
Algorithm
●●
●●
STEP 1: SET PTR = HEAD
STEP 2: IF PTR = NULL
WRITE “EMPTY LIST”
ni
U
GOTO STEP 7
END OF IF
●● STEP 7: EXIT
Example:
m
#include<stdio.h>
#include<stdlib.h>
void create(int);
)A
void traverse();
struct node
int data;
(c
};
void main ()
Notes
ity
{
int choice,item;
do
rs
printf(“\n1.Append List\n2.Traverse\n3.Exit\n4.Enter your choice\n”);
scanf(“%d”,&choice);
switch(choice)
ve
{
case 1:
scanf(“%d”,&item);
create(item);
break;
case 2:
ni
U
traverse();
break;
case 3:
ity
exit(0);
break;
default:
}while(choice != 3);
}
)A
if(ptr == NULL)
{
(c
printf(“\nOVERFLOW\n”);
else
Notes
ity
{
ptr->data = item;
ptr->next = head;
head = ptr;
rs
printf(“\nNode inserted\n”);
ve
void traverse()
ptr = head;
if(ptr == NULL)
printf(“Empty list..”);
ni
U
}
else
{
ity
while (ptr!=NULL)
printf(“\n%d”,ptr->data);
m
}
)A
Output:
1. Append List
2. Traverse
3. Exit
(c
100
Notes
ity
Node inserted
1. Append List
2. Traverse
3. Exit
4. Enter your choice
rs
1
200
ve
Node inserted
1. Append List
2. Traverse
3. Exit
4. Enter your choice
1
Node inserted
1. Append List
ity
2. Traverse
3. Exit
4. Enter your choice
2
m
300
200
)A
100
1. Append List
2. Traverse
3. Exit
4. Enter your choice
(c
Deletion
Like insertion, the Deletion of a node from a singly linked list can be achieved at
different positions. Based on the position of the node being deleted, the operation is Notes
ity
classified into the following categories.
Deletion at beginning
By this process, deletion of a node from the beginning of the list can be done.
This is the easiest operation among all. It just requires a few adjustments in the node
pointers.
rs
●● Point head to the second node
head = head->next;
ve
By this process we can delete the last node of the list. The list can either be empty
or full. Different logic is implemented for the different scenarios.
Steps:
while(temp->next->next!=NULL){ ni
U
temp = temp->next;
temp->next = NULL;
By this process we can delete a node after a specified node in the list. we require
to skip the desired number of nodes to reach the node after which the node will be
deleted. For doing so we need to traverse through the list.
Steps:
m
if(temp->next!=NULL) {
)A
temp = temp->next;
temp->next = temp->next->next;
(c
Searching
While searching, we need to match each element of the list with the given element.
If the element is discovered on any of the location then location of that element is
ity
Example:
#include<stdio.h>
#include<stdlib.h>
struct node
rs
{ int data;
};
ve
struct node *head;
void otherinsert();
void begin_delete();
void last_delete();
void other_delete();
ni
U
void display();
void search();
void main ()
ity
while(choice != 9)
scanf(“\n%d”,&choice);
switch(choice)
case 1:
(c
begininsert();
break;
case 2:
lastinsert();
Notes
ity
break;
case 3:
otherinsert();
break;
rs
case 4:
begin_delete();
break;
ve
case 5:
last_delete();
break;
case 6:
other_delete();
break;
case 7:
ni
U
search();
break;
case 8:
ity
display();
break;
case 9:
exit(0);
m
break;
default:
} } }
void begininsert()
int item;
(c
if(ptr == NULL)
{ printf(“\nOVERFLOW”);
Notes
ity
}
else
{ printf(“\nEnter value\n”);
scanf(“%d”,&item);
rs
ptr->data = item;
ptr->next = head;
head = ptr;
ve
printf(“\nNode inserted”);
} }
void lastinsert()
int item;
ni
ptr = (struct node*)malloc(sizeof(struct node));
U
if(ptr == NULL)
{ printf(“\nOVERFLOW”);
}
ity
else
scanf(“%d”,&item);
ptr->data = item;
m
if(head == NULL)
head = ptr;
)A
printf(“\nNode inserted”);
else
temp = head;
(c
ity
}
temp->next = ptr;
ptr->next = NULL;
printf(“\nNode inserted”);
rs
} } }
void otherinsert()
ve
int i,loc,item;
if(ptr == NULL)
else
printf(“\nOVERFLOW”);
ni
U
{
scanf(“%d”,&item);
ity
ptr->data = item;
scanf(“\n%d”,&loc);
temp=head;
m
for(i=0;i<loc;i++)
temp = temp->next;
)A
if(temp == NULL)
{ printf(“\ncan’t insert\n”);
return;
} }
printf(“\nNode inserted”);
}
Notes
ity
}
void begin_delete()
rs
if(head == NULL)
printf(“\nList is empty.\n”);
ve
}
else
ptr = head;
head = ptr->next;
free(ptr);
ni
printf(“\nNode deleted from the beginning.\n”);
U
}
void last_delete()
ity
if(head == NULL)
{
m
printf(“\nlist is empty”);
head = NULL;
free(head);
}
(c
else
ptr = head;
Notes
ity
while(ptr->next != NULL)
ptr1 = ptr;
rs
}
ptr1->next = NULL;
free(ptr);
ve
printf(“\nDeleted Node from the last.\n”);
} }
void other_delete()
\n”);
int loc,i;
ni
printf(“\n Enter the location of the node after which you want to perform deletion
U
scanf(“%d”,&loc);
ptr=head;
for(i=0;i<loc;i++)
{
ity
ptr1 = ptr;
ptr = ptr->next;
if(ptr == NULL)
{
m
printf(“\nCan’t delete”);
return;
} }
)A
free(ptr);
}
(c
void search()
int item,i=0,flag;
Notes
ity
ptr = head;
if(ptr == NULL)
printf(“\nEmpty List\n”);
rs
}
else
ve
printf(“\nEnter item which you want to search?\n”);
scanf(“%d”,&item);
while (ptr!=NULL)
if(ptr->data == item)
{
ni
printf(“item found at location %d “,i+1);
U
flag=0;
else
ity
flag=1;
i++;
m
if(flag==1)
)A
} } }
void display()
{
(c
ptr = head;
Notes
ity
if(ptr == NULL)
printf(“Nothing to print”);
rs
else
ve
while (ptr!=NULL)
printf(“\n%d”,ptr->data);
} } }
ni
After compiling the above program, the below output will be shown
Output:
U
Choose one option from the following list
1. Insert at beginning
2. Insert at last
3. Insert at any other location
ity
8. Display list
9. Exit
Enter your choice:1
)A
Enter value
10
Node inserted
1. Insert at beginning
2. Insert at last
3. Insert at any other location
ity
5. Delete node from last
6. Delete node after specified location
7. Search for an element
8. Display list
9. Exit
rs
Enter your choice:1
Enter value
20
ve
Node inserted
1. Insert at beginning
2. Insert at last
ni
3. Insert at any other location
4. Delete node from beginning
5. Delete node from last
U
6. Delete node after specified location
7. Search for an element
8. Display list
ity
9. Exit
Enter your choice:1
Enter value
30
Node inserted
m
1. Insert at beginning
2. Insert at last
)A
9. Exit
Notes
ity
Enter your choice:1
Enter value
40
Node inserted
rs
Choose one option from the following list
1. Insert at beginning
2. Insert at last
3. Insert at any other location
ve
4. Delete node from beginning
5. Delete node from last
6. Delete node after specified location
7. Search for an element
8. Display list
9. Exit
Enter your choice:8
ni
U
The list is:
40
30
ity
20
10
1. Insert at beginning
m
2. Insert at last
3. Insert at any other location
4. Delete node from beginning
)A
Enter value:
60
Amity Directorate of Distance & Online Education
76 Data Structure Using C
Node inserted
Notes
ity
Choose one option from the following list
1. Insert at beginning
2. Insert at last
3. Insert at any other location
4. Delete node from beginning
rs
5. Delete node from last
6. Delete node after specified location
7. Search for an element
ve
8. Display list
9. Exit
Enter your choice:8
Enter value
40
30
20
ni
U
10
50
1. Insert at beginning
2. Insert at last
3. Insert at any other location
4. Delete node from beginning
m
9. Exit
Enter your choice:4
1. Insert at beginning
2. Insert at last
ity
4. Delete node from beginning
5. Delete node from last
6. Delete node after specified location
7. Search for an element
8. Display list
rs
9. Exit
Enter your choice:8
ve
30
20
10
50
1. Insert at beginning
2. Insert at last
ni
U
3. Insert at any other location
4. Delete node from beginning
5. Delete node from last
ity
When a node is deleted, some memory space becomes reusable. This memory
space should be obtainable for future use. One way to do this is to instantly insert the
free space into availability list. But this method may be time exhausting for the operating
(c
through all the lists and tags all those cells which are currently being utilized. In the
Notes second step, the OS goes through all the lists again and collects untagged space and
ity
adds this collected space to availability list. The garbage collection may happen when
small amount of free space is left in the system or no free space is left in the system or
when CPU is idle and has time to do the garbage collection.
Garbage collector is the magic component that makes the illusion of infinite
memory possible. It typically comprises of two semi-independent components known as
rs
mutator and collector.
Mutator
Usually, all components of a language runtime that are accountable for executing
application code, allocating/de-allocating new objects, and managing execution
ve
contexts get considered as the mutators. Most acceptably large programs have more
than one mutator threads. Precise number of mutator threads is generally irrelevant to
the garbage collection approaches.
Collector
The collector executes the garbage collection code. It realizes the garbage (read:
ni
unreachable) objects and reclaims their storage. In concurrent GCs, there may be
more than one collector threads. Exact number of collectors is mostly inappropriate
to the approaches that we are going to discuss. Most GCs suggest control over the
behaviours of collectors through configuration settings.
U
ity
m
)A
(c
ity
3.2.1 Introduction to Doubly Linked List
An extra pointer has been added to implement a Doubly Linked List, usually termed
as previous pointer, together with next pointer and data which are there in singly linked
list.
rs
Head
Next Next Next Next
NULL
NULL A B C D
Prev Prev Prev Prev
ve
Below is the process of creating node in Doubly Link List.
struct Node {
int data;
}; ni
struct Node* next; // Pointer to next node in Doubly Link List
to be deleted is given.
3. We can swiftly insert a new node before a given node.
In singly linked list, to delete a node, pointer to the previous node is needed. To
get this previous node, the list has to be traversed. In Doubly Link List, we can get the
earlier node using previous pointer itself.
m
The operations of doubly link list includes insertion, deletion and display
operations. Node can be added in different ways.
(c
The new node is all the time added before the head of the given Linked List. And
recently added node becomes the new head of Doubly Link List.
Head
Notes Next Next Next Next
NULL
ity
NULL A B C D
Prev Prev Prev Prev
Next
E
NULL
Prev
rs
For example if the given Linked List is 20->10->1->5->2 and we include an item 4
at the front, then the Linked List becomes 4->20->10->1->5->2. We need to call push()
function which adds at the front of the list. The push() must receive a pointer to the
head pointer, because push must change the head pointer to point to the new node
ve
Steps:
1. allocate node
2. insert the data
3. Make next of new node as head and previous as NULL
4. change prev of head node to new node
5. move the head to point to the new node
Insertion of a node after a specified node
ni
U
By this way the new node can be inserted after a specified node.
Head
Next Next Next Next
NULL
NULL A B C D
Prev Prev Prev Prev
ity
Next Prev
E
Prev Next
Steps:
m
When we insert a node, the new node is always added after the last node. We
need to traverse the list in order to change the nest of last node to new node.
Notes
Head
Next Next Next Next
ity
NULL
NULL A B C D
Prev Prev Prev Prev
Prev Next
NULL
E
rs
Steps
Let the pointer to this given node be next_node and the data of the new node to be
added as new_data.
1. Check if the next_node is NULL or not. If it’s NULL, return from the function
ve
because any new node cannot be added before a NULL
2. Allocate memory for the new node, let it be called new_node
3. Set new_node->data = new_data
4. Set the previous pointer of this new_node as the previous node of the next_
ni
node, new_node->prev = next_node->prev
5. Set the previous pointer of the next_node as the new_node, next_node->prev
= new_node
6. Set the next pointer of this new_node as the next_node, new_node->next =
U
next_node;
7. If the previous node of the new_node is not NULL, then set the next pointer of
this previous node as new_node, new_node->prev->next = new_node
8. Else, if the prev of new_node is NULL, it will be the new head node. So, make
ity
(*head_ref) = new_node.
Deletion
Deletion can be done at three places. Deletion at beginning, deletion at middle and
deletion at end. All the cases can be done in two steps if the pointer of the node to be
deleted and the head pointer is known.
m
Steps:
1. If we want to delete the first node then we need to make the second node as
head node.
)A
2. If a node is deleted then connect the next node and previous node of the deleted
node.
Let us understand the deletion process with the help of few pictures.
Next
Null
pointer
Start
2 45 3 1
(c
pointer
Previous
pointer
ity
Null
Start
pointer 45 3 1
Previous
pointer
rs
After deletion of middle node:
Null
Start
45 1
ve
pointer
Start
pointer
ni Null
45 Null
U
Fig 3.10 After last node deletion
Searching
While searching, we need to compare each node with the given node and if found
we need to return the location of the item in the list, if not found then null has to be
ity
returned.
Traversing
Traversing simply means visiting each node in order to perform some specific
operation.
Example:
m
#include<stdio.h>
#include<stdlib.h>
)A
struct node
int data;
(c
};
void beginninginsert();
Notes
ity
void lastinsert();
void insertionother();
void deletion_beginning();
void deletion_last();
rs
void deletion_specified();
void display();
void search();
ve
void main ()
while(choice != 9)
ni
printf(“\nChoose one option from the following list:”);
scanf(“\n%d”,&choice);
ity
switch(choice)
case 1:
beginninginsert();
m
break;
case 2:
lastinsert();
)A
break;
case 3:
insertionother();
break;
(c
case 4:
deletion_beginning();
break;
case 5:
Notes
ity
deletion_last();
break;
case 6:
deletion_specified();
rs
break;
case 7:
search();
ve
break;
case 8:
display();
break;
case 9:
exit(0);
break;
ni
U
default:
} } }
ity
void beginninginsert()
int item;
m
if(ptr == NULL)
{
)A
printf(“\nOVERFLOW”);
else
scanf(“%d”,&item);
if(head==NULL)
{
Notes
ity
ptr->next = NULL;
ptr->prev=NULL;
ptr->data=item;
head=ptr;
rs
}
else
ve
ptr->data=item;
ptr->prev=NULL;
ptr->next = head;
head->prev=ptr;
}
head=ptr;
printf(“\nNode inserted\n”);
ni
U
}}
void lastinsert()
{
ity
int item;
if(ptr == NULL)
m
printf(“\nOVERFLOW”);
}
)A
else
printf(“\nEnter value:”);
scanf(“%d”,&item);
ptr->data=item;
(c
if(head == NULL)
ptr->next = NULL;
Notes
ity
ptr->prev = NULL;
head = ptr;
else
rs
temp = head;
while(temp->next!=NULL)
ve
temp = temp->next;
temp->next = ptr;
ni
ptr ->prev=temp;
ptr->next = NULL;
} }
U
printf(“\nNode inserted\n”);
void insertionother()
{
ity
int item,loc,i;
if(ptr == NULL)
m
printf(“\n OVERFLOW”);
}
)A
else
temp=head;
scanf(“%d”,&loc);
for(i=0;i<loc;i++)
temp = temp->next;
Notes
ity
if(temp == NULL)
return;
} }
rs
printf(“Enter value:”);
scanf(“%d”,&item);
ptr->data = item;
ve
ptr->next = temp->next;
temp->next = ptr;
ni
temp->next->prev=ptr;
printf(“\nNode inserted\n”);
} }
U
void deletion_beginning()
if(head == NULL)
ity
printf(“\n UNDERFLOW”);
head = NULL;
free(head);
)A
printf(“\nNode deleted\n”);
else
{
(c
ptr = head;
free(ptr);
Notes
ity
printf(“\nNode deleted\n”);
} }
void deletion_last()
rs
if(head == NULL)
printf(“\n UNDERFLOW”);
ve
}
ni
head = NULL;
free(head);
printf(“\nNode deleted\n”);
U
}
else
ptr = head;
ity
if(ptr->next != NULL)
}
m
free(ptr);
printf(“\nNode deleted\n”);
)A
} }
void deletion_specified()
int val;
printf(“\n Enter the data after which the node is to be deleted : “);
scanf(“%d”, &val);
ptr = head;
Notes
ity
while(ptr -> data != val)
printf(“\nCan’t delete\n”);
rs
}
ve
ptr ->next = NULL;
else
ni
{
free(temp);
printf(“\nNode deleted\n”);
} }
ity
void display()
ptr = head;
while(ptr != NULL)
{
)A
printf(“%d\n”,ptr->data);
ptr=ptr->next;
} }
void search()
(c
int item,i=0,flag;
ptr = head;
Notes
ity
if(ptr == NULL)
printf(“\nEmpty List\n”);
else
rs
{
scanf(“%d”,&item);
ve
while (ptr!=NULL)
if(ptr->data == item)
ni
{
flag=0;
U
break;
else
{
ity
flag=1;
i++;
if(flag==1)
{
)A
Output:
1. Insert in beginning
(c
2. Insert at last
3. Insert at any random location
4. Delete from Beginning
ity
6. Delete the node after the given data
7. Search
8. Display
9. Exit
Enter your choice: 1
rs
Enter Item value: 1
Node inserted
ve
1. Insert in beginning
2. Insert at last
3. Insert at any random location
4. Delete from Beginning
5. Delete from last
6. Delete the node after the given data
7. Search
ni
U
8. Display
9. Exit
Enter your choice: 1
ity
Node inserted
1. Insert in beginning
2. Insert at last
m
Node inserted
ity
1. Insert in beginning
2. Insert at last
3. Insert at any random location
4. Delete from Beginning
5. Delete from last
rs
6. Delete the node after the given data
7. Search
8. Display
ve
9. Exit
Enter your choice: 8
1
ni
Choose one option from the following list :
U
1. Insert in beginning
2. Insert at last
3. Insert at any random location
ity
9. Exit
Enter your choice: 2
Enter value: 89
)A
Node inserted
1. Insert in beginning
2. Insert at last
(c
ity
7. Search
8. Display
9. Exit
Enter your choice: 4
Node deleted
rs
Choose one option from the following list:
1. Insert in beginning
2. Insert at last
ve
3. Insert at any random location
4. Delete from Beginning
5. Delete from last
6. Delete the node after the given data
7. Search
8. Display
9. Exit
ni
U
Enter your choice: 8
1
ity
89
1. Insert in beginning
2. Insert at last
3. Insert at any random location
m
7. Search
8. Display
9. Exit
Enter your choice: 9
(c
ity
3.3.1 Introduction to Circular Linked List
Circular linked list is a linked list where all nodes are connected to form a circle
i.e. the last node is connected to the first node. There is no NULL at the end. A circular
linked list can be a singly circular linked list or doubly circular linked list. To understand
the complete traversal we need to reach the first node again.
rs
Head
2 5 7 8 10
ve
cll
ni
1. Any node can be a starting point. We can traverse the whole list by starting from any
point. We just need to stop when the first visited node is visited again.
2. Useful for implementation of queue. Unlike this implementation, we don’t need to
U
maintain two pointers for front and rear if we use circular linked list. We can maintain
a pointer to the last inserted node and front can always be obtained as next of last.
3. Circular lists are useful in applications to repeatedly go around the list. For example,
when multiple applications are running on a PC, it is common for the operating
system to put the running applications on a list and then to cycle through them,
ity
giving each of them a slice of time to execute, and then making them wait while the
CPU is given to another application. It is convenient for the operating system to use
a circular list so that when it reaches the end of the list it can cycle around to the front
of the list.
In a circular Singly linked list, the last node of the list contains a pointer to the first
node of the list. We can have circular singly linked list as well as circular doubly linked
list.
)A
We traverse a circular singly linked list until we reach the same node where we
started. The circular singly liked list has no beginning and no ending. There is no null
value present in the next part of any of the nodes.
Head
ity
circular list is being stored in the memory. The start or head of the list is pointing to the
element with the index 1 and containing 13 marks in the data part and 4 in the next part.
Which means that it is linked with the node that is being stored at 4th index of the list.
However, due to the fact that we are considering circular linked list in the memory
therefore the last node of the list contains the address of the first node of the list.
rs
start
1
Data Data
1 13 4
ve
2
3
4 15 6
5
6 19 8
7
8 57
Insertion
Insertion at beginning
There are two scenario in which a node can be inserted in circular singly linked
ity
list at beginning. Either the node will be inserted in an empty list or the node is to be
inserted in an already filled list.
Head
temp
old link
m
new link
old link
Firstly, allocate the memory space for the new node by using the malloc method of
C language.
(c
In the first scenario, the condition head == NULL will be true. Since, the list in
Notes which, we are inserting the node is a circular singly linked list, therefore the only node of
ity
the list (which is just inserted into the list) will point to itself only. We also need to make
the head pointer point to this node. This will be done by using the following statements.
If (head == NULL)
rs
head = ptr;
ve
In the second scenario, the condition head == NULL will become false which
means that the list contains at least one node. In this case, we need to traverse the
list in order to reach the last node of the list. This will be done by using the following
statement.
temp = head;
temp = temp->next;
ni
while(temp->next != head)
At the end of the loop, the pointer temp would point to the last node of the list.
U
Since, in a circular singly linked list, the last node of the list contains a pointer to the
first node of the list. Therefore, we need to make the next pointer of the last node point
to the head node of the list and the new node which is being inserted into the list will
be the new head node of the list therefore the next pointer of temp will point to the new
node ptr. Which will be done by using temp -> next = ptr;
ity
Algorithm
Go to step 11
m
[End of if]
ity
Insertion at the end
Steps:
rs
2. make node->next = last->next
3. last-> next = node
4. last = node
ve
Last
Node T
6 8 10
ni
U
Steps:
Last
Node T
12
m
6 8 10
Deletion
Deletion can be done in two ways. Deletion at the beginning and deletion at the
end.
Steps:
1. Define two pointers curr and prev if the node is not empty and initialize the
(c
3. If the node is found, check if it is the only node in the list. If yes, set head = NULL
Notes and free(curr).
ity
4. If the list has more than one node, check if it is the first node of the list ( curr ==
head). If yes, then move prev until it reaches the last node. After prev reaches
the last node, set head = head -> next and prev -> next = head. Delete curr.
5. If curr is not the first node, check if it is the last node in the list (curr -> next ==
head).
rs
6. If curr is the last node. Set prev -> next = head and delete the node curr using
free(curr).
7. If the node to be deleted is neither the first node nor the last node, then set prev
-> next = temp -> next and delete curr.
ve
Searching
We need to compare each element of the node with the given node and return the
location at which the node is present otherwise return null.
Traverse
specific operation.
Example:
ni
Traversing means visiting each and every element of the list to perform some
U
#include<stdio.h>
#include<stdlib.h>
struct node
{
ity
int data;
};
void begindelete();
void lastdelete();
void random_delete();
void display();
void search();
(c
void main ()
ity
while(choice != 7)
rs
printf(“\nEnter your choice:\n”);
scanf(“\n%d”,&choice);
switch(choice)
ve
{
case 1:
begininsert();
ni
break;
case 2:
lastinsert();
U
break;
case 3:
begindelete();
break;
ity
case 4:
lastdelete();
break;
case 5:
m
search();
break;
case 6:
)A
display();
break;
case 7:
exit(0);
(c
break;
default:
ity
}
void begininsert()
rs
{
int item;
ve
ptr = (struct node *)malloc(sizeof(struct node));
if(ptr == NULL)
printf(“\nOVERFLOW”);
else
{
ni
U
printf(“\nEnter the node value:”);
scanf(“%d”,&item);
if(head == NULL)
head = ptr;
else
{
)A
temp = head;
while(temp->next != head)
temp = temp->next;
ptr->next = head;
head = ptr;
printf(“\nNode inserted\n”);
Notes
ity
}
void lastinsert()
rs
struct node *ptr,*temp;
int item;
ve
if(ptr == NULL)
printf(“\nOVERFLOW\n”);
else
printf(“\nEnter Data:”);
ni
U
scanf(“%d”,&item);
ptr->data = item;
if(head == NULL)
ity
head = ptr;
}
m
else
temp = head;
)A
printf(“\nNode inserted\n”);
Notes
ity
}
void begindelete()
rs
struct node *ptr;
if(head == NULL)
ve
printf(“\nUNDERFLOW”);
head = NULL;
free(head);
ni
printf(“\nNode deleted\n”);
U
}
else
{ ptr = head;
ity
ptr->next = head->next;
free(head);
m
head = ptr->next;
printf(“\nNode deleted\n”);
}
)A
void lastdelete()
if(head==NULL)
(c
printf(“\nUNDERFLOW”);
}
Notes
ity
else if (head ->next == head)
head = NULL;
free(head);
rs
printf(“\nNode deleted\n”);
else
ve
{
ptr = head;
}
preptr=ptr;
ptr = ptr->next;
ni
U
preptr->next = ptr -> next;
free(ptr);
printf(“\nNode deleted\n”);
ity
void search()
{
m
int item,i=0,flag=1;
ptr = head;
)A
if(ptr == NULL)
printf(“\nEmpty List\n”);
else
(c
scanf(“%d”,&item);
Notes
ity
if(head ->data == item)
flag=0;
rs
}
else
ve
while (ptr->next != head)
if(ptr->data == item)
flag=0;
break;
ni
printf(“Item found at location %d “,i+1);
U
}
else
{
ity
flag=1;
i++;
if(flag != 0)
)A
}
(c
void display()
ity
ptr=head;
if(head == NULL)
printf(“\nNothing to display.”);
rs
}
else
ve
printf(“\n The list is : \n”);
}
ity
Output:
1. Insert in beginning
2. Insert at end
3. Delete from beginning
4. Delete from end
)A
Node inserted
1. Insert in beginning
Notes
ity
2. Insert at end
3. Delete from beginning
4. Delete from end
5. Search for an element
6. Display
rs
7. Exit
Enter your choice: 1
ve
Node inserted
1. Insert in beginning
2. Insert at end
3. Delete from beginning
4. Delete from end
5. Search for an element
ni
U
6. Display
7. Exit
Enter your choice: 1
ity
Node inserted
1. Insert in beginning
2. Insert at end
m
6. Display
7. Exit
Enter your choice: 4
Node deleted
(c
1. Insert in beginning
2. Insert at end
Amity Directorate of Distance & Online Education
Data Structure Using C 107
ity
4. Delete from end
5. Search for an element
6. Display
7. Exit
Enter your choice: 5
rs
Enter item which you want to search
20
ve
Choose one option from the following list:
1. Insert in beginning
2. Insert at end
3. Delete from beginning
4. Delete from end
5. Search for an element
6. Display
ni
U
7. Exit
Enter your choice: 7
ity
m
)A
(c
ity
A generalized list, A. is a finite sequence of elements. (b.c)): a list of length two; its
first element is the atom a. and its second element is the linear list (b,c). (3) B = (A.A. ())
a list of length three whose first two elements are the list A. and the third element is the
null list. A generalized linked list encompasses structures or elements with everyone
containing its own pointer. It’s generalized if the list can have any deletions, insertions,
and similar inserted effectively into it.
rs
A generalized list L is a finite sequence of n elements (n ≥ 0). The element ei is
either an atom (single element) or another generalized list. The elements ei that are
not atoms, they will be sub-list of L. Suppose L is ((A, B, C), ((D, E), F), G). Here L has
three elements sub-list (A, B, C), sub-list ((D, E), F), and atom G. Again sub-list ((D, E),
ve
F) has two elements one sub-list (D, E) and atom F.
ni
U
ity
m
)A
(c
ity
3.5.1 Applications of Linked List-Polynomial Representation Using
Linked list and Basic Operation
To represent a polynomial of any degree we can use the linked list. If a single
rs
variable is used, the information field node contains two parts. One coefficient of
variable and the other for degree of variable. A polynomial can be represented
in an array or in a linked list by simply storing the coefficient and exponent of each
term. However, for any polynomial operation , such as addition or multiplication of
polynomials , you will find that the linked list representation is more easier to deal with.
ve
It would be very easy to represent the polynomial using a linked list structure, where
each node can hold information pertaining to a single term of the polynomial. Each
node will need to store the variable x, the exponent and the coefficient for each term.
It often does not matter whether the polynomial is in x or y. This information may not
be very crucial for the intended operations on the polynomial. Thus we need to define
a node structure to hold two integers, exp and cof. Compare this representation with
ni
storing the same polynomial using an array structure. In the array we have to have keep
a slot for each exponent of x, thus if we have a polynomial of order 50 but containing
just 6 terms, then a large number of entries will be zero in the array. You will also see
that it would be also easy to manipulate a pair of polynomials if they are represented
U
using linked lists.
Example:
ROOT
3 3 -4 2 2 1 -9 0
In the above example, the external pointer ROOT point to the first node of the
m
linked list. The first node of the linked list contains the data of the variable with highest
degree. First node points to the next node with lower degree of variable. When we need
to do operations such as addition or subtraction then representation of a polynomial
using linked list is beneficial.
)A
Example:
Input:
Output:
5x2-1x1-3x0
Input:
Amity Directorate of Distance & Online Education
110 Data Structure Using C
ity
2nd number = 5x^1 - 5x^0
Output:
rs
List 1 5 2 4 1 2 0 NULL
List 2 5 1 5 0 NULL
Resultant List
ve
5 2 9 1 7 0 NULL
NODE Address of
STRUCTURE Coefficient Power
next node
Example:
#include <stdio.h>
#include <stdlib.h> ni
U
#include <string.h>
struct node
int cof;
ity
int exp;
};
int i, n;
if (scanf(“%d”, &n) != 1)
ity
{
if (ptr == 0)
rs
printf(“enter the coefficient and exponent respectively: “);
ve
ptr->link = NULL;
q = insert(ptr, q);
}
return q;
if (p == NULL)
ity
p = ptr;
else
display(“insert: p = “, p);
m
{
)A
ptr->link = p;
p = ptr;
else
{
(c
temp = p;
ity
temp = temp->link;
b = temp->link;
temp->link = ptr;
rs
ptr->link = b;
ve
return p;
temp = ptr;
ni
U
printf(“%s: “, tag);
{
ity
temp = temp->link;
pad = “ + “;
}
m
putchar(‘\n’);
int main(void)
)A
p1 = create(p1);
p2 = create(p2);
display(“p1”, p1);
display(“p2”, p2);
Notes
ity
return 0;
rs
fprintf(stderr, “%s\n”, tag);
exit(1);
ve
3.5.2 Stack and Queue Implementation Using Linked List
Implement a stack applying single linked list concept. all the single linked list
operations operate based on Stack operations LIFO(last in first out) and with the help
of that knowledge we are going to implement a stack using single linked list. By means
of single linked lists means what we are storing the information in the form of nodes
ni
and we need to follow the stack rules and we need to implement using single linked list
nodes so what are the rules we need to follow in the implementation of a stack a simple
rule that is last in first out and all the operations we should perform so with the help of a
top variable only with the help of top variables are how to insert the elements let’s see
U
A stack can be simply implemented through the linked list. In stack Implementation,
a stack includes a top pointer which is “head” of the stack where pushing and popping
items occurs at the head of the list. first node has null in link field and second node link
have first node address in link field and so on and last node address in “top” pointer.
ity
The main advantage of using linked list over an array is that it is feasible to
implements a stack that can shrink or grow as much as needed. In using array will put
a limitation to the maximum capacity of the array which can lead to stack overflow. Here
each new node will be dynamically allocated, so, overflow is not possible.
Stack Operations:
m
1. push() : Insert the element into linked list nothing but which is the top node of
Stack.
2. pop() : Return top element from the Stack and move the top pointer to the
second node of linked list or Stack.
)A
#include <stdio.h>
int MAXSIZE = 8;
(c
int stack[8];
int isempty() {
Notes
ity
if(top == -1)
return 1;
else
return 0;
rs
}
int isfull() {
if(top == MAXSIZE)
ve
return 1;
else
return 0;
int peek() {
}
return stack[top];
ni
U
int pop() {
int data;
if(!isempty()) {
ity
data = stack[top];
top = top - 1;
return data;
} else {
m
}
)A
if(!isfull()) {
top = top + 1;
stack[top] = data;
} else {
(c
}
Notes
ity
int main() {
push(3);
push(5);
rs
push(9);
push(1);
push(12);
ve
push(15);
printf(“Elements: \n”);
while(!isempty()) {
printf(“%d\n”,data);
ni
U
}
return 0;
If we compile and run the above program, it will produce the following result:
Output:
m
Elements:
15
)A
12
3
(c
In a linked queue, every single node of the queue comprises of two parts i.e. data
Notes part and the link part. Each element of the queue points to its immediate next element
ity
in the memory.
In the linked queue, there are two pointers preserved in the memory i.e. front
pointer and rear pointer. The front pointer contains the address of the starting element
of the queue while the rear pointer comprises the address of the last element of the
queue.
rs
Insertion and deletions are completed at rear and front end respectively. If front and
rear both are NULL, it signifies that the queue is empty. The linked representation of
queue is shown in the following figure.
ve
9 1 7 4
front rear
There are two basic operations which can be employed on the linked queues.
The operations are Insertion and Deletion.The insert operation appends the queue by
the queue.
ni
adding an element to the end of the queue. The new element will be the last element of
Firstly, allocate the memory for the new node ptr by using the following statement.
U
1. Ptr = (struct node *) malloc (sizeof(struct node));
we insert element into an empty queue. In this case, the condition front = NULL
becomes true. Now, the new element will be included as the only element of the queue
and the subsequent pointer of front and rear pointer both, will point to NULL.
ity
if(front == NULL)
front = ptr;
rear = ptr;
m
Algorithm
ELSE
Amity Directorate of Distance & Online Education
Data Structure Using C 117
ity
SET REAR = PTR
[END OF IF]
●● Step 4: END
Deletion
rs
Deletion operation eliminates the element that is first inserted among all the queue
elements. Initially it is required to check either the list is empty or not. The condition
front == NULL becomes true if the list is empty, in this case, we simply write underflow
on the console and make exit.
ve
Else, we will delete the element that is pointed by the pointer front. For this
purpose, copy the node pointed by the front pointer into the pointer ptr. Now, shift the
front pointer, point to its next node and free the node pointed by the node ptr. This is
done by using the following statements.
ni
ptr = front;
free(ptr);
U
Algorithm
Go to Step 5
ity
[END OF IF]
●● Step 5: END
)A
Assignment I
Use the following Node definition for all problems:
(c
struct Node
Item data;
Notes
ity
Node *link;
1. Write a function to concatenate two linked lists. Given lists l1 = (2, 3, 1) and l2 = (4,
5), after return from concatenate(l1,l2) the list l1 should be changed to be l1 = (2, 3,
1, 4, 5). Your function should not change l2 and should not directly link nodes from l1
rs
to l2 (i.e. the nodes inserted into l1 should be copies of the nodes from l2.)
void concatenate(Node*& h1, Node* h2 );
ve
// Postcondition: A copy of list h2 is concatenated (added to the end)
ni
2. Write a function to insert a number into a sorted linked list. Assume the list is sorted
from smallest to largest value. After insertion, the list should still be sorted. Given the
list l1 = (3, 17, 18, 27) and the value 20, on return l1 be the list (3, 17, 18, 20, 27).
U
void insertInOrder(Node*& head_ptr, int value);
3. Write a function to return the median value in a sorted linked list. If the length i of the
list is odd, then the median is the ceiling(i/2) member. For example, given the list (1,
2, 2, 5, 7, 9, 11) as input, your function should return the value 5. If the length of the
m
list is even, then the median is the mean of the i/2 and (i/2)+1 members. Thus, the
median of the sorted list (2, 4, 8, 9) is (4+8)/2. Finally, define the median of an empty
list to be 0.
FILL IN RETURN TYPE listMedian ---- FILL IN ARGUMENTS -------------------
)A
4. Write a function to reverse the nodes in a linked list. Your function should have time
complexity O(n), where n is the length of the list. You should create no new nodes.
void reverse(Node*& head_ptr);
(c
ity
// order.
rs
#include <stdio.h>
#include <stdlib.h>
ve
// A Linked List Node
struct Node
int data;
};
while (ptr)
ptr = ptr->next;
m
printf(“NULL\n”);
}
)A
// Helper function to insert a new node at the beginning of the linked list
newNode->data = data;
(c
newNode->next = *head;
*head = newNode;
}
Notes
ity
// Reverses a given linked list by changing its `.next` pointers and
rs
struct Node* previous = NULL; // the previous pointer
ve
while (current != NULL)
previous = current;
ni
current->next = previous; // fix the current node
U
current = next;
*head = previous;
int main(void)
{
m
// input keys
int keys[] = { 1, 2, 3, 4, 5, 6 };
int n = sizeof(keys)/sizeof(keys[0]);
)A
push(&head, keys[i]);
}
(c
reverse(&head);
printList(head);
return 0;
Notes
ity
}
Questions
1. In a circular linked list
a) Components are all linked together in some sequential manner.
rs
b) There is no beginning and no end.
c) Components are arranged hierarchically.
d) Forward and backward traversal within the list is permitted.
2. Which of the following operations is performed more efficiently by doubly linked list
ve
than by singly linked list?
a) Deleting a node whose location in given
b) Searching of an unsorted list for a given item
c) Inverting a node after the node with given location
3.
d) Traversing a list to process each node
ni
A linear collection of data elements where the linear node is given by means of
pointer is called?
U
a) linked list
b) node list
c) primitive list
d) None of these
ity
d) Binary search
5. Which of these is an application of linked lists?
a) To implement file systems
)A
b) Two pointer
c) Three pointer
d) None
ity
a) To implement file systems
b) For separate chaining in hash-tables
c) To implement non-binary trees
d) Random Access of elements
8. A linear collection of data element given by mean of pointer is called
rs
a) Queue
b) Linked list
c) Graph
ve
d) Stack
9. Which of the following operation is performed more efficiently in doubly linked list?
a) Searching a node at given position
b) Inserting a node at given position
d) None of these
ni
c) Deleting node at given position
Answer key:
1. b, 2. a, 3. a, 4. d, 5. d, 6. b, 7. d, 8. b, 9. c, 10. d
m
)A
(c
ity
Structure:
rs
4.1.2 Basic Terminology
ve
4.2.2 Expression Evaluation
4.2.3 Complete Binary trees
4.2.4 Extended Binary Trees
4.2.5 Traversing Binary Trees
ni
4.2.6 Searching, Insertion and Deletion in Binary Search Trees
Unit-4.4: Graph
ity
4.4.1 Introduction
4.4.2 Graph Theory Terminology
4.4.3 Sequential Representation of Graph (Adjacency and Path Matrix)
4.4.4 Warshall Algorithms
m
ity
4.1.1 Introduction to Trees
Tree is a hierarchical data structure which stores the information naturally in the
form of ladder style. Tree is one of the most effective and advanced data structures. It is
a non-linear data structure compared to arrays, linked lists, stack and queue. It signifies
the nodes connected by edges.
rs
Root A
Subtree Edge
B C
Siblings
ve
Child
Node
Leaf
D E F Node G
ni
The above figure represents structure of a tree. Tree has 2 subtrees. A is a parent
of B and C. B is called a child of A and also parent of D, E, F. Tree is a collection of
elements called Nodes, where each node can have arbitrary number of children.
U
4.1.2 Basic Terminology
Field Description
Root
it. It does not have a parent.
Height of Tree Height of tree represents the height of its root node.
Depth of a node represents the number of edges from the tree’s root
Depth of Node
node to the node.
Degree of
Degree of a node represents a number of children of a node.
Node
(c
ity
4.2.1 Binary Trees and Their Representation
Binary Tree is a unique data structure used for data storage. Binary tree has at
most 2 children. Hence the name binary tree. The topmost node is called root and the
nodes that are under the root node are called its children. The node directly above
another node is called as parent.
rs
Binary Tree is a unique data structure used for data storage reasons . A tree whose
elements have at most 2 children is called a binary tree. Since each element in a binary
tree can have only 2 children, we typically name them the left and right child.
ve
Root
A Level 0
B C Level 1
Child Node H
Sub-tree
I J
Leaf Node
ni Level 3
U
Fig4.2 : Binary tree
1. Data
ity
27
14 35
)A
10 19 31 42
The basic operations that can be completed on a binary search tree data structure,
are the following:
ity
Example:
#include<stdlib.h>
#include<stdio.h>
struct bin_tree {
rs
int data;
};
ve
typedef struct bin_tree node;
ni
node *temp = NULL;
if(!(*tree))
{
U
temp = (node *)malloc(sizeof(node));
temp->data = val;
*tree = temp;
ity
return;
{
m
insert(&(*tree)->left, val);
insert(&(*tree)->right, val);
}
(c
if (tree)
Notes
ity
{
printf(“%d\n”,tree->data);
print_preorder(tree->left);
print_preorder(tree->right);
rs
}
ve
{
if (tree)
print_inorder(tree->left);
printf(“%d\n”,tree->data);
print_inorder(tree->right);
}
ni
U
}
{
ity
if (tree)
print_postorder(tree->left);
print_postorder(tree->right);
m
printf(“%d\n”,tree->data);
}
)A
if (tree)
deltree(tree->left);
(c
deltree(tree->right);
free(tree);
}
Notes
ity
}
if(!(*tree))
rs
{
return NULL;
ve
if(val < (*tree)->data)
search(&((*tree)->left), val);
search(&((*tree)->right), val);
ni
U
}
{
ity
return *tree;
void main()
m
node *root;
node *tmp;
)A
root = NULL;
insert(&root, 9);
insert(&root, 4);
insert(&root, 15);
(c
insert(&root, 6);
insert(&root, 12);
insert(&root, 17);
Notes
ity
insert(&root, 2);
print_preorder(root);
rs
printf(“In Order Display\n”);
print_inorder(root);
ve
print_postorder(root);
if (tmp) {
else
ni
U
}
deltree(root); }
ity
Output:
4
m
15
)A
12
17
In Order Display
4
(c
12
Notes
ity
15
17
rs
6
12
ve
17
15
Searched node=4
ni
Evaluate an expression represented by a String. The expression can contain
parentheses, you can assume parentheses are well-matched. For simplicity, you can
U
assume only binary operations allowed are +, -, *, and /. Arithmetic Expressions can be
written in one of three forms:
Infix Notation: Operators are written between the operands on, e.g. 3+4.
2 3
(c
4 5 6
ity
Select the first element of the list to be the root node. (no. of elements on level-I: 1)
1 1 12 9 5 6 10
Put the second element as a left child of the root node and the third element as the
rs
right child. (no. of elements on level-II: 2)
1
1 12 9 5 6 10
ve
12 9
Put the next two elements as children of the left node of the second level. Again, put the
next two elements as children of the right node of the second level (no. of elements on
level-III: 4) elements).
ni
Keep repeating until you reach the last element.
1
U
12 9 1 12 9 5 6 10
5 6 10
ity
Example:
#include <stdbool.h>
#include <stdio.h>
m
#include <stdlib.h>
struct Node {
int key;
)A
};
// Node creation
node->key = k;
return node;
Notes
ity
}
if (root == NULL)
rs
return (0);
ve
// Check if the tree is a complete binary tree
if (root == NULL)
return true;
return false;
ni
U
return (checkComplete(root->left, 2 * index + 1, numberNodes) &&
checkComplete(root->right, 2 * index + 2, numberNodes));
int main() {
ity
root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
m
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->left = newNode(6);
)A
int index = 0;
else
}
Notes
ity
4.2.4 Extended Binary trees
Extended binary tree is a type of binary tree in which all the null sub tree of the
original tree are replaced with special nodes called external nodes whereas other nodes
are called internal nodes
rs
1
2 3
5 4
ve
Fig 4.4 : Extended Binary tree
Here the circles represent the internal nodes and the boxes represent the external
nodes.
ni
1. The nodes from the original tree are internal nodes and the special nodes are
external nodes.
U
2. All external nodes are leaf nodes and the internal nodes are non-leaf nodes.
3. Every internal node has exactly two children and every external node is a leaf.
It displays the result which is a complete binary tree
Below is an example of making an extended binary tree in C++ by making all the
ity
every node in the tree exactly once is called an enumeration of the tree’s nodes. Some
applications do not require that the nodes be visited in any particular order as long as
each node is visited precisely once. For other applications, nodes must be visited in an
order that preserves some relationship.
)A
Tree traversal is the process of visiting each node in the tree exactly once. Visiting
each node in a graph should be done in a systematic manner. If search result in a visit
to all the vertices, it is called a traversal. There are basically three traversal techniques
for a binary tree that are,
1. Pre-order traversal
(c
2. In-order traversal
3. Post-order traversal
1) Pre-order traversal
Notes
ity
To traverse a binary tree in pre-order, following operations are carried out:
rs
2) Inorder traversal
To traverse a binary tree in in-order traversal, following operations are carried out:
ve
b. Visit the root.
c. Traverse the right most sub tree.
3) Postorder traversal
To traverse a binary tree in postorder traversal, following operations are carried out:
ni
a. Traverse the left sub tree of root.
b. Traverse the right sub tree of root.
c. Visit the root.
U
Example:
Consider the below figure and let us understand the program of In-order, Pre-order
and Post-order traversal.
ity
2 3
4 5
m
#include <stdio.h>
#include <stdlib.h>
)A
/* A binary tree node has data, pointer to left child and a pointer to right child */
struct node
int data;
};
/* function that allocates a new node with the given data and NULL left and right
pointers. */ Notes
ity
struct node* newNode(int data)
malloc(sizeof(struct node));
rs
node->data = data;
node->left = NULL;
node->right = NULL;
ve
return(node);
/* Given a binary tree, print its nodes according to the “bottom-up” post-order
traversal. */
if (node == NULL)
ni
U
return;
postorder(node->left);
postorder(node->right);
ity
printf(“%d “, node->data);
if (node == NULL)
return;
)A
inorder(node->left);
printf(“%d “, node->data);
inorder(node->right);
}
(c
if (node == NULL)
return;
Notes
ity
printf(“%d “, node->data);
preorder(node->left);
preorder(node->right);
rs
int main()
ve
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
preorder(root);
ni
printf(“\nPre-order traversal of binary tree is: “);
postorder(root);
ity
getchar();
return 0;
Output:
m
The value of the key of the left sub-tree is less than the value of its parent (root)
node’s key.
(c
The value of the key of the right sub-tree is greater than or equal to the value of its
parent (root) node’s key.
Search Operation
Notes
ity
Whenever an element is to be searched, start searching from the root node. Then if
the data is less than the key value, search for the element in the left subtree. Otherwise,
search for the element in the right subtree. Follow the same algorithm for each node.
Algorithm:
rs
struct node *current = root;
while(current->data != data){
ve
if(current != NULL) {
printf(“%d “,current->data);
current = current->leftChild;
else {
ni
U
current = current->rightChild;
//not found
ity
if(current == NULL){
return NULL;
}
m
return current;
}
)A
Insert Operation
Deletion
Notes
ity
Delete function is used to delete the specified node from a binary search tree.
However, we must delete a node from a binary search tree in such a way, that the
property of binary search tree doesn’t violate. There are three situations of deleting a
node from binary search tree.
It is the simplest case, in this case, replace the leaf node with the NULL and simple
free the allocated space.
rs
In the following image, we are deleting the node 85, since the node is a leaf node,
therefore the node will be replaced with NULL and allocated space will be freed.
ve
50 and free the node 50
Delete
25 75 25 75
node 85
12 30 60 85 12 30 60 85
Delete node
52 70 52 70
In this case, replace the node with its child and delete the child node, which now
contains the value which is to be deleted. Simply replace it with the NULL and free the
U
allocated space.
In the following image, the node 12 is to be deleted. It has only one child. The node
will be replaced with its child node and the replaced node 12 (which is now leaf node)
will simply be deleted.
ity
Delete 25 75 25 75
node 12
12 30 60 12 30 60
m
52 70 52 70
6 12
Delete node
Algorithm
1. Define Node which has three attributes namely: data, left and right where left
represents the left child of the node and right represents the right child of the
node.
2. When a node is created, data will pass to the data attribute of the node and both
(c
4. insert() will insert the new value into a binary search tree:
Notes
ity
It checks whether root is null, which means tree is empty. New node will become
root node of tree.
a. If tree is not empty, it will compare value of new node with root node. If
value of new node is greater than root, new node will be inserted to right
subtree. Else, it will be inserted in left subtree.
5. deleteNode() will delete a particular node from the tree:
rs
a. If value of node to be deleted is less than root node, search node in left
subtree. Else, search in right subtree.
b. If node is found and it has no children, then set the node to null.
ve
c. If node has one child then, child node will take position of node.
d. If node has two children then, find a minimum value node from its right
subtree. This minimum value node will replace the current node.
Example:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h> ni
U
struct node{
int data;
};
newNode->data= data;
newNode->left = NULL;
)A
newNode->right = NULL;
return newNode;
if(root == NULL){
Notes
ity
root = newNode;
return;
else {
rs
struct node *current = root, *parent = NULL;
while(true) {
parent = current;
ve
if(data < current->data) {
current = current->left;
if(current == NULL) {
parent->left = newNode;
}
}
return;
ni
U
else {
current = current->right;
if(current == NULL) {
ity
parent->right = newNode;
return;
} } } } }
if (root->left != NULL)
return minNode(root->left);
)A
else
return root;
//deleteNode() will delete the given node from the binary search tree
if(node == NULL){
return NULL;
}
Notes
ity
else {
rs
node->right = deleteNode(node->right, value);
else {
ve
node = NULL;
node = node->right;
}
node = node->left;
ni
U
else {
node->data = temp->data;
ity
return node;
m
if(root == NULL){
printf(“Tree is empty\n”);
return;
(c
else {
if(node->left!= NULL)
Notes
ity
inorder(node->left);
printf(“%d “, node->data);
if(node->right!= NULL)
inorder(node->right);
rs
}
int main()
ve
{
insert(5);
insert(3);
insert(7);
insert(6);
insert(1);
ni
U
insert(9);
inorder(root);
inorder(root);
inorder(root);
inorder(root);
return 0;
Notes
ity
}
Output:
135679
rs
Binary search tree after deleting node 9:
13567
ve
1567
167
ni
U
ity
m
)A
(c
ity
4.3.1 General Trees
General tree is a tree in which every node can have either zero or many child
nodes. It cannot be empty. In general tree, there is no limitation on the degree of a
node. The topmost node of a general tree is termed the root node. There are several
subtrees in a general tree. The subtree of a general tree is unordered since the nodes
rs
of the general tree cannot be ordered according to specific criteria. In a general
tree, each node has in-degree(number of parent nodes) one and maximum out-
degree(number of child nodes) n.
ve
ni
Fig 4.7 : General tree
U
4.3.2 AVL Tree
AVL tree is a self-balancing binary search tree in which each node maintains extra
information called a balance factor whose value is either -1, 0 or +1.
ity
Balance factor of a node in an AVL tree is the difference between the height of the
left subtree and that of the right subtree of that node.
The self balancing property of an avl tree is maintained by the balance factor. The
m
-1 -1
9 53
0 1 0
8 21 61
0
(c
11
ity
Rotating the subtrees in an AVL Tree
Left Rotate
In left-rotation, the arrangement of the nodes on the right is transformed into the
rs
arrangements on the left node.
Algorithm:
ve
Ρ
X
α
Y
β
ni γ
1. If y has a left subtree, assign x as the parent of the left subtree of y.
Ρ
U
X
α β Y
ity
γ
2. If the parent of x is NULL, make y as the root of the tree.
3. Else if x is the left child of p, make y as the left child of p.
4. Else assign y as the right child of p.
Ρ
m
X Y
α β γ
)A
Y
X γ
(c
α β
Right Rotate
In left-rotation, the arrangement of the nodes on the left is transformed into the
Notes arrangements on the right node.
ity
1. Let the initial tree be:
Ρ
rs
X α
γ β
2. If x has a right subtree, assign y as the parent of the right subtree of x.
Ρ
ve
Y
X β α
γ
ni
3. If the parent of y is NULL, make x as the root of the tree.
4. Else if y is the right child of its parent p, make x as the right child of p.
5. Else assign x as the left child of p.
U
Ρ
X Y
γ β α
ity
X
γ Y
m
β α
We know that the binary tree nodes may have at most two children. But if they
have only one children, or no children, the link part in the linked list representation
remains null. Using threaded binary tree representation, we can reuse that empty links
by making some threads.
If one node has some vacant left or right child area, that will be used as thread.
There are two types of threaded binary tree. The single threaded tree or fully threaded
(c
binary tree. In single threaded mode, there are another two variations. Left threaded
and right threaded.
In the left threaded mode if some node has no left child, then the left pointer will
point to its in-order predecessor, similarly in the right threaded mode if some node has Notes
ity
no right child, then the right pointer will point to its in-order successor.
For fully threaded binary tree, each node has five fields. Three fields like normal
binary tree node, another two fields to store Boolean value to denote whether link of
that side is actual link or thread.
Header
rs
56
23 89
20 30 85
12
ve
These are the examples of left and right threaded tree
Header
56
23 89
ni
20 30 85
12
56
23 89
20 30 85
ity
12
4.3.4 B Trees
A B-tree is a tree data structure that keeps data sorted and allows searches,
insertions, and deletions in logarithmic amortized time. Unlike self-balancing binary
search trees, it is optimized for systems that read and write large blocks of data. It is
m
The set formulation of the B-tree rules: Every B-tree depends on a positive
constant integer called MINIMUM, which is used to determine how many elements are
held in a single node.
●● Rule 1: The root can have as few as one element (or even no elements if it
also has no children); every other node has at least MINIMUM elements.
●● Rule 2: The maximum number of elements in a node is twice the value of
(c
MINIMUM.
●● Rule 3: The elements of each B-tree node are stored in a partially filled array,
sorted from the smallest element (at index 0) to the largest element (at the
ity
than the number of elements in the node.
o Subtree 0, subtree 1, ...
rs
2. An element at index i is less than all the elements in subtree number i + 1
of the node.
●● Rule 6: Every leaf in a B-tree has the same depth. Thus it ensures that a
ve
B-tree avoids the problem of a unbalanced tree.
93, 107
ni
Subtree 0 Subtree 1 Subtree 2
6
U
2, 4 9
1 3 5 7, 8 10
ity
MINIMUM = 1
m
)A
(c
Unit-4.4: Graph
Notes
ity
4.4.1 Introduction
A Graph is a non-linear data structure containing of nodes and edges. The nodes
are occasionally also mentioned to as vertices and the edges are lines or arcs that
connect any two nodes in the graph.
rs
4.4.2 Graph Theory Terminology
A Graph comprises of a finite set of vertices(or nodes) and set of Edges which
connect a pair of nodes. A graph G consists of two sets
ve
●● a finite, nonempty set of vertices V(G)
●● a finite, possible empty set of edges E(G)
●● G(V,E) represents a graph
An undirected graph is one in which the pair of vertices in a edge is unordered, (v0,
v1) = (v1,v0)
!= <v1,v0>
0 1
ni
A directed graph is one in which each edge is a directed pair of vertices, <v0, v1>
U
Edge 2
4 3
Vertices
ity
In the above Graph, the set of vertices V = {0,1,2,3,4} and the set of edges E = {01,
12, 23, 34, 04, 14, 13}.
To represent networks Graphs are used. The networks may include paths in a city
or telephone network or circuit network. Graphs are also utilized in social networking
m
sites.
ity
as shown in the following image. Here AB can be represented as 1 at row 0,
column 1, BC as 1 at row 1, column 2 and so on, keeping other combinations
as 0.
●● Adjacency − Two node or vertices are adjacent if they are connected to
each other through an edge. In the following example, B is adjacent to A, C is
adjacent to B, and so on.
rs
●● Path − Path represents a sequence of edges between the two vertices. In the
following example, ABCD represents a path from A to D.
ve
0 A
1 B 4 E 5 F
2 C
ni 6 G
U
3 D
Basic Operations
ity
Matrix)
The following two are the most commonly used representations of a graph.
1. Adjacency Matrix
)A
2. Adjacency List
Let us take an undirected graph:
(c
0 1 Notes
ity
2
4 3
rs
1. Adjacency Matrix:
Adjacency Matrix is a 2D array of size Vertex x Vertex.
ve
●● The adjacency matrix of G is a two-dimensional n by n array, say adj_mat
●● If the edge (vi, vj) is in E(G), adj_mat[i][j]=1
●● If there is no such edge in E(G), adj_mat[i][j]=0
●● The adjacency matrix for an undirected graph is symmetric; the adjacency
matrix for a digraph need not be symmetric.
ni
Adjacency Matrix is a 2D array of size Vertex x Vertex. Let the 2D array be adj_
mat[][], a slot adj_mat[i][j] = 1 indicates that there is an edge from vertex i to vertex j.
Adjacency matrix for undirected graph is always symmetric. Adjacency Matrix is also
used to represent weighted graphs. If adj_mat[i][j] = w, then there is an edge from
U
vertex i to vertex j with weight w.
0 1 2 3 4
0 0 1 0 0 1
ity
1 1 0 1 1 1
2 0 1 0 1 0
3 0 1 1 0 1
4 1 1 0 1 0
m
2. Adjacency List
)A
For this, an array of lists is used. The size of the array is equal to the number of
vertices. Let the array be arr[] and arr[i] represents the list of vertices adjacent to the ith
vertex. To represent a weighted graph, the same representation can also be used. The
weights of edges can be represented as lists of pairs. Following is the adjacency list
representation of the above graph.
(c
Notes 0 1 4 /
ity
1 0 4 2 3 /
2 1 3 /
3 1 4 2 /
4 3 0 1 /
rs
Fig 4.12 : Adjacency list
#define MAX_VERTICES 50
ve
typedef struct node *node_pointer;
int vertex;
};
struct node *link;
node_pointer graph[MAX_VERTICES]; ni
U
int n=0; /* vertices currently in use */
Floyd-Warshall algorithm is used. The algorithm will generate a matrix, which will
represent the minimum distance from any node to all other nodes in the graph.
Example:
{INF, 0, 3, INF},
m
10 Notes
(0) (3)
ity
5 1
(1) (2)
rs
3
Fig 4.13 : Directed graph
ve
And graph[i][j] is INF (infinite) if there is no edge from vertex i to j.
Output:
0 5 8 9
INF
INF
INF
0
INF
INF INF
3
0
4
0
ni
U
Algorithm:
We initialize the solution matrix same as the input graph matrix as a first step. Then
we update the solution matrix by considering all vertices as an intermediate vertex.
The idea is to one by one pick all vertices and updates all shortest paths which include
ity
the picked vertex as an intermediate vertex in the shortest path. When we pick vertex
number k as an intermediate vertex, we already have considered vertices {0, 1, 2, ..
k-1} as intermediate vertices. For every pair (i, j) of the source and destination vertices
respectively, there are two possible cases.
1. k is not an intermediate vertex in shortest path from i to j. We keep the value of dis[i]
[j] as it is.
m
Notes A B C
A B D
ity
B A D C
C B E
D A B E /
D E
E D C
Undirected Graph Adjacency List
rs
For each node present in the graph which stores the node value and a pointer to
the next adjacent node to the respective node, an adjacency list is maintained. If all the
adjacent nodes are traversed then store the NULL in the pointer field of last node of
the list. The sum of the lengths of adjacency lists is equal to the twice of the number of
edges present in an undirected graph.
ve
Let us take the directed graph shown in the following figure and check the
adjacency list representation of the graph. The sum of lengths of all the adjacency lists
is equal to the number of edges present in the graph in case of a directed graph.
A A
ni
A B C
B C D
C E
D A
D E
E D
Directed Graph Adjacency List
U
Fig 4.15 : Adjacency list
In the case of weighted directed graph, each node contains an extra field that is
called the weight of the node. The adjacency list representation of a directed graph is
shown in the following figure.
ity
5 2 A B 5
A B C
B C 2 D 8
7 8 4 C E 4
D A 7
10
D E
E D 10
Weighted Directed Graph Adjacency List
m
●● Add/ Remove Vertex: This is the simplest operation in the graph. We can add
a vertex to a graph. It need not be connected to any other vertex through an
edge. When removing a vertex, we must remove all edges originating from
and ending at the deleted vertex.
(c
ity
4.4.7 Traversing A Graph(DFS, BFS)
DFS
Depth First Search or DFS traverses the graph vertically. It starts with the root node
or the first node of the graph and traverses all the child nodes before moving to the
adjacent nodes.
rs
Example
ve
A
A
A
A
A A
BFS
Traversal operation in the graph done by this. BFS horizontally traverses the graph
which means that it traverses all the nodes at a single level before proceeding to the
next level. The BFS algorithm starts at the top of the first node in the graph and then
traverses all the adjacent nodes to it. Once all the adjacent nodes are traversed, the
algorithm repeats the same procedure for child nodes.
m
If we traverse the above graph in BFS fashion then we will get as A -> B -> C -> D
-> E -> F -> G. The algorithm starts from node A and traverses all its adjacent nodes
B, C and D. It marks all the four nodes as visited. Once all the adjacent nodes of A are
traversed, the algorithm moves to the first adjacent node of A and repeats the same
)A
procedure. In this case, the node is B, and the adjacent nodes to B are E and F. Next,
the adjacent nodes to C are traversed. Once all the nodes are visited, the operation
ends.
Example:
#include <stdio.h>
(c
#include <stdlib.h>
#define N 6
Notes
ity
struct Graph {
};
rs
// to store adjacency list nodes of the graph
struct Node {
int dest;
ve
struct Node* next;
};
struct Edge {
};
int src, dest;
ni
// Function to create an adjacency list from specified edges
U
struct Graph* createGraph(struct Edge edges[], int n)
unsigned i;
ity
graph->head[i] = NULL;
newNode->dest = dest;
Notes
ity
// point new node to the current head
newNode->next = graph->head[src];
graph->head[src] = newNode;
rs
}
return graph;
ve
// Function to print adjacency list representation of a graph
int i;
{
ity
ptr = ptr->next;
printf(“\n”);
m
int main(void)
)A
{ 0, 1 }, { 1, 2 }, { 2, 0 }, { 2, 1 },
{ 3, 2 }, { 4, 5 }, { 5, 4 }
(c
};
int n = sizeof(edges)/sizeof(edges[0]);
Notes
ity
// construct a graph from the given edges
printGraph(graph);
rs
return 0;
Output:
ve
(0 -> 1)
(1 -> 2)
(2 -> 1) (2 -> 0)
(3 -> 2)
(4 -> 5)
(5 -> 4)
ni
U
ity
m
)A
(c
ity
4.5.1 Introduction
When graph G is connected, a depth first or breadth first search starting at any
vertex will visit all vertices in G. A spanning tree is any tree that consists solely of edges
in G and that includes all the vertices.
rs
E(G): T (tree edges) + N (nontree edges)
ve
Either dfs or bfs can be used to create a spanning tree
●● When dfs is used, the resulting spanning tree is known as a depth first
spanning tree
●● When bfs is used, the resulting spanning tree is known as a breadth first
spanning tree
●●
ni
While adding a nontree edge into any spanning tree, this will create a cycle
A spanning tree is a minimal subgraph, G’, of G such that V(G’)=V(G) and G’ is
connected.
U
Any connected graph with n vertices must have
By this definition, we can draw a conclusion that every connected and undirected
Graph G has at least one spanning tree. A disconnected graph does not have any
spanning tree, as it cannot be spanned to all its vertices.
Graph G
m
C B
Spanning Trees
A A A
)A
C B C B C B
We now recognize that one graph can have more than one spanning tree.
Following are a few properties of the spanning tree connected to graph G:
ity
vertices.
●● The spanning tree does not have any cycle (loops).
●● Eliminating one edge from the spanning tree will make the graph
disconnected, i.e. the spanning tree is minimally connected.
●● Adding one edge to the spanning tree will create a circuit or loop, i.e. the
rs
spanning tree is maximally acyclic.
Spanning tree is mostly used to find a minimum path to connect all nodes in a
graph. Common application of spanning trees are −
ve
●● Computer Network Routing Protocol
●● Cluster Analysis
ni
Prim’s algorithm is a Greedy algorithm. It begins with an empty spanning tree.
The idea is to maintain two sets of vertices. The first set contains the vertices already
contained in the MST, the other set contains the vertices not yet included. At every step,
it considers all the edges that connect the two sets, and picks the minimum weight edge
from these edges. After picking the edge, it moves the other endpoint of the edge to the
U
set containing MST.
A group of edges that connects two set of vertices in a graph is called cut in
graph theory. So, at every step of Prim’s algorithm, we discover a cut (of two sets, one
contains the vertices already included in MST and other contains rest of the vertices),
ity
collect the minimum weight edge from the cut and include this vertex to MST Set (the
set that contains already included vertices).
The idea behind Prim’s algorithm is simple, a spanning tree implies all vertices
must be connected. So the two disjoint subsets (discussed above) of vertices must be
connected to make a Spanning Tree. And they must be connected with the minimum
weight edge to make it a Minimum Spanning Tree.
m
Algorithm
1. Create a set mstSet that keeps track of vertices already included in MST.
2. Assign a key value to all vertices in the input graph. Initialize all key values as
)A
INFINITE. Assign key value as 0 for the first vertex so that it is picked first.
3. While mstSet doesn’t include all vertices
a) Pick a vertex u which is not there in mstSet and has minimum key value.
b) Include u to mstSet.
c) Update key value of all adjacent vertices of u. To update the key values, iterate
(c
through all adjacent vertices. For every adjacent vertex v, if weight of edge u-v
is less than the previous key value of v, update the key value as weight of u-v.
The concept of using key values is to pick the minimum weight edge from cut.
The key values are utilized only for vertices which are not yet included in MST, Notes
ity
the key value for these vertices indicate the minimum weight edges linking them
to the set of vertices included in MST.
8 7
1 2 3
4 2 9
rs
0 11 8 4 14 4
8 7 6 10
7 6 5
1 2
ve
Fig 4.19 : MST
The set mstSet is firstly empty and keys assigned to vertices are {0, INF, INF, INF,
INF, INF, INF, INF} where INF indicates infinite. Now pick the vertex with the minimum
key value. The vertex 0 is picked, include it in mstSet. So mstSet becomes {0}. After
including to mstSet, update key values of adjacent vertices. Adjacent vertices of 0 are
ni
1 and 7. The key values of 1 and 7 are updated as 4 and 8. Following subgraph shows
vertices and their key values, only the vertices with finite key values are shown. The
vertices encompassed in MST are shown in green color.
U
4
1
0
0
ity
8
7
Select the vertex with minimum key value and not already included in MST (not in
mstSET). The vertex 1 is picked and added to mstSet. So mstSet now becomes {0, 1}.
Update the key values of adjacent vertices of 1. The key value of vertex 2 becomes 8.
m
Pick the vertex with minimum key value and not even now included in MST (not in
mstSET). We can either pick vertex 7 or vertex 2, let vertex 7 is picked. So mstSet now
becomes {0, 1, 7}. Update the key values of adjacent vertices of 7. The key value of
vertex 6 and 8 becomes finite (1 and 7 respectively).
)A
4 8
1 2
0 7
0 8
(c
7 6
8 1
Pick the vertex with minimum key value and not already included in MST (not
Notes in mstSET). Vertex 6 is picked. So mstSet now becomes {0, 1, 7, 6}. Update the key
ity
values of adjacent vertices of 6. The key value of vertex 5 and 8 are updated.
4 8
1 2
0 7
0 8
rs
7 6 5
8 1 2
ve
We replicate the above steps until mstSet contains all vertices of given graph.
Finally, we get the following graph.
4 4 7
1 2 3
ni
0 9
0 8 4
2
7 6 5
8 1 2
U
Example:
#include <limits.h>
#include <stdbool.h>
ity
#include <stdio.h>
// function to find the vertex with minimum key value, from the set of vertices not yet
included in MST
m
return min_index;
(c
{
Notes
ity
int i;
printf(“Edge \tWeight\n”);
rs
}
/*function to construct and print MST for a graph represented using adjacency
matrix representation */
ve
{
ni
int key[V], v;
bool mstSet[V];
U
for ( i = 0; i < V; i++)
/*always include first 1st vertex in MST.Make key 0 so that this vertex is picked as
first vertex. */
ity
key[0] = 0;
parent[0] = -1;
/*pick the minimum key vertex from the set of vertices not yet included in MST */
mstSet[u] = true;
/*Update key value and parent index of the adjacent vertices of the picked vertex.
Consider only those vertices which are not yet included in MST */
printMST(parent, graph);
Notes
ity
}
void main()
int graph[V][V] = { { 0, 2, 0, 6, 0 },
rs
{ 2, 0, 3, 8, 5 },
{ 0, 3, 0, 0, 7 },
{ 6, 8, 0, 0, 9 },
ve
{ 0, 5, 7, 9, 0 } };
primMST(graph);
Output:.
Edge
0-1 2
1-2 3
Weight
ni
U
0-3 6
1-4 5
Steps:
4. Since G is connected and has n>0 vertices, exactly n-1 edges will be selected
Example
)A
4 3 3
4
4
2 2 3
Algorithm
(c
This algorithm will create spanning tree with minimum weight from a given
weighted graph.
1. Begin
Notes
ity
2. Create the edge list of given graph, with their weights.
3. Sort the edge list according to their weights in ascending order.
4. Draw all the nodes to create skeleton for spanning tree.
5. Pick up the edge at the top of the edge list (i.e. edge with minimum weight).
6. Remove this edge from the edge list.
rs
7. Connect the vertices in the skeleton with given edge. If by connecting the
vertices, a cycle is created in the skeleton, then discard this edge.
8. Repeat steps 5 to 7, until n-1 edges are added or list of edges is over.
ve
9. Return
c) Length
d) Width
3. What is a full binary tree?
a) Each node has exactly zero or two children
m
ity
a) Hierarchical structure
b) Faster search
c) Router algorithms
d) Undo/Redo operations in a notepad
6. Which of the following is incorrect with respect to binary trees?
rs
a) Let T be a binary tree. For every k ≥ 0, there are no more than 2k nodes in
level k
b) Let T be a binary tree with λ levels. Then T has no more than 2λ – 1 nodes
ve
c) Let T be a binary tree with N nodes. Then the number of levels is at least
ceil(log (N + 1))
d) Let T be a binary tree with N nodes. Then the number of levels is at least
floor(log (N + 1))
7. Construct a binary search tree by using postorder sequence given below.
Postorder: 2, 4, 3, 7, 9, 8, 5.
1
5
ni
8
U
2 4 7 9
a)
5
ity
3 8
2 4 7 9
b)
5
m
3 9
2 4 7 8
c)
)A
3 7
2 4 8 9
d)
(c
8. Construct a binary tree using inorder and level order traversal given below.
Inorder Traversal: 3, 4, 2, 1, 5, 8, 9
Level Order Traversal: 1, 4, 5, 9, 8, 2, 3
1
Notes
ity
4 5
9 8 2 3
a)
rs
5 4
9 8 2 3
b)
ve
1
4 5
8 9 2 3
c)
4
1
5 ni
U
8 9 3 2
d)
9. What is an AVL tree?
a) a tree which is balanced and is a height balanced tree
ity
Answer key:
1. b, 2. a, 3. a, 4. c, 5. d, 6. d, 7. b, 8. a, 9. a, 10. b
(c
ity
Structure:
rs
5.1.2 Bubble Sort
5.1.3 Selection Sort
5.1.4 Quick Sort
5.1.5 Merge Sort
ve
5.1.6 Heap Sort
5.1.7 Partition Exchange Sort
5.1.8 Shell Sort
5.1.9 Sorting on Different Keys
5.1.10 External Sorting
ni
Unit-5.2: Searching Techniques
5.2.1 Linear Search
U
5.2.2 Binary search
5.2.3 Hashing
5.2.4 Hash Functions
ity
ity
5.1.1 Insertion Sort
Sorting describes organizing data in a particular format. Sorting algorithm stipulates
the way to arrange data in a certain order. Most widespread orders are in numerical or
lexicographical order. A Sorting Algorithm is applied to rearrange a given array or list
elements allowing to a comparison operator on the elements.
rs
Insertion sort is a uncomplicated sorting algorithm that operates similar to the way
you sort playing cards in your hands. The array is virtually separated into a sorted and
an unsorted part. Values from the unsorted part are picked and placed at the proper
position in the sorted part.
ve
Algorithm
ni
2. Compare the current element or key to its predecessor.
3. If the key element is lesser than its predecessor, compare it to the elements
before. Move the greater elements one position up to make space for the
swapped element.
U
Example:
Let us loop for i = 1 (second element of the array) to 4 (last element of the array)
i = 2. 13 will remain at its position as all elements in A[0..I-1] are smaller than 13
i = 3. 5 will move to the beginning and all other elements from 11 to 13 will move
m
i = 4. 6 will move to position after 5, and elements from 11 to 13 will move one
)A
5, 6, 11, 12, 13
Example:
#include <stdio.h>
(c
int main()
ity
printf(“Enter number of elements: \n”);
scanf(“%d”, &n);
rs
scanf(“%d”, &array[c]);
t = array[c];
ve
for (d = c - 1 ; d >= 0; d--) {
if (array[d] > t) {
array[d+1] = array[d];
flag = 1;
else
break;
ni
U
}
if (flag)
array[d+1] = t;
ity
printf(“%d\n”, array[c]);
m
return 0;
}
)A
Output:
Enter 5 integers:
12534
(c
2
Notes
ity
3
rs
Bubble Sort is the plainest sorting algorithm that operates by constantly swapping
the adjacent elements if they are in wrong order.
Example:
ve
First pass:
ni
( 1 4 5 2 8 ) –> ( 1 4 2 5 8 ), Swap since 5 > 2
( 1 4 2 5 8 ) –> ( 1 4 2 5 8 ), Now, since these elements are already in order (8 > 5),
algorithm does not swap them.
Second Pass:
U
( 1 4 2 5 8 ) –> ( 1 4 2 5 8 )
( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )
ity
( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )
Now, the array is already sorted, but our algorithm does not know if it is completed.
The algorithm needs one whole pass without any swap to know it is sorted.
Third Pass:
m
( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )
( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )
( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )
)A
( 1 2 4 5 8 ) –> ( 1 2 4 5 8 )
Example:
#include <stdio.h>
int main()
(c
ity
scanf(“%d”, &n);
scanf(“%d”, &array[c]);
rs
for (c = 0 ; c < n - 1; c++)
ve
{
swap = array[d];
}
array[d] = array[d+1];
array[d+1] = swap;
ni
U
}
printf(“%d\n”, array[c]);
return 0;
}
m
Output:
5
)A
Enter 5 integers
20 30 50 40 70
20
30
(c
40
50
70
Notes
ity
5.1.3 Selection Sort
The selection sort algorithm arranges an array by continually finding the minimum
element (considering ascending order) from unsorted part and placing it at the
beginning. The algorithm holds two subarrays in a given array.
rs
2. Remaining subarray which is unsorted.
In every iteration of selection sort, the least element (considering ascending order)
from the unsorted subarray is selected and moved to the sorted subarray.
ve
Explanations of the above steps:
arr[] = 64 25 12 22 11
11 25 12 22 64
11 12 22 25 64
11 12 22 25 64
m
Example:
#include <stdio.h>
)A
int main()
scanf(“%d”, &n);
scanf(“%d”, &array[c]);
Notes
ity
for (c = 0; c < (n - 1); c++) // finding minimum element (n-1) times
position = c;
rs
{
position = d;
ve
}
if (position != c)
t = array[c];
}
array[position] = t;
ni
array[c] = array[position];
U
}
printf(“%d\n”, array[c]);
return 0;
Output:
m
Enter 5 integers
)A
94126
4
(c
ity
QuickSort is a Divide and Conquer algorithm. It chooses an element as pivot and
partitions the given array around the picked pivot. There are many distinct versions of
quickSort that pick pivot in different ways.
rs
3. Pick a random element as pivot.
4. Pick median as pivot.
The key process in quickSort is partition(). Target of partitions is, given an array
and an element x of array as pivot, put x at its correct position in sorted array and put all
ve
smaller elements (smaller than x) before x, and put all greater elements (greater than x)
after x. All this should be done in linear time.
{
ni
U
/* pi is partitioning index, arr[pi] is now
at right place */
}
m
Partition around
70 (Last element)
)A
Example:
/* C implementation of QuickSort */
Notes
ity
#include <stdio.h>
#include <stdbool.h>
#define MAX 7
rs
void printline(int count) {
int i;
ve
printf(“=”);
printf(“=\n”);
void display() {
int i;
printf(“[“);
ni
U
printf(“%d “,intArray[i]);
printf(“]\n”);
}
m
intArray[num1] = intArray[num2];
)A
intArray[num2] = temp;
while(true) {
//do nothing
Notes
ity
}
//do nothing
rs
if(leftPointer >= rightPointer) {
break;
} else {
ve
printf(“ item swapped :%d,%d\n”, intArray[leftPointer],intArray[rightPointer]);
swap(leftPointer,rightPointer);
swap(leftPointer,right);
return leftPointer;
}
ity
if(right-left <= 0) {
return;
} else {
m
quickSort(left,partitionPoint-1);
)A
quickSort(partitionPoint+1,right);
int main() {
display();
printline(50);
quickSort(0,MAX-1);
Notes
ity
printf(“Output Array: “);
display();
printline(50);
rs
If we compile and run the above program, it will produce the following result :
Output:
Input Array: [4 6 3 2 1 9 7 ]
ve
pivot swapped :9,7
Updated Array: [4 6 3 2 1 7 9 ]
Updated Array: [1 6 3 2 4 7 9 ]
Updated Array: [1 2 3 4 6 7 9 ]
ni
U
pivot swapped :3,3
Updated Array: [1 2 3 4 6 7 9 ]
Output Array: [1 2 3 4 6 7 9 ]
ity
MergeSort(arr[], l, r)
If r > l
)A
1. Find the middle point to divide the array into two halves:
middle m = (l+r)/2
Call merge(arr, l, m, r)
Notes
ity
The following diagram from wikipedia shows the complete merge sort process for
an example array {38, 27, 43, 3, 9, 82, 10}. If we take a closer look at the diagram, we
can see that the array is recursively divided in two halves till the size becomes 1. Once
the size becomes 1, the merge processes come into action and start merging arrays
back till the complete array is merged.
rs
These numbers indicates
the order in which 38 27 43 3 9 82 10
steps are processed 1
38 27 43 3 9 82 10
2 12
ve
38 27 43 3 9 82 10
3 7 13 17
38 27 43 3 9 82 10
4 5 8 9 14 15
27 38 38 43 9 82 10
6
3 27
11
10
38 43 9
ni 16
10
19
82
18
U
3 9 10 27 38 43 82 20
Example:
ity
#include <stdio.h>
#define max 10
int a[11] = { 10, 14, 19, 26, 27, 31, 33, 35, 42, 44, 0 };
int b[10];
m
for(l1 = low, l2 = mid + 1, i = low; l1 <= mid && l2 <= high; i++) {
b[i] = a[l1++];
else
b[i] = a[l2++];
(c
b[i++] = a[l1++];
Notes
ity
while(l2 <= high)
b[i++] = a[l2++];
a[i] = b[i];
rs
}
int mid;
ve
if(low < high) {
sort(low, mid);
sort(mid+1, high);
} else {
return;
ni
U
}
int main() {
ity
int i;
printf(“%d “, a[i]);
m
sort(0, max);
printf(“%d “, a[i]);
If we compile and run the above program, it will produce the following result :
Output
10 14 19 26 27 31 33 35 42 44 0
0 10 14 19 26 27 31 33 35 42 44
Notes
ity
5.1.6 Heap sort
Heap sort is a comparison-based sorting procedure based on Binary Heap data
structure. It is analogous to selection sort where we first find the maximum element
and place the maximum element at the end. We replicate the same process for the
remaining elements. Let us first define a Complete Binary Tree. A complete binary tree
rs
is a binary tree in which every level, except possibly the last, is completely filled, and
all nodes are as far left as possible. A Binary Heap is a Complete Binary Tree where
items are stored in a special order such that value in a parent node is larger (or smaller)
than the values in its two children nodes. The previous is called as max heap and the
concluding is called min-heap. The heap can be exemplified by a binary tree or array.
ve
Heap Sort Algorithm for sorting in increasing order:
ni
3. Repeat step 2 while size of heap is greater than 1.
Heapify procedure can be applied to a node only if its children nodes are heapified.
So the heapification must be performed in the bottom-up order.
U
Lets understand with the help of an example:
4(0)
ity
/ \
10(1) 3(2)
/ \
5(3) 1(4)
m
The numbers in bracket represent the indices in the array representation of data.
4(0)
)A
/ \
10(1) 3(2)
/ \
5(3) 1(4)
(c
10(0)
/ \
Amity Directorate of Distance & Online Education
182 Data Structure Using C
5(1) 3(2)
Notes
ity
/ \
4(3) 1(4)
rs
Example:
#include<stdio.h>
ve
int temp;
int largest = i;
largest = right;
ity
if (largest != i)
temp = arr[i];
arr[i]= arr[largest];
m
arr[largest] = temp;
}
)A
int i;
{
Notes
ity
temp = arr[0];
arr[0]= arr[i];
arr[i] = temp;
heapify(arr, i, 0);
rs
}
void main()
ve
{
int i;
heapSort(arr, size);
Output:
ity
2
m
3
)A
10
23
100
(c
array into subarrays, while in case of merge sort, all the genuine work occurs during
Notes merging the subarrays. In case of quick sort, the blend step does utterly nothing. It is
ity
similarly called partition-exchange sort. This algorithm splits the list into three main
parts:
rs
Pivot element can be any element from the array, it can be the first element, the
last element or any random element. In this tutorial, we will take the rightmost element
or the last element as pivot.
ve
For example: In the array {52, 37, 63, 14, 17, 8, 6, 25}, we take 25 as pivot. So
after the first pass, the list will be changed like this:
{6 8 17 14 25 63 37 52}
Hence after the first pass, pivot will be set at its position, with all the elements
smaller to it on its left and all the elements larger than to its right. Now 6 8 17 14 and
ni
63 37 52 are considered as two separate sunarrays, and same recursive logic will be
applied on them, and we will keep doing this until the complete array is sorted.
and all the elements greater than the pivot will be on the right side of it.
3. And the pivot element will be at its final sorted position.
4. The elements to the left and right, may not be sorted.
5. Then we pick subarrays, elements on the left of pivot and elements on the
right of pivot, and we perform partitioning on them by choosing a pivot in the
m
subarrays.
Let’s consider an array with values {9, 7, 5, 11, 12, 2, 14, 3, 10, 6}
Below, we have a pictorial representation of how quick sort will sort the given
)A
array.
(c
p r
0 1 2 3 4 5 6 7 8 9 Notes
ity
9 7 5 11 12 2 14 3 10 6
p q r
0 1 2 3 4 5 6 7 8 9
5 2 3 6 12 7 14 9 10 11
rs
p q r p q r
0 1 2 3 4 5 6 7 8 9
2 3 5 6 7 9 10 11 14 12
ve
p, r p, r p q, r 8
0 1 2 3 4 5 6 7 8 9
2 3 5 6 7 9 10 11 12 14
p q, r p, r
ni
0 1 2 3 4 5 6 7 8 9
2 3 5 6 7 9 10 11 12 14
p, r
U
0 1 2 3 4 5 6 7 8 9
2 3 5 6 7 9 10 11 12 14
Example:
ity
#include <stdio.h>
int main()
m
int i;
int arr[10]={90,23,101,45,65,28,67,89,34,29};
)A
quickSort(arr, 0, 9);
for(i=0;i<10;i++)
{
Notes
ity
int left, right, temp, loc, flag;
right = end;
flag = 0;
while(flag != 1)
rs
{
right--;
ve
if(loc==right)
flag =1;
else if(a[loc]>a[right])
ni
{
temp = a[loc];
a[loc] = a[right];
U
a[right] = temp;
loc = right;
if(flag!=1)
ity
left++;
if(loc==left)
m
flag =1;
{
)A
temp = a[loc];
a[loc] = a[left];
a[left] = temp;
loc = left;
(c
return loc;
Notes
ity
}
int loc;
if(beg<end)
rs
{
ve
quickSort(a, loc+1, end);
ni
Output:
23 28 29 34 45 65 67 89 90 101
U
5.1.8 Shell Sort
Shell sort is a highly useful sorting algorithm and is established on insertion sort
algorithm. This algorithm precludes large shifts as in case of insertion sort, if the smaller
value is to the far right and has to be moved to the far left.
ity
Knuth’s Formula
h=h*3+1
Let us consider the subsequent example to come up with an idea of how shell sort
m
works. We take over the same array we have used in our previous examples. For our
example and ease of understanding, we take the period of 4. Make a virtual sub-list of
all values located at the interval of 4 positions. Here these values are {35, 14}, {33, 19},
{42, 27} and {10, 44}
)A
35 33 42 10 14 19 27 44
35 14
33 19
42 27
(c
10 44
We compare values in each sub-list and swap them (if necessary) in the original
Notes array. After this step, the new array should look like this.
ity
14 19 27 10 35 33 42 44
Then, we take interval of 1 and this gap generates two sub-lists - {14, 27, 35, 42},
{19, 10, 33, 44}
rs
14 19 27 10 35 33 42 44
ve
14 27 35 42
19 10 33 44
We compare and swap the values, if required, in the original array. After this step,
the array should look like this
14
ni
19 27 10 35 33 42 44
U
Ultimately, we sort the remainder of the array using interval of value 1. Shell sort
uses insertion sort to sort the array. Following is the step-by-step depiction
14
14 19
19 27
27 10
10 35
35 33
33 42
42 44
44
ity
14
14 19
19 27
27 10
10 35
35 33
33 42
42 44
44
14
14 19
19 27
27 10
10 35
35 33
33 42
42 44
44
14
14 19
19 27
27 10
10 35
35 33
33 42
42 44
44
m
14
14 19
19 10
10 27
27 35
35 33
33 42
42 44
44
14
14 10
10 19
19 27
27 35
35 33
33 42
42 44
44
10
10 14
14 19
19 27
27 35
35 33
33 42
42 44
44
)A
10
10 14
14 19
19 27
27 35
35 33
33 42
42 44
44
10
10 14
14 19
19 27
27 35
35 33
33 42
42 44
44
10
10 14
14 19
19 27
27 35
35 33
33 42
42 44
44
(c
We see that it obliged only four swaps to sort the rest of the array.
Algorithm:
ity
Step 2 − Divide the list into smaller sub-list of equal interval h
rs
Sorting keys indicate the criteria used to execute the sort. The psort operator
permits to set a primary sorting key and multiple secondary sorting keys.
The psort operator manipulates the sorting keys to determine the sorting order of a
data set. The sort operator first sorts the records by the primary sorting key. If multiple
ve
records have the same primary key value, the psort operator then sorts these records
by any secondary keys.
You must define a single primary sorting key for the psort operator. You might
optionally define as many secondary keys as required by your job. Note, however, that
each record field can be used only once as a sorting key. Therefore, the total number
{ {
fName iName age fName iName age fName iName age
Mary
Bob
Davis
Jones
41
42
Mary
Bob
Davis
Jones
41
42
Paul
Mary
Smith
Davis
34
41
{
Jane
Paul
Smith
Smith
42
34
Jane
Paul
Smith
Smith
34
42 { Bob
Jane { Jones
Smith
42
42
This figure also indicates the results of three sorts using different combinations of
sorting keys. In this figure, the lName field represents a string field and the age field
represents an integer. By default, the psort operator applies a case-sensitive algorithm
for sorting. This implies that uppercase strings be found before lowercase strings in a
)A
sorted data set. You can utilize an option to the psort operator to select case-insensitive
sorting. You can use the member function APT_PartitionSortOperator::setKey() to
override this default, to perform case-insensitive sorting on string fields.
ity
To handle massive amounts of data, External sorting algorithm is used. It is a kind
of sorting algorithm as the name suggests. After sorting when the date do not fit into the
main memory then they must reside in external memory. This sorting technique uses
hybrid sort-merge strategy. In this process, small chunk of data which can be fit into
main memory are read, sorted and written to a temporary file. Later in merge phase, the
sorted sub-files are combined into a single larger file.
rs
External merge sort algorithm is one of the example of external sorting which sorts
chunks that can fit in RAM and then merges the sorted chunks together. For this, we
need to first divide the file into runs such that the size of run is small enough to fit into
main memory. Then using merge sort, sort each run in the main memory. Later we need
to merge the resulting runs together into bigger runs, until the file is sorted. To learn
ve
external sort algorithm we need to first understand Merge sort (for sorting individual
runs) and Merge K sorted array ( for merging sorted runs).
Inputs:
ni
output_file : Name of output file, output.txt
b 13 d 30
c 34 c 34
c 32 e 18
b 15 g 23 d 5
e 19
e 17 d 22
r 17 d 32
d 22 a 13
d 22 e 15
m 2
d 8
m
m 4 g 23
r 12
p 3 d 22 m 3
d a 13 m 4 p 6
6
p 3
a 15 d 8 r 15
r 17
)A
initial p 1 sorted
relation runs output
runs
create merge merge
runs pass-1 pass-2
Stage 1: First we need to create a number of sorted runs and need to sort each
(c
of them. In this stage, we perform the sorting operation on the disk blocks. After
completing the steps of Stage 1, proceed to Stage 2.
Steps:
Amity Directorate of Distance & Online Education
Data Structure Using C 191
i = 0;
Notes
ity
repeat
read either M blocks or the rest of the relation having a smaller size;
rs
i =i+1;
Stage 2: In Stage 2, we need to merge the runs. Let us think the total number
of runs as N which is less than M. Here, we can allocate one block to each run and
ve
still have some extra space to hold one block of output. We perform the operation as
follows:
Steps:
repeat
ni
select the first tuple among all buffer blocks (where selection is made in sorted
order);
U
write the tuple to the output, and then delete it from the buffer block;
After completing Stage 2, we will get a sorted output. The output file is then
buffered for minimizing the disk-write operations. As this algorithm merges N runs, that’s
why it is known as an N-way merge.
m
)A
(c
ity
5.2.1 Linear Search
Searching is an procedure or a technique that discovers the place of a given
element or value in the list. Any search is believed to be successful or unsuccessful
depending upon whether the element that is being searched is found or not.
rs
This is the easiest method for searching. In this technique of searching,
the element to be uncovered in searching the elements to be found is searched
sequentially in the list. This method can be performed on a sorted or an unsorted list
(usually arrays). In case of a sorted list searching starts from 0th element and remains
until the element is found from the list or the element whose value is greater than
ve
(assuming the list is sorted in ascending order), the value being searched is achieved.
It is a simple algorithm that searches for a certain item inside a list. It operates
looping on each element O(n) unless and until a match occurs or the end of the array is
achieved.
ni
●● algorithm Seqnl_Search(list, item)
●● Pre: list != ;
●● Post: return the index of the item if found, otherwise: 1
●● index <- fi
U
●● while index < list.Cnt and list[index] != item //cnt: counter variable
●● index <- index + 1
●● end while
●● if index < list.Cnt and list[index] = item
ity
●● return index
●● end if
●● return: 1
●● end Seqnl_Search
Example:
m
#include<stdio.h>
int main()
{
)A
int a[20],i,x,n;
scanf(“%d”,&n);
for(i=0;i<n;++i)
scanf(“%d”,&a[i]);
ity
scanf(“%d”,&x);
for(i=0;i<n;++i)
if(a[i]==x)
break;
rs
if(i<n)
else
ve
printf(“Element not found”);
return 0;
ni
Binary search is a very fast and efficient searching technique. It requires the list
to be in sorted order. In this method, to search an element you can compare it with the
present element at the center of the list. If it matches, then the search is successful
otherwise the list is divided into two halves: one from the 0th element to the middle
U
element which is the center element (first half) another from the center element to
the last element (which is the 2nd half) where all values are greater than the center
element.
The searching mechanism proceeds from either of the two halves depending upon
ity
whether the target element is greater or smaller than the central element. If the element
is smaller than the central element, then searching is done in the first half, otherwise
searching is done in the second half.
Algorithm
●● Set L to 0 and R to n: 1
●● if L > R, then Binary_Search terminates as unsuccessful
●● else
●● Set m (the position in the mid element) to the floor of (L + R) / 2
)A
#include <stdio.h>
int main()
Notes
ity
{
scanf(“%d”, &n);
rs
printf(“Enter %d integers\n”, n);
scanf(“%d”, &array[c]);
ve
printf(“Enter value to find\n”);
scanf(“%d”, &search);
first = 0;
last = n - 1;
middle = (first+last)/2;
break;
else
last = middle - 1;
m
return 0;
Output:
Enter 5 integers
12345
Notes
ity
Enter value to find
1 found at location 1.
5.2.3 Hashing
rs
Hashing is an essential Data Structure which is designed to use a particular
function called the Hash function which is used to map a given value with a particular
key for swifter access of elements. The efficiency of mapping depends of the
effectiveness of the hash function used. Hash table or hash map is a data structure
ve
utilized to store key-value pairs. It is a collection of items stored to make it effortless to
find them later. It utilizes a hash function to calculate an index into an array of buckets
or slots from which the anticipated value can be discovered. It is an array of list where
each list is recognized as bucket. It comprises value based on the key. Hash table is
employed to implement the map interface and extends Dictionary class. Hash table is
synchronized and encompasses only unique elements.
Features :
●●
ni
Hashing is the process of mapping enormous amount of data item to smaller
table with the help of hashing function.
U
●● Hashing is also known as Hashing Algorithm or Message Digest Function.
●● It is a method to convert a range of key values into a range of indexes of an
array.
●● It is used to facilitate the next level searching method when matched with the
linear or binary search.
ity
●● Hashing allows to update and retrieve any data entry in a constant time O(1).
●● Constant time O(1) indicates the operation does not depend on the size of the
data.
●● Hashing is utilized with a database to enable items to be retrieved more
quickly.
m
Insert: Move to the bucket corresponds to the above calculated hash index and
)A
Delete: To delete a node from hash table, calculate the hash index for the key,
move to the bucket corresponds to the calculated hash index, search the list in the
current bucket to find and remove the node with the given key (if found).
(c
ity
Keys arrive in the Order (15, 11, 27, 8)
0
1 15 8
2
3
rs
4 11
5
6 27
ve
Fig 5.6 Hash table
Example:
ni
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
U
/* Node for storing an item in a Linked List */
struct node
int key;
ity
int value;
};
struct arrayitem
};
int max = 10;// Determines the maximum capacity of Hash Table array
ity
{
rs
void remove_element(int key);
void rehash();
void init_array();
ve
void insert(int key, int value)
float n = 0.0;
item->key = key;
ity
item->value = value;
item->next = NULL;
if (list == NULL)
{
m
array[index].head = item;
)A
array[index].tail = item;
size++;
else
{
(c
if (find_index == -1)
Notes
ity
{
array[index].tail->next = item;
array[index].tail = item;
rs
size++;
else
ve
{
element->value = value;
}
ni
n = (1.0 * size) / max;
U
if (n >= 0.75)
{
ity
//rehashing
printf(“going to rehash\n”);
rehash();
}
m
void rehash()
{
)A
int i = 0, n = max;
size = 0;
max = 2 * max;
(c
init_array();
ity
{
if (list == NULL)
rs
{
continue;
ve
}
else
/* Presence of Linked List at i, keep moving and accessing the Linked List item until
ni
the end, Get one key and value at a time and add it to new Hash Table array.*/
{
U
insert(list->key, list->value);
list = list->next;
} } }
temp = NULL;
ity
{
m
int retval = 0;
if (temp->key == key)
return retval;
(c
temp = temp->next;
retval++;
Notes
ity
}
return -1;
rs
struct node* get_element(struct node *list, int find_index)
int i = 0;
ve
struct node *temp = list;
while (i != find_index)
temp = temp->next;
i++;
return temp;
ni
U
}
if (list == NULL)
m
}
)A
else
if (find_index == -1)
{
(c
else
Notes
ity
{
if (temp->key == key)
rs
array[index].head = temp->next;
return;
ve
}
temp = temp->next;
if (array[index].tail == temp->next)
{
ni
U
temp->next = NULL;
array[index].tail = temp;
}
ity
else
temp->next = temp->next->next;
}
m
} } }
void display()
int i = 0;
{
(c
if (temp == NULL)
{
Notes
ity
printf(“array[%d] has no elements\n”, i);
else
rs
{
ve
{
temp = temp->next;
printf(“\n”);
}
ni
U
}
void init_array()
ity
int i = 0;
{
m
array[i].head = NULL;
array[i].tail = NULL;
}
)A
int size_of_array()
return size;
(c
void main()
{
Notes
ity
int choice, key, value, n, c;
clrscr();
init_array();
rs
do {
ve
Please enter your choice -: “);
scanf(“%d”, &choice);
switch(choice)
case 1:
insert(key, value);
break;
ity
case 2:
scanf(“%d”, &key);
remove_element(key);
m
break;
case 3:
n = size_of_array();
)A
break;
case 4:
display();
(c
break;
default:
printf(“Wrong Input\n”);
}
Notes
ity
printf(“\nDo you want to continue-:(press 1 for yes)\t”);
scanf(“%d”, &c);
}while(c == 1);
getch();
rs
}
ve
●● This function takes a key and maps it to a value of a certain length which is
called a Hash value or Hash.
●● Hash value symbolizes the original string of characters, but it is normally
lesser than the original.
●● It transfers the digital signature and then both hash value and signature are
●●
ni
sent to the receiver. Receiver utilizes the same hash function to generate the
hash value and then compares it to that received with the message.
If the hash values are same, the message is communicated without errors.
U
5.2.4 Collision Resolution Technique
The hash function is utilized to compute the index of the array. The hash value
is used to store the key in the hash table, as an index. The hash function can return
the identical hash value for two or more keys. When two or more keys are provided
the same hash value, it is called a collision. To handle this collision, we use collision
ity
resolution techniques.
Linear Probing
)A
Quadratic Probing
Double Hashing
In this technique, a linked list is produced from the slot in which collision has
occurred, after which the new key is injected into the linked list. This linked list of slots Notes
ity
looks like a chain, so it is termed separate chaining. It is applied more when we do not
know how many keys to insert or delete.
Time complexity
rs
b. Its worst-case complexity for deletion is o(n).
Advantages of separate chaining
a. It is simple to implement.
b. The hash table never fills full, so we can add additional elements to the chain.
ve
c. It is less sensitive to the function of the hashing.
Disadvantages of separate chaining
a. Linear probing
b. Quadratic probing
c. Double hashing
Linear probing
m
In this, when the collision occurs, we perform a linear probe for the next slot, and
this probing is performed until an empty slot is found. In linear probing, the worst time to
search for an element is O(table size). The linear probing gives the best performance of
the cache but its problem is clustering. The main advantage of this technique is that it
can be easily calculated.
)A
In this, when the collision occurs, we probe for i2th slot in ith iteration, and this
probing is accomplished until an empty slot is discovered. The cache performance in
quadratic probing is lower than the linear probing. Quadratic probing also diminishes
ity
Double hashing
In this, you utilize another hash function, and probe for (i * hash 2(x)) in the ith
iteration. It requires longer to determine two hash functions. The double probing
provides the very poor the cache performance, but there has no clustering problem in it.
rs
0 1 2 3 4 5 6 7 8 9
ve
The above figure shows the hash table with the size of n = 10. Each position of
the hash table is called as Slot. In the above hash table, there are n slots in the table,
names = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}. Slot 0, slot 1, slot 2 and so on. Hash table contains
no items, so every slot is empty.
As we know the mapping between an item and the slot where item belongs in
ni
the hash table is termed the hash function. The hash function receives any item in the
collection and returns an integer in the range of slot names between 0 to n-1.
Suppose we have integer items {26, 70, 18, 31, 54, 93}. One common method of
U
determining a hash key is the division method of hashing and the formula is Hash Key =
Key Value % Number of Slots in the Table
Division method or reminder method takes an item and separates it by the table
size and returns the remainder as its hash value.
ity
26 26 % 10 = 6 6
70 70 % 10 = 0 0
18 18 % 10 = 8 8
31 31 % 10 = 1 1
m
54 54 % 10 = 4 4
93 93 % 10 = 3 3
)A
0 1 2 3 4 5 6 7 8 9
70 31 93 54 26 18
After computing the hash values, we can insert each item into the hash table at the
designated position as shown in the above figure. In the hash table, 6 of the 10 slots
(c
are inhabited, it is described to as the load factor and denoted by, λ = No. of items /
table size. For example , λ = 6/10. Notes
ity
It is easy to search for an item using hash function where it computes the slot
name for the item and then checks the hash table to see if it is appear. Constant
amount of time O(1) is required to compute the hash value and index of the hash table
at that location.
rs
Linear Probing
●● Take the above example, if we insert next item 40 in our collection, it would have
a hash value of 0 (40 % 10 = 0). But 70 also had a hash value of 0, it becomes a
problem. This problem is called as Collision or Clash. Collision creates a problem
for hashing technique.
ve
●● Linear probing is utilized for resolving the collisions in hash table, data structures
for maintaining a collection of key-value pairs.
●● Linear probing was developed by Gene Amdahl, Elaine M. McGraw and Arthur
Samuel in 1954 and analyzed by Donald Knuth in 1963.
●●
●●
dictionary problem.
ni
It is a component of open addressing scheme for using a hash table to resolve the
The simplest method is called Linear Probing. Formula to compute linear probing
is:
U
P = (1 + P) % (MOD) Table_size
For example,
0 1 2 3 4 5 6 7 8 9
ity
70 31 93 54 26 18
If we insert next item 40 in our collection, it would have a hash value of 0 (40 % 10
= 0). But 70 also had a hash value of 0, it becomes a problem.
P = H(40)
44 % 10 = 0
P= (P + 1) % table-size
0 + 1 % 10 = 1
But, position 1 is occupied by 31, so we look elsewhere for a position to store 40.
(c
Notes 0 1 2 3 4 5 6 7 8 9
ity
70 31 40 93 54 26 18
rs
a) Item is somewhere in the middle of the array
b) Item is not in the array at all
c) Item is the last element in the array
ve
d) Item is the last element in the array or item is not there at all
2. If the number of records to be sorted is small, then …… sorting can be efficient.
a) Merge
b) Heap
3.
c) Selection
d) Bubble
ni
The complexity of the sorting algorithm measures the …… as a function of the
U
number n of items to be sorter.
a) average time
b) running time
c) average-case complexity
ity
d) case-complexity
4. Which of the following is not a limitation of binary search algorithm?
a) must use a sorted array
b) requirement of sorted array is expensive when a lot of insertion and deletions
are needed
m
ity
c) sorted linear array
d) pointer array
7. Sorting algorithm can be characterized as
a) Simple algorithm which require the order of n2 comparisons to sort n items.
b) Sophisticated algorithms that require the O(nlog2n) comparisons to sort items.
rs
c) Both of the above
d) None of the above
8. ………. is putting an element in the appropriate place in a sorted list yields a larger
ve
sorted order list.
a) Insertion
b) Extraction
c) Selection
ni
d) Distribution
9. Which of the following sorting algorithm is of priority queue sorting type?
a) Bubble sort
U
b) Insertion sort
c) Merge sort
d) Selection sort
10. Partition and exchange sort is ……..
ity
a) quick sort
b) tree sort
c) heap sort
d) bubble sort
m
Answer key:
1. d, 2. c, 3. b, 4. d, 5. a, 6. a, 7. c, 8. a, 9. d, 10. a
)A
Assignment :
Using the hash function ‘key mod 7’, insert the following sequence of keys in the
hash table- 50, 700, 76, 85, 92, 73 and 101
Step-01:
ity
●● So, draw an empty hash table consisting of 7 buckets as
0
1
2
rs
3
4
5
6
ve
Step-02:
ni
So, key 50 will be inserted in bucket-1 of the hash table as-
0
1 50
U
2
3
4
5
ity
6
Step-03:
0 700
1 50
2
)A
3
4
5
6
Step-04:
0 700 Notes
ity
1 50
2
3
4
5
6 76
rs
Step-05:
ve
●● Bucket of the hash table to which key 85 maps = 85 mod 7 = 1.
●● Since bucket-1 is already occupied, so collision occurs.
●● To handle the collision, linear probing technique keeps probing linearly until an
empty bucket is found.
●● The first empty bucket is bucket-2.
●●
0
1
700
50
ni
So, key 85 will be inserted in bucket-2 of the hash table as-
U
2 85
3 92
4
5
6 76
ity
Step-06:
Notes 0 700
ity
1 50
2 85
3 92
4 73
5
6 76
rs
Step-07:
ve
●● Bucket of the hash table to which key 73 maps = 73 mod 7 = 3.
●● Since bucket-3 is already occupied, so collision occurs.
●● To handle the collision, linear probing technique keeps probing linearly until an
empty bucket is found.
●● The first empty bucket is bucket-4.
●●
ni
So, key 73 will be inserted in bucket-4 of the hash table as-
0
1
700
50
U
2 85
3 92
4 73
5 101
6 76
ity
Step-08:
●● Bucket of the hash table to which key 101 maps = 101 mod 7 = 3.
m
●● So, key 101 will be inserted in bucket-5 of the hash table as-
(c