0% found this document useful (0 votes)
13 views

DSA NOTES

Uploaded by

Anitha Sakthivel
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views

DSA NOTES

Uploaded by

Anitha Sakthivel
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 199

UNIT I LINEAR DATA STRUCTURES – LIST

Data:
A collection of facts, concepts, figures, observations, occurrences or instructions in a
Formalized manner.
Information:
The meaning that is currently assigned to data by means of the conventions applied to
those data(i.e. processed data)
Record:
Collection of related fields.
Data type:
Set of elements that share common set of properties used to solve a program.
Data Structures:
Data Structure is the way of organizing, storing, and retrieving data and their relationship
with each other.
Characteristics of data structures:
1. It depicts the logical representation of data in computer memory.
2. It represents the logical relationship between the various data elements.
3. It helps in efficient manipulation of stored data elements.
4. It allows the programs to process the data in an efficient manner.
Operations on Data Structures:
1.Traversal
2.Search
3.Insertion
4.Deletion
CLASSIFICATION OF DATA STRUCTURES

DATA STRUCTURES

PRIMARY DATA STRUCTURES SECONDARY DATA STRUCTURES

INT, CHAR, FLOAT DOUBLE


LINEAR DATA NON LINEAR DATA
STRUCTURES STRUCTURES

ARRAYS STACKS QUEUES TREES GRAPHS


LISTS

Primary Data Strucutres/Primitive Data Structures:


Primitive data structures include all the fundamental data structures that can be directly
manipulated by machine-level instructions. Some of the common primitive data structures
include integer, character, real, boolean etc
Secondary Data Structures/Non Primitive Data Structures:
Non primitive data structures, refer to all those data structures that are derived from one or
more primitive data structures. The objective of creating non-primitive data structures is to form
sets of homogeneous or heterogeneous data elements.
Linear Data Structures:
Linear data structures are data strucutres in which, all the data elements are arranged in i, linear
or sequential fashion. Examples of data structures include arrays, stacks, queues, linked lists, etc.

Non Linear Structures:


In non-linear data strucutres, there is definite order or sequence in which data elements are
arranged. For instance, a non-linear data structures could arrange data elements in a hierarchical
fashion. Examples of non-linear data structures are trees and graphs.
Application of data structures:
Data structures are widely applied in the following areas:

Compiler design
Operating system
Statistical analysis package
DBMS
Numerical analysis
Simulation
Artificial intelligence
Graphics

ABSTRACT DATA TYPES (ADTS):

An abstract Data type (ADT) is defined as a mathematical model with a collection of operations
defined on that model. Set of integers, together with the operations of union, intersection and set
difference form a example of an ADT. An ADT consists of data together with functions that
operate on that data.
Advantages/Benefits of ADT:
1.Modularity
2.Reuse
3. code is easier to understand
4. Implementation of ADTs can be changed without requiring changes to the program that uses
the ADTs.

THE LIST AI)T:


List is an ordered set of elements.
The general form of the list is A1 ,A2 , ……,AN
A1 - First element of the list
A2- 1st element of the list
N –Size of the list

If the element at position i is Ai, then its successor is Ai+1 and its predecessor is Ai-1
Various operations performed on List

1. Insert (X, 5)- Insert the element X after the position 5.


2. Delete (X) - The element X is deleted
3. Find (X) - Returns the position of X.
4. Next (i) - Returns the position of its successor element i+1.
5. Previous (i) Returns the position of its predecessor i-1.
6. Print list - Contents of the list is displayed.
7. Makeempty- Makes the list empty.

Implementation of list ADT:

1. Array based Implementation


2. Linked List based implementation
Array Implementation of list:
Array is a collection of specific number of same type of data stored in consecutive memory
locations. Array is a static data structure i.e., the memory should be allocated in advance and the
size is fixed. This will waste the memory space when used space is less than the allocated space.
Insertion and Deletion operation are expensive as it requires more data movements
Find and Print list operations takes constant time.

The basic operations performed on a list of elements are


a. Creation of List.
b. Insertion of data in the List
c. Deletion of data from the List
d. Display all data‟s in the List
e. Searching for a data in the list
Declaration of Array:

#define maxsize 10
int list[maxsize], n ;
Create Operation:
Create operation is used to create the list with „ n „ number of elements .If „ n „ exceeds the
array‟s maxsize, then elements cannot be inserted into the list. Otherwise the array elements are
stored in the consecutive array locations (i.e.) list [0], list [1] and so on.
void Create ( )
{
int i;
printf("\nEnter the number of elements to be added in the list:\t");
scanf("%d",&n);
printf("\nEnter the array elements:\t");
for(i=0;i<n;i++)
scanf("%d",&list[i]);
}

If n=6, the output of creation is as follows:


list[6]

Insert Operation:
Insert operation is used to insert an element at particular position in the existing list. Inserting the
element in the last position of an array is easy. But inserting the element at a particular position
in an array is quite difficult since it involves all the subsequent elements to be shifted one
position to the right.
Routine to insert an element in the array:
void Insert( )
{
int i,data,pos;
printf("\nEnter the data to be inserted:\t");
scanf("%d",&data);
printf("\nEnter the position at which element to be inserted:\t");
scanf("%d",&pos);
if (pos==n)
printf (“Array overflow”);
for(i = n-1 ; i >= pos-1 ; i--)
list[i+1] = list[i];
list[pos-1] = data;
n=n+1;
Display();}
Consider an array with 5 elements [ max elements = 10 ]
10 20 30 40 50

If data 15 is to be inserted in the 2nd position then 50 has to be moved to next index position, 40
has to be moved to 50 position, 30 has to be moved to 40 position and 20 has to be moved to
30 position.
10 20 30 40 50

10 20 30 40 50

After this four data movement, 15 is inserted in the 2nd position of the array.
10 15 20 30 40 50

Deletion Operation:
Deletion is the process of removing an element from the array at any position.
Deleting an element from the end is easy. If an element is to be deleted from any particular
position ,it requires all subsequent element from that position is shifted one position towards
left.
Routine to delete an element in the array:
void Delete( )
{
int i, pos ;
printf("\nEnter the position of the data to be deleted:\t");
scanf("%d",&pos);
printf("\nThe data deleted is:\t %d", list[pos-1]);
for(i=pos-1;i<n-1;i++)
list[i]=list[i+1];
n=n-1;
Display();
}
Consider an array with 5 elements [ max elements = 10 ]

10 20 30 40 50

If data 20 is to be deleted from the array, then 30 has to be moved to data 20 position, 40 has to
be moved to data 30 position and 50 has to be moved to data 40 position.

10 20 30 40 50
After this 3 data movements, data 20 is deleted from the 2nd position of the array.

10 30 40 50

Display Operation/Traversing a list


Traversal is the process of visiting the elements in a array.
Display( ) operation is used to display all the elements stored in the list. The elements are stored
from the index 0 to n - 1. Using a for loop, the elements in the list are viewed
Routine to traverse/display elements of the array:
void display( )
{
int i;
printf("\n**********Elements in the array**********\n");
for(i=0;i<n;i++)
printf("%d\t",list[i]);
}

Search Operation:
Search( ) operation is used to determine whether a particular element is present in the list or not.
Input the search element to be checked in the list.
Routine to search an element in the array:
void Search( )
{
int search,i,count = 0;
printf("\nEnter the element to be searched:\t");
scanf("%d",&search);
for(i=0;i<n;i++)
{
if(search == list[i])
count++;
}
if(count==0)
printf("\nElement not present in the list");
else
printf("\nElement present in the list");
}

Advantages of array implementation:


1. The elements are faster to access using random access
2.Searching an element is easier

Limitation of array implementation


An array store its nodes in consecutive memory locations.
The number of elements in the array is fixed and it is not possible to change the number
of elements .
Insertion and deletion operation in array are expensive. Since insertion is performed by
pushing the entire array one position down and deletion is performed by shifting the
entire array one position up.
Applications of arrays:
Arrays are particularly used in programs that require storing large collection of similar type data
elements.
Differences between Array based and Linked based implementation

Array Linked List


Definition Array is a collection of elements Linked list is an ordered collection
having same data type with common of elements which are connected by
name links/pointers
Access Elements can be accessed using Sequential access
index/subscript, random access
Memory structure Elements are stored in contiguous Elements are stored at available
memory locations memory space
Insertion & Deletion Insertion and deletion takes more time Insertion and deletion are fast and
in array easy
Memory Allocation Memory is allocated at compile time Memory is allocated at run time i.e
i.e static memory allocation dynamic memory allocation
Types 1D,2D,multi-dimensional SLL, DLL circular linked list
Dependency Each elements is independent Each node is dependent on each
other as address part contains
address of next node in the list

linked list based implementation:


Linked Lists:

A Linked list is an ordered collection of elements. Each element in the list is referred as a node.
Each node contains two fields namely,
Data field-The data field contains the actual data of the elements to be stored in the list
Next field- The next field contains the address of the next node in the list

DATA NEXT

A Linked list node

10 40 20 30 Null

L
Advantages of Linked list:
1. Insertion and deletion of elements can be done efficiently
2.It uses dynamic memory allocation
3.Memory utilization is efficient compared to arrays
Disadvantages of linked list:
1. Linked list does not support random access
2.Memory is required to store next field
3.Searching takes time compared to arrays
Types of Linked List
1. Singly Linked List or One Way List
2. Doubly Linked List or Two-Way Linked List
3. Circular Linked List
Dynamic allocation
The process of allocating memory to the variables during execution of the program or at run time
is known as dynamic memory allocation. C language has four library routines which allow this
function.
Dynamic memory allocation gives best performance in situations in which we do not know
memory requirements in advance. C provides four library routines to automatically allocate
memory at the run time.

Singly Linked List


A singly linked list is a linked list in which each node contains only one link field pointing to the
next node in the list

SLL
SLL with a Header
Basic operations on a singly-linked list are:
1. Insert – Inserts a new node in the list.
2. Delete – Deletes any node from the list.
3. Find – Finds the position( address ) of any node in the list.
4. FindPrevious - Finds the position( address ) of the previous node in the list.
5. FindNext- Finds the position( address ) of the next node in the list.
6. Display-display the date in the list
7. Search-find whether a element is present in the list or not
Declaration of Linked List
void insert(int X,List L,position P);
void find(List L,int X); void
delete(int x , List L); typedef
struct node *position;
position L,p,newnode;
struct node
{
int data;
position next;
};
Creation of the list:
This routine creates a list by getting the number of nodes from the user. Assume n=4 for this
example.
void create()
{
int i,n;
L=NULL;
newnode=(struct node*)malloc(sizeof(struct node));
printf("\n Enter the number of nodes to be inserted\n");
scanf("%d",&n);
printf("\n Enter the data\n");
scanf("%d",&newnode->data);
newnode->next=NULL;
L=newnode;
p=L;
for(i=2;i<=n;i++)
{
newnode=(struct node *)malloc(sizeof(struct node));
scanf("%d",&newnode->data);
newnode->next=NULL;
p->next=newnode;
p=newnode;
}
}
Initially the list is empty
List L
Null

L
Insert(10,List L)- A new node with data 10 is inserted and the next field is updated to
NULL. The next field of previous node is updated to store the address of new node.

10 Null

L
P
Insert(20,L) - A new node with data 20 is inserted and the next field is updated to NULL.
The next field of previous node is updated to store the address of new node.

Null
10 20

L P
Insert(30,L) - A new node with data 30 is inserted and the next field is updated to NULL. The
next field of previous node is updated to store the address of new node.

10 20 30 Null

L P
Case 1:Routine to insert an element in list at the beginning
void insert(int X, List L, position p)
{

p=L;
newnode=(struct node*)malloc(sizeof(struct node));
printf("\nEnter the data to be
Inserted\n");scanf("%d",&newnode->data);
newnode->next=L; L=newnode;
}
Case 2:Routine to insert an element in list at Position
This routine inserts an element X after the position P.
Void Insert(int X, List L, position p)
{
position newnode;
newnode =(struct node*) malloc( sizeof( struct node ));
if( newnode = = NULL )
Fatal error( “ Out of Space ” );
else
{

Newnode -> data = x ;


Newnode -> next = p ->next ;
P -> next = newnode ;
}
}
Insert(25,L, P) - A new node with data 25 is inserted after the position P and the next field is
updated to NULL. The next field of previous node is updated to store the address of new node.
Case 3:Routine to insert an element in list at the end of the list

void insert(int X, List L, position p)

{
p=L;

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


printf("\nEnter the data to be inserted\n");
scanf("%d",&newnode->data);
while(p->next!=NULL)
p=p->next;
newnode->next=NULL;
p->next=newnode;
p=newnode;

}
Routine to check whether a list is Empty
This routine checks whether the list is empty .If the lis t is empty it returns 1
int IsEmpty( List L )
{ Null
if ( L -> next = = NULL )
return(1); L
}
Routine to check whether the current position is last in the List
This routine checks whether the current position p is the last position in the list. It returns 1 if
position p is the last position
int IsLast(List L , position p)
{
if( p -> next= =NULL)
return(1);
}

Null
10 40 20 30

Routine to Find the Element in the List: P


This routine returns the position of X in the list L
position find(List L, int X)
{
position p;
p=L->next;
while(p!=NULL && p->data!=X)
p=p->next;
return(p);
}
Find(List L, 20) - To find an element X traverse from the first node of the list and move to
the next with the help of the address stored in the next field until data is equal to X or till the
end of the list

Null

10 40 20 30

L
X P
Find Previous
It returns the position of its predecessor.
position FindPrevious (int X, List L)
{
position p;
p = L;
while( p -> next ! = NULL && p -> next -> data! = X )
p = p -> next;
return P;
}

Routine to find next Element in the List


It returns the position of successor.
void FindNext(int X, List L)
{
position P;
P=L->next;
while(P!=NULL && P->data!=X)
P = P->next;
return P->next;
}
Routine to Count the Element in the List:
This routine counts the number of elements in the list
void count(List L)
{
P = L -> next;
while( p != NULL )
{
count++;
p = p -> next;

}
print count;
}
Routine to Delete an Element in the List:
It delete the first occurrence of element X from the list L
void Delete( int x , List L){
position p, Temp;
p = FindPrevious( X, L);
if( ! IsLast (p, L)){
temp = p -> next;
P -> next = temp -> next;
free ( temp );
}}
Routine to Delete the List
This routine deleted the entire list.
void Delete_list(List L)
{
position P,temp;
P=L->next;
L->next=NULL;
while(P!=NULL)
{
temp=P->next;
free(P);
P=temp;
}
}

1. The elements can be accessed using the next link


2. Occupies less memory than DLL as it has only one next field.
Disadvantages of SLL
1. Traversal in the backwards is not possible
2.Less efficient to for insertion and deletion.

Doubly-Linked List
A doubly linked list is a linked list in which each node has three fields namely Data, Next, Prev.
Data-This field stores the value of the element
Next-This field points to the successor node in the list
Prev-This field points to the predecessor node in the list
PREV DATA NEXT

DLL NODE
DOUBLY LINKED LIST

Basic operations of a doubly -linked list are:


1. Insert – Inserts a new element at the end of the list.
2. Delete – Deletes any node from the list.
3. Find – Finds any node in the list.
4. Print – Prints the list

Declaration of DLL Node

typedef struct node *position ; PREV DATA NEXT


struct node
{
int data;
position prev;
position next;
};

Creation of list in DLL


Initially the list is empty. Then assign the first node as head.
newnode->data=X;
newnode->next=NULL;
newnode->prev=NULL;
L=newnode;
If we add one more node in the list,then create a newnode and attach that node to the end of the

list.
L->next=newnode;
newnode->prev=L;

Routine to insert an element in a DLL at the beginning


void Insert (int x, list L, position P){
struct node *Newnode;
if(pos==1)
P=L;
Newnode = (struc node*)malloc (sizeof(struct node));
if (Newnode! = NULL)
Newnode->data= X;
Newnode ->next= L ->next;
L->next ->prev=Newnode
L->next = Newnode;
Newnode ->prev = L;
}

Routine to insert an element in a DLL any position :


void Insert (int x, list L, position P)

struct node *Newnode;

Newnode = (struc node*)malloc (sizeof(struct node));


if (Newnode! = NULL)
Newnode->data= X;
Newnode ->next= P ->next;
P->next ->prev=Newnode
P ->next = Newnode;
Newnode ->prev = P:
}

