0% found this document useful (0 votes)
25 views185 pages

Material

Uploaded by

karen
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)
25 views185 pages

Material

Uploaded by

karen
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/ 185

16CS3202 - Data Structures II Yr CSE / III Sem

UNIT I
LINEAR STRUCTURES
1.1 Abstract Data Types (ADT)
1.2 List ADT
1.3 Array-based implementation
1.4 Linked list implementation
1.5 Doubly-linked lists
1.6 Cursor-based linked lists
1.7 Applications of lists

INTRODUCTION
• A DATA is a collection of facts, concepts, figures, observation, occurrences or instruction in
formalized manner.
• If we arrange some data in an appropriate sequence, then it forms a Structure and gives us a
meaning. This meaning is called Information (i.e, processed data)
• So, we found two things in Information: One is Data and the other is Structure.
DATA STRUCTURE
A data structure is a systematic way of organizing, storing, manipulating and accessing data in
such a way that some meaningful operations can be performed on these data in an effective way.
Applications of data structures
• Compiler design
• Operating System
• Database Management system
• Network analysis
• Expert Systems
CLASSIFICATION OF DATA STRUCTURE

Classification Description Example

Primitive The primitive data structures are known as basic data Integer, Float, Character, Pointer,
data structures. Boolean, String
structure These data structures are directly operated by the
machine instructions.
Normally, primitive data structures have different
representation on different computers.

UNIT 1 Page 1
16CS3202 - Data Structures II Yr CSE / III Sem

Non- The non-primitive data structures are highly Arrays, Lists, Files
Primitive developed complex data structures.
data Basically, these are developed from the primitive
structure data structure.
The non-primitive data structure is responsible for
organizing the group of homogeneous and
heterogeneous data elements.
A non primitive data structure is further divided into
linear and non linear data structure.

Linear Data In Linear data structures, the data items are arranged Array, Linked List, Stack, Queue
Structure in a linear sequence.
Data elements in a liner data structure are traversed
one after the other and only one element can be
directly reached while traversing.

Non Linear The data structure where data items are not Trees, Graphs
Data organized sequentially is called non linear data
Structure structure.
The data elements of the non linear data structure
could be connected to more than one element to
reflect a special relationship among them.

Figure 1 Classification of Data Structure


Difference Between Linear and Non Linear Data Structure

Linear Data Structure Non-Linear Data Structure

Every item is related to its previous and next item. Every item is attached with many other items.

Data is arranged in linear sequence. Data is not arranged in sequence.

UNIT 1 Page 2
16CS3202 - Data Structures II Yr CSE / III Sem

Data items can be traversed in a single run. Data cannot be traversed in a single run.

Examples: Array, Stack, Queue, Linked List. Examples: Tree, Graph.

Implementation is Easy. Implementation is Difficult.

1.1 ABSTRACT DATA TYPE


Abstract Data Types (ADT) is a mathematical model together with the possible set of operations.
E.g. List ADT, Tree ADT, Stack ADT, Set ADT and so on.
• 'Abstract ' implies that we give an implementation-independent view of the data structure
• ADTs specify the type of data stored and the operations that support the data.
• The basic idea of implementing ADT is that the operations are written once in program and can be
called by any part of the program.
• Objects such as list, set and graph along with their operations can be viewed as ADT's
• For example in list ADT we have the operations such as insert, delete, and find, count and so on.
• In the Set ADT, the operations are Union, Intersection, size, complement and so on.

1.2 LIST ADT


List is an ordered set of elements. The general form of the list is A1, A2, A3, ..... ,AN
A1 - First element of the list
AN - Last 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.
The set of operations that can be performed on the list ADT are
 Insert (X, 5) - Insert the element X after the position 5.
 Delete (X) - The element X is deleted
 Find (X) - Returns the position of X.
 Next (i) - Returns the position of its successor element i+1.
 Previous (i) - Returns the position of its predecessor i-1.
 Print list - Contents of the list is displayed.
 Makeempty - Makes the list empty.
Example:
If the list is 34, 12, 52, 16, 12, then find(52) might return 3.
insert(x,3) might make the list into 34, 12, 52, x, 16,12 (if we insert after the position given); and delete(3)
might turn that list into 34, 12, x, 16, 12.
UNIT 1 Page 3
16CS3202 - Data Structures II Yr CSE / III Sem

Implementation of List ADT:


The list can be implemented in three different ways.
1. Array based Implementation
2. Linked List Implementation
3. Cursor Based Implementation.

1.3. ARRAY BASED IMPLEMENTATION


Array is a collection of same set of elements stored in consecutive memory locations.
Example:
A linear array A[8] consisting of numbers is pictured in following figure.

Figure 2 Array Representation


All the list operation can be implemented by using the array. The list implementation using array has some
merits and demerits in it as follows:
• Insertion and Deletion operation are expensive as it requires more data movement
• Find and Printlist operations takes constant time.
• Even if the array is dynamically allocated, an estimate of the maximum size of the list is required
which considerably wastes the memory space.
Types of Array
The types of array are:
• One dimensional array
• Two dimensional array
• Multidimensional array
One Dimensional array
Syntax:
datatype array_name[array_size];
Two Dimensional array
Syntax:
Datatype array_name[row_size][column_size];

ARRAY IMPLEMENTATION OF LIST ABSTRACT DATA TYPE

UNIT 1 Page 4
16CS3202 - Data Structures II Yr CSE / III Sem

/*PROGRAM FOR ARRAY IMPLEMENTATION OF LIST ADT*/


#include<iostream.h>
#include<conio.h>
#define MAX 5
class Arraylist
{
private:
int list[MAX];
int pos;
public:
Arraylist();
void insert();
void del();
void display();
void search();
int isempty();
int isfull();
};
Arraylist::Arraylist()
{
pos=0;
}
void Arraylist::insert()
{
int num,p,i;
if(isfull())
{
cout<<"List is Full Cannot insert\n";
}
else
{
cout<<"Enter the element to insert:";
cin>>num;

UNIT 1 Page 5
16CS3202 - Data Structures II Yr CSE / III Sem

if(isempty())/* if empty list create list*/


{
list[pos]=num;
pos++;
}
else
{
cout<<"Enter the position to insert:";
cin>>p;
if(p-1>pos)
{
cout<<"Position incorrect cannot insert\n";
}
else if(p-1==pos)/*insert at end of list*/
{
list[pos]=num;
pos++;
}
else /*insert at header or middle of list*/
{
for(i=pos;i>p-1;i--)
{
list[i]=list[i-1];
}
list[p-1]=num;
pos++;
}
}
}
display();
}
void Arraylist::del()
{

UNIT 1 Page 6
16CS3202 - Data Structures II Yr CSE / III Sem

int p,i;
if(isempty())
{
cout<<"List is Empty Cannot delete\n";
}
else
{
cout<<"Enter the position to delete:";
cin>>p;
if(p-1>=pos)
{
cout<<"Position incorrect cannot delete\n";
}
else
{
cout<<"Element deleted at position "<<p<<" is "<<list[p-1]<<"\n";
if(p-1==pos-1)
{
pos--;
}
else
{
for(i=p-1;i<pos-1;i++)
{
list[i]=list[i+1];
}
pos--;
}
}
}
display();
}
void Arraylist::display()

UNIT 1 Page 7
16CS3202 - Data Structures II Yr CSE / III Sem

{
int i;
if(isempty())
{
cout<<"List is Empty \n";
}
else
{
cout<<"List Elements are\n";
for(i=0;i<pos;i++)
{
cout<<list[i]<<" ";
}
}
cout<<"\n";
}
int Arraylist::isempty()
{
if(pos==0)
return 1;
else
return 0;
}
int Arraylist::isfull()
{
if(pos==MAX)
return 1;
else
return 0;
}
void Arraylist::search()
{
int data,i;

UNIT 1 Page 8
16CS3202 - Data Structures II Yr CSE / III Sem

int check=0;/*to find an item exist or not*/


if(isempty())
{
cout<<"List is Empty cannot find element\n";
}
else
{
cout<<"Enter the element to search:";
cin>>data;
for(i=0;i<pos;i++)
{
if(list[i]==data)
{
cout<<"Element found at "<<i+1<<" position\n";
check=1;
break;
}
}
if(check==0)
{
cout<<"Element not found\n";
}

}
}
int main()
{
int choice;/*to select multiple menu choices*/
clrscr();
Arraylist obj;
do
{
cout<<"*******MENU*******\n1.Insert\n2.Delete\n3.Display\n4.Search\nEnter your Choice:";

UNIT 1 Page 9
16CS3202 - Data Structures II Yr CSE / III Sem

cin>>choice;
switch(choice)
{
case 1:
obj.insert();
break;
case 2:
obj.del();
break;
case 3:
obj.display();
break;
case 4:
obj.search();
break;
default:
cout<<"wrong choice \n";
}
}while(choice<5);
getch();
return 0;
}
OUTPUT:
*******MENU*******
1.Insert
2.Delete
3.Display
4.Search
Enter your Choice:1
Enter the element to insert:10
List Elements are
10
*******MENU*******

UNIT 1 Page 10
16CS3202 - Data Structures II Yr CSE / III Sem

1.Insert
2.Delete
3.Display
4.Search
Enter your Choice:1
Enter the element to insert:20
Enter the position to insert:2
List Elements are
10 20
*******MENU*******
1.Insert
2.Delete
3.Display
4.Search
Enter your Choice:1
Enter the element to insert:30
Enter the position to insert:1
List Elements are
30 10 20
*******MENU*******
1.Insert
2.Delete
3.Display
4.Search
Enter your Choice:1
Enter the element to insert:40
Enter the position to insert:2
List Elements are
30 40 10 20

1.4 LINKED LIST IMPLEMENTATION


The linked list consists of series of nodes, which are not necessarily adjacent in memory. Each
node contains the element and a pointer to its successor (next) node. The pointer of the last node points
to NULL. Insertion and deletion operations are easily performed using linked list.

UNIT 1 Page 11
16CS3202 - Data Structures II Yr CSE / III Sem

Types of Linked List


1. Singly Linked List
2. Doubly Linked List
3. Circular Linked List.
Basic operations
The basic operations supported by a list are:
• Insertion
➢ Elements can be added either at the beginning, or as a middle element or as the last
element.
• Deletion
➢ Elements can be deleted at the beginning, or from the middle or the last element.
• Display
➢ Display the entire list of elements.
• Search
➢ Search the entire list using the given key element.

1.4.1 SIMPLE LINKED LIST (or) SINGLY LINKED LIST


Simple linked list can be visualized as a chain of nodes, where every node points to the next node.
If a linked list contains the elements a1, a2, a3, a4 and a5, then the representation is shown in figure 3.

Figure 3 Linked list


Figure 4 shows the actual representation of the list in Figure 3. The list contains five structures, which
happen to reside in memory locations 1000, 800,712, 992, and 692 respectively.

Figure 4 Linked list with actual pointer values


The next pointer in the first structure has the value 800, which provides the indication of where the second
structure is.
The other structures each have a pointer that serves a similar purpose. Of course, inorder to access this list,
we need to know where the first cell can be found. A pointer variable can be used for this purpose which
is called as head or first.
Basic operations in Simple linked list
The basic operations in a simple linked list are:
1. Create

UNIT 1 Page 12
16CS3202 - Data Structures II Yr CSE / III Sem

2. Insert
3. Delete
4. Display
1. Create
The linked list structure will be
struct NODE
{
int data;
NODE *next;
};
NODE *first,*last,*curr,*temp;
Create function will create a node initially as per the structure definition and get the data from the
user and store it in the ‘data’ field and place the ‘NULL’ in the next field. If the node created is the first
element then the first and last pointer is assigned to the node created. If the list contains elements then the
temporary pointer is moved to the last element and link with newly created node.
The codes to create the singly linked list are as follows:
curr=new node();
cout<<”Enter the element”;
cin>>curr→data;
curr→next=NULL;
if(first==NULL && last==NULL)
{
fisrt=curr;
last=curr;
temp=curr;
}
else
{
temp→next=curr;
temp=curr;
last=curr;
}
Example:
Assume the list created using the above code contains 5 elements as shown in figure 5.

UNIT 1 Page 13
16CS3202 - Data Structures II Yr CSE / III Sem

Figure 5 Singly linked list after creation


2. Insert
In a singly linked list, the insertion operation can be performed in three ways. They are as follows:
1. Inserting At Beginning of the list
2. Inserting At End of the list
3. Inserting At Specific location in the list

Inserting At Beginning of the list


The steps to insert a new node at beginning of the single linked list are:
Step 1: Create a new node with given value.
Step 2: Set curr→next = first and first = curr.
The C++ code to insert at the beginning of a list is:
curr=new node();
cout<<"Enter the data for the newnode";
cin>>curr->data;
curr->next=first;
first=curr;
Example:
Assume the list contains 5 elements and the new element 5 is inserted at the beginning of a list.

Figure 6 After inserting element 5 at the beginning


Inserting At End of the list
The steps to insert a new node at end of the singly linked list are
Step 1:Keep moving the temp to its next node until it reaches to the last node in the list (until temp → next
is equal to NULL).

UNIT 1 Page 14
16CS3202 - Data Structures II Yr CSE / III Sem

Step 2: Create a new node with given value and curr → next as NULL.
Step 3: Set temp → next = curr and last=curr.
The codes to insert at the end of a list are as follows:
while(temp->next!=NULL)
temp=temp->next;
curr=new node();
cout<<"\nEnter the data for the newnode";
cin>>curr->data;
curr->next=NULL;
temp->next=curr;
last=curr;
Example:
Assume the list contains 6 elements and the new element 60 is inserted at the last of a list.

Figure 7 After inserting element 60 at last


Inserting At Specific location in the list (After a Node)
The steps to insert a new node after a node in the single linked list are
Step 1: Keep moving the temp to its next node until it reaches to the node after which we want to insert
the newNode (until temp → data is equal to the key value).
Step 2: Create a newode with given value.
Step 3: Set ‘curr → next = temp → next' and 'temp → next = curr'
The codes to insert at the specific location of a list are as follows:
cout<<"\nEnter the key data";
cin>>n;
while(temp->data!=n)
{
temp=temp->next;
}
curr=new node();
cout<<"\nEnter the data for the newnode";

UNIT 1 Page 15
16CS3202 - Data Structures II Yr CSE / III Sem

cin>>curr->data;
curr->next=temp->next;
temp->next=curr;
Example:
Assume the list contains 6 elements and the new element 35 is inserted after the element 30 in a list.

Figure 8 After inserting element 35 after element 30


3. Delete
In a singly linked list, the deletion operation can be performed in three ways. They are as follows:
1. Deleting from Beginning of the list
2. Deleting from End of the list
3. Deleting a Specific Node
Deleting from Beginning of the list
The steps to delete a node from beginning of the single linked list are:
Step 1: Define a Node pointer 'temp' and initialize with first.
Step 2: Check whether list is having only one node (temp → next == NULL) and if it is TRUE then set
first = NULL and delete temp (Setting Empty list conditions)
Step 3: If it is FALSE then set first = temp → next, and delete temp.
The codes to delete from the beginning of a list are as follows:
if(temp==first)
{
first=temp->next;
cout<<”\nDeleted node”<<temp->data;
free(temp);
}
Example:
Assume the list contains 7 elements and the first element 5 is deleted in a list.

UNIT 1 Page 16
16CS3202 - Data Structures II Yr CSE / III Sem

Figure 9 Singly linked list after deleting the first element


Deleting from End of the list and at the specific position
The steps to delete a node from end of the singly linked list are
Step 1:Define two Node pointers 'prev' and 'temp' and initialize 'temp' with first.
Step 2: Check whether list has only one Node (temp →data == key data)
Step 3: If it is TRUE, then set first = NULL and delete temp. And terminate the function. (Setting Empty
list condition)
Step 4: If it is FALSE, then set 'prev = temp ' and move temp to its next node. Repeat the same until it
reaches to the last node in the list. (until temp == NULL)
Step 5: Finally, Set prev → next = NULL and delete temp.
The codes to delete from the beginning of a list are as follows:
temp=first;
while(temp!=NULL)
{
if(temp->data==num)
{
break;
}
else
{
prev=temp;
temp= temp->next;
}
}
if(temp==first)
{
first=NULL;
cout<<”\nDeleted node”<<temp->data;
free(temp);

UNIT 1 Page 17
16CS3202 - Data Structures II Yr CSE / III Sem

}
else
{
prev->next=temp->next;
cout<<”\nDeleted node”<<temp->data;
free(temp);
}
Example:
Assume the list contains 6 elements and the element 60 is deleted in a list.

Figure 10 Singly linked list after deleting last element


