You are on page 1of 146

Define Data structure ?

Data Structure can be defined as the group of data elements which provides an efficient

way of storing and organising data in the computer so that it can be used efficiently.

Some examples of Data Structures are arrays, Linked List, Stack, Queue, etc. Data

Structures are widely used in almost every aspect of Computer Science i.e. Operating

System, Compiler Design, Artifical intelligence, Graphics and many more.

or

“A data structure is basically a group of data elements that are put together under one

name, and which defines a particular way of storing and organizing data in a computer so

that it can be used efficiently.”

Data Structures are widely used in the given below areas.

•COMPILER DESIGN
•OPERATING SYSTEM
•DBMS
•ARTIFICIAL INTELLIGENCE
•GRAPHICS
•SIMULATION
•NUMERICAL ANALYSIS etc.
Classification of data Structure PRIMITIVE DATA TYPE –:

Primitive data structures are the fundamental data types which are supported by a

programming language. some basic data types are integer, character, Boolean pointer,

float, double, and real.

NON-PRIMITIVE DATA STRUCTURES -:

Non-primitive data structures are that data structures that are created using primitive data

structures as-: as array, linked list, tree, etc.

LINEAR DATA STRUCTURES -:

If the element of data structures is stored in linear or sequential order then it is called linear

data structures as-: array, stack, queue, linked list.

Linear data structures are stored in memory with a linear relationship between elements by

means of a sequential memory location.


Arrays: An array is a collection of similar type of data items and each data item is called

an element of the array. The data type of the element may be any valid data type like char,

int, float or double.

Linked List:Linked list is a linear data structure which is used to maintain a list in the

memory. It can be seen as the collection of nodes stored at non-contiguous memory

locations. Each node of the list contains a pointer to its adjacent node.

Stack: Stack is a linear list in which insertion and deletions are allowed only at one end,

called top.

Queue: Queue is a linear list in which elements can be inserted only at one end called rear

and deleted only at the other end called front.

NON-LINEAR DATA STRUCTURES –:

If the element of data structures is not stored in sequential order, then it is called non-linear

data structures. As -: tree and graph.

Non-linear data structures are stored in memory with random orders location.

Trees: Trees are multilevel data structures with a hierarchical relationship among its

elements known as nodes. The bottommost nodes in the hierarchy are called leaf node

while the topmost node is called root node. Each node contains pointers to point adjacent

nodes.

Graphs: Graphs can be defined as the pictorial representation of the set of elements

(represented by vertices) connected by the links known as edges. A graph is different from

tree in the sense that a graph can have cycle while the tree cannot have the one.
Data Structure Operations

1) Traversing: Every data structure contains the set of data elements. Traversing the data
structure means visiting each element of the data structure in order to perform some
specific operation like searching or sorting.
Example: If we need to calculate the average of the marks obtained by a student in 6
different subjects, we need to traverse the complete array of marks and calculate the total
sum, then we will divide that sum by the number of subjects i.e. 6, in order to find the
average.

2) Insertion: Insertion can be defined as the process of adding the elements to the data
structure at any location.
If the size of data structure is n then we can only insert n-1 data elements into it.

3) Deletion:The process of removing an element from the data structure is called Deletion.
We can delete an element from the data structure at any random location.
If we try to delete an element from an empty data structure then underflow occurs.

4) Searching: The process of finding the location of an element within the data structure is
called Searching. There are two algorithms to perform searching, Linear Search and
Binary Search.

5) Sorting: The process of arranging the data structure in a specific order is known as
Sorting. There are many algorithms that can be used to perform sorting, for example,
insertion sort, selection sort, bubble sort, etc.

6) Merging: When two lists List A and List B of size M and N respectively, of similar type of
elements, clubbed or joined to produce the third list, List C of size (M+N), then this process
is called merging

What is a Stack?

A Stack is a linear data structure that follows the LIFO (Last-In-First-Out) principle. Stack

has one end, whereas the Queue has two ends (front and rear). It contains only one

pointer top pointer pointing to the topmost element of the stack. Whenever an element is
added in the stack, it is added on the top of the stack, and the element can be deleted only

from the stack top. In other words, a stack can be defined as a container in which

insertion and deletion can be done from the one end known as the top of the stack.

1. Working of Stack

Stack works on the LIFO pattern. As we can observe in the below figure there are five

memory blocks in the stack; therefore, the size of the stack is 5.

Suppose we want to store the elements in a stack and let's assume that stack is empty.

We have taken the stack of size 5 as shown below in which we are pushing the elements

one by one until the stack becomes full.

2. Standard Stack Operations

The following are some common operations implemented on the stack:


•push(): When we insert an element in a stack then the operation is known as a
push. If the stack is full then the overflow condition occurs.

•Pop(): When we delete an element from the stack, the operation is known as a
pop. If the stack is empty means that no element exists in the stack, this state is
known as an underflow state.

•IsEmpty(): It determines whether the stack is empty or not.

•IsFull(): It determines whether the stack is full or not.'

•peek(): It returns the element at the given position.

•Count(): It returns the total number of elements available in a stack.

•Change(): It changes the element at the given position.

•Display(): It prints all the elements available in the stack.

3. PUSH operation

The steps involved in the PUSH operation is given below:

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

•If we try to insert the element in a stack, and the stack is full, then the overflow
condition occurs.

•When we initialize a stack, we set the value of top as -1 to check that the stack is
empty.

•When the new element is pushed in a stack, first, the value of the top gets
incremented, i.e., top=top+1, and the element will be placed at the new position of
the top.

•The elements will be inserted until we reach the max size of the stack.
POP Operation

The steps involved in the POP operation is given below:

•Before deleting the element from the stack, we check whether the stack is empty.

•If we try to delete the element from the empty stack, then the underflow condition occurs.

•If the stack is not empty, we first access the element which is pointed by the top

•Once the pop operation is performed, the top is decremented by 1, i.e., top=top-1.
4. Ap
plication
s of
Stack

Balancin
g of
symbols:
Stack is
used for balancing a symbol. For example, we have the following program:
intmain()

1. {
2. cout<<"Poly";
3. cout<<"Technic";
4. }

As we know, each program has an opening and closing braces; when the opening braces

come, we push the braces in a stack, and when the closing braces appear, we pop the

opening braces from the stack. Therefore, the net value comes out to be zero. If any

symbol is left in the stack, it means that some syntax occurs in a program.

String reversal: Stack is also used for reversing a string. For example, we want to reverse

a "Poly Technic" string, so we can achieve this with the help of a stack.

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.

DFS(Depth First Search):This search is implemented on a Graph, and Graph uses the

stack data structure.


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 prefix

Infix to postfix

Prefix to infix

Prefix to postfix

Postfix to infix

Array implimatation of Stack

In array implementation, the stack is formed by using the array. All the operations

regarding the stack are performed using arrays.

1. Adding an element onto the stack (push operation)

Adding an element into the top of the stack is referred to as push operation. Push
operation involves following two steps.

1.Increment the variable Top so that it can now refere to the next memory location.

2.Add element at the position of incremented top. This is referred to as adding new
element at the top of the stack.

Algorithm

begin

if top = n then stack full


top = top + 1

stack (top) : = item;

end

1. implementation of push algorithm in C language

void push (int val,int n) //n is size of the stack

if (top == n )

printf("\n Overflow");

else

top = top +1;

stack[top] = val;

}
1. Deletion of an element from a stack (Pop operation)

Deletion of an element from the top of the stack is called pop operation. The value of the

variable top will be Decrimented by 1 whenever an item is deleted from the stack. The top

most element of the stack is stored in an another variable and then the top is decremented

by 1. the operation returns the deleted value that was stored in another variable as the

result.

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

stack.

Algorithm

begin

if top = 0 then stack empty;

item = stack(top);

top = top - 1;

end;

2. Implementation of POP algorithm using C language

int pop ()

if(top == -1)

printf("Underflow");

return 0;

}
else

return stack[top - - ];

Visiting each element of the stack (Peek operation)

Peek operation involves returning the element which is present at the top of the stack w ithout

deleting it. Underflow condition can occur if we try to return the top element in an already empty

stack.

Begin
if top = -1 then stack empty
item = stack[top]
return item
End

3. Implementation of Peek algorithm using C language

int peek()
{
if (top == -1)
{
printf("Underflow");
return 0;
}
else
{
return stack [top];
}
}
4. Implementation of Stack using Array

#include <stdio.h>
int stack[100],i,j,choice=0,n,top=-1;
void push();
void pop();
void show();
void main ()
{
printf("Enter the number of elements in the stack ");
scanf("%d",&n);
printf("*********Stack operations using array*********");
printf("\n----------------------------------------------\n");
while(choice != 4)
{
printf("Chose one from the below options...\n");
printf("\n1.Push\n2.Pop\n3.Show\n4.Exit");
printf("\n Enter your choice \n");
scanf("%d",&choice);
switch(choice)
{
case 1:
{
push();
break;
}
case 2:
{
pop();
break;
}
case 3:
{
show();
break;
}
case 4:
{
printf("Exiting....");
break;
}
default:
{
printf("Please Enter valid choice ");
}
}
}
}