Routine to insert an element in a DLL at the end:


void insert(int X, List L, position p)
{
p=L;
newnode=(struct node*)malloc(sizeof(struct node));
printf("\nEnter the data to be inserted\n");
scanf("%d",&newnode->data);
while(p->next!=NULL)
p=p->next;
newnode->next=NULL;
p->next=newnode;
newnode->prev=p;
}
Routine for deleting an element:
void Delete (int x ,List L)
{
Position p , temp;
P = Find( x, L );
if(P==L->next)
temp=L;
L->next=temp->next;
temp->next->prev=L;
free(temp);
elseif( IsLast( p, L ) )
{
temp = p;
p -> prev -> next = NULL;
free(temp);
}
else
{
temp = p;
p -> prev -> next = p -> next;
p -> next -> prev = p -> prev;
free(temp);
}
Routine to display the elements in the list:
void Display( List L )
{
P = L -> next ;
while ( p != NULL)
{
printf(“%d”, p -> data ;
p = p -> next ;
}
printf(“ NULL”);
}
Routine to search whether an element is present in the list

void find()
{
int a,flag=0,count=0;
if(L==NULL)
printf(“\nThe list is empty”);
else
{
printf(“\nEnter the elements to be searched”);
scanf(“%d”,&a);
for(P=L;P!=NULL;P=P->next)
{
count++;
if(P->data==a)
{
flag=1;
printf(“\nThe element is found”);
printf(“\nThe position is %d”,count);
break;
}
}
if(flag==0)
printf(“\nThe element is not found”);
}
}
Advantages of DLL:
The DLL has two pointer fields. One field is prev link field and another is next link field.
Because of these two pointer fields we can access any node efficiently whereas in SLL only one
link field is there which stores next node which makes accessing of any node difficult.
Disadvantages of DLL:
The DLL has two pointer fields. One field is prev link field and another is next link field.
Because of these two pointer fields, more memory space is used by DLL compared to SLL
CIRCULAR LINKED LIST:
Circular Linked list is a linked list in which the pointer of the last node points to the first node.

Types of CLL:
CLL can be implemented as circular singly linked list and circular doubly linked list.

Singly linked circular list:


A Singly linked circular list is a linked list in which the last node of the list points to the first
node.

Declaration of node:
typedef struct node *position;
struct node
{
int data;
position next;
};

Routine to insert an element in the beginning


void insert_beg(int X,List L)
{
position Newnode;
Newnode=(struct node*)malloc(sizeof(struct node));
if(Newnode!=NULL)
{
Newnode->data=X;
Newnode->next=L->next;
L->next=Newnode;
}
}

Routine to insert an element in the middle


void insert_mid(int X, List L, Position p)
{
position Newnode;
Newnode=(struct node*)malloc(sizeof(struct node));
if(Newnode!=NULL)
{
Newnode->data=X;
Newnode->next=p->next;
p->next=Newnode;
}
}

Routine to insert an element in the last


void insert_last(int X, List L)
position Newnode;
Newnode=(struct node*)malloc(sizeof(struct node));
if(Newnode!=NULL)
{
P=L;
while(P->next!=L)
P=P->next;
Newnode->data=X;
P->next=Newnode;
Newnode->next=L;
}
}
Routine to delete an element from the beginning
void del_first(List L)
{
position temp;
temp=L->next;
L->next=temp->next;
free(temp);
}
Routine to delete an element from the middle
void del_mid(int X,List L)
{
position p, temp;
p=findprevious(X,L);
if(!Islast(P,L))
{
temp=p->next;
p->next=temp->next;
free(temp);
}
}
Routine to delete an element at the last position
void del_last(List L)
{
position p, temp;
p=L;
while(p->next->next!=L)
p=p->next;
temp=p->next;
p->next=L
free(temp);}
Doubly Linked circular list:
A doubly linked circular list is a doubly linked list in which the next link of the last node points
to the first node and prev link of the first node points to the last node of the list.
Declaration of node:
typedef struct node *position;
struct node
{
int data;
position next;
position prev;
};

Routine to insert an element in the beginning


void insert_beg(int X,List L)
{
position Newnode;
Newnode=(struct node*)malloc(sizeof(struct node));
if(Newnode!=NULL)
{
Newnode->data=X;
Newnode->next=L->next;
L->next->prev=Newnode;
L->next=Newnode;
Newnode->prev=L;
}
}
Routine to insert an element in the middle
void insert_mid(int X, List L, Position p)
{
position Newnode;
Newnode=(struct node*)malloc(sizeof(struct node));
if(Newnode!=NULL)
{
Newnode->data=X;
Newnode->next=p->next;
p->next->prev=Newnode;
p->next=Newnode;
Newnode->prev=p;
}
}
Routine to insert an element in the last
void insert_last(int X, List L)
{
position Newnode,p;
Newnode=(struct node*)malloc(sizeof(struct node));
if(Newnode!=NULL)
{
p=L;
while(p->next!=L)
p=p->next;
Newnode->data=X;
p->next =Newnode;
Newnode->next=L;
Newnode->prev=p;
L->prev=newnode;
}
}
Routine to delete an element from the beginning
void del_first(List L)
{
position temp;
if(L->next!=NULL)
{
temp=L->next;
L->next=temp->next;
temp->next->prev=L;
free(temp);
}
Routine to delete an element from the middle
void del_mid(int X,List L)
{
Position p, temp;
p=FindPrevious(X);
if(!IsLast(p,L))
{
temp=p->next;
p->next=temp-next;
temp->next->prev=p;
free(temp);
}
}
Routine to delete an element at the last position
void del_last(List L)
{
position p, temp;
p=L;
while(p->next!=L)
p=p->next;
temp=p;
p->next->prev=L;
L->prev=p->prev;
free(temp);
}
Advantages of Circular linked List

It allows to traverse the list starting at any point.


It allows quick access to the first and last records.
Circularly doubly linked list allows to traverse the list in either direction.

Applications of List:
1. Polynomial ADT
2.Radix sort
3.Multilist
Polynomial Manipulation
Polynomial manipulations such as addition, subtraction & differentiation etc.. can be
performed using linked list
Declaration for Linked list implementation of Polynomial ADT
struct poly
{
int coeff;
int power;
struct poly *next;
}*list1,*list2,*list3;

Creation of the Polynomial


poly create(poly*head1,poly*newnode1)
{
poly *ptr;
if(head1==NULL)

{
}
else
{

}head1=newnode1;return (head1);

ptr=head1;
while(ptr->next!=NULL)ptr=ptr->next;
ptr->next=newnode1;

return(head1);
}
Addition of two polynomials
void add()
{
poly *ptr1, *ptr2, *newnode ;
ptr1= list1;
ptr2 = list2;
while( ptr1 != NULL && ptr2 != NULL )
{
newnode = (struct poly*)malloc( sizeof ( struct poly ));
if( ptr1 -> power = = ptr2 -> power )
{
newnode -> coeff = ptr1 -> coeff + ptr2 -> coeff;
newnode -> power = ptr1 -> power ;
newnode -> next = NULL;
list3 = create( list3, newnode );
ptr1 = ptr1 -> next;
ptr2 = ptr2 -> next;
}
else if(ptr1 -> power > ptr2 -> power )
{

}
else newnode -> coeff = ptr1 -> coeff;
{ newnode -> power = ptr1 -> power;
newnode -> next = NULL;
list3 = create( list3, newnode );
ptr1 = ptr1 -> next;

ptr2 = ptr2 -> next;


}}} newnode -> coeff = ptr2 -> coeff;
newnode -> power = ptr2 -> power;
newnode -> next = NULL;
list3 = create( list3, newnode );
Subtraction of two polynomial
{
void sub() poly *ptr1, *ptr2, *newnode;
ptr1 = list1;
ptr2 = list2;
while( ptr1 != NULL && ptr2 != NULL )
{
newnode = (struct poly*)malloc( sizeof (struct poly)) ;
if(ptr1->power==ptr2->power)
{
newnode->coeff=(ptr1-coeff)-(ptr2->coeff);
newnode->power=ptr1->power;
newnode->next=NULL;
list3=create(list3,newnode);
ptr1=ptr1->next;

ptr2=ptr2->next;
}
else
{
if(ptr1-power>ptr2-power)
{
newnode->coeff=ptr1->coeff;
newnode->power=ptr1->power;
newnode->next=NULL;
list3=create(list3,newnode);
} ptr1=ptr1->next;
else
{
newnode->coeff=-(ptr2->coeff);
newnode->power=ptr2->power;
newnode->next=NULL;
list3=create(list3,newnode);
ptr2=ptr2->next;
}
}
}

Polynomial Differentiation:
void diff()

{
poly *ptr1, *newnode;
ptr1 = list1;
while( ptr1 != NULL)
{
newnode = (struct poly*)malloc( sizeof (struct poly));

newnode->coeff=(ptr1-coeff)*(ptr1->power);
newnode->power=ptr1->power-1;
newnode->next=NULL;
list3=create(list3,newnode);
ptr1=ptr1->next;
}
}
Polynomial Multiplication
void mul()
{
poly *ptr1, *ptr2, *newnode ;
ptr1= list1;
ptr2 = list2;
while( ptr1 != NULL && ptr2 != NULL )
{
newnode = (struct poly*)malloc( sizeof ( struct poly ));
if( ptr1 -> power = = ptr2 -> power )
{
newnode -> coeff = ptr1 -> coeff * ptr2 -> coeff;
newnode -> power = ptr1 -> power+ptr2->power; ;
newnode -> next = NULL;
list3 = create( list3, newnode );
ptr1 = ptr1 -> next;
ptr2 = ptr2 -> next;
}}
}
UNIT II LINEAR DATA STRUCTURES – STACKS, QUEUES
STACK

 Stack is a Linear Data Structure that follows Last In First Out(LIFO) principle.
 Insertion and deletion can be done at only one end of the stack called TOP of the stack.
 Example: - Pile of coins, stack of trays

STACK ADT:

STACK MODEL

TOP pointer

It will always point to the last element inserted in the stack.


For empty stack, top will be pointing to -1. (TOP = -1)
Operations on Stack (Stack ADT)
Two fundamental operations performed on the stack are PUSH and POP.
(a) PUSH:

It is the process of inserting a new element at the Top of the stack.

For every push operation:

1. Check for Full stack ( overflow ).


2. Increment Top by 1. (Top = Top + 1)
3. Insert the element X in the Top of the stack.
(b) POP:

It is the process of deleting the Top element of the stack.

For every pop operation:

1. Check for Empty stack ( underflow ).


2. Delete (pop) the Top element X from the stack
3. Decrement the Top by 1. (Top = Top - 1 )

Exceptional Conditions of stack

1. Stack Overflow

An Attempt to insert an element X when the stack is Full, is said to be stack
overflow.
 For every Push operation, we need to check this condition.
2. Stack Underflow:

 An Attempt to delete an element when the stack is empty, is said to be stack


underflow.
 For every Pop operation, we need to check this condition.

Implementation of Stack
Stack can be implemented in 2 ways.

1. Static Implementation (Array implementation of Stack)


2. Dynamic Implementation (Linked List Implementation of Stack)

Array Implementation of Stack

 Each stack is associated with a Top pointer.


 For Empty stack, Top = -1.
 Stack is declared with its maximum size.
Array Declaration of Stack:
#define ArraySize 5
int S [ Array Size];
or
int S [ 5 ];
(i) Stack Empty Operation:
 Initially Stack is Empty.
 With Empty stack Top pointer points to – 1.
 It is necessary to check for Empty Stack before deleting (pop) an element from the stack.

Routine to check whether stack is empty

int IsEmpty ( Stack S )


{
if( Top = = - 1 )
return(1);
}

(ii) Stack Full Operation:


 As we keep inserting the elements, the Stack gets filled with the elements.
 Hence it is necessary to check whether the stack is full or not before inserting a new
element into the stack.

Routine to check whether a stack is full

int IsFull ( Stack S )

{ if( Top = = Arraysize – 1 )

return(1);

}
(ii) Push Operation

 It is the process of inserting a new element at the Top of the stack.


 It takes two parameters. Push(X, S) the element X to be inserted at the Top of the Stack
S.
 Before inserting an Element into the stack, check for Full Stack.
 If the Stack is already Full, Insertion is not possible.
 Otherwise, Increment the Top pointer by 1 and then insert the element X at the Top of the
Stack.
Routine to push an element into the stack

void Push ( int X , Stack S )


{
if ( Top = = Arraysize - 1)
Error(“Stack is full!!Insertion is not possible”);
else
{ Top = Top + 1;
S [ Top ] =X;
}
}

(iv) Pop Operation


 It is the process of deleting the Top element of the stack.
 It takes only one parameter. Pop(X).The element X to be deleted from the Top of the
Stack.
 Before deleting the Top element of the stack, check for Empty Stack.
 If the Stack is Empty, deletion is not possible.
 Otherwise, delete the Top element from the Stack and then decrement the Top pointer by
1.
Routine to Pop the Top element of the stack
void Pop ( Stack S )
{
if ( Top = = - 1)
Error ( “Empty stack! Deletion not possible”);
else
{ X = S [ Top ] ;
Top = Top – 1 ;
}
}
(v) Return Top Element
 Pop routine deletes the Top element in the stack.
 If the user needs to know the last element inserted into the stack, then the user can return
the Top element of the stack.
 To do this, first check for Empty Stack.
 If the stack is empty, then there is no element in the stack.
 Otherwise, return the element which is pointed by the Top pointer in the Stack.

Routine to return top Element of the stack

int TopElement(Stack S)
{
if(Top==-1)
{
Error(“Empty stack!!No elements”);
return 0;
}
else
return S[Top];
}
Implementation of stack using Array
/* static implementation of stack*/

#include<stdio.h>
#include<conio.h>
#define size 5
int stack [ size ];
int top;
void push( )
{
int n ;
printf( "\n Enter item in stack" ) ;
scanf( " %d " , &n ) ;
if( top = = size - 1)
{
printf( "\nStack is Full" ) ;
}
else
{
top = top + 1 ;
stack [ top ] = n ;
}
}
void pop( )
{
int item;
if( top = = - 1)
{
printf( "\n Stack is empty" );
}
else
{ item = stack[ top ] ;
printf( "\n item popped is = %d" , item );
top - -;

}
}
void display( )
{
int i;
printf("\n item in stack are");
for(i = top; i > = 0; i --)
printf("\n %d", stack[ i ] );
}
void main( )
{
char ch,ch1;
ch = 'y';
ch1 = 'y';
top = -1;
clrscr( );
while(ch !='n')
{
push( );
printf("\n Do you want to push any item in stack y/n");
ch=getch( );
}
display( );
while( ch1!='n' )
{
printf("\n Do you want to delete any item in stack y/n");
ch1=getch( );
pop( );
}
display( );
getch( );}
OUTPUT:
Enter item in stack20
Do you want to push any item in stack y/n
Enter item in stack25
Do you want to push any item in stack y/n
Enter item in stack30
Stack is Full
Do you want to push any item in stack y/n
item in stack are
25
20
15
10
5
Do you want to delete any item in stack y/n
item popped is = 25
Do you want to delete any item in stack y/n
item popped is = 20
Do you want to delete any item in stack y/n
item popped is = 15
item in stack are
10
5
Linked list implementation of Stack
 Stack elements are implemented using SLL (Singly Linked List) concept.
 Dynamically, memory is allocated to each element of the stack as a node.
Type Declarations for Stack using SLL
struct node;
typedef struct node *stack;
typedef struct node *position;
stack S;
struct node{ int
data; position
next;};
int IsEmpty(Stack S);
void Push(int x, Stack S);
void Pop(Stack S);
int TopElement(Stack S);
(i) Stack Empty Operation:
 Initially Stack is Empty.
 With Linked List implementation, Empty stack is represented as S -> next = NULL.
 It is necessary to check for Empty Stack before deleting ( pop) an element from the stack.
Routine to check whether the stack is empty S

int IsEmpty( Stack S) HEADER NULL


{
if ( S -> next = = NULL)
EMPTY STACK
return ( 1 );
}

(ii) Push Operation


 It is the process of inserting a new element at the Top of the stack.
 With Linked List implementation, a new element is always inserted at the Front of the
List.(i.e.) S -> next.
 It takes two parameters. Push(X, S) the element X to be inserted at the Top of the StackS.
 Allocate the memory for the newnode to be inserted.
 Insert the element in the data field of the newnode.
 Update the next field of the newnode with the address of the next node which is stored
in the S -> next.
S

Header

30 20 10 NULL

40

newnode
Before Insertion
Push routine /*Inserts element at front of the list
void push(int X, Stack S)
{
Position newnode, Top;
newnode = malloc (sizeof( struct node ) );
newnode -> data = X;
newnode -> next = S -> next;
S -> next = newnode;
Top = newnode;
}

Header

40 30 20 10 NULL

After Insertion
TOP
(iii) Pop Operation
 It is the process of deleting the Top element of the stack.
 With Linked List implementations, the element at the Front of the List
(i.e.) S -> next is always deleted.
 It takes only one parameter. Pop(X).The element X to be deleted from the Front of the
List.
 Before deleting the front element in the list, check for Empty Stack.
 If the Stack is Empty, deletion is not possible.
 Otherwise, make the front element in the list as “temp”.
 Update the next field of header.
 Using free ( ) function, Deallocate the memory allocated for temp node.
PANIMALA R
S
padamavani arts and science college

Header

40 30 20 10 NULL

TOP
Before Deletion
Pop routine /*Deletes the element at front of list
void Pop( Stack S )
{
Position temp, Top;
Top = S -> next;
if( S -> next = = NULL)
Error(“empty stack! Pop not possible”);
else
{
Temp = S -> next;
S -> next = temp -> next;
free(temp);
Top = S -> next;
}}

Header

40 30 20 10 NULL

HEADER

30 20 10 NULL
After Deletion
(iv) Return Top Element
 Pop routine deletes the Front element in the List.
 If the user needs to know the last element inserted into the stack, then the user can
return the Top element of the stack.
 To do this, first check for Empty Stack.
 If the stack is empty, then there is no element in the stack.
 Otherwise, return the element present in the S -> next -> data in the List.

Routine to Return Top Element


int TopElement(Stack S)

if(S->next==NULL)

error(“Stack is empty”);

return 0;

else

return S->next->data;

}
S

Header NULL

40 30 20 10

TOP
Applications of Stack

The following are some of the applications of stack:

1. Evaluating the arithmetic expressions


o Conversion of Infix to Postfix Expression
o Evaluating the Postfix Expression
2. Balancing the Symbols
3. Function Call
4. Tower of Hanoi
5. 8 Queen Problem
Evaluating the Arithmetic Expression
There are 3 types of Expressions
 Infix Expression
 Postfix Expression
 Prefix Expression

INFIX:

The arithmetic operator appears between the two operands to which it is being
applied.

POSTFIX:

The arithmetic operator appears directly after the two operands to which it applies.
Also called reverse polish notation.
PREFIX:
The arithmetic operator is placed before the two operands to which it applies. Also
called polish notation.

Evaluating Arithmetic Expressions

1. Convert the given infix expression to Postfix expression


2. Evaluate the postfix expression using stack.

Algorithm to convert Infix Expression to Postfix Expression:


Read the infix expression one character at a time until it encounters the delimiter “#”
Step 1: If the character is an operand, place it on the output.
Step 2: If the character is an operator, push it onto the stack. If the stack operator has a higher or
equal priority than input operator then pop that operator from the stack and place it onto the
output.
Step 3:If the character is left parenthesis, push it onto the stack

Step 4:If the character is a right parenthesis, pop all the operators from the stack till it encounters
left parenthesis, discard both the parenthesis in the output.
E.g. Consider the following Infix expression: - A*B+(C-D/E)#

Read char Stack Output

A
A

*
A
*

B
+ AB
*

+ AB*

AB*
(
(
+
Read char Stack Output

C AB*C
(
+

- AB*C
-
(
+

- AB*CD
D
(
+

AB*CD
/
/
-
(
+

AB*CDE
E /
-
(
+

AB*CDE/-

)
/
-
(
+
Read char Stack Output

AB*CDE/-+

Output: Postfix expression:- AB*CDE/-+


Evaluating the Postfix Expression
Algorithm to evaluate the obtained Postfix Expression
Read the postfix expression one character at a time until it encounters the delimiter „#‟
Step 1: If the character is an operand, push its associated value onto the stack.
Step 2: If the character is an operator, POP two values from the stack, apply the operator to
them and push the result onto the stack.
E.g consider the obtained Postfix expression:- AB*CDE/-+

Operand Value
A 2
B 3
C 4
D 4
E 2

Char Read Stack

A 2

B 3
2
Char Read Stack

6
*

4
C 6

4
D 4
6

2
/ 4
6

- 2
6

+ 8

OUTPUT = 8

Example 2: Infix expression:- (a+b)*c/d+e/f#

Read char Stack Output

a a
(
+
+ a
(

b
ab
+
(

) ab+

* ab+
*

c ab+c

/ ab+c*

d ab+c*d

ab+c*d/
+

21
e ab+c*d/e

/ ab+c*d/e

/
+

f ab+c*d/ef

/
+

# ab+c*d/ef/+

Postfix expression:- ab+c*d/ef/+

Evaluating the Postfix Expression

Operand Value
a 1
b 2
c 4
d 2
e 6
f 3
Char Read Stack

A 1

B 2
1

3
+

4
C 3

12
*

2
D 12

6
/

6
6
E

3
F 6
6

2
6
/

8
+

Output = 8
Example for unbalanced symbols:
QUEUES:

 Queue is a Linear Data Structure that follows First in First out (FIFO) principle.
 Insertion of element is done at one end of the Queue called “Rear “end of the Queue.
 Deletion of element is done at other end of the Queue called “Front “end of the Queue.
 Example: - Waiting line in the ticket counter.

Front End
Deletion RearEnd
QUEUE Q
Insertion
Queue Model

Front Pointer:-

It always points to the first element inserted in the Queue.

Rear Pointer:-

It always points to the last element inserted in the Queue.

For Empty Queue:-

Front (F) = - 1

Rear (R) = - 1

Operations on Queue

Fundamental operations performed on the queue are

1. EnQueue
2. DeQueue
(i) EnQueue operation:-

 It is the process of inserting a new element at the rear end of the Queue.
 For every EnQueue operation
o Check for Full Queue
o If the Queue is full, Insertion is not possible.
o Otherwise, increment the rear end by 1 and then insert the element in the rear end
of the Queue.

(ii) DeQueue Operation:-

 It is the process of deleting the element from the front end of the queue.
 For every DeQueue operation
o Check for Empty queue
o If the Queue is Empty, Deletion is not possible.
o Otherwise, delete the first element inserted into the queue and then increment the
front by 1.

Exceptional Conditions of Queue

 Queue Overflow
 Queue Underflow

(i) Queue Overflow:

 An Attempt to insert an element X at the Rear end of the Queue when the
Queue is full is said to be Queue overflow.
 For every Enqueue operation, we need to check this condition.
(ii) Queue Underflow:
 An Attempt to delete an element from the Front end of the Queue when the
Queue is empty is said to be Queue underflow.
 For every DeQueue operation, we need to check this condition.
Implementation of Queue

Queue can be implemented in two ways.

1. Implementation using Array (Static Queue)


2. Implementation using Linked List (Dynamic Queue)

Array Declaration of Queue:


#define ArraySize 5
int Q [ ArraySize];
or
int Q [ 5 ];

Initial Configuration of Queue:

(i) Queue Empty Operation:


Initially Queue is Empty.
 With Empty Queue, Front ( F ) and Rear ( R ) points to – 1.
It is necessary to check for Empty Queue before deleting (DeQueue) an element from the
Queue (Q).
Routine to check for Empty Queue
int IsEmpty ( Queue Q )
{
if( ( Front = = - 1) && ( Rear = = - 1 ) )
return ( 1 );
}

int IsEmpty ( Queue Q )

if( ( Front = = - 1) && ( Rear = = - 1 ) )

return ( 1 );

(ii) Queue Full Operation

As we keep inserting the new elements at the Rear end of the Queue, the Queue becomes
full.
When the Queue is Full, Rear reaches its maximum Arraysize.
For every Enqueue Operation, we need to check for full Queue condition.

Routine to check for Full Queue


int IsFull( Queue Q )

if ( Rear = = ArraySize - 1 )

return ( 1 );

}
(iii) Enqueue Operation

It is the process of inserting a new element at the Rear end of the Queue.
It takes two parameters, Enqueue(X, Q). The elements X to be inserted at the Rear end of
the Queue Q.
Before inserting a new Element into the Queue, check for Full Queue.
If the Queue is already Full, Insertion is not possible.
Otherwise, Increment the Rear pointer by 1 and then insert the element X at the Rear end
of the Queue.
If the Queue is Empty, Increment both Front and Rear pointer by 1 and then insert the
element X at the Rear end of the Queue.

Routine to Insert an Element in a Queue

void EnQueue (int X , Queue Q)


{
if ( Rear = = Arraysize - 1)
print (" Full Queue !!!!. Insertion not
possible");
else if (Rear = = - 1)
{
Front = Front + 1;
Rear = Rear + 1;
Q [Rear] = X;
}
else
{
Rear = Rear + 1;
Q [Rear] = X;
}
}
(iv) DeQueue Operation
It is the process of deleting a element from the Front end of the Queue.
It takes one parameter, DeQueue (Q). Always front element in the Queue will be deleted.
Before deleting an Element from the Queue, check for Empty Queue.
If the Queue is empty, deletion is not possible.
If the Queue has only one element, then delete the element and represent the empty queue
by updating Front = - 1 and Rear = - 1.
If the Queue has many Elements, then delete the element in the Front and move the Front
pointer to next element in the queue by incrementing Front pointer by 1.

ROUTINE FOR DEQUEUE

void DeQueue ( Queue Q )


{
if ( Front = = - 1)
print (" Empty Queue !. Deletion not possible " );
else if( Front = = Rear )
{
X = Q [ Front ];
Front = - 1;
Rear = - 1;
}
else
{
X = Q [ Front ];
Front = Front + 1 ;
}
}
Linked List Implementation of Queue

 Queue is implemented using SLL (Singly Linked List ) node.


 Enqueue operation is performed at the end of the Linked list and DeQueue
operation is performed at the front of the Linked list.
 With Linked List implementation, for Empty queue
Front = NULL & Rear = NULL
Linked List representation of Queue with 4 elements

Header

10 20 30 40 NULL

Front Rear

Declaration for Linked List Implementation of Queue ADT

struct node;
typedef struct node * Queue;
typedef struct node * position;
int IsEmpty (Queue Q);
Queue CreateQueue (void);
void MakeEmpty (Queue Q);
void Enqueue (int X, Queue Q);
void Dequeue (Queue Q);
struct node
{
int data ;
position next;
}* Front = NULL, *Rear = NULL;
(i) Queue Empty Operation:
 Initially Queue is Empty.
 With Linked List implementation, Empty Queue is represented as S -> next = NULL.
 It is necessary to check for Empty Queue before deleting the front element in the Queue.

ROUTINE TO CHECK WHETHER THE QUEUE IS EMPTY

int IsEmpty (Queue Q


{ Q

return (1); Header NULL


}
Empty Queue
(ii) EnQueue Operation

 It is the process of inserting a new element at the Rear end of the Queue.
 It takes two parameters, EnQueue ( int X , Queue Q ). The elements X to be inserted into
the Queue Q.
 Using malloc ( ) function allocate memory for the newnode to be inserted into the Queue.
 If the Queue is Empty, the newnode to be inserted will become first and last node in the
list. Hence Front and Rear points to the newnode.
 Otherwise insert the newnode in the Rear -> next and update the Rear pointer.

Routine to EnQueue an Element in Queue

void EnQueue ( int X, Queue Q )


{
struct node *newnode;
newnode = malloc (sizeof (struct node));
if (Rear = = NULL)
{

Q -> next = newnode;


Front = newnode;
Rear = newnode;
}
else
{
Rear = newnode;
}
} Q

Header NULL
Q
Empty Queue
Before Insertion Header

(iii) DeQueue Operation After Insertion


It is the process of deleting the front element from the Queue. Front Rear
It takes one parameter, Dequeue ( Queue Q ). Always element in the front (i.e) element pointed
by Q -> next is deleted always.
Element to be deleted is made “temp”.
If the Queue is Empty, then deletion is not possible.
If the Queue has only one element, then the element is deleted and Front and Rear pointer is
made NULL to represent Empty Queue.
Otherwise, Front element is deleted and the Front pointer is made to point to next node in the list.
The free ( ) function informs the compiler that the address that temp is pointing to, is unchanged
but the data present in that address is now undefined.
Routine to DeQueue an Element from the Queue

void DeQueue ( Queue Q )


{
struct node *temp;
if ( Front = = NULL )
Error (“Empty Queue!!! Deletion not possible.” );
else if (Front = = Rear)
{
temp = Front;
Q -> next = NULL;
Front = NULL;
Rear = NULL;
free ( temp );
}
else
{
temp = Front;
Q -> next = temp -> next;
Front = Front Next;
free (temp);
}
}

Applications of Queue

1. Serving requests on a single shared resource, like a printer, CPU task scheduling etc.
2. In real life, Call Center phone systems will use Queues, to hold people calling them in an
order, until a service representative is free.
3. Handling of interrupts in real-time systems. The interrupts are handled in the same order
as they arrive, First come first served.
4. Batch processing in operating system.
5. Job scheduling Algorithms like Round Robin Algorithm uses Queue.
Drawbacks of Queue (Linear Queue)

 With the array implementation of Queue, the element can be deleted logically only by
moving Front = Front + 1.
 Here the Queue space is not utilized fully.

To overcome the drawback of this linear Queue, we use Circular Queue.


CIRCULAR QUEUE

In Circular Queue, the insertion of a new element is performed at the very first location of the
queue if the last location of the queue is full, in which the first element comes just after the last
element.

 A circular queue is an abstract data type that contains a collection of data which allows
addition of data at the end of the queue and removal of data at the beginning of the
queue.
 Circular queues have a fixed size.
 Circular queue follows FIFO principle.
 Queue items are added at the rear end and the items are deleted at front end of the circular
queue
 Here the Queue space is utilized fully by inserting the element at the Front end if the rear
end is full.

Operations on Circular Queue

Fundamental operations performed on the Circular Queue are

 Circular Queue Enqueue


 Circular Queue Dequeue
Formula to be used in Circular Queue

For Enqueue Rear = ( Rear + 1) % ArraySize


For Dequeue Front = ( Front + 1) % ArraySize
(i) Circular Queue Enqueue Operation

It is same as Linear Queue EnQueue Operation (i.e) Inserting the element at the Rear end.
First check for full Queue.
If the circular queue is full, then insertion is not possible.
Otherwise check for the rear end.
If the Rear end is full, the elements start getting inserted from the Front end.

Routine to Enqueue an element in circular queue

void Enqueue ( int X, CircularQueue CQ )


{
if( Front = = ( Rear + 1 ) % ArraySize)
Error( “Queue is full!!Insertion not possible” );
else if( Rear = = -1 )
{
Front = Front + 1;
Rear = Rear + 1;
CQ[ Rear ] = X;
}
else
{
Rear = ( Rear + 1 ) % Arraysize;
CQ[ Rear ] = X;
}
}
F
Circular Queue DeQueue Operation

It is same as Linear Queue DeQueue operation (i.e) deleting the front element.
First check for Empty Queue.
If the Circular Queue is empty, then deletion is not possible.

If the Circular Queue has only one element, then the element is deleted and Front and Rear
pointer is initialized to - 1 to represent Empty Queue.
Otherwise, Front element is deleted and the Front pointer is made to point to next element in the
Circular Queue.

F, R
F= -1,R= --1

Routine To DeQueue An Element In Circular Queue

void DeQueue (CircularQueue CQ)


{
if(Front== - 1)
Empty(“Empty Queue!”);
else if(Front==rear)
{
X=CQ[Front];
Front=-1;
Rear=-1;
}
else
{
X=CQ[Front];
Front=(Front+1)%Arraysize;
}}
DOUBLE-ENDED QUEUE (DEQUE)

In DEQUE, insertion and deletion operations are performed at both ends of the Queue.

Exceptional Condition of DEQUE

(i) Input Restricted DEQUE


Here insertion is allowed at one end and deletion is allowed at both ends.

Deletion Insertion
Deletion

Front Rear
(ii) Output Restricted DEQUE

Here insertion is allowed at both ends and deletion is allowed at one end.

Insertion
Deletion Insertion

Front Rear

Operations on DEQUE

Four cases for inserting and deleting the elements in DEQUE are

1. Insertion At Rear End [ same as Linear Queue ]


2. Insertion At Front End
3. Deletion At Front End [ same as Linear Queue ]
4. Deletion At Rear End

Case 1: Routine to insert an element at Rear end

void Insert_Rear (int X, DEQUE DQ)


{
if( Rear = = Arraysize - 1)
Error(“Full Queue!!!! Insertion not possible”);
else if( Rear = = -1)
{
Front = Front + 1;
Rear = Rear + 1;
DQ[ Rear ] = X;
}
else
{
Rear = Rear + 1;
DQ[ Rear ] = X;
}
}
Case 2: Routine to insert an element at Front end

void Insert_Front ( int X, DEQUE DQ )


{
if( Front = = 0 )
Error(“Element present in Front!!!!! Insertion not possible”);
else if(Front = = -1)
{
Front = Front + 1;
Rear = Rear + 1;
DQ[Front] = X;
}
else
{
Front = Front - 1;
DQ[Front] = X;
}
}
Case 3: Routine to delete an element from Front end

void Delete_Front(DEQUE DQ)


{
if(Front = = - 1)
Error(“Empty queue!!!! Deletion not possible”);
else if( Front = = Rear )
{
X = DQ[ Front];
Front = - 1;
Rear = - 1;
}
else
{
X = DQ [ Front ];
Front = Front + 1;
}
}
Case 4: Routine to delete an element from Rear end

void Delete_Rear(DEQUE DQ)


{
if( Rear = = - 1)
Error(“Empty queue!!!! Deletion not possible”);
else if( Front = = Rear )
{
X = DQ[ Rear ];
Front = - 1;
Rear = - 1;
}
else
{
X = DQ[ Rear ];
Rear = Rear - 1;
}

}
UNIT-III TREE ADT
Binary Tree using Array Representation
Each node contains info, left, right and father fields. The left, right and father
fields of a node point to the node’s left son, right son and father respectively.

Using the array implementation, we may declare,


#define NUMNODES 100
struct nodetype
{
int info;
int left;
int right;
int father;
};
struct nodetype node[NUMNODES];

This representation is called linked array representation.

Example: -

Fig (a) Fig (b)


The above trees can be represented in memory sequentially as follows

A
B
-
C
-
-
-
D
-

The above representation appears to be good for complete binary trees


and wasteful for many other binary trees. In addition, the insertion or
deletion of nodes from the middle of a tree requires the insertion of many
nodes to reflect the change in level number of these nodes.
www.padeepz.net

Figure 2.5 Figure 2.6

0 1
A A

B 1 C 2 B 2 C
3

D E F G D E F G
3 4 5 6 4 5 6 7

A B C D E F G A B C D E F G

0 1 2 3 4 5 6 1 2 3 4 5 6 7
For Figure 2.5 For Figure 2.6
Root = i Root = i
leftchild=2i+1 leftchild=2i
rightchild=2i+2 rightchild=2i+1
leftchild’s parent position = i/2 parent position= i/2
2n+1 – 1 => array size 2n+1 - 1 => size of array
n => no of levels of a tree n => number of levels of a tree
rightchild’s position= i-1/2

Binary Tree using Link Representation

The problems of sequential representation can be easily overcome through


the use of a linked representation.
Each node will have three fields LCHILD, DATA and RCHILD as represented
below

LCHILD DATA RCHILD


T
Fig (a) Fig (b)

In most applications it is adequate. But this structure make it difficult to


determine the parent of a node since this leads only to the forward movement
of the links.

Using the linked implementation we may declare,

Struct treenode
{
int data;
structtreenode *leftchild;
structtreenode *rightchild;
}*T;

T
2000
1000 1 1006

1000 1006
2 1004
1002 1008 5 1010

1002 1004 1008 1010

NULL 3 NULL NULL 4 NULL NULL 6 NULL NULL 7 NULL

TYPES OF BINARY TREES

Left Skewed Binary tree :


A binary tree which has only left child is called left skewed binary tree.
A

Right Skewed Binary tree :


A Binary tree which has only right child is called right skewed binary tree.

Full Binary Tree :


It is the one which has exactly two children for each node at each level and
all the leaf nodes should be at the same level.

Complete Binary Tree :


It is the one tree where all the leaf nodes need not be at the same
level and at the bottom level of the complete binary tree, the nodes should be
filled from the left to the right.
All full binary trees are complete binary tree. But all complete binary trees
need not be full binary tree.

B C
CONVERSION OF A GENERAL TREE TO BINARY TREE

General Tree:

A General Tree is a tree in which each node can have an unlimited out degree.
Each node may have as many children as is necessary to satisfy its
requirements. Example: Directory Structure
It is considered easy to represent binary trees in programs than it is to
represent general trees. So, the general trees can be represented in binary
tree format.

Changing general tree to Binary tree:

The binary tree format can be adopted by changing the meaning of the left and
right pointers. There are two relationships in binary tree,
Parent to child
Sibling to sibling
Using these relationships, the general tree can be implemented as binary tree.

Algorithm
Identify the branch from the parent to its first or leftmost child. These
branches from each parent become left pointers in the binary tree
Connect siblings, starting with the leftmost child, using a branch for each
sibling to its right sibling.
Remove all unconnected branches from the parent to its children
A

B E F

C D G H I
BINARY TREE TRAVERSALS

Compared to linear data structures like linked lists and one dimensional array,
which have only one logical means of traversal, tree structures can be
traversed in many different ways. Starting at the root of a binary tree, there
are three main steps that can be performed and the order in which they are
performed defines the traversal type. These steps (in no particular order) are:
performing an action on the current node (referred to as "visiting" the node),
traversing to the left child node, and traversing to the right child node. Thus
the process is most easily described through recursion.
A binary tree traversal requires that each node of the tree be processed once
and only once in a predetermined sequence.
The two general approaches to the traversal sequence are,
Depth first traversal
Breadth first traversal

Breadth-First Traversal

In a breadth-first traversal, the processing proceeds horizontally form the


root to all its children, then to its children’s children, and so forth until all
nodes have been processed. In other words, in breadth traversal, each level is
completely processed before the next level is started.
Depth-First Traversal

In depth first traversal, the processing proceeds along a path from the root
through one child to the most distant descendent of that first child before
processing a second child. In other words, in the depth first traversal, all the
descendants of a child are processed before going to the next child.

There are basically three ways of binary tree traversals.


1. Inorder --- (left child,root,right child)
A
2. Preorder --- (root,left child,right child)
3. Postorder --- (left child,right child,root)
B C
Inorder--- B A C
Preorder --- A B C
Postorder --- B C A

In C, each node is defined as a structure of the following form:


struct node
{
int info;
struct node *lchild;
struct node *rchild;
}
typedef struct node NODE;

Inorder Traversal

Steps :
Traverse left subtree in inorder
Process root node
Traverse right subtree in inorder

B E

C D F

The Output is : C  B  D A E  F

Algorithm
Algorithm inoder traversal (BinTree T)
Begin
If ( not empty (T) ) then
Begin
Inorder_traversal ( left subtree ( T ) )
Print ( info ( T ) ) / * process node */
Inorder_traversal ( right subtree ( T ) )
End
End

Routines
void inorder_traversal ( NODE * T)
{
if( T ! = NULL)
{
inorder_traversal(T->lchild);
printf(“%d \t “, T->info);
inorder_traversal(T->rchild);
}
}

Preorder Traversal
Steps :
Process root node
Traverse left subtree in preorder
Traverse right subtree in preorder

Algorithm
Algorithm inoder traversal (BinTree T)
Begin
If ( not empty (T) ) then
Begin
Print ( info ( T ) ) / * process node */
Preorder_traversal ( left subtree ( T ) )
Preorder_traversal ( right subtree ( T ) )
End
End

Routines
void inorder_traversal ( NODE * T)
{
if( T ! = NULL)
{
printf(“%d \t “, T->info);
preorder_traversal(T->lchild);
preorder_traversal(T->rchild);
}
}
Output is : A B  C  D  E  F

Postorder Traversal

Steps :
Traverse left subtree in postorder
Traverse right subtree in postorder
process root node

Algorithm
Algorithm postorder traversal (BinTree T)
Begin
If ( not empty (T) ) then
Begin
Postorder_traversal ( left subtree ( T ) )
Postorder_traversal ( right subtree( T))
Print ( Info ( T ) ) / * process node */
End
End

Routines
void postorder_traversal ( NODE * T)
{
if( T ! = NULL)
{
postorder_traversal(T->lchild);
postorder_traversal(T->rchild);
printf(“%d \t”, T->info);
}
}

B E

C D F

Output is : C  D  B  F  E  A

A
Examples :

1. FIND THE TRAVERSAL OF THE FOLLOWING TREE B


C

ANSWER : POSTORDER: DBCA INORDER: DBAC PREORDER:ABCD

2. FIND THE TRAVERSAL OF THE FOLLOWING TREE

B
C

D E G
F
ANSWER : POSTORDER: DEBFGCA INORDER: DBEAFCG
PREORDER:ABDECFG

3.A BINARY TREE HAS 8 NODES. THE INORDER AND POSTORDER TRAVERSAL OF THE
TREE ARE GIVEN BELOW. DRAW THE TREE AND FIND PREORDER.
POSTORDER: F E C H G D B A
INORDER: FCEABHDG
A
Answer:

C B

F E D

H
G

PREORDER: ACFEBDHG

Example 4
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)

APPLICATIONS

1. Some applications of preorder traversal are the evaluation of expressions in


prefix notation and the processing of abstract syntax trees by compilers.
2. Binary search trees (a special type of BT) use inorder traversal to print all of
their data in alphanumeric order.
3.A popular application for the use of postorder traversal is the evaluating of
expressions in postfix notation.

EXPRESSION TREES

Algebraic expressions such as

a/b+(c-d)e
Tree representing the expression a/b+(c-d)e.
Converting Expression from Infix to Postfix using STACK

To convert an expression from infix to postfix, we are going to use a stack.

Algorithm
1) Examine the next element in the input.
2) If it is an operand, output it.
3) If it is opening parenthesis, push it on stack.
4) If it is an operator, then
i) If stack is empty, push operator on stack.
ii) If the top of the stack is opening parenthesis, push operator on stack.
iii) If it has higher priority than the top of stack, push operator on stack.
iv) Else pop the operator from the stack and output it, repeat step 4.
5) If it is a closing parenthesis, pop operators from the stack and output them
until an opening parenthesis is encountered. pop and discard the opening
parenthesis.
6) If there is more input go to step 1
7) If there is no more input, unstack the remaining operators to output.