4. Display
The steps to display the elements of a single linked list are:
Step 1: Check whether list is Empty (first == NULL)
Step 2: If it is Empty then, display 'List is Empty!!!' and terminate the function.
Step 3: If it is Not Empty then, define a Node pointer 'temp' and initialize with first.
Step 4: Keep displaying temp → data with an arrow (--->) until temp reaches to the last node
Step 5: Finally display temp → data with arrow pointing to NULL (temp → data ---> NULL).
The codes to display the list are as follows:
if(first==NULL)
{
cout<< “'List is Empty!!!”;
}
else
{
temp=first;
while(temp!=NULL)
{
cout<< temp->data << “→”;

UNIT 1 Page 18
16CS3202 - Data Structures II Yr CSE / III Sem

temp = temp → next;


}
cout<< “NULL”;
}
Comparison between array and linked list are summarized in following table
Characteristic ARRAY LINKED LIST
Linked list is an ordered collection of
Array is a collection of elements having
Define elements which are connected by
same data type with common name.
links/pointers.
In array, elements can be accessed using
index/subscript value, i.e. elements can In linked list, elements can’t be accessed
Access be randomly accessed like arr[0], arr[3], randomly but can be accessed
etc. So array provides fast and random only sequentially.
access.
In linked list, elements can be stored at any
Memory In array, elements are stored
available place as address of node is stored
Structure in consecutive manner in memory.
in previous node.
Insertion & deletion takes more time in Insertion & deletion are fast & easy in
Insertion &
array as elements are stored in linked list as only value of pointer is needed
Deletion
consecutive memory locations. to change.
Memory In array, memory is allocated at compile In linked list, memory is allocated at run
Allocation time i.e. Static Memory Allocation. time i.e. Dynamic Memory Allocation.
Array can be single dimensional, two Linked list can
Types
dimension or multidimensional. be singly, doubly or circular linked list.
In array, each element is independent, no In Linked list, location or address of
Dependency connection with previous element or with elements is stored in the link part of
its location. previous element/node.
In linked list, adjacency between the
In array, no pointers are used like linked
elements are maintained using pointers or
Extra Space list so no need of extra space in memory
links, so pointers are used and for that extra
for pointer.
memory space is needed.

Figure

UNIT 1 Page 19
16CS3202 - Data Structures II Yr CSE / III Sem

1.5 DOUBLY LINKED LIST


A doubly linked list is a list that contains links to next and previous nodes. Unlike singly linked
lists where traversal is only one way, doubly linked lists allow traversals in both ways. Following are the
important terms to understand the concept of doubly linked list.
• data − Each data of a linked list can store a data called an element.
• next − Each link of a linked list contains a link to the next node called next.
• prev − Each link of a linked list contains a link to the previous node called prev.
Advantage:
* Deletion operation is easier.
* Finding the predecessor & Successor of a node is easier.
Disadvantage:
* More Memory Space is required since it has two pointers.

A generic doubly linked list node can be designed as:


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

If a doubly linked list contains the elements a1, a2, a3, a4 and a5, then the representation is shown in
figure 11 .

Figure 11 A Doubly linked list

Figure 12 shows the actual representation of the list. The list contains four structures, which happen to
reside in memory locations 1000, 800,712, 992 respectively.

Figure 12 Doubly Linked list with actual pointer values

UNIT 1 Page 20
16CS3202 - Data Structures II Yr CSE / III Sem

Basic operations in Doubly linked list


The basic operations in a doubly linked list are:
1. Create
2. Insert
3. Delete
4. Display
1. Create
The create operation will create new list of elements by using the structure definition.
Step 1: Define a new node by using the structure node.
Step 2: If the first pointer is NULL, then assign the new node to first to indicate the node as first element
in a list.
Step 3: Else, keep moving the temporary pointer ‘temp’ to the last node in the list and link with the newly
created node.
The code used to create a doubly linked list is as follows:
void double_llist::create_list(int value)
{
node *first,*temp;
curr = new node;
curr->data = value;
curr->next = NULL;
if (first == NULL)
{
curr->prev = NULL;
first = curr;
}
else
{
temp = first;
while (temp->next != NULL)
temp = temp->next;
temp->next = curr;
curr->prev = temp;
last=curr;
}

UNIT 1 Page 21
16CS3202 - Data Structures II Yr CSE / III Sem

2. Insertion
There are three situation for inserting element in list.
1. Inserting At Beginning of the list
2. Inserting At End of the list
3. Inserting At Specific location in the list
Insertion at the front of a list
The steps to insert a new element at the front of a list are:
Step 1: Check whether the list is empty. If it is TRUE, then print to create a new list.
Step 2: If it if FALSE, then define a new pointer ‘temp’ and assign to first element.
Step 3: Create a new node with the definition of structure node and assign the value to curr->data and
NULL to curr->prev.
Step 4: Assign curr->next to ‘temp’ to connect the element.
Step 5: Also assign the temp->prev to curr in order to link the previous node and make the curr node to
first.
The code used to insert a new element at the beginning of doubly linked list is as follows:
void double_llist::add_begin(int value)
{
if (first == NULL)
{
cout<<"First Create the list."<<endl;
return;
}
temp=first;
node *curr;
curr = newnode;
curr->prev = NULL;
curr->data = value;
curr->next = temp;
temp->prev = curr;
first=curr;
cout<<"Element Inserted"<<endl;
}

UNIT 1 Page 22
16CS3202 - Data Structures II Yr CSE / III Sem

Example:
The doubly linked list after inserting the element 10 at the beginning is as follows:

Figure 13 Doubly Linked listafter inserting the element at the beginning


Insertion at a particular position of a list
The steps to insert a new element at the front of a list are:
Step 1: Check whether the list is empty. If it is TRUE, then print to create a new list.
Step 2: If it if FALSE, define a temporary pointer ‘temp’ and assign to first pointer.
Step 3: Keep moving the temp pointer until the required position is reached by using temp->temp->next.
Step 4: Create a new node using the structure definition and assign the value to data.
Step 5: If the temp reached the position, check whether the temp->next is equal to NULL. If it is
TRUE, then assign temp-> next to curr and curr->prev to temp. Also assign curr->next as NULL to
indicate that node as a last node.
Step 6: If it is FALSE, then assign the address stored in temp->next to curr->next to connect in chain.
Step 7: To make the chain as a doubly linked list, assign the temp->next->prev to curr and curr->prev to
temp.
The code used to insert any new element at any position of a doubly linked list is as follows:
void double_llist::add_after(int value, intpos)
{
if (first == NULL)
{
cout<<"First Create the list."<<endl;
return;
}
node *temp;
int i;
temp = first;
for (i = 1;i < pos;i++)

UNIT 1 Page 23
16CS3202 - Data Structures II Yr CSE / III Sem

{
temp = temp->next;
}
curr = newnode;
curr->data = value;
if (temp->next == NULL) /*Insert at Last position*/
{
temp->next = curr;
curr->next = NULL;
curr->prev = temp;
}
else /*Insert at middle of the list*/
{
curr->next = temp->next;
curr->prev = temp;
curr->next->prev = curr;
temp->next = curr;
}
cout<<"Element Inserted"<<endl;
}
Example:
The new element 30 inserted after the element 30 is shown below:

Figure 14 Doubly Linked list after inserting the element at the position

The element 50 inserted at the last of a doubly linked list is shown below:

UNIT 1 Page 24
16CS3202 - Data Structures II Yr CSE / III Sem

Figure 15 Doubly Linked list after inserting the element at the last

3. Deletion
Similar to the insertion, the deletion operation in a doubly linked list is performed in three ways:
1. Delete from the beginning
2. Delete at the middle
3. Delete at the last
Steps to follow for deletion operation
Step1: If the given key element matches with the first element, then assign a temporary pointer ‘temp’to
first and NULL to first->prev to indicate no element previous. Then deallocate the memory used by temp.
Step 2: Else, keep moving the temp pointer until it reaches the node previous to the required position.
Step 3: Define another temporary pointer variable ‘temp1’and assign to the matched element node.
Step 4: Before deleting the temp1 node, link the temp node and to the node next to temp1.
Step 5: Deallocate the memory used by temp1.
Step 6: If both the conditions in step 1 & 2 fails, then the element to be deleted is the last node. Assign
NULL to the next of previous node and deallocate the memory.
The code used to perform the deletion operation in a doubly linked list is as follows:
void double_llist::delete_element(int value)
{
node *temp, *q;
if (first->data == value) /*first element deletion*/
{
temp = first;
first = temp->next;
first->prev = NULL;
cout<<"Element Deleted"<<endl;

UNIT 1 Page 25
16CS3202 - Data Structures II Yr CSE / III Sem

free(tmp);
return;
}
temp = first;
while (temp->next->next != NULL)
{
if (temp->next->data == value) /*Element deleted in between*/
{
temp1 = temp->next;
temp->next = temp1->next;
temp1->next->prev = temp;
cout<<"Element Deleted"<<endl;
free(tmp1);
return;
}
temp= temp->next;
}
if (temp->next->data == value) /*last element deleted*/
{
temp1= temp->next;
free(temp1);
temp->next = NULL;
cout<<"Element Deleted"<<endl;
return;
}
}

Example:
Assume the doubly linked list contains the 4 elements after the create operation as shown below:

UNIT 1 Page 26
16CS3202 - Data Structures II Yr CSE / III Sem

Figure 16 Doubly Linked list with 4 elements


The list after deleting the first element 10 is as follows:

Figure 17 Doubly Linked list after deleting the element from the beginning
The list after deleting the middle element 30 is as follows:

Figure 18 Doubly Linked list after deleting the element from the middle
4. Display
The display function is used to display the element present in the list from first to last using the next
pointer and from last to first using prev pointer.
The code used to display the list of elements in a doubly linked list is as follows:
void display()
{
temp=first;
//Display the elements from first to last
cout << “First to Last\n”;
cout<<”NULL”;
for(temp=first;temp!=NULL;temp=temp->next)
cout<<”<-“<<temp->data << ”->”;
cout>>”NULL\n”;

UNIT 1 Page 27
16CS3202 - Data Structures II Yr CSE / III Sem

//Display the elements from last to first


cout << “Last to First\n”;
for(temp=last;temp!=NULL;temp=temp->prev)
cout<<”<-“<<temp->data << ”->”;
cout<<”NULL”;

1.4.2 CIRCULAR LINKED LIST


In the circular linked list the previous element stores the address of the next element and the last
element stores the address of the starting element. The elements points to each other in a circular way
which forms a circular chain. Circular linked list can be implemented as Circular Singly linked list and
Circular Doubly linked list.
1. 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.
If a linked list contains the elements a1, a2, a3, a4 and a5, then the representation is shown in figure 19.

Figure 19 Circular Singly linked list

Figure 20 shows the actual representation of the circular doubly link list in memory. The list contains five
nodes, which happen to reside in memory locations 1000, 800,712, 992, and 692 respectively.

Figure 20 Circular Singly Linked list with actual pointer values


The next pointer in the first node has the value 800, which provides the indication of where the second
node is. The next pointer in the last element has the value of 1000, shows the circular chained list.

2. Doubly Linked Circular List


A doubly linked circular list is a Doubly linked list in which the forward link of the last node points to the
first node and backward link of the first node points to the last node of the list as shown in the figure 21.

UNIT 1 Page 28
16CS3202 - Data Structures II Yr CSE / III Sem

Figure 21 Circular Doubly linked list


Figure 22 shows the actual representation of the doubly circular link list in memory. The list contains
three nodes with elements 10, 15 and 20, which happen to reside in memory locations 1000, 2000, and
3000 respectively.

Figure 22 Circular Doubly Linked list with actual pointer values

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.

1.6 CURSOR-BASED LINKED LISTS


If linked lists are required and pointers are not available, then an alternate implementation must be
used. The alternate method we will describe is known as a cursor implementation.
The two important items present in a pointer implementation of linked lists are
1. The data is stored in a collection of structures. Each structure contains the data and a pointer to the
next structure.
2. A new structure can be obtained from the system's global memory by a call to malloc and released
by a call to free.
Cursor implementations satisfy condition 1 by a global array of structures. For any cell in the array, its
array index can be used in place of an address.
It satisfies the condition 2 by allowing the equivalent of malloc, new and free for cells in the
CURSOR_SPACE array. To do this, a list of cells that are not in any list is noted. The list will use cell 0
as a header. The initial configuration is shown in Figure 23.

UNIT 1 Page 29
16CS3202 - Data Structures II Yr CSE / III Sem

Figure 23 An initialized CURSOR_SPACE


Declaration for cursor implementation of linked list
typedef int node_ptr;
struct node
{
element_type element;
node_ptr next;
};
typedef node_ptr LIST;
typedef node_ptr position;
struct node CURSOR_SPACE[ SPACE_SIZE ];

Routines used for cursor-alloc and cursor-free


position cursor_alloc( void )
{
position p;
p = CURSOR_SPACE[O].next;
CURSOR_SPACE[0].next = CURSOR_SPACE[p].next;
return p;
}
void cursor_free( position p)
{
CURSOR_SPACE[p].next = CURSOR_SPACE[0].next;

UNIT 1 Page 30
16CS3202 - Data Structures II Yr CSE / III Sem

CURSOR_SPACE[0].next = p;
}
Deletion routine for linked lists--cursor implementation
void delete( element_type x, LIST L )
{
position p, tmp_cell;
p = find_previous( x, L );
if( !is_last( p, L) )
{
tmp_cell = CURSOR_SPACE[p].next;
CURSOR_SPACE[p].next = CURSOR_SPACE[tmp_cell].next;
cursor_free( tmp_cell );
}
}

Figure 24 Example of a cursor implementation of linked lists

Insertion routine for linked lists--cursor implementation


/* Insert (after legal position p); */
/* header implementation assumed */
void insert( element_type x, LIST L, position p )
{
position tmp_cell;
tmp_cell = cursor_alloc( )
if( tmp_cell ==0 )
UNIT 1 Page 31
16CS3202 - Data Structures II Yr CSE / III Sem

fatal_error("Out of space!!!");
else
{
CURSOR_SPACE[tmp_cell].element = x;
CURSOR_SPACE[tmp_cell].next = CURSOR_SPACE[p].next;
CURSOR_SPACE[p].next = tmp_cell;
}
}

1.7 APPLICATIONS OF LINKED LIST


Various applications of linked list are:
• Stack
• Queue
• Priority Queue
• Sparse matrix
• Polynomial ADT
• Radix Sort
• Multi list
1.7.1 POLYNOMIAL ADT
We can perform the polynomial manipulations such as addition, subtraction and differentiation etc
using linked list.
One of the most important application of Linked List is representation of a polynomial in
memory. Although, polynomial can be represented using a linear linked list but common and
preferred way of representing polynomial is using circular linked list with a header node.

Polynomial Representation: Header linked list are frequently used for maintaining polynomials in
memory. The header node plays an important part in this representation since it is needed to
represent the zero polynomial.
Specifically, the information part of node is divided into two fields representing respectively, the
coefficient and the exponent of corresponding polynomial term and nodes are linked according to
decreasing degree. List pointer variable POLY points to header node whose exponent field is
assigned a negative number, in this case -1. The array representation of List will require three
linear arrays as COEFF, EXP and LINK
Example 1:
Input:
1st number = 5x^2 + 4x^1 + 2x^0

UNIT 1 Page 32
16CS3202 - Data Structures II Yr CSE / III Sem

2nd number = 5x^1 + 5x^0


Output:
5x^2 + 9x^1 + 7x^0

Example2:
Input:
1st number = 5x^3 + 4x^2 + 2x^0
2nd number = 5x^1 + 5x^0
Output:
5x^3 + 4x^2 + 5x^1 + 7x^0

To perform the above polynomial addition using linked list, the structure must be defined as below:

Using the above definition, the polynomial can be added in a linked list as follows:

Figure 18 Polynomial addition using linked list

/*PROGRAM TO REPRESENT POLYNOMIAL ADDITION*/


This program adds the two polynomials implemented using linear linked list and stores the sum in another
linear linked list. POLY1 and POLY2 are the two variables that point to the starting nodes of the two
polynomials.

#include<iostream>

UNIT 1 Page 33
16CS3202 - Data Structures II Yr CSE / III Sem

using namespace std;


// Node structure containing power and coefficient of variable
struct Node
{
int coeff;
int pow;
Node *next;
};
// Function to create new node
Node* create_node(int x, int y, Node *head)
{
Node *z = head;
Node *curr = new Node();
curr->coeff = x;
curr->pow = y;
curr->next = NULL;
if(head == NULL)
{
head=curr;
return(head);
}
else
{
while(z->next!=NULL)
{
z=z->next;
}
z->next=curr;
return(head);
}
}
// Function Adding two polynomial numbers
void polyadd(Node *poly1, Node *poly2, Node *p)

UNIT 1 Page 34
16CS3202 - Data Structures II Yr CSE / III Sem

{
Node *last=p;
while(poly1!=NULL && poly2!=NULL)
{
// If power of 1st polynomial is greater then 2nd, then store 1st as it is and move its pointer
if(poly1->pow > poly2->pow)
{
p->pow = poly1->pow;
p->coeff = poly1->coeff;
poly1 = poly1->next;
}
// If power of 2nd polynomial is greater then 1st, then store 2nd as it is and move its pointer
else if(poly1->pow < poly2->pow)
{
p->pow = poly2->pow;
p->coeff = poly2->coeff;
poly2 = poly2->next;
}
// If power of both polynomial numbers is same then add their coefficients
else
{
p->pow = poly1->pow;
p->coeff = poly1->coeff + poly2->coeff;
poly1 = poly1->next;
poly2 = poly2->next;
}
// Dynamically create new node
p->next = new Node();
last = p;
p = p->next;
p->next = NULL;
}
while(poly1!=NULL|| poly2!=NULL)

UNIT 1 Page 35
16CS3202 - Data Structures II Yr CSE / III Sem

{
if(poly1!=NULL)
{
p->pow = poly1->pow;
p->coeff = poly1->coeff;
poly1 = poly1->next;
}
if(poly2!=NULL)
{
p->pow = poly2->pow;
p->coeff = poly2->coeff;
poly2 = poly2->next;
}
p->next = new Node();
last=p;
p = p->next;
p->next = NULL;
}
last->next=NULL;
}
// Display Linked list
void show(Node *node)
{
while(node!= NULL)
{
cout<< node->coeff <<"^"<< node->pow;
node = node->next;
if(node!= NULL)
cout<<" + ";
}
}
//main program
int main()

UNIT 1 Page 36
16CS3202 - Data Structures II Yr CSE / III Sem

{
Node *poly1 = NULL, *poly2 = NULL;
// Create first list of 5x^2 + 4x^1 + 2x^0
poly1=create_node(5,2,poly1);
poly1=create_node(4,1,poly1);
poly1=create_node(2,0,poly1);
// Create second list of 5x^1 + 5x^0
poly2=create_node(5,1,poly2);
poly2=create_node(5,0,poly2);
cout<<"1st Number: ";
show(poly1);
cout<<"\n2nd Number: ";
show(poly2);
Node *poly;
// Function add two polynomial numbers
polyadd(poly1, poly2, poly);
// Display resultant List
cout<<"\nAdded polynomial: ";
show(poly);
return 0;
}

Output:
1st Number: 5x^2 + 4x^1 + 2x^0
2nd Number: 5x^1 + 5x^0
Added polynomial: 5x^2 + 9x^1 + 7x^0

UNIT 1 Page 37
16CS3202 - Data Structures II Yr CSE / III Sem

Unit-II
STACK AND QUEUES
Syllabus:
2.1 Stack ADT
2.2 Queue ADT
2.3 circular queue implementation
2.4 Applications of stacks
2.5 Applications of queues

2.1 THE STACK ADT

A stack is a list with the restriction that insertions and deletions can be performed in only one position,
namely, the end of the list, called the top. The fundamental operations on a stack are push, which is
equivalent to an insert, and pop, which deletes the most recently inserted element. The most recently
inserted element is available in top position. Stacks are also known as LIFO (last in, first out) lists.

Figure 2.1 Stack and its operations


2.1.1 Implementation of Stacks:
There are two popular stack implementations. Such as,
• Linked List implementation
• Array implementation
When stack is implemented using array, that stack can organize only limited number of elements. When
stack is implemented using linked list, that stack can organize unlimited number of elements.
a) Array implementation of Stack:
A stack data structure can be implemented using one dimensional array, where we can store only fixed
number of data values. This implementation contains one dimensional array of specific size and insert or
delete the values into that array by using LIFO principle with the help of a variable 'top'. Initially top is
set to -1.
Stack Operations using Array:
Whenever we want to delete a value from the stack, then delete the top value and decrement the top
value by one. To create an empty stack, following steps can be used.
Step 1: Include all the header files which are used in the program and define a constant 'SIZE' with
specific value.

UNIT 2 Page 1
16CS3202 - Data Structures II Yr CSE / III Sem

Step 2: Declare all the functions used in stack implementation.


Step 3: Create a one dimensional array with fixed size (int stack[SIZE])
Step 4: Define an integer variable 'top' and initialize with '-1'. (int top = -1)

The codes to create empty stackand various operations on stack are as follows:
#define SIZE 10
int stack[SIZE], top = -1;
void push(int);
void pop();
void display();

(i) Insertion on Stack (Push):


In a stack, push() is a function used to insert an element into the stack. The new element is always
inserted at top position. Push function takes one integer value as parameter and inserts that value into
the stack. We can use the following steps to push an element on to the stack.
Step 1: Check whether stack is FULL. (top == SIZE-1)
Step 2: If it is FULL, then display "Stack is FULL!!! Insertion is not possible!!!" and terminate the
function.
Step 3: If it is NOT FULL, then increment top value by one (top++) and set stack[top] to value
(stack[top] = value).
The codes to insert new element on stack are as follow:
void push(int value){
if(top == SIZE-1)
cout<<"\nStack is Full!!! Insertion is not possible!!!";
else{
top++;
stack[top] = value;
cout<<"\nInsertion success!!!";
}
}

(ii) Deletion on Stack(Pop):


In a stack, pop() is a function used to delete an element from the stack. In a stack, the element is always
deleted from top position. Pop function does not take any value as parameter. We can use the following
steps to pop an element from the stack...
Step 1: Check whether stack is EMPTY. (top == -1)
Step 2: If it is EMPTY, then display "Stack is EMPTY!!! Deletion is not possible!!!" and terminate
the function.
Step 3: If it is NOT EMPTY, then delete stack[top] and decrement top value by one (top- -).
The codes to delete an existing element on stack are as follow:
void pop(){
if(top == -1)
cout<<"\nStack is Empty!!! Deletion is not possible!!!";
else{
cout<<"\nDeleted :"<< stack[top];

UNIT 2 Page 2
16CS3202 - Data Structures II Yr CSE / III Sem

top--;
}
}

(iii) Displays the elements of a Stack


We can use the following steps to display the elements of a stack...
Step 1: Check whether stack is EMPTY. (top == -1)
Step 2: If it is EMPTY, then display "Stack is EMPTY!!!" and terminate the function.
Step 3: If it is NOT EMPTY, then define a variable 'i' and initialize with top. Display stack[i] value
and decrement i value by one (i--).
Step 3: Repeat above step until i value becomes '0'.
The code to display stack elements are as follows:
void display(){
if(top == -1)
cout<<"\nStack is Empty!!!";
else{
int i;
cout<<"\nStack elements are:\n";
for(i=top; i>=0; i--)
cout<<”\n”<<stack[i];
}
}

b) Linked List implementation of Stack:


