You are on page 1of 329

ashish0751@gmail.

com
UNIT-1 and Unit-2
Data Structures
(AI&DS, AI&ML,IIOT)

Dr. Ashish Kumar


VIPS-TC
ashish0751@gmail.com
School of Engineering & Technology
Data structure and Algorithmic complexity
Data structure
 Data structure is a way of collecting and organizing the data in such a way that we can perform operations on these data in an effective way.

 The operations are adding, updating, deleting, sorting, searching the data and so on.

 A data structure is not only used for organizing the data. It is also used for processing, retrieving, and storing data. There are different basic
and advanced types of data structures that are used in almost every program or software system that has been developed. So we must have
good knowledge about data structures. 

 Depending on your requirement and project, it is important to choose the right data structure for your project.

 For example, we have some data which has, Employee's name “Raju" and age 25.

 Here “Raju" is of String data type and 25 is of integer data type.

 We can organize these data as a record like Employee record, which will have both employee's name and age in it. Now we can collect and
store employee's records in a file or database as a data structure. 

 For example, if you want to store data sequentially in the memory, then you can go for the Array data structure

ashish0751@gmail.com
Advantages of Data structures
Efficiency: 

If the choice of a data structure for implementing a particular ADT is proper, it makes the program very efficient

in terms of time and space.

Reusability: 

The data structure provides reusability means that multiple client programs can use the data structure.

Abstraction: 

The data structure specified by an ADT also provides the level of abstraction. The client cannot see the internal

working of the data structure, so it does not have to worry about the implementation part. The client can only

see the interface.

ashish0751@gmail.com
DATA STRUCTURES

ashish0751@gmail.com
Primitive data structures
Primitive Data Structures: A primitive data structure can store the value of only one data type. For example, a char data
structure (a primitive data structure) can store only characters.
Key features of a primitive data structure:
•The size of a primitive data structure is known as it can store can only one data type.
•The primitive data structure will always store some data. It cannot contain the NULL value.
•Examples of the primitive data type are integer, character, boolean, float, double, long, etc.

ashish0751@gmail.com
Non-Primitive data structures


Linear data structure
Data structure in which data elements are arranged sequentially or linearly, where each element is attached to
its previous and next adjacent elements, is called a linear data structure. Examples of linear data structures
are array, stack, queue, linked list, etc.
• Static data structure: Static data structure has a fixed memory size. It is easier to access the elements in a
static data structure. An example of this data structure is an array.
• Dynamic data structure: In dynamic data structure, the size is not fixed. It can be randomly updated
during the runtime which may be considered efficient concerning the memory (space) complexity of the
code. Examples of this data structure are queue, stack, etc.


Non-linear data structure: 
Data structures where data elements are not placed sequentially or linearly are called non-linear data
structures. In a non-linear data structure, we can’t traverse all the elements in a single run only.
ashish0751@gmail.com
Examples of non-linear data structures are trees and graphs.
Linear Vs Non-linear Data Structures

Linear Data Structures Non Linear Data Structures

The data items are arranged in The data items are arranged in non-
sequential order, one after the other. sequential order (hierarchical manner).

All the items are present on the single The data items are present at different
layer. layers.

It can be traversed on a single run. It requires multiple runs. That is, if we


That is, if we start from the first start from the first element it might not
element, we can traverse all the be possible to traverse all the elements
elements sequentially in a single pass. in a single pass.

Different structures utilize memory in


The memory utilization is not efficient. different efficient ways depending on
the need.

The time complexity increase with the


Time complexity remains the same.
data size.

Example: Arrays, Stack, Queue Example: Tree, Graph, Map


ashish0751@gmail.com
Linear Data Structures
1. Array Data Structure 2. Stack Data Structure
In an array, elements in memory In stack data structure, elements are stored in the LIFO
are arranged in continuous principle. That is, the last element stored in a stack will be
memory. All the elements of an removed first.
array are of the same type. And,
the type of elements that can be It works just like a pile of plates where the last plate kept on
stored in the form of arrays is the pile will be removed first.
determined by the programming
language. 3. Queue Data Structure
Unlike stack, the queue data structure works
in the FIFO principle where first element
stored in the queue will be removed first.
It works just like a queue of people in the
ticket counter where first person on the
queue will get the ticket first.

4. Linked List Data Structure


In linked list data structure, data elements are
connected through a series of nodes. And, each
node contains the data items and address to the
next node.
ashish0751@gmail.com
Non Linear Data Structures
1. Graph Data Structure 2. Trees Data Structure
In graph data structure, each node Similar to a graph, a tree is also a collection
is called vertex and each vertex is of vertices and edges. However, in tree data
connected to other vertices structure, there can only be one edge
through edges. between two vertices.

ashish0751@gmail.com
Algorithmic complexity

ashish0751@gmail.com
Algorithm
 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.
 An algorithm is any well-defined computational procedure that takes some value, or set of values, as input
and produces some value, or set of values, as output”
 Algorithms are generally created independent of underlying languages, i.e. an algorithm can be implemented in
more than one programming language.

Complexity Analysis
Based on Based on
Measuring an Input’s Size Measuring Running Time
Space Complexity Time Complexity
Algorithm & Pseudocode
What is Algorithm What is Pseudocode
• Pseudocode is an informal way of writing a program. It is
• An algorithm is a step by step procedure to not exactly a computer program. It represents the algorithm
solve a problem. of the program in natural language and mathematical
• A procedure is a finite sequence of notations. Usually, there is no particular code syntax to write
instructions, where each is carried out in a a pseudocode. Therefore, there is no strict syntax as a usual
finite amount of time. programming language. It uses simple English language.
• Every problem can be solved with the help of
an algorithm. • Pseudocode to add 2 numbers is as follows:
• For example, when the user wants to login to a
Facebook account, first he has to go to Sum of Two Numbers()
Facebook.com. Then he has to give the correct Begin
username and password. Then he has to click             Set sum=0;
the login button. If the username and password             Read: num1, num2;
are correct, the user can enter his account.             Set sum = num1+num2;
• Likewise, every problem has a sequence of             Print sum;
steps to solve it. This is also an algorithm End
because it provides a correct sequence of steps
to solve the problem.
ashish0751@gmail.com
Characteristics and Properties of an Algorithm
 Clear and Unambiguous: The algorithm should be clear and unambiguous. Each of its steps should be clear in all aspects and
must lead to only one meaning.
 Well-Defined Inputs: If an algorithm says to take inputs, it should be well-defined inputs. It may or may not take input.
 Well-Defined Outputs: The algorithm must clearly define what output will be yielded and it should be well-defined as well. It
should take at least 1 output.
 Finite-ness: The algorithm must be finite, i.e. it should terminate after a finite time.
 Feasible: The algorithm must be simple, generic, and practical, such that it can be executed with the available resources. It must
not contain some future technology or anything.
 Language Independent: The Algorithm designed must be language-independent, i.e. it must be just plain instructions that can be
implemented in any language, and yet the output will be the same, as expected.

Properties of Algorithm:
•It should terminate after a finite time.
•It should produce at least one output.
•It should take zero or more input.
•It should be deterministic means giving the same output for the same input case.
•Every step in the algorithm must be effective i.e. every step should do some work.
ashish0751@gmail.com
Example

Write an algorithm and draw a flowchart that will read the two sides of a rectangle and calculate its area.

Algorithm
START

• Input the width (W) and Length (L) of a rectangle Input


• Calculate the area (A) by multiplying L with W W, L

• Print A
ALxW
Pseudocode
• Step 1: Input W,L Print
A
• Step 2: A  L x W
• Step 3: Print A STOP

ashish0751@gmail.com
Algorithm Complexity (Performance Analysis)
The performance of an algorithm is Time Complexity--
judged by two important criteria. • The time complexity of an algorithm quantifies the amount of time
(i) Time complexity
(ii) space complexity. taken by an algorithm to run as a function of the length of the input.
• Note that the time to run is a function of the length of the input and
Generally, there is always more than one not the actual execution time of the machine on which the algorithm
way to solve a problem in computer is running on.
science with different algorithms. • In order to calculate time complexity on an algorithm, it is assumed
Therefore, it is highly required to use a that a constant time c is taken to execute one operation, and then
method to compare the solutions in order
the total operations for an input length on N are calculated.
to judge which one is more optimal. The
method must be:
 Independent of the machine and Space Complexity  −
its configuration, on which the Space is measured by counting the maximum memory space required
algorithm is running on. by the algorithm.
 Shows a direct correlation with The complexity of an algorithm f(n) gives the running time and/or the
the number of inputs. storage space required by the algorithm in terms of n as the size of
 Can distinguish two algorithms input data.
clearly without ambiguity.
ashish0751@gmail.com
Space Complexity
 Space complexity of an algorithm represents the amount of memory space
Following is a simple example that
required by the algorithm in its life cycle. tries to explain the concept −
 The space required by an algorithm is equal to the sum of the following two • Algorithm: SUM(A, B)
• Step 1 - START
components − • Step 2 - C ← A + B + 10
 A fixed part that is a space required to store certain data and variables, • Step 3 - Stop
that are independent of the size of the problem. For example, simple
variables and constants used, program size, etc.
 A variable part is a space required by variables, whose size depends on  Here we have three variables A, B,
the size of the problem. For example, dynamic memory allocation, and C and one constant.
recursion stack space, etc. Hence S(P) = 1 + 3.
Now, space depends on data types of
 Space complexity S(P) of any algorithm P is
given variables and constant types and
it will be multiplied accordingly.
S(P) = C + SP(I)
where C is the fixed part and S(I) is the variable part of the algorithm, which
depends on instance characteristic I.
ashish0751@gmail.com
Examples(Space Complexity)
1. Algorithm abc (a, b, c) • For every instance
2. { • 3 computer words required to store variables: a, b,
and c.
3. return a+b+b*c+(a+b-c)/(a+b)+4.0; • Therefore Sp()= 3.
4. }
• S(P) = 3.

1. Algorithm Sum(a[], n) • Every instance needs to store array a[] & n.


2. { • Space needed to store n = 1 word.
3. s:= 0.0; • Space needed to store a[ ] = n floating point words (or at
least n words)
4. for i = 1 to n do • Space needed to store i and s = 2 words
5. s := s + a[i];
• Sp(n) = (n + 3).
6. return s;
7. } • Hence S(P) = (n + 3).
ashish0751@gmail.com 19
Time Complexity

• Time complexity of an algorithm represents the amount of time required by the algorithm to run to completion.
• Time Complexity: The time complexity of an algorithm quantifies the amount of time taken by an algorithm to run as a
function of the length of the input. Note that the time to run is a function of the length of the input and not the actual
execution time of the machine on which the algorithm is running on.
• In order to calculate time complexity on an algorithm, it is assumed that a constant time c is taken to execute one
operation, and then the total operations for an input length on N are calculated. 
• Time requirements can be defined as a numerical function f(n), where f(n) can be measured as the number of steps,
provided each step consumes constant time.
• Time required f(P) to run a program P also consists of two components:
A fixed part:
compile time which is independent of the problem instance  c.
A variable part:
run time which depends on the problem instance  tp(instance)
T(P) = c + tp(instance)
ashish0751@gmail.com
Example 1 (Time Complexity)

Statements S/E Freq. Total

1 Algorithm Sum(a[],n,m) 0 - 0

2 { 0 - 0

3 for i=1 to n do; 1 n+1 n+1

4 for j=1 to m do 1 n(m+1) n(m+1)

5 s = s+a[i][j]; 1 nm nm

6 return s; 1 1 1

7 } 0 - 0

2nm+2n+2
Example 2 (Time Complexity)
Statements S/E Freq. Total

1 Algorithm Sum(a[],n) 0 - 0
2 { 0 - 0
3 S = 0.0; 1 1 1
4 for i=1 to n do 1 n+1 n+1
5 s = s+a[i]; 1 n n
6 return s; 1 1 1
7 } 0 - 0
F(n)=2n+3

**IMP**
This f(n) can be represented in the form of best case, worst case, average case, see next slides
1. Big O (Oh) Notation = Worst Case Analysis
2. Big Ω (Omega) Notation = Best Case Analysis
3. Big Ɵ (Theta) Notation = Average Case Analysis

Consider an algorithm representing two functions: f(n) and g(n)


ashish0751@gmail.com
Big O Notation (worst case )

• Big O of a function gives us ‘rate of growth’ of the step count function f(n), in terms of a
simple function g(n), which is easy to compare.

f(n) = O(g(n))
iff there exist positive constants c and n0 such that
f(n) <= c*g(n) for all n, n>=n0.

f(n) <= c*g(n) for all n, n>=n0.


Example:2
Given f(n) = 10n2+4n+2 Example:1 f(n) = 3n+2 is O(n)
Can we write O(n2) ?? because 3n+2 <= 4n for all
If we can prove f(n) <= c*g(n) then we can write O(g(n)) or O(n2) n >= 2. c = 4, n0 = 2. Here g(n) = n.
Yes, because 10n2+4n+2 <= 11n2 for all n >=5.
Therefore
ashish0751@gmail.com the complexity of f(n) is O(n2) 24
Omega Notation (Ω-notation)
• Omega notation represents the lower bound of the running time of an Ω(g(n)) = { f(n): there exist positive constants
algorithm. Thus, it provides the best case complexity of an algorithm.
• That means Big-Omega notation always indicates the minimum time
c and n0 such that 0 ≤ cg(n) ≤ f(n)
required by an algorithm for all input values. That means Big-Omega
for all n ≥ n0 }
notation describes the best case of an algorithm time complexity.
• Omega gives the lower bound of a function
Example
Consider the following f(n) and g(n)...
f(n) = 3n + 2 g(n) = n
If we want to represent f(n) as Ω(g(n)) then it must satisfy f(n) >= C
g(n) for all values of C > 0 and n0>= 1
f(n) >= C g(n)
⇒3n + 2 >= C n
Above condition is always TRUE for all values of C = 1 and n >= 1.
By using Big - Omega notation we can represent the time complexity as
follows...
3n + 2 = Ω(n)

ashish0751@gmail.com
Big - Theta Notation (Θ)
• Big - Theta notation is used to define the average bound of an algorithm in terms of Time Complexity.
• Theta notation always indicates the average time required by an algorithm for all input values.
• Big - Theta notation describes the average case of an algorithm time complexity.

• Consider function f(n) as time complexity of an algorithm and g(n) is the most significant term.
• If C1 g(n) <= f(n) <= C2 g(n) for all n >= n0, C1 > 0, C2 > 0 and n0 >= 1. Then we can represent f(n) as Θ(g(n)).
• f(n) = Θ(g(n))

f(n) = Θ(g(n))
Example
Consider the following f(n) and g(n)...
f(n) = 3n + 2
g(n) = n
If we want to represent f(n) as Θ(g(n)) then it must satisfy 
C1 g(n) <= f(n) <= C2 g(n) for all values of C1 > 0, C2 > 0 and n0>= 1
C1 g(n) <= f(n) <= C2 g(n)
⇒C1 n <= 3n + 2 <= C2 n
Above condition is always TRUE for all values of C1 = 1, C2 = 4 and n >= 2.
By using Big - Theta notation we can represent the time complexity as
follows...
ashish0751@gmail.com
3n + 2 = Θ(n)
Array, String and recursion

ashish0751@gmail.com
Introduction of Array
• An array is a collection of similar data elements.
• These data elements have the same data type.
• The elements of the array are stored in consecutive memory locations and
are referenced by an index (also known as the subscript).
• The subscript is an ordinal number which is used to identify an element of the
array.

Declaration
int arr[5];

ashish0751@gmail.com
Declaration of Arrays
• We have already seen that every variable must be declared before it is used.
• The same concept holds true for array variables. An array must be declared
before being used.
• Declaring an array means specifying the following:
• Data type—the kind of values it can store, for example, int, char, float, double.
• Name—to identify the array.
• Size—the maximum number of values that the array can hold.
• Arrays are declared using the following syntax:
type name[size]; int arr[5];
• The type can be either int, float, double, char, or any other valid data type.
• The number within brackets indicates the size of the array, i.e., the maximum
number of elements that can be stored in the array.
ashish0751@gmail.com
Declaration of Arrays

• Figure 3.3 shows how different


types of arrays are declared.

ashish0751@gmail.com 31
Calculating the Address of Array Elements
• The address of other data elements can simply be
calculated using the base address.
• The formula to perform this calculation is, Address of
data element,
A[k] = BA(A) + w(k – lower_bound)

Example: Given the base address of an array A[1300 ………… 1900] as 1020 and the size of each element is
2 bytes in the memory, find the address of A[1700].  
Solution:
Given:
Base address B = 1020
Lower Limit/Lower Bound of subscript LB = 1300
Storage size of one element store in any array W = 2 Byte
Subset of element whose address to be found I = 1700
Formula used:
Address of A[I] = B + W * (I – LB)
Solution:
Address of A[1700] = 1020 + 2 * (1700 – 1300)
                              = 1020 + 2 * (400)
                              = 1020 + 800
ashish0751@gmail.com
Address of A[1700] = 1820 32
Initializing Arrays during Declaration
• The elements of an array can be initialized at the time of declaration, just as any other variable.
• When an array is initialized, we need to provide a value for every element in the array.
• Arrays are initialized by writing,