Example
Suppose we want to convert 2*3/(2-1)+5*(4-1) into Prefix form: Reversed
Expression: )1-4(*5+)1-2(/3*2

Char Scanned Stack Contents(Top on right) Postfix Expression


2 Empty 2
* * 2
3 * 23
/ / 23*
( /( 23*
2 /( 23*2
- /(- 23*2
1 /(- 23*21
) / 23*21-
+ + 23*21-/
5 + 23*21-/5
* +* 23*21-/5
( +*( 23*21-/5
4 +*( 23*21-/54
- +*(- 23*21-/54
1 +*(- 23*21-/541
) +* 23*21-/541-
Empty 23*21-/541-*+

So, the Postfix Expression is 23*21-/541-*+

Converting Expression from Infix to Prefix using STACK

It is a bit trickier algorithm, in this algorithm we first reverse the input


expression so that a+b*c will become c*b+a and then we do the conversion
and then again the output string is reversed. Doing this has an advantage that
except for some minor modifications the algorithm for Infix->Prefix remains
almost same as the one for Infix->Postfix.

Algorithm
1) Reverse the input string.
2) Examine the next element in the input.
3) If it is operand, add it to output string.
4) If it is Closing parenthesis, push it on stack.
5) If it is an operator, then
i) If stack is empty, push operator on stack.
ii) If the top of stack is closing parenthesis, push operator on stack.
iii) If it has same or higher priority than the top of stack, push operator on
stack.
iv) Else pop the operator from the stack and add it to output string, repeat
step 5.
6) If it is a opening parenthesis, pop operators from stack and add them to
output string until a closing parenthesis is encountered. Pop and discard the
closing parenthesis.
7) If there is more input go to step 2
8) If there is no more input, unstack the remaining operators and add them to
output string.
9) Reverse the output string.