Stack implemented using array is not suitable, when we don't know the size of data which we are
going to use. A stack data structure can be implemented by using linked list data structure. Stack
implemented using linked list works for variable size of data.
In linked list implementation of a stack, every new element is inserted as 'top' element. That
means every newly inserted element is pointed by 'top'. Whenever we want to remove an element from
the stack, simply remove the node which is pointed by 'top' by moving 'top' to its next node in the list.
The next field of the first element must be always NULL.
Example:

Figure 2.3 Schematic diagram of Stack using linked list

UNIT 2 Page 3
16CS3202 - Data Structures II Yr CSE / III Sem

In above example, the last inserted node is 99 and the first inserted node is 25. The order of elements
inserted is 25, 32,50 and 99.
Operations:
To implement stack using linked list, we need to set the following things before implementing actual
operations.
Step 1: Include all the header files which are used in the program. And declare all the user defined
functions.
Step 2: Define a 'Node' structure with two members such as data and next.
Step 3: Define a Node pointer 'top' and set it to NULL.
The codes to create empty stack are as follows:
struct Node
{
int data;
struct Node *next;
}*top = NULL;
void push(int);
void pop();
void display();

(i) Inserting an element into the Stack(Push):


We can use the following steps to insert a new node into the stack...
Step 1: Create a newNode with given value.
Step 2: Check whether stack is Empty (top == NULL)
Step 3: If it is Empty, then set newNode → next = NULL.
Step 4: If it is Not Empty, then set newNode → next = top.
Step 5: Finally, set top = newNode.
The codes to insert new element on stack are as follows:
void push(int value)
{
struct Node *newNode=new Node();
newNode->data = value;
if(top == NULL)
newNode->next = NULL;
else
newNode->next = top;
top = newNode;
cout<<"\nInsertion is Success!!!\n";
}

(ii) Deleting an Element from a Stack(Pop):


We can use the following steps to delete a node from the stack...
Step 1: Check whether stack is Empty (top == NULL).
Step 2: If it is Empty, then display "Stack is Empty!!! Deletion is not possible!!!" and terminate the
function

UNIT 2 Page 4
16CS3202 - Data Structures II Yr CSE / III Sem

Step 3: If it is Not Empty, then define a Node pointer 'temp' and set it to 'top'.
Step 4: Then set 'top = top → next'.
Step 7: Finally, delete 'temp' (free(temp)).
The codes to delete existing element on stack are as follows:
void pop()
{
if(top == NULL)
cout<<"\nStack is Empty!!!\n";
else{
struct Node *temp = top;
cout<<”\nDeleted element:”<<temp->data;
top = temp->next;
free(temp);
}
}

(iii) Displaying stack elements:


We can use the following steps to display the elements (nodes) of a stack...
Step 1: Check whether stack is Empty (top == NULL).
Step 2: If it is Empty, then display 'Stack is Empty!!!' and terminate the function.
Step 3: If it is Not Empty, then define a Node pointer 'temp' and initialize with top.
Step 4: Display 'temp → data --->' and move it to the next node. Repeat the same until temp reaches to
the first node in the stack (temp → next != NULL).
Step 4: Finally! Display 'temp → data --->NULL'.
The codes to display elements of stack are as follows:
void display()
{
if(top == NULL)
cout<<"\nStack is Empty!!!\n";
else{
struct Node *temp = top;
while(temp->next != NULL){
cout<<"--->"<<temp->data;
temp = temp -> next;
}
Cout<<"--->NULL”<<temp->data;
}
}

2.2 QUEUE ADT


Queue is a linear data structure in which the insertion and deletion operations are performed at two
different ends. In a queue data structure, the insertion operation, called "enQueue() is performed at a
position which is known as 'rear' and the deletion operation, called "deQueue()" is performed at a
position which is known as 'front'. In queue data structure, the insertion and deletion operations are
performed based on FIFO (First In First Out) principle.

UNIT 2 Page 5
16CS3202 - Data Structures II Yr CSE / III Sem

Example
After inserting 25, 30, 51, 60 and 85, queue is as follows:

Queue data structure can be implemented in two ways. They are as follows:
1. Array based implementation
2. Linked List based implementation
When a queue is implemented using array, that queue can organize only limited number of elements.
When a queue is implemented using linked list, that queue can organize unlimited number of elements.
(i) Array based implementation:
A queue data structure can be implemented using one dimensional array. The implementation of
queue using array contains one dimensional array of specific size, variables 'front' and 'rear'. Initially
both 'front' and 'rear' are set to -1. Whenever, we want to insert a new value into the queue, increment
'rear' value by one and then insert at that position. Whenever we want to delete a value from the queue,
then increment 'front' value by one and then delete the value at 'front' position.
Operations using Array:
The below steps are used to create an empty queue.
Step 1: Include all the header files which are used in the program and define a constant 'SIZE' with
specific value.
Step 2: Declare all the user defined functions which are used in queue implementation.
Step 3: Create a one dimensional array with above defined SIZE (int queue[SIZE])
Step 4: Define two integer variables 'front' and 'rear' and initialize both with '-1'.
(int front = -1, rear = -1)

The code to create empty queue are as follows:


#define SIZE 10
void enQueue(int);
void deQueue();
void display();
int queue[SIZE], front = -1, rear = -1;
(a) enQueue(value) - Inserting value into the queue
In a queue data structure, enQueue() is a function used to insert a new elementat rear position in the
queue. We can use the following steps to insert an element into the queue:
Step 1: Check whether queue is FULL. (rear == SIZE-1)
Step 2: If it is FULL, then display "Queue is FULL!!! Insertion is not possible!!!" and terminate the
function.
Step 3: If it is NOT FULL, then increment rear value by one (rear++) and set

UNIT 2 Page 6
16CS3202 - Data Structures II Yr CSE / III Sem

queue[rear] = value.
The code to insert new element in queue are as follows:
void enQueue(int value){
if(rear == SIZE-1)
cout<<"\nQueue is Full!!! Insertion is not possible!!!";
else{
if(front == -1)
front = 0;
rear++;
queue[rear] = value;
cout<<"\nInsertion success!!!”;
}}
(b) deQueue() - Deleting a value from the Queue
In a queue data structure, deQueue() is a function used to delete an element from frontposition from the
queue. We can use the following steps to delete an element from the queue:
Step 1: Check whether queue is EMPTY. (front == rear)
Step 2: If it is EMPTY, then display "Queue is EMPTY!!! Deletion is not possible!!!" and terminate
the function.
Step 3: If it is NOT EMPTY, then increment the front value by one (front ++). Then display
queue[front] as deleted element. Then check whether both front and rear are equal (front == rear), if
it TRUE, then set both front and rear to '-1' (front = rear = -1).
The code to delete an element in queue is as follows:
void deQueue(){
if(front == rear)
cout<<"\nQueue is Empty!!! Deletion is not possible!!!";
else{
cout<<"\nDeleted :"<< queue[front]);
front++;
if(front == rear)
front = rear = -1;
}
}
(c)display() - Displays the elements of a Queue
We can use the following steps to display the elements of a queue.
Step 1: Check whether queue is EMPTY. (front == rear)
Step 2: If it is EMPTY, then display "Queue is EMPTY!!!" and terminate the function.
Step 3: If it is NOT EMPTY, then define an integer variable 'i' and set 'i = front+1'.
Step 3: Display 'queue[i]' value and increment 'i' value by one (i++). Repeat the same until 'i' value is
equal to rear (i<= rear)
The code to delete an element in queue is as follows:
void display(){
if(rear == -1)
cout<<"\nQueue is Empty!!!";
else{
int i;

UNIT 2 Page 7
16CS3202 - Data Structures II Yr CSE / III Sem

cout<<"\nQueue elements are:\n”;


for(i=front; i<=rear; i++)
cout<<"\t"<<queue[i];
}
}

(ii) linked list implementation:


The major problem with the queue implemented using array is, It will work for only fixed number of
data. A queue data structure can be implemented using linked list data structure. The queue using linked
list can work for variable size of data. In linked list implementation of a queue, the last inserted node is
always pointed by 'rear' and the first node is always pointed by 'front'.

Example:

In above example, the last inserted node is 50 and it is pointed by 'rear' and the first inserted node is 10
and it is pointed by 'front'. The order of elements inserted is 10, 15, 22 and 50.
Operations
To implement queue using linked list, we need to set the following things before implementing actual
operations.
Step 1:Declare all the user defined functions.
Step 2: Define a 'Node' structure with two members data and next.
Step 3: Define two Node pointers 'front' and 'rear' and set both to NULL.
The code to create empty queue are as follows:
struct Node
{
int data;
struct Node *next;
}*front = NULL,*rear = NULL;
void insert(int);
void delete();
void display();

(a) enQueue(value) - Inserting an element into the Queue


We can use the following steps to insert a new node into the queue...
Step 1: Create a newNode with given value and set 'newNode → next' to NULL.
Step 2: Check whether queue is Empty (rear == NULL)
Step 3: If it is Empty then, set front = newNode and rear = newNode.
Step 4: If it is Not Empty then, set rear → next = newNode and rear = newNode.
The code to insert new element in queue is as follows:
void enQueue(int value)
{
struct Node *newNode= new Node();
UNIT 2 Page 8
16CS3202 - Data Structures II Yr CSE / III Sem

newNode->data = value;
newNode -> next = NULL;
if(front == NULL)
front = rear = newNode;
else{
rear -> next = newNode;
rear = newNode;
}
cout<<"\nInsertion is Success!!!\n";
}

(b) deQueue() - Deleting an Element from Queue:


We can use the following steps to delete a node from the queue...
Step 1: Check whether queue is Empty (front == NULL).
Step 2: If it is Empty, then display "Queue is Empty!!! Deletion is not possible!!!" and terminate
from the function
Step 3: If it is Not Empty then, define a Node pointer 'temp' and set it to 'front'.
Step 4: Then set 'front = front → next' and delete 'temp' (free(temp)).
The codes to delete element from queue are as follows:
void deQueue()
{
if(front == NULL)
cout<<"\nQueue is Empty!!!\n";
else{
struct Node *temp = front;
front = front -> next;
cout<<"\nDeleted element:\n"<<temp->data;
free(temp);
}
}

(c) display() - Displaying the elements of Queue:


We can use the following steps to display the elements (nodes) of a queue...
Step 1: Check whether queue is Empty (front == NULL).
Step 2: If it is Empty then, display 'Queue is Empty!!!' and terminate the function.
Step 3: If it is Not Empty then, define a Node pointer 'temp' and initialize with front.
Step 4: Display 'temp → data --->' and move it to the next node. Repeat the same until 'temp' reaches
to 'rear' (temp → next != NULL).
Step 4: Finally, Display 'temp → data --->NULL'.
The codes to display elements in queue are as follows:
void display()
{
if(front == NULL)
cout<<"\nQueue is Empty!!!\n";
else{

UNIT 2 Page 9
16CS3202 - Data Structures II Yr CSE / III Sem

struct Node *temp = front;


while(temp->next != NULL){
cout<<”--->"<<temp->data;
temp = temp -> next;
}
Cout<<"--->NULL\n"<<temp->data;
}
}

2.3 CIRCULAR QUEUE:


In normal queue, even though we have empty positions in the queue we cannot make use of them to
insert new element. To overcome this problem we use circular queue data structure.

Circular Queue is a linear data structure in which the operations are performed based on FIFO (First
In First Out) principle and the last position is connected back to the first position to make a
circle.Graphical representation of a circular queue is as follows:

Implementation of Circular Queue


To implement a circular queue data structure using array, we first perform the following steps before we
implement actual operations.
Step 1: Include all the header files which are used in the program and define a constant 'SIZE' with
specific value.
Step 2: Declare all user defined functions used in circular queue implementation.
Step 3: Create a one dimensional array with above defined SIZE (int cQueue[SIZE])
Step 4: Define two integer variables 'front' and 'rear' and initialize both with '-1'. (int front = -1, rear
= -1)
Coding:
#define SIZE 5
void enQueue(int);
void deQueue();
void display();
int cQueue[SIZE], front = -1, rear = -1;

UNIT 2 Page 10
16CS3202 - Data Structures II Yr CSE / III Sem

(a) enQueue(value) - Inserting value into the Circular Queue