void push ()
{
int val;
if (top == n )
printf("\n Overflow");
else
{
printf("Enter the value?");
scanf("%d",&val);
top = top +1;
stack[top] = val;
}
}

void pop ()
{
if(top == -1)
printf("Underflow");
else
top = top -1;
}

void show()
{
for (i=top;i>=0;i--)
{
printf("%d\n",stack[i]);
}
if(top == -1)
{
printf("Stack is empty");
}
}
Infix-to-Postfix Conversion

Sample example :

Input infix expression : a * ( b + c + d)


Output postfix expression : abc+d+*
Input Infix expression : a*b
Output postfix expression : ab*

Precedenc
Type Operators Associativity
e
1 Postfix () [] -> . ++ — Left to Right
2 Unary + – ! ~ ++ — (type)* & sizeof Right to Left
3 Multiplicative */% Left to Right
4 Additive +– Left to Right
5 Shift <<, >> Left to Right
6 Relational < <= > >= Left to Right
7 Equality == != Left to Right
8 Bitwise AND & Left to Right
9 Bitwise XOR ^ Left to Right
10 Bitwise OR | Left to Right
11 Logical AND && Left to Right
12 Logical OR || Left to Right
13 Conditional ?: Right to Left
14 Assignment = += -+ *= /= %= >>= <<= &= ^= |= Right to Left
15 Comma , Left to Right

What is Infix Notation?

Infix notation is the notation in which operators come between the required

operands. It is the same as the arithmetic notation that we had learned in our

school days.
1. Syntax of infix notation

The syntax of infix notation is X op Y.

Example - If we were to add two numbers 3 and 4, the operator that is '+' would come

between the operands 3 and 4. So the infix notation will be 3 + 4.

What is Postfix Expression?

Postfix Expression, also known as Reverse Polish Notation is the type of notation in which

operator comes after the operand. For eg- If the infix expression is x + y, it's corresponding

postfix notation is x y +.

Conversion of Infix to Postfix

1. Rules for the conversion from infix to postfix expression

Initially we have a infix expression given to us to convert to postfix notation. The infix

notation is parsed from left to right, and then converted to postfix. Assume initially the

postfix expression is empty, and we will fill the postfix expression out with the following

steps:

1.If we have an opening parenthesis "(", we push it into the stack.

2.If we have an operand, we append it to our postfix expression.

3.If we have a closing parenthesis ")" we keep popping out elements from the top of

the stack and append them to our postfix expression until we encounter an opening

parenthesis. We pop out the left parenthesis without appending it.


4.If we encounter an operator: -

4.1. If the operator has higher precedence than the one on top of the stack

(We can compare), we push it in the stack.

4.2. If the operator has lower or equal precedence than the one on top of the

stack, we keep popping out and appending it to the postfix expression.

5.When the last token of infix expression has been scanned, we pop the remaining

elements from stack and append them to our postfix expression.

Infix expression: K + L - M*N + (O^P) * W/U/V * T + Q

postfix expression is :KL+MN∗−OPW∗U/V/T∗+Q+


Element Stack contents Postfix Expression
K
K

+
+
L + KL

- K L+
-

- K L+M
M

-* K L+M
*

-* K L+M N
N

+ K L+M N * -
+