Example

Suppose we want to convert 2*3/(2-1)+5*(4-1) into Prefix form: Reversed


Expression: )1-4(*5+)1-2(/3*2

Char Stack Contents(Top on Prefix Expression(right to


Scanned right) left)
) )
1 ) 1
- )- 1
4 )- 14
( Empty 14-
* * 14-
5 * 14-5
+ + 14-5*
) +) 14-5*
1 +) 14-5*1
- +)- 14-5*1
2 +)- 14-5*12
( + 14-5*12-
/ +/ 14-5*12-
3 +/ 14-5*12-3
* +/* 14-5*12-3
2 +/* 14-5*12-32
Empty 14-5*12-32*/+

Reverse the output string : +/*23-21*5-41 So, the final Prefix Expression is
+/*23-21*5-41

EVALUATION OF EXPRESSIONS
CONSTRUCTING AN EXPRESSION TREE
Let us consider the postfix expression given as the input, for constructing an
expression tree by performing the following steps :
1. Read one symbol at a time from the postfix expression.
2. Check whether the symbol is an operand or operator.
i. If the symbol is an operand, create a one node tree and push a
pointer on to the stack.
ii. If the symbol is an operator, pop two pointers from the stack
namely, T1 and T2 and form a new tree with root as the operator,
and T2 as the left child and T1 as the right child.
iii. A pointer to this new tree is then pushed on to the stack.

We now give an algorithm to convert a postfix expression into an expression


tree. Since we already have an algorithm to convert infix to postfix, we can
generate expression trees from the two common types of input. The method
we describe strongly resembles the postfix evaluation algorithm of Section
3.2.3. We read our expression one symbol at a time. If the symbol is an
operand, we create a one-node tree and push a pointer to it onto a stack. If the
symbol is an operator, we pop pointers to two trees T1 and T2 from the stack
(T1 is popped first) and form a new tree whose root is the operator and whose
left and right children point to T2 and T1 respectively. A pointer to this new
tree is then pushed onto the stack.
As an example, suppose the input is
ab+cde+**
The first two symbols are operands, so we create one-node trees and push
pointers to them onto a stack.*
*For convenience, we will have the stack grow from left to right in the
diagrams.
Next, a '+' is read, so two pointers to trees are popped, a new tree is formed,
and a pointer to it is pushed onto the stack.*

Next, c, d, and e are read, and for each a one-node tree is created and a pointer
to the corresponding tree is pushed onto the stack.

Now a '+' is read, so two trees are merged.


Continuing, a '*' is read, so we pop two tree pointers and form a new tree with
a '*' as root.

Finally, the last symbol is read, two trees are merged, and a pointer to the final
tree is left on the stack.
BINARY SEARCH TREE

Binary search tree (BST) is a node-based binary tree data structure which
has the following properties:

The left sub-tree of a node contains only nodes with keys less than the
node's key.
The right sub-tree of a node contains only nodes with keys greater than
the node's key.
Both the left and right sub-trees must also be binary search trees.
From the above properties it naturally follows that:
Each node (item in the tree) has a distinct key.

Program: Creating a Binary Search Tree

We assume that every node of a binary search tree is capable of holding an


integer data item and that the links can be made to point to the root of the left
subtree and the right subtree, respectively. Therefore, the structure of the
node can be defined using the following declaration:
struct tnode
{
int data;
struct tnode *lchild,*rchild;
};

A complete C program to create a binary search tree follows:


#include <stdio.h>
#include <stdlib.h>
struct tnode
{
int data;
struct tnode *lchild, *rchild;
};

struct tnode *insert(struct tnode *p,int val)


{
struct tnode *temp1,*temp2;
if(p == NULL)
{
p = (struct tnode *) malloc(sizeof(struct tnode)); /* insert the new node as
root node*/
if(p == NULL)
{
printf("Cannot allocate\n");
exit(0);
}
p->data = val;
p- >lchild=p->rchild=NULL;
}
else
{
temp1 = p;
/* traverse the tree to get a pointer to that node whose child will be the newly
created node*/
while(temp1 != NULL)
{
temp2 = temp1;
if( temp1 ->data > val)
temp1 = temp1->lchild;
else
temp1 = temp1->rchild;
}
if( temp2->data > val)
{
temp2->lchild = (struct tnode*)malloc(sizeof(struct tnode));/*inserts the
newly created node as left child*/
temp2 = temp2->lchild;
if(temp2 == NULL)
{
printf("Cannot allocate\n");
exit(0);
}
temp2->data = val;
temp2->lchild=temp2->rchild = NULL;
}
else
{
temp2->rchild = (struct tnode*)malloc(sizeof(struct tnode));/ *inserts the
newly created node
as left child*/
temp2 = temp2->rchild;
if(temp2 == NULL)
{
printf("Cannot allocate\n");
exit(0);
}
temp2->data = val;
temp2->lchild=temp2->rchild = NULL;
}
}
return(p);
}
/* a function to binary tree in inorder */
void inorder(struct tnode *p)
{
if(p != NULL)
{
inorder(p->lchild);
printf("%d\t",p->data);
inorder(p->rchild);
}
}
void main()
{
struct tnode *root = NULL;
int n,x;
printf("Enter the number of nodes\n");
scanf("%d",&n);
while( n - > 0)
{
printf("Enter the data value\n");
scanf("%d",&x);
root = insert(root,x);
}
inorder(root);
}
EXAMPLE Construct a BST with nodes 2,4,5,7,1
Normal Tree 2
4 5