type array_name[size]={list of values};


• It is a compiler error to specify more values than there are elements in the array.

ashish0751@gmail.com
Inputting Values from the Keyboard

int x [3] ; • An array can be initialized by inputting values from the


x[0] =1; keyboard.
x[1] =5; • In this method, a while/do–while or a for loop is executed
x[2] =8; to input the value for each element of the array.
what if the array size was 100 ? • For example, look at the code shown in Fig. 3.9.
• In the code, we start at the index i at 0 and input the value
for the first element of the array.
• Since the array has 10 elements, we must input values for
elements whose index varies from 0 to 9.

ashish0751@gmail.com 34
Run time initialization( from user)
#include <stdio.h>
//////////////////////////////////
void main()
{
int i;
int A[6];
for(i = 0; i < 6; i++)
{ printf("enter elementt number %d ",i+1);
scanf("%d" , &A[i]); }
printf("***********\n");
for(i = 0; i < 6; i++)
printf("elementt number %d is: %d\n",i+1,A[i]);
}//end main

ashish0751@gmail.com
Accessing the Elements of an Array

• Now to process all the elements of the array, we use a loop as shown in Fig. 3.4.
• Figure 3.5 shows the result of the code shown in Fig. 3.4.
• The code accesses every individual element of the array and sets its value to –1.
• In the for loop, first the value of marks[0] is set to –1, then the value of the index (i) is
incremented and the next value, that is, marks[1] is set to –1.
• The procedure continues until all the 10 elements of the array are set to –1.

ashish0751@gmail.com
36
Assigning Values to Individual Elements

• Any value that evaluates to the data type as that of the array can be assigned to the individual array element.
• A simple assignment statement can be written as marks[3] = 100; Here, 100 is assigned to the fourth
element of the array which is specified as marks[3].
• Note that we cannot assign one array to another array, even if the two arrays have the same type and size.
• To copy an array, you must copy the value of every element of the first array into the elements of the second
array. Figure 3.10 illustrates the code to copy an array.

You cannot assign one array to another :


int A[5]={9,8,7,6,5};
int B[5];
A=B; //error … illegal
Instead, we must assign each value
individually
ashish0751@gmail.com
Character arrays initialization

char string1[] = “hello world”;


char string1[6] = “world”;
char string2[] = { 'f', 'i', 'r', 's', 't', ‘\0’ }; ‘\0’ denotes the end of string

Char string3[4]= {’w’,’o’,’w’,’\0’};

Run time initialization

char string1[20];
scanf( "%s", string1 ); //Reads characters until whitespace encountered
// Can write beyond end of array, be careful

ashish0751@gmail.com 38
c string
• In C programming, a string is a sequence of
characters terminated with a null character \
0. 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. For example:
char c[] = "c string";

ashish0751@gmail.com
TWO-DIMENSIONAL ARRAYS
• One-dimensional arrays are organized linearly in only one
direction.
For example, if we want to store the marks obtained by
• But at times, we need to store data in the form of grids or
tables. three students in three different subjects, we can declare a
• Here, the concept of single-dimension arrays is extended to two dimensional array as:
incorporate two-dimensional data structures.
int marks[3][3];
• A two-dimensional array is specified using two subscripts
where the first subscript denotes the row and the second A two-dimensional array is declared as:
denotes the column.
• The C compiler treats a two-dimensional array as an array data_type array_name[row_size][column_size];
of one-dimensional arrays.
• Figure 3.26 shows a two-dimensional array which can be
viewed as an array of arrays.
• The declaration statement tells the compiler the name of the
array, the data type of each element in the array, and the size
of each dimension.

ashish0751@gmail.com
TWO-DIMENSIONAL ARRAYS

• Declaring Two-dimensional arrays


• In the above statement, a two-dimensional array called marks has been declared that has m(3)
rows and n(5) columns.
• The first element of the array is denoted by marks[0][0], the second element as marks[0][1], and
so on.
• Here, marks[0][0] stores the marks obtained by the first student in the first subject, marks[1][0]
stores the marks obtained by the second student in the first subject.
• The pictorial form of a two-dimensional array of int marks[3][5] is shown in Fig. 3.27.

ashish0751@gmail.com
Address calculation in 2D Array in C
Graphical
int A[3][4]; Representa
Address of A[I][J] = B + W * ((I – LR) * N + (J – LC))   
tion of
I = Row Subset of an element whose address to be found, 
Array
0th 1st 2nd 3rd address in
J = Column Subset of an element whose address to be found, 
B = Base address, 
memory
0th 100 102 104 106 W = Storage size of one element store in an array(in byte), 
LR = Lower Limit of row/start row index of the matrix(If not
1st 108 110 112 114 given assume it as zero), 
LC = Lower Limit of column/start column index of the
matrix(If not given assume it as zero), 
2nd 116 118 120 122 N = Number of column given in the matrix.

Address of A[i][j]= Base Address + size of data type{No. of cols(i-0)+(j-0)}

Calculation:
A[2][2]= 100+2{4(2-0)+(2-0)}
A[2][2]= Address ? =100+2{8+2}
If base address is 100 the address of =120

A[2][2] is 120
ashish0751@gmail.com
Example: Given an array, arr[1………10][1………15] with base value 100 and the
size of each element is 1 Byte in memory. Find the address of arr[8][6] with the help
of row-major order.
Solution:
Given:
Base address B = 100
Storage size of one element store in any array W = 1 Bytes
Row Subset of an element whose address to be found I = 8
Column Subset of an element whose address to be found J = 6
Lower Limit of row/start row index of matrix LR = 1 
Lower Limit of column/start column index of matrix = 1
Number of column given in the matrix N = Upper Bound – Lower Bound + 1
                                                                            = 15 – 1 + 1
                                                                            = 15
Formula:
Address of A[I][J] = B + W * ((I – LR) * N + (J – LC)) 
Solution: https://www.geeksforgeeks.org/calculation-of-address-of-elem
Address of A[8][6] = 100 + 1 * ((8 – 1) * 15 + (6 – 1)) ent-of-1-d-2-d-and-3-d-using-row-major-and-column-major-ord
                                   = 100 + 1 * ((7) * 15 + (5)) er/
                                  = 100 + 1 * (110)
Address of A[I][J] = 210
ashish0751@gmail.com
2D Array: Initializing Two-dimensional arrays

• Initialization 1: • Therefore, the declaration statement given


int marks[2][3]={90, 87, 78, 68, 62, 71}; below is valid.
• Initialization 2: The above statement can int marks[][3]={{90,87,78},{68, 62, 71}};
also be written as:
int marks[2][3]={{90,87,78},{68, 62, 71}}; • In order to initialize the entire two-
dimensional array to zeros, simply specify
• The above two-dimensional array has two
rows and three columns. the first value as zero.
That is, int marks[2][3] = {0};
• First, the elements in the first row are
initialized and then the elements of the • The individual elements of a two-
second row are initialized.
dimensional array can be initialized using
• Therefore, marks[0][0] = 90 the assignment operator as shown here.
• marks[0][1] = 87 marks[0][2] = 78 marks[1][2] = 79;
marks[1][0] = 68 marks[1][1] = 62 or marks[1][2] = marks[1][1] + 10;
marks[1][2] = 71
ashish0751@gmail.com
2D array example: Storing elements in a matrix and printing it.

1.#include <stdio.h>    
2.void main ()    
3.{    
4.    int arr[3][3],i,j;     
5.    for (i=0;i<3;i++)    
6.    {    
7.        for (j=0;j<3;j++)    
8.        {    
9.            printf("Enter a[%d][%d]: ",i,j);                
10.            scanf("%d",&arr[i][j]);    
11.        }    
12.    }    
13.    printf("\n printing the elements ....\n");     
14.    for(i=0;i<3;i++)    
15.    {    
16.        printf("\n");    
17.        for (j=0;j<3;j++)    
18.        {    
19.            printf("%d\t",arr[i][j]);    
20.        }    
21.    }    
22.}    
3D Array

Declaring a 3D array:
•Specify data type, array name, block size, row size and
column size.
•Each subscript can be written within its own separate
pair of brackets.
•Syntax: data_type array_name[block_size]
[row_size][column_size];
Function calling using Recursion
• In C, When a function calls a copy of itself then the
process is known as Recursion. To put it short, when a
function calls itself then this technique is known as
Recursion. And the function is known as a recursive
function.
• You have to be more careful when you are using recursion
in your program. You just cannot use recursion in all your
problems because it will make your program more
complex and difficult.
• Recursion can be used in case of similar subtasks like
sorting, searching, and traversal problems. While using
recursion, you will have to define an exit condition on that
function, if not then it will go into an infinite loop.
ashish0751@gmail.com
Example: Sum of Natural Numbers Using Recursion
This exit condition inside a recursive function is known as base condition.
int sum(int n)
{
if(n==1) //Base Condition
return 1;
return n+ sum(n-1); // Function calling itself
}
Factorial using Recursion
1.#include<stdio.h>  
2.  
3.long factorial(int n)  
4.{  
5.  if (n == 0)  
6.    return 1;  
7.  else  
8.    return(n * factorial(n-1));  
9.}  
10.   
11.void main()   Enter a number: 6 Factorial of 5 is: 720
12.{  
13.  int number;  
14.  long fact;  
15.  printf("Enter a number: ");  
16.  scanf("%d", &number);   
17.   
18.  fact = factorial(number);  
19.  printf("Factorial of %d is %ld\n", number, fact);  
20.  return 0;  
21.}  
ashish0751@gmail.com
Stack
Stack
 Stack is an abstract data type with a bounded(predefined) capacity. It is a simple data structure that allows adding and
removing elements in a particular order.

 A stack is an abstract data type that holds an ordered, linear sequence of items. A stack is a last in, first out (LIFO)
structure.

 A real-life example is a stack of plates: you can only take a plate from the top of the stack, and you can only add a plate
to the top of the stack. If you want to reach a plate that is not on the top of the stack, you need to remove all of the
plates that are above that one. In the same way, in a stack data structure, you can only access the element on the top of
the stack. The element that was added last will be the one to be removed first. Therefore, to implement a stack, you
need to maintain a pointer to the top of the stack (the last element to be added).

 Every time an element is added, it goes on the top of the stack and the only element that can be removed is the element
that is at the top of the stack.
ashish0751@gmail.com
Basic features of Stack

1. Stack is an ordered list of similar data type.

2. Stack is a LIFO (Last in First out) structure or we can say FILO(First in Last out).

3. push() function is used to insert new elements into the Stack and pop() function is used to remove an element
from the stack. Both insertion and removal are allowed at only one end of Stack called Top.
4. Stack is said to be in Overflow state when it is completely full and is said to be in Underflow state if it is
completely empty.

ashish0751@gmail.com
The main stack operations are

push(data) adds an element to the top of the stack

pop() removes an element from the top of the stack

peek() returns a copy of the element on the top of the stack


without removing it
is_empty() checks whether a stack is empty

is_full() checks whether a stack is at maximum capacity when


stored in a static (fixed-size) structure

ashish0751@gmail.com
Stack and array

Stacks differ from the arrays in a way that in arrays random access is possible; this means that we can access any
element just by using its index in the array. Whereas, in a stack only limited access is possible and only the top
element is directly available.

Consider an array, arr = [1, 2, 3, 4]. To access 2, we can simply write arr[1], where 1 is the index of the array
element, 2. But if the same is implemented using a stack, we can only access the topmost element that is 4.

ashish0751@gmail.com
Applications of Stack
1. Balancing of symbols: Stack is used for balancing a symbol. For example, we have the following program:
int main()  
a) {  
b)    cout<<"Hello";  
c)    cout<<"javaTpoint";  
d) }  
each program has an opening and closing braces; when the opening braces come, we push the braces in a stack, and when the closing braces appear, we pop the
opening braces from the stack. Therefore, the net value comes out to be zero. If any symbol is left in the stack, it means that some syntax occurs in a program.

2. String reversal: Stack is also used for reversing a string. For example, we want to reverse a "javaTpoint" string, so we can achieve this with the help of a stack.
First, we push all the characters of the string in a stack until we reach the null character. After pushing all the characters, we start taking out the character one by one
until we reach the bottom of the stack.

3. UNDO/REDO: It can also be used for performing UNDO/REDO operations. For example, we have an editor in which we write 'a', then 'b', and then 'c'; therefore,
the text written in an editor is abc. So, there are three states, a, ab, and abc, which are stored in a stack. There would be two stacks in which one stack shows UNDO
state, and the other shows REDO state.

4. Recursion: The recursion means that the function is calling itself again. To maintain the previous states, the compiler creates a system stack in which all the
previous records of the function are maintained.

5. . DFS (Depth First Search): This search is implemented on a Graph, and Graph uses the stack data structure.
6. Backtracking: Suppose we have to create a path to solve a maze problem. If we are moving in a particular path, and we realize that we come on the wrong way. In
order to come at the beginning of the path to create a new path, we have to use the stack data structure.

7. Expression conversion: Stack can also be used for expression conversion. This is one of the most important applications of stack. The list of the expression
conversion is given below:. Infix to prefixInfix to postfixPrefix to infixPrefix to postfixPostfix to infix

8. Memory management: The stack manages the memory. The memory is assigned in the contiguous memory blocks. The memory is known as stack memory as all
the variables are assigned in a function call stack memory. The memory size assigned to the program is known to the compiler. When the function is created, all its
ashish0751@gmail.com
variables are assigned in the stack memory. When the function completed its execution, all the variables assigned in the stack are released.
Implementation of Stack Data Structure

Stack can be easily implemented using an Array or a Linked List. Arrays are quick, but are limited in
size and Linked List requires overhead to allocate, link, unlink, and deallocate, but is not limited in size.
Here we will implement Stack using array.
Analysis of Stack Operations
Below mentioned are the time complexities for various operations that can be performed on the Stack
data structure.
•Push Operation : O(1)
•Pop Operation : O(1)
•Top Operation : O(1)
•Search Operation : O(n)
The time complexities for push() and pop() functions are O(1) because we always have to insert or
remove the data from the top of the stack, which is a one step process.

ashish0751@gmail.com
Algorithm for PUSH and POP Operation
PUSH
begin procedure push: stack, data

if stack is full
return null
endif

top ← top + 1
stack[top] ← data

end procedure

POP
 The steps involved in the POP operation is given begin procedure pop: stack
below:
if stack is empty
 Before deleting the element from the stack, we check
whether the stack is empty.
return null
endif
 If we try to delete the element from the empty stack, then
the underflow condition occurs. data ← stack[top]
 If the stack is not empty, we first access the element top ← top - 1
which is pointed by the top return data
 Once the pop operation is performed, the top is