In a circular queue, enQueue() is a function which is used to insert an element into the circular queue. In
a circular queue, the new element is always inserted at rear position. We can use the following steps to
insert an element into the circular queue:
Step 1: Check whether queue is FULL. ((rear == SIZE-1 && front == 0) || (front == rear+1))
Step 2: If it is FULL, then display "Queue is FULL!!! Insertion is not possible!!!" and terminate the
function.
Step 3: If it is NOT FULL, then check rear == SIZE - 1 && front != 0 if it is TRUE, then set
rear = -1.
Step 4: Increment rear value by one (rear++), set queue[rear] = value and check 'front == -1' if it is
TRUE, then set front = 0.
Coding:
void enQueue(int value)
{
if((front == 0 && rear == SIZE - 1) || (front == rear+1))
cout<<"\nCircular Queue is Full! Insertion not possible!!!\n";
else{
if(rear == SIZE-1 && front != 0)
rear = -1;
cQueue[++rear] = value;
cout<<"\nInsertion Success!!!\n";
if(front == -1)
front = 0;
}
}

(b) deQueue() - Deleting a value from the Circular Queue


In a circular queue, deQueue() is a function used to delete an element from the circular queue. In a
circular queue, the element is always deleted from front position. We can use the following steps to
delete an element from the circular queue:
Step 1: Check whether queue is EMPTY. (front == -1 && rear == -1)
Step 2: If it is EMPTY, then display "Queue is EMPTY!!! Deletion is not possible!!!" and terminate
the function.
Step 3: If it is NOT EMPTY, then display queue[front] as deleted element and increment the front
value by one (front ++). Then check whether front == SIZE, if it is TRUE, then set front = 0. Then
check whether both front - 1 and rear are equal (front -1 == rear), if it TRUE, then set both front and
rear to '-1' (front = rear = -1).
Coding:
void deQueue()
{
if(front == -1 && rear == -1)
cout<<"\nCircular Queue is Empty! Deletion is not possible!!!\n";
else{
cout<<"\nDeleted element :\n"<<cQueue[front++];
if(front == SIZE)
front = 0;

UNIT 2 Page 11
16CS3202 - Data Structures II Yr CSE / III Sem

if(front-1 == rear)
front = rear = -1;
}
}

(c) display() - Displays the elements of a Circular Queue


We can use the following steps to display the elements of a circular queue...
Step 1: Check whether queue is EMPTY. (front == -1)
Step 2: If it is EMPTY, then display "Queue is EMPTY!!!" and terminate the function.
Step 3: If it is NOT EMPTY, then define an integer variable 'i' and set 'i = front'.
Step 4: Check whether 'front <= rear', if it is TRUE, then display 'queue[i]' value and increment 'i'
value by one (i++). Repeat the same until 'i <= rear' becomes FALSE.
Step 5: If 'front <= rear' is FALSE, then display 'queue[i]' value and increment 'i' value by one (i++).
Repeat the same until'i <= SIZE - 1' becomes FALSE.
Step 6: Set i to 0.
Step 7: Again display 'cQueue[i]' value and increment i value by one (i++). Repeat the same until 'i <=
rear' becomes FALSE.
Coding:
void display()
{
if(front == -1)
cout<<"\nCircular Queue is Empty!!!\n";
else{
int i = front;
cout<<"\nCircular Queue Elements are : \n";
if(front <= rear){
while(i <= rear)
cout<<”\t"<<cQueue[i++];
}
else{
while(i <= SIZE - 1)
cout<<”\t"<<cQueue[i++];
i = 0;
while(i <= rear)
cout<<”\t"<<cQueue[i++];
}
}
}

2.2.1 DOUBLE ENDED QUEUE (DEQUEUE)

Double Ended Queue is also a Queue data structure in which the insertion and deletion operations are
performed at both the ends (front and rear). That means, we can insert at both front and rear positions
and can delete from both front and rear positions.

UNIT 2 Page 12
16CS3202 - Data Structures II Yr CSE / III Sem

Double Ended Queue can be represented in TWO ways, those are as follows...
1. Input Restricted Double Ended Queue
2. Output Restricted Double Ended Queue
(i) Input Restricted Double Ended Queue
In input restricted double ended queue, the insertion operation is performed at only one end and deletion
operation is performed at both the ends.

(ii)Output Restricted Double Ended Queue


In output restricted double ended queue, the deletion operation is performed at only one end and
insertion operation is performed at both the ends.

2.4 APPLICATIONS OF STACK:

The linear data structure stack can be used in the following situations.
1. It can be used to process function calls.
2. It can be used to check whether symbols are balanced in programming language statements
3. Converting and evaluating expressions.
(i) Balancing Symbols
In syntax error checking, a lack of one symbol(such as a missing brace or comment starter) can
cause the compiler to spill out a hundredlines of diagnostics. For simplicity,we will check for balancing
of parentheses, brackets, and braces using stack and ignore any othercharacter that appears.
The simple algorithm uses a stack and is as follows:
Make an empty stack. Read characters until end of file. If the character is an openingsymbol,
push it onto the stack. If it is a closing symbol and the stack is empty, reportan error. Otherwise, pop the
stack. If the symbol popped is not the correspondingopening symbol, then report an error. At end of file,
if the stack is not empty, report anerror.

UNIT 2 Page 13
16CS3202 - Data Structures II Yr CSE / III Sem

(ii) Postfix Expressions:


A postfix expression can be evaluated using the Stack data structure. To evaluate a postfix expression
using Stack, we can use the following steps:
1. Read all the symbols one by one from left to right in the given Postfix Expression
2. If the reading symbol is operand, then push it on to the Stack.
3. If the reading symbol is operator (+ , - , * , / etc.,), then perform TWO pop operations and store
the two popped operands in two different variables (operand1 and operand2). Then perform reading
symbol operation using operand1 and operand2 and push result back on to the Stack.
4. Finally, perform a pop operation and display the popped value as final result.
Example
Consider the following Expression,
Infix Expression : (5+3)*(8-2)
Postfix Expression : 5 3 + 8 2 - *

UNIT 2 Page 14
16CS3202 - Data Structures II Yr CSE / III Sem

Infix Expression : (5+3)*(8-2) = 48


Postfix Expression : 5 3 + 8 2 - * = 48

(iii)Function Call:
When there is a function call, all the important information that needs to be saved, suchas register values
(corresponding to variable names) and the return address (which can beobtained from the program
counter, which is typically in a register), is saved on a stack. Then the control is transferredto the new
function, which is free to replace the registers with its values. If it makes otherfunction calls, it follows
the same procedure. When the function wants to return, it looksat the stack at the top and restores all the
registers. It then makes the returnjump.The information savedis called either an activation record or
stack frame. There is always the possibility that we will run out of stack spaceby having too many
simultaneously active functions.
(iv) Infix to Postfix Conversion:
We can use stack to convert an infix expression into postfix form. To know about the basics of
expression, following topics will be useful.An expression is a collection of operators and operands that
represents a specific value. Based on the operator position, expressions are divided into 3 types, such as
• Infix Expression
• Postfix Expression
• Prefix Expression
In infix expression, operator is used in between operands. For example, a+b. In postfix
expression, operator is used after operands. For example, ab+. In prefix expression, operator is used
before operands. For example, +ab.
To convert Infix Expression into Postfix Expression using a stack data structure, we can use the
following steps:
1. Read all the symbols one by one from left to right in the given Infix Expression.
2. If the reading symbol is operand, then directly print it to the result (Output).
3. If the reading symbol is left parenthesis '(', then Push it on to the Stack.
4. If the reading symbol is right parenthesis ')', then Pop all the contents of stack until respective left
parenthesis is poped and print each poped symbol to the result.
5. If the reading symbol is operator (+ , - , * , / etc.,), then Push it on to the Stack. However, first pop the
operators which are already on the stack that have higher or equal precedence than current operator and
print them to the result.
Example:
Consider the following Infix Expression...
(A+B)*(C-D)
The given infix expression can be converted into postfix expression using Stack data Structure as
follows:

UNIT 2 Page 15
16CS3202 - Data Structures II Yr CSE / III Sem

UNIT 2 Page 16
16CS3202 - Data Structures II Yr CSE / III Sem

The final Postfix Expression is as follows...


AB+CD-*

2.5 APPLICATIONS OF QUEUES:

• When jobs are submitted to a printer, jobs sent to a printer are placed on a queue.
• Lines at ticketcounters are queues, because service is first-come first-served.
• Users on other machines are given access to files on a first-come first-served basis, so the data
structure is a queue.
• Further examples include the following:
1. Calls to large companies are generally placed on a queue when all operators are busy.
2. In large universities, where resources are limited, students must sign a waiting list ifall computers are
occupied. The student who has been at a computer the longest isforced off first, and the student who has
been waiting the longest is the next user to beallowed on.

2.5.1 PRIORITY QUEUE


Priority queue is a variant of queue data structure in which insertion is performed in the
order of arrival and deletion is performed based on the priority.

There are two types of priority queues, such as:

UNIT 2 Page 17
16CS3202 - Data Structures II Yr CSE / III Sem

1. Max Priority Queue


2. Min Priority Queue

1. Max Priority Queue


In max priority queue, elements are inserted in the order in which they arrive the queue and always
maximum value is removed first from the queue. For example assume that we insert in order 8, 3, 2, 5
and they are removed in the order 8, 5, 3, 2. The following are the operations performed in a Max
priority queue:
1. isEmpty() - Check whether queue is Empty.
2. insert() - Inserts a new value into the queue.
3. findMax() - Find maximum value in the queue.
4. remove() - Delete maximum value from the queue.
Max Priority Queue Representations:
There are 6 representations of max priority queue.
1. Using an Unordered Array (Dynamic Array)
2. Using an Unordered Array (Dynamic Array) with the index of the maximum value
3. Using an Array (Dynamic Array) in Decreasing Order
4. Using an Array (Dynamic Array) in Increasing Order
5. Using Linked List in Increasing Order
6. Using Unordered Linked List with reference to node with the maximum value

a. Using an Unordered Array (Dynamic Array)


In this representation elements are inserted according to their arrival order and maximum
element is deleted first from max priority queue. For example, assume that elements are inserted in the
order of 8, 2, 3 and 5. And they are removed in the order 8, 5, 3 and 2.

Each operation is according to this representation:


• isEmpty(): If 'front == -1' queue is Empty. This operation requires O(1) time complexity that
means constant time.
• insert(): New element is added at the end of the queue. This operation requires O(1) time
complexity that means constant time.
• findMax(): To find maximum element in the queue, we need to compare with all the elements in
the queue. This operation requires O(n) time complexity.
• remove() : To remove an element from the queue first we need to perform findMax() which
requires O(n) and removal of particular element requires constant time O(1). This operation
requires O(n) time complexity.

b. Using an Unordered Array (Dynamic Array) with the index of the maximum value
In this representation elements are inserted according to their arrival order and maximum
element is deleted first from max priority queue. For example, assume that elements are inserted in the
order of 8, 2, 3 and 5. And they are removed in the order 8, 5, 3 and 2.

UNIT 2 Page 18
16CS3202 - Data Structures II Yr CSE / III Sem

Each operation is according to this representation:


• isEmpty() - If 'front == -1' queue is Empty. This operation requires O(1) time complexity that
means constant time.
• insert() - New element is added at the end of the queue with O(1) and for each insertion we need
to update maxIndex with O(1). This operation requires O(1) time complexity that means
constant time.
• findMax() - To find maximum element in the queue is very simple as maxIndex has maximum
element index. This operation requires O(1) time complexity.
• remove() - To remove an element from the queue first we need to perform findMax() which
requires O(1) , removal of particular element requires constant time O(1) and update maxIndex
value which requires O(n). This operation requires O(n) time complexity.

c. Using an Array (Dynamic Array) in Decreasing Order


In this representation elements are inserted according to their value in decreasing order and maximum
element is deleted first from max priority queue. For example, assume that elements are inserted in the
order of 8, 5, 3 and 2. And they are removed in the order 8, 5, 3 and 2.

Each operation is according to this representation:


• isEmpty() - If 'front == -1' queue is Empty. This operation requires O(1) time complexity that
means constant time.
• insert() - New element is added at a particular position in the decreasing order into the queue
with O(n), because we need to shift existing elements inorder to insert new element in
decreasing order. This operation requires O(n) time complexity.
• findMax() - To find maximum element in the queue is very simple as maximum element is at
the beginning of the queue. This operation requires O(1) time complexity.
• remove() - To remove an element from the queue first we need to perform findMax() which
requires O(1), removal of particular element requires constant time O(1) and rearrange
remaining elements which requires O(n). This operation requires O(n) time complexity.

d. Using an Array (Dynamic Array) in Increasing Order


In this representation elements are inserted according to their value in increasing order and maximum
element is deleted first from max priority queue. For example, assume that elements are inserted in the
order of 2, 3, 5 and 8. And they are removed in the order 8, 5, 3 and 2.

Each operation is according to this representation:


• isEmpty() - If 'front == -1' queue is Empty. This operation requires O(1) time complexity that
means constant time.

UNIT 2 Page 19
16CS3202 - Data Structures II Yr CSE / III Sem

• insert() - New element is added at a particular position in the increasing order into the queue
with O(n), because we need to shift existing elements inorder to insert new element in increasing
order. This operation requires O(n) time complexity.
• findMax() - To find maximum element in the queue is very simple as maximum element is at
the end of the queue. This operation requires O(1) time complexity.
• remove() - To remove an element from the queue first we need to perform findMax() which
requires O(1), removal of particular element requires constant time O(1) and rearrange
remaining elements which requires O(n). This operation requires O(n) time complexity.

e.Using Linked List in Increasing Order


In this representation, we use a single linked list to represent max priority queue. In this
representation elements are inserted according to their value in increasing order and node with
maximum value is deleted first from max priority queue. For example, assume that elements are inserted
in the order of 2, 3, 5 and 8. And they are removed in the order 8, 5, 3 and 2.

Each operation is according to this representation:


• isEmpty() - If 'head == NULL' queue is Empty. This operation requires O(1) time complexity
that means constant time.
• insert() - New element is added at a particular position in the increasing order into the queue
with O(n), because we need to the position where new element has to be inserted. This operation
requires O(n) time complexity.
• findMax() - To find maximum element in the queue is very simple as maximum element is at
the end of the queue. This operation requires O(1) time complexity.
• remove() - To remove an element from the queue is simply removing the last node in the queue
which requires O(1). This operation requires O(1) time complexity.

f. Using Unordered Linked List with reference to node with the maximum value
In this representation, we use a single linked list to represent max priority queue. Always we
maintain a reference (maxValue) to the node with maximum value. In this representation elements are
inserted according to their arrival and node with maximum value is deleted first from max priority
queue. For example, assume that elements are inserted in the order of 2, 8, 3 and 5. And they are
removed in the order 8, 5, 3 and 2.

Each operation is according to this representation:


• isEmpty() - If 'head == NULL' queue is Empty. This operation requires O(1) time complexity
that means constant time.
• insert() - New element is added at end the queue with O(1) and update maxValue reference with
O(1). This operation requires O(1) time complexity.

UNIT 2 Page 20
16CS3202 - Data Structures II Yr CSE / III Sem

• findMax() - To find maximum element in the queue is very simple as maxValue is referenced to
the node with maximum value in the queue. This operation requires O(1) time complexity.
• remove() - To remove an element from the queue is deleting the node which referenced by
maxValue which requires O(1) and update maxValue reference to new node with maximum
value in the queue which requires O(n) time complexity. This operation requires O(n) time
complexity.

UNIT 2 Page 21
16CS3202 - Data Structures II Yr CSE / III Sem

UNIT – III
NON LINEAR DATA STRUCTURES-TREE
3.1 Tree ADT
3.2 Representation of trees
3.3 Binary Tree ADT
3.4 Expression trees
3.5 Applications of trees
3.6 BST ADT
3.7 Tree traversals
3.8 AVL Trees
3.9 B-Tree
3.10 Heaps
3.10.1 Binary heaps
3.10.2 Applications of binary heaps
3.11 Binomial heaps

3.1 Tree ADT


In linear data structure, data is organized in sequential order and in non-linear data structure,
data is organized in random order. Tree is a very popular data structure used in wide range of
applications.
A tree data structure can be defined as follows...
Tree is a non-linear data structure which organizes data in hierarchical structure and this
is a recursive definition.
A tree data structure can also be defined as follows...
Tree data structure is a collection of data (Node) which is organized in hierarchical
structure and this is a recursive definition
In tree data structure, every individual element is called as Node. Node in a tree data structure,
stores the actual data of that particular element and link to next element in hierarchical structure.
In a tree data structure, if we have N number of nodes then we can have a maximum of N-
1 number of links.
Example

Terminology

UNIT 4 Page 1
16CS3202 - Data Structures II Yr CSE / III Sem

In a tree data structure, we use the following terminology...


1. Root
In a tree data structure, the first node is called as Root Node. Every tree must have root node.
We can say that root node is the origin of tree data structure. In any tree, there must be only one root
node. We never have multiple root nodes in a tree.

2. Edge
In a tree data structure, the connecting link between any two nodes is called as EDGE. In a tree
with 'N' number of nodes there will be a maximum of 'N-1' number of edges.

3. Parent
In a tree data structure, the node which is predecessor of any node is called as PARENT
NODE. In simple words, the node which has branch from it to any other node is called as parent node.
Parent node can also be defined as "The node which has child / children".

4. Child