7 1

Binary Search Tree


The Values in the left subtree must be smaller than the keyvalue to be
inserted.
The Values in the right subtree must be larger than the keyvalue to be
inserted.

Take the 1st element 2 and compare with 4. 2<4

So
2
4

Similarly 2<5,5>4 and 7>2,7>4,7>5

2
4
5
7
and 1<2 so

2
4
1 5
7
is the final BST.

OPERATIONS

Operations on a binary tree require comparisons between nodes. These


comparisons are made with calls to a comparator, which is a subroutine
that computes the total order (linear order) on any two values. This
comparator can be explicitly or implicitly defined, depending on the
language in which the BST is implemented.
The following are the operations that are being done in Binary Tree
 Searching.
 Sorting.
 Deletion.
 Insertion.
Insert

The insertion routine is conceptually simple. To insert x into tree T, proceed


down the tree as you would with a find. If x is found, do nothing (or "update"
something). Otherwise, insert x at the last spot on the path traversed. Figure
below shows what happens. To insert 5, we traverse the tree as though a find
were occurring. At the node with key 4, we need to go right, but there is no
subtree, so 5 is not in the tree, and this is the correct spot.
Duplicates can be handled by keeping an extra field in the node record
indicating the frequency of occurrence. This adds some extra space to the
entire tree, but is better than putting duplicates in the tree (which tends to
make the tree very deep). Of course this strategy does not work if the key is
only part of a larger record. If that is the case, then we can keep all of the
records that have the same key in an auxiliary data structure, such as a list or
another search tree.

Figure shows the code for the insertion routine. Since T points to the root of
the tree, and the root changes on the first insertion, insert is written as a
function that returns a pointer to the root of the new tree. Lines 8 and 10
recursively insert and attach x into the appropriate subtree.

Insertion into a binary search tree


Searchtree insert(elementtype X, Searchtree T)
{
If(T== NULL)
{
/* create and return a one node tree*/
T=malloc(sizeof(structtreenode));
If(T==NULL)
Fatalerror(“Out of Space”);
Else
{
T-->element=X;
T-->left=T-->right=NULL;
}
}
Else if(x<T-->element)
T-->left=insert(X,T-->left);
Else if(X>=T-->left)
T-->right=insert(X,T-->right);
Return T;
}

EXAMPLE Insert node 5 in given tree


STEP 1: Now 5<6 and 5>2 and 5<4 so

Thus 5 is inserted.

Delete

As is common with many data structures, the hardest operation is deletion.


Once we have found the node to be deleted, we need to consider several
possibilities.
If the node is a leaf, it can be deleted immediately. If the node has one child,
the node can be deleted after its parent adjusts a pointer to bypass the node
(we will draw the pointer directions explicitly for clarity).. Notice that the
deleted node is now unreferenced and can be disposed of only if a pointer to it
has been saved. The complicated case deals with a node with two children.
The general strategy is to replace the key of this node with the smallest key of
the right subtree (which is easily found) and recursively delete that node
(which is now empty). Because the smallest node in the right subtree cannot
have a left child, the second delete is an easy one.

To delete an element, consider the following three possibilities :


Case 1: Node to be deleted is a leaf node.
Case 2: Node with only one child.
Case 3: Node with two children.

Case 1: Node with no children | Leaf node :


1. Search the parent of the leaf node and make the link to the leaf node as
NULL.
2. Release the memory of the deleted node.

Case 2: Node with only one child :


1. Search the parent of the node to be deleted.
2. Assign the link of the parent node to the child of the node to be deleted.
3. Release the memory for the deleted node.

Case 3: Node with two children :


It is difficult to delete a node which has two children.
So, a general strategy has to be followed.
1. Replace the data of the node to be deleted with either the largest element
from the left subtree or the smallest element from the right subtree.

Case 1:

6 6

2 8 2 8

1 4 1 4

Before Deletion After Deletion of 3

EXAMPLE :
Case 2 :

6 6

2 8 2 8

1 4 1

3 3

Before deletion of 4 After deletion of 4

EXAMPLE The right subtree of the node x to be deleted is empty.


EXAMPLE The left subtree of the node x to be deleted is empty.

Case 3 :

6 6

2 8 3 8

1 4 1 4

5
3 5

Before deletion of 2 After deletion


EXAMPLE

DELETION BY COPYING: METHOD#1


Copy the minimum key in the right subtree of x to the node x, then
delete the one-child or leaf-node with this minimum key.

DELETION BY COPYING: METHOD#2


Copy the maximum key in the left subtree of x to the node x, then delete
the one-child or leaf-node with this maximum key.

The code in performs deletion. It is inefficient, because it makes two passes


down the tree to find and delete the smallest node in the right subtree when
this is appropriate. It is easy to remove this inefficiency, by writing a special
delete_min function, and we have left it in only for simplicity.
If the number of deletions is expected to be small, then a popular strategy to
use is lazy deletion: When an element is to be deleted, it is left in the tree and
merely marked as being deleted. This is especially popular if duplicate keys
are present, because then the field that keeps count of the frequency of
appearance can be decremented. If the number of real nodes in the tree is the
same as the number of "deleted" nodes, then the depth of the tree is only
expected to go up by a small constant (why?), so there is a very small time
penalty associated with lazy deletion. Also, if a deleted key is reinserted, the
overhead of allocating a new cell is avoided.
Deletion routine for binary search trees
Searchtree delete(elementtype X, searchtree T)
{
positiontmpcell;
if(T==NULL)
error(“element not found”);
else if(X<T-->element)
T-->left=delete(X,T-->left);
Else if(X>T-->element)
T-->right=delete(X,T-->right);
Else if(T-->left != NULL && T-->right!=NULL)
{
/* Replace with smallest in right subtree*/
Tmpcell=findmin(T-->right);
T-->element=tmpcell-->element;
T-->right=delete(T-->element,T-->right);
}
Else
{
/* One or Zero children*/
tmpcell=T;
if(T-->left==NULL)
T=T-->right;
Else if(T-->right==NULL)
T=T-->left;
Free(tmpcell);
}
Return T;
}

COUNTING THE NUMBER OF NODES IN A BINARY SEARCH TREE

Introduction
To count the number of nodes in a given binary tree, the tree is required to be
traversed recursively until a leaf node is encountered. When a leaf node is
encountered, a count of 1 is returned to its previous activation (which is an
activation for its parent), which takes the count returned from both the
children's activation, adds 1 to it, and returns this value to the activation of its
parent. This way, when the activation for the root of the tree returns, it
returns the count of the total number of the nodes in the tree.
SWAPPING OF LEFT & RIGHT SUBTREES OF A GIVEN BINARY TREE

Introduction
An elegant method of swapping the left and right subtrees of a given binary
tree makes use of a recursive algorithm, which recursively swaps the left and
right subtrees, starting from the root.

Applications of Binary Search Trees


One of the applications of a binary search tree is the implementation of a
dynamic dictionary. This application is appropriate because a dictionary is an
ordered list that is required to be searched frequently, and is also required to
be updated (insertion and deletion mode) frequently. So it can be
implemented by making the entries in a dictionary into the nodes of a binary
search tree. A more efficient implementation of a dynamic dictionary involves
considering a key to be a sequence of characters, and instead of searching by
comparison of entire keys, we use these characters to determine a multi-way
branch at each step. This will allow us to make a 26-way branch according to
the first letter, followed by another branch according to the second letter and
so on.

Applications of Trees

1. Compiler Design.
2. Unix / Linux.
3. Database Management.
4. Trees are very important data structures in computing.
5. They are suitable for:
a. Hierarchical structure representation, e.g.,
i. File directory.
ii. Organizational structure of an institution.
iii. Class inheritance tree.
b. Problem representation, e.g.,
i. Expression tree.
ii. Decision tree.
c. Efficient algorithmic solutions, e.g.,
i. Search trees.
ii. Efficient priority queues via heaps.
AVL TREE
The AVL tree is named after its two inventors, G.M. Adelson-Velsky and E.M.
Landis, who published it in their 1962 paper "An algorithm for the
organization of information."
Avl tree is a self-balancing binary search tree. In an AVL tree, the heights of
the two child subtrees of any node differ by at most one; therefore, it is also
said to be height-balanced.
The balance factor of a node is the height of its right subtree minus the
height of its left subtree and a node with balance factor 1, 0, or -1 is
considered balanced. A node with any other balance factor is considered
unbalanced and requires rebalancing the tree. This can be done by avl tree
rotations
Need for AVL tree
The disadvantage of a binary search tree is that its height can be as large
as N-1
This means that the time needed to perform insertion and deletion and
many other operations can be O(N) in the worst case
We want a tree with small height
A binary tree with N node has height at least Q(log N)
Thus, our goal is to keep the height of a binary search tree O(log N)
Such trees are called balanced binary search trees. Examples are AVL
tree, red-black tree.
Thus we go for AVL tree.

HEIGHTS OF AVL TREE


An AVL tree is a special type of binary tree that is always "partially" balanced.
The criteria that is used to determine the "level" of "balanced-ness" which is
the difference between the heights of subtrees of a root in the tree. The
"height" of tree is the "number of levels" in the tree. The height of a tree is
defined as follows:
1. The height of a tree with no elements is 0
2. The height of a tree with 1 element is 1
3. The height of a tree with > 1 element is equal to 1 + the height of its
tallest subtree.
4. The height of a leaf is 1. The height of a null pointer is zero.
The height of an internal node is the maximum height of its children plus 1.
FINDING THE HEIGHT OF AVL TREE

AVL trees are identical to standard binary search trees except that for every
node in an AVL tree, the height of the left and right subtrees can differ by at
most 1 . AVL trees are HB-k trees (height balanced trees of order k) of order
HB-1. The following is the height differential formula:
|Height (Tl)-Height(Tr)|<=k

When storing an AVL tree, a field must be added to each node with one of
three values: 1, 0, or -1. A value of 1 in this field means that the left subtree
has a height one more than the right subtree. A value of -1 denotes the
opposite. A value of 0 indicates that the heights of both subtrees are the same.
EXAMPLE FOR HEIGHT OF AVL TREE

An AVL tree is a binary search tree with a balanced condition.


Balance Factor(BF) = Hl --- Hr. Hl
=> Height of the left subtree. Hr
=> Height of the right subtree.

If BF={ --1,0,1} is satisfied, only then the tree is balanced.


AVL tree is a Height Balanced Tree.
If the calculated value of BF goes out of the range, then balancing has to be
done.

Rotation :
www.padeepz.net
Modification to the tree. i.e. , If the AVL tree is Imbalanced, proper rotations
has to be done.
A rotation is a process of switching children and parents among two or three
adjacent nodes to restore balance to a tree.

• There are two kinds of single rotation:

Right Rotation Left Rotation

An insertion or deletion may cause an imbalance in an AVL tree.


The deepest node, which is an ancestor of a deleted or an inserted node, and
whose balance factor has changed to -2 or +2 requires rotation to rebalance
the tree.

Balance Factor :

BF= --1
7

5 12
BF=1 BF= --1
2 10 14

BF= 0 BF=0 BF=1


11
BF=0

This Tree is an AVL Tree and a height balanced tree.

An AVL tree causes imbalance when any of following condition occurs:


I.An insertion into Right child’s right subtree.
II.An insertion into Left child’s left subtree.
III.AFTER INSERTION Right child’s left subtree.
iv. An insertion into Left child’s right subtree.

These imbalances can be overcome by,

1. Single Rotation – ( If insertion occurs on the outside,i.e.,LL or RR)

-> LL (Left -- Left rotation) --- Do single Right.


-> RR (Right -- Right rotation) – Do single Left.

2. Double Rotation - ( If insertion occurs on the inside,i.e.,LR or RL)

-> RL ( Right -- Left rotation) --- Do single Right, then single Left.
-> LR ( Left -- Right rotation) --- Do single Left, then single Right.

General Representation of Single Rotation

1. LL Rotation :

• The right child y of a node x becomes x's parent.


• x becomes the left child of y.
• The left child T2 of y, if any, becomes the right child of x.
2. RR Rotation :

• The left child x of a node y becomes y's parent.


• y becomes the right child of x.
• The right child T2 of x, if any, becomes the left child of y.
General Representation of Double Rotation
1. LR( Left -- Right rotation):

2. RL( Right -- Left rotation) :


EXAMPLE:
LET US CONSIDER INSERTING OF NODES 20,10,40,50,90,30,60,70 in an AVL
TREE
APPLICATIONS
AVL trees play an important role in most computer related applications. The
need and use of avl trees are increasing day by day. their efficiency and less
complexity add value to their reputation. Some of the applications are
Contour extraction algorithm
Parallel dictionaries
Compression of computer files
Translation from source language to target language
Spell checker
ADVANTAGES OF AVL TREE
AVL trees guarantee that the difference in height of any two subtrees
rooted at the same node will be at most one. This guarantees an
asymptotic running time of O(log(n)) as opposed to O(n) in the case of a
standard bst.
Height of an AVL tree with n nodes is always very close to the
theoretical minimum.
Since the avl tree is height balabced the operation like insertion and
deletion have low time complexity.
Since tree is always height balanced.Recursive implementation is
possible.
The height of left and the right sub-trees should differ by atmost
1.Rotations are possible.
DISADVANTAGES OF AVL TREE
one limitation is that the tree might be spread across memory
as you need to travel down the tree, you take a performance hit at every
level down
one solution: store more information on the path
Difficult to program & debug ; more space for balance factor.
asymptotically faster but rebalancing costs time.
most larger searches are done in database systems on disk and use
other structures

BINARY HEAPS

A heap is a specialized complete tree structure that satisfies the heap


property:
it is empty or
the key in the root is larger than that in either child and both subtrees
have the heap property.
In general heap is a group of things placed or thrown, one on top of the
other.
In data structures a heap is a binary tree storing keys at its nodes.
Heaps are based on the concepts of a complete tree

Structure Property :
COMPLETE TREE
A binary tree is completely full if it is of height, h, and has 2h+1-1 nodes.
it is empty or
its left subtree is complete of height h-1 and its right subtree is
completely full of height h-2 or
its left subtree is completely full of height h-1 and its right subtree is
complete of height h-1.

A complete tree is filled from the left:


all the leaves are on
o the same level or
o two adjacent ones and
all nodes at the lowest level are as far to the left as possible.
PROCEDURE
INSERTION:
Let us consider the element X is to be inserted.
First the element X is added as the last node.
It is verified with its parent and adjacent node for its heap property.
The verification process is carried upwards until the heap property is
satisfied.
If any verification is not satisfied then swapping takes place.
Then finally we have the heap.
DELETION:
The deletion takes place by removing the root node.
The root node is then replaced by the last leaf node in the tree to obtain
the complete binary tree.
It is verified with its children and adjacent node for its heap property.
The verification process is carried downwards until the heap property
is satisfied.
If any verification is not satisfied then swapping takes place.
Then finally we have the heap.

PRIORITY QUEUE

It is a data structure which determines the priority of jobs.