decremented by 1, i.e., top=top-1.
end procedure
ashish0751@gmail.com
ashish0751@gmail.com
Programming code (Stack) 23 int main(){ 46 void push(){
24 printf("STATIC ARRAY (Total Capacity: %d)\
1 // Implementing Static Stack using an n", N); 47 // Checking overflow state
Array in C 2 25 int choice;26
3 #include <stdio.h> 27 while(1){ 48 if(top == N-1)
4 #include <stdlib.h> 28 printf("\nChoose any of the following
5 #include <stdbool.h> 6
49 printf("Overflow State: can't add
options:\n");
7 // N will be the capacity of the Static 29 printf(" 0: Exit 1: Push 2: Pop more elements into the stack\n");
Stack 3: Peek\n");
8 #define N 1000 9
50 else{
30 printf(" 4: Check if the stack is empty 5:
10 // Initializing the top of the stack to be -1 Check if the stack is full\n\n"); 51 int x;
11 int top = -1;12 31 scanf("%d", &choice);
13 // Initializing the stack using an array 52 printf("Enter element to be pushed
14 int stack[N];15 33 switch(choice){ into the stack: ");
16 // Function prototypes 34 case 0: exit(0);
17 void push(); // Push element to the 35 case 1: push(); break; 53 scanf("%d", &x);
top of the stack 36 case 2: pop(); break;
18 int pop(); // Remove and return the 37 case 3: peek(); break; 54 top+=1;
top most element of the stack 38 case 4: isEmpty(); break;
19 int peek(); // Return the top most 39 case 5: isFull(); break;
55 stack[top] = x;
element of the stack 40 default: printf("Please choose a correct 56 }
20 bool isEmpty(); // Check if the stack is option!");
in Underflow state or not 41 } 57 }
21 bool isFull(); // Check if the stack is in 42 }
Overflow state or not 43 return 0; 58
44 }

ashish0751@gmail.com
78 bool isEmpty(){
79 if(top == -1){
59 int pop(){ 80 printf("Stack is empty: Underflow
State\n");
60 // Checking underflow state
81 ; return true;
61 if(top == -1) 82 }
62 printf("Underflow State: Stack 83 printf("Stack is not empty\n"); 87 bool isFull(){
already empty, can't remove any 84 return false; 88 if(top == N-1){
element\n"); 85 } 89 printf("Stack is full: Overflow
63 else{ State\n");
64 int x = stack[top]; 90 return true;
65 printf("Popping %d out of the 91 }
72 int peek(){
stack\n", x); 92 printf("Stack is not full\n");
66 top-=1; 73 int x = stack[top]; 93 return false;
67 return x; 74 printf("%d is the top most 94 }
68 } element of the stack\n", x);
69 return -1;
75 return x;
70 }
ashish0751@gmail.com
76 }
Arithmetic expression

ashish0751@gmail.com
Arithmetic Expressions
• Arithmetic Expressions involve constants and operations.
• An expression can be written with constants, variables, and symbols that can act as an operator or parenthesis.
All this expression needs to follow a specific set of rules. According to this rule, the parsing of the expression
is done based on grammar. 
• An arithmetic expression is expressed in the form of Notation. Now, there are three ways to write an
expression in Arithmetics:
• Infix Notation
• Prefix (Polish) Notation
• Postfix (Reverse-Polish) Notation
• Binary operations have different levels of precedence and association .
• First : Exponentiation (^)
• Second: Multiplication (*) and Division (/)
• Third : Addition (+) and Subtraction (-)

ashish0751@gmail.com
Example
• Evaluate the following Arithmetic Expression:
5 ^ 2 + 3 * 5 – 6 * 2 / 3 + 24 / 3 + 3
• First:
25 + 3 * 5 – 6 * 2 / 3 + 24 / 3 + 3
• Second:
25 + 15 – 4 + 8 + 3
• Third:
47

Q. 1 + 2*3 + 30/5
=1+ (2*3) + (30/5)
=1+6+6 = 13

ashish0751@gmail.com
Arithmetic Expressions
1. Infix Notation
Infix is the day to day notation that we use of format A + B type. The general form can be classified as (a op
b) where a and b are operands(variables) and op is Operator. <operands> <operators> <operands> 
•Example 1 : A + B
•Example 2 : A * B + C / D

2. Postfix Notation
Postfix is notation that compiler uses/converts to while reading left to right and is of format AB+ type. The general form can
be classified as (ab op) where a and b are operands(variables) and op is Operator.
•Example 1 : AB+
•Example 2 : AB*CD/+

3. Prefix Notation
Prefix is notation that compiler uses/converts to while reading
right to left (some compilers can also read prefix left to right)
and is of format +AB type. The general form can be classified
as (op ab) where a and b are operands(variables) and op is
Operator. <operators> <operands> <operands> 
•Example 1 : +AB
•Example 2 : +*AB/CD
ashish0751@gmail.com
Postfix and Prefix Examples

INFIX POSTFIX PREFIX


A+B AB + + A B
A*B+C AB * C + + * A B C
A * (B + C) AB C + * * A + B C
A - (B - (C - D)) -A-B-C D
A-B-C-D AB C D---
A B-C-D- ---A B C D

Prefix : Operators come before


the operands

ashish0751@gmail.com
Examples ( Infix to Prefix Notation)

• (A + B) * C = * + ABC

• A + (B * C) = + A *BC

• (A + B) / (C - D) = / +AB –CD

ashish0751@gmail.com
Infix to Postfix
Method-1
Method-2

A * B + C  ((A * B) + C) A * (B + C)  (A * (B + C) )
 ((A B * C +  (A (B C + *
ashish0751@gmail.com
 A B * C +  A B C + *
Infix to Postfix

Infix Postfix
A+B AB+
A+B*C ABC*+
(A + B) * C AB+C*
A+B*C+D ABC*+D+
(A + B) * (C + D) AB+CD+*
A*B+C*D AB*CD*+

• • A+B* C+D
A+B*C
•  ((A + (B * C)) + D )
•  (A + (B * C)) •  ((A + (B C*) )+ D)
•  (A + (B C *) ) •  ((A B C *+) + D)
•  A B C * + • ABC*+D+
Infix to postfix conversion using stack

**Requires operator precedence information


1. Print operands as they arrive.
2. If the stack is empty or contains a left parenthesis on top, push the incoming operator onto the stack.
3. If the incoming symbol is a left parenthesis, push it on the stack.
4. If the incoming symbol is a right parenthesis, pop the stack and print the operators until you see a left
parenthesis. Discard the pair of parentheses.
5. If the incoming symbol has higher precedence than the top of the stack, push it on the stack.
6. If the incoming symbol has equal precedence with the top of the stack, use association. If the association is left
to right, pop and print the top of the stack and then push the incoming operator. If the association is right to left,
push the incoming operator.
7. If the incoming symbol has lower precedence than the symbol on the top of the stack, pop the stack and print the
top operator. Then test the incoming operator against the new top of stack.
8. At the end of the expression, pop and print all operators on the stack. (No parentheses should remain.)

Reference: Debasis Samanta, Computer Science & Engineering, Indian Institute of Technology Kharagpur
Infix to Postfix using stack
Current Operator Postfix string
Expression: symbol Stack
1 A   A
A * (B + C * D) + E 2 * * A
3 ( *( A
becomes
4 B *( AB

ABC D* +*E+ 5 + *(+ AB


6 C *(+ ABC
7 * *(+* ABC
8 D *(+* ABCD
Postfix notation is also called as 9 ) * ABCD*+
Reverse Polish Notation (RPN)
10 + + ABCD*+*
11 E + ABCD*+*E
12     ABCD*+*E+
Infix to Postfix using stack
A+(B*C–(D/E↑F)*G)*H
Symbol Scanned Stack Expression P
A ( A
+ ( + A
( ( + ( A
B ( + ( AB
* ( + ( * AB
C ( + ( * ABC
- ( + ( - ABC*
( ( + ( - ( ABC*
D ( + ( - ( ABC*D
/ ( + ( - ( / ABC*D
E ( + ( - ( / ABC*DE

ashish0751@gmail.com
↑ ( + ( - ( / ↑ ABC*DE
Continue…

A+(B*C–(D/E↑F)*G)*H
Symbol Scanned Stack Expression P
F ( + ( - ( / ↑ ABC*DEF
) ( + ( - A B C * D E F ↑/
* ( + ( - * A B C * D E F ↑/
G ( + ( - * A B C * D E F ↑/ G
) ( + A B C * D E F ↑/ G * -
* ( + * A B C * D E F ↑/ G * -
H ( + * A B C * D E F ↑/ G * - H
) A B C * D E F ↑/ G * - H * +

ashish0751@gmail.com
Infix to prefix using stack
Sr. no. Expression Stack Prefix
Given Infix - ((a/b)+c)-(d+(e*f)) 0 ( ((  
1 ( (((  
•Step 1: Reverse the infix string. Note that while 2 f ((( f

reversing the string you must interchange left and right 3 * (((* f
4 e (((* fe
parentheses.
5 ) (( fe*
•Step 2: Obtain the postfix expression of the infix
6 + ((+ fe*
expression Step 1.
7 d ((+ fe*d
•Step 3: Reverse the postfix expression to get the
8 ) ( fe*d+
prefix expression
9 – (- fe*d+
10 ( (-( fe*d+
This is how you convert manually for theory 11 c (-( fe*d+c
question in the exam 12 + (-(+ fe*d+c
1.String after reversal – ))f*e(+d(-)c+)b/a(( 13 ( (-(+( fe*d+c
2.String after interchanging right and left 14 b (-(+( fe*d+cb
parenthesis – ((f*e)+d)-(c+(b/a)) 15 / (-(+(/ fe*d+cb
3.Apply postfix conversion algorithm using stack 16 a (-(+(/ fe*d+cba
4.Reverse Postfix Expression (Given After the table 17 ) (-(+ fe*d+cba/
below) 18 ) (- fe*d+cba/+
19 )   fe*d+cba/+-

Final prefix: -+/abc+d*ef


ashish0751@gmail.com
Evaluating Postfix (RPN) Expressions
"By hand" (Underlining technique):
1. Scan the expression from left to right to find an operator.
2. Locate ("underline") the last two preceding operands
and combine them using this operator.
3. Repeat until the end of the expression is reached.

Example:
2 3 4 + 5 6 - - *
® 2 3 4 + 5 6 - - *
® 2 7 5 6 - - *
® 2 7 5 6 - - *
® 2 7 -1 - *
® 2 7 -1 - * ® 2 8 * ® 2 8 * ® 16
76
Evaluation of Postfix (RPN) Expression using stack

P is an arithmetic expression in Postfix Notation.

1. Add a right parenthesis “)” at the end of P.

2. Scan P from left to right and Repeat Step 3 and 4 for each element of P until the
sentinel “)” is encountered.

3. If an operand is encountered, put it on STACK.


4. If an operator @ is encountered, then:
(a) Remove the two top elements of STACK, where A is the top
element and B is the next to top element.
(b) Evaluate B @ A.
(c) Place the result of (B) back on STACK.
[End of if structure.]
[End of step 2 Loop.]
5. Set VALUE equal to the top element on STACK.
6. Exit.
ashish0751@gmail.com
ashish0751@gmail.com
Queue
What is a Queue?

 Queue is the data structure that is similar to the queue in


the real world.
 A queue is a data structure in which whatever comes
first will go out first, and it follows the FIFO (First-In-
First-Out) policy.
 Queue can also be defined as the list or collection in
which the insertion is done from one end known as
the rear end or the tail of the queue, whereas the
deletion is done from another end known as the front
end or the head of the queue.

• The real-world example of a queue is the ticket queue outside a cinema hall, where the person who enters first in the
queue gets the ticket first, and the last person enters in the queue gets the ticket at last. Similar approach is followed
in the queue in data structure.
Queue
A queue is defined as a linear data structure that is open at both ends and
the operations are performed in First In First Out (FIFO) order.

We define a queue to be a list in which all additions to the list are made at
one end, and all deletions from the list are made at the other end.  

The element which is first pushed into the order, the operation is first
performed on that.

ashish0751@gmail.com
Representation of Queue

ashish0751@gmail.com
FIFO Principle of Queue

•A Queue is like a line waiting to purchase tickets, where the first person in line is the first person served.
(i.e. First come first serve).
•Position of the entry in a queue ready to be served, that is, the first entry that will be removed from the
queue, is called the front of the queue(sometimes, head of the queue), similarly, the position of the last
entry in the queue, that is, the one most recently added, is called the rear (or the tail) of the queue. See
the below figure.

ashish0751@gmail.com
Characteristics and Representation of Queue

Characteristics of Queue:
•Queue can handle multiple data.
•We can access both ends.
•They are fast and flexible. 

Queue Representation:
Like stacks, Queues can also be represented in an array: In this
representation, the Queue is implemented using the array.
Variables used in this case are
•Queue: the name of the array storing queue elements.
•Front: the index where the first element is stored in the array
representing the queue.
•Rear: the index where the last element is stored in an array
representing the queue.
ashish0751@gmail.com
Applications of Queue
 Queue, as the name suggests is used whenever we need to manage any group of objects in an
order in which the first one coming in, also gets out first while the others wait for their turn,
like in the following scenarios:
 Printers: Queue data structure is used in printers to
maintain the order of pages while printing.
 Interrupt handling in computes: The interrupts are
operated in the same order as they arrive, i.e., interrupt
which comes first, will be dealt with first.
 Process scheduling in Operating systems: Queues
are used to implement round-robin scheduling
algorithms in computer systems.
 Switches and Routers: Both switch and router
interfaces maintain ingress (inbound) and egress
(outbound) queues to store packets.
 Customer service systems: It develops call center
phone systems using the concepts of queues.
ashish0751@gmail.com
Basic Operations of Queue

A queue is an object (an abstract data structure - ADT) that

allows the following operations:

•Enqueue: Add an element to the end of the queue

•Dequeue: Remove an element from the front of the queue

•IsEmpty: Check if the queue is empty

•IsFull: Check if the queue is full

•Peek: Get the value of the front of the queue without removing

it ashish0751@gmail.com
Queue operations
Enqueue Dequeue
The Enqueue operation is used to add The Dequeue operation is used to
an element to the front of the queue. remove an element from the rear of the
Steps of the algorithm: queue.
1.Check if the Queue is full. Steps of the algorithm:
2.Set the front as 0 for the first 1.Check if the Queue is empty.
element. 2.Return the value at the front index.
3.Increase rear by 1. 3.Increase front by 1.
4.Add the new element at 4.Set front and rear as -1 for the last
the rear index.
ashish0751@gmail.com
element.
Queue operations
Peek isFull
The Peek operation is The isFull operation is used to check if the queue is
used to return the full or not.
Steps of the algorithm:
front most element of
1.Check if the number of elements in the queue
the queue. (size) is equal to the capacity, if yes, return True.
Steps of the 2.Return False.
algorithm:
1.Check if the Queue isEmpty
is empty. The isEmpty operation is used to check if the queue
2.Return the value at is empty or not.
the front index. Steps of the algorithm:
1.Check if the number of elements in the queue (size)
is equal to 0, if yes, return True.
2.Return False.
ashish0751@gmail.com
Enqueue() Operation
•Step 1: Check if the queue is full.
•Step 2: If the queue is full, Overflow
error.
•Step 3: If the queue is not full,
increment the rear pointer to point to
the next available empty space. 
•Step 4: Add the data element to the
queue location where the rear is
pointing.
•Step 5: Here, you have successfully
added 7, 2, and -9.
ashish0751@gmail.com
ashish0751@gmail.com
Major drawback of using a linear Queue

• The major drawback of using a linear Queue is that insertion is done only
from the rear end. If the first three elements are deleted from the Queue, we
cannot insert more elements even though the space is available in a Linear
Queue.
• In this case, the linear Queue shows the overflow condition as the rear is
pointing to the last element of the Queue.
#include<stdio.h>
#include<stdlib.h> switch(choice)
#define maxsize 3 {
void insert(); case 1:
void delete(); insert();
void display(); break;
int front = -1, rear = -1; case 2:
int queue[maxsize]; delete();
void main () break;
{ case 3:
int choice=1; display();
while(choice == 1) break;
{ case 4:
printf("\ exit(0);
n*************************Main break;
Menu*****************************\n"); default:
printf("\ printf("\nEnter valid choice??\n");
n============================================ }
=====================\n"); printf("do you want to repeat
printf("\n1.insert an element\ operations");
n2.Delete an element\n3.Display the queue\ scanf("%d",&choice);
n4.Exit\n"); }
printf("\nEnter your choice ?"); }
scanf("%d",&choice);
void insert() void delete()
{ {
int item; int item;
printf("\nEnter the element\n"); if (front == -1 || front > rear)
{
scanf("\n%d",&item);
printf("\nUNDERFLOW\n");
if(rear == maxsize-1) return; 
{ }
printf("\nOVERFLOW\n"); else
{
return;
item = queue[front];
} if(front == rear)
if(front == -1 && rear == -1) {
{ front = 0; front = -1;
rear = -1 ;
rear = 0;
}
} else
else {
{ front = front + 1;
rear = rear+1; }
} printf("\nvalue deleted ");
queue[rear] = item; } 
printf("\nValue inserted ");  
}
 }
 
void display()
{
int i;
if(rear == -1)
{
printf("\nEmpty queue\n");
}
else
{ printf("\nprinting values .....\n");
for(i=front;i<=rear;i++)
{
printf("\n%d\n",queue[i]);
}
}
}
Priority Queues
• Priority Queue is an abstract data type that is similar to a queue, and every element has some priority value
associated with it.
• The priority of the elements in a priority queue determines the order in which elements are served (i.e., the
order in which they are removed).
• If in any case the elements have same priority, they are served as per their ordering in the queue.
• A priority queue is a special type of queue in which each element is associated with a priority value. And,
elements are served on the basis of their priority. That is, higher priority elements are served first.

Difference between Priority Queue and Normal


Queue
In a queue, the first-in-first-out rule is implemented
whereas, in a priority queue, the values are
removed on the basis of priority. The element with
the highest priority is removed first.
Characteristics of a Priority Queue
•Each item in the queue must have a priority associated
with it.
•Higher or lower priority elements must be dequeued
before lower or higher priority elements respectively
depending on priority order taken by user that is if user
consider lower number as higher priority or higher number
as higher priority.
•Complexity of Priority queue
•If two elements in the queue have the same priority value • Insertion : O(log n)O(logn)
• Peek : O(1)O(1)
then the first in first out rule is followed for these two • Deletion : O(log n)O(logn
elements alone i.e. the element that entered the priority
queue first will be the first to be removed.
Lists, Dictionaries, Sets, and Tuples
Python Collections are used to store data, for example, lists, dictionaries, sets, and tuples, all of which are
built-in collections.
Lists Tuples Sets Dictionaries

A tuple is A dictionary is
A list is a collection A set is an unordered collection
of ordered data. an ordered collection of an unordered collection. of data that stores data
data. in key-value pairs

Sets are mutable and Dictionaries are mutable


Lists are mutable. Tuples are immutable. have no duplicate and keys do not allow
elements. duplicates.

Dictionaries are
Lists are declared with Tuples are enclosed Sets are represented in enclosed in curly
square braces. within parenthesis. curly brackets. brackets in the form of
key-value pairs.
list1=[1,4,"Gitam",6,"college"]
list2=[]  # creates an empty list
list3=list((1,2,3))
print(list1) Output
print(list2) [1, 4, 'Gitam', 6, 'college’]
print(list3) []
[1, 2, 3]

tuple1=(1,2,"college",9)
tuple2=() # creates an empty tuple
tuple3=tuple((1,3,5,9,"hello"))
print(tuple1) Output
(1, 2, 'college', 9)
print(tuple2) ()
print(tuple3) (1, 3, 5, 9, 'hello')
set1={1,2,3,4,5,"hello","tup"} Output
set2={(1,8,"python",7)} {1, 2, 3, 4, 5}
print(set1) {1, 3, 6, 7}
print(set2)

dict1={"key1":1,"key2":"value2",3:"value3"}
print(dict1.keys())  # all the keys are
printed
Output
print(dict1.values()) # all the values are
dict_keys(['key1', 'key2', 3])
printed
dict_values([1, 'value2', 'value3'])
dict1["key1"]="replace_one"  # value
{'key1': 'replace_one', 'key2':
assigned to key1 is replaced
'value2', 3: 'value3'} value2
print(dict1)
print(dict1["key2"])
List
A list is an ordered data structure with elements separated by a comma and enclosed within square brackets. For
example, list1 and list2 shown below contains a single type of data.

list1 = ["apple", "banana", "cherry"]
list2 = [1, 5, 7, 9, 3]
list3 = [True, False, False]
list1 = ["abc", 34, True, 40, "male"]

thislist = ["apple", "banana", "cherry"]
print(thislist[1]) output---banana
ashish0751@gmail.com
Dr. Ashish Kumar
ashish0751@gmail.com
VIPS-TC
Linear search program in C
#include <stdio.h>
1. Linear Search int main()
{
  int array[9];
int search, c, n;
for (c = 0; c < n; c++)   for(c=0;c<10;c++)
  { {
    if (array[c] == search)    /* If printf("Enter element”);
required element is found */
Scanf(“%d”,&array[c]);
    {
      printf("%d is present at location
%d.\n", search, c+1);
      break;
    }
  }
  if (c == n)   scanf("%d", &n);
    printf("%d isn't present in the array.\     for (c = 0; c < n; c++)
n", search);
    scanf("%d", &array[c]);
  return 0;
}   printf("Enter a number to search\n");
  scanf("%d", &search);  
2. Binary Search
Binary Search Algorithm: The basic steps to perform Binary Search are:
•Begin with an interval covering the whole array. (Array is Sorted)
•If the value of the search key is less than the item in the middle of the interval, narrow the interval to the lower half.
•Otherwise, narrow it to the upper half.
•Repeatedly check until the value is found or the interval is empty.
Binary Search

low = 0;
#include <stdio.h> high = n - 1;
mid = (low+high)/2;
int main()
{ while (low <= high) {
if(array[mid] < key)
int i, low, high, mid, n, key, low = mid + 1;
array[100];
printf("Enter number of elementsn"); else if (array[mid] == key) {
scanf("%d",&n); printf("%d found at location %d.n", key, mid+1);
printf("Enter %d integersn", n); break;
for(i = 0; i < n; i++) }
scanf("%d",&array[i]); else
printf("Enter value to findn"); high = mid - 1;
scanf("%d", &key); mid = (low + high)/2;
}
if(low > high)
printf("Not found! %d isn't present in the list.n", key);
return 0;
}
3. Insertion Sort
Insertion sort is a simple sorting algorithm that works similar to the
way you sort playing cards in your hands. The array is virtually split
into a sorted and an unsorted part. Values from the unsorted part are
picked and placed at the correct position in the sorted part.
Algorithm 
To sort an array of size n in ascending order: 
1: Iterate from arr[1] to arr[n] over the array. 
2: Compare the current element (key) to its predecessor. 
3: If the key element is smaller than its predecessor, compare it to
the elements before. Move the greater elements one position up to
make space for the swapped element.
Insertion Sort
Bubble Sort
Bubble sort
Bubble Sort
Selection Sort
Selection Sort
Selection sort program in C for (c = 0; c < (n - 1); c++) 
#include <stdio.h>
int main()   {
{
    position = c;
  int array[100], n, c, d, position, t;
  printf("Enter number of elements\n");     for (d = c + 1; d < n; d++)
  scanf("%d", &n);     {
  printf("Enter %d integers\n", n);       if (array[position] > array[d])
  for (c = 0; c < n; c++)         position = d;
    scanf("%d", &array[c]);     }
       if (position != c)
    {
      t = array[c];
      array[c] = array[position];
      array[position] = t;
    }
  }
  printf("Sorted list in ascending order:\
n");
  for (c = 0; c < n; c++)
    printf("%d\n", array[c]);
  return 0;
}
Quick Sort

QuickSort is a Divide and Conquer algorithm. It


picks an element as a pivot and partitions the
given array around the picked pivot. There are
many different versions of quick Sort that pick
pivot in different ways. 
•Always pick the first element as a pivot.
•Always pick the last element as a pivot
(implemented below)
•Pick a random element as a pivot.
•Pick median as the pivot.

https://www.geeksforgeeks.org/quick-sort/
ashish0751@gmail.com
int main()
{
Quick Sort #include <stdio.h>
void swap(int *p, int *q)

int n, i; {
void quickSort(int a[], int low, int high) int temp = *p;
printf("What is the size of the
{ *p = *q;
array?\n");
if (low < high) *q = temp;
scanf("%d",&n);
{ }
int a[n]; int k = partition(a, low, high); int partition(int a[], int low, int high)
printf("Enter elements of quickSort(a, low, k - 1); {
the array one by one\n"); quickSort(a, k + 1, high); int pivot = a[high];
for(i = 0; i < n; i++) } int i = (low - 1);
{ }
for (int j = low; j <= high- 1; j++)
scanf("\n%d",&a[i]); {
void print(int a[], int size)
} if (a[j] <= pivot)
{
{
quickSort(a, 0, n - 1);
int i;
i++;
printf("Sorted array: "); for (i = 0; i < size; i++)
swap(&a[i], &a[j]);
print(a, n); printf("%d ", a[i]);
}
return 0; printf("\n");
}
} }
swap(&a[i + 1], &a[high]);
return (i + 1);
}

ashish0751@gmail.com
Quick Sort Algorithm
1.The divide-and-conquer strategy is used in quicksort. Below the recursion step is described: Choose a pivot value. We take the value of the middle element as

pivot value, but it can be any value, which is in range of sorted values, even if it doesn't present in the array.

2.Partition. Rearrange elements in such a way, that all elements which are lesser than the pivot go to the left part of the array and all elements greater than the

pivot, go to the right part of the array. Values equal to the pivot can stay in any part of the array. Notice, that array may be divided in non-equal parts.

3.Sort both parts. Apply quicksort algorithm recursively to the left and the right parts.

The algorithm rearranges the unsorted list by picking a pivot value and rearranging the list so that values that are lower than the pivot value are positioned before

it in the list, and values that are higher than the pivot value are positioned after it in the list. To rearrange the values, the low mark and high mark are used.

4. As the list is checked, the low mark is moved up over values that are lower than the pivot value. Once the low mark reaches a value that is higher than the

pivot value, it stops in that place and the algorithm proceeds to examine the high mark.

5. The high mark is moved down over values that are higher than the pivot value. If the high mark reaches a value that is lower than the pivot value, the

algorithm swaps the values of the low mark and the high mark.

6. The process continues until the high mark overlaps with the low mark, which indicates the new position for the pivot value. Sometimes the pivot value is

already in that
ashish0751@gmail.com position.
Radix sort
The algorithm is named radix sort as it specifies the radix r to be used which
changes how the sort is performed. The radix, or base, of the number system is
the number of digits that represent a single position in the number; a radix of 2
is binary (0-1), 10 is decimal (0-9), 16 is hexadecimal (0-F) and so on. Radix
Sort is a linear sorting algorithm. The algorithm based on idea that sorting the
elements by first grouping the individual digits of the same place value. Radix
sort depends on the digits or letters, so it is less flexible than other sorts.
Radix Sort Algorithm
1.Take the least significant digit of each element.
2.Sort the list of elements based on that digit, but keep the order of elements
with the same digit.
3.Repeat the sort with each more significant digit.
The speed of the Radix sort depends on the inner basic operations.
If the operations are not efficient enough, Radix sort can be slower than other
algorithms such as Quick Sort and Merge Sort.
ashish0751@gmail.com
https://www.growingwiththeweb.com/sorting/radix-sort-lsd/
Radix sort

Advantages of Radix Sort


1.Fast when the keys are short i.e when the range of the array
elements is less. Time and Space Complexity of Radix Sort
2.Used in suffix array construction algorithms like Manber’s Time Complexity
algorithm and DC3 algorithm.
Worst Case O(nk)
Disadvantages of Radix Sort
Best Case O(nk)
3.Radix Sort depends on digits or letters, so it is less flexible
Average Case O(nk)
than other sorts.
Space Complexity
4.The constant for Radix sort is greater compared to other
Worst Case O(n+k)
sorting algorithms.
5.It takes more space compared to Quick sort which is inplace
sorting.
ashish0751@gmail.com
Merge Sort: Divide-and-Conquer
• Divide and Conquer is more than just a military strategy; it is also a method
of algorithm design that has created such efficient algorithms as Merge Sort.

• In terms or algorithms, this method has three distinct steps:

• Divide: If the input size is too large to deal with in a straightforward


manner, divide the data into two or more disjoint subsets.
• Recur: Use divide and conquer to solve the subproblems associated with
the data subsets.
• Conquer: Take the solutions to the subproblems and “merge” these
solutions into a solution for the original problem.

Merge sort is one of the efficient & fastest sorting algorithms with the following time complexity:
Worst Case Time Complexity: O(n*logn)
Best Case Time Complexity: O(n*log n)
Average Time Complexity: O(n*log n)
Given: Arr(5, 8, 3, 9, 1, 2)
•We split the array into two halves Arr1 = (5, 8, 3) and Arr2 = (9, 1, 2).
•Again, we divide them into two halves: Arr3 = (5, 8) and Arr4 = (3) and
Arr5 = (9, 1) and Arr6 = (2)
•Again, we divide them into two halves: Arr7 = (5), Arr8 = (8), Arr9 =
(9), Arr10 = (1) and Arr6 = (2)
•We will now compare the elements in these sub arrays in order to
merge them.

Merge Sort Algorithm:


step 1: start

step 2: declare array and left, right, mid variable

step 3: perform merge function.


if left > right
return
mid= (left+right)/2
mergesort(array, left, mid)
mergesort(array, mid+1, right)
merge(array, left, mid, right)

step 4: Stop
#include <stdio.h>  void sort(int low, int high) { void merging(int low, int mid, int high)
#define max 10  int mid; {
int a[11] = { 10, 14, 19, 26, 27, int l1, l2, i; 
 
31, 33, 35, 42, 44, 0 };
if(low < high) { for(l1 = low, l2 = mid + 1, i = low; l1
int b[10]; <= mid && l2 <= high; i++) {
int main() mid = (low + high) / 2;
if(a[l1] <= a[l2])
{ sort(low, mid);
b[i] = a[l1++];
int i;  sort(mid+1, high); else
printf("List before sorting\ merging(low, mid, high);
n");  b[i] = a[l2++];
} else { } 
for(i = 0; i <= max; i++)
printf("%d ", a[i]);
return; while(l1 <= mid)

  } b[i++] = a[l1++]; 

sort(0, max);  } while(l2 <= high)


printf("\nList after sorting\ b[i++] = a[l2++]; 
n");
for(i = low; i <= high; i++)
  for(i = 0; i <= max; i++)
a[i] = b[i];
printf("%d ", a[i]);

}
Heap sort
• Heap sort processes the elements by creating the min-heap or max-heap using
the elements of the given array.

• Min-heap or max-heap represents the ordering of array in which the root element
represents the minimum or maximum element of the array.

• Max heap is a complete binary tree. A complete binary tree is a binary tree in
which all levels are completely filled and all the nodes in the last level are as left
as possible. 

• also meets this criteria: the parent’s key is larger than both children’s keys. The
Max heap should largest value is at the root. Heap is related to priority Heap sort

queue and heapsort.
Heap sort basically recursively performs two main operations -
Algorithm 1: Algorithm 2:
•Build a heap H, using the elements of array. Insertion Heapify +
•Repeatedly delete the root element of the heap formed in 1st phase. +Deletion Deletion
ashish0751@gmail.com
Algorithm1: Max Heap Construction Algorithm
We shall use the same example to demonstrate how a Max Heap is created. The procedure to create Min Heap is
similar but we go for min values instead of max values. We are going to derive an algorithm for max heap by inserting
one element at a time. At any point of time, heap must maintain its property.

While insertion, we also assume that we are inserting


a node in an already heapified tree.
Step 1 − Create a new node at the end of heap.
Step 2 − Assign new value to the node.
Step 3 − Compare the value of this child node with its
parent.
Step 4 − If value of parent is less than child, then swap
them.
Step 5 − Repeat step 3 & 4 until Heap property holds.
ashish0751@gmail.com
Heap: Insertion of node

ashish0751@gmail.com
Max Heap Deletion Algorithm

Let us derive an algorithm to delete from max heap.


Deletion in Max (or Min) Heap always happens at the
root to remove the Maximum (or minimum) value.
Step 1 − Remove root node.
Step 2 − Move the last element of last level to root.
Step 3 − Compare the value of this child node with its
parent.
Step 4 − If value of parent is less than child, then swap
them.
Step 5 − Repeat step 3 & 4 until Heap property holds.

ashish0751@gmail.com
After Inserting all
the node,
Deletion Starts
with root node

ashish0751@gmail.com
ashish0751@gmail.com
Algotithm-2 (part 1:Heapify )

• Create a complete tree with a given array


• Start with last leaf node parent.
• At parent node check the max heap node
conditions.
• now after the adjustment go to second last
leaf node and find the parent and apply
heapify method and so on…

Algotithm-2 (part
ashish0751@gmail.com 2:Delete procedure is same, refer previous slided)
Max-heap implementation – Insertion algorithm

ashish0751@gmail.com
Summary of Sorting Algorithms
Algorithm Time Notes
 in-place
selection-sort O(n2)  slow (good for small inputs)

 in-place
insertion-sort O(n2)  slow (good for small inputs)

quick-sort O(n log n)  in-place, randomized


expected  fastest (good for large inputs)

 in-place
heap-sort O(n log n)  fast (good for large inputs)

 sequential data access


merge-sort O(n log n)  fast (good for huge inputs)
Heap Sort
• Advantages of heapsort:
• Efficiency –  The time required to perform Heap sort increases logarithmically
while other algorithms may grow exponentially slower as the number of items to
sort increases. This sorting algorithm is very efficient.
• Memory Usage – Memory usage is minimal because apart from what is necessary
to hold the initial list of items to be sorted, it needs no additional memory space to
work
• Simplicity –  It is simpler to understand than other equally efficient sorting
algorithms because it does not use advanced computer science concepts such as
recursion

ashish0751@gmail.com
Deletion

ashish0751@gmail.com
Linked List
ashish0751@gmail.com
Pointer
Fun with Pointers

134
Introduction to structure
 A structure is a user defined data type : collection of
variables under a single name.

 Arrays allow to define type of variables that can hold several


data items of the same kind.

 structure is another user defined data type available in C that


allows to combine data items of different kinds.

 A structure is a convenient way of grouping several pieces of


related information together and for handling a group of
logically related data items.

 For example: name, roll, fee, marks, address, gender and


phone are related information of a student.
Revision
ashish0751@gmail.com
Defining a structure ( Structure declaration)

• A structure is a collection of one or more variables,


possibly of different types, grouped together under struct structure_name/tag
a single name for convenient handling. {
data_type member_variable1; // declaration of Member-1
• Structures help to organize complicated data,
data_type member_variable2; // declaration of Member-2
particularly in large programs, because they permit
data_type member_variable3; // declaration of Member-3
a group of related variables to be treated as a unit
};
instead of separate entities.

Example 1:
struct passenger
{ Example 2:
char name [20]; struct student{
int age; char name[20];
int train_no; int roll;
char board_place[20]; float marks;
char destn[20]; char remarks;
};
ashish0751@gmail.com };
e 1. struct motor p, q, r;
y p Declares and sets aside
e t
• Defines a new type f th storage for three variables ,
e o
• E.g., a m t h e p, q, and r, each of type
f
struct motor { N r s o struct motor
float volts; be t 2. struct motor M[25];
float amps; em uc Declares a 25-element array
M tr
int phases; s of struct motor;
float rpm;
allocates 25 units of storage,
}; //struct motor each one big enough to hold
the data of one motor
3. struct motor *m;
Declares a pointer to an
object of type struct
ashish0751@gmail.com
motor
Examples of structure ( Declaration &Initiation)

Ex. 1 #include<stdio.h> Ex. 3: Array


struct Point Ex. 2  struct Point of Structure
{ #include<stdio.h> {
   int x, y;  struct Point    int x, y;
}; { };
     int x, y;  int main()
int main() }; {
{  int main()    // Create an array of
   // A valid { structures
initialization. member x    struct Point p1 = {0, 1};    struct Point arr[10]; 
gets value 0 and y      // Access array members
   // gets value 1.  The    // Accessing members of point    arr[0].x = 10;
order of declaration is p1    arr[0].y = 20; 
followed.    p1.x = 20;    printf("%d %d", arr[0].x,
   struct Point p1 = {0, 1}; printf ("x = %d, y = %d", p1.x, arr[0].y);
} p1.y);    return 0;
    return 0; }
}
X=20, y=1
ashish0751@gmail.com
strcpy(person1.name, "George
Orwell");
person1.citNo = 1984;
person1. salary = 2500;

• Notice that we have


used strcpy() function to assign the
value to person1.name.
• This is because name is a char array
(C-string) and we cannot use the
assignment operator = with it after
we have declared the string.
Keyword typedef

• We use the typedef keyword to create an alias name for data types.


• It is commonly used with structures to simplify the syntax of declaring
variables.

ashish0751@gmail.com
Self Referential Structures
Self Referential structures are those structures that have one or more Types of Self Referential Structures 
pointers which point to the same type of structure, as their member.  Self Referential Structure with Single Link

struct node { 1.Self Referential Structure with Multiple Links


    int data1;
    char data2; Self Referential Structure with Single Link: These structures can have
    struct node* link;
}; only one self-pointer as their member
 
int main()
{
    struct node ob;
    return 0;
}

In the above example ‘link’ is a pointer to a structure of type ‘node’.


Hence, the structure ‘node’ is a self-referential structure with ‘link’ as
the referencing pointer. 
An important point to consider is that the pointer should be initialized
properly before accessing, as by default it contains garbage value.
#include <stdio.h>
 struct node {
    int data1;
    char data2;
    struct node* link;
};
 int main()
{
    struct node ob1; // Node1
     // Initialization
    ob1.link = NULL;
    ob1.data1 = 10;
    ob1.data2 = 20; 
    struct node ob2; // Node2 
    // Initialization
    ob2.link = NULL;
Self Referential Structure Program
    ob2.data1 = 30;
    ob2.data2 = 40; 
    // Linking ob1 and ob2
    ob1.link = &ob2;
 // Accessing data members of  ob2 using ob1
    printf("%d", ob1.link->data1);
    printf("\n%d", ob1.link->data2);
    return 0;
}
Linked List
• A linked list is a data structure which allows
to store data dynamically and manage data
efficiently.
Linked List can be defined as collection of objects
called nodes that are randomly stored in the
memory.
A node contains two fields i.e. data stored at that
particular address and the pointer which contains
the address of the next node in the memory.
The last node of the list contains pointer to the
null.
There are three common types of Linked List.
1. Singly Linked List
2. Doubly Linked List
3. Circular Linked List
Linked List (Few salient features)

• There is a pointer (called header) points the first element (also called node)

• Successive nodes are connected by pointers.

• Last element points to NULL.

• It can grow or shrink in size during execution of a program.

• It can be made just as long as required.

• It does not waste memory space, consume exactly what it needs.


1. Single Linked List
Depending on the way in which the links are used to maintain adjacency, several different types of linked lists are
possible.
Single linked list (or simply linked list) Node Creation:
• A head pointer addresses the first element of the list. typedef struct node
• Each element points at a successor element. {
• The last element has a link value NULL. int data;
struct node *link;
}node;

head

A B C NULL

145
Defining a Node of a Linked List
Each structure of the list is called a node, and consists of two fields:
• Item (or) data
• Address of the next item in the list (or) pointer to the next node in the list
How to define a node of a linked list?
typedef struct node Note:
{ node Such structures which contain a
int data; /* Data */ member field pointing to the same
struct node *next; /* pointer*/ Data structure type are called self-
}node; next referential structures.

Data Time Complexity Space


Structure Compleity

Average Worst Worst


Acces Search Insertion Deletion Access Search Insertion Deletion
s
Singly Linked θ(n) θ(n) θ(1) θ(1) O(n) O(n) O(1) O(1) O(n)
List
#include<stdio.h> node *prnt;
typedef struct node
node *head;
{
prnt=one;
int data;
Head=one;
struct node *link;
while(prnt!=NULL)
}node;
{

int main() printf("%d",prnt->data);


{ prnt=prnt->link;
node *one=(node *)malloc(1*sizeof(node)); }
node *two=(node *)malloc(1*sizeof(node)); return 0;
node *three=(node *)malloc(1*sizeof(node)); }
one->data=1;
two->data=2;
three->data=3;
one->link=two;
two->link=three;
three->link=NULL;
Double Linked List
Double linked list
• Pointers exist between adjacent nodes in both directions.
• The list can be traversed either forward or backward.
• Usually two pointers are maintained to keep track of the list, head and tail.

head tail Node Creation

A B C 1.typedef struct node   
2.{  
3.    struct node *prev;   
4.    int data;  
5.    struct node *next;   
6.} node;
Defining a Node of a Double Linked List
Each node of doubly linked list (DLL) consists of three fields:
• Item (or) Data
• Pointer of the next node in DLL
• Pointer of the previous node in DLL
node
Data
prev next

How to define a node of a doubly linked list (DLL)?


typedef struct node
{
int data;
struct node *next; // Pointer to next node in DLL
struct node *prev; // Pointer to previous node in DLL
}node;
Double Linked List
• Doubly linked list is a collection of nodes linked together in a sequential way.
• Doubly linked list is almost similar to singly linked list except it contains two
address or reference fields, where one of the address field contains reference of
the next node and other contains reference of the previous node.
• First and last node of a linked list contains a terminator generally a NULL
value, that determines the start and end of the list.
• Doubly linked list is sometimes also referred as bi-directional linked list since it
allows traversal of nodes in both direction.
• Since doubly linked list allows the traversal of nodes in both direction, we can
keep track of both first and last nodes.

150
Double versus Single Linked List

Advantages over singly linked list


1) A DLL can be traversed in both forward and backward direction.
2) The delete operation in DLL is more efficient if pointer to the node to be deleted
is given.

Disadvantages over singly linked list


3) Every node of DLL Require extra space for an previous pointer.
4) All operations require an extra pointer previous to be maintained.

151
Circular Linked List

• The pointer from the last element in the list points back to the first element.
• A circular linked list is basically a linear linked list that may be single- or double-linked.

• The only difference is that there is no any NULL value terminating the list.
• In fact in the list every node points to the next node and last node points to the first node, thus forming a circle. Since it forms a circle with
no end to stop it is called as circular linked list.

• In circular linked list there can be no starting or ending node, whole node can be traversed from any node.

• In order to traverse the circular linked list, only once we need to traverse entire list until the starting node is not traversed again.

• A circular linked list can be implemented using both singly linked list and doubly linked list.

head
A B C

152
Creating a single linked list
If we need n number of nodes in the linked list:
• Allocate n newNodes, one by one.
• Read in the data for the newNodes.
• Modify the links of the newNodes so that the chain is formed.

newNode = (struct node *)malloc(sizeof(struct node));


newNode->data = data; //Links the data field of newNode with data
newNode->next = NULL; //Links the address field of newNode with NULL

temp->next = newNode; //Links previous node i.e. temp to the newNode


temp = temp->next;

It creates n number of nodes . For e.g. if the data entered is 200, 50, 30 then
the list look like
head
100 200 50 30 NULL

153
Operations on Linked Lists

154
Operations on single linked list
• Traversing a list
• Printing, finding minimum, etc.

• Insertion of a node into a list


• At front, end and anywhere, etc.

• Deletion of a node from a list


• At front, end and anywhere, etc.

• Comparing two linked lists


• Similarity, intersection, etc.
• Merging two linked lists into a larger list
• Union, concatenation, etc.
• Ordering a list
• Reversing, sorting, etc.

155
Traversing a Linked List

156
Single Linked List: Traversing

Once the linked list has been constructed and header


points to the first node of the list,
• Follow the pointers.
• Display the contents of the nodes as they are traversed.
• Stop when the next pointer points to NULL.

The function traverseList(struct Node *) is given in the next


slide. This function to be called from main() function as:
int main()
{
// Assume header, the pointer to the linked list is given as an input
printf("\n Data in the list \n");
traverseList(header);
return 0;
}

157
Single linked list: Traversing

void traverseList(struct Node *header)


{
struct node *temp;

/* If the list is empty i.e. head = NULL */


if(header == NULL)
{
printf("List is empty.");
}
else
{
temp = header;
while(temp != NULL)
{
printf("Data = %d\n", temp->data); //Prints the data of current node
temp = temp->next; //Advances the position of current node
}
}
}

158
Insertion in a Linked List

159
Single Linked List: Insertion

Insertion steps:
SN Operation Description
• Create a new node 1 Insertion
beginning
at It involves inserting any element at the front of the list. We just
need to a few link adjustments to make the new node as the head
of the list.
• Start from the header node 2 Insertion at It involves insertion at the last of the linked list. The new node
end of the list can be inserted as the only node in the list or it can be inserted as
• Manage links to the last one. Different logics are implemented in each scenario.

• Insert at front 3 Insertion after It involves insertion after the specified node of the linked list. We
specified node need to skip the desired number of nodes in order to reach the
node after which the new node will be inserted. .
• Insert at end
• Insert at any position

160
Insertion at Front

Steps to insert node at the beginning of singly linked list


Step 1: Create a new node. 

161
Insertion at Front

Step 2: Link the newly created node with the head node, i.e. the newNode will now
point to head node.

Step 3: Make the new node as the head node, i.e. now head node will point to newNode.  

162
Insertion at front
/*Create a new node and insert at the beginning of the linked list.*/

void insertNodeAtBeginning(int data)


{
struct node *newNode;
newNode = (struct node*)malloc(sizeof(struct node));

if(newNode == NULL)
{
printf("Unable to allocate memory.");
}
else
{
newNode->data = data; //Links the data part
newNode->next = head; //Links the address part

head = newNode; //Makes newNode as first node

printf("DATA INSERTED SUCCESSFULLY\n");


}
}

163
Single Linked List: Insertion at End
Steps to insert node at the end of Singly linked list
Step 1: Create a new node and make sure that the address part of the new node points to
NULL. i.e. newNode->next=NULL

Step 2: Traverse to the last node of the linked list and connect the last node of the list with
the new node, i.e. last node will now point to new node. (lastNode->next =
newNode).  

164
Insertion at End
/* Create a new node and insert at the end of the linked list. */
void insertNodeAtEnd(int data)
{
    struct node *newNode, *temp; 
    newNode = (struct node*)malloc(sizeof(struct node)); 
    if(newNode == NULL)
    {
        printf("Unable to allocate memory.");
    }
    else
    {
        newNode->data = data; //Links the data part
        newNode->next = NULL; 
        temp = head;
 
        while(temp->next != NULL) //Traverse to the last node
            temp = temp->next;
 
        temp->next = newNode; //Links the address part 
        printf("DATA INSERTED SUCCESSFULLY\n");
    }
}

165
Single Linked List: Insertion at any Position
Steps to insert node at any position of Singly Linked List
Step 1: Create a new node. 

Step 2: Traverse to the n-1th position of the linked list and connect the new node with the
n+1th node. (newNode->next = temp->next) where temp is the n-1th node.

166
Single Linked List: Insertion at any position

Step 3: Now at last connect the n-1th node with the new node i.e. the n-1th node will now
point to new node. (temp->next = newNode) where temp is the n-1th node.
Insertion at any Position

/* Create a new node and insert at middle of the linked list.*/

void insertNodeAtMiddle(int data, int position)


{
int i;
struct node *newNode, *temp;

newNode = (struct node*)malloc(sizeof(struct node));

if(newNode == NULL)
{
printf("Unable to allocate memory.");
}
else
{
newNode->data = data; //Links the data part
newNode->next = NULL;

temp = head;

168
Insertion at any Position
        for(i=2; i<=position-1; i++) /* Traverse to the n-1 position */
        {
            temp = temp->next;
 
            if(temp == NULL)
                break;
        } 
        if(temp != NULL)
        {
            /* Links the address part of new node */
            newNode->next = temp->next;
 
            /* Links the address part of n-1 node */
            temp->next = newNode;
 
            printf("DATA INSERTED SUCCESSFULLY\n");
        }
        else
        {
            printf("UNABLE TO INSERT DATA AT THE GIVEN POSITION\n");
        }
    }
}

169
Double Linked List: Insertion at any Position
Steps to insert a new node at nth position in a Doubly linked list.
Step 1: Traverse to N-1 node in the list, where N is the position to insert. Say temp now
points to N-1th node.

Step 2: Create a newNode that is to be inserted and assign some data to its data field.

170
Doubly Linked List: Insertion at any Position
Step 3: Connect the next address field of newNode with the node pointed by next address
field of temp node.

Step 4: Connect the previous address field of newNode with the temp node.

171
Doubly Linked List: Insertion at any Position
Step 5: Check if temp.next is not NULL then, connect the previous address field of node
pointed by temp.next to newNode.

Step 6: Connect the next address field of temp node to newNode.

172
Doubly Linked List: Insertion at any Position
Step 7: Final doubly linked list looks like

173
Doubly Linked List: Insertion at any Position
#include <stdio.h>
#include <stdlib.h>

struct node { /* Basic structure of Node */


int data;
struct node * prev;
struct node * next;
}*head, *last;

int main()
{
int n, data;
head = NULL;
last = NULL;

printf("Enter the total number of nodes in list: ");


scanf("%d", &n);
createList(n); // function to create double linked list
displayList(); // function to display the list

printf("Enter the position and data to insert new node: ");


scanf("%d %d", &n, &data);
insert_position(data, n); // function to insert node at any position
displayList();
return 0;
}
174
Doubly Linked List: Insertion at any Position
void createList(int n)
{
int i, data;
struct node *newNode;
if(n >= 1){ /* Creates and links the head node */
head = (struct node *)malloc(sizeof(struct node));
printf("Enter data of 1 node: ");
scanf("%d", &data);
head->data = data;
head->prev = NULL;
head->next = NULL;

last = head;

for(i=2; i<=n; i++){ /* Creates and links rest of the n-1 nodes */
newNode = (struct node *)malloc(sizeof(struct node));
printf("Enter data of %d node: ", i);
scanf("%d", &data);

newNode->data = data;
newNode->prev = last; //Links new node with the previous node
newNode->next = NULL;

last->next = newNode; //Links previous node with the new node


last = newNode; //Makes new node as last/previous node
}
printf("\nDOUBLY LINKED LIST CREATED SUCCESSFULLY\n");
}
}
175
Doubly Linked List: Insertion at any Position
void insert_position(int data, int position)
{
struct node * newNode, *temp;
if(head == NULL){
printf("Error, List is empty!\n");
}
else{
temp = head;
if(temp!=NULL){
newNode = (struct node *)malloc(sizeof(struct node));

newNode->data = data;
newNode->next = temp->next; //Connects new node with n+1th node
newNode->prev = temp; //Connects new node with n-1th node

if(temp->next != NULL)
{
temp->next->prev = newNode; /* Connects n+1th node with new node */
}
temp->next = newNode; /* Connects n-1th node with new node */
printf("NODE INSERTED SUCCESSFULLY AT %d POSITION\n", position);
}
else{
printf("Error, Invalid position\n");
}
}
}

176
Doubly Linked List: Insertion at any Position

void displayList()
{
struct node * temp;
int n = 1;

if(head == NULL)
{
printf("List is empty.\n");
}
else
{
temp = head;
printf("DATA IN THE LIST:\n");

while(temp != NULL)
{
printf("DATA of %d node = %d\n", n, temp->data);
n++;

/* Moves the current pointer to next node */


temp = temp->next;
}
}
177
}
Few Exercises to Try Out
For doubly linked list write a function to:
• Insert a node at front of the list and at end of the list.
insert_front(data);
insert_end(data);

• Sort the DLL in ascending order.

• Count the number of nodes in the given DLL.

178
Deletion from a Linked List

179
Single Linked List: Deletion

Deletion steps
• Start from the header node
• Manage links to
• Delete at front
• Delete at end
• Delete at any position
• freeingup the node as free space.

180
Free Memory after Deletion
• Do not forget to free() memory location dynamically allocated
for a node after deletion of that node.

• It is the programmer’s responsibility to free that memory


block.

• Failure to do so may create a dangling pointer – a memory,


that is not used either by the programmer or by the system.

• The content of a free memory is not erased until it is


overwritten.

181
Single Linked List: Deletion at Front
Steps to delete first node of Singly Linked List
Step 1: Copy the address of first node i.e. head node to some temp variable say toDelete.

Step 2: Move the head to the second node of the linked list (head = head->next).
Single linked list: Deletion at front
Step 3: Disconnect the connection of first node to second node.

Step 4: Free the memory occupied by the first node.

183
Deletion at Front

/* Delete the first node of the linked list */


void deleteFirstNode()
{
struct node *toDelete;

if(head == NULL)
{
printf("List is already empty.");
}
else
{
toDelete = head;
head = head->next;

printf("\nData deleted = %d\n", toDelete->data);

/* Clears the memory occupied by first node*/


free(toDelete);

printf("SUCCESSFULLY DELETED FIRST NODE FROM LIST\n");


}
}
184
Single linked list: Deletion at End
Steps to delete last node of a Singly Linked List
Step 1: Traverse to the last node of the linked list keeping track of the second last node in some temp variable say
secondLastNode.

Step 2: If the last node is the head node then make the head node as NULL else disconnect the second last node with the last
node i.e. secondLastNode->next = NULL

Step 3: Free the memory occupied by the last node.


Deletion at End

/* Delete the last node of the linked list */


void deleteLastNode()
{
struct node *toDelete, *secondLastNode;
toDelete = head;
    secondLastNode = head;
 
    while(toDelete->next != NULL) /* Traverse to the last node of the list*/
     {
       secondLastNode = toDelete;
       toDelete = toDelete->next;
     }
    if(toDelete == head)
     {
       head = NULL;
     }
    else
     {
      /* Disconnects the link of second last node with last node */
       secondLastNode->next = NULL;
     }
      /* Delete the last node */
    free(toDelete);
}
186
Single Linked List: Deletion at any Position
Steps to delete a node at any position of Singly Linked List
Step 1: Traverse to the nth node of the singly linked list and also keep reference of n-1th node
in some temp variable say prevNode. 

Step 2: Reconnect n-1th node with the n+1th node i.e. prevNode->next = toDelete->next
(Where prevNode is n-1th node and toDelete node is the nth node and toDelete->next is the n+1th
node).

187
Single Linked List: Deletion at any Position
Step 3: Free the memory occupied by the nth node i.e. toDelete node.

188
Deletion at any Position

/* Delete the node at any given position of the linked list  */
void deleteMiddleNode(int position)
{
    int i;
    struct node *toDelete, *prevNode; 
    if(head == NULL)
    {
        printf("List is already empty.");
    }
    else
    {
        toDelete = head;
        prevNode = head;
 
        for(i=2; i<=position; i++)
        {
            prevNode = toDelete;
            toDelete = toDelete->next;
 
            if(toDelete == NULL)
                break;
        }

189
Deletion at any Position

        if(toDelete != NULL)
{
if(toDelete == head)
head = head->next;

prevNode->next = toDelete->next;
toDelete->next = NULL;

/* Deletes the n node */


free(toDelete);

printf("SUCCESSFULLY DELETED NODE FROM MIDDLE OF LIST\n");


}
else
{
printf("Invalid position unable to delete.");
}
}
}

190
Circular linked list
Basic structure of singly circular linked list:

Doubly circular linked list:

191
Circular linked list:
Advantages of a Circular linked list
• Entire list can be traversed from any node.
• Circular lists are the required data structure when we want a list to be accessed
in a circle or loop.
• Despite of being singly circular linked list we can easily traverse to its previous
node, which is not possible in singly linked list.

Disadvantages of Circular linked list


• Circular list are complex as compared to singly linked lists.
• Reversing of circular list is a complex as compared to singly or doubly lists.
• If not traversed carefully, then we could end up in an infinite loop.
• Like singly and doubly lists circular linked lists also doesn’t supports direct
accessing of elements.

192
Operations on circular linked list
• Creation of list
• Traversal of list
• Insertion of node
• At the beginning of list
• At any position in the list
• Deletion of node
• Deletion of first node
• Deletion of node from middle of the list
• Deletion of last node
• Counting total number of nodes
• Reversing of list

193
Creation and Traversal of a Circular List

#include <stdio.h>
#include <stdlib.h>

/* Basic structure of Node */

struct node {
int data;
struct node * next;
}*head;

int main()
{
int n, data;
head = NULL;

printf("Enter the total number of nodes in list: ");


scanf("%d", &n);
createList(n); // function to create circular linked list
displayList(); // function to display the list

return 0;
}

194
Circular Linked List: Creation of List
void createList(int n)
{
int i, data;
struct node *prevNode, *newNode;
if(n >= 1){ /* Creates and links the head node */
head = (struct node *)malloc(sizeof(struct node));

printf("Enter data of 1 node: ");


scanf("%d", &data);

head->data = data;
head->next = NULL;
prevNode = head;

for(i=2; i<=n; i++){ /* Creates and links rest of the n-1 nodes */
newNode = (struct node *)malloc(sizeof(struct node));

printf("Enter data of %d node: ", i);


scanf("%d", &data);

newNode->data = data;
newNode->next = NULL;
prevNode->next = newNode; //Links the previous node with newly created node
prevNode = newNode; //Moves the previous node ahead
}
prevNode->next = head; //Links the last node with first node
printf("\nCIRCULAR LINKED LIST CREATED SUCCESSFULLY\n");
}
}
195
Circular Linked List: Traversal of List

void displayList()
{
struct node *current;
int n = 1;

if(head == NULL)
{
printf("List is empty.\n");
}
else
{
current = head;
printf("DATA IN THE LIST:\n");

do {
printf("Data %d = %d\n", n, current->data);

current = current->next;
n++;
}while(current != head);
}
}

196
Unit- 3 and Unit-4
AI&ML, AI&DS, IIOT
What is a Tree data structure?
• A Tree is a non-linear data structure and a hierarchy consisting of a collection of nodes such that each node of the tree
stores a value and a list of references to other nodes (the “children”).
• This data structure is a specialized method to organize and store data in the computer to be used more effectively. It
consists of a central node, structural nodes, and sub-nodes, which are connected via edges. We can also say that tree data
structure has roots, branches, and leaves connected with one another.
Basic Terminologies In Tree Data Structure:
•Parent Node: The node which is a predecessor of a node is called the parent node of that node. {B} is the parent node of {D, E}.
•Child Node: The node which is the immediate successor of a node is called the child node of that node. Examples: {D, E} are the child nodes
of {B}.
•Root Node: The topmost node of a tree or the node which does not have any parent node is called the root node. {A} is the root node of the tree.
A non-empty tree must contain exactly one root node and exactly one path from the root to all other nodes of the tree.
•Leaf Node or External Node: The nodes which do not have any child nodes are called leaf nodes. {G, K, L, M, N, O, P} are the leaf nodes of
the tree.
•Ancestor of a Node: Any predecessor nodes on the path of the root to that node are called Ancestors of that node. {A,B} are the ancestor nodes
of the node {E}

•Descendant: Any successor node on the path from


the leaf node to that node. {E,I} are the descendants of
the node {B}.
•Sibling: Children of the same parent node are called
siblings. {D,E} are called siblings.
•Level of a node: The count of edges on the path
from the root node to that node. The root node has
level 0.
•Internal node: A node with at least one child is
called Internal Node.
•Neighbour of a Node: Parent or child nodes of that
node are called neighbors of that node.
•Subtree: Any node of the tree along with its
Tree Terminologies
Node
• A node is an entity that contains a key or value and pointers to its
child nodes.
• The last nodes of each path are called leaf nodes or external
nodes that do not contain a link/pointer to child nodes.
• The node having at least a child node is called an internal node.
Edge
It is the link between any two nodes.
Root
It is the topmost node of a tree.
Rooted Tree
• A rooted tree G is a connected acyclic graph with a special
node that is called the root of the tree and every edge directly
or indirectly originates from the root.
• An ordered rooted tree is a rooted tree where the children of
each internal vertex are ordered.
• If every internal vertex of a rooted tree has not more than m
children, it is called an m-ary tree.
Rooted Tree
• If every internal vertex of a rooted tree has exactly m children, It must be directed graph
Only one node ---Indegree(0)
it is called a full m-ary tree. All other node ---indegree(1)
• If m = 2, the rooted tree is called a binary tree.
One node ---Indegree(0) Binary Tree--- rooted tree and outdegree 2 or less
All other node indegree exactly (1) than 2.
Height of a Tree
• The height of a Tree is the height of the root node or the
depth of the deepest node.

• Depth of a Node
The depth of a node is the number of edges from the root to
the node.

Degree of a Node
• The degree of a node is the total number of branches of that Height and depth of each node in a tree
node.
Binary Tree
• The Binary tree means that the node can have maximum two children. Here, binary name
itself suggests that 'two'; therefore, each node can have either 0, 1 or 2 children.
Properties of Binary Tree
•At each level of i, the maximum number of nodes is 2i.
•The height of the tree is defined as the longest path from the root node to the leaf node. The tree which
is shown above has a height equal to 3. Therefore, the maximum number of nodes at height 3 is equal to
(1+2+4+8) = 15. In general, the maximum number of nodes possible at height h is (2 0 + 21 + 22+….2h) =
2h+1 -1.
•The minimum number of nodes possible at height h is equal to h+1.
•If the number of nodes is minimum, then the height of the tree would be maximum. Conversely, if the
number of nodes is maximum, then the height of the tree would be minimum.
If there are 'n' number of nodes in the binary tree.
The minimum height can be computed as:
As we know that,
n = 2h+1 -1
n+1 = 2h+1
Taking log on both the sides,
log2(n+1) = log2(2h+1)
log2(n+1) = h+1
Binary Tree
• The Binary tree means that the node can have maximum two children. Here, binary name
itself suggests that 'two'; therefore, each node can have either 0, 1 or 2 children.
1. Full Binary Tree-
 
•A binary tree in which every node has either 0 or 2 children is
called as a Full binary tree.
•Full binary tree is also called as Strictly binary tree.

2. Complete Binary Tree


Valid and Invalid Structure of Full Binary Tree
Complete Binary Tree has all levels completely filled with nodes
except the last level and in the last level, all the nodes are as left side
as possible.
A complete binary tree is a binary tree in which node insertion takes
place from the left.

Valid and Invalid Structure of Complete Binary


Tree
Perfect Binary Tree
In a perfect binary tree, all the internal nodes have exactly two children. Every leaf node in a perfect binary
tree must be present at the same level. A perfect binary tree is also called a strict binary tree.
Perfect Binary Tree is a Binary Tree in which all internal nodes have 2 children and all the leaf nodes
are at the same depth or same level.
Skewed Binary Tree-
If a tree which is dominated by left child node or right child
node, is said to be a Skewed Binary Tree.In a skewed binary
tree, all nodes except one have only one child node. The
remaining node has no child.

A skewed binary tree is a binary tree that satisfies the


following 2 properties-
•All the nodes except one node has one and only one child.
•The remaining node has no child.
OR
A skewed binary tree is a binary tree of n nodes such that its
depth is (n-1)
Extended Binary Tree
•Extended binary tree consists of replacing every null subtree of
the original tree with special nodes.
•Empty circle represents internal node and filled circle
represents external node.
•The nodes from the original tree are internal nodes and the
special nodes are external nodes.
•Every internal node in the extended binary tree has exactly two
children and every external node is a leaf. It displays the result
which is a complete binary tree.
Inorder Traversal Postorder Traversal Preorder Traversal
1.Traverse the left subtree by 1.Visit all the nodes in the left subtree 1.Visit root node
recursively calling inOrder function 2.Visit all the nodes in the right subtree 2.Visit all the nodes in the left subtree
2.Process the root value by pushing it 3.Visit the root node 3.Visit all the nodes in the right subtree
into nodes
3.Traverse the right subtree by
recursively calling inOrder function
Construct a tree; Inorder and Preorder is given
5 -> 12 -> 6 -> 1 -> 9
Binary Search Tree 

Binary Search Tree is a node-based binary tree data structure which has the following properties:
•The left subtree of a node contains only nodes with keys lesser than the node’s key.
•The right subtree of a node contains only nodes with keys greater than the node’s key.
•The left and right subtree each must also be a binary search tree.

•A binary search tree follows some order to arrange the

elements. In a Binary search tree, the value of left node must be

smaller than the parent node, and the value of right node must

be greater than the parent node. This rule is applied recursively

to the left and right subtrees of the root.


Which Tree is a Binary Search Tree (BST)

A B
Option A is BST
Creating a binary search tree Step 6 - Insert 55.
Suppose the data elements are - 45, 15, 79, 90, 10, 55, 12
Step 1 - Insert 45. Step 4 - Insert 90.
90 is greater than 45 and 79, so it will
be inserted as the right subtree of 79.

Step 2 - Insert 15.


As 15 is smaller than 45, so insert it
as the root node of the left subtree.

Step 7 - Insert 12.


Step 5 - Insert 10.

Step 3 - Insert 79
As 79 is greater than 45, so insert it as
the root node of the right subtree.
Insert: 65

https://www.javatpoint.com/binary-search-tree
Searching Element in BST
1.Compare the element with the root of the tree.
2.If the item is matched then return the location of the node.
3.Otherwise check if item is less than the element present on root, if so then move to the left sub-tree.
4.If not, then move to the right sub-tree.
5.Repeat this procedure recursively until match found.
6.If element is not found then return NULL.
Searching Element in BST
Delete a node in BST
The node to be deleted is a leaf node
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.

Case 2: Deleting a node with two children: call the


node to be deleted N. Do not delete N. Instead, choose
either its inorder successor node or its
inorder predecessor node

Case 3: Deleting a node with one child: remove the node and
replace it with its child.
Applications of Binary Search tree
Applications of Binary Search tree:
•BSTs are used for indexing.
•It is also used to implement various searching algorithms.
•IT can be used to implement various data structures.
•BSTs can be used in decision support systems to store and quickly retrieve data.
•BSTs can be used to store and quickly retrieve data in computer simulations.
•BSTs can be used to implement fast autocomplete systems.
Real-time Application of Binary Search tree:
•BSTs are used for indexing in databases.
•It is used to implement searching algorithms.
•BSTs are used to implement Huffman coding algorithm.
•It is also used to implement dictionaries.
•Used for data caching.
•Used in Priority queues.
•Used in spell checkers.
Advantages of Binary Search Tree:
•BST is fast in insertion and deletion when balanced. It is fast with a time complexity of O(log n).
•BST is also for fast searching, with a time complexity of O(log n) for most operations. 
•BST is efficient. It is efficient because they only store the elements and do not require additional memory for pointers or other data structures.
•We can also do range queries – find keys between N and M (N <= M).
•BST code is simple as compared to other data structures.
•BST can automatically sort elements as they are inserted, so the elements are always stored in a sorted order.
•BST can be easily modified to store additional data or to support other operations. This makes it flexible.
AVL Tree
• AVL Tree is invented by GM Adelson - Velsky and EM Landis in 1962.
• The tree is named AVL in honour of its inventors.
• AVL Tree can be defined as height balanced binary search tree in which each node is associated with a
balance factor which is calculated by subtracting the height of its right sub-tree from that of its left sub-
tree.

Balance Factor
• 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. Tree is said to be balanced if balance
factor of each node is in between -1 to 1, otherwise, the
tree will be unbalanced and need to be balanced.
Balance Factor (k) = height (left(k)) - height (right(k))

Balance Factor = (Height of Left Subtree - Height of Right


Subtree) 
Balance Factor Calculation in Tree
Imbalance in Tree
2. LL Imbalance
Solution
One Right Rotation

AVL tree may become unbalanced, if a node is inserted in the left subtree of the left subtree. The tree then
needs a right rotation.

Imbalanced AVL Tree One Right Rotation Balanced AVL Tree


Step II
1. We have 2 Rotations are required ,
added 2 and First right rotation with
node 1 is respect to node (3)
imbalanced

Step 3.
Now one left
Rotation with
respect to node (1)
4. LR Imbalance
Solution
2 Rotation
First Left-
Then Right Rotation

Let's first check how to perform Left-Right


rotation. A left-right rotation is a combination of
left rotation followed by right rotation.

Insert 3, 1, 2 in AVL Tree

Imbalanced AVL Tree One Left Rotation R Rotation Balanced AVL


Tree
Construct a AVL Tree by inserting from 1 to 5 numbers

-1 1 -2
1 0 1

2 3 Not AVL, RR Imbalance


2 2 -1 One Left Rotation
0

3 0
2 -1
0 2 -1 2 -2
2
4 5 4 0
0 1
0 -1 -2
1 3 0 1 3 0 1 3
0
5 0
0 3
After Rotation
4 0 4 -1

AVL Tree
5 0
ashish0751@gmail.com
Construct
AVL Tree with
data items:
51, 26, 11, 6,
8, 4, 31

ashish0751@gmail.com 235
AVL Example (insert 42)
which node is imbalanced ? Ans Node (40)
How ? When 42 is added
Conclusion: Node (46) will be connected in right
Which imbalanced ; it is RLLR , remove last two letters, with node(45)

Now it is RL imbalanced node (45) will be added in the right sub tree but (50)
is added. But it is confirmed that it will be part of
2 Rotations are required right subtree, therefore it is connected node(45)’s
right and (50)’s Left
First Right rotation with respect to 50
After one left rotation with respect to node (40)
Deletion in AVL Tree
• Deleting a node from an AVL tree is similar to that in a binary search tree.
• Deletion may disturb the balance factor of an AVL tree and therefore the tree needs to be rebalanced in order to
maintain the AVLness.
• For this purpose, we need to perform rotations.
AVL Deletion

• The two types of rotations are


L Deletion R Deletion
L Deletion and R Deletion.
• If the node which is to be deleted
is present in the left sub-tree of
the critical node, then L deletion L-1 L0 L+1 R-1 R0 R+1
needs to be applied else if, the
node which is to be deleted is
present in the right sub-tree of
the critical node, the R deletion RR RR RL LR LL LL
will be applied. Imbalance Imbalance Imbalance Imbalance Imbalance Imbalance
Delete 60

R Deletion, why: node 50


is imbalanced
Threaded Binary Tree
• In the linked representation of binary trees, more than one half of the link
fields contain NULL values which results in wastage of storage space.
• If a binary tree consists of n nodes then n+1 link fields contain NULL
values.
• So in order to effectively manage the space, a method was devised by
Perlis and Thornton in which the NULL links are replaced with special
links known as threads.
• Such binary trees with threads are known as threaded binary trees. Each
node in a threaded binary tree either contains a link to its child node or
thread to other nodes in the tree.
Advantages of Threaded Binary Tree
•In this Tree it enables linear traversal of elements.
•It eliminates the use of stack as it perform linear
traversal, so save memory.
•Enables to find parent node without explicit use of
parent pointer
•Threaded tree give forward and backward traversal
of nodes by in-order fashion
•Nodes contain pointers to in-order predecessor and
successor
•For a given node, we can easily find inorder
predecessor and successor. So, searching is much
more easier.
Disadvantages of Threaded Binary Tree
•Every node in threaded binary tree need extra
information(extra memory) to indicate whether its
left or right node indicated its child nodes or its
inorder predecessor or successor. So, the node
consumes extra memory to implement.
•Insertion and deletion are way more complex and
time consuming than the normal one since both
threads and ordinary links need to be maintained.
B Tree
B tree is an m-way tree that self-balances. Because of their balanced nature, such trees are widely used to organize and
manage massive datasets and to facilitate searches.

In the case of minimum children,


If the B tree has an order of m, then
•the leaf nodes have= zero children.
• each node can have a maximum =m children.
•the internal nodes have = ceiling of m/2 Children .
• Each node can have maximum (m-1) keys.
•The root node has minimum one key
For example, if the value of m is 5 then the maximum value

of keys is 4 and maximum 5 children are possible. •Internal node= (ceiling of m/2 - 1) minimum keys.

•If we perform insertion in the B tree, then the node is always

inserted in the leaf node.


Deletion in B Tree

https://www.youtube.com/watch?v=pN4C8cLVc7I
2-3 Tree
•  2-3 Tree is also a height balanced tree.
• The time complexity of search/insert/delete is O(log N) .

Properties of 2-3 tree


•Nodes with two children are called 2-nodes. The 2-nodes
have one data value and two children
•Nodes with three children are called 3-nodes. The 3-nodes
have two data values and three children.
•Data is stored in sorted order.
•It is a balanced tree.
•All the leaf nodes are at same level.
•Each node can either be leaf, 2 node, or 3 node.
•Always insertion is done at leaf.
3 way tree== 2- 3 TREE
2-3-4 Tree
B+ Tree
• B+ Tree is an extension of B Tree which allows efficient
insertion, deletion and search operations.
• In B Tree, Keys and records both can be stored in the internal
as well as leaf nodes. Whereas, in B+ tree, records (data) can
only be stored on the leaf nodes while internal nodes can only
store the key values.
• The leaf nodes of a B+ tree are linked together in the form of a
singly linked lists to make the search queries more efficient.
• B+ Tree are used to store the large amount of data which can
not be stored in the main memory. Due to the fact that, size of
main memory is always limited, the internal nodes (keys to
access records) of the B+ tree are stored in the main memory
whereas, leaf nodes are stored in the secondary memory.
Properties of B+ Trees
1.All data is stored in the leaf nodes, while the internal

nodes store just the indices.


2.Each leaf is at the same height.

3.All leaf nodes have links to the other leaf nodes.

4.The root node has a minimum of two children.

5.Each node except root can have a maximum of m children and a

minimum of m/2 children.

6.Each node can contain a maximum of m-1 keys and a minimum

of ⌈m/2⌉ - 1 keys.
B+ Tree
B*-Tree
B*-tree of order m is a search tree that is either empty or that satisfies three
properties:
•The root node has minimum two and maximum 2 floor ((2m-2)/3) +1 children
•Other internal nodes have the minimum floor ((2m-1)/3) and maximum m
children
•All external nodes are on the same level.
The advantage of using B* trees over B-trees is a unique feature called the
‘two-to-three’ split. By this, the minimum number of keys in each node is not
half the maximum number, but two-thirds of it, making data far more compact.
Unit-4
AI&ML, AI&DS, IIOT
Unit 4
Section 1

File
File

File is a collection of records related to each other. The file size is limited by the size of memory and storage
medium.
A file structure is a combination of representations for data in files. It is also a collection of operations for
accessing the data. It enables applications to read, write, and modify data. File structures may also help to find the
data that matches certain criteria. An improvement in file structure has a great role in making applications
hundreds of times faster.
The main goal of developing file structures is to minimize the number of trips to the disk in order to get
desired information. It ideally corresponds to getting what we need in one disk access or getting it with as little
disk access as possible.
A good file structure should:
•Fast access to a great capacity
File Organization
•Reduce the number of disk accesses
• File organization ensures that records are available for processing. It is used to •Manage growth by splitting these collections.
determine an efficient file organization for each base relation.
There are three types of organizing the file:
• For example, if we want to retrieve employee records in alphabetical order of 1. Sequential access file organization
name. Sorting the file by employee name is a good file organization. 2. Direct access file organization
• However, if we want to retrieve all employees whose marks are in a certain 3. Indexed sequential access file organization

range, a file is ordered by employee name would not be a good file organization.
1. Sequential access file organization 3. Indexed sequential access file organization
•Storing and sorting in contiguous block within files on tape or disk is called as sequential access file •Indexed sequential access file combines both
organization. sequential file and direct access file organization.
•In sequential access file organization, all records are stored in a sequential order. The records are arranged in the •In indexed sequential access file, records are stored
ascending or descending order of a key field. randomly on a direct access device such as magnetic
•Sequential file search starts from the beginning of the file and the records can be added at the end of the file. disk by a primary key.
•In sequential file, it is not possible to add a record in the middle of the file without rewriting the file. •This file have multiple keys. These keys can be
alphanumeric in which the records are ordered is
•Advantages of sequential file called primary key.
•It is simple to program and easy to design. •The data can be access either sequentially or
•Sequential file is best use if storage space. randomly using the index. The index is stored in a
•Disadvantages of sequential file file and read into memory when the file is opened.
•Sequential file is time consuming process. •Advantages of Indexed sequential access file
•It has high data redundancy. organization
•Random searching is not possible. In indexed sequential access file, sequential file and
random file access is possible.
•It accesses the records very fast if the index table is
2. Direct access file organization properly organized.
•Direct access file is also known as random access or relative file organization. •The records can be inserted in the middle of the file.
•In direct access file, all records are stored in direct access storage device (DASD), such as hard disk. The records are •It provides quick access for sequential and direct
randomly placed throughout the file. The records does not need to be in sequence because they are updated directly and processing.
rewritten back in the same location. •It reduces the degree of the sequential search.
•This file organization is useful for immediate access to large amount of information. It is used in accessing large •Disadvantages of Indexed sequential access file
databases. It is also called as hashing. organization
•Advantages of direct access file organization Indexed sequential access file requires unique keys
Direct access file helps in online transaction processing system (OLTP) like online railway reservation system. and periodic reorganization.
•In direct access file, sorting of the records are not required. •Indexed sequential access file takes longer time to
•It accesses the desired records immediately, It updates several files quickly. search the index for the data access or retrieval.
•It has better control over record allocation. •It requires more storage space.
•Disadvantages of direct access file organization •It is expensive because it requires special software.
Direct access file does not provide back up facility and It is expensive. •It is less efficient in the use of storage space as
•It has less storage space as compared to sequential file. compared to other file organizations.
Indexed sequential access file organization
Indexing
Indexing is a data structure technique that helps to speed up data
retrieval. As we can quickly locate and access the data in the database, it
is a must-know data structure that will be needed for database
optimizing. Indexing minimizes the number of disk accesses required Indexing is a general name for a process of partitioning
when a query is processed. Indexes are created as a combination of the
intended at speeding up data look-ups. Indexing can
two columns.
•First column is the Search key. It contains a copy of the primary key or partition the data set based on a value of a field or a
candidate key of the table. The values of this column may be sorted or
combination of fields. It can also partition the data set based
not. But if the values are sorted, the corresponding data can be accessed
easily. on a value of a function, called hash function, computed
•Second column is the Data reference or Pointer. It contains the
from the data in a field or a combination of fields. In this
address of the disk block where we can find the corresponding key value.
specific case, indexing is called data hashing.
Read more:
https://medium.com/nerd-for-tech/indexing-data-structure
s-aa7363693c40
Hashing (Hash Function)
• In a hash table, a new index is processed using the keys. and, the element corresponding to that
key is stored in the index. This process is called hashing.
• Let k be a key and h(x) be a hash function.
• Here, h(k) will give us a new index to store the
element linked with k.
Hash Collision
When the hash function generates the same index for multiple keys, there will be a conflict
(what value to be stored in that index). This is called a hash collision. When the two
different values have the same hash value, then the problem occurs between the two values,
known as a collision.
Example
If the key value is 26 and 16 then the index would be:
h(26) = 26%10 = 6
h(16) = 16%10 = 6

We can resolve the hash collision using one of the following techniques.
1. Collision resolution by chaining/Separate chaining
2. Open Addressing: Linear/Quadratic Probing and Double Hashing
Collision resolution by chaining/Separate chaining
Example: Let us consider a simple hash function as “key mod 7” and a sequence
of keys as 50, 700, 76, 85, 92, 73, 101

In chaining, if a hash function

produces the same index for multiple

elements, these elements are stored

in the same index by using a doubly-

linked list.
Separate Chaining
0 / Chaining:
1 / All keys that map to the same
2 / table location are kept in a list (a.k.a. a
3 / “chain” or “bucket”)
4 /
5 / As easy as it sounds
6 /
7 / Example:
8 /
insert 10, 22, 107, 12, 42
9 /
with mod hashing
and TableSize = 10

ashish0751@gmail.com CSE373: Data Structures & Algorithms 264


Summer 2016
Separate Chaining
0 10 / Chaining:
1 / All keys that map to the same
2 / table location are kept in a list
3 / (a.k.a. a “chain” or “bucket”)
4 /
5 / As easy as it sounds
6 /
7 / Example:
8 /
insert 10, 22, 107, 12, 42
9 /
with mod hashing
and TableSize = 10

ashish0751@gmail.com CSE373: Data Structures & Algorithms 265


Summer 2016
Separate Chaining
0 10 / Chaining:
1 / All keys that map to the same
2 22 / table location are kept in a list
3 / (a.k.a. a “chain” or “bucket”)
4 /
5 / As easy as it sounds
6 /
7 / Example:
8 /
insert 10, 22, 107, 12, 42
9 /
with mod hashing
and TableSize = 10

ashish0751@gmail.com CSE373: Data Structures & Algorithms 266


Summer 2016
Separate Chaining
0 10 / Chaining:
1 / All keys that map to the same
2 22 / table location are kept in a list
3 / (a.k.a. a “chain” or “bucket”)
4 /
5 / As easy as it sounds
6 /
7 107 / Example:
8 /
insert 10, 22, 107, 12, 42
9 /
with mod hashing
and TableSize = 10

ashish0751@gmail.com CSE373: Data Structures & Algorithms 267


Summer 2016
Separate Chaining
0 10 / Chaining:
1 / All keys that map to the same
2 12 22 / table location are kept in a list
3 / (a.k.a. a “chain” or “bucket”)
4 /
5 / As easy as it sounds
6 /
7 107 / Example:
8 /
insert 10, 22, 107, 12, 42
9 /
with mod hashing
and TableSize = 10

ashish0751@gmail.com CSE373: Data Structures & Algorithms 268


Summer 2016
Separate Chaining
0 10 / Chaining:
1 / All keys that map to the same
2 42 12 22 / table location are kept in a list
3 / (a.k.a. a “chain” or “bucket”)
4 /
5 / As easy as it sounds
6 /
7 107 / Example:
8 /
insert 10, 22, 107, 12, 42
9 /
with mod hashing
and TableSize = 10

ashish0751@gmail.com CSE373: Data Structures & Algorithms 269


Summer 2016
Open Addressing: Linear Probing
In linear probing, the hash table is searched sequentially that starts from the original location of the hash. If
in case the location that we get is already occupied, then we check for the next location. 

Let hash(x) be the slot index computed using a hash function and S be the table size 
If slot hash(x) % S is full, then we try (hash(x) + 1) % S
If (hash(x) + 1) % S is also full, then we try (hash(x) + 2) % S
If (hash(x) + 2) % S is also full, then we try (hash(x) + 3) % S 
…………………………………………..
…………………………………………..
Let us consider a simple hash function as “key mod 7” and a sequence of keys as 50, 700,
76, 85, 92, 73, 101. 
ashish0751@gmail.com
Linear Probing

ashish0751@gmail.com Data Structures Using C, Second Edition 272


Reema Thareja
Linear Probing(2/2)

ashish0751@gmail.com Data Structures Using C, Second Edition 273


Reema Thareja
Quadratic Probing
• In this technique, if a value is already stored at a location generated by h(k), then the following hash
function is used to resolve the collision:
h(k, i) = [h′(k) + c1i + c2i2] mod m
where m is the size of the hash table,
h′(k) = (k mod m), i is the probe number that varies from 0 to m–1, and c1 and c2 are constants such that
c1 and c2 ≠ 0.

Procedure of Quadratic Probing


Let hash(x) be the slot index computed using the hash function and m be the size of the hash table.
•If the slot hash(x) % m is full, then we try (hash(x) + 12) % m.
•If (hash(x) + 12) % m is also full, then we try (hash(x) + 22) % m.
•If (hash(x) + 22) % m is also full, then we try (hash(x) + 32) % m.
This process is repeated for all the values of i until an empty slot is found.

ashish0751@gmail.com
Key Hash Function h(X) Index Collision Alt Index
79 h0(79) 9
= ( Hash(79) + F(0)2) % 10
= ((79 % 10) + 0) % 10
28 h0(28) 8
= ( Hash(28) + F(0)2) % 10
= ((28 % 10) + 0) % 10
39 h0(39) 9 The first
= ( Hash(39) + F(0)2) % 10 collision
= ((39 % 10) + 0) % 10 occurs
h1(39) 0 0
= ( Hash(39) + F(1)2) % 10
= ((39 % 10) + 1) % 10
68 h0(68) 8 The
= ( Hash(68) + F(0)2) % 10 collision
= ((68 % 10) + 0) % 10 occurs
h1(68) 9 Again
= ( Hash(68) + F(1)2) % 10 collision
= ((68 % 10) + 1) % 10 occurs
h2(68) 2 2
= ( Hash(68) + F(2)2) % 10
= ((68 % 10) + 4) % 10
89 h0(89) 9 The
= ( Hash(89) + F(0)2) % 10 collision
= ((89 % 10) + 0) % 10 occurs
h1(89) 0 Again
= ( Hash(89) + F(1)2) % 10 collision
= ((89 % 10) + 1) % 10 occurs
h2(89) 3 3
= ( Hash(89) + F(2)2) % 10
ashish0751@gmail.com = ((89 % 10) + 4) % 10 Quadratic Probing
Quadratic Probing

ashish0751@gmail.com Data Structures Using C, Second Edition 276


Reema Thareja
Quadratic Probing

ashish0751@gmail.com Data Structures Using C, Second Edition 277


Reema Thareja
Double Hashing

ashish0751@gmail.com Data Structures Using C, Second Edition 278


Reema Thareja
Double Hashing

ashish0751@gmail.com Data Structures Using C, Second Edition 279


Reema Thareja
Application: Telephone Directory
Problem Description
Task. In this task your goal is to implement a simple phone book manager. It should be able to process the
following types of user’s queries:
add number name. It means that the user adds a person with name name and phone number number to the
phone book. If there exists a user with such number already, then your manager has to overwrite the
corresponding name.
del number. It means that the manager should erase a person with number number from the phone book. If
there is no such person, then it should just ignore the query.
find number. It means that the user looks for a person with phone number number. The manager should reply
with the appropriate name, or with string “not found” (without quotes) if there is no such person in the book.

We need a hash to save the mapping from phone number to name and name to phone number:
Using Array — Direct Addressing Using List
To implement a hash using an array, Unlike using array, using list will
firstly we convert phone number to help us to save space. We just new
number: data to list but the
'0930-345-234' -> 0930345234 operation search still costs O(n) to
perform.
name_to_number = { 'john' : '0930-345-234', 'alice' :
'0934-234-546', ... }
number_to_name = { '0930-345-234' : 'john', '0934-
Application: Telephone Directory

Hash integer
We want to transform phone number into smaller set — 1000 elements.
•Take phone numbers up to length 7, for example 148–25–67.
•Convert phone numbers to integers 1482 567
•Choose prime number bigger than 10⁷ , e.g. p = 10 000 019
•Choose hash table size, e.g. m = 1 000
We will make phone number bigger than prime p, and modulo to m, the result will be a set of hashing
values that smaller than m. 

                       
We just choose a, b number big enough to be multipliers. So ax +b will be larger than p. We modulo p
and modulo m to get the result.
Select a = 34, b = 2, so h = h(34,2,p) and consider x = 1 482 567
corresponding to phone number 148–25–67. p = 10 000 019.h(x) = ((34 ×
1482567 + 2) mod 10000019) mode 1000 = 185
Dictionary (Hash Tables)
• A dictionary is a general concept that maps keys to values. There are many ways
to implement such a mapping. 0 12
2
• A hashtable is a specific way to implement a dictionary. 1 5
“key”
• Consider an array or an array list.
2 42
3 91
• To access a value, you use an integer index. Key 2 maps to
value 42. 4 0
• The array “maps” the index to a data value stored in the array.
5 57
• We can consider the index value to be the “key” to obtaining the
corresponding data value.
• As long as the index value is within range, there is a strict one-to-one Hash Table
correspondence between an index value and a stored data value. Hashing in data structure uses hash tables to store the key-
• A hash table also stores data values. value pairs. The hash table then uses the hash function to
generate an index. Hashing uses this unique index to perform
• Use a key to obtain the corresponding data value.
insert, update, and search operations.
• The key does not have to be an integer value. It can be defined as a bucket where the data are stored in an
• For example, the key could be a string. array format. These data have their own index value. If the
index values are known then the process of accessing the
data is quicker.
ashish0751@gmail.com
Unit 4
Section 2

Graph Theory
NONLINEAR DATA STRUCTURES: GRAPH

• This nonlinear data structures is the Graph. Graphs representations have


found application in almost all subjects like geography, engineering and
solving games and puzzles.
• A graph G consist of
Set of vertices V (called nodes), (V = {v1, v2, v3, v4......}) and
Set of edges E (i.e., E {e1, e2, e3......}
• A graph can be represents as G = (V, E), where V is a finite and non-empty set
at vertices, and E is a set of pairs of vertices called edges. Each edge ‘e’ in E is
identified with a unique pair (a, b) of nodes in V, denoted by e = [a, b].

vertex V and edge E can be represented as: V = {v1, v2, v3, v4, v5, v6} and E = {e1, e2, e3,
e4, e5, e6} E = {(v1, v2) (v2, v3) (v1, v3) (v3, v4), (v3, v5) (v5, v6)}. There are six edges and
vertices in the graph.
vertices
1 2
3

5 4

2
Edges
1
5 3
Directed
Edge 4
BASIC TERMINOLOGIES
A directed graph G is defined as an ordered pair (V, E) where, V is a set of vertices and the ordered pairs in E are called edges on V. A
directed graph can be represented geometrically as a set of marked points (called vertices) V with a set of arrows (called edges) E between
pairs of points (or vertex or nodes) so that there is at most one arrow from one vertex to another vertex. For example, Fig 9.2 shows a directed
graph, where G = {a, b, c, d}, {(a, b), (a, d), (d, b), (d, d), (c, c)}
An edge (a, b), in said to the incident with the vertices it joints, i.e., a, b. We can also say that the
edge (a, b) is incident from a to b. The vertex a is called the initial vertex and the vertex b is called the
terminal vertex of the edge (a, b). If an edge that is incident from and into the same vertex, say (d, d) of
(c, c) in Fig. 9.2, is called a loop.

Two vertices are said to be adjacent if they are joined by an edge. Consider edge (a, b), the vertex a
is said to be adjacent to the vertex b, and the vertex b is said to be adjacent from the vertex a. A vertex is
said to be an isolated vertex if there is no edge incident with it. In Fig. 9.2 vertex C is an isolated vertex.

An undirected graph G is defined abstractly as an ordered pair (V, E), where V is a set of vertices
and the E is a set at edges. An undirected graph can be represented geometrically as a set of marked
points (called vertices) V with a set at lines (called edges) E between the points. An undirected graph G is
shown in Fig. 9.3.
The degree of a vertex v, denoted deg(v), is the number of incident
edges of v. The in-degree and out-degree of a vertex v are the number
of the incoming and outgoing edges of v, and are denoted indeg(v) and
outdeg(v), respectively.
Degree of 3 is 3
2 In Degree of 3 is 2
1 Out Degree of 3 is 1

5 3 Degree of 4 is 2
In Degree of 4 is 1
4
adjacent
1 2
3
Incoming
Edges 2
5 4

2
Incident 3
1
5 3
Outgoing
Edges 2 4
Lec.11

Let G = (V, E) be a graph. A graph G1 = (V1, E1) is said to be a sub-graph of G if E1 is a subset at E and V1 is a subset at V such that the
edges in E1 are incident only with the vertices in V1. For example Fig 9.5 (b) is a sub-graph at Fig. 9.5(a). A sub- graph of G is said to be a
spanning sub-graph if it contains all the vertices of G. For example Fig. 9.5(c) shows a spanning sub-graph at Fig. 9.5(a).

The number of edges incident on a vertex is its degree. The degree of vertex a, is written as degree (a). If the degree of
vertex a is zero, then vertex a is called isolated vertex. For example the degree of the vertex a in Fig. 9.5 is 3.

A graph G is said to be weighted graph if every edge and/or vertices in the graph is assigned with some weight or value. A
weighted graph can be defined as G = (V, E, We, Wv) where V is the set of vertices, E is the set at edges and We is a weights of
the edges whose domain is E and Wv is a weight to the vertices whose domain is V. Consider the following graph.

Fig 9:6 shows the distance in km b/w four cities in India. Here V = {N, K, M, C,} E = {(N, K), (N, M), (M, K), (M,C), (K,C)} We = {55,47,
39, 27, 113} and Wv = {N, K, M, C} the weight at the vertices is not necessary to maintain have become the set Wv and V are same.
Allowing for two undirected edges to have the same end vertices, and for two
directed edges to have the same origin and the same destination. Such edges
are called parallel edges or multiple edges.

e3
A e4 B
e5
e2 e1

D C
e2
e3
self-loop A e4 B
e5
e1
An edge (undirected or directed) is a
self-loop if its two endpoints coincide
D C

A B
simple

An edge (undirected or directed) is a self-loop


D C if its two endpoints coincide
Adjacency Matrix
Directed graph representation
•Adjacency matrix is a sequential representation.
•It is used to represent which nodes are adjacent to each other.
i.e. is there any edge connecting nodes to a graph.
•In this representation, we have to construct a nXn matrix A. If
there is any edge from a vertex i to vertex j, then the Undirected graph representation

corresponding element of A, ai,j = 1, otherwise ai,j= 0.


•If there is any weighted graph then instead of 1s and 0s, we can
store the weight of the edge.

Graph Representation
• Adjacency Matrix
• Incidence Matrix
• Adjacency List
2. Incidence Matrix
e1 e2 e3 e4 e5
e1 1 1 0 0 0
A B A
e3 e5 B -1 0 1 0 1
e2
C 0 0 0 -1 -1
e4
D C D 0 -1 -1 1 0
Adjacency List

•Adjacency list is a linked representation.

•In this representation, for each vertex in the

graph, we maintain the list of its neighbors. It

means, every vertex of the graph contains list of

its adjacent vertices.

•We have an array of vertices which is indexed

by the vertex number and for each vertex v, the

corresponding array element points to a singly

linked list of neighbors of v.


DFS
BFS
Graph Searching Methodology Depth-First Search (DFS)

Depth-First Search (DFS)


– Searches down one path as deep as
possible
– When no nodes available, it backtracks
– When backtracking, it explores side-
paths that were not taken
– Uses a stack (instead of a queue in BFS)
– Allows an easy recursive
implementation
– Recursive marking algorithm
– Initially every vertex is unmarked
• n vertices and m edges
• Storage complexity O(n + m)
• Time complexity O(n + m)
• Linear Time!
DFS vs BFS
Walk in Graph Theory-
 
In graph theory,
•A walk is defined as a finite length alternating sequence of vertices
and edges.
•The total number of edges covered in a walk is called as Length
of the Walk.
 

In this graph, few examples of walk are-


•a , b , c , e , d (Length = 4)
•d , b , a , c , e , d , e , c (Length = 7)
•e , c , b , a , c , e , d (Length = 6)

•Open walk- A walk is said to be an open walk if the starting and ending
vertices are different i.e. the origin vertex and terminal vertex are different. 
Closed walk- A walk is said to be a closed walk if the starting and ending
vertices are identical i.e. if a walk starts and ends at the same vertex, then it is said to
be a closed walk. 
Trail –  Circuit – 
Trail is an open walk in which no edge is repeated.  Traversing a graph such that not an edge is repeated but vertex
Vertex can be repeated. can be repeated and it is closed also i.e. it is a closed trail. 
   
     Vertex can be repeated.
Edge can not be repeated.

Here 1->3->8->6->3->2 is trail 


Also 1->3->8->6->3->2->1 will be a closed trail 
Euler Graph and Path

Euler Graph Euler Path-


 
Any connected graph is called as an • Euler path is also known as Euler
Euler Graph if and only if all its
Trail or Euler Walk.
vertices are of even degree.
OR
An Euler Graph is a connected •If there exists a Trail in the
graph that contains an Euler Circuit. connected graph that contains all the
edges of the graph, then that trail is
An Euler circuit is a circuit that called as an Euler trail.
uses every edge in a graph with no OR
repeats. Being a circuit, it must start •If there exists a walk in the
and end at the same vertex. connected graph that visits every
edge of the graph exactly once,
then such a walk is called as an Euler
walk. (Vertex can be repeated)
 
Euler graph
What are Hamiltonian Cycles and Paths

• A Hamiltonian path, also called a Hamilton


path, is a graph path between two vertices of
a graph that visits each vertex exactly once. If a
Hamiltonian path exists whose endpoints are
adjacent, then the resulting graph cycle is called
a Hamiltonian cycle (or Hamiltonian cycle).
• A graph that possesses a Hamiltonian path is
called a traceable graph.
Spanning Tree
The spanning tree is a subgraph of an undirected connected graph. It
includes all the vertices in the subgraph and the least number of edges that
can connect every vertex without forming a loop or cycle. 
The spanning tree must have an equal number of vertices as of the given
graph. In the spanning tree, the total number of edges is n-1. Here, n is the
number of vertices in the graph.

Minimum Spanning Tree


A minimum spanning tree or minimum cost spanning tree is that spanning tree, which covers all the vertices of the graph with
minimum edges and the sum of the weight of those edges is minimum among other spanning trees of that graph. 
The minimum spanning trees are mainly of two types:
•Prim’s MST
•Kruskal’s MST
Prim’s Algorithm
Kruskal’s MST
Dijkstra’s Shortest Path Algorithm

• Given a graph and a source vertex

in the graph, find the shortest

paths from the source to all

vertices in the given graph.

Dijkstra algorithm is a single-source shortest path algorithm. Here, single-


source means that only one source is given, and we have to find the shortest
path from the source to all the nodes.
Transitive closure of a graph

• Given a directed graph, find out if a vertex j is reachable from another vertex i
for all vertex pairs (i, j) in the given graph. Here reachable mean that there is a
path from vertex i to j. The reach-ability matrix is called the transitive closure
of a graph.
Activity Network
First define the activities and estimate their duration, we are ready to create an activity network diagram which is a
graphical representation of the logical relationship (i.e., dependencies) among the project activities.
Activities are carried out in order. Therefore, they have predecessors and successors. They have logical
relationships or dependencies which show the sequence in which the activities are to be performed. There are four
relationships between activities, which can be indicated as “Finish-to-Start” (FS), “Finish-to-Finish” (FF), “Start-
to-Start” (SS), and “Start-to-Finish” (SF).

Showing the activities in rectangles or circles, and their


relationships (dependencies) as arrows is called a precedence
diagramming method (PDM). This kind of diagram is also called an
activity-on-node (AON) diagram (Figure 7.1). Another way to
show how tasks relate is with the activity-on-arrow (AOA) diagram
(Figure 7.1). 
Activity Network Lead
A lead is the opposite of a lag. A lead is the
1. Finish-to-Start (FS) Relationship amount of time a successor activity can be
In this relationship, a predecessor activity should be finished in order advanced with respect to a predecessor
to start the successor activity. This is the most common relationship activity. In Figure 7.4, Activity B (successor)
between activities. As seen in Figure 7.2, Activity A must be finished to can start three days before Activity A
start Project B. (predecessor) finishes
•Ex. We must finish cooking all our meals (predecessor) to start
serving them in the dinner (successor).
•We should finish packing all the luggage to start driving to the airport
for the holiday.

2. Lag
A lag is the amount of time a successor activity can be delayed with
respect to a predecessor activity Consider that we should paint one room
in our house. We need to apply plaster to walls first (predecessor). When
the walls dry, we can paint them (successor). It is an FS relationship.
Read More:
However, we need to wait for two days for the walls to dry. This causes a
https://pressbooks.ulib.csuohio.edu/pro
two-day delay between two activities which is called a lag (Figure 7.3). ject-management-navigating-the-compl
exity/chapter/7-4-creating-an-activity-n
                          etwork-diagram/

 Figure 7.3: Finish-to-Start with a Lag


Topological Sort
The topological sort algorithm takes a directed acyclic graph and returns an array of the
nodes where each node appears before all the nodes it points to.
The ordering of the nodes in the array is called a topological ordering.

Since node 1 points to nodes 2 and 3, node 1 appears before them


in the ordering. And, since nodes 2 and 3 both point to node 4, they
appear before it in the ordering.

So [1, 2, 3, 4, 5] would be a topological ordering of the graph.

Can a graph have more than one valid topological ordering? Yep! In the example

above, [1, 3, 2, 4, 5] works too.


Topo sort - good example
B Any linear ordering in which
C all the arrows go to the right
A
is a valid solution
F

D E

A B F C D E
Note that F can go anywhere in this list because it is not connected.
Also the solution is not unique.
Topo sort - bad example
B
C
A Any linear ordering in which
an arrow goes to the left
F is not a valid solution

D E

A B F C E D
NO!
Topological Sort
Given a digraph G = (V, E), find a linear ordering of
its vertices such that:
for any edge (v, w) in E, v precedes w in the ordering
B
C
A
F

D E

12/26/03
Only acyclic graphs can be topo. sorted

• A directed graph with a cycle cannot be


topologically sorted.

B
C
A
F

D E

12/26/03 Digraphs - Lecture 14 316


Topo sort algorithm - 1a
Step 1: Identify vertices that have no incoming edges
• If no such vertices, graph has only cycle(s) (cyclic graph)
• Topological sort not possible – Halt.

B
C
A

Example of a cyclic graph


D

12/26/03 Digraphs - Lecture 14 317


Topo sort algorithm
Step 1: Identify vertices that have Step 2: Identify vertices that have no
no incoming edges incoming edges
The “in-degree” of these vertices is zero • Select one such vertex

Select
B B
C C
A A
F F
D E D E
Step 3: Delete this vertex of in-degree Repeat Step 1 and Step 2 Step 3until
0 and all its outgoing edges from the graph is empty
graph. Place it in the output.
Continue until done
B Select
C
A
B
F A C

D F A
E

D E

319
Select B. Copy to sorted list. Delete B
B and its edges.
B
C

F A B

D E
C
Select C. Copy to sorted list. Delete C and its edges.
C

F A B C

12/26/03 D E 320
D Select D. Copy to sorted list. Delete D and its edges.

F A B C D

D E

E, F Select E. Copy to sorted list. Delete E and its edges.


Select F. Copy to sorted list. Delete F and its edges.

F A B C D E F

E
Done
B
C
A
F

D E

A B C D E F

12/26/03 Digraphs - Lecture 14 322


Implementation
Assume adjacency list
representation
B
C 1 2 4
A
2 3
F
3 4 5
D E 4 5
5
Translation 1 2 3 4 5 6 6
value next
array A B C D E F

12/26/03 Digraphs - Lecture 14 323


Calculate In-degrees
D A

0 1 2 4
1 2 3
1 3 4 5
In-Degree
array; or add a 2 4 5
field to array A 5
2
0 6

12/26/03 Digraphs - Lecture 14 324


Calculate In-degrees

for i = 1 to n do D[i] := 0; endfor


for i = 1 to n do
x := A[i];
while x ≠ null do
D[x.value] := D[x.value] + 1;
x := x.next;
endwhile
endfor

12/26/03 Digraphs - Lecture 14 325


Maintaining Degree 0 Vertices
Key idea: Initialize and maintain a queue (or stack)
of vertices with In-Degree 0 D A

0 1 2 4
Queue 1 6
1 2 3
1 3 4 5
2 3
6 2 4 5
1
2 5
4 5
0 6

12/26/03 Digraphs - Lecture 14 326


Topo Sort using a Queue
(breadth-first)
After each vertex is output, when updating In-Degree array,
enqueue any vertex whose In-Degree becomes zero
D A
Queue 6 2
dequeue enqueue 0 1 2 4
Output 1 0 2 3
1 3 4 5
2 3 1 4 5
1 6
2 5
4 5
0 6
12/26/03 Digraphs - Lecture 14 327
References
• http://www.cprogramming.com/tutorial/computersciencetheory/mergesort.html
• http://www.sorting-algorithms.com/merge-sort
• http://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/Sorting/mergeSort.htm
• http://en.wikipedia.org/wiki/Merge_sort
• Lecture #05: © Dsamanta, CS 10001 : Programming and Data Structures
• https://www.geeksforgeeks.org/heap-sort/
• https://www.geeksforgeeks.org/data-structures/
• https://www.javatpoint.com/data-structure-tutorial
• https://www.scaler.com/topics/data-structures/
• https://www.programiz.com/dsa
• https://nptel.ac.in/courses/106103069
• https://nptel.ac.in/courses/106102064
• https://www.javatpoint.com/

ashish0751@gmail.com

You might also like