UNIT 4 Page 2
16CS3202 - Data Structures II Yr CSE / III Sem

In a tree data structure, the node which is descendant of any node is called as CHILD Node. In
simple words, the node which has a link from its parent node is called as child node. In a tree, any
parent node can have any number of child nodes. In a tree, all the nodes except root are child nodes.

5. Siblings
In a tree data structure, nodes which belong to same Parent are called as SIBLINGS. In simple
words, the nodes with same parent are called as Sibling nodes.

6. Leaf
In a tree data structure, the node which does not have a child is called as LEAF Node. In simple
words, a leaf is a node with no child.
In a tree data structure, the leaf nodes are also called as External Nodes. External node is also a
node with no child. In a tree, leaf node is also called as 'Terminal' node.

UNIT 4 Page 3
16CS3202 - Data Structures II Yr CSE / III Sem

7. Internal Nodes
In a tree data structure, the node which has at least one child is called as INTERNAL Node. In
simple words, an internal node is a node with at least one child.
In a tree data structure, nodes other than leaf nodes are called as Internal Nodes. The root
node is also said to be Internal Node if the tree has more than one node. Internal nodes are also called
as 'Non-Terminal' nodes.

8. Degree
In a tree data structure, the total number of children of a node is called as DEGREE of that
Node. In simple words, the Degree of a node is total number of children it has. The highest degree of a
node among all the nodes in a tree is called as 'Degree of Tree'

9. Level
In a tree data structure, the root node is said to be at Level 0 and the children of root node are at
Level 1 and the children of the nodes which are at Level 1 will be at Level 2 and so on... In simple
words, in a tree each step from top to bottom is called as a Level and the Level count starts with '0' and
incremented by one at each level (Step).

UNIT 4 Page 4
16CS3202 - Data Structures II Yr CSE / III Sem

10. Height
In a tree data structure, the total number of edges from leaf node to a particular node in the
longest path is called as HEIGHT of that Node. In a tree, height of the root node is said to be height of
the tree. In a tree, height of all leaf nodes is '0'.

11. Depth
In a tree data structure, the total number of edges from root node to a particular node is called
as DEPTH of that Node. In a tree, the total number of edges from root node to a leaf node in the
longest path is said to be Depth of the tree. In simple words, the highest depth of any leaf node in a
tree is said to be depth of that tree. In a tree, depth of the root node is '0'.

12. Path

UNIT 4 Page 5
16CS3202 - Data Structures II Yr CSE / III Sem

In a tree data structure, the sequence of Nodes and Edges from one node to another node is
called as PATH between that two Nodes. Length of a Path is total number of nodes in that path. In
below example the path A - B - E - J has length 4.

13. Sub Tree


In a tree data structure, each child from a node forms a sub tree recursively. Every child node
will form a sub tree on its parent node.

3.3 Binary Tree ADT


In a normal tree, every node can have any number of children. Binary tree is a special type of
tree data structure in which every node can have a maximum of 2 children. One is known as left child
and the other is known as right child.
A tree in which every node can have a maximum of two children is called as Binary Tree. In a
binary tree, every node can have either 0 children or 1 child or 2 children but not more than 2 children.
Example

UNIT 4 Page 6
16CS3202 - Data Structures II Yr CSE / III Sem

TYPES OF BINARY TREE:


a) Complete Binary Tree
b) Full Binary Tree
c) Left Skewed Binary Tree
d) Right Skewed Binary Tree
Complete Binary Tree
In a binary tree, every node can have a maximum of two children. But in strictly binary tree,
every node should have exactly two children or none and in complete binary tree all the nodes must
have exactly two children and at every level of complete binary tree there must be 2 level number of
nodes 2h+1 – 1 where h is the number of nodes. For example at level 2 there must be 22 = 4 nodes and at
level 3 there must be 23 = 8 nodes.
A binary tree in which every internal node has exactly two children and all leaf nodes are at
same level is called Complete Binary Tree.

Complete binary tree is also called as Perfect Binary Tree

Full Binary Tree:


A full binary tree (sometimes proper binary tree or 2-tree or strictly binary tree) is a tree in
which every node other than the leaves has two children.
So you have no nodes with only 1 child. Appears to be the same as strict binary tree.

UNIT 4 Page 7
16CS3202 - Data Structures II Yr CSE / III Sem

Left Skewed Binary Tree:


A binary tree in which each node is having either only left sub-trees or no sub-trees is called as
left skewed binary tree. In this program, binary tree is first created. Then every child node is parsed.
While parsing only the left sub-trees are considered as valid and if any right sub-tree is found then that
binary tree is not a left skewed binary tree.

Right Skewed Binary Tree:


A binary tree in which each node is having either only right sub-trees or no sub-trees is called as
right skewed binary tree. In this program, binary tree is first created. Then every child node is parsed.
While parsing only the right sub-trees are considered as valid and if any left sub-tree is found then that
binary tree is not a right skewed binary tree.

Applications of binary trees:


 Binary Search Tree - Used in many search applications where data is constantly entering/leaving,
such as the map and set objects in many languages' libraries.

UNIT 4 Page 8
16CS3202 - Data Structures II Yr CSE / III Sem

 Hash Trees - used in p2p programs and specialized image-signatures in which a hash needs to be
verified, but the whole file is not available.
 Syntax Tree - Constructed by compilers and (implicitly) calculators to parse expressions.

3.2 BINARY TREE REPRESENTATIONS


A binary tree data structure is represented using two methods. Those methods are as follows...
 Array Representation
 Linked List Representation
Consider the following binary tree...

1. Array Representation
In array representation of binary tree, we use a one dimensional array (1-D Array) to represent a
binary tree.
Consider the above example of binary tree and it is represented as follows...

To represent a binary tree of depth 'n' using array representation, we need one dimensional
array with a maximum size of 2n+1 - 1.
2. Linked List Representation
We use double linked list to represent a binary tree. In a double linked list, every node consists
of three fields. First field for storing left child address, second for storing actual data and third for
storing right child address.
In this linked list representation, a node has the following structure...

The above example of binary tree represented using Linked list representation is shown as follows...

UNIT 4 Page 9
16CS3202 - Data Structures II Yr CSE / III Sem

Declaration of Binary Tree:


typedefstruct node
{
int data;
struct node *left;
struct node *right;
}node;

Insertion:
node *get_node()
{
node *temp;
temp=(node*)malloc(sizeof(node));
temp->left=NULL;
temp->right=NULL;
return temp;
}
void insert(node *root,node *New)
{
charch;
New=get_node();
cout<<"\nEnter the Element";
cin>>New->data;
if(root==NULL)
root=New;
else
cout<<nWhere to insert left/right of %d"<<root->data;
ch=getche();

UNIT 4 Page 10
16CS3202 - Data Structures II Yr CSE / III Sem

if((ch=='r')||(ch=='r'))
{
if(root->right==NULL)
{
root->right=New;
}
else
insert(root->right,New);
}
else
{
if(root->left==NULL)
{
root->left=New;
}
else
insert(root->left,New);
}
}

3.7 BINARY TREE TRAVERSALS


When we wanted to display a binary tree, we need to follow some order in which all the nodes
of that binary tree must be displayed. In any binary tree displaying order of nodes depends on the
traversal method.
Displaying (or) visiting order of nodes in a binary tree is called as Binary Tree Traversal.
There are three types of binary tree traversals.
 In - Order Traversal
 Pre - Order Traversal
 Post - Order Traversal
Consider the following binary tree...

1. In - Order Traversal (Left Child- Root - Right Child)


In In-Order traversal, the root node is visited between left child and right child.

UNIT 4 Page 11
16CS3202 - Data Structures II Yr CSE / III Sem

In this traversal, the left child node is visited first, then the root node is visited and later we go
for visiting right child node.
This in-order traversal is applicable for every root node of all subtrees in the tree. This is
performed recursively for all nodes in the tree.
That means here we have visited in the order of I - D - J - B - F - A - G - K - C - H using In-
Order Traversal.
In-Order Traversal for above example of binary tree is
I-D-J-B-F-A-G-K-C–H

Algorithm
Until all nodes are traversed −
Step 1 − Recursively traverse left subtree.
Step 2 − Visit root node.
Step 3 − Recursively traverse right subtree.

voidinorder(node *temp)
{
if(temp!=NULL)
{
inorder(temp->left);
cout>>temp->data;
inorder(temp->right);
}
}

2. Pre - Order Traversal (Root - Left Child- Right Child)


In Pre-Order traversal, the root node is visited before left child and right child nodes. In this
traversal, the root node is visited first, then its left child and later its right child. This pre-order traversal
is applicable for every root node of all subtrees in the tree.
That means here we have visited in the order of A-B-D-I-J-F-C-G-K-H using Pre-Order
Traversal.
Pre-Order Traversal for above example binary tree is
A-B-D-I-J-F-C-G-K–H

Algorithm
Until all nodes are traversed −
Step 1 − Visit root node.
Step 2 − Recursively traverse left subtree.
Step 3 − Recursively traverse right subtree.

voidpreorder(node *temp)
{
if(temp!=NULL)

UNIT 4 Page 12
16CS3202 - Data Structures II Yr CSE / III Sem

{
printf("%d",temp->data);
preorder(temp->left);
preorder(temp->right);
}
}

3. Post - Order Traversal (Left Child- Right Child- Root)


In Post-Order traversal, the root node is visited after left child and right child. In this traversal,
left child node is visited first, then its right child and then its root node. This is recursively performed
until the right most node is visited.
Here we have visited in the order of I - J - D - F - B - K - G - H - C - A using Post-Order
Traversal.
Post-Order Traversal for above example binary tree is
I-J-D-F-B-K-G-H-C-A

Algorithm
Until all nodes are traversed −
Step 1 − Recursively traverse left subtree.
Step 2 − Recursively traverse right subtree.
Step 3 − Visit root node.
voidpostorder(node *temp)
{
if(temp!=NULL)
{
postorder(temp->left);
postorder(temp->right);
printf("%d",temp->data);
}
}

3.5 APPLICATIONS OF TREES


1. Manipulate hierarchical data.
2. Storing data in a way that makes it efficiently searchable (binary search tree and tree traversal)
3. Manipulate sorted lists of data.
4. As a workflow for compositing digital images for visual effects.
5. Binary Search Tree.
6. Expression tree.
7. Threaded Binary Tree.

UNIT 4 Page 13
16CS3202 - Data Structures II Yr CSE / III Sem

3.4 EXPRESSION TREE


Algebraic expression trees represent expressions that contain numbers, variables, and unary and
binary operators. ... The nodes of binary operators have two child nodes, and the unary operators have
one child node.
Expression tree is a binary tree in which each internal node corresponds to operator and each
leaf node corresponds to operand so for example expression tree for 3 + ((5 + 9) * 2) would be:

Inorder traversal of expression tree produces infix version of given postfix expression (same
with preorder traversal it gives prefix expression)

This image can help you in understanding the main principles of Expression tree:

Construction of Expression Tree:


Now For constructing expression tree we use a stack. We loop through input expression and do
following for every character.
a) If character is operand push that into stack.
b) If character is operator pop two values from stack make them its child and push current node
again.
c) At the end only element of stack will be root of expression tree.

3.6 BINARY SEARCH TREE (BST ADT)


In a binary tree, every node can have maximum of two children but there is no order of nodes
based on their values. In binary tree, the elements are arranged as they arrive to the tree, from top to
bottom and left to right.
A binary tree has the following time complexities...

UNIT 4 Page 14
16CS3202 - Data Structures II Yr CSE / III Sem

Search Operation - O (n)


Insertion Operation - O (1)
Deletion Operation - O (n)
To enhance the performance of binary tree, we use special type of binary tree known as Binary
Search Tree. Binary search tree mainly focus on the search operation in binary tree. Binary search tree
can be defined as follows...
Binary Search Tree is a binary tree in which every node contains only smaller values in its
left subtree and only larger values in its right subtree.
In a binary search tree, all the nodes in left subtree of any node contains smaller values and all
the nodes in right subtree of that contains larger values as shown in following figure...

Example
The following tree is a Binary Search Tree. In this tree, left subtree of every node contains
nodes with smaller values and right subtree of every node contains larger values.

Every Binary Search Tree is a binary tree but all the Binary Trees need not to be binary search
trees.

UNIT 4 Page 15
16CS3202 - Data Structures II Yr CSE / III Sem

The following operations are performed on a Binary Search Tree...


 Insertion
 Search
 Deletion

Insertion Operation in BST


In a binary search tree, the insertion operation is performed with O(log n) time complexity. In
binary search tree, new node is always inserted as a leaf node. The insertion operation is performed as
follows...
Step 1: Create a newNode with given value and set its left and right to NULL.
Step 2: Check whether tree is Empty.
Step 3: If the tree is Empty, then set set root to newNode.
Step 4: If the tree is Not Empty, then check whether value of newNode
is smaller or larger than the node (here it is root node).
Step 5: If newNode is smaller than or equal to the node, then move to its left child. If
newNode is larger than the node, then move to its right child.
Step 6: Repeat the above step until we reach to a leaf node (e.i., reach to NULL).
Step 7: After reaching a leaf node, then insert the newNode as left child if newNode is smaller
or equal to that leaf else insert it as right child.

Construct a Binary Search Tree by inserting the following sequence of numbers...


10, 12, 5, 4, 20, 8, 7, 1 5 and 13
Above elements are inserted into a Binary Search Tree as follows...

UNIT 4 Page 16
16CS3202 - Data Structures II Yr CSE / III Sem

structtree_node
{
tree_node *left;
tree_node *right;
int data;
};

classbst
{
tree_node *root;
public:
bst()

UNIT 4 Page 17
16CS3202 - Data Structures II Yr CSE / III Sem

{
root=NULL;
}
intisempty()
{
return(root==NULL);
}
};
voidbst::insert(int no)
{
tree_node *p=new tree_node;
tree_node *parent;
p->data=no;
p->left=NULL;
p->right=NULL;
parent=NULL;
if(isempty())
root=p;
else
{
tree_node *ptr;
ptr=root;
while(ptr!=NULL)
{
parent=ptr;
if(no>ptr->data)
ptr=ptr->right;
else
ptr=ptr->left;
}
if(no<parent->data)
parent->left=p;
else
parent->right=p;
}
}

Search Operation in BST


In a binary search tree, the search operation is performed with O (log n) time complexity. The
search operation is performed as follows...
Step 1: Read the search element from the user
Step 2: Compare, the search element with the value of root node in the tree.

UNIT 4 Page 18
16CS3202 - Data Structures II Yr CSE / III Sem

Step 3: If both are matching, then display "Given node found!!!" and terminate the function
Step 4: If both are not matching, then check whether search element is smaller or larger than
that node value.
Step 5: If search element is smaller, then continue the search process in left subtree.
Step 6: If search element is larger, then continue the search process in right subtree.
Step 7: Repeat the same until we found exact element or we completed with a leaf node
Step 8: If we reach to the node with search value, then display "Element is found" and
terminate the function.
Step 9: If we reach to a leaf node and it is also not matching, then display "Element not found"
and terminate the function.

Deletion Operation in BST


In a binary search tree, the deletion operation is performed with O (log n) time complexity.
Deleting a node from Binary search tree has following three cases...
 Case 1: Deleting a Leaf node (A node with no children)
 Case 2: Deleting a node with one child
 Case 3: Deleting a node with two children

Case 1: Deleting a leaf node


We use the following steps to delete a leaf node from BST...
Step 1: Find the node to be deleted using search operation
Step 2: Delete the node using free function (If it is a leaf) and terminate the function.

Case 2: Deleting a node with one child


We use the following steps to delete a node with one child from BST...
Step 1: Find the node to be deleted using search operation
Step 2: If it has only one child, then create a link between its parent and child nodes.
Step 3: Delete the node using free function and terminate the function.

Case 3: Deleting a node with two children


We use the following steps to delete a node with two children from BST...
Step 1: Find the node to be deleted using search operation
Step 2: If it has two children, then find the largest node in its left subtree (OR)
the smallest node in its right subtree.
Step 3: Swap both deleting node and node which found in above step.
Step 4: Then, check whether deleting node came to case 1 or case 2 else goto steps 2
Step 5: If it comes to case 1, then delete using case 1 logic.
Step 6: If it comes to case 2, then delete using case 2 logic.
Step 7: Repeat the same process until node is deleted from the tree.

UNIT 4 Page 19
16CS3202 - Data Structures II Yr CSE / III Sem

3.8 AVL TREES


Invented by Russian scientists G.M.Adelson-velsky and E.M.Landis in 1962.
The binary tree structure that is balanced with respect to height of sub trees. The tree can be
made balanced and because of this retrieval of any node can be done in O (log n) times, where n is total
number of nodes.
Definition:
 An empty tree is height balanced if t is a non-empty binary tree with TL and as its left and right
sub trees. The T is height balanced if and only if.
 TL and TR are height balanced.
 The hL – hR<=1 where hL and hR are heights of TL and TR.

Balanced factor:
 The balanced factor BF (T) of a node in binary tree is defined as to be h L – hR where HL and HR
are heights of left and right sub trees of T.
 The AVL tree follows the property of binary search tree. In fact AVL trees are basically binary
search tress with balance factor as -1, 0 or +1.
 After insertion of any node in an AVL tree if the balance factor of any node becomes other than
-1, 0 or +1then it is said AVL property is violated.
 BalanceFactor = height(left-subtree) − height(right-subtree)