The Minimum the value of Priority, Higher is the priority of the job.
The best way to implement Priority Queue is Binary Heap.
A Priority Queue is a special kind of queue datastructure. It has zero or more
collection of elements, each element has a priority value.
• Priority queues are often used in resource management, simulations,
and in the implementation of some algorithms (e.g., some graph
algorithms, some backtracking algorithms).
• Several data structures can be used to implement priority queues.
Below is a comparison of some:

Basic Model of a Priority Queue

Deletion(h) Insertion(h)
PRIORITY QUEUEI

Implementation of Priority Queue


1. Linked List.
2. Binary Search Tree.
3. Binary Heap.
Linked List :
A simple linked list implementation of priority queue requires o(1) time
to perform the insertion at the front and o(n) to delete at minimum element.

Binary Search tree :


This gives an average running time of o(log n) for both insertion and
deletion.(deletemin).

The efficient way of implementing priority queue is Binary Heap (or)


Heap.

Heap has two properties :


1. Structure Property.
2. Heap Order Preoperty.

1. Structure Property :
The Heap should be a complete binary tree, which is a completely filled
tree, which is a completely filled binary tree with the possible exception of the
bottom level, which is filled from left to right.
A Complete Binary tree of height H, has between 2h and (2h+1 - 1) nodes.

Sentinel Value :
The zeroth element is called the sentinel value. It is not a node of the tree.
This value is required because while addition of new node, certain operations
are performed in a loop and to terminate the loop, sentinel value is used.
Index 0 is the sentinel value. It stores irrelated value, inorder to terminate the
program in case of complex codings.
Structure Property : Always index 1 should be starting position.

2. Heap Order Property :

The property that allows operations to be performed quickly is a heap order


property.
Mintree:
Parent should have lesser value than children.
Maxtree:
Parent should have greater value than children.
These two properties are known as heap properties
Max-heap
Min-heap
Min-heap:
The smallest element is always in the root node.Each node must have a
key that is less or equal to the key of each of its children.
Examples

Max-Heap:
The largest Element is always in the root node.
Each node must have a key that is greater or equal to the key of each of its
children.

Examples

HEAP OPERATIONS:
There are 2 operations of heap
Insertion
Deletion

Insert:
Adding a new key to the heap

Rules for the insertion:


To insert an element X, into the heap, do the following:
Step1: Create a hole in the next available location , since otherwise the tree
will not be complete.
Step2: If X can be placed in the hole, without violating heap order, then do
insertion, otherwise slide the element that is in the hole’s parent node, into
the hole, thus, bubbling the hole up towards the root.
Step3: Continue this process until X can be placed in the hole.

Example Problem :

1. Insert- 18 in a Min Heap


2. Insert the keys 4, 6, 10, 20, and 8 in this order in an originally empty max-
heap

Delete-max or Delete-min:
Removing the root node of a max- or min-heap, respectively

Procedure for Deletemin :


* Deletemin operation is deleting the minimum element from the loop.
* In Binary heap | min heap the minimum element is found in the root.
* When this minimum element is removed, a hole is created at the root.
* Since the heap becomes one smaller, make the last element X in the heap to
move somewhere in the heap.
* If X can be placed in the hole, without violating heap order property, place it ,
otherwise slide the smaller of the hole’s children into the hole, thus , pushing
the hole down one level.
* Repeat this process until X can be placed in the hole.
This general strategy is known as Percolate Down.
EXAMPLE PROBLEMS :

1. DELETE MIN
2. Delete Min -- 13
Other Heap Operations

1. Decrease Key.
2. Increase Key.
3. Delete.
4. Build Heap.

1. Decrease Key :

10 10 8

15 12 8 12 10 12

20 30 20 30 20 30

The Decrease key(P,∆,H) operation decreases the value of the key at


position P, by a positive amount ∆. This may violate the heap order property,
which can be fixed by percolate up Ex : decreasekey(2,7,H)

2. Increase Key :

The Increase Key(P,∆,H) operation increases the value of the key at


position P, by a positive amount ∆. This may violate heap order property,
which can be fixed by percolate down.
Ex : increase key(2,7,H)

10 10 10

12 22 12 20 12
15

20 30 20 30 22 30
3. Delete :

The delete(P,H) operation removes the node at the position P, from the heap
H. This can be done by,

Step 1: Perform the decrease key operation, decrease key(P,∞,H).


Step 2: Perform deletemin(H) operation.

Step 1: Decreasekey(2, ∞,H)


10 10 -∞

20 12 -∞ 12
10 12

22 30 22 30
22 30

Step 2 : Deletemin(H)
10 10

12 12
10 22 12

20 20
30

APPLICATIONS
The heap data structure has many applications
Heap sort
Selection algorithms
Graph algorithms
Heap sort :
One of the best sorting methods being in-place and with no quadratic
worst-case scenarios.
Selection algorithms:
Finding the min, max, both the min and max, median, or even the k-th
largest element can be done in linear time using heaps.
Graph algorithms:
By using heaps as internal traversal data structures, run time will be
reduced by an order of polynomial. Examples of such problems are Prim's
minimal spanning tree algorithm and Dijkstra's shortest path problem.

ADVANTAGE

The biggest advantage of heaps over trees in some applications is that


construction of heaps can be done in linear time.
It is used in
o Heap sort
o Selection algorithms
o Graph algorithms

DISADVANTAGE
Heap is expensive in terms of
safety
maintenance
performance
Performance :
Allocating heap memory usually involves a long negotiation with the OS.
Maintenance:
Dynamic allocation may fail; extra code to handle such exception is
required.
Safety :
Object may be deleted more than once or not deleted at all .
B-TREES
Multi-way Tree
A multi-way (or m-way) search tree of order m is a tree in which

Each node has at-most m subtrees, where the subtrees may be


empty.
Each node consists of at least 1 and at most m-1 distinct keys
The keys in each node are sorted.

The keys and subtrees of a non-leaf node are ordered as:


 T0, k1, T1, k2, T2, . . . , km-1, Tm-1 such that:
All keys in subtree T0 are less than k1.
All keys in subtree Ti , 1 <= i <= m - 2, are greater than ki but less than
ki+1.
All keys in subtree Tm-1 are greater than km-1

A B-tree of order m (or branching factor m), where m > 2, is either an empty
tree or a multiway search tree with the following properties:
The root is either a leaf or it has at least two non-empty subtrees
and at most m non-empty subtrees.
Each non-leaf node, other than the root, has at least m/2 non-
empty subtrees and at most m non-empty subtrees. (Note: x is the
lowest integer > x ).
The number of keys in each non-leaf node is one less than the
number of non-empty subtrees for that node.
All leaf nodes are at the same level; that is the tree is perfectly
balanced.

Insertion in B-Trees

OVERFLOW CONDITION:
A root-node or a non-root node of a B-tree of order m overflows if, after a
key insertion, it contains m keys.

Insertion algorithm:
If a node overflows, split it into two, propagate the "middle" key to the
parent of the node. If the parent overflows the process propagates upward. If
the node has no parent, create a new root node.
• Note: Insertion of a key always starts at a leaf node.

Insertion in a B-tree of odd order


Example: Insert the keys 78, 52, 81, 40, 33, 90, 85, 20, and 38 in this order in
an initially empty B-tree of order 3

Insertion in a B-tree of even order

At each node the insertion can be done in two different ways:


• right-bias: The node is split such that its right subtree has more keys
than the left subtree.
• left-bias: The node is split such that its left subtree has more keys than
the right subtree.

Example: Insert the key 5 in the following B-tree of order 4:


Unit IV: Graphs: DEFINITION-REPRESENTATION OF GRAPH- GRAPH-BREADTH FIRST
TRACERSAL-EPTH FIRST TRAVERSAL -TOPOLOGICAL
SORT-BI-CONNECTIVITY-CUT VERTEX-EUCLER CIRCUITS-APPLICATIONS OF HEAP.

Graph: - A graph is data structure that consists of following two components.


 A finite set of vertices also called as nodes.
 A finite set of ordered pair of the form (u, v) called as edge.
(or)
A graph G=(V, E) is a collection of two sets V and E, where
V Finite number of vertices
E Finite number of Edges,

Edge is a pair (v, w), where v, w ∈ V.

Application of graphs:
 Coloring of MAPS
 Representing network
o Paths in a city
o Telephone network o
Electrical circuits etc.
 It is also using in social network
including o LinkedIn
o Facebook
Types of Graphs:
 Directed graph
 Undirected Graph

Directed Graph:
In representing of graph there is a directions are
shown on the edges then that graph is called
Directed graph.
That is,
A graph G=(V, E) is a directed graph ,Edge is a

pair (v, w), where v, w ∈ V, and the pair is ordered.


Means vertex ‘w’ is adjacent to v.
Directed graph is also called digraph.
Undirected Graph:
In graph vertices are not ordered is called undirected
graph. Means in which (graph) there is no direction
(arrow head) on any line (edge).
A graph G=(V, E) is a directed graph ,Edge is a pair
(v, w), where v, w ∈ V, and the pair is not ordered.
Means vertex ‘w’ is adjacent to ‘v’, and vertex ‘v’ I adjacent tow
Note: in graph there is another component
called weight/ cost.
Weight graph:
Edge may be weight to show that there is
a cost to go from one vertex to another.
Example: In graph of roads (edges) that
connect one city to another (vertices), the
weight on the edge might represent the
distance between the two cities (vertices).
Difference between Trees and Graphs
Trees Graphs
Path Tree is special form of graph i.e. minimally In graph there can be more than
connected graph and having only one path one path i.e. graph can have uni-
between any two vertices. directional or bi-directional paths
(edges) between nodes
Loops Tree is a special case of graph having Graph can have loops, circuits as
Root Node no loops, no circuits and no self-loops. well as can have self-loops.
Parent In tree there is exactly one root node and In graph there is no such concept
Child every child have only one parent. of root node.
relationship In trees, there is parent child relationship so In Graph there is no such parent
Complexity flow can be there with direction top to child relationship.
bottom or vice versa.
Trees are less complex then graphs as having Graphs are more complex in
Types of no cycles, no self-loops and still connected. compare to trees as it can have
Traversal cycles, loops etc
Graph is traversed by
Tree traversal is a kind of special case of
DFS: Depth First Search
traversal of graph. Tree is traversed in Pre-
Connection BFS : Breadth First Search
Order, In-Order and Post-Order(all three
Rules algorithm
in DFS or in BFS algorithm)
In graphs no such rules/
In trees, there are many rules / restrictions
restrictions are there for
for making connections between nodes
connecting the nodes through
DAG through edges.
edges.
Graph can be Cyclic or Acyclic.
Trees come in the category of DAG :
Different Directed Acyclic Graphs is a kind of
Types directed graph that have no cycles.
Different types of trees are : Binary Tree , There are mainly two types of
Binary Search Tree, AVL tree, Heaps. Graphs :Directed and Undirected
Applications graphs.
Graph applications : Coloring of
Tree applications: sorting and searching like maps, in OR (PERT & CPM),
Tree Traversal & Binary Search. algorithms, Graph coloring, job
No. of edges scheduling, etc.
In Graph, no. of edges depends on
Tree always has n-1 edges. the graph.
Model Tree is a hierarchical model. Graph is a network model.
Figure
Other types of graphs:
Complete Graph:A complete graph is a simple undirected graph in which every pair of distinct
vertices isconnected by a unique edge.
OR
If an undirected graph of n vertices consists of n(n-1)/2 number of edges then the graph is
called complete graph

.
Sub graph:
A sub-graph G' of graph G is a graph, such that the set of vertices and set of edges
of G' are proper subset of the set of vertices and set of edges of graph G
respectively.

Connected Graph:
A graph which is connected in the sense of a topological space (study of shapes), i.e., there is
a path from any point to any other point in the graph. A graph that is not connected is said to
be disconnected.
path:
A path in a graph is a finite or infinite sequence of edges which connect a sequence of
vertices. Means a path form one vertices to another vertices in a graph is represented by
collection of all vertices (including source and destination) between those two vertices.

Cycle: A path that begins and ends at the same vertex.

Simple Cycle: a cycle that does not pass through other vertices more than once

Degree:
The degree of a graph vertex v of a graph G is the number of graph edges which touch v. The
vertex degree is also called the local degree or valency. Or

The degree (or valence) of a vertex is the number of edge ends at that vertex.

For example, in this graph all of the vertices have degree three.
In a digraph (directed graph) the degree is usually divided into the in-degree and the out-
degree
 In-degree: The in-degree of a vertex v is the number of edges with v as their terminal
vertex.
 Out-degree: The out-degree of a vertex v is the number of edges with v as their initial
vertex.
TOPOLOGICAL SORT
A topological sort is a linear ordering of vertices in a Directed Acyclic Graph
such that if there is a path from Vi to Vp, then Vj appears after Vi in the linear
ordering.Topological sort is not possible if the graph has a cycle.
INTRODUCTION
In graph theory, a topological sort or topological ordering of a directed
acyclic graph (DAG) is a linear ordering of its nodes in which each node
comes before all nodes to which it has outbound edges.
Every DAG has one or more topological sorts.
More formally, define the partial order relation R over the nodes of the
DAG such that xRy if and only if there is a directed path from x to y.
Then, a topological sort is a linear extension of this partial order, that is,
a total order compatible with the partial order.

PROCEDURE
Step – 1 : Find the indegree for every vertex.
Step – 2 : Place the vertice whose indegree is 0, on the empty queue.
Step – 3 : Dequeue the vertex V and decrement the indegrees of all its adjacent
vertices.
Step – 4 : Enqueue the vertex on the queue if its indegree falls to zero.
Step – 5 : Repeat from Step -3 until the queue becomes empty.
The topological ordering is the order in which the vertices dequeue.

Vertices Indegree
1 0
2 0
GRAPH TRAVERSAL
Graph traversal is the Visiting all the nodes of a graph.
The traversals are :
1. DFS (Depth First Search)
2. BFS (Breadth First Search)

BREADTH FIRST SEARCH


The Breadth first search was one of the systematic approaches for
exploring and searching the vertices/nodes in a given graph. The
approach is called "breadth-first" because from each vertex ‘v’ that we
visit, we search as broadly as possible by next visiting all the vertices
adjacent to v.
It can also be used to find out whether a node is reachable from a given
node or not.
It is applicable to both directed and undirected graphs.
Queue is used in the implementation of the breadth first search.
AlGORITHM
Procedure bfs()
{
//BFS uses Queue data structure
Queue q=new LinkedList();
q.add(this.rootNode);
printNode(this.rootNode);
rootNode.visited=true;
while(!q.isEmpty())
{
Node n=(Node)q.remove(); Node child=null;
while((child=getUnvisitedChildNode(n))!=null)
{
child.visited=true;
printNode(child);
q.add(child);
}
}
//Clear visited property of nodes
clearNodes();
}

Procedure
Step -1 Select the start vertex/source vertex. Visit the vertex and mark it
as one (1) (1 represents visited vertex).
Step -2 Enqueue the vertex.
Step -3 Dequeue the vertex.
Step -4 Find the Adjacent vertices.
Step -5 Visit the unvisited adjacent vertices and mark the distance as 1.
Step -6 Enqueue the adjacent vertices.
Step -7 Repeat from Step – 3 to Step – 5 until the queue becomes empty.

Vertices Visited
Ex : A B Vertices
A 1
C D B 0 1
C 0 1
D 0 1
Enqueue A B C D
Dequeue A B C D

A B
Vertices Visited
Vertices
C 1
C D A 0 1
B 0 1
D 0 1
E E 0 1
Enqueue C A B D
E
Dequeue C A B D
E
APPLICATIONS
Breadth-first search can be used to solve many problems in graph theory, for
example.
Finding all nodes within one connected component
Copying Collection, Cheney's algorithm
Finding the shortest path between two nodes u and v (in an unweighted
graph)
Finding the shortest path between two nodes u and v (in a weighted
graph: see talk page)
Testing a graph for bipartiteness
(Reverse) Cuthill–McKee mesh numbering
Testing whether graph is connected.
Computing a spanning forest of graph.
Computing, for every vertex in graph, a path with the minimum number
of edges between start vertex and current vertex or reporting that no
such path exists.
Computing a cycle in graph or reporting that no such cycle exists.
Uses
Testing whether graph is connected.
Computing a spanning forest of graph.
Computing, for every vertex in graph, a path with the minimum number
of edges between start vertex and current vertex or reporting that no
such path exists.
Computing a cycle in graph or reporting that no such cycle exists.