+( K L+M N * -
(

+(^ K L+M N * - O
O

^ K L+M N * - O
+(^

+(^ K L+M N * - O P
P

+ K L+ M N * - O P^
)

+* K L + M N* - O P ^
*

+* K L + M N* - O P ^ W
W

K L + M N* - O P ^ W *
/ +/

U K L + M N* - O P ^W * U
+/

/ K L + M N* - O P ^W * U /
+/

V K L + M N* - O P ^ W * U / V
+/

* K L + M N* - O P ^W * U / V /
+*

T K L + M N* - O P ^W * U / V / T
+*

+ K L + M N* - O P ^W * U / V / T * +
+

+ K L + M N* - O P ^W * U / V / T * + Q
Q
Element Stack contents Postfix Expression
K L + M N* - O P ^W * U / V / T * + Q+

Infix to Postfix Conversion Example


Convert the (X - Y / (Z + U) * V) infix expression into postfix expression.

S.N. Input Operand Stack Postfix Expression


1 ( ( -
2 X ( X
3 - (- X
4 Y (- XY
5 / (-/ XY
6 ( (-/( XY
7 Z (-/( XYZ
8 + (-/(+ XYZ
9 U (-/(+ XYZU
10 ) (-/ XYZU+
11 * (-* XYZU+/
12 V (-* XYZU+/V
13 ) - XYZU+/V*-

Infix Expression Postfix Expression


A*B/C AB*C/
(A/(B-C+D))*(E-A)*C ABC-D+/EA-*C*
A/B-C+D*E-A*C AB/C-DE*AC*-

Introduction to Queues

1.A queue can be defined as an ordered list which enables insert operations to be

performed at one end called REAR and delete operations to be performed at

another end called FRONT.

2. Queue is referred to be as First in First Out list.


3. For example, people waiting in line for a rail ticket form a queue.

Appication of Queue

1Queues are widely used as waiting lists for a single shared resource like

printer, disk, CPU.

2.Queues are used in asynchronous transfer of data (where data is not being
transferred at the same rate between two processes) for eg. pipes, file IO, sockets.

3.Queues are used as buffers in most of the applications like MP3 media player, CD
player, etc.

4.Queue are used to maintain the play list in media players in order to add and
remove the songs from the play-list.

5.Queues are used in operating systems for handling interrupts.

Types of Queues.

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.
Types of Queue

There are four different types of queue that are listed as follows -
1. Simple Queue or Linear Queue

2. Circular Queue

3. Priority Queue
4. Double Ended Queue (or Deque)

1. Simple Queue or Linear Queue


In Linear Queue, an insertion takes place from one end while the deletion occurs

from another end. The end at which the insertion takes place is known as the rear

end, and the end at which the deletion takes place is known as front end. It strictly

follows the FIFO rule.


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.

2. Circular Queue

A circular queue is similar to a linear queue as it is also based on the FIFO (First In First

Out) principle except that the last position is connected to the first position in a

circular queue that forms a circle. It is also known as a Ring Buffer.


3. Operations on Circular Queue

o Front: It is used to get the front element from the Queue.

o Rear: It is used to get the rear element from the Queue.

•enQueue(value): This function is used to insert the new value in the Queue. The
new element is always inserted from the rear end.

•DeQueue(): This function deletes an element from the Queue. The deletion in a
Queue always takes place from the front end.

4. Applications of Circular Queue


o Memory management: The circular queue provides memory management. As we have
already seen that in linear queue, the memory is not managed very efficiently. But in case
of a circular queue, the memory is managed efficiently by placing the elements in a
location which is unused.

o CPU Scheduling: The operating system also uses the circular queue to insert the processes
and then execute them.

o Traffic system: In a computer-control traffic system, traffic light is one of the best
examples of the circular queue. Each light of traffic light gets ON one by one after every
interval of time. Like red light gets ON for one minute then yellow light for one minute and
then green light. After green light, the red light gets ON.
There was one limitation in the array implementation of Queue. If the rear reaches to the
end position of the Queue, then there might be possibility that some vacant spaces are
left in the beginning which cannot be utilized. So, to overcome such limitations, the
concept of the circular queue was introduced.
when rear reach the end of a queue, start from the beginning of a queue. The circular
incrementation is achievable with the help of the modulo division.

Let’s say the MaxSize of your queue is 5, and the rear pointer has already reached the
end of a queue. There is one empty space at the beginning of a queue, which means
that the front pointer is pointing to location 1.

Algorithm to insert an element in a circular queue

Step 1: IF (REAR+1) %MAX = FRONT


Write " OVERFLOW "
Goto step 4
[End OF IF]

Step 2: IF FRONT = -1 and REAR = -1


SET FRONT = REAR = 0
ELSE IF REAR = MAX - 1 and FRONT! = 0
SET REAR = 0
ELSE
SET REAR = (REAR + 1) % MAX
[END OF IF]

Step 3: SET QUEUE[REAR] = VAL

Step 4: EXIT

Priority queue.

It is a special type of queue in which the elements are arranged based on the
priority.
It is a special type of queue data structure in which every element has a priority
associated with it.
Suppose some elements occur with the same priority, they will be arranged
according to the FIFO principle.
The representation of priority queue is shown in the below image –

Insertion in priority queue takes place based on the arrival, while deletion in the
priority queue occurs based on the priority. Priority queue is mainly used to
implement the CPU scheduling algorithms.

There are two types of priority queue that are discussed as follows –

o Ascending priority queue - In ascending priority queue, elements can be


inserted in arbitrary order, but only smallest can be deleted first. Suppose
an array with elements 7, 5, and 3 in the same order, so, insertion can be done
with the same sequence, but the order of deleting the elements is 3, 5, 7.
o Descending priority queue - In descending priority queue, elements can be
inserted in arbitrary order, but only the largest element can be deleted
first. Suppose an array with elements 7, 3, and 5 in the same order, so,
insertion can be done with the same sequence, but the order of deleting the
elements is 7, 5,
3.

o
Characteristics of Priority Queue

Priority queue in a data structure is an extension of a linear queue that possesses the
following properties:

• Every element has a certain priority assigned to it.

• Every element of this queue must be comparable.

• It will delete the element with higher priority before the element with
lower priority.

• If multiple elements have the same priority, it does their removal from the
queue according to the FCFS principle.

understand these properties with the help of an example. Consider you have to insert
7, 2, 45, 32, and 12 in a priority queue. The element with the least value has the
highest property. Thus, you should maintain the lowest element at the front node.
Deque (or double-ended queue)

The deque stands for Double Ended Queue. Deque is a linear data structure where
the insertion and deletion operations are performed from both ends.

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

1. Types of deque
There are two types of deque -
o Input restricted queue
o Output restricted queue
Input restricted Queue
In input restricted queue, insertion operation can be performed at only one end,
while deletion can be performed from both ends.
Output restricted Queue

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

2. Operations performed on deque

There are the following operations that can be applied on a deque -


o Insertion at front
o Insertion at rear
o Deletion at front
o Deletion at rear
Array representation of Queue

We can easily represent queue by using linear arrays. There are two

variables i.e. front and rear, that are implemented in the case of every

queue. Front and rear variables point to the position from where insertions

and deletions are performed in a queue. Initially, the value of front and

queue is -1 which represents an empty queue. Array representation of a

queue containing 5 elements along with the respective values of front and

rear, is shown in the following figure.


Algorithm to insert any element in a queue

Check if the queue is already full by comparing rear to max - 1. if so, then
return an overflow error.
If the item is to be inserted as the first element in the list, in that case set
the value of front and rear to 0 and insert the element at the rear end.
Otherwise keep increasing the value of rear and insert each element one
by one having rear as the index.
Algorithm

Step 1: IF REAR = MAX – 1


Write OVERFLOW
Go to step
[END OF IF]

Step 2: IF FRONT = -1 and REAR = -1


SET FRONT = REAR = 0
ELSE
SET REAR = REAR + 1
[END OF IF]

Step 3: Set QUEUE[REAR] = NUM

Step 4: EXIT

C Function

void insert (int queue[], int max, int front, int rear, int item)
{
if (rear + 1 == max)
{
printf("overflow");
}
else
{
if(front == -1 && rear == -1)
{
front = 0;
rear = 0;
} There are various operations which can be performed on singly
linked list. A list of all such operations is given below.
else
{
rear = rear + 1;
}
queue[rear]=item;
}
}

Algorithm to delete an element from the queue


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

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

Step 2: EXIT
C Function

int delete (int queue[], int max, int front, int rear)
{
int y;
if (front == -1 || front > rear)

{
printf("underflow");
}
else
{
y = queue[front];
if(front == rear)
{
front = rear = -1;
else
front = front + 1;

}
return y;
}
}
Menu driven program to implement queue using array

#include<stdio.h>
#include<stdlib.h>
#define maxsize 5
void insert();
void delet();
void display();
int front = -1, rear = -1;
int queue[maxsize];
void main ()
{
int choice=0;
while(choice != 4)
{

printf("\n*************************MainMenu***********************\n");

printf("\n===================================================\n");
printf("\n1.insert an element\n2.Delete an element\n3.Display the queue\n4.Exit\n");
printf("\nEnter your choice ?");
scanf("%d",&choice);
switch(choice)
{
case 1:
insert();
break;
case 2:
delet();
break;
case 3:
display();
break;
case 4:
exit(0);
break;
default:
printf("\nEnter valid choice??\n");
}
}
}

void insert()
{
int item;
printf("\nEnter the element\n");
scanf("\n%d",&item);
if(rear == maxsize-1)
{
printf("\nOVERFLOW\n");
return;
}
if(front == -1 && rear == -1)
{
front = 0;
rear = 0;
}
else
{
rear = rear+1;
}
queue[rear] = item;
printf("\nValue inserted ");
}

void delet()
{
int item;
if (front == -1 || front > rear)
{
printf("\nUNDERFLOW\n");
return;

}
else
{
item = queue[front];
if(front == rear)
{
front = -1;
rear = -1 ;
}
else
{
front = front + 1;
}
printf("\nvalue deleted ");
}
}

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]);
}
}
}
Out Put

*************Main Menu**************

==============================================

1.insert an element
2.Delete an element
3.Display the queue
4.Exit

Enter your choice ?1

Enter the element


123

Value inserted

*************Main Menu**************

==============================================

1.insert an element
2.Delete an element
3.Display the queue
4.Exit

Enter your choice ?1


Enter the element
90

Value inserted

*************Main Menu**************

===================================

1.insert an element
2.Delete an element
3.Display the queue
4.Exit

Enter your choice ?2

value deleted

*************Main Menu**************
==============================================

1.insert an element
2.Delete an element
3.Display the queue
4.Exit

Enter your choice ?3


printing values .....

90

*************Main Menu**************

==============================================

1.insert an element
2.Delete an element
3.Display the queue
4.Exit

Enter your choice ?4


Module – 2

Linked List

o Linked List can be defined as collection of objects called nodes that are

randomly stored in the memory.

o A node contains two fields i.e., data stored at that particular address and

the pointer which contains the address of the next node in the memory.

o The last node of the list contains pointer to the null.

o You have to start somewhere, so we give the address of the first node a
special name called HEAD. Also, the last node in the linked list can be
identified because its next portion points to NULL.
o Linked lists can be of multiple types: singly, doubly, and circular linked list.

Uses of Linked List


o The list is not required to be contiguously present in the memory. The node
can reside anywhere in the memory and linked together to make a list.
This achieves optimized utilization of space.
o list size is limited to the memory size and doesn't need to be declared in
advance.

o Empty node cannot be present in the linked list.

o We can store values of primitive types or objects in the singly linked list.

Why use linked list over array?


Array contains following limitations:

1. The size of array must be known in advance before using it in the


program.

2. Increasing size of the array is a time taking process. It is almost impossible to


expand the size of the array at run time.

3. All the elements in the array need to be contiguously stored in the memory.
Inserting any element in the array needs shifting of all its predecessors.

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

1. It allocates the memory dynamically. All the nodes of linked list are non-
contiguously stored in the memory and linked together with the help of
pointers.

2. Sizing is no longer a problem since we do not need to define its size at the time
of declaration. List grows as per the program's demand and limited to the
available memory space.

Singly linked list or One way chain


Singly linked list can be defined as the collection of ordered set of elements. The

number of elements may vary according to need of the program. A node in the singly

linked list consists of two parts: data part and link part. Data part of the node
stores actual information that is to be represented by the node while the link

part of the node stores the address of its immediate successor.

One way chain or singly linked list can be traversed only in one direction. In other

words, we can say that each node contains only next pointer, therefore we cannot

traverse the list in the reverse direction.

In the above figure, the arrow represents the links. The data part of every node

contains the marks obtained by the student in the different subject. The last node in

the list is identified by the null pointer which is present in the address part of the last

node. We can have as many elements we require, in the data part of the list.

Operations on Singly Linked List

There are various operations which can be performed on singly linked list. A list of
all such operations is given below.

1.

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

3. Node Creation

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

/* Initialize nodes */
struct node *head;
struct node *one = NULL;
struct node *two = NULL;
struct node *three = NULL;

/* Allocate memory */
one = malloc(sizeof(struct node));
two = malloc(sizeof(struct node));
three = malloc(sizeof(struct node));

/* Assign data values */


one->data = 1;
two->data = 2;
three->data=3;

/* Connect nodes */
one->next = two;
two->next = three;
three->next = NULL;

/* Save address of first node in head */


head = one;

The power of a linked list comes from the ability to break the chain and rejoin it. E.g.
if you wanted to put an element 4 between 1 and 2, the steps would be:

• Create a new struct node and allocate memory to it.

• Add its data value as 4

• Point its next pointer to the struct node containing 2 as the data value

• Change the next pointer of "1" to the node we just created.


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

int main()
{
//node structure
struct node
{
int data;
struct node *next;
};

//declaring nodes
struct node *head,*middle,*last;

//allocating memory for each node


head = malloc(sizeof(struct node));
middle = malloc(sizeof(struct node));
last = malloc(sizeof(struct node));

//assigning values to each node


head->data = 10;
middle->data = 20;
last->data = 30;

//connecting each nodes. head->middle->last


head->next = middle;
middle->next = last;
last->next = NULL;

//temp is a reference for head pointer.


struct node *temp = head;

//till the node becomes null, printing each nodes data


while(temp != NULL)
{
printf("%d->",temp->data);
temp = temp->next;
}
printf("NULL");

return 0;
}

Output

1->2->3->NULL
Linked List Operations: Traverse, Insert and Delete

• Traversal - access each element of the linked list.

• Insertion - adds a new element to the linked list.

• Deletion - removes the existing elements.

• Search - find a node in the linked list.

• Sort - sort the nodes of the linked list.

• Head points to the first node of the linked list


• Next pointer of the last node is NULL , so if the next current node is NULL , we

have reached the end of the linked list.

Traverse a Linked List

Displaying the contents of a linked list is very simple. We keep moving the
temp node to the next one and display its contents.

When temp is NULL, we know that we have reached the end of the linked list
so we get out of the while loop.

struct node *temp = head;

printf("\n\nList elements are - \n");

while(temp != NULL)

printf("%d --->",temp->data);

temp = temp->next;
}
Output

List elements are -

1 --->2 --->3 --->

Insert Elements to a Linked List


1. Insert at the beginning

• Allocate memory for new node

• Store data

• Change next of new node to point to head

• Change head to point to recently created node

struct node *newNode;

newNode = malloc(sizeof(struct node));

newNode->data = 4;

newNode->next = head;

head = newNode;
2. Insert at the End

• Allocate memory for new node

• Store data

• Traverse to last node

• Change next of last node to recently created node

struct node *newNode;

newNode = malloc(sizeof(struct node));

newNode->data = 4;

newNode->next = NULL;

struct node *temp = head;

while(temp->next != NULL)

temp = temp->next;

temp->next = newNode;
3. Insert at the Middle

• Allocate memory and store data for new node

• Traverse to node just before the required position of new node

• Change next pointers to include new node in between

struct node *newNode;

newNode = malloc(sizeof(struct node));

newNode->data = 4;

struct node *temp = head;

for(int i=2; i < position; i++)

if(temp->next != NULL)

temp = temp->next;

newNode->next = temp->next;

temp->next = newNode;
Delete from a Linked List

You can delete either from the beginning, end or from a particular posit ion.

1. 1. Delete from beginning

• Point head to the second node

head = head->next;

2. Delete from end

• Traverse to second last element

• Change its next pointer to null

struct node* temp = head;

while(temp->next->next!=NULL)

temp = temp->next;

temp->next = NULL;
3. Delete from middle

• Traverse to element before the element to be deleted

• Change next pointers to exclude the node from the chain

for(int i=2; i< position; i++) {

if(temp->next!=NULL) {

temp = temp->next;

temp->next = temp->next->next;

Search an Element on a Linked List

You can search an element on a linked list using a loop using the following
steps. We are finding item on a linked list.
• Make head as the current node.

• Run a loop until the current node is NULL because the last element

points to NULL.
• In each iteration, check if the key of the node is equal to item. If it the

key matches the item, return true otherwise return false.


#include<stdio.h>

#include<stdlib.h>

struct node

int data;

struct node *next;

};

struct node *head;

void beginsert ();

void lastinsert ();

void randominsert();

void begin_delete();

void last_delete();

void random_delete();
void display();

void search();

int main ()

int choice =0;

while(choice != 9)

printf("\n\n*********Main Menu*********\n");

printf("\nChoose one option from the following list ...\n");

printf("\n===============================================\n");

printf("\n 1.Insert in begining\n2.Insert at last\n3.Insert at any random location\n4.Delete from


Beginning\n 5.Delete from last\n6 Delete node after specified location\n7.Search for an
element\n8.Show\n9.Exit\n");

printf("\nEnter your choice?\n");

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

switch(choice)

case 1:

beginsert();

break;

case 2:

lastinsert();

break;

case 3:

randominsert();

break;
case 4:

begin_delete();

break;

case 5:

last_delete();

break;

case 6:

random_delete();

break;

case 7:

search();

break;

case 8:

display();

break;

case 9:

exit(0);

break;

default:

printf("Please enter valid choice..");

return (0);

void beginsert()

{
struct node *ptr;

int item;

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

if(ptr == NULL)

printf("\nOVERFLOW");

else

printf("\nEnter value\n");

scanf("%d",&item);

ptr->data = item;

ptr->next = head;

head = ptr;

printf("\nNode inserted");

void lastinsert()

struct node *ptr,*temp;

int item;

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

if(ptr == NULL)

printf("\nOVERFLOW");
}

else

printf("\nEnter value?\n");

scanf("%d",&item);

ptr->data = item;

if(head == NULL)

ptr -> next = NULL;

head = ptr;

printf("\nNode inserted");

else

temp = head;

while (temp -> next != NULL)

temp = temp -> next;

temp->next = ptr;

ptr->next = NULL;

printf("\nNode inserted");

}
void randominsert()

int i,loc,item;

struct node *ptr, *temp;

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

if(ptr == NULL)

printf("\nOVERFLOW");

else

printf("\nEnter element value");

scanf("%d",&item);

ptr->data = item;

printf("\nEnter the location after which you want to insert ");

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

temp=head;

for(i=0;i<loc;i++)

temp = temp->next;

if(temp == NULL)

printf("\ncan't insert\n");

return;

}
}

ptr ->next = temp ->next;

temp ->next = ptr;

printf("\nNode inserted");

void begin_delete()

struct node *ptr;

if(head == NULL)

printf("\nList is empty\n");

else

ptr = head;

head = ptr->next;

free(ptr);

printf("\nNode deleted from the begining ...\n");

void last_delete()

struct node *ptr,*ptr1;

if(head == NULL)

{
printf("\nlist is empty");

else if(head -> next == NULL)

head = NULL;

free(head);

printf("\nOnly node of the list deleted ...\n");

else

ptr = head;

while(ptr->next != NULL)

ptr1 = ptr;

ptr = ptr ->next;

ptr1->next = NULL;

free(ptr);

printf("\nDeleted Node from the last ...\n");

void random_delete()

struct node *ptr,*ptr1;

int loc,i;
printf("\n Enter the location of the node after which you want to perform deletion \n");

scanf("%d",&loc);

ptr=head;

for(i=0;i<loc;i++)

ptr1 = ptr;

ptr = ptr->next;

if(ptr == NULL)

printf("\nCan't delete");

return;

ptr1 ->next = ptr ->next;

free(ptr);

printf("\nDeleted node %d ",loc+1);

void search()

struct node *ptr;

int item,i=0,flag;

ptr = head;

if(ptr == NULL)

printf("\nEmpty List\n");
}

else

printf("\nEnter item which you want to search?\n");

scanf("%d",&item);

while (ptr!=NULL)

if(ptr->data == item)

printf("item found at location %d ",i+1);

flag=0;

else

flag=1;

i++;

ptr = ptr -> next;

if(flag==1)

printf("Item not found\n");

}
void display()

struct node *ptr;

ptr = head;

if(ptr == NULL)

printf("Nothing to print");

else

printf("\nprinting values . . . . .\n");

while (ptr!=NULL)

printf("\n%d",ptr->data);

ptr = ptr -> next;

}
Circular Singly Linked List
In a circular Singly linked list, the last node of the list contains a pointer to the first
node of the list. We can have circular singly linked list as well as circular doubly
linked list.

We traverse a circular singly linked list until we reach the same node where we
started. The circular singly liked list has no beginning and no ending. There is no null
value present in the next part of any of the nodes.

Memory Representation of circular linked list


Memory representation of a circular linked list containing marks of a student in 4

subjects. However, the image shows a glimpse of how the circular list is being stored

in the memory. The start or head of the list is pointing to the element with the index 1

and containing 13 marks in the data part and 4 in the next part. Which means that it is

linked with the node that is being stored at 4th index of the list .

In Circular linked list last node of the list contains the address of the first node of the

list.

Operations on Circular Singly linked list:


1. Insertion
SN Operation Description

1 Insertion at beginning Adding a node into circular singly linked list at the beginning.

2 Insertion at the end Adding a node into circular singly linked list at the end.

2. Deletion & Traversing


SN Operation Description

1 Deletion at Removing the node from circular singly linked list at the beginning.
beginning

2 Deletion at the Removing the node from circular singly linked list at the end.
end

3 Searching Compare each element of the node with the given item and return the
location at which the item is present in the list otherwise return null.

4 Traversing Visiting each element of the list at least once in order to perform some
specific operation.
Doubly linked list

Doubly linked list is a complex type of linked list in which a node contains a
pointer to the previous as well as the next node in the sequence. Therefore, in a
doubly linked list, a node consists of three parts: node data, pointer to the next
node in sequence (next pointer), pointer to the previous node (previous
pointer).
The first element of the list that is i.e. 13 stored at address 1. The head pointer points

to the starting address 1. Since this is the first element being added to the list

therefore the prev of the list contains null. The next node of the list resides at address

4 therefore the first node contains 4 in its next pointer.

We can traverse the list in this way until we find any node containing null or -1 in its

next part.
Linked list implementation of stack
In linked list implementation of stack, the nodes are maintained non-contiguously in
the memory. Each node contains a pointer to its immediate successor node in the
stack. Stack is said to be overflown if the space left in the memory heap is not enough
to create a node.

The top most node in the stack always contains null in its address field.

Adding a node to the stack (Push operation)


1. Create a node first and allocate memory to it.

2. If the list is empty then the item is to be pushed as the start node of the list. This includes
assigning value to the data part of the node and assign null to the address part of the node.

3. If there are some nodes in the list already, then we have to add the new element in the
beginning of the list (to not violate the property of the stack). For this purpose, assign the
address of the starting element to the address field of the new node and make the new
node, the starting node of the list.
#include <stdio.h>

#include <stdlib.h>

// Structure to create a node with data and the next pointer

struct node {

int info;

struct node *ptr;

}*top,*top1,*temp;

int count = 0;

// Push() operation on a stack

void push(int data) {

if (top == NULL)

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

top->ptr = NULL;

top->info = data;

else

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

temp->ptr = top;

temp->info = data;
top = temp;

count++;

printf("Node is Inserted\n\n");

int pop() {

top1 = top;

if (top1 == NULL)

printf("\nStack Underflow\n");

return -1;

else

top1 = top1->ptr;

int popped = top->info;

free(top);

top = top1;

count--;

return popped;

}
void display() {

// Display the elements of the stack

top1 = top;

if (top1 == NULL)

printf("\nStack Underflow\n");

return;

printf("The stack is \n");

while (top1 != NULL)

printf("%d--->", top1->info);

top1 = top1->ptr;

printf("NULL\n\n");

int main() {

int choice, value;

printf("\nImplementation of Stack using Linked List\n");


while (1) {

printf("\n1. Push\n2. Pop\n3. Display\n4. Exit\n");

printf("\nEnter your choice : ");

scanf("%d", &choice);

switch (choice) {

case 1:

printf("\nEnter the value to insert: ");

scanf("%d", &value);

push(value);

break;

case 2:

printf("Popped element is :%d\n", pop());

break;

case 3:

display();

break;

case 4:

exit(0);

break;

default:

printf("\nWrong Choice\n");

}
}

Output

Push Operation

Implementation of Stack using Linked List

1. Push

2. Pop

3. Display

4. Exit

Enter your choice : 1

Enter the value to insert: 12

Node is Inserted

1. Push

2. Pop

3. Display

4. Exit

Enter your choice : 1

Enter the value to insert: 45

Node is Inserted
1. Push

2. Pop

3. Display

4. Exit

Enter your choice : 1

Enter the value to insert: 56

Node is Inserted

1. Push

2. Pop

3. Display

4. Exit

Enter your choice : 3

The stack is

56--->45--->12--->NULL
Pop operation

The stack is

56--->45--->12--->NULL

1. Push

2. Pop

3. Display

4. Exit

Enter your choice : 2

Popped element is :56

1. Push

2. Pop

3. Display

4. Exit

Enter your choice : 2

Popped element is :45

1. Push

2. Pop

3. Display

4. Exit
Enter your choice : 3

The stack is

12--->NULL

1. Push

2. Pop

3. Display

4. Exit

Enter your choice : 2

Popped element is :12

1. Push

2. Pop

3. Display

4. Exit
Implementation of Queue using Linked List
#include<stdio.h>
#include<stdlib.h>

// Structure to create a node with data and the next pointer


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

struct node * front = NULL;


struct node * rear = NULL;

// Enqueue() operation on a queue


void enqueue(int value)
{
struct node * ptr;
ptr = (struct node * ) malloc(sizeof(struct node));
ptr->data = value;
ptr->next = NULL;
if ((front == NULL) && (rear == NULL))
{
front = rear = ptr;
}
else
{
rear-> next = ptr;
rear = ptr;
}
printf("Node is Inserted\n\n");
}

// Dequeue() operation on a queue


int dequeue()
{
if (front == NULL)
{
printf("\nUnderflow\n");
return -1;
}
else
{
struct node * temp = front;
int temp_data = front-> data;
front = front-> next;
free(temp);
return temp_data;
}
}

// Display all elements of the queue


void display()
{
struct node * temp;
if ((front == NULL) && (rear == NULL))
{
printf("\nQueue is Empty\n");
}
else
{
printf("The queue is \n");
temp = front;
while (temp)
{
printf("%d--->", temp-> data);
temp = temp-> next;
}
printf("NULL\n\n");
}
}

int main() {
int choice, value;
printf("\nImplementation of Queue using Linked List\n");
while (choice != 4) {
printf("1.Enqueue\n2.Dequeue\n3.Display\n4.Exit\n");
printf("\nEnter your choice : ");
scanf("%d", & choice);
switch (choice)
{
case 1:
printf("\nEnter the value to insert: ");
scanf("%d", & value);
enqueue(value);
break;
case 2:
printf("Popped element is :%d\n", dequeue());
break;
case 3:
display();
break;
case 4:
exit(0);
break;
default:
printf("\nWrong Choice\n");
}
}
return 0;
}

Output

Enqueue Operation

Implementation of Queue using Linked List


1. Enqueue
2. Dequeue
3. Display
4. Exit

Enter your choice: 1

Enter the value to insert: 12


Node is Inserted

1.Enqueue
2.Dequeue
3.Display
4.Exit

Enter your choice: 1

Enter the value to insert: 45


Node is Inserted

1.Enqueue
2.Dequeue
3.Display
4.Exit

Enter your choice: 1

Enter the value to insert: 56


Node is Inserted

1.Enqueue
2.Dequeue
3.Display
4.Exit

Enter your choice : 3


The queue is
12--->45--->56--->NULL

Dequeue Operation

The queue is
12--->45--->56--->NULL

1.Enqueue
2.Dequeue
3.Display
4.Exit

Enter your choice: 2


Popped element is:12
1. Enqueue
2. Dequeue
3. Display
4. Exit
Enter your choice: 2
Popped element is:45
1. Enqueue
2. Dequeue
3. Display
4. Exit

Enter your choice : 3


The queue is
56--->NULL

1.Enqueue
2.Dequeue
3.Display
4.Exit
NON-LINEAR DATA STRUCTURES –:

If the element of data structures is not stored in sequential order, then it is called non-

linear data structures. As -: tree and graph.

Non-linear data structures are stored in memory with random orders location.

Trees: Trees are multilevel data structures with a hierarchical relationship among its

elements known as nodes. The bottommost nodes in the hierarchy are called leaf

node while the topmost node is called root node. Each node contains pointers to

point adjacent nodes.

Graphs: Graphs can be defined as the pictorial representation of the set of elements

(represented by vertices) connected by the links known as edges. A graph is

different from tree in the sense that a graph can have cycle while the tree cannot have

the one.

Non-linear data structure


o A non-linear data structure is another important type in which data elements
are not arranged sequentially; mainly, data elements are arranged in
random order without forming a linear structure.
o Data elements are present at the multilevel, for example, tree.
o In trees, the data elements are arranged in the hierarchical form, whereas
in graphs, the data elements are arranged in random order, using the edges
and vertex.
o Multiple runs are required to traverse through all the elements completely.
Traversing in a single run is impossible to traverse the whole data structure.
o Each element can have multiple paths to reach another element.
o The data structure where data items are not organized sequentially is called a
non-linear data structure. In other words, data elements of the non-linear
data structure could be connected to more than one element to reflect a special
relationship among them.

Tree
A tree is also one of the data structures that represent hierarchical data. Suppose
we want to show the employees and their positions in the hierarchical form then it
can be represented as shown below:
The above tree shows the organization hierarchy of some company. In the above
structure, john is the CEO of the company, and John has two direct reports named
as Steve and Rohan. Steve has three direct reports named Lee, Bob,
Ella where Steve is a manager. Rohan has two direct reports
named Sal and Emma. Emma has two direct reports named Tom and Raj. Tom has
one direct report named Bill. This particular logical structure is known as a Tree. Its
structure is similar to the real tree, so it is named a Tree. In this structure, the root is
at the top, and its branches are moving in a downward direction. Therefore, we
can say that the Tree data structure is an efficient way of storing the data in a
hierarchical way.
o Root: The root node is the topmost node in the tree hierarchy. In other
words, the root node is the one that doesn't have any parent. In the above
structure, node numbered 1 is the root node of the tree. If a node is directly
linked to some other node, it would be called a parent-child relationship.
o Child node: If the node is a descendant of any node, then the node is known
as a child node.
o Parent: If the node contains any sub-node, then that node is said to be the
parent of that sub-node.
o Sibling: The nodes that have the same parent are known as siblings.
o Leaf Node: - The node of the tree, which doesn't have any child node, is
called a leaf node. A leaf node is the bottom-most node of the tree. There
can be any number of leaf nodes present in a general tree. Leaf nodes can also
be called external nodes.
o Internal nodes: A node has atleast one child node known as an internal
o Ancestor node: - An ancestor of a node is any predecessor node on a path
from the root to that node. The root node doesn't have any ancestors. In the
tree shown in the above image, nodes 1, 2, and 5 are the ancestors of node 10.
o Descendant: The immediate successor of the given node is known as a
descendant of a node. In the above figure, 10 is the descendant of node 5.
Degree

1. Degree of a node is the total number of children of that node.


2. Degree of a tree is the highest degree of a node among all the nodes in the tree.

• Degree of node A = 2
• Degree of node B = 3
• Degree of node C = 2
• Degree of node D = 0
• Degree of node E = 2
• Degree of node F = 0
• Degree of node G = 1
• Degree of node H = 0
• Degree of node I = 0
• Degree of node J = 0
• Degree of node K = 0

Level

• In a tree, each step from top to bottom is called as level of a tree.


• The level count starts with 0 and increments by 1 at each level or step.

Height

• Total number of edges that lies on the longest path from any leaf node to a particular
node is called as height of that node.
• Height of a tree is the height of root node.
• Height of all leaf nodes = 0
Here,

• Height of node A = 3
• Height of node B = 2
• Height of node C = 2
• Height of node D = 0
• Height of node E = 1
• Height of node F = 0
• Height of node G = 1
• Height of node H = 0
• Height of node I = 0
• Height of node J = 0
• Height of node K = 0

Depth

• Total number of edges from root node to a particular node is called as depth of that
node.
• Depth of a tree is the total number of edges from root node to a leaf node in the
longest path.
• Depth of the root node = 0
• The terms “level” and “depth” are used interchangeably.
Here,

• Depth of node A = 0
• Depth of node B = 1
• Depth of node C = 1
• Depth of node D = 2
• Depth of node E = 2
• Depth of node F = 2
• Depth of node G = 2
• Depth of node H = 2
• Depth of node I = 3
• Depth of node J = 3
• Depth of node K = 3
Subtree

• In a tree, each child from a node forms a subtree recursively.


• Every child node forms a subtree on its parent node.

Forest

A forest is a set of disjoint trees


Binary Tree
The Binary tree means that the node can have maximum two children. Here,
binary name itself suggests that 'two'; therefore, each node can have either 0, 1 or 2
children.

The above tree is a binary tree because each node contains the utmost two children.
The logical representation of the above tree is given below:

In the above tree, node 1 contains two pointers, i.e., left and a right pointer
pointing to the left and right node respectively. The node 2 contains both the nodes
(left and right node); therefore, it has two pointers (left and right). The nodes 3, 5
and 6 are the leaf nodes, so all these nodes contain NULL pointer on both left
and right parts.
Types of Binary Trees:

Full Binary Tree

A full binary tree can be defined as a binary tree in which all the nodes have 0 or two children. In
other words, the full binary tree can be defined as a binary tree in which all the nodes have two
children except the leaf nodes.
Complete binary tree
A binary tree is said to be a complete binary tree when all the levels are completely filled
except the last level, which is filled from the left.
The below tree is a complete binary tree:

The complete binary tree is similar to the full binary tree except for the two differences
which are given below:

o The filling of the leaf node must start from the leftmost side.

o It is not mandatory that the last leaf node must have the right sibling.
Let's understand the above points through an example:
Consider the below tree:

The above tree is a complete binary tree, but not a full binary tree as node 6 does not have its right
sibling.

Full/ proper/ strict Binary tree


The full binary tree is also known as a strict binary tree. The tree can only be considered as the full
binary tree if each node must contain either 0 or 2 children. The full binary tree can also be defined
as the tree in which each node must contain 2 children except the leaf nodes.
Perfect Binary Tree
A tree is a perfect binary tree if all the internal nodes have 2 children, and all the leaf nodes are at
the same level.

Linked Representation of Binary Tree in C

1. We use the concept of doubly-linked lists to represent a node.

2. The left pointer of this node points to the left child and the right pointer points
to the right child, and if there is no left or right child, we represent that using
a NULL.
Operations on a Binary Search Tree

What is a Binary Search tree

A binary search tree follows some order to arrange the elements. In a Binary search tree, the value
of left node must be smaller than the parent node, and the value of right node
must be greater than the parent node. This rule is applied recursively to the left and right
subtrees of the root.

Let's understand the concept of Binary search tree with an example.

In the above figure, we can observe that the root node is 40, and all the nodes of the left subtree are
smaller than the root node, and all the nodes of the right subtree are greater than the root node.
Similarly, we can see the left child of root node is greater than its left child and smaller than its
right child. So, it also satisfies the property of binary search tree. Therefore, we can say that the
tree in the above image is a binary search tree.

Suppose if we change the value of node 35 to 55 in the above tree, check whether the tree will
be binary search tree or not.

In the above tree, the value of root node is 40, which is greater than its left child 30 but smaller than
right child of 30, i.e., 55. So, the above tree does not satisfy the property of Binary search tree.
Therefore, the above tree is not a binary search tree.

Advantages of Binary search tree


o Searching an element in the Binary search tree is easy as we always have a hint that which
subtree has the desired element.

o As compared to array and linked lists, insertion and deletion operations are faster in BST.
Example of creating a binary search tree
Now, let's see the creation of binary search tree using an example.
Suppose the data elements are - 45, 15, 79, 90, 10, 55, 12, 20, 50

o First, we have to insert 45 into the tree as the root of the tree.

o Then, read the next element; if it is smaller than the root node, insert it as the root of the left
subtree, and move to the next element.

o Otherwise, if the element is larger than the root node, then insert it as the root of the right
subtree.

Step 1 - Insert 45.

Step 2 - Insert 15.


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

Step 3 - Insert 79.

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

90 is greater than 45 and 79, so it will be inserted as the right subtree of 79 .

Step 5 - Insert 10.

10 is smaller than 45 and 15, so it will be inserted as a left subtree of 15 .

Step 6 - Insert 55.

55 is larger than 45 and smaller than 79, so it will be inserted as the left subtree of 79.
Step 7 - Insert 12.

12 is smaller than 45 and 15 but greater than 10, so it will be inserted as the right subtree of 10.

Step 8 - Insert 20.

20 is smaller than 45 but greater than 15, so it will be inserted as the right subtree of 15.
Step 9 - Insert 50.

50 is greater than 45 but smaller than 79 and 55. So, it will be inserted as a left subtree of 55 .

Now, the creation of binary search tree is completed.

Searching in Binary search tree

Searching means to find or locate a specific element or node in a data structure. In Binary search
tree, searching a node is easy because elements in BST are stored in a specific order. The steps of
searching a node in Binary Search tree are listed as follows –

1. First, compare the element to be searched with the root element of the tree.

2. If root is matched with the target element, then return the node's location.

3. If it is not matched, then check whether the item is less than the root elemen t, if it is smaller
than the root element, then move to the left subtree.

4. If it is larger than the root element, then move to the right subtree.

5. Repeat the above procedure recursively until the match is found.

6. If the element is not found or not present in the tree, then return NULL.

Now, let's understand the searching in binary tree using an example. We are taking the binary search
tree formed above. Suppose we have to find node 20 from the below tree.
Step1:

Step2:

Step3:
4 is not f ound so, traverse through the lef t subtree of 8
Algorithm to search an element in Binary search tree
Search (root, item)
Step 1 - if (item = root → data) or (root = NULL)
return root
else if (item < root → data)
return Search(root → left, item)
else
return Search(root → right, item)
END if
Step 2 - END

Binary search tree traversal

Preorder traversal sequence : F, B, A, D, C, E, G, I, H


(root, left, right)

Inorder traversal sequence : A, B, C, D, E, F, G, H, I


(left, root, right)

Postorder traversal sequence: A, C, E, D, B, H, I, G, F


(left, right, root)
Preorder traversal

1. Visit root node

2. Visit all the nodes in the left subtree

3. Visit all the nodes in the right subtree

Inorder traversal

1. First, visit all the nodes in the left subtree

2. Then the root node

3. Visit all the nodes in the right subtree

Postorder traversal

1. Visit all the nodes in the left subtree

2. Visit all the nodes in the right subtree

3. Visit the root node


Inorder traversal sequence: (left, root, right)

Preorder traversal sequence: (root, left, right)

Postorder traversal sequence: (left, right, root)

Inorder Algorithm

Until all nodes are traversed −

Step 1 − Recursively traverse left subtree.

Step 2 − Visit root node.

Step 3 − Recursively traverse right subtree.


Preorder Algorithm

Until all nodes are traversed −

Step 1 − Visit root node.

Step 2 − Recursively traverse left subtree.

Step 3 − Recursively traverse right subtree.

Post Algorithm

Until all nodes are traversed −

Step 1 − Recursively traverse left subtree.

Step 2 − Recursively traverse right subtree.

Step 3 − Visit root node.

Binary Search Tree: Insertion

A new key is always inserted at the leaf by maintaining the property of the binary search tree. We
start searching for a key from the root until we hit a leaf node. Once a leaf node is found, the new
node is added as a child of the leaf node. The below steps are followed while we try to insert a
node into a binary search tree:

• Check the value to be inserted (say X) with the value of the current node
(say val) we are in:
• If X is less than val move to the left subtree.
• Otherwise, move to the right subtree.
• Once the leaf node is reached, insert X to its right or left based on the relation
between X and the leaf node’s value.
Let us try to insert a node with value 40 in this tree:
1st step: 40 will be compared with root, i.e., 100.
• 40 is less than 100.
• So move to the left subtree of 100. The root of the left subtree is 20.
2nd step: 40 is now compared with 20.
• It is greater than 20.
• So move to the right subtree of 20 whose root is 30.
3rd step: 30 is a leaf node.
• So we have to insert 40 to the left or right of 30.
• As 40 is greater than 30, insert 40 to the right of 30.
Binary search tree Deletion

Delete function is used to delete the specified node from a binary search tree. However, we must
delete a node from a binary search tree in such a way, that the property of binary search tree
doesn't violate. There are three situations of deleting a node from binary search tree .

The node to be deleted is a leaf node

It is the simplest case, in this case, replace the leaf node with the NULL and simple free the
allocated space.
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.

The node to be deleted has only one child.


In this case, replace the node with its child and delete the child node, which now contains
the value which is to be deleted. Simply replace it with the NULL and free the allocated
space.
In the following image, the node 12 is to be deleted. It has only one child. The node will be
replaced with its child node and the replaced node 12 (which is now leaf node) will simply
be deleted.
The node to be deleted has two children.

It is a bit complexed case compare to other two cases. However, the node which is to be
deleted, is replaced with its in-order successor or predecessor recursively until the node
value (to be deleted) is placed on the leaf of the tree. After the procedure, replace the node
with NULL and free the allocated space.
In the following image, the node 50 is to be deleted which is the root node of the tree. The
in-order traversal of the tree given below.
6, 25, 30, 50, 52, 60, 70, 75.
replace 50 with its in-order successor 52. Now, 50 will be moved to the leaf of the tree,
which will simply be deleted.
binary search tree Deletion algorithm

• If the root is NULL, then return root (Base case)


• If the key is less than the root’s value, then set root->left =
deleteNode(root->left, key)
• If the key is greater than the root’s value, then set root->right =
deleteNode(root->right, key)
• Else check
• If the root is a leaf node, then return null
• else if it has only the left child, then return the left child
• else if it has only the right child, then return the right child
• else set the value of root as of its inorder successor and recur
to delete the node with the value of the inorder successor
Module V

Graph

A graph is a non-linear data structure that has a finite number of vertices and edges, and these
edges are used to connect the vertices. The vertices are used to store the data elements, while the
edges represent the relationship between the vertices. A graph is used in various real-world
problems like telephone networks, circuit networks, social networks like LinkedIn, Facebook. In
the case of facebook, a single user can be considered as a node, and the conn ection of a user with
others is known as edges.

Definition

A graph G can be defined as an ordered set G(V, E) where V(G) represents the set of vertices and
E(G) represents the set of edges which are used to connect these vertices.
A Graph G(V, E) with 5 vertices (A, B, C, D, E) and six edges ((A,B), (B,C), (C,E), (E,D), (D,B),
(D,A)) is shown in the following figure.
Graph Terminologies

Vertex and Edge

A graph is a set of points, called nodes or vertices, which are interconnected by a set of lines
called edges.

An edge is the mathematical term for a line that connects two vertices. Many edges can be formed
from a single vertex. Without a vertex, an edge cannot be formed. There must be a starting vertex
and an ending vertex for an edge

Here, ‘a’ and ‘b’ are the two vertices and the link between them is called an edge.

Adjacent vertices and edges

• In a graph, two vertices are said to be adjacent, if there is an edge between the two
vertices. Here, the adjacency of vertices is maintained by the single edge that is
connecting those two vertices.
• In a graph, two edges are said to be adjacent, if there is a common vertex
between the two edges. Here, the adjacency of edges is maintained by the single
vertex that is connecting two edges.

In the above graph −


• ‘a’ and ‘b’ are the adjacent vertices, as there is a common edge ‘ab’ between them.
• ‘a’ and ‘d’ are the adjacent vertices, as there is a common edge ‘ad’ between them.
• ab’ and ‘be’ are the adjacent edges, as there is a common vertex ‘b’ between them.
• be’ and ‘de’ are the adjacent edges, as there is a common vertex ‘e’ between them.
Self-loop /Loop

In a graph, if an edge is drawn from vertex to itself, it is called a loop.

In the above graph, V is a vertex for which it has an edge (V, V) forming a loop.

In this graph, there are two loops which are formed at vertex a, and vertex b .

Parallel edges

In a graph, if a pair of vertices is connected by more than one edge, then those edges are called
parallel edges.

In the above graph, ‘a’ and ‘b’ are the two vertices which are connected by two edges ‘ab’ and ‘ab’
between them. So, it is called as a parallel edge.

Isolated vertex

A vertex with degree zero is called an isolated vertex.

Here, the vertex 'a' and vertex 'b' has a no connectivity between each other and also to any other
vertices. So, the degree of both the vertices 'a' and 'b' are zero. These are also called as isolated
vertices.

Degree of vertex

In graph theory , the degree of a vertex is the number of edges connecting it. In the example
below, vertex a has degree 5, and the rest have degree 1. A vertex with degree 1 is called an "end
vertex"
In the above Undirected Graph,
• deg(a) = 2, as there are 2 edges meeting at vertex 'a'.
• deg(b) = 3, as there are 3 edges meeting at vertex 'b'.
• deg(c) = 1, as there is 1 edge formed at vertex 'c'
So 'c' is a pendent vertex.
• deg(d) = 2, as there are 2 edges meeting at vertex 'd'.
• deg(e) = 0, as there are 0 edges formed at vertex 'e'.
So 'e' is an isolated vertex.

In the above graph,


deg(a) = 2, deg(b) = 2, deg(c) = 2, deg(d) = 2, and deg(e) = 0.
The vertex 'e' is an isolated vertex. The graph does not have any pendent vertex.
Pendant vertex
By using degree of a vertex, we have a two special types of vertices. A vertex with degree one is
called a pendent vertex and A vertex with degree zero is called an isolated vertex.

subgraph

A graph in data structure is said to be a subgraph if it is a part of another graph. In the


following example, graphs H1, H2 and H3 are subgraphs of the graph G.

A subgraph G of a graph is graph G’ whose vertex set and edge set subsets of the graph G. In simple
words a graph is said to be a subgraph if it is a part of another graph .

There are 2 different types of subgraphs:

Vertex Disjoint in Graph Theory

A subgraph with no common vertex is called a vertex disjoint subgraph of the parent graph G.
Since the vertices in a vertex disjoint graph cannot have a common edge, a vertex disjoint
subgraph will always be an edge-disjoint subgraph.
Paths and Cycles

Walk:

A walk can be defined as a sequence of edges and vertices of a graph. When we have a graph
and traverse it, then that traverse will be known as a walk. In a walk, there can be repeated
edges and vertices. The number of edges which is covered in a walk will be known as the
Length of the walk. In a graph, there can be more than one walk.

So, for a walk, the following two points are important, which are described as follows:

o Edges can be repeated

o Vertex can be repeated

For example: In this example, we have a graph, which is described as follows:

In the above graph, there can be many walks, but some of them are described as follows:
1. A, B, C, E, D (Number of length = 4)

2. D, B, A, C, E, D, C (Number of length = 7)

3. E, C, B, A, C, E, D (Number of length = 6)

Open Walk:
A walk will be known as an open walk in the graph theory if the vertices at which the walk starts
and ends are different. That means for an open walk, the starting vertex and ending vertex must
be different. In an open walk, the length of the walk must be more than 0.

Closed Walk:
A walk will be known as a closed walk in the graph theory if the vertices at which the walk starts
and ends are identical. That means for a closed walk, the starting vertex and ending vertex must
be the same. In a closed walk, the length of the walk must be more than 0.

1. Closed walk = A, B, C, D, E, C, A
2. Open walk = A, B, C, D, E, C

Paths
A path is a type of open walk where neither edges nor vertices are allowed to repeat. There is a
possibility that only the starting vertex and ending vertex are not same in a path. In an open walk,
the length of the walk must be more than 0.

So, for a path, the following two points are important, which are described as follows:

o Edges cannot be repeated

o Vertex cannot be repeated


In the above graph, there is a path, which is described as follows:

Path: F, H, C, A, B, D

Cycle:

A closed path in the graph theory is also known as a Cycle. A cycle is a type of closed walk
where neither edges nor vertices are allowed to repeat. There is a possibility that only the starting
vertex and ending vertex are the same in a cycle.

So, for a cycle, the following two points are important, which are described as follows:

o Edges cannot be repeated

o Vertex cannot be repeated


In the above graph, there is a cycle, which is described as follows:

Cycle: A, B, D, C, A

Cycle is a closed path.


These cannot have repeat anything (neither edges nor vertices).

Types of Graphs
Directed Graphs

A graph whose all edges are directed by arrows is known as a directed graph. They are also
known as digraphs .

Undirected Graphs

A graph whose edges are not directed by arrows is known as an undirected graph.

Simple

A graph that is undirected and has no parallel edges or loops is known as a simple graph.

A simple graph with n vertices has the degree of every vertex is at most n-1.
Complete Graphs

A complete graph is a graph in which each pair of graph vertices is connected by an edge. A
complete graph with n number of vertices contains exactly nC2 edges and is represented by Kn.

In the above image we see that each vertex in the graph is connected with all the remaining vertices
through exactly one edge hence both graphs are complete graphs.

Connected Graph

A connected graph is a graph where we can visit from any one vertex to an y other vertex. In a
connected graph, there is at least one edge or path that exists between every pair of vertices.

Disconnected Graphs

A disconnected graph is a graph in which no path exists between every pair of vertices.
Cyclic Graphs

For a graph to be called a cyclic graph, it should consist of at least one cycle. If a graph has a
minimum of one cycle present, it is called a cyclic graph.

The graph shown in the image has two cycles present, satisfying the required condition for a graph
to be cyclic, thus making it a cyclic graph.

Acyclic Graphs

A graph is called an acyclic graph if zero cycles are present, and an acyclic graph is the
complete opposite of a cyclic graph.
The graph shown in the above image is acyclic because it has zero cycles present in it. That means
if we begin traversing the graph from vertex B, then a single path doesn't exist that will traverse all
the vertices and end at the same vertex that is vertex B.

Bipartite Graph

A bipartite graph is a special kind of graph with the following properties-

• It consists of two sets of vertices X and Y.


• The vertices of set X join only with the vertices of set Y.
• The vertices within the same set do not join.

Here,

• The vertices of the graph can be decomposed into two sets.


• The two sets are X = {A, C} and Y = {B, D}.
• The vertices of set X join only with the vertices of set Y and vice-versa.
• The vertices within the same set do not join.
• Therefore, it is a bipartite graph.
Complete Bipartite

A complete bipartite graph may be defined as follows

A bipartite graph where every vertex of set X is joined to every vertex of set Y is called as
complete bipartite graph.

The following graph is an example of a complete bipartite graph-

Here,

• This graph is a bipartite graph as well as a complete graph.


• Therefore, it is a complete bipartite graph.
• This graph is called as K4,3 .
Connected Graph

• A graph in which we can visit f rom any one vertex to any other vertex is called as a connected
graph.
• In connected graph, at least one path exists between every p air of vertices.

Here,

• In this graph, we can visit from any one vertex to any other vertex.
• There exists at least one path between every pair of vertices.
• Therefore, it is a connected graph .

Disconnected Graphs

A graph in which there does not exist any path between at least one pair of vertices is called as a
disconnected graph.
Regular Graphs

• A graph in which degree of all the vertices is same is called as a regular graph.
• If all the vertices in a graph are of degree ‘k’, then it is called as a “ k-regular graph “.

In these graphs,

• All the vertices have degree-2.


• Therefore, they are 2-Regular graphs.

Representation of Graphs – Set


It stores elements in a sorted way, and duplicate elements are not allowed. Therefore, this
approach cannot be used for graphs containing parallel edges.

Following is an example of an undirected and unweighted graph with 5 vertices.


Below is adjacency list representation of this graph using array of sets.
Representation of Graphs – Linked
An adjacency list is used in the linked representation to store the Graph in the computer's memory.
It is efficient in terms of storage as we only have to store the values for edges.

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

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

An adjacency list is maintained for each node present in the graph, which stores the node value and
a pointer to the next adjacent node to the respective node. If all the adjacent nodes are traversed,
then store the NULL in the pointer field of the last node of the list.
Now, consider the directed graph, and let's see the adjacency list representation of that graph .

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

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

Representation of Graphs - Matrix

In graph theory, a graph representation is a technique to store graph into the memory of
computer.

To represent a graph, we just need the set of vertices, and for each vertex the neighbours of
the vertex (vertices which is directly connected to it by an edge). If it is a weighted graph, then
the weight will be associated with each edge.

Adjacency Matrix

o Adjacency matrix is a sequential representation.

o It is used to represent which nodes are adjacent to each other. i.e., is there any edge
connecting nodes to a graph.
o If there is any weighted graph then instead of 1s and 0s, we can store the weight of the
edge.

Example

Consider the following undirected graph representation:

Directed graph representation

See the directed graph representation:

In the above examples, 1 represents an edge from row vertex to column vertex, and 0 represents no
edge from row vertex to column vertex.
Undirected weighted graph representation

Pros: Representation is easier to implement and follow.

Cons: It takes a lot of space and time to visit all the neighbours of a vertex, we have to traverse all
the vertices in the graph, which takes quite some time.

Incidence Matrix
In Incidence matrix representation, graph can be represented using a matrix of size:

Total number of vertices by total number of edges.


It means if a graph has 4 vertices and 6 edges, then it can be represented using a matrix of 4X6
class. In this matrix, columns represent edges and rows represent vertices.

This matrix is filled with either 0 or 1 or -1. Were,

o 0 is used to represent row edge which is not connected to column vertex.

o 1 is used to represent row edge which is connected as outgoing edge to column vertex.

o -1 is used to represent row edge which is connected as incoming edge to column vertex.

Example

Consider the following directed graph representation.


Graph Traversals

Graph traversal is a technique used for searching a vertex in a graph. The graph traversal is also
used to decide the order of vertices is visited in the search process. A graph traversal finds the edges
to be used in the search process without creating loops. That means using graph traversal we visit
all the vertices of the graph without getting into looping path.

There are two graph traversal techniques and they are as follows...

1. DFS (Depth First Search)

2. BFS (Breadth First Search)

BFS algorithm

A standard BFS implementation puts each vertex of the graph into one of two categories:

1. Visited

2. Not Visited

The purpose of the algorithm is to mark each vertex as visited while avoiding cycles.

The algorithm works as follows:

1. Start by putting any one of the graph's vertices at the back of a queu e.

2. Take the front item of the queue and add it to the visited list.

3. Create a list of that vertex's adjacent nodes. Add the ones which aren't in the
visited list to the back of the queue.

4. Keep repeating steps 2 and 3 until the queue is empty.

The graph might have two different disconnected parts so to make sure that we cover
every vertex, we can also run the BFS algorithm on every node
Let's see how the Breadth First Search algorithm works with an example. We use an undirected
graph with 5 vertices.

Undirected graph with 5 vertices

We start from vertex 0, the BFS algorithm starts by putting it in the Visited list and putting all its
adjacent vertices in the stack.

Visit start vertex and add its adjacent vertices to queue

Next, we visit the element at the front of queue i.e. 1 and go to its adjacent nodes. Since 0 has
already been visited, we visit 2 instead.

Visit the f irst neighbour of start node 0, which is 1

Vertex 2 has an unvisited adjacent vertex in 4, so we add that to the back of the queue and visit 3,
which is at the front of the queue.
Visit 2 which was added to queue earlier to add its neighbours

4 remains in the queue

Only 4 remains in the queue since the only adjacent node of 3 i.e. 0 is already visited. We visit it.

Visit last remaining item in the queue to check if it has unvisited neighbours
Depth first Search

Depth first Search or Depth first traversal is a recursive algorithm for searching all the vertices of a
graph or tree data structure. Traversal means visiting all the nodes of a graph.

Depth First Search Algorithm

A standard DFS implementation puts each vertex of the graph into one of two categories:

1. Visited

2. Not Visited

The purpose of the algorithm is to mark each vertex as visited while avoiding cycles.

The DFS algorithm works as follows:

1. Start by putting any one of the graph's vertices on top of a stack.

2. Take the top item of the stack and add it to the visited list.

3. Create a list of that vertex's adjacent nodes. Add the ones which aren't in the visited list to
the top of the stack.

4. Keep repeating steps 2 and 3 until the stack is empty.

Let's see how the Depth First Search algorithm works with an example. We use an undirected graph
with 5 vertices.
We start from vertex 0, the DFS algorithm starts by putting it in the Visited list and putting all its
adjacent vertices in the stack.

We start from vertex 0, the DFS algorithm starts by putting it in the Visited list and putting all its
adjacent vertices in the stack.

Next, we visit the element at the top of stack i.e. 1 and go to its adjacent nodes. Since 0 has already
been visited, we visit 2 instead.

Vertex 2 has an unvisited adjacent vertex in 4, so we add that to the top of the stack and visit it .
After we visit the last element 3, it doesn't have any unvisited adjacent nodes, so we have completed
the Depth First Traversal of the graph.

You might also like