Insertion:
1) Left sub tree of Left child of pivot node SINGLE RIGHT ROTATION
2) Right sub tree of Right child of pivot node SINGLE LEFT ROTATION
3) Left sub tree of Right child of pivot node LEFT RIGHT ROTATION
4) Right sub tree of Left child of pivot node RIGHT LEFT ROTATION

SINGLE RIGHT ROTATION


SINGLE LEFT ROTATION Mirror image of each other

AVL Rotations
To balance itself, an AVL tree may perform the following four kinds of rotations −
a) Left rotation
b) Right rotation
c) Left-Right rotation
d) Right-Left rotation

UNIT 4 Page 20
16CS3202 - Data Structures II Yr CSE / III Sem

The first two rotations are single rotations and the next two rotations are double rotations. To have
an unbalanced tree, we at least need a tree of height 2. With this simple tree, let's understand them one
by one.
Left Rotation
If a tree becomes unbalanced, when a node is inserted into the right subtree of the right subtree,
then we perform a single left rotation −

In our example, node A has become unbalanced as a node is inserted in the right subtree of A's
right subtree. We perform the left rotation by making Athe left-subtree of B.

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

As depicted, the unbalanced node becomes the right child of its left child by performing a right
rotation.

Left-Right Rotation
Double rotations are slightly complex version of already explained versions of rotations. To
understand them better, we should take note of each action performed while rotation. Let's first check
how to perform Left-Right rotation. A left-right rotation is a combination of left rotation followed by
right rotation.

State Action

A node has been inserted into the right subtree of the left
subtree. This makes C an unbalanced node. These scenarios
cause AVL tree to perform left-right rotation.

UNIT 4 Page 21
16CS3202 - Data Structures II Yr CSE / III Sem

We first perform the left rotation on the left subtree of C. This


makes A, the left subtree of B.

Node C is still unbalanced, however now, it is because of the


left-subtree of the left-subtree.

We shall now right-rotate the tree, making B the new root node
of this subtree. C now becomes the right subtree of its own left
subtree.

The tree is now balanced.

Right-Left Rotation
The second type of double rotation is Right-Left Rotation. It is a combination of right rotation
followed by left rotation.

State Action

A node has been inserted into the left subtree of the right
subtree. This makes A, an unbalanced node with balance factor
2.

UNIT 4 Page 22
16CS3202 - Data Structures II Yr CSE / III Sem

First, we perform the right rotation along C node,


making C the right subtree of its own left subtree B.
Now, B becomes the right subtree of A.

Node A is still unbalanced because of the right subtree of its


right subtree and requires a left rotation.

A left rotation is performed by making B the new root node of


the subtree. A becomes the left subtree of its right subtree B.

The tree is now balanced.

Insertion Operation in AVL Tree


In an AVL tree, the insertion operation is performed with O (log n) time complexity. In AVL
Tree, new node is always inserted as a leaf node. The insertion operation is performed as follows...
Step 1: Insert the new element into the tree using Binary Search Tree insertion logic.
Step 2: After insertion, check the Balance Factor of every node.
Step 3: If the Balance Factor of every node is 0 or 1 or -1 then go for next operation.
Step 4: If the Balance Factor of any node is other than 0 or 1 or -1 then tree is said to be
imbalanced. Then perform the suitable Rotation to make it balanced. And go for next operation.
Insert the following element into an AVL tree 3, 5, 11, 8, 4, 1, 12, 7, 2, 6, 10

UNIT 4 Page 23
16CS3202 - Data Structures II Yr CSE / III Sem

Insert 3

Insert 5

Insert 11

While inserting the new node 11 as right sub tree of right child the Balance Factor
condition -1,0,+1 is not satisfying in the node 3, so we going for the single rotation RR

Insert 8

UNIT 4 Page 24
16CS3202 - Data Structures II Yr CSE / III Sem

Insert 4,1

Insert 12

Insert 7

UNIT 4 Page 25
16CS3202 - Data Structures II Yr CSE / III Sem

Insert 2

Insert 6

While inserting the new node 6 as right sub tree of left child the Balance Factor
condition -1,0,+1 is not satisfying in the node 11 & 8, so we going for the single
rotation LL

UNIT 4 Page 26
16CS3202 - Data Structures II Yr CSE / III Sem

Insert 10

While inserting the new node 10 as right sub tree of left child the Balance Factor
condition -1,0,+1 is not satisfying in the node 11, so we going for the Double rotation
RL

UNIT 4 Page 27
16CS3202 - Data Structures II Yr CSE / III Sem

3.9 B-Tree
B-Tree was developed in the year of 1972 by Bayer and McCreight with the name Height
Balanced m-way Search Tree. Later it was named as B-Tree.
B – Tree is specialized multiway tree used to store the records in a disk. There are number of
sub trees to each node. So that the height of the tree is relatively small. So that only small number of
nodes must be read from disk to retrieve an item.
B-Tree of Order m has the following properties:
Here, number of keys in a node and number of children for a node is depend on the order of the B-
Tree. Every B-Tree has order.
a) All the leaf nodes are on the bottom level and all the leaf nodes must be at same level.
b) The node which has n children possess (n – 1) keys and All nodes except root must have
at least [m/2]-1 keys.
c) The keys in each node are in ascending order.
d) The node should have at least two children, for every node, child [0] has only keys
which are less then node. Key [0] similarly, node. Child [1] has only keys which are greater than node.
Key [0].
e) All the internal nodes except root node have at least ceil (m/2) non empty children. The
ceil is a function such that ceil (3.4) = 4, ceil (9.3) = 10.
f) If the root node is a non-leaf node, then it must have at least 2 children and each leaf
node must contain at least ceil (m/2) – 1 keys.
g) All the key values within a node must be in Ascending Order.
For example, B-Tree of Order 5 contains maximum 4 key values in a node and maximum 5
children for a node.

Insertion:
We will construct a B – tree of order 5 following numbers:
3, 14, 7, 1, 8, 5, 11, 17, 13, 6, 23, 12, 20, 26, 4, 16, 18, 24, 25, 19
The internal node should have at least 3 non empty children and each leaf node must contain at
least 2 keys.

UNIT 4 Page 28
16CS3202 - Data Structures II Yr CSE / III Sem

Insert the following element using B – Tree of order


5 78,21,14,11,97,85,74,63,45,42,57,50,16,19,32,30,31.

Insert 78

Insert 21

Insert 14

Insert 11

Insert 97

The Condition fails as the order of B – tree is 5, so 4 keys and 5 child should be there. So we going to
split the B- tree into two half

UNIT 4 Page 29
16CS3202 - Data Structures II Yr CSE / III Sem

Insert 85

Insert 74

Insert 63

The Condition fails as the order of B – tree is 5, so 4 keys and 5 child should be there. So we going to
split the B- tree into two half

UNIT 4 Page 30
16CS3202 - Data Structures II Yr CSE / III Sem

Insert 45

Insert 42

Insert 57

The Condition fails as the order of B – tree is 5, so 4 keys and 5 child should be there. So we going to
split the B- tree into two half

Insert 20

UNIT 4 Page 31
16CS3202 - Data Structures II Yr CSE / III Sem

Insert 16

Insert 19

The Condition fails as the order of B – tree is 5, so 4 keys and 5 child should be there. So we going to
split the B- tree into two half

Insert 32

Insert 32
& 32

The Condition fails as the order of B – tree is 5, so 4 keys and 5 child should be there. So we going to
split the B- tree into two half

UNIT 4 Page 32
16CS3202 - Data Structures II Yr CSE / III Sem

The Condition fails as the order of B – tree is 5, so 4 keys and 5 child should be there. So we going to
split the B- tree into two half

UNIT 4 Page 33
16CS3202 - Data Structures II Yr CSE / III Sem

3.10 Heaps
3.10.1 Binary Heap
Heap is a complete binary tree or a almost complete binary tree in which every parent node be
either greater or lesser than its child nodes.
 In this Heap can be MIN or MAX.
 MAX Heap in the tree in which each node is greater than or equal to the value of the
children node
 MIN Heap in the tree in which each node is lesser than or equal too the value of the
children nodes.
MAX Heap:
In MAX Heap every parent node is greater than or equal to than its child node.

18

13 4

11 10

MIN Heap:
In MIN Heap every parent node is lesser than its children.

13 14

12 20

Parental Property
 Parent node being greater or lesser in heap so its called parental property.
 Heap having two important property
 Heap should satisfy following two conditions.
 It should be a complete binary tree or almost a complete binary tree
 Its should satisfy the parental property

UNIT 4 Page 34
16CS3202 - Data Structures II Yr CSE / III Sem

Almost complete binary tree:

18 18
18

13 4 13 4
13 4

11 10
11 10
 In A:Binary tree
satisfying properties, its level 2 and 1 but left and right child is present for each level.
10
A B C
 In B: Binary tree doesn't satisfying the 2nd property than the leaves at level 3 and level 1 are
not adjacent. So its not complete binary tree.
 In C: Binary tree doesn't satisfying the 1st property than 2nd level but only right child is
present.

Properties Of Priority Queue Using Heap:


 There should be either complete or almost complete binary tree.
 The root of a heap always contains its smallest or largest element.
 Heap sub tree in a heap is also a heap.
 Heap can be implemented as array by recording its element, top-down and left -right
Array Insertion:
 Root node A[0].
 Left child is at 2i+1 position in array A.
 Right child is at 2i+2 position in array A.
 Parent node is at the position in the array A.

UNIT 4 Page 35
16CS3202 - Data Structures II Yr CSE / III Sem

Algorithm for Insertion of Element:


 Insert the element at the last position in the heap.
 Compare its parent, swap the two nodes if parental till it satisfy the “Parent is greater than its
child“.

18
18 13 4 11 10

13 4

11 10
 To insert the element 19 in the given tree

18 18

13 4 13 4



11 10 11 10 19

 Its not satisfying the property 2 so we swap the element.4 > 19

18
18

13 4
13 19

11 10 19
11 10 4

UNIT 4 Page 36
16CS3202 - Data Structures II Yr CSE / III Sem

 Its not satisfying the property 2 so we swap the element 19 > 18

18 19

13 19 13 18

11 10 4 11 10 4

Algorithms for Deletion of Heap:


 Exchange of root with the last leaf.
 Decrease the heap size by 1.
 Heapify smaller tree using the bottom up constructions algorithms.
Delete of key 19

19 19

13 18 13 18
4 4 4

11 10 13 4 18 13 18 13 18
11 10 4

11 10 19 11 10 19 11 10

Now we go for checking of heap property so condition fails.

13 18

UNIT 4 11 10 Page 37
16CS3202 - Data Structures II Yr CSE / III Sem

So we move the 18 as root and 4 as right child

18

13 4

11 10

3.10.2 Applications of binary heaps


Applications of Heap Data Structure
a. Heap Data Structure is generally taught with Heapsort.
b. Priority Queues: Priority queues can be efficiently implemented using Binary Heap
because it supports insert(), delete() and extractmax(), decreaseKey() operations in O(logn) time.
c. Binomoial Heap and Fibonacci Heap are variations of Binary Heap. These variations
perform union also in O(logn) time which is a O(n) operation in Binary Heap. Heap Implemented
priority queues are used in Graph algorithms like Prim’s Algorithm and Dijkstra’s algorithm.

3.11 BINOMIAL HEAP


The main application of Binary Heap is as implement priority queue. Binomial Heap is to
extension of Binary Heap that provides faster union or merge operation together with other operations
provided by Binary Heap.
A Binomial Heap is a collection of Binomial Trees
A Binomial Tree of order 0 has 1 node. A Binomial Tree of order k can be constructed by
taking two binomial trees of order k-1, and making one as leftmost child of other.
A Binomial Tree of order k has following properties.
It has exactly 2k nodes.
a) It has depth as k.
b) There are exactly kCi nodes at depth i for i = 0, 1, . . . , k.
c) The root has degree k and children of root are themselves Binomial Trees with order k-
1, k-2,.. 0 from left to right.

UNIT 4 Page 38
16CS3202 - Data Structures II Yr CSE / III Sem

Binomial Heap:
A Binomial Heap is a set of Binomial Trees where each Binomial Tree follows Min Heap
property. And there can be at-most one Binomial Tree of any degree.

Binary Representation of a number and Binomial Heaps


A Binomial Heap with n nodes has number of Binomial Trees equal to the number of set bits in
Binary representation of n. For example let n be 13, there 3 set bits in binary representation of n

UNIT 4 Page 39
16CS3202 - Data Structures II Yr CSE / III Sem

(00001101), hence 3 Binomial Trees. We can also relate degree of these Binomial Trees with positions
of set bits. With this relation we can conclude that there are O(Logn) Binomial Trees in a Binomial
Heap with ‘n’ nodes.

Operations of Binomial Heap:


The main operation in Binomial Heap is union(), all other operations mainly use this operation.
The union() operation is to combine two Binomial Heaps into one. Let us first discuss other operations,
we will discuss union later.
a) insert(H, k): Inserts a key ‘k’ to Binomial Heap ‘H’. This operation first creates a Binomial
Heap with single key ‘k’, then calls union on H and the new Binomial heap.
b) getMin(H): A simple way to getMin() is to traverse the list of root of Binomial Trees and return
the minimum key. This implementation requires O(Logn) time. It can be optimized to O(1) by
maintaining a pointer to minimum key root.
c) extractMin(H): This operation also uses union(). We first call getMin() to find the minimum key
Binomial Tree, then we remove the node and create a new Binomial Heap by connecting all subtrees of
the removed minimum node. Finally we call union() on H and the newly created Binomial Heap. This
operation requires O(Logn) time.
d) delete(H): Like Binary Heap, delete operation first reduces the key to minus infinite, then calls
extractMin().
e) decreaseKey(H): decreaseKey() is also similar to Binary Heap. We compare the decreases key
with it parent and if parent’s key is more, we swap keys and recur for parent. We stop when we either
reach a node whose parent has smaller key or we hit the root node. Time complexity of decreaseKey()
is O(Logn).

Union operation in Binomial Heap:


Given two Binomial Heaps H1 and H2, union (H1, H2) creates a single Binomial Heap.
a) The first step is to simply merge the two Heaps in non-decreasing order of degrees. In the
following diagram, figure(b) shows the result after merging.
b) After the simple merge, we need to make sure that there is at-most one Binomial Tree of any
order. To do this, we need to combine Binomial Trees of same order. We traverse the list of merged
roots, we keep track of three pointers, prev, x and next-x. There can be following 4 cases when we
traverse the list of roots.
Case 1: Orders of x and next-x are not same, we simply move ahead.
In following 3 cases orders of x and next-x are same.
Case 2: If order of next-next-x is also same, move ahead.
Case 3: If key of x is smaller than or equal to key of next-x, then make next-x as a child of x by
linking it with x.
Case 4: If key of x is greater, then make x as child of next.

UNIT 4 Page 40
16CS3202 - Data Structures II Yr CSE / III Sem

Binomial Heap Representation:


A Binomial Heap is a set of Binomial Trees. A Binomial Tree must be represented in a way that
allows sequential access to all siblings, starting from the leftmost sibling (We need this in and
extractMin() and delete()). The idea is to represent Binomial Trees as leftmost child and right-sibling
representation, i.e., every node stores two pointers, one to the leftmost child and other to the right
sibling.

UNIT 4 Page 41
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 1
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 2
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 3
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 4
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 5
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 6
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 7
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 8
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 9
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 10
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 11
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 12
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 13
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 14
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 15
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 16
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 17
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 18
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 19
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 20
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 21
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 22
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 23
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 24
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 25
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 26
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 27
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 28
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 29
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 30
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 31
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 32
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 33
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 34
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 35
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 36
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 37
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 38
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 39
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 40
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 41
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 42
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 43
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 44
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 45
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 46
16CS3202 - DATA STRUCTURES - NOTES

UNIT 4 Page 47
16CS3202 - Data Structures II Yr CSE / III Sem
UNIT - V
SORTING, SEARCHING AND HASHING
5.1 Sorting algorithms:
5.1.1 Insertion sort
5.1.2 Selection sort
5.1.3 Shell sort
5.1.4 Bubble sort
5.1.5 Quick sort
5.1.6 Merge sort
5.1.7 Radix sort
5.2 Searching:
5.2.1 Linear search
5.2.2 Binary Search
5.3 Hashing
5.4 Separate chaining
5.5 Open addressing
5.6 Rehashing
5.7 Extendible hashing

5.1 SORTING
Sorting refers to arranging data in a particular format. Sorting algorithm specifies the way to arrange
data in a particular order. Most common orders are in numerical or lexicographical order.
The importance of sorting lies in the fact that data searching can be optimized to a very high level, if
data is stored in a sorted manner. Sorting is also used to represent data in more readable formats.
Following are some of the examples of sorting in real-life scenarios.
 Telephone Directory − the telephone directory stores the telephone numbers of people sorted by
their names, so that the names can be searched easily.
 Dictionary − the dictionary stores words in an alphabetical order so that searching of any word
becomes easy.
Types of Sorting Techniques
There are many types of Sorting techniques, differentiated by their efficiency and space requirements.
Following are some sorting techniques which we will be covering in next sections.
1. Bubble Sort
2. Insertion Sort
3. Selection Sort
4. Shell Sort
5. Quick Sort
6. Merge Sort
7. Radix Sort