DEPTH FIRST SEARCH


Depth first search works by taking a node, checking its neighbors,
expanding the first node it finds among the neighbors, checking if that
expanded node is our destination, and if not, continue exploring more
nodes.
In depth-first search, edges are explored out of the most recently
discovered vertex v that still has unexplored edges leaving it.
When all of v' s edges have been explored, the search "backtracks" to
explore edges leaving the vertex from which v was discovered.
This process continues until we have discovered all the vertices that are
reachable from the original source vertex.
If any undiscovered vertices remain, then one of them is selected as a
new source and the search is repeated from that source.
This entire process is repeated until all vertices are discovered.
Stack is used in the implementation of the depth first search.
In DFS, the basic data structures for storing the adjacent nodes is stack.
Procedure:
Step -1 Select the start vertex.
Step -2 Visit the vertex.
Step -3 Push the vertex on to the stack.
Step -4 Pop the vertex.
Step -5 Find the adjacent vertices, and select any 1 of them.
Step -6 Repeat from Step – 4 to Step – 5 until the stack becomes empty.

Vertices Visited
A B Vertices Stack O/P
A 1 A
B 0 1 D
C 0 1 C
C D D 0 1
A D C B

Vertices Visited Stack o/p A BD C


Vertices
A B A 1
B 0 1
C 0 1
D 0 1
C D
Applications of DFS :
1. To check whether the undirected graph is connected or not.
2. To check if the connected undirected graph is bi – connected or not.
3. To check whether the directed graph is acyclic or not.

I. Undirected Graph :
An undirected graph is connected if and only if a depth first search
starting from any node visits every node.

A 1. Tree Edge
2. Back Edge ----------- >

B D E
A A
C B B
C E C
D D

B A C
G B
C D A
F D
G F
E E
A

B
C D
F
G E

II. Bi-Connectivity :
The vertices which are responsible for disconnection is called as
Articulation points.
If in a connected undirected graph, the removal of any node does not
affect the connectivities, then the graph is said to be biconnected graph.
1. Num Low(w) ≥ Num(v)
2. Low
Calculation of Num and Low gives the articulation point.

B A A (1,1)
B (2,1)
C G
C D (3,1) (7,7)
F D (4,1)
(5,4)
G E EF (6,4)

BICONNECTIVITY :
A connected undirected graph is biconnective if there are no vertices
whose removal disconnects the rest of the graph.

A biconnected undirected graph is a connected graph that is not broken


into disconnected pieces by deleting any single vertex (and its incident
edges).
A biconnected directed graph is one such that for any two vertices v and
w there are two directed paths from v to w which have no vertices in
common other than v and w.
If a is not bio-connected,the vertices whose removal would disconnect
the graph is called articulation points.
DEFINITION

Equivalent definitions of a biconnected graph G:


Graph G has no separation edges and no separation vertices
For any two vertices u and v of G, there are two disjoint simple paths
between u and v (i.e., two simple paths between u and v that share no
other vertices or edges)
For any two vertices u and v of G, there is a simple cycle
containing u and v.
Biconnected Components
Biconnected component of a graph G are:
A maximal biconnected subgraph of G, or
A subgraph consisting of a separation edge of G and its end vertices
Interaction of biconnected components
An edge belongs to exactly one biconnected component
A nonseparation vertex belongs to exactly one biconnected component
A separation vertex belongs to two or more biconnected components

Articulation Point :
The vertices whose removal disconnects the graph are known as
Articulation Points.
Steps to find Articulation Points :
(i) Perform DFS, starting at any vertex.
(ii) Number the vertex as they are visited as Num(V).
(iii) Compute the lowest numbered vertex for every vertex V in the DFS
tree, which we call as low(W), that is reachable from V by taking one
or more tree edges and then possible one back edge by definition.

Low(V) = min(Num(V), Num(W), Low(W))


The Lowest Num(W) among all back edges V, W.
The Lowest Low(W) among all the tree edges V, W.
The root is an articulation if and only if (iff) it has more than two children.
Any vertex V other than the root is an Articulation point iff V has some child W
such that Low(W)≥Num (V)
A (1,1)
B (2,1)
C (3,1)
D (4,1) G (7,7)
E (5,4)

F (6,4)

Low(F) = min(Num(V), Num(W), Low(W))


= min(6, 4, -1)
=4
Low(E) = min(5, 6, 4)
=4
Low(D) = min(4, 1, 4)
=1
Low(G) = min(7, -, -)
=7

Low(C) = min(3, (4,7), (1,7))


=1
Low(B) = min(2, 3, 1)
=1
Low(A) = min(1, 2, 1)
=1
Example 2

B E H I
A C F I K

D
G

B
C
A F
D G E
H
J
K
I
Visited Parent[]
1 2 3 4
1A 1B 1C 1D 10 11 1 2 13
0 1 2 3
Num[] 1 A 1B 1C 1D

A A (1,1)
B C B (2,1)
D C (3,1)
D (4,4)

APPLICATION
Bio-Connectivity is a application of depth first search.
Used mainly in network concepts.

BICONNECTIVITY ADVANTAGES
Total time to perform traversal is minimum.
Adjacency lists are used
Traversal is given by O(E+V).

DISADVANTAGES
Have to be careful to avoid cycles
Vertices should be carefully removed as it affects the rest of the graph.

EULER CIRCUIT
EULERIAN PATH
An Eulerian path in an undirected graph is a path that uses each edge
exactly once. If such a path exists, the graph is called traversable or semi-
eulerian.

EULERIAN CIRCUIT
An Eulerian circuit or Euler tour in an undirected graph is a cycle that
uses each edge exactly once. If such a cycle exists, the graph is called
Unicursal. While such graphs are Eulerian graphs, not every Eulerian graph
possesses an Eulerian cycle.

EULER'S THEOREM

Euler's theorem 1
If a graph has any vertex of odd degree then it cannot have an Euler
circuit.
If a graph is connected and every vertex is of even degree, then it at least
has one Euler circuit.
Euler's theorem 2
If a graph has more than two vertices of odd degree then it cannot have
an Euler path.
If a graph is connected and has just two vertices of odd degree, then it at
least has one Euler path. Any such path must start at one of the odd-
vertices and end at the other odd vertex.
ALGORITHM
Fleury's Algorithm for finding an Euler Circuit
1. Check to make sure that the graph is connected and all vertices are of
even degree
2. Start at any vertex
3. Travel through an edge:
o If it is not a bridge for the untraveled part, or
o there is no other alternative
4. Label the edges in the order in which you travel them.
5. When you cannot travel any more, stop.
Fleury's Algorithm
1. pick any vertex to start .
2. from that vertex pick an edge to traverse .
3. darken that edge, as a reminder that you can't traverse it again .
4. travel that edge, coming to the next vertex .
5. repeat 2-4 until all edges have been traversed, and you are back at the
starting vertex .
At each stage of the algorithm:
the original graph minus the darkened (already used) edges = reduced
graph
important rule: never cross a bridge of the reduced graph unless there is
no other choice
Note:

the same algorithm works for Euler paths


before starting, use Euler’s theorems to check that the graph has an
Euler path and/or circuit to find.

APPLICATION

Eulerian paths are being used in bioinformatics to reconstruct the DNA


SEQUENCE from its fragments.
UNIT V SORTING, SEARCHING AND HASH TECHNIQUES
SORTING:
Definition:
Sorting is a technique for arranging data in a particular order.
Order of sorting:
Order means the arrangement of data. The sorting order can be ascending or descending. The
ascending order means arranging the data in increasing order and descending order means
arranging the data in decreasing order.
Types of Sorting
Internal Sorting
External Sorting
Internal Sorting
Internal Sorting is a type of sorting technique in which data resides on main memory of
computer. It is applicable when the number of elements in the list is small.
E.g. Bubble Sort, Insertion Sort, Shell Sort, Quick Sort., Selection sort, Radix sort
External Sorting
External Sorting is a type of sorting technique in which there is a huge amount of data and it resides on
secondary devise(for eg hard disk,Magnetic tape and so no) while sorting.
E.g. Merge Sort, Multiway Merge Sort,Polyphase merge sort
Sorting can be classified based on
1.Computational complexity
2.Memory utilization
3. Stability
4. Number of comparisons.
ANALYSIS OF ALGORITHMS:
Efficiency of an algorithm can be measured in terms of:

Space Complexity: Refers to the space required to execute the algorithm

Time Complexity: Refers to the time required to run the program.


Sorting algorithms:
Insertion sort
Selection sort
Shell sort
Bubble sort
Quick sort
Merge sort
Radix sort
INSERTION SORTING:
The insertion sort works by taking elements from the list one by one and inserting them
in the correct position into a new sorted list.
Insertion sort consists of N-1 passes, where N is the number of elements to be sorted.
The ith pass will insert the ith element A[i] into its rightful place among
A[1],A[2],…,A[i-1].
After doing this insertion the elements occupying A[1],…A[i] are in sorted order.

How Insertion sort algorithm works?

Insertion Sort routine:


void Insertion_sort(int a[ ], int n)
{
int i, j, temp;
for ( i = 0 ; i < n -1 ; i ++ )
{
temp = a [ j ] ;
for ( j = i ; j > 0 && a [ j -1 ] > temp ; j -- )
{
a[ j ] = a [ j – 1 ] ;
}
a[j]=temp;
}}
Advantage of Insertion sort
Simple implementation.
Efficient for (quite) small data sets.
Efficient for data sets that are already substantially sorted.

Disadvantages of Insertion sort


It is less efficient on list containing more number of elements.
As the number of elements increases the performance of the program would be slow.
Insertion sort needs a large number of element shifts.
Selection Sort
Selection sort selects the smallest element in the list and place it in the first position then selects
the second smallest element and place it in the second position and it proceeds in the similar way
until the entire list is sorted. For “n” elements, (n-1) passes are required. At the end of the ith
iteration, the ith smallest element will be placed in its correct position.

Selection Sort routine:


void Selection_sort( int a[ ], int n )
{
int i , j , temp , position ;
for ( i = 0 ; i < n – 1 ; i ++ )
{
position = i ;
for ( j = i + 1 ; j < n ; j ++ )
{
if ( a[ position ] > a[ j ] )
position = j;}
temp = a[ i ];
a[ i ] = a[ position ];
a[ position ] = temp;
}}

How Selection sort algorithm works?


Advantages of selection sort
• Memory required is small.
• Selection sort is useful when you have limited memory available.
• Relatively efficient for small arrays.

Disadvantage of selection sort


• Poor efficiency when dealing with a huge list of items.
• The selection sort requires n-squared number of steps for sorting n elements.
• The selection sort is only suitable for a list of few elements that are in random order.
Shell Sort
• Invented by Donald shell.
• It improves upon bubble sort and insertion sort by moving out of order elements more
than one position at a time.
• In shell sort the whole array is first fragmented into K segments, where K is preferably a
prime number.
• After the first pass the whole array is partially sorted.
• In the next pass, the value of K is reduced which increases the size of each segment and
reduces the number of segments.
• The next value of K is chosen so that it is relatively prime to its previous value.
• The process is repeated until K=1 at which the array is sorted.
• The insertion sort is applied to each segment so each successive segment is partially
sorted.
• The shell sort is also called the Diminishing Increment sort, because the value of k
decreases continuously

A Shell Sort with Increments of Three