UNIT 5 Page 1
16CS3202 - Data Structures II Yr CSE / III Sem
5.1.1 Insertion Sort
It is a simple Sorting algorithm which sorts the array by shifting elements one by one. Following are some
of the important characteristics of Insertion Sort.
1. It has one of the simplest implementation
2. It is efficient for smaller data sets, but very inefficient for larger lists.
3. Insertion Sort is adaptive, that means it reduces its total number of steps if given a partially sorted
list, hence it increases its efficiency.
4. It is better than Selection Sort and Bubble Sort algorithms.
5. Its space complexity is less. Like Bubble Sorting, insertion sort also requires a single additional
memory space.
6. It is a Stable sorting, as it does not change the relative order of elements with equal keys
How Insertion Sort Works?
We take an unsorted array for our example.

Insertion sort compares the first two elements.

It finds that both 14 and 33 are already in ascending order. For now, 14 is in sorted sub-list.

Insertion sort moves ahead and compares 33 with 27.

And finds that 33 is not in the correct position.

It swaps 33 with 27. It also checks with all the elements of sorted sub-list. Here we see that the sorted sub-
list has only one element 14, and 27 is greater than 14. Hence, the sorted sub-list remains sorted after
swapping.

UNIT 5 Page 2
16CS3202 - Data Structures II Yr CSE / III Sem
By now we have 14 and 27 in the sorted sub-list. Next, it compares 33 with 10.

These values are not in a sorted order.

So we swap them.

However, swapping makes 27 and 10 unsorted.

Hence, we swap them too.

Again we find 14 and 10 in an unsorted order.

We swap them again. By the end of third iteration, we have a sorted sub-list of 4 items.

This process goes on until all the unsorted values are covered in a sorted sub-list.
Program for Insertion Sort
#include <stdlib.h>
#include <iostream.h>
using namespace std;
//member functions declaration
void insertionSort(int arr[], int length);
void printArray(int array[],int size);

UNIT 5 Page 3
16CS3202 - Data Structures II Yr CSE / III Sem
int main() {
int array[5]= {5,4,3,2,1};
insertionSort(array,5);
return 0;
}
void insertionSort(int arr[], int length) {
int i, j ,tmp;
for (i = 1; i < length; i++) {
j = i;
while (j > 0 && arr[j - 1] > arr[j]) {
tmp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = tmp;
j--;
}
printArray(arr,5);
}
}
void printArray(int array[], int size){
cout<< "Sorting tha array using Insertion sort... ";
int j;
for (j=0; j < size;j++)
for (j=0; j < size;j++)
cout <<" "<< array[j];
cout << endl;
}

5.1.2 Selection Sort


Selection sorting is conceptually the most simplest sorting algorithm. This algorithm first finds the
smallest element in the array and exchanges it with the element in the first position, then find the second
smallest element and exchange it with the element in the second position, and continues in this way until
the entire array is sorted.
Note: Selection sort is an unstable sort i.e it might change the occurrence of two similar elements in the
list while sorting. But it can also be a stable sort when it is implemented using linked list data structures.
How Selection Sort Works?

UNIT 5 Page 4
16CS3202 - Data Structures II Yr CSE / III Sem
Consider the following depicted array as an example.

For the first position in the sorted list, the whole list is scanned sequentially. The first position where 14 is
stored presently, we search the whole list and find that 10 is the lowest value.

So we replace 14 with 10. After one iteration 10, which happens to be the minimum value in the list,
appears in the first position of the sorted list.

For the second position, where 33 is residing, we start scanning the rest of the list in a linear manner.

We find that 14 is the second lowest value in the list and it should appear at the second place. We swap
these values.

After two iterations, two least values are positioned at the beginning in a sorted manner.

The same process is applied to the rest of the items in the array.
Following is a pictorial depiction of the entire sorting process −

UNIT 5 Page 5
16CS3202 - Data Structures II Yr CSE / III Sem

Program for Selection Sort


#include <iostream>
using namespace std;
// Sort arr[] of size n using Selection Sort.
void SelectionSort (int arr[], int n)
{
int i, j;

UNIT 5 Page 6
16CS3202 - Data Structures II Yr CSE / III Sem
for (i = 0; i < n; ++i)
{
for (j = i+1; j < n; ++j)
{
//Comparing consecutive data and switching values if i > j.
if (arr[i] > arr[j])
{
arr[i] = arr[i]+arr[j];
arr[j] = arr[i]-arr[j];
arr[i] = arr[i]-arr[j];
}
}
// Value at i will be minimum of all the value above this index.
}
}
int main()
{
int n, i;
cout<<"\nEnter the number of data element to be sorted: ";
cin>>n;
int arr[n];
for(i = 0; i < n; i++)
{
cout<<"Enter element "<<i+1<<": ";
cin>>arr[i];
}
SelectionSort(arr, n);
// Display the sorted data.
cout<<"\nSorted Data ";
for (i = 0; i < n; i++)
cout<<"->"<<arr[i];
return 0;
}

UNIT 5 Page 7
16CS3202 - Data Structures II Yr CSE / III Sem
5.1.3 Shell Sort
Shell sort is a highly efficient sorting algorithm and is based on insertion sort algorithm. This algorithm
avoids large shifts as in case of insertion sort, if the smaller value is to the far right and has to be moved to
the far left.
This algorithm uses insertion sort on a widely spread elements, first to sort them and then sorts the less
widely spaced elements. This spacing is termed as interval. This interval is calculated based on Knuth's
formula as −
Knuth's Formula
h=h*3+1
where − h is interval with initial value 1

How Shell Sort Works?


Let us consider the following example to have an idea of how shell sort works. We take the same array we
have used in our previous examples. For our example and ease of understanding, we take the interval of 4.
Make a virtual sub-list of all values located at the interval of 4 positions. Here these values are {35, 14},
{33, 19}, {42, 27} and {10, 44}

We compare values in each sub-list and swap them (if necessary) in the original array. After this step, the
new array should look like this –

Then, we take interval of 2 and this gap generates two sub-lists - {14, 27, 35, 42}, {19, 10, 33, 44}

UNIT 5 Page 8
16CS3202 - Data Structures II Yr CSE / III Sem

We compare and swap the values, if required, in the original array. After this step, the array should look
like this –

Finally, we sort the rest of the array using interval of value 1. Shell sort uses insertion sort to sort the
array.
Following is the step-by-step depiction −

UNIT 5 Page 9
16CS3202 - Data Structures II Yr CSE / III Sem

// C++ implementation of Shell Sort


#include <iostream>
using namespace std;
/* function to sort arr using shellSort */
int shellSort(int arr[], int n)

UNIT 5 Page 10
16CS3202 - Data Structures II Yr CSE / III Sem
{
// Start with a big gap, then reduce the gap
for (int gap = n/2; gap > 0; gap /= 2)
{
// Do a gapped insertion sort for this gap size.
// The first gap elements a[0..gap-1] are already in gapped order
// keep adding one more element until the entire array is
// gap sorted
for (int i = gap; i < n; i += 1)
{
// add a[i] to the elements that have been gap sorted
// save a[i] in temp and make a hole at position i
int temp = arr[i];

// shift earlier gap-sorted elements up until the correct


// location for a[i] is found
int j;
for (j = i; j >= gap && arr[j - gap] > temp; j -= gap)
arr[j] = arr[j - gap];

// put temp (the original a[i]) in its correct location


arr[j] = temp;
}
}
return 0;
}
void printArray(int arr[], int n)
{
for (int i=0; i<n; i++)
cout << arr[i] << " ";
}
int main()
{
int arr[] = {12, 34, 54, 2, 3}, i;
int n = sizeof(arr)/sizeof(arr[0]);

cout << "Array before sorting: \n";


printArray(arr, n);

UNIT 5 Page 11
16CS3202 - Data Structures II Yr CSE / III Sem

shellSort(arr, n);
cout << "\nArray after sorting: \n";
printArray(arr, n);
return 0;
}

5.1.4 Bubble Sort


Bubble Sort is an algorithm which is used to sort N elements that are given in a memory for eg: an Array
with N number of elements. Bubble Sort compares the entire element one by one and sort them based on
their values. It is also known as Sinking Sort.
It is called Bubble sort, because with each iteration the largest element in the list bubbles up towards the
last place, just like a water bubble rises up to the water surface.
Sorting takes place by stepping through all the data items one-by-one in pairs and comparing adjacent data
items and swapping each pair that is out of order.

How Bubble Sort Works?


We take an unsorted array for our example.

Bubble sort starts with very first two elements, comparing them to check which one is greater.

In this case, value 33 is greater than 14, so it is already in sorted locations. Next, we compare 33 with 27.

We find that 27 is smaller than 33 and these two values must be swapped.

The new array should look like this −

Next we compare 33 and 35. We find that both are in already sorted positions.

UNIT 5 Page 12
16CS3202 - Data Structures II Yr CSE / III Sem

Then we move to the next two values, 35 and 10.

We know then that 10 is smaller 35. Hence they are not sorted.

We swap these values. We find that we have reached the end of the array. After one iteration, the array
should look like this −

To be precise, we are now showing how an array should look like after each iteration. After the second
iteration, it should look like this −

Notice that after each iteration, at least one value moves at the end.

And when there's no swap required, bubble sorts learns that an array is completely sorted.

Algorithm
We assume list is an array of n elements. We further assume that swap function swaps the values of the
given array elements.
begin BubbleSort(list)
for all elements of list
if list[i] > list[i+1]
swap(list[i], list[i+1])
end if
end for
return list

UNIT 5 Page 13
16CS3202 - Data Structures II Yr CSE / III Sem

end BubbleSort

Program:
#include <iostream>
using namespace std;
// Sort arr[] of size n using Bubble Sort.
void BubbleSort (int arr[], int n)
{
int i, j;
for (i = 0; i < n; ++i)
{
for (j = 0; j < n-i-1; ++j)
{
// Comparing consecutive data and switching values if value at
j > j+1.
if (arr[j] > arr[j+1])
{
arr[j] = arr[j]+arr[j+1];
arr[j+1] = arr[j]-arr[j + 1];
arr[j] = arr[j]-arr[j + 1];
}
}
// Value at n-i-1 will be maximum of all the values below this index.
}
}
int main()
{
int n, i;
cout<<"\nEnter the number of data element to be sorted: ";
cin>>n;
int arr[n];
for(i = 0; i < n; i++)
{
cout<<"Enter element "<<i+1<<": ";
cin>>arr[i];
}
BubbleSort(arr, n);

UNIT 5 Page 14
16CS3202 - Data Structures II Yr CSE / III Sem
// Display the sorted data.
cout<<"\nSorted Data ";
for (i = 0; i < n; i++)
cout<<"->"<<arr[i];
return 0;
}

5.1.5 Quick Sort


Quick Sort, as the name suggests, sorts any list very quickly. Quick sort is not a stable search, but it is
very fast and requires very less additional space. It is based on the rule of Divide and Conquer(also
called partition-exchange sort). This algorithm divides the list into three main parts :
1. Elements less than the Pivot element
2. Pivot element(Central element)
3. Elements greater than the pivot element
In the list of elements, mentioned in below example, we have taken 25 as pivot. So after the first pass, the
list will be changed like this.
6 8 17 14 25 63 37 52
Hence after the first pass, pivot will be set at its position, with all the elements smaller to it on its left and
all the elements larger than to its right. Now 6 8 17 14 and 63 37 52 are considered as two separate lists,
and same logic is applied on them, and we keep doing this until the complete list is sorted.

Program for Quick Sort


#include<iostream>
#include<cstdlib>

UNIT 5 Page 15
16CS3202 - Data Structures II Yr CSE / III Sem
using namespace std;
// Swapping two values.
void swap(int *a, int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
// Partitioning the array on the basis of values at high as pivot value.
int Partition(int a[], int low, int high)
{
int pivot, index, i;
index = low;
pivot = high;
// Getting index of pivot.
for(i=low; i < high; i++)
{
if(a[i] < a[pivot])
{
swap(&a[i], &a[index]);
index++;
}
}
// Swapping value at high and at the index obtained.
swap(&a[pivot], &a[index]);
return index;
}
// Random selection of pivot.
int RandomPivotPartition(int a[], int low, int high)
{
int pvt, n, temp;
n = rand();
// Randomizing the pivot value in the given subpart of array.
pvt = low + n%(high-low+1);

// Swapping pvt value from high, so pvt value will be taken as pivot while
partitioning.

UNIT 5 Page 16
16CS3202 - Data Structures II Yr CSE / III Sem
swap(&a[high], &a[pvt]);
return Partition(a, low, high);
}
// Implementing QuickSort algorithm.
int QuickSort(int a[], int low, int high)
{
int pindex;
if(low < high)
{
// Partitioning array using randomized pivot.
pindex = RandomPivotPartition(a, low, high);
// Recursively implementing QuickSort.
QuickSort(a, low, pindex-1);
QuickSort(a, pindex+1, high);
}
return 0;
}
int main()
{
int n, i;
cout<<"\nEnter the number of data element to be sorted: ";
cin>>n;
int arr[n];
for(i = 0; i < n; i++)
{
cout<<"Enter element "<<i+1<<": ";
cin>>arr[i];
}
QuickSort(arr, 0, n-1);
// Printing the sorted data.
cout<<"\nSorted Data ";
for (i = 0; i < n; i++)
cout<<"->"<<arr[i];
return 0;
}

5.1.6 Merge Sort

UNIT 5 Page 17
16CS3202 - Data Structures II Yr CSE / III Sem
Merge Sort follows the rule of Divide and Conquer. In merge sort the unsorted list is divided into N
sublists, each having one element, because a list consisting of one element is always sorted. Then, it
repeatedly merges these sublists, to produce new sorted sublists, and in the end, only one sorted list is
produced.
Merge sort first divides the array into equal halves and then combines them in a sorted manner.

How Merge Sort Works?


To understand merge sort, we take an unsorted array as the following −

We know that merge sort first divides the whole array iteratively into equal halves unless the atomic
values are achieved. We see here that an array of 8 items is divided into two arrays of size 4.

This does not change the sequence of appearance of items in the original. Now we divide these two arrays
into halves.

We further divide these arrays and we achieve atomic value which can no more be divided.

Now, we combine them in exactly the same manner as they were broken down. Please note the color
codes given to these lists.
We first compare the element for each list and then combine them into another list in a sorted manner. We
see that 14 and 33 are in sorted positions. We compare 27 and 10 and in the target list of 2 values we put
10 first, followed by 27. We change the order of 19 and 35 whereas 42 and 44 are placed sequentially.

In the next iteration of the combining phase, we compare lists of two data values, and merge them into a
list of found data values placing all in a sorted order.

After the final merging, the list should look like this −

UNIT 5 Page 18
16CS3202 - Data Structures II Yr CSE / III Sem

Program for Merge Sort


#include <iostream>
using namespace std;
// A function to merge the two half into a sorted data.
void Merge(int *a, int low, int high, int mid)
{
// We have low to mid and mid+1 to high already sorted.
int i, j, k, temp[high-low+1];
i = low;
k = 0;
j = mid + 1;
// Merge the two parts into temp[].
while (i <= mid && j <= high)
{
if (a[i] < a[j])
{
temp[k] = a[i];
k++;
i++;
}
else
{
temp[k] = a[j];
k++;
j++;
}
}
// Insert all the remaining values from i to mid into temp[].
while (i <= mid)
{
temp[k] = a[i];
k++;
i++;
}
// Insert all the remaining values from j to high into temp[].

UNIT 5 Page 19
16CS3202 - Data Structures II Yr CSE / III Sem
while (j <= high)
{
temp[k] = a[j];
k++;
j++;
}
// Assign sorted data stored in temp[] to a[].
for (i = low; i <= high; i++)
{
a[i] = temp[i-low];
}
}
// A function to split array into two parts.
void MergeSort(int *a, int low, int high)
{
int mid;
if (low < high)
{
mid=(low+high)/2;
// Split the data into two half.
MergeSort(a, low, mid);
MergeSort(a, mid+1, high);

// Merge them to get sorted output.


Merge(a, low, high, mid);
}
}
int main()
{
int n, i;
cout<<"\nEnter the number of data element to be sorted: ";
cin>>n;
int arr[n];
for(i = 0; i < n; i++)
{
cout<<"Enter element "<<i+1<<": ";
cin>>arr[i];
}

UNIT 5 Page 20
16CS3202 - Data Structures II Yr CSE / III Sem
MergeSort(arr, 0, n-1);
// Printing the sorted data.
cout<<"\nSorted Data ";
for (i = 0; i < n; i++)
cout<<"->"<<arr[i];
return 0;
}

5.1.7 Radix Sort


Radix sort is a small method that many people intuitively use when alphabetizing a large list of names.
Specifically, the list of names is first sorted according to the first letter of each name, that is, the names are
arranged in 26 classes.
Intuitively, one might want to sort numbers on their most significant digit. However, Radix sort works
counter-intuitively by sorting on the least significant digits first. On the first pass, all the numbers are
sorted on the least significant digit and combined in an array. Then on the second pass, the entire numbers
are sorted again on the second least significant digits and combined in an array and so on.

5.2 SEARCHING
Searching is an operation or a technique that helps finds the place of a given element or value in
the list. Any search is said to be successful or unsuccessful depending upon whether the element that is
being searched is found or not. Some of the standard searching technique that is being followed in data
structure is listed below:

UNIT 5 Page 21
16CS3202 - Data Structures II Yr CSE / III Sem
 Linear Search or Sequential Search
 Binary Search

5.2.1 Linear Search:


This is the simplest method for searching. In this technique of searching, the element to be found in
searching the elements to be found is searched sequentially in the list. This method can be performed on a
sorted or an unsorted list (usually arrays). In case of a sorted list searching starts from 0 th element and
continues until the element is found from the list or the element whose value is greater than (assuming the
list is sorted in ascending order), the value being searched is reached.
As against this, searching in case of unsorted list also begins from the 0 th element and continues until the
element or the end of the list is reached.

Example:
The list given below is the list of elements in an unsorted array. The array contains 10 elements. Suppose
the element to be searched is ’46’, so 46 is compared with all the elements starting from the 0 th element
and searching process ends where 46 is found or the list ends.
The performance of the linear search can be measured by counting the comparisons done to find out an
element.
Program for Linear Search:
#include <iostream>
#include<conio.h>
#include<stdlib.h>
#define MAX_SIZE 5
using namespace std;
int main()
{
int arr_search[MAX_SIZE], i, element;
cout << "Simple C++ Linear Search Example - Array\n";
cout << "\nEnter " << MAX_SIZE << " Elements for Searching : " << endl;
for (i = 0; i < MAX_SIZE; i++)
cin >> arr_search[i];
cout << "\nYour Data :";
for (i = 0; i < MAX_SIZE; i++)
{
cout << "\t" << arr_search[i];

UNIT 5 Page 22
16CS3202 - Data Structures II Yr CSE / III Sem
}
cout << "\nEnter Element to Search : ";
cin>>element;
/* for : Check elements one by one - Linear */
for (i = 0; i < MAX_SIZE; i++)
{
/* If for Check element found or not */
if (arr_search[i] == element)
{
cout << "\nLinear Search : Element : " << element << " : Found :
Position : " << i + 1 << ".\n";
break;
}
}
if (i == MAX_SIZE)
cout << "\nSearch Element : " << element << " : Not Found \n";
getch();
}

5.2.2 Binary Search


Binary search is a very fast and efficient searching technique. It requires the list to be in sorted order. In
this method, to search an element you can compare it with the present element at the center of the list. If it
matches, then the search is successful otherwise the list is divided into two halves: one from the 0 th
element to the middle element which is the center element (first half) another from the center element to
the last element (which is the 2nd half) where all values are greater than the center element.
The searching mechanism proceeds from either of the two halves depending upon whether the target
element is greater or smaller than the central element. If the element is smaller than the central element,
then searching is done in the first half, otherwise searching is done in the second half.
Example:
For a binary search to work, it is mandatory for the target array to be sorted. We shall learn the process of
binary search with a pictorial example. The following is our sorted array and let us assume that we need to
search the location of value 31 using binary search.

First, we shall determine half of the array by using this formula −


mid = low + (high - low) / 2
Here it is, 0 + (9-0) / 2 = 4 (integer value of 4.5). So, 4 is the mid of the array.

UNIT 5 Page 23
16CS3202 - Data Structures II Yr CSE / III Sem

Now we compare the value stored at location 4, with the value being searched, i.e. 31. We find that the
value at location 4 is 27, which is not a match. As the value is greater than 27 and we have a sorted array,
so we also know that the target value must be in the upper portion of the array.

We change our low to mid + 1 and find the new mid value again.
low = mid + 1
mid = low + (high-low) / 2
Our new mid is 7 now. We compare the value stored at location 7 with our target value 31.

The value stored at location 7 is not a match, rather it is more than what we are looking for. So, the value
must be in the lower part from this location.

Hence, we calculate the mid again. This time it is 5.

We compare the value stored at location 5 with our target value. We find that it is a match.

We conclude that the target value 31 is stored at location 5.

UNIT 5 Page 24
16CS3202 - Data Structures II Yr CSE / III Sem
Binary search halves the searchable items and thus reduces the count of comparisons to be made to very
less numbers.
Program for Binary Search:
#include <iostream>
#include<conio.h>
#include<stdlib.h>
#define MAX_SIZE 5
using namespace std;
int main()
{
int arr_search[MAX_SIZE], i, element;
int f = 0, r = MAX_SIZE, mid;
cout << "Simple C++ Binary Search Example - Array\n";
cout << "\nEnter " << MAX_SIZE << " Elements for Searching : " << endl;
for (i = 0; i < MAX_SIZE; i++)
cin >> arr_search[i];
cout << "\nYour Data :";
for (i = 0; i < MAX_SIZE; i++)
{
cout << "\t" << arr_search[i];
}
cout << "\nEnter Element to Search : ";
cin>>element;
while (f <= r)
{
mid = (f + r) / 2;
if (arr_search[mid] == element)
{
cout << "\nSearch Element : " << element << " : Found : Position : " <<
mid + 1 << ".\n";
break;
}
else if (arr_search[mid] < element)
f = mid + 1;
else
r = mid - 1;
}
if (f > r)

UNIT 5 Page 25
16CS3202 - Data Structures II Yr CSE / III Sem
cout << "\nSearch Element : " << element << " : Not Found \n";
getch();
}

5.3 HASHING
• It is a technique used for performing insertions, deletions and search operation in constant average time
by implementing Hash table data structure.
• Instead of comparisons, it uses a mathematical function
Types of hashing
1.Static hashing
– the hash function maps search key value to a fixed set of locations
2.Dynamic hashing
– the hash table can grow to handle more items at run time.

Hash table
• The hash table data structure is an array of some fixed size table, containing the keys. A key value is
associated with each record. A hash table is partitioned into array of buckets. Each bucket has many slots
and each slot holds one record
Hashing functions
• A hashing function is a key-to-address transformation which acts upon a given key to compare the
relative position of the key in the hash table.
• A key can be a number, string, record, etc.
• A simple hash function
– Hash (Key) = (Key) Mod (Table-size)
– For example, if the key is 24 and the table size is 5, then
– Hash (24) = 24 % 5 = 4
– The key value “24” is placed in the relative location “4” in the hash table
Hash function
• A good Hash Function should
– Minimize collisions
– Be easy and quick to compute
– Distribute keys evenly in the hash table
– Use all the information provided in the key
• Routine for simple Hash Function
Hash(char *key, int Table_size)

UNIT 5 Page 26
16CS3202 - Data Structures II Yr CSE / III Sem
{
int Hash_value = 0;
while(*key != „10‟)
Hash_value = Hash_value + *key;
*key++;
return (Hash_value % Table_size);
}
Methods of Hashing Function
1. Mid square method
2. Modulo division or division remainder
3. Folding method
4. Pseudo random number generator method
5. Digit or character extraction method
6. Radix transformation

1. Mid square method


The key is squared and the middle part of the result is taken as the hash value based on the number
or digits required for addressing.
H(X) = middle digits of X²
For example :
– Map the key 2453 into a hash table of size 1000.
– Now X = 2453 and X = 6017209
– Extracted middle value “172” is the hash value
2. Modulo division
This method computes hash value from key using modulo(%) operator
H(key) = Key % Table_size

Index Slot

0 4

For example:

UNIT 5 Page 27
16CS3202 - Data Structures II Yr CSE / III Sem
– Map the key 4 into a hash table of size 4
– H(4) = 4 % 4 = 0
3. Folding method
This method involves splitting keys into two or more parts each of which has the same length as
the required address and then adding the parts to form the hash function
 Two types
o Fold shifting method
o Fold boundary method
 Fold shifting method
o key = 123203241
o Partition key into 3 parts of equal length.
o 123, 203 & 241
o Add these three parts
o 123+203+241 = 567 is the hash value
 Fold boundary method
o Similar to fold shifting except the boundary parts are reversed
o 123203241 is the key
o 3 parts 123, 203, 241
o Reverse the boundary partitions
o 321, 203, 142
o 321 + 203 + 142 = 666 is the hash value
4. Pseudo random number generator method
This method generates random number given a seed as parameter and the resulting random number
then scaled into the possible address range using modulo division. The random number produced can be
transformed to produce a hash value.

5. Digit or Character extraction method


This method extracts the selected digits from the key
Example:
 Map the key 123203241 to a hash table size of 1000
 Select the digits from the positions 2 , 5, 8 .
 Now the hash value = 204

6. Radix transformation

UNIT 5 Page 28
16CS3202 - Data Structures II Yr CSE / III Sem
In this method , a key is transformed into another number base
Example :
 Map the key (8465)10 using base 15
 Now (8465)10 = (2795)15
 Now the hash value is 2795
Applications of Hash tables
 Database systems
 Symbol tables
 Data dictionaries
 Network processing algorithms
 Browse caches

COLLISION
Collision occurs when a hash value of a record being inserted hashes to an address that already contain a
different record. (i.e) when two key values hash to the same position.
Example : 37, 24 , 7

Index Slot

2 37

4 24

• 37 is placed in index 2
• 24 is placed in index 4
• Now inserting 7
• Hash (7) = 7 mod 5 = 2
• 2 collides
Collision Resolution strategies
The process of finding another position for the collide record is called Collision Resolution strategy.
Two categories
1. Open hashing - separate chaining

UNIT 5 Page 29
16CS3202 - Data Structures II Yr CSE / III Sem

 Each bucket in the hash table is the head of a linked list. All elements that hash to same
value are linked together.
2. Closed hashing - Open addressing, rehashing and extendible hashing.
 Collide elements are stored at another slot in the table.
 It ensures that all elements are stored directly into the hash table.

5.4 SEPARATE CHAINING


• It is an open hashing technique
• A pointer field is added to each record location.
• 10, 11, 81, 7, 34, 94, 17,29,89

Routine for insertion in Separate chaining


void insert(int key, Hashtable H)
{
Position pos,Newcell;
List L;
Pos=Find(key,H);
if(Pos==NULL) /*key is not found */
{
Newcell = malloc(sizeof(struct ListNode));
if(Newcell !=NULL)
{
L=H→TheLists[Hash(key,H →Tablesize)];
Newcell → Next = L →Next;
Newcell →Element = key;

L →Next = Newcell;

UNIT 5 Page 30
16CS3202 - Data Structures II Yr CSE / III Sem
}
}
}
Position Find(int key, Hashtable H)
{
Position P;
List L;
L=H→TheLists[Hash(key,H →Tablesize)];
P = L →Next;
while(P!=NULL && P →Element !=key)
P=P →Next;
return P;
}
Advantages and Disadvantages
• Advantages
– More number of elements can be inserted as it uses array of linked lists.

– Collision resolution is simple and efficient.
• Disadvantages
– It requires pointers that occupy more space.
– It takes more effort to perform search, since it takes time to evaluate the hash function and also
to traverse the list.

5.5 OPEN ADDRESSING


 It is a closed hashing technique.
 In this method, if collision occurs, alternative cells are tried until an empty cell is
found.
 There are three common methods
 Linear probing
 Quadratic probing
 Double hashing
a) Linear probing
• In linear probing, for the ith probe the position to be tried is in a linear
function
• F(i) = i, Hash(X) = X % Tablesize
• Hi(x) =Hash(X) + F(i) mod Tablesize

UNIT 5 Page 31
16CS3202 - Data Structures II Yr CSE / III Sem
= Hash(X) + i mod Tablesize
Example: To insert 42,39,69,21,71,55 to the hash table of size 10 using linear probing
1. H0(42) = 42 % 10 = 2
2. H0(39) = 39 %10 = 9
3. H0(69) = 69 % 10 = 9 collides with 39
H1(69) = (9+1) % 10 = 10 % 10 = 0
4. H0(21) = 21 % 10 = 1
5. H0(71) = 71 % 10 = 1 collides with 21

H1(71) = (1 +1) % 10 = 2 % 10 = 2 collides with 42


H2(71) = (2 +1) % 10 = 3 % 10 = 3
6. H0(55) = 55 % 10 = 5

Index Empty Table After 42 After 39 After 69 After 21 After 71 After 55

0 69 69 69 69

1 21 21 21

2 42 42 42 42 42 42

3 71 71

5 55

9 39 39 39 39 39

• Advantages
– It doesn‟t require pointers
• Disadvantages
– It forms clusters that degrades the performance of the hash table
b) Quadratic probing
• Based on quadratic function i.e., F(i) = i

UNIT 5 Page 32
16CS3202 - Data Structures II Yr CSE / III Sem
• Hi(x) =Hash(X) + F(i) mod Table size
Example: To insert 89, 18, 49, 58, 69 to the hash table of size 10 using quadratic probing
1. H0(89) = 89 %10 =9

2. H0(18) = 18 %10 =8
3. H0(49) = 49 %10 =9 collides with 89

4. H1(49) = (9+12) % 10 = 10 % 10 = 0

5. H0(58) = 58 %10 = 8 collides with 18

H1(58) = (8 +12) % 10 = 9 % 10 = 9 collides with 89

H2(58) = (8 + 22) % 10 = 12 % 10 = 2

6. H0(69) = 69 % 10 =9 collides with 89

H1(69) = (9 +12) % 10 = 10 % 10 = 0 collides with 49

H2(69) = (9 + 22) % 10 = 13 % 10 = 3

Index Empty Table After 89 After 18 After 49 After 58 After 69

0 49 49 49

2 58 58

3 69

5 55

8 18 18 18 18

9 89 89 89 89 89

Limitations:
• It faces secondary clustering that is difficult to find the empty slot if the table is half full.

UNIT 5 Page 33
16CS3202 - Data Structures II Yr CSE / III Sem
C) Double Hashing
• It 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 from the point of
collision to insert.
• F(i) = i * Hash2(X)
• Hi(x) = (Hash(X) + F(i)) mod Tablesize
Hi(x) = (Hash(X) + i * Hash2(X) ) mod Tablesize A popular second hash function is
Hash2(X) = R – (X % R)
where R is a prime number
• Insert : 89, 18, 49, 58, 69 using Hash2(X) = R – (X % R) and R = 7
• Open addressing hash table using double hashing

Here Hash(X) = X % 10 & Hash2(X) = 7 – (X % 7)

Index Empty Table After 89 After 18 After 49 After 58 After 69

0 69

3 58 58

6 49 49 49

8 18 18 18 18

9 89 89 89 89 89

1. H0(89) = 89 % 10 = 9

2. H0(18) = 18 % 10 = 8

3. H0(49) = 49 % 10 = 9 collides with 89

UNIT 5 Page 34
16CS3202 - Data Structures II Yr CSE / III Sem
H1(49) = ((49 % 10 ) + 1 * (7- (49 % 7)) ) % 10
=16 % 10 = 6
4. H0(58) = 58 % 10 = 8 collides with 18

H1(58) = ((58 % 10 ) + 1 * (7- (58 % 7)) ) % 10


=13 % 10 = 3
5. H0(69) = 69 % 10 = 9 collides with 89

H1(69) = ((69 % 10 ) + 1 * (7- (69 % 7)) ) % 10


= 10 % 10 = 0

5.6 REHASHING
 It is a closed hashing technique.
 If the table gets too full, then the rehashing method builds new table that is about twice as big and
scan down the entire original hash table, comparing the new hash value for each element and
inserting it in the new table.
 Rehashing is very expensive since the running time is O(N), since there are N elements to rehash
and the table size is roughly 2N
 Rehashing can be implemented in several ways like
a. Rehash , as soon as the table is half full
b. Rehash only when an insertion fails
Routine for rehashing
HashTable Rehash(HashTable H)
{
int i, oldsize;
cell *oldcells;
oldcells = H→Thecells;
oldsize = H → Table_size;
H= InitializeTable(2*oldsize);
for (i=0;i<oldsize; i++)
if (oldcells[i].Info==Legitimate)
Insert(oldcells[i].Element.H);
free(oldcells);
return H;
}
Example : Suppose the elements 13, 15, 24, 6 are inserted into an open addressing hash table of size 7 and
if linear probing is used when collision occurs.

UNIT 5 Page 35
16CS3202 - Data Structures II Yr CSE / III Sem
Index Slot

0 6

1 15

3 24

6 13

• If 23 is inserted, the resulting table will be over 70 percent full.

Index Slot

0 6

1 15

2 23

3 24

6 13

• A new table is created. The size of the new table is 17, as this is the first prime number that is
twice as large as the old table size.

Index Slot

UNIT 5 Page 36
16CS3202 - Data Structures II Yr CSE / III Sem
5

6 6

7 23

8 24

10

11

12

13 13

14

15 15

16

Advantages
• Programmer doesn‟t worry about the table size
• Simple to implement

5.7 EXTENDIBLE HASHING


• When open addressing or separate hashing is used, collisions could cause several blocks to be
examined during a Find operation, even for a well distributed hash table.
• Furthermore , when the table gets too full, an extremely expensive rehashing step must be
performed, which requires O(N) disk accesses.
• These problems can be avoided by using extendible hashing.
• Extendible hashing uses a tree to insert keys into the hash table.
Example:
• Consider the key consists of several 6 bit integers.
• The root of the “tree” contains 4 pointers determined by the leading 2 bits.
• In each leaf the first 2 bits are identified and indicated in parenthesis.
• D represents the number of bits used by the root(directory)
• The number of entries in the directory is 2D

UNIT 5 Page 37
16CS3202 - Data Structures II Yr CSE / III Sem

• Suppose to insert the key 100100.


• This would go to the third leaf but as the third leaf is already full.
• So split this leaf into two leaves, which are now determined by the first three bits.
• Now the directory size is increased to 3.

Similarly if the key 000000 is to be inserted, then the first leaf is split into 2 leaves.

Advantages & Disadvantages:

UNIT 5 Page 38
16CS3202 - Data Structures II Yr CSE / III Sem
• Advantages
– Provides quick access times for insert and find operations on large databases.
• Disadvantages
– This algorithm does not work if there are more than M duplicates

UNIT 5 Page 39

You might also like