A Shell Sort after Sorting Each Sublist
];
for ( j = i ; j > = k && a [ j – k ] > temp ; j = j – k )
{
a[
j]
=a
[j
–k
];
}
a [ j ] = temp ;
}
}
Advantages of Shell sort
• Efficient for medium-size lists.
Disadvantages of Shell sort
; • Complex algorithm, not nearly as efficient as the merge, heap and
quick sorts
iBubble Sort
Bubble sort is one of the simplest internal sorting algorithms.
< Bubble sort works by comparing two consecutive elements
and the largest element among these two bubbles towards
n right at the end of the first pass the largest element gets
sorted and placed at the end of the sorted list.
; This process is repeated for all pairs of elements until it
moves the largest element to theend of the list in that
i iteration.
Bubble sort consists of (n-1) passes, where n is the
+ number of elements to be sorted.In 1st pass the largest
element will be placed in the nth position.
+ In 2nd pass the second largest element will be
placed in the (n-1)th position.In (n-1)th pass
) only the first two elements are compared.
{
t
= temp;
e
m
p

i
Advantage of Bubble sort
• It is simple to write
• Easy to understand
• It only takes a few lines of code.
Disadvantage of Bubble sort
• The major drawback is the amount of time it takes to sort.
• The average time increases almost exponentially as the number of table elements
increase.
Quick Sort
Quicksort is a divide and conquer algorithm.
The basic idea is to find a “pivot” item in the array and compare all other items with pivot
element.
Shift items such that all of the items before the pivot are less than the pivot value and all
the items after the pivot are greater than the pivot value.
After that, recursively perform the same operation on the items before and after the pivot.
Find a “pivot” item in the array. This item is the basis for comparison for a single round.
Start a pointer (the left pointer) at the first item in the array.
Start a pointer (the right pointer) at the last item in the array.
1. Assume A[0]=pivot which is the left. i.e pivot=left.
2. Set i=left+1; i.e A[1];
3. Set j=right. ie. A[6] if there are 7 elements in the array
4. If A[pivot]>A[i],increment i and if A[j]>A[pivot],then decrement j, Otherwise swap A[i]
and A[j] element.
5. If i=j,then swap A[pivot] and A[j].
Advantages of Quick sort
• Fast and efficient as it deals well with a huge list of items.
• No additional storage is required.
Disadvantages of Quick sort
• The difficulty of implementing the partitioning algorithm.

Merge Sort
Merge sort is a sorting algorithm that uses the divide, conquer, and combine algorithmic
paradigm.
Divide means partitioning the n-element array to be sorted into two sub-arrays of n/2 elements.
If there are more elements in the array, divide A into two sub-arrays, A1 and A2, each containing
about half of the elements of A.
Conquer means sorting the two sub-arrays recursively using merge sort.
Combine means merging the two sorted sub-arrays of size n/2 to produce the sorted array of n
elements.
The basic steps of a merge sort algorithm are as follows:
If the array is of length 0 or 1, then it is already sorted.
Otherwise, divide the unsorted array into two sub-arrays of about half the size.
Use merge sort algorithm recursively to sort each sub-array.
Merge the two sub-arrays to form a single sorted list.

Advantages of Merge sort


• Mergesort is well-suited for sorting really huge amounts of data that does not fit into
memory.
• It is fast and stable algorithm

Disadvantages of Merge sort


• Merge sort uses a lot of memory.
• It uses extra space proportional to number of element n.
• This can slow it down when attempting to sort very large data.

Radix Sort

Radix sort is one of the linear sorting algorithms. It is generalized form of bucket sort. It
can be performed using buckets from 0 to 9.
It is also called binsort, card sort.
It works by sorting the input based on each digit. In first pass all the elements are stored
according to the least significant digit.
In second pass the elements are arranged according to the next least significant digit and
so on till the most significant digit.
The number of passes in a Radix sort depends upon the number of digits in the given
numbers.

Algorithm for Radix sort

Steps1: Consider 10 buckets (1 for each digit 0 to 9)

Step2: Consider the LSB (Least Significant Bit) of each number (numbers in the one‟s
Place…. E.g., in 43 LSB = 3)
Step3: Place the elements in their respective buckets according to the LSB of each number

Step4: Write the numbers from the bucket (0 to 9) bottom to top.

Step5: repeat the same process with the digits in the 10‟s place (e.g. In 43 MSB =4)

Step6: repeat the same step till all the digits of the given number are consider.
Consider the following numbers to be sorted using Radix sort.

Sorted list of array : 3 15 27 31 37 43 80


Routine for Radix sort
void Radix_sort ( int a [ ] , int n )
{
int bucket [ 10 ] [ 5 ] , buck [ 10 ] , b [ 10 ] ;
int i , j , k , l , num , div , large , passes ;
div = 1 ;
num = 0 ;
large = a [ 0 ] ;
for ( i = 0 ; i < n ; i ++ )
{
if ( a[ I ] > large )
{
large = a [ i ] ;
}
while ( large > 0 )
{
num ++ ;
large = large / 10 ;
}
for ( passes = 0 ; passes < num ; passes ++ )
{
for ( k = 0 ; k < 10 ; k ++ )
{
buck [ k ] = 0 ;
}
for ( i = 0 ; i < n ; i ++ )
{
l = ( ( a [ i ] / div ) % 10 ) ;
} bucket [ l ] [ buck [ l ] ++ ] = a [ i ] ;
i=0;
for ( k = 0 ; k < 10 ; k ++ )
{
for ( j = 0 ; j < buck [ k ] ; j ++ )
{
a [ i ++ ] = bucket [ k ] [ j ] ;
}
}
div * = 10 ;
}
}
}

Program for Radix sort

#include<stdio.h >
void main( )
{
int a [ 5 ] = { 4, 5, 2, 3, 6 } , i = 0 ;
void Radix_sort ( int a [ ] , int n );
Radix_sort(a,5);
printf( " After Sorting :" ) ;
for ( i = 0 ; i < 5 ; i ++ )
printf ( " %d ", a[ i ] ) ;
}
void Radix_sort ( int a [ ] , int n )
{
int bucket [ 10 ] [ 5 ] , buck [ 10 ] , b [ 10 ] ;
int i , j , k , l , num , div , large , passes ;
div = 1 ;
num = 0 ;
large = a [ 0 ] ;
for ( i = 0 ; i < n ; i ++ ){
if ( a[ i] > large )
padamavani arts
{ and science
college
large = a [ i ] ;
}
while ( large > 0 )
{
num ++ ;
large = large / 10 ;
}
for ( passes = 0 ; passes < num ; passes ++ )
{
for ( k = 0 ; k < 10 ; k ++ )
{
buck [ k ] = 0 ;
}
for ( i = 0 ; i < n ; i ++ )
{
l = ( ( a [ i ] / div ) % 10 ) ;
bucket [ l ] [ buck [ l ] ++ ] = a [ i ] ;
}
i=0;
for ( k = 0 ; k < 10 ; k ++ )
{
for(j=0 ; j<buck[k];j++ )
{
a[i++]=bucket[ k ][ j ] ;
}
}
div*= 10 ;
}
}
}

Advantages of Radix sort:


• Fast and complexity does not depend on the number of data.
• Radix Sort is very simple.
Disadvantages of Radix sort:
• Radix Sort takes more space than other sorting algorithms, since in addition to the array that
will be sorted, you need to have a sub list for each of the possible digits or letters.
• Since Radix Sort depends on the digits or letters, Radix Sort is also much less flexible than
other sorts.
Analysis of Sorting algorithms:

S.No Algorithm Best Case Analysis Average Case Worst Case


Analysis Analysis
1 Insertion sort O(N) O(N2) O(N2)
2 Selection sort O(N2) O(N2) O(N2)
3 Shell sort O(N log N) O(N1.5) O(N2)
4 Bubble sort O(N2) O(N2) O(N2)
5 Quick sort O(N log N) O(N log N) O(N 2)
6 Merge sort O(N log N) O(N log N) O(N log N)
7 Radix or bucket or O(N log N) O(N log N) O(N log N)
binsort sort or card
sort

SEARCHING
Searching is an algorithm, to check whether a particular element is present in the list.
Types of searching:-
Linear search
Binary Search
Linear Search
Linear search is used to search a data item in the given set in the sequential manner, starting from
the first element. It is also called as sequential search

Linear Search routine:

void Linear_search ( int a[ ] , int n )


{
int search , count = 0 ;
for ( i = 0 ; i < n ; I ++ )
{
if ( a [ i ] = = search )
{
count ++ ;
}
}
if ( count = = 0 )
print “Element not Present” ;
else
print “Element is Present in list" ;
}
Advantages of Linear search:
• The linear search is simple - It is very easy to understand and implement;
• It does not require the data in the array to be stored in any particular order.
Disadvantages of Linear search:
• Slower than many other search algorithms.
• It has a very poor efficiency.

Binary Search
Binary search is used to search an item in a sorted list. In this method , initialize the lower
limit and upper limit.
The middle position is computed as (first+last)/2 and check the element in the middle
position with the data item to be searched.
If the data item is greater than the middle value then the lower limit is adjusted to one
greater than the middle value.Otherwise the upper limit is adjusted to one less than the
middle value.
Working principle:
Algorithm is quite simple. It can be done either recursively or iteratively:
1. Get the middle element;
2. If the middle element equals to the searched value, the algorithm stops;
3. Otherwise, two cases are possible:
o Search value is less than the middle element. In this case, go to the step 1 for the
part of the array, before middle element.
o Searched value is greater, than the middle element. In this case, go to the step 1
for the part of the array, after middle element.

Advantages of Binary search:


In Linear search, the search element is compared with all the elements in the array. Whereas
in Binary search, the search element is compared based on the middle element present in the
array.
A technique for searching an ordered list in which we first check the middle item and - based
on that comparison - "discard" half the data. The same procedure is then applied to the
remaining half until a match is found or there are no more items left.
Disadvantages of Binary search:
Binary search algorithm employs recursive approach and this approach requires more
stack space.
It requires the data in the array to be stored in sorted order.
It involves additional complexity in computing the middle element of the array.
Analysis of Searching algorithms:

S.No Algorithm Best Case Analysis Average Case Worst Case


Analysis Analysis

1 Linear search O(1) O(N) O(N)


2 Binary search O(1) O(log N) O(log N)

HASHING :
Hashing is a technique that is used to store, retrieve and find data in the data structure
called Hash Table. It is used to overcome the drawback of Linear Search (Comparison) &
Binary Search (Sorted order list). It involves two important concepts-
 Hash Table
 Hash Function
Hash table
A hash table is a data structure that is used to store and retrieve data (keys) very
quickly.
It is an array of some fixed size, containing the keys.
Hash table run from 0 to Tablesize – 1.
Each key is mapped into some number in the range 0 to Tablesize – 1.
This mapping is called Hash function.
Insertion of the data in the hash table is based on the key value obtained from the
hash function.
Using same hash key value, the data can be retrieved from the hash table by few
or more Hash key comparison.
The load factor of a hash table is calculated using the formula:
(Number of data elements in the hash table) / (Size of the hash table)
Factors affecting Hash Table Design

Hash function
Table size.
Collision handling scheme

0
1
2
3
.
. Simple Hash table with table size = 10
8
9
Hash function:
It is a function, which distributes the keys evenly among the cells in the Hash
Table.
Using the same hash function we can retrieve data from the hash table.
Hash function is used to implement hash table.
The integer value returned by the hash function is called hash key.
If the input keys are integer, the commonly used hash function is

H ( key ) = key % Tablesize

typedef unsigned int index;


index Hash ( const char *key , int Tablesize )
{
unsigned int Hashval = 0 ;
while ( * key ! = „ \0 „ )
Hashval + = * key ++ ;
return ( Hashval % Tablesize ) ;
}
A simple hash function

Types of Hash Functions


1. Division Method
2. Mid Square Method
3. Multiplicative Hash Function
4. Digit Folding
1. Division Method:
It depends on remainder of division.
Divisor is Table Size.
Formula is ( H ( key ) = key % table size )
E.g. consider the following data or record or key (36, 18, 72, 43, 6) table size = 8

2. Mid Square Method:


We first square the item, and then extract some portion of the resulting digits. For
example, if the item were 44, we would first compute 442=1,936. Extract the middle two digit
93 from the answer. Store the key 44 in the index 93.

93

44

3. Multiplicative Hash Function:


Key is multiplied by some constant value.
Hash function is given by,
H(key)=Floor (P * ( key * A ))
P = Integer constant [e.g. P=50]
A = Constant real number [A=0.61803398987],suggested by Donald Knuth to use this
constant
E.g. Key 107
H(107)=Floor(50*(107*0.61803398987))
=Floor(3306.481845)
H(107)=3306
Consider table size is 5000

3306 107

4999

4. Digit Folding Method:

The folding method for constructing hash functions begins by dividing the item into
equal-size pieces (the last piece may not be of equal size). These pieces are then added together
to give the resulting hash key value. For example, if our item was the phone number 436-555-
4601, we would take the digits and divide them into groups of 2 (43, 65, 55, 46, 01). After the
addition, 43+65+55+46+01, we get 210. If we assume our hash table has 11 slots, then we need
to perform the extra step of dividing by 11 and keeping the remainder. In this case 210 % 11 is 1,
so the phone number 436-555-4601 hashes to slot 1.

6-555-4601
Collision:
If two more keys hashes to the same index, the corresponding records cannot be stored in the
same location. This condition is known as collision.
Characteristics of Good Hashing Function:

 It should be Simple to compute.


 Number of Collision should be less while placing record in Hash Table.
 Hash function with no collision  Perfect hash function.
 Hash Function should produce keys which are distributed uniformly in hash table.
 The hash function should depend upon every bit of the key. Thus the hash
function that simply extracts the portion of a key is not suitable.
Collision Resolution Strategies / Techniques (CRT):
If collision occurs, it should be handled or overcome by applying some technique. Such
technique is called CRT.
There are a number of collision resolution techniques, but the most popular are:
 Separate chaining (Open Hashing)
 Open addressing. (Closed Hashing)
Linear Probing
Quadratic Probing
Double Hashing
Separate chaining (Open Hashing)
Open hashing technique.
Implemented using singly linked list concept.
Pointer (ptr) field is added to each record.
When collision occurs, a separate chaining is maintained for colliding data.
Element inserted in front of the list.
H (key) =key % table size
Two operations are there:-
 Insert
 Find
Structure Definition for Node
typedef Struct node *Position;
Struct node
{
int data; defines the nodes
Position next;
};
Structure Definition for Hash Table
typedef Position List;
struct Hashtbl
{ Defines the hash table which contains
int Tablesize; array of linked list
List * theLists;
};

Initialization for Hash Table for Separate Chaining


Hashtable initialize(int Tablesize)
{
HashTable H;
int i;
H = malloc (sizeof(struct HashTbl)); Allocates table
H  Tablesize = NextPrime(Tablesize);
Hthe Lists=malloc(sizeof(List) * HTablesize);  Allocates array of list
for( i = 0; i < H  Tablesize; i++ )
{
H  TheLists[i] = malloc(Sizeof(Struct node));  Allocates list headers
H  TheLists[i]  next = NULL;
}
return H;
}
Insert Routine for Separate Chaining
void insert (int Key, Hashtable H)
{
Position P, newnode; *[Inserts element in the Front of the list always]*
List L;
P = find ( key, H );
if(P = = NULL)
{
newnode = malloc(sizeof(Struct node));
L = H  TheLists[Hash(key,Tablesize)];
newnode  nex t= L  next;
newnode  data = key;
L  next = newnode;
}}
Position find( int key, Hashtable H){
Position P, List L;
L = H TheLists[Hash(key,Tablesize)];
P = L  next;
while(P != NULL && P  data != key)
P = P  next;
return P;}
If two keys map to same value, the elements are chained together.
Initial configuration of the hash table with separate chaining. Here we use SLL(Singly Linked List)
concept to chain the elements.

0 NULL
1
NULL
2 NULL
3 NULL
4 NULL
5 NULL
6 NULL
7
8 NULL
9 NULL
NULL
Insert the following four keys 22 84 35 62 into hash table of size 10 using separate chaining.
The hash function is
H(key) = key % 10
1. H(22) = 22 % 10 =2 2. 84 % 10 = 4

3.H(35)=35%10=5 4. H(62)=62%10=2
Advantages
1. More number of elements can be inserted using array of Link List
Disadvantages
1. It requires more pointers, which occupies more memory space.
2.Search takes time. Since it takes time to evaluate Hash Function and also to traverse the
List
Open Addressing
Closed Hashing
Collision resolution technique
Uses Hi(X)=(Hash(X)+F(i))mod Tablesize
When collision occurs, alternative cells are tried until empty cells are found.
Types:-
 Linear Probing
 Quadratic Probing
 Double Hashing
Hash function
 H(key) = key % table size.
Insert Operation
 To insert a key; Use the hash function to identify the list to which the
element should be inserted.
 Then traverse the list to check whether the element is already present.
 If exists, increment the count.
 Else the new element is placed at the front of the list.
Linear Probing:
Easiest method to handle collision.
Apply the hash function H (key) = key % table size
Hi(X)=(Hash(X)+F(i))mod Tablesize,where F(i)=i.
How to Probing:
first probe – given a key k, hash to H(key)
second probe – if H(key)+f(1) is occupied, try H(key)+f(2)
And so forth.
Probing Properties:
We force f(0)=0
The ith probe is to (H (key) +f (i)) %table size.
If i reach size-1, the probe has failed.
Depending on f (i), the probe may fail sooner.
Long sequences of probe are costly.
Probe Sequence is:
H (key) % table size
H (key)+1 % Table size
H (Key)+2 % Table size
1. H(Key)=Key mod Tablesize
This is the common formula that you should apply for any hashing
If collocation occurs use Formula 2
2. H(Key)=(H(key)+i) Tablesize
Where i=1, 2, 3, …… etc
Example: - 89 18 49 58 69; Tablesize=10
1. H(89) =89%10
=9
2. H(18) =18%10
=8
3. H(49) =49%10
=9 ((coloids with 89.So try for next free cell using formula 2))
i=1 h1(49) = (H(49)+1)%10
= (9+1)%10
=10%10
=0
4. H(58) =58%10
=8 ((colloids with 18))
i=1 h1(58) = (H(58) +1)%10
= (8+1) %10
=9%10
=9 =>Again collision
i=2 h2(58) =(H(58)+2)%10
=(8+2)%10
=10%10
=0 =>Again collision
EMPTY 89 18 49 58 69
0 49 49 49
1 58 58
2 69
3
4
5
6
7
8 18 18 18
9 89 89 89 89

Linear probing

Quadratic Probing
To resolve the primary clustering problem, quadratic probing can be used. With quadratic
probing, rather than always moving one spot, move i2 spots from the point of collision, where
i is the number of attempts to resolve the collision.
Another collision resolution method which distributes items more evenly.
From the original index H, if the slot is filled, try cells H+12, H+22, H+32,.., H + i2 with
wrap-around.
Hi(X)=(Hash(X)+F(i))mod Tablesize,F(i)=i2
Hi(X)=(Hash(X)+ i2)mod Tablesize

Limitation: at most half of the table can be used as alternative locations to resolve collisions.
This means that once the table is more than half full, it's difficult to find an empty spot. This
new problem is known as secondary clustering because elements that hash to the same hash
key will always probe the same alternative cells.
Double Hashing
Double hashing uses the idea of applying a second hash function to the key when a
collision occurs. The result of the second hash function will be the number of positions forms
the point of collision to insert.
There are a couple of requirements for the second function:
It must never evaluate to 0 must make sure that all cells can be probed.
Hi(X)=(Hash(X)+i*Hash2(X))mod Tablesize
A popular second hash function is:
Hash2 (key) = R - (key % R) where R is a prime number that is smaller than the size of the
table.
Rehashing
Once the hash table gets too full, the running time for operations will start to take too
long and may fail. To solve this problem, a table at least twice the size of the original will be
built and the elements will be transferred to the new table.
Advantage:
A programmer doesn‟t worry about table system.
Simple to implement
Can be used in other data structure as well
The new size of the hash table:
should also be prime
will be used to calculate the new insertion spot (hence the name rehashing)
This is a very expensive operation! O(N) since there are N elements to rehash and the
table size is roughly 2N. This is ok though since it doesn't happen that often.
The question becomes when should the rehashing be applied?
Some possible answers:
once the table becomes half full
once an insertion fails
once a specific load factor has been reached, where load factor is the ratio of the
number of elements in the hash table to the table size
Extendible Hashing
Extendible Hashing is a mechanism for altering the size of the hash table to accommodate
new entries when buckets overflow.
Common strategy in internal hashing is to double the hash table and rehash each entry.
However, this technique is slow, because writing all pages to disk is too expensive.
Therefore, instead of doubling the whole hash table, we use a directory of pointers to
buckets, and double the number of buckets by doubling the directory, splitting just the
bucket that overflows.
Since the directory is much smaller than the file, doubling it is much cheaper. Only one
page of keys and pointers is split.
000 100 0 1
010 100
100 000
111 000
001 000 000 100 100 000
011 000 010 100
101 000 111 000
001 000
111 001 011 000 101 000
001 010
101 100 111 001
101 110 00 01 10 11

000 100 100 000


010 100 111 000
001 000 101 000
011 000 111 001
001 010 101 100
001 011 101 110
www.padeepz.net 1

You might also like